|
Developing Struts Application
If we are asked to give a very
brief outline of Struts, we can enumerate the following
points.
i) 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...
ii) All data submitted by user
are sent to corresponding ActionForm.There are many actionforms but only
one ActionServlet(because, it is the controller).
iii) 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).
iv) 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).
v) The important and distinctive
feature of this arrangement is that the entire thing is done by
'Declarative-Management'.(and hence
ActionMapping)
vi) Sometimes, the data submitted
has to be validated and error messages , generated.
(ActionErrors).
vii) We use tags in input side and
also for output view.(The input form also belongs
to 'view' category in MVC.)( Struts-tags)
viii) The details about the ActionServlet and
other servlets if any ,in our application are given in
web.xml
ix) 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.
i)
query.jsp
ii) QueryForm.java(derived from
ActionForm)
iii)QueryAction.java(derived from
Action)
iv)
sqlbean.java ( a utility bean)
v)
resultbean.java ( a value bean)
vi)
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 sourcecode 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>
-------------------------------------
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.java
is as given
below).
---------------------------------------------
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.
The full code for QueryAction
has been
given
below..
------------------------------------------
-
//
QueryAction.java
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
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'.
---------------------------------------
//
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
<html>
<body
bgcolor=orange>
<jsp:useBean id="result" scope="session" class="demo1.resultbean" />
<jsp:getProperty name="result" property="value"
/>
<br>
ok
here
</body>
</html>
=====================================
|