You are on page 1of 76

Presentation on Struts 2

Developed by Zackriya
Whats struts?
• Struts is a well-organized framework based on MVC architecture

• Apache Struts is an open-source framework that is used for developing


Java web application

• Provided an excellent framework for developing application easily by


organizing JSP and Servlet based on HTML formats and Java code.
Why struts 2.0
• Programming the abstract classes instead of interfaces is one of design problem of struts1
framework that has been resolved in the struts 2 framework

• Simplified Actions - Actions are simple POJOs. Any java class with execute() method can be
used as an Action class.

• No more ActionForms - ActionForms feature is no more known to the struts2 framework.

• Struts 2 Actions are HTTP independent

• Intelligent Defaults - Most configuration elements have a default value which can be set according
to the need

• Better Tag features

• Annotations introduced : Applications in struts 2 can use Java 5 annotations as an alternative to


XML and Java properties configuration.

Struts 1 vs 2
Servlet Dependency: Actions in Struts1 have dependencies on the servlet API since the
HttpServletRequest and HttpServletResponse objects are passed to the execute method when an
Action is invoked but in case of Struts 2, Actions are not container dependent because they are
made simple POJOs.

• Action classes: Programming the abstract classes instead of interfaces is one of design issues of
struts1 framework that has been resolved in the struts 2 framework

• Threading Model: In Struts1, Action resources must be thread-safe or synchronized, there should
only be one instance of a class to handle all requests for that Action. In Struts 2, Action objects are
instantiated for each request, so there are no thread-safety issues.

• Harvesting inputs

• Expression Language: Struts1 integrates with JSTL. Struts 2 can also use JSTL, however it
supports a more powerful and flexible expression language called "Object Graph Notation
Language" (OGNL).
• Type Conversion
CONTROLLER- Filter Dispatcher
• The role of the controller is played by the Struts 2
FilterDispatcher

• Is a servlet filter that inspects each incoming request to


determine which Struts 2 action should handle the
request

• The framework handles all of the controller work

• Just need to inform the framework which request URLs


map to which of your actions.

• Two ways of informing the framework – XML and Java


Annotation
Way to inform the framework
XML:

<action name="Login" class="manning.Login">


<result>/AccountPage.jsp</result>
<result name="input">/Login.jsp</result>
</action>

Java Annotation:

@Results({
@Result(name="input", value="/Login.jsp" )
@Result(value="/AccountPage.jsp" )
})
public class Login implements Action {
public String execute() {
//Business logic for login
}
}
Way to inform the framework.. contd
Model - Action
• Struts 2 action serves two roles

• First, an action is an encapsulation of the calls to


business logic into a single unit of work.

• Second, the action serves as a locus of data


transfer.

• The controller hands over control of the request


processing to the action by invoking it

• When the action completes its work, it’ll render


a view back to the user who submitted the
request, by forward the result to the Struts 2
view component
View - Result
• The view is the presentation component of the
MVC pattern

• The role of the view is clear-cut: it translates the


state of the application into a visual presentation
with which the user can interact.

• Presentation can be represented by JSP or some


other presentation layer technology
View - Result
• The view is the presentation component of the
MVC pattern

• The role of the view is clear-cut: it translates the


state of the application into a visual presentation
with which the user can interact.

• Presentation can be represented by JSP or some


other presentation layer technology
How Struts 2 works
Interceptors
• Interceptor allows common, cross-cutting
tasks to be defined in clean, reusable
components that you can keep separate
from your action code.

• Interceptors are Struts 2 components that


execute both before and after the action

• Logging is a typical cross-cutting


scenario.
ValueStack and OGNL
• ValueStack is a storage area that holds all
of the data associated with the processing
of a request

• Rather than passing the data around,


Struts 2 keeps it in a convenient, central
location—the ValueStack

• OGNL is the tool that allows us to access


the data we put in that central repository

• OGNL is an expression language that allows


you to reference and manipulate the data
on the ValueStack
Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<filter>
<filter-name>struts2</filter-name>
<filter-
class>org.apache.struts2.dispatcher.FilterDispatcher</filter
-class> </filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts
Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
<package name="default" namespace="/"
extends="struts-default">
<action name="Menu">
<result>/menu/Menu.jsp</result>
</action>
</package>
<include
file="manning/demoWorld/demoWorld.xml"/>
</struts>
demoWorld.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC….>
<struts>
<package name="demoWorld"
namespace="/demoWorld" extends="struts-default">
<action name="Name">
<result>/demoWorld/NameCollector.jsp</result>
</action>

