Developing Struts Application

If we are asked to give a very brief outline of Struts, we can enumerate the following points.

Developing Struts Application

Developing Struts Application

     

If we are asked to give a very brief outline of Struts, we can enumerate the following points.

  1. All requests are passed through a controller servlet, known as Action-servlet.
    This is achieved by suitable 'url-mapping' in web.xml file. We have been doing 'URL-pattern' in Tomcat4,when using servlets.
    And in j2ee webserver like Tomcat, this facilitates 'centralized-declarative change management', by editing the concerned XML files, without touching the source or class files of the servlets or Struts Actions...
  2.  All data submitted by user are sent to corresponding ActionForm. There are many actionforms but only one ActionServlet(because, it is the controller).
  3.  The ActionServlet, examines the source of request and extracts the data from specified actionform and sends it to a specified instance of Action class.(as specified in struts-config.xml).
  4. The action object carries out the business logic either directly or through helper classes , creates an instance of valuebean, populates this bean with data and sends the bean to the View JSP.( an instance of ActionForward).
  5. The important and distinctive feature of this arrangement is that the entire thing is done by 'Declarative-Management'.(and hence ActionMapping)
  6. Sometimes, the data submitted has to be validated and error messages , generated. (ActionErrors).
  7.  We use tags in input side and also for output view.(The input form also belongs to 'view' category in MVC.)( Struts-tags)
  8.  The details about the ActionServlet and other servlets if any ,in our application are given in web.xml
  9.  Details about various action classes,forms, action-forwards etc are given in struts-config.xml

---------------------------------------------

It is now the right time ( & 'high time' at that!)to take up a simple and practical example. Our focus in this tutorial is actual implementation. In an illustration,we should not introduce more than one 'unfamiliar' tool or concept. Many tutorials, bring in tools like 'Ant', 'Eclipse' etc, which have their own learning curve! Our aim is to avoid such things and yet develop a useful lesson.

--------------------------------------------

We use the following six files, in this demo, in that sequence too.

  1.  query.jsp
  2.  QueryForm.java(derived from ActionForm)
  3. QueryAction.java(derived from Action)
  4.  sqlbean.java ( a utility bean)
  5.  resultbean.java ( a value bean)
  6. result.jsp

( besides the web.xml & struts-config.xml files)

Where is the much-spoken-about ActionServlet?

That is provided by Struts Framework itself.

We do not subclass it, except for advanced work. It remains unobtrusively in the background , silently supervising things. As Ted Husted says, many developers leave it alone. The truth is that , we need hardly set our eyes on web.xml in this demo..or on the source code of ActionServlet.

-------------------------------------

In our example, the starting point is ' query.jsp', which is invoked by the URL, 'http://localhost:8080/sam/query.jsp'.The user fills up a form giving password and also an sql query.If the password is 'ADMINISTRATOR', the query is executed. Otherwise, the form is presented back to the user with the values already entered by him intact, so that he need not fill up the form again but needs to make only the required corrections. This is achieved by the FormBean. It is a Struts-specific class known as 'ActionForm'.

We provide, getter and setter methods for each of the controls in the form. In our example, these are 'password' and 'query'. We are also using struts-tags named as 'html' tags. (for simplicity, we are using simple text rather than password control).Note the taglib directive. This is not JSTL but Struts Tag Library. We should note the following very carefully. The name of the form is given as 'queryForm' & action is 'Query'. (the case is extremely important!).There is automatic conversion of action from 'Query' to 'Query.do'.

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

// query.jsp

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<html>
<body bgcolor=yellow>
This is query page
<br>
<html:form action="Query" name="queryForm" type="demo1.QueryForm">
Are you the Administrator?<br>
Your password please!<br>
<html:text property="password" />
<br>
query <br>
<html:text property="query"   
size="60" />
<br>
<html:submit />
</html:form>
</body>
</html>

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

Usually, in normal html forms, the control has a 'name' attribute. But in html:text, it is known as 'property'.
The corresponding formbean is given below.

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

All actions with extensions of '*.do', are automatically directed to the StrutsServlet(ie) ActionServlet. In the default web.xml file provided by the Struts application, the actionservlet is given 'URL-pattern' as '*.do'.( see web.xml)as given below.)

-------------------------------

