You may ask why I am using Ibatis instead of Hibernate. Let me tell you hibernate is damn good but if you have an existing system but you gotta improve that and it is on oracle ..then ibatis is the best.
In this article I would describe the architecture ,how to integrate all together and other good effective ways to do the pagination ,decoration ,validation etc.
Also I can show up some example and i can help you if you face any issues..
Why struts 2.
Struts 2 is an elegant extensible framework provides AOP, first class ajax, easy integration to spring etc.
In our application we can consider it as a front controller.All the requests come through the controller.
Its ajax support is really magnificent.It is bundled with dojo sx tags. We will be using dojo tags for the ajax.Instead of dojo , you can use the jquery, yahoo widget ,gwt etc.
But once you get familiar with one plugin it is almost same to use the rest.
Struts provides Aspect oriented programming via interceptors. There are many default interceptors for file uploading and downloading , double post , wait and exec ,validation etc.
I will show some samples ,rest you can refer the site.
Why spring
We use spring as enterprise architecture ,the core and the context.
Inversion of control , promotes the loosely coupled system.
Lets have look at the spring architecture:
To understanding spring architecture please refer http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/overview.html#overview-modules
Instead of the spring mvc, we use the struts 2 version ,as we discussed ,for better ajax,easy development ,easy flow etc.
Lets design our application structure
Struts 2 also provides junit for testing .
Lets go through the features...(I am assuming you at least know struts 1 or struts 2 flow)
Integrating DOJO plug-ins for ajax.
Step1: Add struts2-dojo-plugin-2.1.8.1.jar into the project lib
Step2: call this tags
<%@ taglib prefix="sx" uri="/struts-dojo-tags" >
<%@ taglib prefix="s" uri="/struts-tags" %>
That’s it. Now you will be free to use all the features of sx tags and s tags. The sx tag is the dojo ajax tag which is for the ajax calls. I will explain two basic ajax actions below. The s tag is a common tag for all struts 2 actions like jstl tags. You don’t need to use jstl tags here. Listen the s tags wont support expression language. It supports ognl. Don’t worry it is almost same as expression language.
A simple ajax call.
Purpose: load a select box from db using sx:tags.
There three sx tags that helpful to do this operation. Sx:bind,sx:div and sx:autocompleter.
Now we will look into sx:div.
In the jsp ,instead of normal div, we can use sx:div as I have shown below
<sx:div id="divCategory"
cssStyle="overflow: auto"
href="%{#url}"
loadingText="Loading"
showLoadingText="false"
indicator="loadingImage1" >
</sx:div><img id="loadingImage1" src="${pageContext.request.contextPath}/images/loading.gif" style="display:none"></TD>
And a url <s:url var="url" action="CategoryList" namespace="/ajaxcalls"></s:url>
The variable var=url and href="%{#url}" should be matched. When the page loads div call the url and calls the action in the action property action="CategoryList”
This is the action details in the struts.xml
<package name="ajaxcalls" namespace="/ajaxcalls" extends="struts-default" >
<action name="CategoryList" class="loginAction" method="getCategoryList">
<result >/pages/ajax/List.jsp</result>
</action>
In the List.jsp, just have a common select box.
<%
response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
%>
<s:select
name="catId"
id="catId"
list="map"
headerValue="All"
headerKey=""
onchange="dojo.event.topic.publish('/ event);"
>
</s:select>
This list="map" should be a map with key and values.
A simple ajax call.
Purpose: load a select box from db using sx:tags.
There three sx tags that helpful to do this operation. Sx:bind,sx:div and sx:autocompleter.
Now we will look into sx:div.
In the jsp ,instead of normal div, we can use sx:div as I have shown below
<sx:div id="divCategory"
cssStyle="overflow: auto"
href="%{#url}"
loadingText="Loading"
showLoadingText="false"
indicator="loadingImage1" >
</sx:div><img id="loadingImage1" src="${pageContext.request.contextPath}/images/loading.gif" style="display:none"></TD>
And a url <s:url var="url" action="CategoryList" namespace="/ajaxcalls"></s:url>
The variable var=url and href="%{#url}" should be matched. When the page loads div call the url and calls the action in the action property action="CategoryList”
This is the action details in the struts.xml
<package name="ajaxcalls" namespace="/ajaxcalls" extends="struts-default" >
<action name="CategoryList" class="loginAction" method="getCategoryList">
<result >/pages/ajax/List.jsp</result>
</action>
In the List.jsp, just have a common select box.
<%
response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
%>
<s:select
name="catId"
id="catId"
list="map"
headerValue="All"
headerKey=""
onchange="dojo.event.topic.publish('/ event);"
>
</s:select>
This list="map" should be a map with key and values.
Using sx:bind
<sx:bind href="%{#templatesUpURL}"
formId="frm"
listenTopics="/event"
loadingText="Loading..Please wait!" showLoadingText="true"
targets="divTemplate" indicator="loadingImage1"
beforeNotifyTopics="/beforeTemplateRequest"
afterNotifyTopics="/afterTemplateRequest"></sx:bind>
Whenever you change the select box ,dojo publish an event as ‘event’.
Our dojo sx:bind tags listen the event and invoke the url.There are many property to do actions before request and after request.Please go through the sx:bind.targets="divTemplate" is destination of this action. Means it updates the target div. process is same as the previous one.
Autocompleter using strust 2
This is one of the coolest features of dojo plugin with struts 2. You don’t need too much js methods for this autocomplete.
Step 1.
Use sx:autocomplete tags. The syntax are almost same as the sx:div. from the url ,it call an action .for example autocomplete
<package name="autocompleter" namespace="/autocompleter" extends="json-default">
<action name=" autocomplete" class="com.ge.example.actions. Autocomplete ">
<result name="input">/pages/jsp/dmsSearch.jsp</result>
<result type="json">
<param name="root">options</param>
</result>
</action>
</package>
<sx:bind href="%{#templatesUpURL}"
formId="frm"
listenTopics="/event"
loadingText="Loading..Please wait!" showLoadingText="true"
targets="divTemplate" indicator="loadingImage1"
beforeNotifyTopics="/beforeTemplateRequest"
afterNotifyTopics="/afterTemplateRequest"></sx:bind>
Whenever you change the select box ,dojo publish an event as ‘event’.
Our dojo sx:bind tags listen the event and invoke the url.There are many property to do actions before request and after request.Please go through the sx:bind.targets="divTemplate" is destination of this action. Means it updates the target div. process is same as the previous one.
Autocompleter using strust 2
This is one of the coolest features of dojo plugin with struts 2. You don’t need too much js methods for this autocomplete.
Step 1.
Use sx:autocomplete tags. The syntax are almost same as the sx:div. from the url ,it call an action .for example autocomplete
<package name="autocompleter" namespace="/autocompleter" extends="json-default">
<action name=" autocomplete" class="com.ge.example.actions. Autocomplete ">
<result name="input">/pages/jsp/dmsSearch.jsp</result>
<result type="json">
<param name="root">options</param>
</result>
</action>
</package>
step 2
In the action, you should have a method as I shown below.
In the action, you should have a method as I shown below.
public Map<String, String> getOptions() throws Exception {
Map bigMap=new HashMap();
bigMap=AjaxService.getDealList(tmp1) ;
return (Map<String, String>) bigMap;
}
}
That’s it.
Note:
May be you have to override the css for applying new style. If you face any issue in css, try this
.dojoComboBoxOptions {
font-family: Verdana, Helvetica, Garamond, sans-serif,Tahoma;
font-size: 10px;
width:100%;
background-color: white;
border: 1px solid #000000;
overflow: hidden;
cursor: default;
display:inline;
}
To get the key and value, you can try dojo.event.topic.subscribe("/name",function(event,widget)
{
var autoCompleter=dojo.widget.byId("dealName");
var dealId= autoCompleter.getSelectedKey();
var dealName= autoCompleter.getSelectedValue();
Please comment if you are facing any issues.
Some OGNL help
Struts2 came with a new expression language called Object Graph Notation language.
Since it wont allow regular EL with s:tags , we are force to use the OGNL but it is very easy.
For access session variables ,
<s:if test="#session.LoginUser!=null">
Lets think about variables with pagescope,
%{#attr.paramName}
Also you can push the value into the stack using set as shown
Map bigMap=new HashMap();
bigMap=AjaxService.getDealList(tmp1) ;
return (Map<String, String>) bigMap;
}
}
That’s it.
Note:
May be you have to override the css for applying new style. If you face any issue in css, try this
.dojoComboBoxOptions {
font-family: Verdana, Helvetica, Garamond, sans-serif,Tahoma;
font-size: 10px;
width:100%;
background-color: white;
border: 1px solid #000000;
overflow: hidden;
cursor: default;
display:inline;
}
To get the key and value, you can try dojo.event.topic.subscribe("/name",function(event,widget)
{
var autoCompleter=dojo.widget.byId("dealName");
var dealId= autoCompleter.getSelectedKey();
var dealName= autoCompleter.getSelectedValue();
Please comment if you are facing any issues.
Some OGNL help
Struts2 came with a new expression language called Object Graph Notation language.
Since it wont allow regular EL with s:tags , we are force to use the OGNL but it is very easy.
For access session variables ,
<s:if test="#session.LoginUser!=null">
Lets think about variables with pagescope,
%{#attr.paramName}
Also you can push the value into the stack using set as shown
s:set var="abc" value="propertyName"
if it is a bean , you can access the bean values as
%{#abc.name}
Will be explaining some interesting facts of OGNL later…
What is an interceptor?
Well before moving into interceptors, I would like to introduce Sitemesh.
Sitemesh
• Sitemesh is a web-page layout and decoration framework and web- application integration framework to aid in creating large sites consisting of many pages for which a consistent look/feel, navigation and layout scheme is required.
Integrating into struts 2
Step I:
<filter><!-- integration of sitemesh plugins -->
<filter-name>struts-prepare</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter</filter-class>
</filter>
<filter><!-- integration of sitemesh plugins -->
<filter-name>struts-execute</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter</filter-class>
</filter>
<filter><!-- integration of sitemesh plugins -->
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts-prepare</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>struts-execute</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Step 2:
Copy the Sitemesh.xml or add this into the file
<sitemesh>
<property name="decorators-file" value="/WEB-INF/decorators.xml"/>
<excludes file="${decorators-file}"/>
<page-parsers>
<parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
</page-parsers>
<decorator-mappers>
<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
<param name="property.1" value="meta.decorator"/>
<param name="property.2" value="decorator"/>
</mapper>
<mapper class="com.opensymphony.module.sitemesh.mapper.FrameSetDecoratorMapper">
</mapper>
<mapper class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper">
<param name="match.MSIE" value="ie"/>
<param name="match.Mozilla [" value="ns"/>
<param name="match.Opera" value="opera"/>
<param name="match.Lynx" value="lynx"/>
</mapper>
<mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
<param name="decorator" value="printable"/>
<param name="parameter.name" value="printable"/>
<param name="parameter.value" value="true"/>
</mapper>
<mapper class="com.opensymphony.module.sitemesh.mapper.RobotDecoratorMapper">
<param name="decorator" value="robot"/>
</mapper>
<mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
<param name="decorator.parameter" value="decorator"/>
<param name="parameter.name" value="confirm"/>
<param name="parameter.value" value="true"/>
</mapper>
<mapper class="com.opensymphony.module.sitemesh.mapper.FileDecoratorMapper">
</mapper>
<mapper class="org.apache.struts2.sitemesh.NoneDecoratorMapper">
</mapper>
<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
<param name="config" value="${decorators-file}"/>
</mapper>
</decorator-mappers>
</sitemesh>
Look at the first line,it is very important value="/WEB-INF/decorators.xml"/>
In the decorators, we can exclude the request that we don’t want Sitemesh anymore.
<?xml version="1.0" encoding="ISO-8859-1"?>
<decorators defaultdir="/WEB-INF/decorators">
<!-- Any urls that are excluded will never be decorated by Sitemesh -->
<decorator name="main" page="main.jsp">
<pattern>/*</pattern>
</decorator>
<excludes>
<pattern>/start.action</pattern>
<pattern>/ajaxcalls/*</pattern>
<pattern>/autocompleter/*</pattern>
<pattern>/CategoryList.jsp</pattern>
</excludes>
<decorator name="panel" page="panel.jsp"/>
</decorators>
Since we specified the default directory as <decorators defaultdir="/WEB-INF/decorators">
The default directory will be decorators under web-inf.
Step 3:
Lets have a look at main.jsp
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.d
<%@taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>
<%@taglib prefix="page" uri="http://www.opensymphony.com/sitemesh/page" %>
<%@taglib prefix="s" uri="/struts-tags" %>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><decorator:title default=" Web Application"/></title>
<decorator:head/>
</head>
<body topmargin="0" leftmargin="0" >
<div id="body" class="main" >
<div id="header">
<table border="0" width="100%" cellspacing="0" t>
<tr border="0" >
<td width="25%" style="width: 89px"><img border="0" src="<%=request.getContextPath()%>/images/header.JPG"></td><td style="width: 664px">
<table border="0">
<tr>
<td style="width: 86px"></td>
<td valign="bottom" class="welcome">
</td><td valign="bottom" class="header" >
</td>
</tr>
<tr>
<td style="width: 86px"></td>
<td valign="bottom" class="welcome">
Welcome Back :
</td><td valign="bottom" class="header" >
<s:if test="#session.User.firstName neq null " >
<s:property value="#session.User.firstName"/> <s:property value="#session.User.lastName"/>
</s:if>
<s:else>
<s:property value=" User'"/>
</s:else>
</td>
</tr>
<tr>
<td valign="bottom">
</td><td></td>
</tr>
</table>
</td>
<td align="right" style="width: 153px"><img border="0" src="<%=request.getContextPath()%>/images/search.jpg"></td>
</tr >
<TR >
<TD width="100%" colspan="3" height="25px" style="background-image: url('<%=request.getContextPath()%>/images/GreenBar-center.png')"></TD>
</TR>
</table>
</div>
<div id="main" style="width:100%;height:100%;" >
<table width="100%" height="100%" border="1">
<tr>
<td width="10%" valign="top" style="border-left:1px solid #599CD4;border-right:thick solid #BCBDD8; background-color: #599CD4;">
<page:applyDecorator page="/WEB-INF/decorators/tiny-panel.jsp" name="panel" />
</td>
<td width="99%" valign="top" >
<table width="100%" height="100%" >
<tr>
<td class="bodyTitle" width="100%" align="center" >
<decorator:title />
</td>
</tr>
<tr>
<td valign="top" height="100%" width="100%">
<decorator:body />
</td>
</tr>
</table>
</td>
</tr>
</table>
<div id="footer" class="h15-footer" >
<table width="100%" height="100%" >
<tr>
<td align="left"> <span >© 2010 ABC .All Rights Reserved. </span></td>
<td align="right">
</table>
</div>
</div>
</div>
</body>
</html>
Come back to interceptors…
The below link is the best place to know more about interceptors.
https://cwiki.apache.org/WW/interceptors.html
First you go through the theory. I will explain one use of interceptor below. Consider a situation where your clients want a wait page while executing an action. Yes of course you can use js for that, kind of cheating the user. What if your framework provides a feature for that….
That is called execAndWait
Step1.
Write a action like <action name="action" class="your class name" method="method" >
<interceptor-ref name="basicStack"/>
<interceptor-ref name="execAndWait">
<param name="delay">2000</param>
</interceptor-ref>
<result name="wait">/pages/jsp/wait.jsp</result>
<result name="success" >/pages/jsp/edit.jsp</result>
</action>
Step2:
Add a wait.jsp in the mentioned path.
Step 3:
Add the below content to the jsp page.
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Please wait</title>
</script>
<meta http-equiv="refresh" content="10;url=<s:url />" />
</head>
<body >
<br><br>
<div style="height:100px" >
<img alt="loading please wait" src="${pageContext.request.contextPath}/images/loading1.gif">
<font color="black" face="arial" size="2"><b>Please wait while we process your request.
</b></font>
</div>
<div id="rest" style="position:absolute;right:;top:;width:400;background-color:#93AEfefe; visibility:visible">
<font color="black" face="arial" size="2"> <br><br><br><br><br><br><br> <b>Click <a href="<s:url />">Refresh</a> if this page does not
reload automatically.
</div>
</body>
</html>
There are many other interceptor features like validations, double post elimination, file upload, page preparation, and more
Be careful while combining many interceptors together like file uploading and wait page. I got an error. It is a bug. If someone overcame that pls let me know.
Validation
Why don’t you check https://cwiki.apache.org/WW/basic-validation.html. It is so easy. As I told you, my intention is to help you when you get stuck somewhere.
Will come with more...
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.d
<%@taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>
<%@taglib prefix="page" uri="http://www.opensymphony.com/sitemesh/page" %>
<%@taglib prefix="s" uri="/struts-tags" %>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><decorator:title default=" Web Application"/></title>
<decorator:head/>
</head>
<body topmargin="0" leftmargin="0" >
<div id="body" class="main" >
<div id="header">
<table border="0" width="100%" cellspacing="0" t>
<tr border="0" >
<td width="25%" style="width: 89px"><img border="0" src="<%=request.getContextPath()%>/images/header.JPG"></td><td style="width: 664px">
<table border="0">
<tr>
<td style="width: 86px"></td>
<td valign="bottom" class="welcome">
</td><td valign="bottom" class="header" >
</td>
</tr>
<tr>
<td style="width: 86px"></td>
<td valign="bottom" class="welcome">
Welcome Back :
</td><td valign="bottom" class="header" >
<s:if test="#session.User.firstName neq null " >
<s:property value="#session.User.firstName"/> <s:property value="#session.User.lastName"/>
</s:if>
<s:else>
<s:property value=" User'"/>
</s:else>
</td>
</tr>
<tr>
<td valign="bottom">
</td><td></td>
</tr>
</table>
</td>
<td align="right" style="width: 153px"><img border="0" src="<%=request.getContextPath()%>/images/search.jpg"></td>
</tr >
<TR >
<TD width="100%" colspan="3" height="25px" style="background-image: url('<%=request.getContextPath()%>/images/GreenBar-center.png')"></TD>
</TR>
</table>
</div>
<div id="main" style="width:100%;height:100%;" >
<table width="100%" height="100%" border="1">
<tr>
<td width="10%" valign="top" style="border-left:1px solid #599CD4;border-right:thick solid #BCBDD8; background-color: #599CD4;">
<page:applyDecorator page="/WEB-INF/decorators/tiny-panel.jsp" name="panel" />
</td>
<td width="99%" valign="top" >
<table width="100%" height="100%" >
<tr>
<td class="bodyTitle" width="100%" align="center" >
<decorator:title />
</td>
</tr>
<tr>
<td valign="top" height="100%" width="100%">
<decorator:body />
</td>
</tr>
</table>
</td>
</tr>
</table>
<div id="footer" class="h15-footer" >
<table width="100%" height="100%" >
<tr>
<td align="left"> <span >© 2010 ABC .All Rights Reserved. </span></td>
<td align="right">
</table>
</div>
</div>
</div>
</body>
</html>
Come back to interceptors…
The below link is the best place to know more about interceptors.
https://cwiki.apache.org/WW/interceptors.html
First you go through the theory. I will explain one use of interceptor below. Consider a situation where your clients want a wait page while executing an action. Yes of course you can use js for that, kind of cheating the user. What if your framework provides a feature for that….
That is called execAndWait
Step1.
Write a action like <action name="action" class="your class name" method="method" >
<interceptor-ref name="basicStack"/>
<interceptor-ref name="execAndWait">
<param name="delay">2000</param>
</interceptor-ref>
<result name="wait">/pages/jsp/wait.jsp</result>
<result name="success" >/pages/jsp/edit.jsp</result>
</action>
Step2:
Add a wait.jsp in the mentioned path.
Step 3:
Add the below content to the jsp page.
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Please wait</title>
</script>
<meta http-equiv="refresh" content="10;url=<s:url />" />
</head>
<body >
<br><br>
<div style="height:100px" >
<img alt="loading please wait" src="${pageContext.request.contextPath}/images/loading1.gif">
<font color="black" face="arial" size="2"><b>Please wait while we process your request.
</b></font>
</div>
<div id="rest" style="position:absolute;right:;top:;width:400;background-color:#93AEfefe; visibility:visible">
<font color="black" face="arial" size="2"> <br><br><br><br><br><br><br> <b>Click <a href="<s:url />">Refresh</a> if this page does not
reload automatically.
</div>
</body>
</html>
There are many other interceptor features like validations, double post elimination, file upload, page preparation, and more
Be careful while combining many interceptors together like file uploading and wait page. I got an error. It is a bug. If someone overcame that pls let me know.
Validation
Why don’t you check https://cwiki.apache.org/WW/basic-validation.html. It is so easy. As I told you, my intention is to help you when you get stuck somewhere.
Will come with more...