<action name="HelloWorld"
class="manning.demoWorld.HelloWorld">
<result
name="SUCCESS">/demoWorld/HelloWorld.jsp</res
ult>
</action>
</package>
</struts>
Menu.jsp
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Struts 2 in Action: Menu</title>
</head>

<body>
<hr>
<ul>
<li><a href="<s:url
action='demoWorld/Name'/>">HelloWorld</a></li>
</ul>
<hr>
</body>

</html>
struts.xml
NameCollector.jsp
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>

<head>
<title>Name Collector</title>
</head>

<body>
<hr>
<h4>Enter your name so that we can customize a
greeting just for you!</h4>
<s:form action="HelloWorld">
<s:textfield name="name" label="Your name"/>
<s:submit/>
</s:form>
<hr>
</body>
</html>
HelloWorld.jsp
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>HelloWorld</title>
</head>

<body>

<hr>
<h3>Custom Greeting Page</h3>
<h4><s:property value="customGreeting"/></h4>
<hr>
</body>

</html>
ValueStack as a repository
HelloWorld.java

D:\Tomcat 5.0\
webapps\HelloWorld\WEB-INF
Directory structure
Action in detail
Action encapsulates the unit of work through the
execute() method
Action – Data Transfer
• Request parameters from the form are moved to properties that
have matching names.

• In addition to receiving the incoming data from the request, these


JavaBeans properties on the action will also expose the data to the
result.
Action – result routing
The final duty of an action component is to return a control string that
selects the result that should be rendered.

<action name="HelloWorld" class="manning.demoWorld.HelloWorld">


<result name="SUCCESS">/demoWorld/HelloWorld.jsp</result>
<result name=“ERROR">/demoWorld/Error.jsp</result>
</action>
Packaging your actions

• name attribute is merely a logical name by which you can reference


the package

<package name="demoWorld" namespace="/demoWorld"


extends="struts-default">
<action name="Name">
<result>/demoWorld/NameCollector.jsp</result>
</action>
Packaging your actions…contd
• The namespace attribute is used to generate the URL namespace to
which the actions of these packages are mapped.

• When a URL arrives as


http://localhost:8080/HelloWorld/demoWorld/Name.action, the
framework consults the /demoWorld namespace for the action named
Name

<package name="demoWorld" namespace="/demoWorld"


extends="struts-default">
<action name="Name">
<result>/demoWorld/NameCollector.jsp</result>
</action>
Packaging your action (extends attribute)
• “extends” is similar to extends keyword in java

• “extends” attribute names another package whose components


should be inherited by the current package.

<package name="demoWorld" namespace="/demoWorld"


extends="struts-default">
<action name="Name">
<result>/demoWorld/NameCollector.jsp</result>
</action>
Packaging your action (extends attribute)
• The struts-default package, defined in the system’s struts-
default.xml file, declares a huge set of commonly needed Struts 2
components ranging from complete interceptor stacks to all the
common result types.

• Params interceptor has been the one moving data from request
parameters to our action’s JavaBean properties
Validation through Action
• Action to extend ActionSupport class to provide
validation

• workflow interceptor to be called after param


interceptor

• workflow interceptor first looks for a validate()


method on the action to invoke.

• If data doesn’t validate, create and store the


error in addFieldError() method provided by
ActionSupport class

• After execution of validate() method control


goes back to the workflow interceptor
Validation through Action
• workflow interceptor will check if any error
messages were generated

• If errors are found, then request processing is


aborted and control returns back to the input
form, where the appropriate error message will
be displayed

• The control will go to a page where name


attribute of result tag has “input” as the value

<result name="input">/demoWorld/NameCollector.jsp</result>
Validation code…
demoWorld.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ….">

<struts>
<package name="demoWorld" namespace="/demoWorld"
extends="struts-default">
…..
<action name="HelloWorld"
class="manning.demoWorld.HelloWorld">
<result>/demoWorld/HelloWorld.jsp</result>
<result
name="input">/demoWorld/NameCollector.jsp</result>
</action>
</package>
</struts>
Validation code…

Validation_Demo
Interceptors
The framework creates an object called an ActionInvocation that
encapsulates the action and all of the interceptors that have been
configured to fire before and after that action executes
Interceptor invocation
• First url mapping

• Create an object of the action and store it inside


ActionInvocation object.

• Checks the extends property and sees the sequence


of interceptor invocation in that xml

• References to that interceptors are add in the


ActionInvocation

• ActionInvocation also stores references to the request


object and map of the results available to the action.
Interceptor invocation… contd
How the interceptor fires
• Framework calls the invoke() method of ActionInvocation,
ActionInvocation consults its state and executes whichever
interceptor come next

