Struts2

13,580 views

Published on

This is a presentation I gave recently at the Apache conference

Published in: Technology, Education
  • Be the first to comment

Struts2

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

×