Using Struts 2 and Spring Frameworks Together - Bruce Phillips - Home
Web frameworks Struts 2
Transcript of Web frameworks Struts 2
Web frameworks
and
Struts 2
Why use web frameworks?
• Separa3on of applica3on logic and markup – Easier to change and maintain
– Easier to re-‐use – Less error prone
• Access to func3onality to solve rou3ne needs
– Data transfer between client (HTTP) and server (Java) – Valida3on
– Interna3onaliza3on – User interface components (tags)
Problem area
• Mixing application logic and markup is bad practise – Harder to change and maintain – Error prone – Harder to re-use
public void doGet( HttpServletRequest request, HttpServletResponse response ) { PrintWriter out = response.getWriter(); out.println( ”<html>\n<body>” ); if ( request.getParameter( ”foo” ).equals( ”bar” ) ) out.println( ”<p>Foo is bar!</p>” ); else out.println( ”<p>Foo is not bar!</p>” ); out.println( ”</body>\n</html>” ); }
Advantages
• Separation of application logic and web design through the MVC pattern
• Integration with template languages • Some provides built-in components for
– Form validation – Error handling – Request parameter type conversion – Internationalization – IDE integration
Struts 2
• Built on top of XWork – a command pattern framework • Integrated with the Spring IoC container • Provides a clean implementation of the MVC pattern
The MVC pattern • Breaks an application into three parts:
– Model: The domain object model / service layer – View: Template code / markup – Controller: Presentation logic / action classes
• Defines interaction between components to promote separation of concerns and loose coupling – Each file has one responsibility – Enables division of labour between programmers and designers – Facilitates unit testing – Easier to understand, change and debug
MVC with Front Controller Web browser.
Displays output. Front controller. Maps request URLs to controller classes.
Implemented as a servlet.
Command instances/ Action classes.
Interacts with backend services of the system.
Backend services working with the API/
data model.
Web page template like
JSP or Velocity.
Action Flow
Client HTTP request to URL
web.xml
(Struts 2) Servlet dispatcher
struts.xml (config file)
Stack of interceptors
Action classes (User code)
Stack of interceptors
Result
Response to client
(getRandomString.action)
(GetRandomStringAction.java)
(random.vm)
web.xml
• Servlet container configuration file • Maps URL patterns to the Struts dispatcher • Most typical pattern is *.action • Located in WEB-INF/ folder • Can redirect to the Filter- or ServletDispatcher
<filter> <filter-name>struts</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>struts</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping>
struts.xml
• Struts (dispatcher) configuration file • Located in root of classpath (by default) • struts-default.xml is included automatically • Maps URLs to action classes • Maps result codes to results
<struts> <package name="default" extends=”struts-default"> <action name=”invertString" class="no.uio.inf5750.example.action.InvertStringAction"> <result name="success" type="velocity">word.vm</result> </action> </package> </struts>
Action classes
• Java code executed when a URL is requested • Must implement the Action interface or extend
ActionSupport – Provides the execute method – Must return a result code (SUCCESS, ERROR, INPUT) – Used to map to results
• Properties set by the request through public set-methods • Properties made available to the response through public
get-methods
Action classes
public class InvertStringAction implements Action { private String word; public void setWord( String word ) { this.word = word; } private String invertedWord; public String getInvertedWord() { return this.invertedWord; } public String execute() { char[] chars = word.toCharArray(); // do some inverting here... invertedWord = buffer.toString(); return SUCCESS; } }
Implements Action
Must correspond to request parameter,
exposed through set-method
Must correspond to property name in view,
exposed through get-method
Execute method with user code
Must return a result code (defined in Action)
getRandomString.action?word=someEnteredWord HTTP request
View
• Struts 2 integrates with many view technologies: – JSP – Velocity – Freemarker – JasperReports
• Values sent to controller with POST or GET as usual
• Values made available to the view by the controller
View
• Velocity is a popular template engine and -language
<html> <body> <form method=”post” action=”invertString.action”> <p><input type=”text” name=”word”></p> <p><input type=”submit” value=”Invert”></p> </form> <p>$invertedWord</p> </body> </html>
Form action to URL mapped in struts.xml
Input name corresponding to set-method in action class
Velocity parameter corresponding to
get-method in action class
public String getInvertedWord() { return this.invertedWord; }
Java Action class
struts.xml (2)
• Different result codes can be mapped to different results
<struts> <package name="default" extends=”struts-default"> <action name=”invertString" class="no.uio.inf5750.example.action.InvertStringAction"> <result name="success" type="velocity">word.vm</result> <result name=”input” type=”velocity”>input.vm</result> </action> </package> </struts>
struts.xml (3)
• Static parameters can be defined • Requires public set-methods in action classes • Automatic type conversion is provided
<struts> <package name="default" extends=”struts-default"> <action name=”invertString" class="no.uio.inf5750.example.action.GetRandomStringAction"> <result name="success" type="velocity">random.vm</result> <param name=”numberOfChars”>32</param> </action> </package> </struts>
struts.xml (4)
• Files can include other files – Files are merged
• Facilitates breaking complex applications into manageable modules – Specified files are searched for in classpath – Configuration can be separated into multiple files / JARs
<struts> <include file=”struts-public.xml”/> <include file=”struts-secure.xml”/> </struts>
struts.xml (5)
• Actions can be grouped in packages • Useful for large systems to promote modular design • A package can extend other packages
– Definitions from the extended package are included – Configuration of commons elements can be centralized
<struts> <package name="default" extends=”struts-default"> <action name=”invertString” class=”no.uio.no.example.action.InvertStringAction”> <!– mapping omitted --> </action> </package> <package name=”secure” extends=”default”> <!– Secure action mappings --> </package> </struts>
struts.xml (6)
• Actions can be grouped in namespaces • Namespaces map URLs to actions
– Actions identified by the name and the namespace it belongs to – Facilitates modularization and improves maintainability
<xwork> <include file="webwork-default.xml"/> <package name=”secure" extends=”default” namespace=”/secure”> <action name=”getUsername” class=”no.uio.inf5750.example.action.GetUsernameAction”> <result name=”success” type=”velocity”>username.vm</result> </action> </package> </xwork>
Interceptors
• Invoked before and/or after the execution of an action • Enables centralization of concerns like security, logging
<struts> <package name="default" extends=”struts-default"> <interceptors> <interceptor name=”profiling” class=”no.uio.example.interceptor.ProfilingInterceptor”/> </interceptors> <action name=”invertString” class=”no.uio.no.example.action.InvertStringAction”> <result name=”success” type=”velocity”>word.vm</result> <interceptor-ref name=”profiling”/> </action> </package> </struts>
Provided interceptors
• Interceptors perform many tasks in Struts 2 – ParametersInterceptor (HTTP request params) – StaticParametersInterceptor (config params) – ChainingInterceptor
• Many interceptor stacks provided in struts-default.xml – defaultStack – i18nStack – fileUploadStack and more
Interceptor stacks
• Interceptors should be grouped in stacks • A default interceptor stack can be defined
– Should include the Struts default stack
<struts> <!– package omitted à <interceptors> <interceptor name=”profiling” class=”no.uio.example.interceptor.ProfilingInterceptor”/> <interceptor name=”logging” class=”no.uio.example.logging.LoggingInterceptor”/> <interceptor-stack name=”exampleStack”> <interceptor-ref name=”defaultStack”/> <interceptor-ref name=”profiling”/> <interceptor-ref name=”logging”/> </interceptor-stack> </interceptors> <default-interceptor-ref name=”exampleStack”/> </struts>
Result types
• Determines behaviour between action execution and view rendering
• Several result types are bundled: • Dispatcher (JSP)
– Default - will generate a JSP view
• Velocity – Will generate a Velocity view
• Redirect – Will redirect the request to the specified action after execution
• Chain – Same as redirect but makes all parameters available to the
following action
Result types
<struts> <package name="default" extends=”struts-default"> <action name=”getRandomString” class=”no.uio...GetRandomStringAction”> <result name=”success” type=”chain”>invertString</result> <result name=”input” type=”redirect”>error.action</result> </action> <action name=”invertString” class=”no.uio...InvertStringAction”> <result name=”success” type=”velocity”>word.vm</result> </action> </package> </struts>
Chain result type.
The properties in GetRandomStringAction
will be available for InvertStringAction.
Redirect result type.
Redirects the request to another action after
being executed.
Velocity result type.
Generates a HTML response based on a
Velocity template.
Result types
• Several provided result types integrated with ext tools – JasperReports – Flash – Freemarker
• Custom result types can be defined
<struts> <package name=”default” extends=”struts-default”> <result-types> <result-type name=”velocityXML” class=”no.uio.inf5750.example.XMLResult”/> </result-types> </package> </struts>
public class XMLResult implements Result { public void execute( ActionInvocation invocation ) { Action action = invocation.getAction(); // Print to HTTPServletResponse or // modify action parameters or whatever... } }
IoC
• Struts 2 integrates with the Spring IoC container • The class property in action mappings refers to Spring
bean identifiers instead of classes
<xwork> <!– Include file and package omitted --> <action name=”getRandomString” class=”getRandomStringAction”> <result name=”success” type=”chain”>invertString</result> </action> </xwork>
struts.xml
Struts 2 configuration file
<bean id=”getRandomStringAction” class=”no.uio.inf5750.example.action.GetRandomStringAction”/>
beans.xml
Spring configuration file
Velocity
• Velocity is a template language – Template: basis for documents with similar structure – Template language: format defining where variables should be
replaced in a document
• Features include: – Variable replacement – Simple control structures – Method invocation
• Velocity result is included in struts-default.xml • Velocity is a runtime language
– Fast – Error prone
Velocity
<html> <head><title>$word</title></head> <body> #if ( $word == ”Hello” ) <div style=”background-color: red”> #elseif ( $word == ”Goodbye” ) <div style =background-color: blue”> #else <div> #end $word.substring( 10 ) </div> #foreach ( $word in $words ) <p>$word</p> #end </body> </html>
Control structures
Method call
Loop
Variable replacement
Purpose of Web frameworks
• Solving applica3on level concerns / rou3ne work! – Binding request parameters to Java types – Valida3ng data – Providing interna3onaliza3on – Rendering presenta3on layer (HTML etc) – Making calls to business layer
Ac3on classes
• Purposes – Encapsulates the work to be done for a request
– Serve as data carrier in transfer from request to view – Determine which result should render the view
public class InvertStringAction implements Action { private String word; // set-method private String invertedWord; // get-method public String execute() { if ( word == null || word.trim().length() == 0 ) { return INPUT; } invertedWord = getInvertedWord(); // implemented another place return SUCCESS; } }
Ac3on classes
• Ac3onSupport: Abstract convenience class providing: – Valida3on
– Interna3onaliza3on
• Works together with interceptors in the default stack
• Ac3onContext: Container holding relevant data for a request: – ValueStack
– Request parameters – Session variables
ModelDriven Ac3ons
• Transfers data directly onto model objects – Avoids tedious object crea3on code
• Provided by interface ModelDriven<T>
– Exposes method T getModel()
ModelDriven Ac3ons public class SaveStudent extends ActionSupport implements ModelDriven<Student> { private Student student = new Student(); public Student getModel() { return student; } private StudentService studentService = // retrieved somehow public String execute() { studentService.saveStudent( student ); return SUCCESS; } }
Class extending Ac3onSupport and implemen3ng ModelDriven
getModel implemented
Student instance created
Student object populated with data and ready to use
Data will be availabe in view
Don’t change object reference!
Valida3on
• Basic valida3on accessible from Ac3onContext
• The DefaultWorkFlowInterceptor works behind the scenes
• Separates valida3on logic from business logic
Valida3on public class CalculateAction extends ActionSupport { private Integer numerator; private Integer denominator; // set-methods private Double result; // get-method public void validate() { if ( denominator == null ) { addFieldError( ”denominator”, ”Please enter a numerator” ); } elseif ( denominator == 0 ) { addFieldError( ”denominator”, ”Divison by zero not allowed” ); } } public String execute() { result = // calculate somehow } }
Class extending Ac3onSupport
Execute method containing logic
Java bean proper3es
Validate method containing logic for checking validity of data
Storing errors via methods provided by Ac3onSupport
Valida3on workflow separated from execu3on
Valida3on <action name=”calcuate” class=”no.uio.inf5750.example.action.CalculateAction”> <result name=”success” type=”velocity”>calculate.vm</result> <result name=”input” type=”velocity”>calculate.vm</result> </action>
Input result is used when valida3on errors exist
<html> <body> #sform( "action=calculate" ) #stextfield( "label=Numerator" "name=numerator" ) #stextfield( "label=Denominator" "name=denominator" ) #ssubmit( "value=Calculate" ) #end </body> </html>
Valida3on error messages printed for appropriate UI tag in view
Interna3onaliza3on
• Separa3on layer between source code and messages • Built upon Java resource bundles, which will be found in:
– Same package and with same name as Ac3on class – Classpath aXer seYng struts.custom.i18n.resources config property
• Messages accessible in Java code through getText(..) • Locale accessible in Java code through getLocale()
• Messages accessible in template through key and name proper3es of UI tags
Interna3onaliza3on
<constant name="struts.custom.i18n.resources" value="i18n.i18n" />
salute=Bonjour!
public class SaluteAction extends ActionSupport { public String execute() { String salute = getText( ”salute” ); Locale locale = getLocale(); return SUCCESS; } }
<h3>#stext( "name=salute" )</h3>
struts.xml configura3on
i18n.proper3es in i18n folder on classpath
Ac3on class using getText(..) and getLocale()
Velocity template using text tag
UI component tags
• High level tag API implemented in: – JSP
– Velocity (used in this lecture) – Freemarker
• Data tags
– Moves data between the ValueStack and the view
• Control tags – Alters the rendering flow of the view
• UI tags – Provides advanced HTML form controls
Spring integra3on
• Useful to apply dependency injecFon to a Struts 2 applica3on – Struts 2 Spring plugin is required (struts2-‐spring-‐plugin) – Spring started in web.xml with ContextLoaderListener
• Approach 1: Define dependencies and ac3on classes in Spring – Class a`ribute in Struts 2 config points at Spring bean id
• Approach 2: Use auto-‐wiring by name – Struts 2 will instan3ate Ac3ons but let Spring inject beans aXerwards
– Bean iden3fiers are matched to set-‐methods in Ac3ons
Auto-‐wiring by name
<bean id=“studentService” class=“no.uio.inf5750.model.DefaultStudentService”/>
public class SaveStudentAction extends ActionSupport
{ private StudentService studentService;
public voic setStudentService( StudentService studentService )
{ this.studentService = studentService;
}
// Student properties and setters
public String execute() {
studentService.saveStudent( student ); } }
Only the StudentService bean is defined in the configura3on
Ac3on class provides StudentService property and set-‐
method
Name of set-‐method is matched with Spring bean iden3fiers
Short summary
• Struts 2 is built upon the Java Servlet specifica3on which is built upon HTTP
• Struts 2 solves applica3on level rou3ne work not provided by the Servlet specific3on
– Binding request params to Java types – Valida3ng data
– Providing interna3onaliza3on – Rendering presenta3on layer – Making calls to business layer
Struts 2 in DHIS 2
• Web commons project (dhis-web-commons) – Java code for widgets, security, portal – Interceptor, result configuration – Application logic interceptors – Custom results
• Web commons resources project (dhis-web-commons-resource ) – Web resources like templates, javascripts, css
Web modules in DHIS 2
• Templates included in backbone template – main.vm – Static params in Struts 2 configuration for page and menu
• Must depend on dhis-web-commons and dhis-web-commons-resources
• Struts packages must – Include dhis-web-commons.xml – Extend dhis-web-commons package – Have the same package name as the artifact id – Have the same namespace as the artifact id
• Development tip: $ mvn jetty:run –war – Packages and deploys war file to Jetty for rapid development
Resources
• Brown, Davis, Stanlick: Struts 2 in AcFon
• Velocity user guide:
– h`p://velocity.apache.org/engine/devel/user-‐guide.html
• Struts home page:
– h`p://struts.apache.org
• HTTP Specifica3on
– h`p://www.w3.org/Protocols/rfc2616/rfc2616.html
• Java Servlet Specifica3on – h`p://jcp.org/aboutJava/communityprocess/mrel/jsr154/index2.html