Você está na página 1de 87

Struts

Slides by Igor Polevoy

Web Interface Best Practices


Minimize Java Code in JSP
Separation of concerns (web designer/Java developer)
Include directive: <%@ include file="filename" %> : static inclusion when pre-processing JSP Include action: <jsp:include page="page.jsp" flush="true" /> : dynamic execution of request by included resource

Use include mechanisms

Do not mix business logic with presentation logic


Separate responsibilities Better maintainability Better composition

Web Interface Best Practices


Use JSP custom tags (may have to develop these)
Eliminate Java code from HTML Easier syntax Improve web designers productivity Elements of reusable code Suggestions:
Keep tag syntax simple (fewer attributes)

Do not re-invent a wheel

Web Interface Best Practices


Place business logic in JavaBeans Do not use logic in custom tags that is not user interface-specific Use MVC pattern Use XHTML syntax

Web Interface Best Practices


Use Servlet filters for common tasks
Common login Compression Authentication/Authorization

Create a portable security model


If cannot avoid vendor security model

Cache results from DBMS in RowSets

Power of Frameworks
Frameworks:
Provides abstraction of a particular concept Defines how these abstractions work together to solve a problem Framework components are reusable Organizes patterns at higher level Provides generic behaviour (many different applications can be built with the use of the same application)

JSP Model 1 Architecture

Web Browser

JSP

JavaBean

Demo Model 1 example

MVC Pattern
Change notification Model Query state Change state

User input
View View selection events Controller

JSP Model 2 Architecture

Servlet Web Browser JSP

JavaBean

Demo Model 2 example

Java Web UI History


Java based CGI - HTML mixed in Java Servlets HTML mixed in Java JavaServer Pages Java code mixed in HTML Servlets + JSP use of MVC pattern to separate business logic from presentation Frameworks: Tapestry(servlets, its own html templates), Struts, JavaServer Faces

Struts
Framework for building Web applications using Java Builds on MVC pattern Located at: http://jakarta.apache.org/struts/

Struts History
Created in 2000 by Craig R. McClanahan Donated to ASF in 2000 Current stable release: 1.3.5 Soon (2006) to be released 2.0 1.x will be around - there is new development, great community, many applications are developed in 1.x

Quick Technology Overview


HTTP Protocol (request/response) HTML The Java Language and Application Frameworks JavaBeans Properties Files and ResourceBundles Java Servlets JavaServer Pages, JSP Tag Libraries XML

Struts MVC
Struts does not specify how to implement Model part of MVC JSP and Struts Tag Libraries used for View part of MVC Struts Controller implemented as: ActionServlet and ActionMapping

Struts MVC
3 Major Components
Servlet controller (Controller) Java Server Pages (View) Application Business Logic (Model)

Controller bundles and routes HTTP request to other objects in framework (Actions) Controller parses configuration file

Struts MVC
Configuration file contains action mappings (determines navigation) Controller uses mappings to turn HTTP requests into application actions Mapping must specify
A request path Object type to act upon the request

View Components
HTML DTO Struts ActionForms objects JavaServer Pages Struts Tags Custom Tags Java Resource Bundles Other: graphics, downloads, etc.

View Components Action Forms


ActionForm Beans Extends the ActionForm class
Create one for each input form in the application JavaBeans style properties must match form entries

View Components Action Forms


Continued
Define a property (with associated getXxx() and setXxx() methods) for each field that is present in the form. The field name and property name must match according to the usual JavaBeans conventions Place a bean instance on your form, and use nested property references. For example, you have a "customer" bean on your Action Form, and then refer to the property "customer.name" in your JSP view. This would correspond to the methods customer.getName() and customer.setName(string Name) on your customer bean

Controller Components
org.apache.struts.ActionServlet is a main component of Struts org.apache.struts.action.Action extension of controller component (defined in action mapping in the configuration file)

Controller Components
Deployment descriptor for Struts

Struts use configuration file called


struts-config.xml

This file provides for a configuration of controller components (actions), resources, model components: JavaBeans and other resources

Controller Components
The action mapping example <action-mappings> Action mapping name <action path="/addBookAction type= "edu.depaul.struts_example.BookInputAction" name="addBookBean" mapping type scope="request" input="/add_book.jsp"> Form Bean name <forward name="Go" path="/result.jsp"/> <forward name="cancel" forward definition path="/index.html"/> </action>

Model Components
System State Beans A set of one or more JavaBeans classes, whose properties define the current state of the system Example: shopping cart In a J2EE application a model is usually encapsulated as a layer of Session Faades