• Invoke() method calls the Interceptors intercept() method


which takes ActionInvocation as the parameter.

• intercept() calls the ActionInvocation.invoke() method


inside, ActionInvocation consults its state and executes
whichever interceptor comes next.

• Again invoke() method will call the intercept() method of


the next Interceptors

• When all the interceptors() have been invoked, the


invoke() method will cause the action itself to be executed.
Interceptor invocation… contd

• In normal execution, the invocation process


tunnels down through all of the interceptors
until, finally, there are no more interceptors in
the stack and the action fires.

• ActionInvocation itself maintains the state of this


process internal so it always knows where it is
in the stack.
Interceptor invocation… contd

What does interceptor() do internally

1. Do some preprocessing
2. Pass control on to successive interceptors, and
ultimately the action, by calling invoke(), or divert
execution by itself returning a control string.
3. Do some postprocessing
Interceptor invocation… contd

intercept() method of the TimerInterceptor, one


of the interceptors

public String intercept(ActionInvocation


invocation) throws Exception {
long startTime =
System.currentTimeMillis();
String result = invocation.invoke();
long executionTime =
System.currentTimeMillis() - startTime;
... log the time ...
return result;
}
Interceptors - Timer

• This simple interceptor merely records the duration of


an execution

• If you place this interceptor at the heart of your stack,


just before the action, then it will time the action’s
execution itself

• If you place it at the outermost layer of the stack, it’ll


time the execution of the entire stack, as well as the
action

Output:
INFO: Executed action [/manning/demoWorld/HelloWorld] took 123
ms
Interceptors - Logger

• This interceptor provides a simple logging


mechanism that logs an entry statement during
preprocessing and an exit statement during
postprocessing

Output:
INFO: Starting execution stack for action
/manning/demoWorld/HelloWorld
INFO: Finishing execution stack for action
/manning/demoWorld/HelloWorld

• This interceptor serves as a good demonstration of


an interceptor that does processing both before and
after the action executes.
Interceptors - Params
• It transfers the request parameters to properties
exposed by the ValueStack

• To enable this transfer, the developer needs only to


provide JavaBeans properties on her actions, using
the same names as the form fields being submitted

• When Struts 2 receives a request, it immediately


creates an ActionContext, a ValueStack, and an
action object.

• As a carrier of application data, the action object is


quickly placed on the ValueStack so that its
properties will be accessible, via OGNL, to the far
reaches of the framework(eg: incoming form
prepopulation and for result rendering)
Interceptors – params… contd

•The params interceptor doesn’t know where the data


is ultimately going; it just moves it to the first
matching property it can find on the ValueStack

•There’s only one tricky bit about the ValueStack. The


ValueStack pretends to be a single object when
OGNL expressions are resolved against it

•If multiple occurrences of the same property exist,


those lowest down in the stack are hidden by the
uppermost occurrence of a similarly named property.
Interceptors – params… contd
• So how do the right objects get onto the ValueStack in time
to receive the data transfer?

• Since the action is always put on the ValueStack at the start


of a request-processing cycle, the action will be placed at the
top and any request for a action property will be fetched
since it will be at the top of the valuestack
Interceptors - STATIC-PARAMS
• This interceptor also moves parameters onto properties
exposed on the ValueStack

• The difference is the origin of the parameters

• The parameters that this interceptor moves are defined in the


action elements of the declarative architecture

eg:
<action name="exampleAction"
class="example.ExampleAction">
<param name="firstName">John</param>
<param name="lastName">Doe</param>
</action>

• These parameters are moved onto the ValueStack. In the


defaultStack, the static-params interceptor fires before the
params interceptor. This means that the request parameters
will override values from the XML param element. You could, of
course, change the order of these interceptors.
Interceptors - Workflow
• It works with our actions to provide data validation and
subsequent workflow alteration if a validation error occurs.

public String intercept(ActionInvocation invocation)


throws Exception {
Action action = invocation.getAction();
if (action instanceof Validateable) {
Validateable validateable = (Validateable) action;
validateable.validate();
}
if (action instanceof ValidationAware) {
ValidationAware validationAwareAction =
ValidationAware) action;
if (validationAwareAction.hasErrors()) {
return Action.INPUT;
}
}
return invocation.invoke();
}
Interceptors – workflow…contd
•If the action has implemented the Validateable interface,
the interceptor will invoke its validate() method to
execute the action’s validation logic

•If the action implements the ValidationAware interface,


the interceptor will check to see whether any errors were
created by the validation logic by calling the hasErrors()
method

