Spring:如何重定向URL且不重置表单输入内容
表单提交出错后保留输入内容的两种解决方案
一、重定向时保留表单数据(使用Spring Flash Attributes)
重定向会发起新的GET请求,原POST请求的Model数据无法直接传递,Spring的Flash Attributes可以解决这个问题——它会把数据暂存在Session中,重定向完成后自动取出并清除Session中的数据。
修改POST接口代码
把原来的ModelMap换成RedirectAttributes,在异常捕获时将表单数据和错误信息存入Flash:
@RequestMapping(value=POST_FORM, method=RequestMethod.POST) public String postForm( @ModelAttribute("createForm") StoreDto form, @PathVariable String channelCode, Authentication authentication, RedirectAttributes redirectAttributes) { UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal(); try { form.setClientId(userPrincipal.getUser().getClient().getId()); ruleService.save(form); }catch(Exception e) { // 存入表单数据和错误信息到Flash redirectAttributes.addFlashAttribute("createForm", form); redirectAttributes.addFlashAttribute("err", e.getClass().getSimpleName()); return "redirect:/config/"+form.getChannelCode()+"/form/create"; } return "redirect:/config/"+form.getChannelCode()+"/list"; }
修改表单页面的GET接口代码
添加参数接收Flash中的表单数据,并将其放入Model供页面回显:
@GetMapping(CREATE_FORM) public String createForm(@PathVariable String channelCode, @RequestParam(required = false) String error, Authentication authentication, ModelMap model, @ModelAttribute(value = "createForm", required = false) StoreDto form) { UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal(); SalesDto salesDto = salesService.findByClientIdAndChannelCode(userPrincipal.getUser().getClient().getId(), channelCode); List<StoreDto> storeDtos = ruleService.findAllRuleStoreByClientIdAndChannelCode(userPrincipal.getUser().getClient().getId(), channelCode); model.addAttribute("channel", salesDto); model.addAttribute("stores", storeDtos); // 优先使用Flash中的错误信息,其次是URL参数中的 if (model.containsAttribute("err")) { model.addAttribute("err", model.getAttribute("err")); } else if (error != null) { model.addAttribute("err", error); } // 如果有Flash传递的表单数据,回显到页面 if (form != null) { model.addAttribute("createForm", form); } return "configuration/form_create"; }
二、无需重定向的替代方案
如果不想用重定向,直接在POST接口异常时返回表单视图,同时将用户输入的表单数据和页面所需的其他数据重新放入Model,就能直接保留输入内容。
修改POST接口代码
异常捕获时,重新填充表单页面的公共数据,把用户输入的表单数据放回Model,然后直接返回表单视图:
@RequestMapping(value=POST_FORM, method=RequestMethod.POST) public String postForm( @ModelAttribute("createForm") StoreDto form, @PathVariable String channelCode, Authentication authentication, ModelMap model) { UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal(); try { form.setClientId(userPrincipal.getUser().getClient().getId()); ruleService.save(form); return "redirect:/config/"+form.getChannelCode()+"/list"; // 成功提交后仍重定向,避免重复提交 }catch(Exception e) { // 填充表单页面所需的公共数据 SalesDto salesDto = salesService.findByClientIdAndChannelCode(userPrincipal.getUser().getClient().getId(), channelCode); List<StoreDto> storeDtos = ruleService.findAllRuleStoreByClientIdAndChannelCode(userPrincipal.getUser().getClient().getId(), channelCode); model.addAttribute("channel", salesDto); model.addAttribute("stores", storeDtos); model.addAttribute("err", e.getClass().getSimpleName()); model.addAttribute("createForm", form); // 回显用户输入的表单数据 return "configuration/form_create"; // 直接返回表单视图,不重定向 } }
优化建议:抽取公共代码
为了避免重复代码,可以把填充公共数据的逻辑抽成私有方法:
private void populateFormCommonData(UserPrincipal userPrincipal, String channelCode, ModelMap model) { SalesDto salesDto = salesService.findByClientIdAndChannelCode(userPrincipal.getUser().getClient().getId(), channelCode); List<StoreDto> storeDtos = ruleService.findAllRuleStoreByClientIdAndChannelCode(userPrincipal.getUser().getClient().getId(), channelCode); model.addAttribute("channel", salesDto); model.addAttribute("stores", storeDtos); }
之后在createForm方法和postForm的异常块中调用这个方法即可。
内容的提问来源于stack exchange,提问作者Ernest Daniel
相关产品推荐
相关产品推荐