Struts Model Components


Accessing Relational Databases Struts can define the data sources for an application from within its standard configuration file A simple JDBC connection pool is also provided (can be configured in the configuration file)

Struts Action Forms


Action Forms are a Java Beans Extends ActionForm class from Struts Framework (makes it dependent on the Struts API) Action Forms are mapped to HTML forms hence the name

Struts Action Forms


Extend
org.apache.struts.action.ActionForm
validate() - optional reset() - optional

Override: Provide JavaBeans/style properties that match an HTML form input/output values

Struts Actions
For every action in the application , a custom Action is defined These a similar to servlets Short lived (for the duration of the request) Stateless do not put any state in the Action classes

Struts Action
FQCN: org.apache.struts.action.Action Implementations subclass this class and provide implementation of execute method:
ActionForward execute(ActionMapping , ActionForm , HttpServletRequest , HttpServletResponse );

Action.execute() Arguments
ActionMapping - provides access to the information stored in the configuration file (struts-config.xml) entry that configures this Action class. ActionForm formThis is the form bean. By this time, the form bean has been pre-populated and the validate() method has been called and returned with no errors (assuming that validation is turned on). All the data entered by the user is available through the form bean. HttpServletRequest requestThis is the standard JSP or Servlet request object. HttpServletResponse responseThis is the standard JSP or Servlet response object.

Action.execute() Return Value: ActionForward


ActionForward represents a destination to which the controller, RequestProcessor, might be directed to perform a RequestDispatcher.forward or HttpServletResponse.sendRedirect to, as a result of processing activities of an Action class. Instances of this class may be created dynamically as necessary, or configured in association with an ActionMapping instance for named lookup of destinations from configuration files

RequestProcessor the heart of Controller (Chain of Responsibility Pattern)


SelectAction Determine the ActionMapping associated with this path. CreateActionForm Instantiate (if necessary) the ActionForm associated with this mapping (if any) and place it into the appropriate scope. PopulateActionForm Populate the ActionForm associated with this request, if any. ValidateActionForm Perform validation (if requested) on the ActionForm associated with this request (if any). SelectInput If validation failed, select the appropriate ForwardConfig for return to the input page. CreateAction Create an instance of the class specified by the current ActionMapping ExecuteAction This is the point at which your Action's execute method will be called. PerformForward Finally, the process method of the RequestProcessor takes the ActionForward returned by your Action class, and uses it to select the next resource (if any). Most often the ActionForward leads to the presentation page that renders the response.

03StrutsSimple Demo

Decomposing Struts Application (web.xml)


<servlet> <servlet-name>action</servlet-name> <servlet-class> org.apache.struts.action.ActionServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>

Decomposing Struts Application (index.jsp)


<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %> <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %> <html:form action="simpleAction" method="POST"> First Name: <html:text property="firstName"/> <font color="red"><html:errors property="firstName"/> </font> Last Name: <html:text property="lastName"/> <font color="red"><html:errors property="lastName"/> </font> <html:submit value="Submit"/> </html:form> Note: some HTML tags are omitted for clarity

Decomposing Struts Application (SimpleForm.java)


Rule: Action forms in Struts must: Conform to the JavaBeans property name conventions Action forms properties must correspond to the names defined in a form public class SimpleForm extends ActionForm { private String firstName; private String lastName;

public String getFirstName() { return firstName; }


... other getters and setters }

Decomposing Struts Application (struts-config.xml part 1)


<form-beans type="org.apache.struts.action.ActionFormBean"> <form-bean name="simpleBean" type="edu.depaul.struts.SimpleForm" /> </form-beans>

Decomposing Struts Application (struts-config.xml part 2)


<action-mappings type="org.apache.struts.action.ActionMapping"> <action path="/simpleAction" type="edu.depaul.struts.SimpleAction" name="simpleBean" scope="request" input="/index.jsp"> <forward name="next" path="/next.jsp"/> <forward name="again" path="/index.jsp"/> </action> </action-mappings> <!-This is a reference to a resource bundle with messages. The file name is: struts-examples.properties --> <message-resources parameter="struts-examples" />

Anatomy of a Struts Application

Web Container
Browser 1 ActionServlet 5 JSP View

Action 3 Model DBMS

struts-config

Decomposing Struts Application (SimpleAction.java)