•If some are present, the workflow interceptor takes the


rather drastic step of completely halting execution of the
action. It does this by returning its own INPUT control
string

•Further execution stops immediately. The INPUT result is


rendered, and postproc essing occurs as control climbs
back out of the interceptor stack
Calling method apart from execute() as default
-
Change in demoWorld.xml
<action name="HelloWorld_*" method="{1}"
class="manning.demoWorld.HelloWorld">
<result>/demoWorld/HelloWorld.jsp</result>
<result
name="input">/demoWorld/NameCollector.jsp</res
ult>
</action>
Change in NameCollector.jsp
<s:form action="HelloWorld_edit">
<s:textfield name="name" label="Your
name"/>
<s:submit/>
</s:form>
Interceptors - Exception
• The exception interceptor comes first in the
defaultStack, and should probably come first in any
custom stacks you create yourself

<global-results>
<result name="error2">/menu/Menu.jsp</result>
<result name="error1">/index2.html</result>
</global-results>
<global-exception-mappings>
<exception-mapping
exception="java.lang.NullPointerException"
result="error1"/>
<exception-mapping
exception="java.lang.Exception" result="error2"/>
User defined Interceptors
public class CapsInterceptor implements Interceptor {

public void destroy() { }


public void init() { }

public String intercept( ActionInvocation actionInvocation )


throws Exception {
Action action = ( Action ) actionInvocation.getAction();
if(action instanceof HelloWorld)
{
String name = ((HelloWorld)action).getName();
name = name.toUpperCase();
((HelloWorld)action).setName(name);
}
System.out.println("CapsInterceptor in: interceptor");
return actionInvocation.invoke();
}

}
User defined Interceptors…contd

Changes in demoWorld.xml

<interceptors>
<interceptor name="capsInterceptor"
class="manning.demoWorld.CapsInterceptor" />

<interceptor-stack name="myinterceptor">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="capsInterceptor" />

</interceptor-stack>

</interceptors>
<default-interceptor-ref name="myinterceptor" />
OGNL

• OGNL stands for Object-Graph Navigation Lanugage.

• Its integrated with Struts 2 framework to help with data


transfer and type conversion.

• Acts as a glue between the framework’s string-based HTTP


input and output and the Java-based internal processing

• OGNL consists of two things: an expression language and type


converters
OGNL – Expression Language
• Binds Java-side data properties to strings in the text-
based view layers, commonly found in the name
attributes of form input fields, or in various attributes of
the Struts 2 tags.

Eg:
<h5>Congratulations! You have created </h5>
<h3>The <s:property value=“phoneNumber" />
Portfolio</h3>

• This Struts 2 property tag takes a value from a property


on one of our Java objects and writes it into the HTML in
place of the tag

•The simplicity of the expression language makes for a


ridiculously low learning curve
OGNL - Type Converters
OGNL - Type Converters

• Even in this simple case of the Struts 2 property tag in the view
side, a conversion must be made from the Java type of the
property referenced by the OGNL expression language to the
string format of the HTML output.

• Struts 2 framework provides adequate built-in OGNL type


converters

• OGNL first needs a context in which to search for its targets.

• Framework automatically transfers parameters to our action


object, the action is sitting on something called the ValueStack

• User object is exposed as a JavaBeans property on our action


object
OGNL - Type Converters .. contd
• params interceptor will move the data from the request
object to the ValueStack

• params interceptor interprets the request parameter name


as an OGNL expression to locate the correct destination
property on the ValueStack

• Once the OGNL expression has been used to locate the


destination property, the data can be moved onto that
property by calling the property’s setter with the correct
value.
OGNL - Type Converters … contd

• At this point, the original value in request is still the String “37”
for age, here’s where the type converters come into play.

• For this OGNL will consult its set of available type converters to
see if any of them can handle this particular conversion.

• Data out - procedure


Mapping of field names to properties
via OGNL
• <s:textfield name="user.username" label="Username"/>

Part of Action class User Class


private User user;
public User getUser() { public class User {
return user; private String username;
} public String getUsername() {
public void setUser(User user) { return username;
this.user = user; }
} public void setUsername(String
username) {
this.username = username;
}}
Mapping of field names
Arrays Action class implementation
<s:form
action="ArraysDataTransferTest" private Double[] ages ;
> public Double[] getAges() {
<s:textfield name="ages" return ages;
label="Ages"/>
}
<s:textfield name="ages"
label="Ages"/> public void setAges(Double[] ages) {
<s:textfield name="ages" this.ages = ages;
label="Ages"/> }
<s:textfield name="names[0]" private String[] names = new String[10];
label="names"/> public String[] getNames() {
<s:textfield name="names[1]" return names;
label="names"/> }
<s:textfield name="names[2]" public void setNames(String[] names) {
label="names"/>
this.names = names;
<s:submit/>
}
</s:form>
Mapping of Array properties
• The ages property is an array of element type Double. OGNL sees
this and automatically runs its type conversion for each element of the
array.

