开发者

Spring MVC Validation - Avoiding POST-back

I'd like to validate a Spring 3 MVC form. When an element is invalid, I want to re-display the form with a validation message. This is pretty simple so far. The rub is, when the user hits refresh after an invalid submission, I don't want them to POST, I want them to GET. This means I need to do a redirect from t开发者_如何学Pythonhe form POST (submission) to re-display the form with validation messages (the form is submitted via a POST).

I'm thinking the best way to do this is to use SessionAttributeStore.retrieveAttribute to test if the form is already in the user's session. If it is, use the store form, otherwise create a new form.

Does this sound right? Is there a better way to do this?


To solve this problem, I store the Errors object in the session after a redirect on a POST. Then, on a GET, I put it back in the model. There are some holes here, but it should work 99.999% of the time.

public class ErrorsRedirectInterceptor extends HandlerInterceptorAdapter {
    private final static Logger log = Logger.getLogger(ErrorsRedirectInterceptor.class);

    private final static String ERRORS_MAP_KEY = ErrorsRedirectInterceptor.class.getName()
            + "-errorsMapKey";

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler, ModelAndView mav)
        throws Exception 
    {
        if (mav == null) { return; }

        if (request.getMethod().equalsIgnoreCase(HttpMethod.POST.toString())) {
            // POST
            if (log.isDebugEnabled()) { log.debug("Processing POST request"); }
            if (SpringUtils.isRedirect(mav)) {
                Map<String, Errors> sessionErrorsMap = new HashMap<String, Errors>();
                // If there are any Errors in the model, store them in the session
                for (Map.Entry<String, Object> entry : mav.getModel().entrySet()) {
                    Object obj = entry.getValue();
                    if (obj instanceof Errors) {
                        if (log.isDebugEnabled()) { log.debug("Adding errors to session errors map"); }
                        Errors errors = (Errors) obj;
                        sessionErrorsMap.put(entry.getKey(), errors);
                    }
                }
                if (!sessionErrorsMap.isEmpty()) {
                    request.getSession().setAttribute(ERRORS_MAP_KEY, sessionErrorsMap);
                }
            }
        } else if (request.getMethod().equalsIgnoreCase(HttpMethod.GET.toString())) {
            // GET
            if (log.isDebugEnabled()) { log.debug("Processing GET request"); }
            Map<String, Errors> sessionErrorsMap =
                    (Map<String, Errors>) request.getSession().getAttribute(ERRORS_MAP_KEY);
            if (sessionErrorsMap != null) {
                if (log.isDebugEnabled()) { log.debug("Adding all session errors to model"); }
                mav.addAllObjects(sessionErrorsMap);
                request.getSession().removeAttribute(ERRORS_MAP_KEY);
            }
        }
    }
}


It's not clear from your question but it sounds like your GET and POST actions are mapped to the same handler. In that case you can do something like:

if ("POST".equalsIgnoreCase(request.getMethod())) {
    // validate form
    model.addAttribute(form);
    return "redirect:/me.html";
}
model.addAttribute(new MyForm());
return "/me.html";

In the JSP check if there are any error on the form and display as needed.


Such approach is called PRG (POST/REdirect/GET) design pattern I explained it few days ago as one of the answers:

Spring MVC Simple Redirect Controller Example

Hope it helps :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