Recipe9.5.Reporting Errors and Messages from an Action


Recipe 9.5. Reporting Errors and Messages from an Action

Problem

You want to display error messages to the user when things go wrong and success messages when things go right.

Solution

For Struts 1.1, use ActionErrors for reporting errors and ActionMessages for informational messages. For Struts 1.2, use ActionMessages for informational messages and errors.

Discussion

Struts gives you a least four classes and three custom tags for creating, storing, and displaying errors and messages. In Struts 1.1, the ActionErrors class is used to hold a collection of errors, represented by ActionError instances. Each ActionError consists of a key to be looked up from the default MessageResources bundle and an optional set of Objects (up to four) to be used as parameters for message substitution. The Action class in Example 9-9 shows typical usage of ActionErrors.

Example 9-9. Creating ActionErrors from an Action
package com.oreilly.strutsckbk.ch09; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.PropertyUtils; import org.apache.struts.Globals; import org.apache.struts.action.Action; import org.apache.struts.action.ActionError; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; public class RegistrationAction extends Action {     public ActionForward execute(ActionMapping mapping,                                    ActionForm form,                                   HttpServletRequest request,                                    HttpServletResponse response)              throws Exception {                  ActionErrors errors = new ActionErrors( );         String username = (String) PropertyUtils.getSimpleProperty(                                                  form, "username");         String password = (String) PropertyUtils.getSimpleProperty(                                                  form, "password");                  if (username.equals(password)) {             ActionError error = new ActionError(                    "error.register.sameAsPassword", username);             // Use  Action Message with Struts 1.2             //ActionMessage error = new ActionMessage(             //       "error.register.sameAsPassword", username);             errors.add("username", error);         }                  if (!errors.isEmpty( )) {             saveErrors(request, errors);             return mapping.getInputForward( );         }         User user = new User( );         user.setUsername(username);         user.setPassword(password);         SecurityService service = new SecurityService( );         service.add(user);         return mapping.findForward("success");     } }

If you need to create informational messages, use the ActionMessages and ActionMessage classes in a similar fashion, as shown in Example 9-10.

Example 9-10. Creating ActionMessages from an Action
package com.oreilly.strutsckbk.ch09; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.PropertyUtils; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; public class LoginAction extends Action {     public ActionForward execute(ActionMapping mapping,                                    ActionForm form,                                   HttpServletRequest request,                                    HttpServletResponse response)              throws Exception {                  ActionMessages messages = new ActionMessages( );                  String username = (String) PropertyUtils.getSimpleProperty(                                                  form, "username");         String password = (String) PropertyUtils.getSimpleProperty(                                                  form, "password");         SecurityService service = new SecurityService( );         service.authenticate( username, password);         User user = new User( );         user.setUsername(username);         request.getSession( ).setAttribute("user", user);                  ActionMessage message = new ActionMessage(                   "message.login.success", username);         messages.add(ActionMessages.GLOBAL_MESSAGE, message);         if (!messages.isEmpty( )) {             saveMessages( request, messages );         }         return mapping.findForward("success");     } }

Though you'll find little difference in the APIs you use to create errors or messages, the approaches for rendering errors or messages can differ. You can display all errors on a JSP page this way:

<html:errors/>

You would think you could do the same thing with the html:messages tag, but the html:messages tag behaves differently than the html:errors tag. By default, the html:messages tag retrieves the values stored as errorsnot messagesfrom the HttpServletRequest. You must explicitly set the message attribute to true to retrieve values stored as messages.

The html:messages tag was originally created to display error messages without requiring that the message resources contain HTML. After ActionMessages were added to Struts, the html:messages tag was amended to support display of information messages in addition to error messages.


Unlike the html:errors tag, the html:messages tag is a looping tag, like logic:iterate. The tag iterates through ActionErrors, ActionMessages, or an array of strings. The required id attribute defines a page-scoped variable that contains the formatted message. You can use the bean:write or the JSTL c:out tag to display each message:

<html:messages message="true" >     <c:out value="${msg}"/><br /> </html:messages>

Unlike the html:errors tag, the html:messages tag doesn't use a predefined header and footer for display. The presentation details are left to you. Recipe 9.6 shows you some ways to create custom presentation for your errors and messages.

What if you are using Struts 1.2? Well, the ActionError class has been deprecated in favor of ActionMessage in Struts 1.2. On the other hand, ActionErrors has not been deprecated; however, in most places you can use an ActionMessages object where you used to use ActionErrors.

To preserve the Struts core API, ActionErrors was not deprecated.


So, how do you identify errors versus messages? It depends on the attribute name that they are stored under in the request.

The saveErrors( ) method now accepts ActionMessages instead of ActionErrors; yet it stores the object in the request as errors using the key identified by the constant org.apache.struts.Globals.ERROR_KEY. The saveMessages( ) method accepts ActionMessages. It stores the object in the request using the key identified by the org.apache.struts.Globals.MESSAGE_KEY constant. The html:errors and html:messages tags are used in Struts 1.2 just like in Struts 1.1.

If you have ever needed to store messages HTTP session, you can use a new method, added in Struts 1.2, of the base Action class:

saveMessages(HttpSession session, ActionMessages messages);

This method was added to provide a workaround for message display when the rendering page is the result of a redirect instead of a forward. When the messages are saved in the servlet request, the JSP page that displays those messages must be the result of a forward; if the JSP were redirected to the messages would be lost. With the new saveMessages( ) method, messages are saved in the session and are therefore available whether the page is the result of a forward or a redirect.

You can redirect instead of forward to the "success page" to prevent double-submission problems. See Recipe 7.9 for more details.


Now that the messages are saved in the session, what's to prevent them from showing up on a page where they shouldn't? The Struts developers anticipated this problem. The ActionMessages class provides the isAccessed( ) method to indicate if the messages have been displayed (accessed) or not. The RequestProcessor, in the new processCachedMessages( ) method, checks this value and removes any messages stored in the session that have been accessed. So, though you store the messages in the session, they will be cleaned on the next request after they have been displayed.

Here's how you would use the new saveMessages method in the Action shown in Example 9-10:

if (!messages.isEmpty(  )) {     saveMessages( request.getSession(true), messages ); }

You can change the forward for the success page to a redirect:

<forward name="success" path="/login_success.jsp" redirect="true"/>

Your messages will still be available on the success page, and you don't have to worry about double postings.

See Also

Struts 1.2 introduced the ability to have session-scoped action messages. The Struts 1.2 release notes at http://struts.apache.org/userGuide/release-notes.html describe this feature.

You can use the html:messages tag to render errors or messages; see Recipe 9.6 for additional details on this and other related tags.



    Jakarta Struts Cookbook
    Jakarta Struts Cookbook
    ISBN: 059600771X
    EAN: 2147483647
    Year: 2005
    Pages: 200

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net