For Struts Developers
May 06, 2015
For Struts Developers
Me• Scott Stanlick
– Drummer– Techie– Instructor– Connoisseur of cereal malt beverages
2
Agenda• Hello Struts 2• Action/Interceptor/Result• Configuration• OGNL/Value Stack• Tag Libraries• Business Validation• Plug-ins• Wrap up
3
Hello Struts 2
The History
4
What is Struts 2?
• Not Struts 1.x!
• EE5 Web Framework
• Originally OpenSymphony WebWork
• WebWork + Struts + Apache Incubator– Struts 2 was hatched in ‘07
5
Built Specifically For…• Developer Productivity
– Simple HTTP-free code– Easy Spring integration– Reusable UI templates– Plug-in architecture– Crazy cool type conversions– Rich validation– Easy to test– And so much more!
6
Configuration Styles
• Packaged actions (namespace)
• Package inheritance
• Wildcard mappings
• Generic actions
• Annotations
• Ruby-On-Rails Rest-style mappings– Convention over configuration
7
Plug-in Architecture
• Similar to Firefox and Eclipse• Add features by dropping in a jar• Several bundled plug-ins
– Tiles– JFreeChart– JasperReports– REST-Style URI mappings
• Plug-in registry growing steadily
8
The Core Components
• Actions
• Interceptors
• Results
9
Differences from Struts Classic
• No form beans• Actions are no longer singletons• HTTP-free• Intelligent defaults• Easy to extend with
– Interceptors– Results– Plug-ins
10
Action/Interceptor/Result
The Request Pipeline
11
12
ActionContext(ThreadLocal)
MVC2
• Where C=Cool!• Request
– FilterDispatcher• Dispatcher
– StrutsActionProxy» ActionInvocation [ThreadLocal]
13
Action• Packaged according to like kind
– Sort of like Java packages• ThreadLocal (safe)• Typically extend ActionSupport• Contain your domain model
– Can be model driven• May contain multiple methods• Not tangled up with Servlet/API• Easy to test!
14
Action Mapping
15
<package name="hr" namespace="/hr" extends="starter"><action
name=“uri“ class=“class“ method=“method"> <result>destination</result>
</action><package>
Wildcard Action Mapping
16
<package name="hr" namespace="/hr" extends="starter"><action
name=“employeeAction_*" class=“HREmployeeManager" method=“{1} ">
<result>/employee/{1}.jsp</result></action>
<package>
HREmployeeManager Actionclass HREmployeeManager {
private Employee model;
private EmployeeService service;
public List getList(){…}
}
17
Interceptor• Intercepts request
– Think AOP
• Called before/after your action
• Useful for cross-cutting concerns
• Built-ins cover 98+% of all use cases
• Configured at package or action level
• Is central to the framework itself– Eat your own dog food!
18
Interceptor Stack• An interceptor has a specific role
– Parameter interception– Validation– Workflow
• Named “stacks” provide pluggable lists pre-assembled for goal specific cases– defaultStack– fileUploadStack– modelDrivenStack– paramsPrepareParamsStack
19
Interceptor Configuration
• Easy to configure wrong!
• config-browser plug-in provides a glimpse into the runtime– More about this later
20
Timer Interceptor
• Stopwatch feature for action execution– “starts” before your action – “stops” afterward
• Writes performance timings to log
• Order of interceptors is interesting– See next slide
21
Timer Interceptor (cont.)
<interceptors>
<interceptor-stack name="stackWithTimer">
<interceptor-ref name="timer"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
records action's execution with interceptors
22
Timer Interceptor (cont.)
<interceptors>
<interceptor-stack name="stackWithTimer">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="timer"/>
</interceptor-stack>
</interceptors>
records only the action's execution time
23
Default Stack <interceptor-stack name="defaultStack"> <interceptor-ref name="exception"/> <interceptor-ref name="alias"/> <interceptor-ref name="servletConfig"/> <interceptor-ref name="prepare"/> <interceptor-ref name="i18n"/> <interceptor-ref name="chain"/> <interceptor-ref name="debugging"/> <interceptor-ref name="profiling"/> <interceptor-ref name="scopedModelDriven"/> <interceptor-ref name="modelDriven"/> <interceptor-ref name="fileUpload"/> <interceptor-ref name="checkbox"/> <interceptor-ref name="staticParams"/> <interceptor-ref name="params"> <param name="excludeParams">dojo\..*</param> </interceptor-ref> <interceptor-ref name="conversionError"/> <interceptor-ref name="validation"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> <interceptor-ref name="workflow"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> </interceptor-stack>
24
Result• What should be returned to requester?
• Many provided out of the box
• It’s easy to write your own– Graphics– JSON– PDF
• It’s another configurable object
25
Result Types<result-types> <result-type name="chain" class=“…"/> <result-type name="dispatcher" class=“…" default="true"/> <result-type name="freemarker" class=“…"/> <result-type name="httpheader" class=“…"/> <result-type name="redirect" class=“…"/> <result-type name="redirectAction" class=“…"/> <result-type name="stream" class=“…"/> <result-type name="velocity" class=“…"/> <result-type name="xslt" class=“…"/> <result-type name="plainText" class=“…" />
<result-type name="plaintext" class=“…" /></result-types>
26
Result Example<action …>
<result name="success" type="dispatcher">/employee/list.jsp
</result></action>
• name and type are optional– name defaults to success– type default can be set by package
27
Connecting the Wildcard Dots
28
<action name=“employeeAction_*“ class=“HREmployeeManager“ method=“{1} ">
<result>/employee/{1}.jsp</result>
</action>
• www.foo.com/employeeAction_list
• list()
• list.jsp
Configuration
Declaring the Web Site Capabilities
29
struts.xml• Core configuration file for framework • Can contain multiple packages<struts>
<package name=“base" extends="struts-default"> <action...>
</package> <include file=“hr.xml"/> <include file=“logon.xml"/> <include file=“preferences.xml"/>
</struts>
30
struts-default.xml• Most of your packages will extend this
– Directly/Indirectly
• Contains about everything you need
• Packages form inheritance hierarchies
• The key sections are– package– result-types– interceptors/stacks
31
Package Inheritance
<package name=“hr" extends=“base“ namespace="/hr">
<action name=“…”/>
</package>
32
• struts-default• base
• hr
Intelligent Configuration
• Declarative architecture
• Configurable defaults
• Extendable– Framework extension points– Sub-packages
• Shipped in the struts2-core-2.m.n.jar– struts-default.xml
33
Sample Declaration
<package name=“hr“ extends=“base“ namespace="/hr">
<action name="list“
method=“preload” class=“HREmployeeManager”>
<result>/pages/hr/employee/list.jsp</result>
</action>
</package>
34
Constant Configuration• Modify framework and plug-in behavior • Can be declared at multiple levels• Searched in the following order
– struts-default.xml– struts-plugin.xml– struts.xml– struts.properties– web.xml
• Subsequent files override previous ones
35
struts.properties
struts.devMode=truestruts.objectFactory=springstruts.configuration.xml.reload=truestruts.freemarker.templatesCache=truestruts.ui.theme=simplestruts.enable.DynamicMethodInvocation=falsestruts.custom.i18n.resources=resources.Messages…
36
OGNL/ValueStack
Dynamic Data/Object Graph
37
Dynamic Data
38
• Where is dynamic data stored?– Data to generate pages– User input from pages
• Form beans are gone
• Dependence on Servlet/API is bad
• Welcome to the ValueStack
ValueStack• Leverages the OGNL framework
– Object Graph Navigation Language• Extends OGNL to support searching stack
– Top down to locate object/property• Where Interceptors put/get object data• Thread Safe• ActionContext.getContext().getValueStack()
39
Struts 2 and OGNL
40
OG
NL
OG
NL
Con
text
(A
ctio
nC
on
text
)Value Stack (OGNL root) |___Action |___other objects…
#parameters#request#session#application#attr (searches p, r, s, then a)
ValueStack
• Request “Object Stack”
• OGNL expressions search it top down
• Can specify object level
• Common operations
– peek
– pop
– push
41
Type Conversions
• OGNL uses reflection to convert types
• JavaBeans convention provides “hint”
• Custom converters can be added– Scope
• Bean/Model• Action• Application
42
Tag Libraries
The UI
43
Struts 2 Tags
• Tags are divided into 2 sets– UI
• Form/Non-Form• Ajax
– Leverages dojo
– Generic• Control
– if, else, iterator
• Data– bean, text, url
44
Struts 2 Tags
• Decoupled from underlying view technology– JSP– Velocity– FreeMarker
• Markup via Freemarker templates
45
S2 Tag Syntax
• The value attribute is not a string– It’s an OBJECT
• What you pass is evaluated as an expression!
• <s:sometag … value=“foo”/>– Looks for getFoo()
• <s:sometag … value=“{‘foo’}”/>– String literal is passed
46
Tag Templates
• The markup generated is your choice– HTML– XML– JSON– WML– …
47
UI Tag Templates
• Template technology is FreeMarker
• CSS classes can be used to control L&F
• You may tweak provided templates
• Tight affinity with ValueStack
48
Base select Component• View technology agnostic• org.apache.struts2.components.Select• Generates markup via TemplateEngine• S2 provides FreeMarkerTemplateEngine
– Unites ValueStack & FreeMarker
49
<s:select/> JSP Custom Tag
• org.apache.struts2.views.jsp.ui.SelectTag• Renders a select widget
50
<@s.select/> FreeMarker Tag• org.apache.struts2.views.freemarker.tags.SelectModel
• Renders a select widget
51
StrutsRequestWrapper
• JSTL does not know OGNL
• This class wraps the Struts request
• Delegates to the Value Stack
• ${customer.address.city}– Resolves to stack.find under the covers
52
S2 and JSTL• OGNL values are exposed to JSP/JSTL• Expression syntax is a little different
– JSTL: ${a.b.c}– OGNL: %{a.b.c}
• Beware of JSP 2.1 Unified EL JSR 245– EL has been expanded to interpret #{}– Clashes with OGNL usage for Maps
• #{ "foo" : "foo value", "bar" : "bar value" }
53
Themes
• S2 UI tags grouped into themes– simple - minimal with no "bells and whistles" – xhtml - uses common HTML practices – css_xhtml - xhtml theme re-implemented
using strictly CSS for layout – Ajax - based on the xhtml theme that
provides advanced AJAX features
• Specified globally or at the tag level
54
Simple Theme
55
<H2>Employee Save</H2><s:form> <s:textfield key="employee.name“ required="true"/> <s:textfield key="employee.department“ required="true"/></s:form>
XHTML Theme
56
<H2>Employee Save</H2><s:form> <s:textfield key="employee.name“ required="true"/> <s:textfield key="employee.department“ required="true"/></s:form>
Business Validation
Rules and Regulations
57
Validation Styles
• Annotations
• XML
• Java
58
Simple Field Example• Form
– <s:textfield key="age"/> • Action
– private int age; get/set• Validator <ActionClassName>-validation.xml
<field name="age"> <field-validator type="int">
<param name="min">13</param>
<param name="max">19</param>
<message>Only people ages 13 to 19 allowed</message>
</field-validator>
</field>
59
Validator Types• conversion• date• email• short – int – long - double• regex <takes a regular expression>• required• requiredstring• stringlength• url• visitor - conditionalvisitor• fieldexpression <resolves an OGNL expression>• expression <resolves an OGNL expression>
60
Another Field Example<field name=“password">
<field-validator type="expression">
<param name="expression">
password.equals(password2)
</param>
<message>
Password 2 must equal ${password}
</message>
</field-validator>
</field>
61
Non-Field Validation
62
<validators> <validator type="expression"> <param name="expression“> ( (a==b) && (b==c) )</param> <message>all three fields must be the same></message> </validator>
</validators>
Plug-ins
Extensions Simplified
63
Benefits of plug-ins
• Strategic points in the framework where you can – Provide you own implementations– Add new features
• Add functionality without modifying code– Open-Closed Principle
64
Configuration Browser
• Exposes the runtime configuration
• Accessed via a browser– http://.../config-browser/index.action
65
OGNL Viewer• Provides debugging screens to provide
insight into the data behind the page• Accessed via a browser
– http://..?debug={flag}
• Flag values– xml, console, command, browser
• Make sure – DebuggingInterceptor is included– struts.devMode=true
66
Wrap up
Odds & Ends
67
My Web Site
68
• www.struts2inaction.com
• The cobbler’s children have no shoes
• Too many paying gigs to lace up my own site!
• Vacation time coming• It will rock!
Resources
• Manning
• Nabble
• Also watch for – Struts 2 in Practice (Wes Wannemacher)
69