Developing Struts Application
If we are asked to give a very brief outline of Struts, we can enumerate the following points.
- 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...
- All data submitted by user are sent to corresponding ActionForm. There are
many actionforms but only one ActionServlet(because, it is the controller).
- 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).
- 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).
- The important and distinctive feature of this arrangement is that the entire
thing is done by 'Declarative-Management'.(and hence
ActionMapping)
- Sometimes, the data submitted has to be validated and error messages ,
generated. (ActionErrors).
- We use tags in input side and also for output view.(The input form also
belongs to 'view' category in MVC.)( Struts-tags)
- The details about the ActionServlet and other servlets if any ,in our
application are given in web.xml
- 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.
- query.jsp
- QueryForm.java(derived from ActionForm)
- QueryAction.java(derived from Action)
- sqlbean.java ( a utility bean)
- resultbean.java ( a value bean)
- 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>