Dashboard > WebWork > ... > Cookbook > Using WebWork and XWork with JSP 2.0 and JSTL 1.1
  WebWork Log In View a printable version of the current page.  
  Using WebWork and XWork with JSP 2.0 and JSTL 1.1
Added by Jens Riboe, last edited by Philip Luppens on Feb 22, 2007  (view change)
Labels: 
(None)

JSTL support is fully integrated. You no longer need to use this approach.

WW2/WX1 and its taglib is oriented towards OGNL, which is using a value stack
for all action properties. These values are not direct available for the
expression language of JSP2/JSTL1.1.

However, it's easy to populate the request
attribute set, with all gettable properties of an action object. You need to provide
an interceptor that does the job, by register a PreResultListener which is
invoked after the return of Action.execute() but before the rendering of the result .

The interceptor below is using Jakarta BeanUtils. It first extracts all getters
of the current action, invokes them one at the time and stores the values into a map.
Then it iterates over the map and populates the request attribute set.
The double iteration is not needed, it's just there for clarity.

class ActionPropertyExportInterceptor

package com.whatever.interceptors;

import com.opensymphony.webwork.WebWorkStatics;
import com.opensymphony.xwork.Action;
import com.opensymphony.xwork.ActionInvocation;
import com.opensymphony.xwork.interceptor.AroundInterceptor;
import com.opensymphony.xwork.interceptor.PreResultListener;
import org.apache.commons.beanutils.PropertyUtils;
import javax.servlet.http.HttpServletRequest;
import java.beans.PropertyDescriptor;
import java.util.*;

/**
 * Populates HTTP Request Attributes with all gettable properties of the current action.
 */
public class ActionPropertyExportInterceptor extends AroundInterceptor {
    protected void before(ActionInvocation invocation) throws Exception {
        invocation.addPreResultListener( new PropertyExporter() );
    }
    protected void after(ActionInvocation dispatcher, String result) throws Exception { }

    public static class PropertyExporter implements PreResultListener {
        private static final List   ignore = Arrays.asList(new String[] {"class", "texts"}); //skip getClass,...

        //Invoked after Action.execute() but before Result
        //Calls all getters of the action and insert the values into the request
        public void beforeResult(ActionInvocation invocation, String resultCode) {
            Map                 props   = extractGetterPropertyValues( invocation.getAction() );
            HttpServletRequest  request = getRequest(invocation);
            for (Iterator it = props.entrySet().iterator(); it.hasNext();) {
                Map.Entry   e = (Map.Entry) it.next();
                request.setAttribute((String) e.getKey(), e.getValue());
            }
        }

        public Map extractGetterPropertyValues(Object bean) {
            PropertyDescriptor[]  descr = PropertyUtils.getPropertyDescriptors(bean);
            Map                   props = new HashMap();
            for (int i = 0; i < descr.length; i++) {
                PropertyDescriptor d = descr[i];
                if (d.getReadMethod() == null) continue;
                if (ignore.contains(d.getName())) continue;

                try {
                    props.put(d.getName(), PropertyUtils.getProperty(bean, d.getName()));
                } catch (Exception e) { }
            }
            return props;
        }

        public HttpServletRequest getRequest(ActionInvocation invocation) {
            return (HttpServletRequest) invocation.getInvocationContext().get(WebWorkStatics.HTTP_REQUEST);
        }
    }
}

Don't forget to declare the interceptor in your xwork.xml file and insert it
into your interceptor stack.

xwork.xml snippet

<interceptor name="export" class="com.whatever.interceptors.ActionPropertyExportInterceptor" />
. . .
<interceptor-stack name="standard-interceptors">
    <interceptor-ref name="timer" />
    <interceptor-ref name="logger" />
    <interceptor-ref name="params" />
*    <interceptor-ref name="export"/>*
    <interceptor-ref name="validateParams"/>
    <interceptor-ref name="awarePlugger" />
</interceptor-stack>

Your action need to provide getters for all properties that should be exported into the
request attribute set.

class ViewUser

public class ViewUser extends ActionSupport {
    private int                         id;
    private User                        user;

    public String execute() throws Exception {
        user = findUser( getId() );
        return Action.SUCCESS;
    }

    public  int   getId()          {return id;}
    public  void  setId(int id)    {this.id = id;}
*    public  User  getUser()        {return user;}*

    private User  findUser(int id) {...}
}

The User class might look like this

class User

import java.util.Date;
public class User {
    private int     id;
    private String  firstName, lastName, email;
    private String  street, zip, city;
    private Date    date;
    
    public String  getFirstName() {return firstName;}
    //..._getters and setters_...
}

Finally, using the samples above you can write your JSP2 page like this.

ViewUser.jsp

<%@ taglib prefix="c"   uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn"  uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
<head>
    <title>Info about ${user.firstName}</title>
</head>
<body>
    <h1>Info about ${user.firstName} ${user.lastName} [OS:ID=${user.id}]</h1>
    <table border="1" cellspacing="0" cellpadding="2" width="90%" >
    <tr>
        <th>Name</th> <td>${user.firstName} ${user.lastName}</td>
    </tr>
    <tr>
        <th>Created</th> <td><fmt:formatDate value="${user.date}" pattern="yyyy-MM-dd HH:mm"/></td>
    </tr>
    <tr>
        <th>Email</th> <td>${user.email}</td>
    </tr>
    <tr>
        <th>Address</th> <td>${user.street} ${user.zip} ${fn:toUpperCase(user.city)}</td>
    </tr>
    </table>
</body>
</html>

Displaying validation errors with JSTL

<c:if test="${!empty fieldErrors || !empty actionErrors}">
  <div class="red">
    <ul>
      <c:forEach items="${fieldErrors}" var="fieldError">
        <c:forEach items="${fieldError.value}" var="error">
          <li>${error}</li>
        </c:forEach>
      </c:forEach>
      <c:forEach items="${actionErrors}" var="actionError">
        <li>${actionError}</li>
      </c:forEach>
    </ul>
  </div>
</c:if>

Site powered by a free Open Source Project / Non-profit License (more) of Confluence - the Enterprise wiki.
Learn more or evaluate Confluence for your organisation.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.2.9 Build:#527 Sep 07, 2006) - Bug/feature request - Contact Administrators