(We need not type even a single line of web.xml. It is already available in the Struts application.) If the full file is printed here, it will only look forbidding. So, the relevant portion alone is shown here.ActionServlet configuration mentions the name of the servlet as 'action' and gives the fully qualified class-name of servlet.

This is followed by init-parameters section.where the 'config' param is indicated as 'struts-config.xml in WEB-INF folder of the application.(shown in bold).This is followed by servlet-mapping, as already mentioned.Finally, we have tag-library descriptors for struts custom-tag-libs like 'html','logic', 'bean' etc.

It is worth mentioning again that we do not have to type this file. It is equally important that we should not corrupt this file carelessly!
It is best left alone.

-------------------------------
 web.xml
===========================================

<?xml version="1.0" ....."?>
.......
.......
........  
<!-- Action Servlet Configuration -->
<servlet>
  <servlet-name>action</servlet-name>
  <servlet-class> 
      org.apache.struts.action.ActionServlet 
   </servlet-class>

<init-param> <param-name>config</param-name> <param-value> /WEB-INF/struts-config.xml</param-value> </init-param> ........ ........ ........  <!-- Standard Action Servlet Mapping -->
<servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> ........ ........ ........   <!-- Struts Tag Library Descriptors -->
<taglib> <taglib-uri>/tags/struts-bean</taglib-uri> <taglib-location>/WEB-INF/struts-bean.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-html</taglib-uri>
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
</taglib>
<taglib> <taglib-uri>/tags/struts-logic</taglib-uri> <taglib-location>/WEB-INF/struts-logic.tld</taglib-location> </taglib> .... ..... </web-app>

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

When the user submits the query.jsp, the formbean is automatically filled up with the values from the jsp-page and the flow goes to the ActionServlet.  

// QueryForm.java 

package demo1; 
import javax.servlet.http.*;
import org.apache.struts.action.*;

 public class QueryForm extends ActionForm
    {
          String password =null; 
          String query =null;

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

   public String getPassword()
           { return password;   }
  public void setPassword(String b)
             {  password=b;  }

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

 public String getQuery()
         {return query;}
  public void setQuery(String a)
          {query=a;}

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

  public void reset(ActionMapping mapping, HttpServletRequest request)
     {
	password=null;
	query=null;
 	 }
	}

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

In the struts-config.xml file, we make two entries. One entry is for the instance of QueryForm bean and the other entry is for the instance of QueryAction class.As the entry for 'query action' makes a reference to 'query form', let us first see the details of the entry for 'query form'.The struts-config.xml file in WEB-INF folder is created by us and is the nerve-center of customized functionality.

------------------------------------------

( this is the part dealing with the formbean)

<form-beans>
<form-bean  name="queryForm" type="demo1.QueryForm" /> 
</formbeans>

------------------------------------

This means that our formbean is named 'queryForm' and is available in demo1 subfolder of classes folder.(WEB-INF\classes\demo1\QueryForm.class)
Carefully note the name of the bean. It is the same name given in the instance of QueryForm class, as it appears in QueryAction.java, given separately.(all the authors follow uniform pattern of naming the bean. The class name begins with capital letter and the instance begins with lowercase).Since all these are inter-dependent, unless we are careful, we can never even get started with invoking the form!

-----------------------------------

The next segment of mapping in struts-config.xml deals with the action mapping for the instance of Action class, (ie) QueryAction.

<action-mappings>

<action path="/Query"  

       type="demo1.QueryAction"  

       name="queryForm"

       scope="session"
 
       input="/query.jsp" >
 <forward  name="success" 

 	path="/result1.jsp" />

<forward name="failure" 

	path="/query.jsp" />

</action>

</action-mappings>

----------------------------------------------------- 0

It means that the request comes from the path "/Query.do", the corresponding action class is QueryAction class in demo1 subfolder of classes folder of webserver.The input is coming from query.jsp. Finally, it says that the matching form to be used is 'queryForm'.

Therefore, the action class extracts the properties from queryForm and does some validation according to our code. If the user had correctly entered the password as 'ADMINISTRATOR', processing goes on.

(the code snippet from QueryAction.javais as given below).

------------------------------------------------- 1

QueryForm queryForm =(QueryForm) form;

String a = queryForm.getPassword();

String b = queryForm.getQuery();