• The ages property the framework will create an array for us, so we
don’t need to initialize

• For names property we need to initialize the array with a size since
the OGNL expressions are targeting individual elements of an existing
array.

<h5>Congratulations! You have transferred and converted data to and


from Arrays.</h5>
<h3>Age number 3 = <s:property value="ages[2]" /> </h3>
<h3>Name number 3 = <s:property value="names[2]" /> </h3>
Mapping of List properties
• You don’t have preinitialize any of your Lists, even the ones that’ll
receive data from the indexed OGNL notation.

• Without any specification, the elements of these Lists will be


of String objects.

<s:form action=“ListDataTransferTest">
<s:textfield name="ages" label="Ages"/>
<s:textfield name="ages" label="Ages"/>
<s:textfield name="ages" label="Ages"/>
<s:textfield name="names[0]" label="names"/>
<s:textfield name="names[1]" label="names"/>
<s:textfield name="names[2]" label="names"/>
<s:submit/>
</s:form>
Mapping of List properties… contd
• If List need to handle non-string property, we need to define the non
string mapping in a properties file.

• The file need to follow the below syntax

•If the Action file is ListDataTransferTest then the property file should be
ListDataTransferTest-conversion.properties and place this file in the classpath

• If we want to tell OGNL that we want “Double” type of element in our List
property, add the below line in the properties file
•Elements
Mapping of List properties… contd

<s:textfield name="weights[0]" label="weights"/>


<s:textfield name="weights[1]" label="weights"/>
<s:textfield name="weights[2]" label="weights"/>

• If we want to tell OGNL that weights property should be converted to


“Double” type add the below line in the properties file

Element-weights=java.lang.Double
Control Tags

index.jsp index.jsp

demoTag.xml Demotag.xml

IfControlTag.jsp IfControlTag.jsp
Append Tag
The append tag is a generic tag that is used to merge multiple
iterators into one iterator

AppendTag.java AppendTag.jsp

AppendTag.java AppendTag.jsp
UI tag: textfield

Including a file: <s:include value="myBirthday.jsp" />

TextField tag:

<%@ taglib prefix="s" uri="/struts-tags" %>
 <h1><span style="background-color
: #FFFFcc">Textfield Tag Example!</span></h>
  <s:form>
    <s:textfield label="Employee Name" name="empname" size="15" 
maxlength="10" />
  </s:form>
  </body>
</html>
UI tag…contd
TextArea tag:
 <body>
  <h1><span style="background-color
: #FFFFcc">Textarea Tag Example!</span></h>
  <s:form>
    <s:textarea label="Description" name="description" cols="15" ro
ws="10" />
  </s:form>
  </body>
UI tag…contd
Radio tag:
 <body>
  <h1><span style="background-color: #FFFFcc">Radio Tag Example!
</span></h>
  <s:form>
    <s:radio label="Fruits" name="fruitsname" list="fruits" />
    <s:radio label="Animals" name="animalsname" list="animals" />
  </s:form>
  </body>
UI tag…contd
Checkbox tag:
 <body>
    <h1><span style="background-
color: #FFFFcc">Checkbox Tag Example!</span></h1>
      <b>Sex</b><br>
      <s:checkbox label="Male" name="male" value="true" /><br>
      <s:checkbox label="Female" name="male" />
  </body>
UI tag…contd
TextArea tag:
 <body>
  <h1><span style="background-color
: #FFFFcc">Textarea Tag Example!</span></h>
  <s:form>
    <s:textarea label="Description" name="description" cols="15" ro
ws="10" />
  </s:form>
  </body>
UI tag…contd
TextArea tag:
 <body>
  <h1><span style="background-color
: #FFFFcc">Textarea Tag Example!</span></h>
  <s:form>
    <s:textarea label="Description" name="description" cols="15" ro
ws="10" />
  </s:form>
  </body>
UI tag…contd
TextArea tag:
 <body>
  <h1><span style="background-color
: #FFFFcc">Textarea Tag Example!</span></h>
  <s:form>
    <s:textarea label="Description" name="description" cols="15" ro
ws="10" />
  </s:form>
  </body>

You might also like