public ActionForward execute( ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { //getting posted information SimpleForm simpleForm = (SimpleForm) actionForm; ///... - business related processing httpServletRequest.setAttribute("simpleForm", simpleForm); //passing control to the next page return actionMapping.findForward("next"); }

Request Processing
If action mapping defined in the configuration file, the Controller Servlet/RequestProcessor will perform the following:

Check session or request for instance of bean of appropriate class If no session/request bean exists, one is created automatically For every request parameter whose name corresponds to the name of a property in the bean, the corresponding setter method will be called The validate() method of ActionForm is called The updated ActionForm bean will be passed to the Action Class execute() method when it is called, making these values immediately available The execute() method must return an instance of ActionForward instructing the controller which is the next view (page) The next page is merged with data passed in request or session object, and then renders HTML

Request Processing
4 ActionForm 3 1 Web Browser displays page 2 Controller Model Action 5

struts-config

JSP Page

Page Construction html tags


The <html:html> Tag The <html:html>tag simply generates the <html> HTML element at the beginning of the file. In our case, this is a very basic tag. If this application were written to provide locale-specific text, the tag could have been written as <html:html locale=true> Using the local=true option causes this page to set its locale value based on the Accept-Language header submitted by the client browser (if a locale was not already set).

Page Construction html tags


The <html:base> Tag The <html:base>tag generates an HTML <base> element in the <head> section of the document. The <base> HTML element is used to assist the client browser in correctly forming relative URL paths if theyre present in the HTML page. In this case, our <html:base/> tag rendered the following HTML: <base href=http://localhost:8080/appname/mypage.jsp>

Page Construction html tags


The <html:link> tag provides convenience and a great deal of flexibility if it makes sense for your application to URL encode request parameters. It also automatically handles URL encoding of Session IDs to ensure that you can maintain session state with users who have cookies turned off in their browser. <global-forwards> <forward name=index path=/index.jsp/> </global-forwards> <html:link forward=index>Go Home</html:link> The HTML generated is <a href=/myapp/index.jsp>Go Home</a> Create Link by Specifying a Full URL

<html:link href=http://jakarta.apache.org/struts/index.html> Generate an href directly


</html:link>

Form Construction
The Basics of Form Processing This section provides information on the following tags: <html:form> - Render an HTML <form> element <html:text> - Text box INPUT element <html:hidden> INPUT type=hidden element <html:submit>Place a Submit INPUT element <html:cancel>Place a Submit INPUT element which can be used to cancel workflow

Form Construction <html:form>


<html:form action="simpleAction" method="POST">
simplAction - action name corresponds to action name in configuration <action path="/simpleAction" cancellable="true" type="edu.depaul.struts.SimpleAction" name="simpleBean" // name of bean mapped to form controls scope="request" input="/index.jsp" >

Form Construction <html:text/>


<html:text property="firstName"/> Generates HTML: <input type="text" name="firstName" value=""> Bean form bound: public class SimpleForm extends ActionForm { private String firstName; private String lastName; ...

Form Construction <html:submit/>


<html:submit value="Submit"/>

Generates: <input type="submit" value="Submit">

Form Construction <html:select>


<html:select property="address">
<html:option value="Please, make selection"/> <html:options property="addresses"/>

</html:select> Where address is a form bean property which will be set with a selected value addresses Collection type property for inputs

Input Validation
Validation can be provided:
FormBean.validate(ActionMapping mapping, HttpServletRequest request) Directly in the Action.execute() method:
ActionMessages actionMessages = new ActionMessages(); if (simpleForm.getFirstName() == null ||simpleForm.getFirstName().equals("")) { actionMessages.add("firstName", new ActionMessage("field.required")); }

Input Validation
if (!actionErrors.isEmpty()) { saveMessages(request, actionErrors); return actionMapping.getInputForward(); } getInputForward(); -> sends back name of a page from which the Action was invoked

Strings in ActionForm
Struts converts data according to property data type If typed value cannot be converted to appropriate type, then exception is thrown Exception cannot be intercepted happens before validation Best practice: all properties are Strings

Message Configuration
Resource Bundle specified in a struts-config file: <message-resources parameter="strutsexamples" /> Simple Java properties file: message_key=Message Text Easy to do I18N

Message Output
<html:errors> - outputs all error messages <html:errors property=propName> outputs a message for property propName if one exists

Global Messages
Page Global Messages: Adding: messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(this.message.key) ); Displaying: <html:messages property= org.apache.struts.action.GLOBAL_MESSAGE/>

Uploading Files form bean


public class UploadForm extends ActionForm { private FormFile file; ... - setter and getter

Uploading Files jsp


<html:form action="/uploadAction" enctype="multipart/form-data"> Please select local file:<br/> <html:file property="file"/> <html:submit/> </html:form>

Uploading Files action


UploadForm form = (UploadForm)actionForm; FormFile formFile = form.getFile(); byte data[] = formFile.getFileData(); //now that you have data, you can act on the //contents of a file

Bean Tags
The <bean:cookie> tag retrieves a cookie or cookies sent to the server from thebrowser. The <bean:header> Tag - provides access to the HTTP header The <bean:parameter> tag enables you to explicitly get a parameter passed into this page (either by a form submit or by arguments in the URL). The <bean:page> Tag: to gain access to the request, session, response, Struts config, or application data. The id attribute must be one of the strings request, session, config, response, or application).

Bean Tag Examples


<bean:cookie id=cookie name=/tags/cookiedemo value=firsttime/> <bean:write name=cookie property=value/>

<bean:header id=lang name=Accept-Language/> The preferred language for this browser is: <bean:write name=lang/>
<bean:parameter id="bean1" name="bean1" /> <bean:write name=bean1 property=name/> <bean:page id=this_session property=session/> Session Created = <bean:write name=this_session property=creationTime/>

Bean Tag bean:message


<bean:message key="welcome.user" arg0="${user.username}" />

${user.username} JSP 2.0 EL expression


Resource Bundle: welcome.user={0}, welcome to Acme Books

Bean Tag bean:resource


<bean:resource id="webxml" name="/WEBINF/web.xml"/> Gets contents of a resource and assigns it to a parameter with id=webxml

DynaActoinForms
org.apache.struts.action.DynaActionForm

config: <form-bean name=userForm type=org.apache.struts.action.DynaActionForm> <form-property name=userId type=java.lang.String initial=admin/> <form-property name=password type=java.lang.String/> </form-bean> No need to write any Java. Validation? There is no validate() method. Solution1: validate in Action Solution 2: sub-class the DynaActionForm class and add a validate() method Solution 3: Use validation framework Disadvantage: not type safe, typos can lead to hours of debugging (no Compile time type checking)

DynaActionForms inside Action


execute(...) { DynaActionForm myForm = (DynaActionForm )form; String name = (String)myForm.get(name); }

Validation Framework
Jakarta Commons Validator Framework
http://jakarta.apache.org/commons

Deployed as a Struts Plugin Extended by Struts to provide generic validation rules Common Rules:
check for required fields check for max/min size check for the right data type

Validator Built-in Rules


required field data provided minlength more than min length maxlength less than max length range in range of values mask correct format (takes regexp) date validates correct date format email validates correct E-Mail fromat primitives: byte, integer, float, double, etc.

Validator Setup
<plug-in className="org.apache.struts.validator.ValidatorPlugIn"> <set-property property="pathnames" value="/org/apache/struts/validator/validator-rules.xml, /WEBINF/validation.xml"/> <set-property property="stopOnFirstError" value="true"/> </plug-in>

Validator Files
validation-rules.xml contains all possible rules validation.xml contains mappings of forms, properties and rules

Validator Example
DynaValidatorForm
Configure a dyna-form in struts-config.xml file <form-bean name="userForm"

type="org.apache.struts.validator.DynaValidatorForm">

<form-property name="userId" type="java.lang.String"/> <form-property name="password" type="java.lang.String"/> </form-bean> DynaValidatorForm - provides basic field validation based on an XML file

Validator Example action mapping


<action path="/validationAction" cancellable="true" type="edu.depaul.struts.ValidationAction" name="userForm" scope="request" input="/validation.jsp">
<forward name="next" path="/validation-results.jsp"/> <forward name="cancelled" path="/index.jsp"/> </action>

Validator Example validation.jsp


validation.jsp (HTML omitted for clarity see demo): <html:form action="validationAction" method="POST"> User ID: <html:text property="userId"/> <html:errors property="userId"/>

Password <html:password property="password"/> <html:errors property="password"/> <html:submit value="Submit"/> <html:cancel value="Cancel"/> </html:form>

Validator Example validation.xml


<form name="userForm"> action form name <field property="userId" property name validated depends="required, maxlength"> <msg mandatory name="required" key="validationForm.iserId.required" /> <msg name="maxlength" key="validationForm.iserId.maxlength" /> <arg0 name=required key=iserId.label/> <var> <var-name>maxlength</var-name> <var-value>3</var-value> </var> resource bundle </field> message key

... other fields

Validator Framework validation.jsp


Where userForm name of action form defined in the struts-config.xml userId name of a form property being validated validationForm.iserId.required message key from message resource bundle Also: <arg0 name=required key=iserId.label/> You can have the following in the message bundle:
validationForm.iserId.maxlength={0} exceeded maximum length. iserId.label=User Id

In this case, the error message returned by the framework in case this field does not pass validation would be: User Id exceeded maximum length.

Validator Framework validation.xml


var element is used to pass any variables to the validation rule that is being used. minlength maxlength range mask date minlength maxlength min,max mask datePattern

Validator Framework
mixing programmatic invocation and XML rules

class MyValidatorForm extends DynaValidatorForm { ... public ActionErrors validate(ActionMapping, HttpServletRequest) {


super.validate(mapping, request); ...

Validator Framework Adding new rules(validators)


1. Create class with public static method: someMethod( ValidatorAction, Field, ActionErrors, HttpServletRequest); 2. Provide a new validator definition in the validationrules.xml file: a. Validator name b. Class name c. Method name d. Signature 3. Can provide JavaScript to validate on client

Validator Framework
Struts bakes rules directly into Jakarta Validator Framework. Jakarta Framework allows for any method signature, but Struts requires exact signature dependency in Struts- difficult to reuse validators in a different environment JavaScript can break if user disables JS in client Better to implement validation logic in a framework independent manner (even if using Jakarta Validator) and invoke validations from validate() methods this will lead to more infrastructure work

Struts-Tiles
Tool for creating reusable layouts for sites Open Source Project (ASF) Integrated with Struts Not Enabled by default Allows for tiles definitions in XML

Struts-Tiles
Need to define a Tiles plugin in strutsconfig.xml:
<plug-in className= "org.apache.struts.tiles.TilesPlugin"> <set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml" /> </plug-in>
Close to the end of file with all other plugins

Struts-Tiles
Create template JSP(template.jsp): <table border="1"> <tr> <td> <tiles:insert attribute='header'/> </td></tr> <tr> <td> <tiles:insert attribute='menu'/> </td></tr> <tr> <td> <tiles:insert attribute='content'/> </td></tr> <tr> <td> <tiles:insert attribute='footer'/> </td></tr> </table>

Struts-Tiles
Provide Tiles Definitions in the tiles-defs.xml file:
<definition name=".baseDef" page="/tiles/template.jsp"> <put name="title" value="Base Template Page"/> <put name="header" value="/tiles/header.jsp"/> <put name="footer" value="/tiles/footer.jsp"/> <put name="menu" value="/tiles/menu.jsp"/> <put name="content" value="/tiles/blank.jsp"/> </definition>

Struts-Tiles
<definition name=".index" extends=".baseDef"> <put name="title" value="New Page Title"/> <put name="content" value="/tiles/index.jsp"/> </definition> This definition extends .baseDef and overrides title and content fields

Struts-Tiles
Provide Action Mapping in the <action path="/someAction" ...

... </action>

<forward name="next" path=".index"/>

Looking Ahead Struts 2 - 2006?


* Improved design - All Struts 2 classes are based on interfaces. Core interfaces are HTTP independant. * Intelligent Defaults - Most configuration elements have a default value that you can set and forget. * Enhanced Results - Unlike ActionForwards, Struts 2 Results can actually help prepare the response. * First-class AJAX support - The AJAX theme gives your interactive applications a boost. * Stateful Checkboxes - Struts 2 checkboxes do not require special handling for false values. * QuickStart - Many changes can be made on the fly without restarting a web container.

Looking Ahead Struts 2 - 2006?


* Easy-to-test Actions - Struts 2 Actions are HTTP independant and can be tested without resorting to mocks. * Easy-to-customize controller - Struts 1 lets you customize the request processor per module, Struts 2 lets you customize the request handling per action, if you like. * Easy-to-customize tags - Struts 2 tags can be customized by changing an underlying stylesheet. * Easy cancel handling - The Struts 2 Cancel button can go directly to a different action. * Easy Spring integration - Struts 2 Actions are Spring-aware. Just add your own Spring beans! * Easy Plugins - Struts 2 extensions can be added by dropping in a JAR. No manual configuration required!

Looking Ahead Struts 2 - 2006?


* POJO forms - No more ActionForms! Use any JavaBean you like or put properties directly on your Action. No need to use all String properties! * POJO Actions - Any class can be used as an Action class. You don't even have to implement an interface!

Struts 2.0
Bottom Line: Integrated with WebWork Breaks backwards compatibility 1.x is deeply entrenched in enterprise JSF is gaining momentum Struts 1.x has been too long in the 1.x mode Is there future for 2.0? - time will tell