首页 > 解决方案 > 使用 RedirectView 进行重定向,然后在 Controller 方法中访问重定向属性

问题描述

我正在尝试使用 Spring MVC 在我的应用程序中创建用户表单,然后验证 ModelAttribute。如果我的验证失败,我会使用 ModelAndView 返回在表单上显示验证错误的视图。我的控制器代码呈现空白表单是:

@GetMapping("/home")
public ModelAndView getUserHome(){
    ModelAndView mv = new ModelAndView();

    //In actual application, I have more code to put attributes in ModelAndView that will be needed
    //on view form, like select box options
    mv.addObject("user", new User());
    mv.setViewName("user/home/userHome");
    return mv;
}

填写视图上的用户表单并单击提交按钮后,我将请求发布到以下控制器方法:

@PostMapping("/persistUser")
public ModelAndView saveUser(@ModelAttribute("user") @Validated User user, BindingResult bindingResult, ModelMap modelMap){

    ModelAndView mv = new ModelAndView();

    List<ObjectError> errors = bindingResult.getAllErrors();

    if(bindingResult.hasErrors() && !(errors.size() == 1 && errors.get(0).getCode().equals("user.system.mismatch"))){

        mv.addObject("user", user);
        //more code to put more attributes like select box options on view
        mv.setViewName("user/home/userHome");
        return mv;
    }

    //if no errors, I have code to persist user object here. At this point
    //I sure can have userId and pass this as request attribute to redirect URL.
    //But, I need to also pass some messages(based on business logic) about what selections were
    //made on user form. I do not have the option to persist these selections on backend,
    //as our database does not have supporting columns for that. Therefore, I need to send them as 
    //redirect attributes. And these messages would be displayed only once, right after the user 
    //object was created. Upon subsequent visits to this userId view, these messages would no longer 
    //be required. So we don't really need to persist them at backend.

    RedirectView rv = new RedirectView("/user/home?userId="+user.getId(), true, true, false);
    //Here user.getId() is the userId newly persisted.
    modelMap.addAttribute("message", messageSource.getMessage("user.system.mismatch", null, Locale.US));

    return new ModelAndView(rv, modelMap);
}

我在这里获取“用户”模型对象,执行验证,如果出现错误,我通过 ModelAndView 将用户发送回表单。如果没有错误,我有代码来持久化对象并重定向到另一个显示刚刚创建的用户对象的视图。在这个视图中,我需要显示一些我试图作为重定向属性传递给重定向接收控制器方法的消息。请阅读解释我为什么需要传递消息的注释行。我写了我的控制器方法如下:

@GetMapping("/user/home")
public ModelAndView getUser(
                        @RequestParam(name="userId", required = true) String userId,
                        @RequestParam(name="message", required = false) String message,
                        HttpSession session){
    ModelAndView mv = new ModelAndView();

    User user = (User)session.getAttribute("user");

    mv.addObject("message", message);
    mv.setViewName("user/home/view");
    return mv;
}

我无法在此处检索“消息”属性。我也尝试过使用 RedirectAttributes,但无论哪种方式,我都无法检索存储在“消息”中的值。当然我可以发送“消息”作为另一个请求参数,但是我的消息往往很长,我不想看到超长的 URL。

有人可以建议我如何解决这个问题吗?谢谢。

标签: springspring-mvc

解决方案


我终于想出了一种将“消息”添加为 RedirectAttributes 并稍后将其检索为 ModelAttribute 的方法。以下是控制器方法的修改版本:

@PostMapping("/persistUser")
public ModelAndView saveUser(@ModelAttribute("user") @Validated User user, BindingResult bindingResult, RedirectAttributes ra){

ModelAndView mv = new ModelAndView();

List<ObjectError> errors = bindingResult.getAllErrors();

if(bindingResult.hasErrors() && !(errors.size() == 1 && errors.get(0).getCode().equals("user.system.mismatch"))){

    mv.addObject("user", user);
    //more code to put more attributes like select box options on view
    mv.setViewName("user/home/userHome");
    return mv;
}

RedirectView rv = new RedirectView("/user/home?userId="+user.getId(), true, true, false);
//Here user.getId() is the userId newly persisted.
ra.addFlashAttribute("message", messageSource.getMessage("user.system.mismatch", null, Locale.US));

return new ModelAndView(rv);
}

然后重定向接收方法如下:

@GetMapping("/user/home")
public ModelAndView getUser(
                    @RequestParam(name="userId", required = true) String userId,
                    @ModelAttribute(name="message") String message,
                    HttpSession session){
ModelAndView mv = new ModelAndView();

User user = (User)session.getAttribute("user");

mv.addObject("message", message);
mv.setViewName("user/home/view");
return mv;
}

这对我来说按预期工作。


推荐阅读