Saturday 17 March 2012

SPRING, STRUTS and JDBC Integration


 Spring    is widely used in companies. Whether it is Struts or Hibernate or other  services like mail, jms, security or jax-ws, it is required to be used through Spring.

  So, I am trying to develop a struts  demo through Spring.

 
Even for integrating Struts1.1 with Spring, there are 3 methods. ( as mentioned in the famous book ‘Spring in Action’ by Craig Walls..p347 to 351).. The first method is easiest. In that case, I just extended my action class from  Spring’s ActionSupport class.

The code snippet will be as follows.

( we must import
import org.springframework.context.
ApplicationContext;
import org.springframework.web.struts.
ActionSupport;


public class demoAction extends ActionSupport
{

public ActionForward execute
(ActionMapping   mapping,
ActionForm       form,
HttpServletRequest   request,
HttpServletResponse   response)
throws Exception
{

ApplicationContext   context=
     getWebApplicationContext();

helper helper1 =
(helper) context.getBean(“helper1”);

String   r = helper1.help();

request.setAttribute(“result”,r);

return
mapping.findForward(“success”);
}
// etc as usual.

So the only change will be this and all the other struts files will be same.
Ofcourse, we will have beans.xml where we define helper class and helper bean.
The mapping is done in beans.xml
as follows.( this is Spring file)
=================================

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
   <bean     name="bean1"
         class="demopack.hellobean">

   </bean>
</beans>
================================



This helper class can be as simple as hellobean or jdbcquerybean or hibernatebean.
It makes little difference.
This is the first iteration.

I got correct result , whatever be the helperclass.

This is the simplest method.
================================

   The objection may be that it ties our code tightly with Spring.

 So, there is a second method known as Delegation method.

In this case, my action class is NOT derived from ActionSupport.

The code snippet for my action class is:

public class demoAction extends Action
{
  public   hellobean      bean1;

  public  void setBean1
       (hellobean   b){bean1=b;}

  public ActionForward execute(
ActionMapping          mapping,                               ActionForm             form,                              HttpServletRequest     request,                               HttpServletResponse    response)
        throws IOException,ServletException
   {
demoForm    demoform =
 ( demoForm)  form;
String      s1       =
        demoform.getName();      String r=bean1.sayhello( s1);    
      request.setAttribute
       ("result",  r);
      return (mapping.findForward("success"));
      }
}

But we have to make an entry in struts-config file as follows:
-------------------------------

<form-bean   name="demoForm"  type="demopack.demoForm"   />
</form-beans>
...
<action

 path="/demo"
            input="/demoInput.jsp"
            name="demoForm"
            type="org.springframework.web.
struts.DelegatingActionProxy"
            scope="session"          
            validate="true"    >          

 <forward name="success" path="/demoOutput.jsp" />

<forward name="failure" path="/demoInput.jsp" />
     </action>

    </action-mappings>
...


<plug-in
 className             =    
"org.springframework.web.struts.
ContextLoaderPlugIn">

<set-property  property="contextConfigLocation"
value  =  "/WEB-INF/beans.xml"/>
</plug-in>

</struts-config>


And then we have to map demoAction and our helper class in beans.xml file.

  <bean     name="bean1"
   class="demopack.hellobean"/>

  <bean  name="/demo"
  class="demopack.demoAction" >
    <property name="bean1">
        <ref  bean="bean1"/>
    </property>
  </bean>

we should be careful when setting the name property of the bean which points to  ‘demoAction’ class. The value of the name property should be same as the value of ‘path’ property of <action> tag.



The third method is  
‘Request Delegation’ .
Spring provides DelegatingRequesProcessor  for <controller> tag  (in struts-config.xml)
 
It will be stated as

<controller processorClass = "org.springframework.web.struts.
DelegatingRequestProcessor"/>


when you are using request delegation  method, you need not   specify the type attribute in the <action> tag.
   
when a request received for “/demo”, DelegatingRequesProcessor  will automatically refer to beans.xml file for the appropriate action.

Apart from this <controller> tag, every thing is same as delegate method
<action

   path="/demo"
   input="/demoInput.jsp"
    name="demoForm"
   scope="session"          
 validate="true" >
         ...

     </action>
<controller processorClass=
"org.springframework.web.struts.
DelegatingRequestProcessor"/>

...
<plug-in
         className="org.springframework.web.struts.ContextLoaderPlugIn">

      <set-property  property="contextConfigLocation"
                     value="/WEB-INF/beans.xml"/>
</plug-in>

================================      

Next example is about integrating struts1.1 , spring1.2 and jdbc

   I begin with demoInput.jsp. almost demoInput.jsp,
demoForm.java and demoOutput.jsp are very similar
to a usual struts application.

  But, demoAction.java code has to be changed a bit from
our usual pattern and ofcourse, helper class (In our case
springhiberbean is the helper class)is DAO and it
is very simple.In this bean I have written code only for
displaying the records.

  Apart from these things, we have to concentrate on xml
files also.


In addition to struts-config.xml

  we have to provide spring application context xml file.
this spring application context(beans.xml file in ourcase) file is to be

accessed through
struts-config.xml

for clearity I have given the code for demoInput.jsp,

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>


<html>
<body bgcolor=green    text=cyan>

<html:errors />

<html:form action="/demo"
           name="demoForm"
           type="demopack.demoForm">


type your name (only admin can view records)

<br>
<html:text      property="name" /> name<br>


<html:submit />
</html:form>

</body>
</html>

   In above code, I highlighted the ‘action’ attribute.
we all know that demoAction(Action) class is highly
tie up with servlet API. So, There will be some difficulties
in testing Action class.

  To avoid these difficulties, spring introduced Dependency
Injection concept. and so It has to be mapped in spring application
context (beans.xml) file.

   When mapping this demoAction class in struts-config file, we have to use this
action=’/demo’.

demoForm.java will be having setter getter method code as usual.
For brevity, I  skipped the demoForm and demoOutput.jsp.

  demoAction.java

package demopack;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

import  org.apache.struts.action.*;



public class demoAction extends Action
{


  public   springquerybean       bean1;

  public  void setBean1(springquerybean   b){bean1=b;}




  public ActionForward execute(ActionMapping          mapping,
                               ActionForm             form,
                               HttpServletRequest     request,
                               HttpServletResponse    response)

                       throws IOException,ServletException
   {


      demoForm    demoform = ( demoForm)  form;

      String      s1       = demoform.getName();

      System.out.println(s1);

      //-----------------------------------------------------

     if(s1.equals("admin"))
     {
      String r=bean1.getrecords();

       System.out.println(r);

      request.setAttribute("result",  r);

      return (mapping.findForward("success"));
      }
      else
      {
      return (mapping.findForward("failure"));
      }
     
      }


}


 
  Apart from the highlighted lines, every thing is similar to usual code.
springquerybean object will be passed to setter function through beans.xml
file.

  The following code is for springquerybean. It is DAO and the highlighted one is VO.
I have placed springquerybean and dsgetset  in demopack. but it is not necessary.
The difference is If you placed it in package, you  have to specify that in beans.xml file as


   <bean     name="bean1"
         class="demopack.springquerybean">

           otherwise you can simply say


<bean     name="bean1"
         class="springquerybean">

So, you can use any bean. It doesn’t matter in which package
it is placed. The only thing is that you have to specify the package
in   <bean>  tag.


springquerybean.java

package  demopack;
import java.io.*;
import javax.sql.*;
import java.sql.*;
import java.util.*;


import org.springframework.beans.factory.*;
import org.springframework.beans.factory.xml.*;
import org.springframework.core.io.*;
import org.springframework.jdbc.core.*;
import org.springframework.jdbc.datasource.*;
import org.springframework.jdbc.object.*;
import org.springframework.jdbc.support.*;

public class springquerybean
{
   
   dsgetset  dbean1;

    public void  setDbean1(dsgetset  b){dbean1 = b;}


     public   String getrecords()
     {

                 String r="";
      try
      {

      DataSource ds=dbean1.getDatasource();

           java.util.List  list1;
           
            JdbcTemplate   jt = new   JdbcTemplate(ds);

            list1=jt.queryForList("select *from table1");

            Iterator i=list1.iterator();

            while(i.hasNext())
            {
               Object  ob = i.next();
                r=r+ob.toString()+"\n";
             
            }





        }  catch(Exception e1)
           { r=r+e1;}

      return r;
    }

}


Value Object
dsgetset.java

package  demopack;


import org.springframework.jdbc.core.*;
import org.springframework.jdbc.datasource.*;
import org.springframework.jdbc.object.*;
import org.springframework.jdbc.support.*;
import javax.sql.*;

public class   dsgetset
{

DataSource datasource;


    public void setDatasource(DataSource ds)
    {  datasource = ds;  }

    public DataSource getDatasource()
    {  return datasource;  }
}

  We can reduce this code some more by adding the dsgetset content to
springquerybean  code. For clarity I have divided the code as two classes.



beans.xml file



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
   <bean     name="bean1"
         class="demopack.springquerybean">
   <property name="dbean1">
           <ref  bean="dsbean1"/>
   </property>

   </bean>

   <bean  name="/demo"
          class="demopack.demoAction" >
             <property name="bean1">
                         <ref  bean="bean1"/>
              </property>
    </bean>

<bean id="datasource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">

   <property name="driverClassName">
       <value>sun.jdbc.odbc.JdbcOdbcDriver</value>
   </property>

   <property name="url">
       <value>jdbc:odbc:contacts</value>
   </property>

   <property name="username">
       <value>root</value>
   </property>

   <property name="password">
       <value></value>
   </property>

   </bean>

   <bean id="dsbean1" class="demopack.dsgetset">
      <property name="datasource"><ref bean="datasource"/></property>
   </bean>
</beans>


    Next important thing is referring beans.xml file through struts-config.xml
file. For that you need to to insert an additional tag  <plug-in> in struts
configuration file.

<form-bean   name="demoForm"  type="demopack.demoForm"   />
 </form-beans>

<action

            path="/demo"
            input="/demoInput.jsp"
            name="demoForm"
            type="org.springframework.web.struts.DelegatingActionProxy"
            scope="session"          
            validate="true"    >

           

            <forward name="success" path="/demoOutput.jsp" />
            <forward name="failure" path="/demoInput.jsp" />
     </action>

    </action-mappings>

<plug-in
         className="org.springframework.web.struts.ContextLoaderPlugIn">

      <set-property  property="contextConfigLocation"
                     value="/WEB-INF/beans.xml"/>
</plug-in>

</struts-config>