if(a.equals("ADMINISTRATOR"))
{

---------------------------------------------

( Though, at first, the Struts code looks unfamiliar and frightening, on repeated reading and familiarity, it sounds like a song! Perhaps, the reason, why, users get addicted!)
Otherwise, the returned ActionForward in the action class is "failure" and we have mapped this string to query.jsp (ie) going back to the opening form itself! We must admit that , this declarative manipulation , is a really clever and inspired innovation, in flow management. By simply changing the entry in this struts-config file, the behaviour of the program can be easily changed.

 RequestDispatcher class instances are NOT explicitly mentioned anywhere, but the same effect is obtained. 2

The full code for QueryAction has been given below..

-----------------------------------------

// QueryAction.java 3

package demo1;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;

public class QueryAction extends Action
{
public ActionForward execute(ActionMapping mapping, ActionForm form,
       HttpServletRequest request,HttpServletResponse response)
       throws IOException, ServletException {
  		QueryForm queryForm =(QueryForm) form;
		String a = queryForm.getPassword();
		String b = queryForm.getQuery(); 
	if(a.equals("ADMINISTRATOR")) {
		System.out.println (" now in QueryAction ========");
		sqlbean bean1 = new sqlbean();
	// business delegation
		System.out.println("bean1 ready");
		String r= bean1.getresult(b);
 		System.out.println ("function invoked on bean1");
		System.out.println("value is..."+r);
		resultbean mathew = new resultbean();
 		System.out.println("mathew bean created");
		mathew.setValue(r);
		System.out.println ("value set for mathew");
  		String m = mathew.getValue();
 		System.out.println("verifying the value");
  		System.out.println(m);
 		System.out.println ("--------ok -------------");
  		HttpSession session=request.getSession();
  		session.setAttribute("result",mathew); 
 		System.out.println("attribute for 'result' set as mathew");
  		resultbean bean=(resultbean)session.getAttribute("result");
 		System.out.println(bean.toString());
		String v=bean.getValue();
		System.out.println("verifying...."+v);
		System.out.println ("now sending mathew to result.jsp");
		return (mapping.findForward("success"));
  		}else{
		return (mapping.findForward("failure"));
	    }
       }
 }

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

If the password is correct, the processing proceeds to create an instance of 'sqlbean'.

This type of delegating the work to a functionbean is the recommended practice. We are advised not to let the Action class itself do any business-processing directly. Instead we create an instance of functionbean and just invoke a method on it by passing the parameter and getting the return value. We illustrated the same method in the tutorial on MVC in the last edition too and so it should not be difficult to follow.

// sqlbean.java 4

package demo1;
import java.io.*;
import java.sql.*;

public class sqlbean {
  public String getresult(String sql) {
  String r = "";
  try
	{
	Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
	String url = "jdbc:odbc:dbdemo";
	Connection connection=DriverManager.getConnection(url);
	Statement statement=connection.createStatement();
	ResultSet rs = statement.executeQuery(sql);
   while(rs.next()) {
	String a = rs.getString(1);
	String b = rs.getString(2);
	r=r+a+"<br>"+b+"<br>"+"---------"+"<br>";
	}
  	}
	catch(Exception e1) {System.out.println(""+e1); }
  	return r;
     }
}

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

After getting the result from the utilitybean, the code creates an instance of valuebean known as 'resultbean'. This has just one property (ie) value. The name of this bean has been given as 'mathew'., just to make it standout from the crowd.And mathew's value is set as 'r'.

-------------------------------------------------------------- 5

// resultbean.java

package demo1;
	public class resultbean
	     {
		String value;
		public resultbean(){
		value=" ";
	   }
 
	public String getValue(){
		return value;
	   } 
	public void setValue(String v){
	value=v;
  }
}

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

We now create a session context( though, some authors frown upon it ), and set the session-attribute of "result" as mathew!
Thus, we are passing the bean itself to the destination (ie) result.jsp
In result.jsp, we have used just jsp-tags like <jsp:useBean....> and <jsp:getProperty..>
Carefully note the syntax. especially the 'id' and 'name'. The 'id' is NOT 'mathew' but 'result'!.
We just extract the value and automatically display it.Thus, we have met the stringent requirement that our view pages should be absolutely free from 'scriptlets'.

------------------------------------------

// result.jsp 6

<html>
<body bgcolor=orange>
<jsp:useBean  id="result" scope="session" class="demo1.resultbean" />
<jsp:getProperty name="result" property="value" />
<br>
ok here
</body>
</html>