Spring MVC Controller 使用 URL 参数重定向而不是响应

Posted

技术标签:

【中文标题】Spring MVC Controller 使用 URL 参数重定向而不是响应【英文标题】:Spring MVC Controller redirect using URL parameters instead of in response 【发布时间】:2010-03-23 14:17:48 【问题描述】:

我正在尝试在我的 Spring MVC 应用程序中实现 RESTful url。一切都很好,除了处理表单提交。我需要重定向回原始表单或“成功”页面。

@Controller
@RequestMapping("/form")
public class MyController 

    @RequestMapping(method = RequestMethod.GET)
    public String setupForm() 
        // do my stuff
        return "myform";
    

    @RequestMapping(method = RequestMethod.POST)
    public String processForm(ModelMap model)             
        // process form data

        model.addAttribute("notification", "Successfully did it!");
        return "redirect:/form";
    

但是,正如我在Spring documentation 中所读到的,如果您重定向任何参数,都会将其放入 url。这对我不起作用。解决这个问题的最优雅的方法是什么?

【问题讨论】:

你想达到什么重定向 URL? 没关系,我只需要在处理完post数据后重定向到一个页面,并通知用户他们提交的内容处理成功。似乎这是一个常见的请求jira.springframework.org/browse/SPR-1294。但可能暂时不会修复。 看起来这两个相关票证中描述的任何一个修复程序都不能解决您的特定问题:其中一个是关于控制哪些模型属性作为查询字符串公开(但仍会公开一些),另一个是关于添加属性作为 url 路径的一部分(例如,这对于 ID 来说非常安静,但仍然没有给您提供成功消息的地方)。 【参考方案1】:

我遇到了同样的问题。像这样解决它:

return new ModelAndView("redirect:/user/list?success=true");

然后我的控制器方法如下所示:

public ModelMap list(@RequestParam(required=false) boolean success) 
    ModelMap mm = new ModelMap();
    mm.put(SEARCH_MODEL_KEY, campaignService.listAllCampaigns());
    if(success)
        mm.put("successMessageKey", "campaign.form.msg.success");
    return mm;

除非您想发送简单的数据,而不是集合,否则可以完美运行。那么我猜你必须使用会话。

【讨论】:

【参考方案2】:

这个问题是由模型属性被持久化到查询字符串中引起的(正如其他人所说)——这通常是不可取的,并且有产生安全漏洞和荒谬查询字符串的风险。我通常的解决方案是永远不要在 Spring MVC 中使用字符串进行重定向,而是使用可以配置为不公开模型属性的 RedirectView(请参阅:http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/web/servlet/view/RedirectView.html

RedirectView(String url, boolean contextRelative, boolean http10Compatible, boolean exposeModelAttributes)

所以我倾向于使用 util 方法来执行“安全重定向”,例如:

public static RedirectView safeRedirect(String url) 
    RedirectView rv = new RedirectView(url);
    rv.setExposeModelAttributes(false);
    return rv;

另一种选择是使用 bean 配置 XML:

<bean id="myBean" class="org.springframework.web.servlet.view.RedirectView">
   <property name="exposeModelAttributes" value="false" />
   <property name="url" value="/myRedirect"/>
</bean>

同样,您可以将其抽象为自己的类以避免重复(例如 SafeRedirectView)。


关于“清除模型”的说明 - 这与在所有情况下都“不暴露模型”不同。我工作的一个站点有很多过滤器,它们向模型添加了东西,这意味着在重定向之前清除模型不会阻止长查询字符串。我还建议“不公开模型属性”比“在重定向之前清除模型”更符合语义。

【讨论】:

RedirectView - 安全重定向对我有用。谢谢 MatCarey!【参考方案3】:

您可以让processForm() 返回一个 View 对象,并让它返回具有setExposeModelAttributes() 参数的具体类型RedirectView

当您返回以"redirect:" 为前缀的视图名称时,Spring MVC 无论如何都会将其转换为RedirectView 对象,它只是将setExposeModelAttributes 转换为true(我认为这是一个奇怪的默认值)。

【讨论】:

如果成功消息没有作为查询字符串公开,它如何到达重定向视图? 你希望它如何到达成功页面?如果您想进行重定向,那么您似乎需要将其作为请求参数传递,或者您可以在会话中设置它并在下一页将其删除。但它必须以某种方式通过。 好吧,我可以返回一个带有“/form”作为构造参数的 ModelAndView。但是,这会导致页面成为 POST 请求。因此,如果他们要刷新页面,它将重新发送发布请求。不完全是我想要发生的事情。因此重定向。但似乎重定向还不支持这一点。设置为3.1修改。【参考方案4】:

http://jira.springframework.org/browse/SPR-6464 为我提供了在 Spring MVC 提供功能(可能在 3.0.2 版本中)之前让事情正常工作所需的东西。虽然我只是简单地实现了它们临时拥有的类并将过滤器添加到我的 Web 应用程序上下文中。效果很好!

【讨论】:

作为一项更新,此功能计划用于 Spring 3.1 而且确实是在Spring 3.1中实现的。 链接已损坏。【参考方案5】:

如果您不想在 URL 中显示成功消息,那么一种选择是将其放入会话中(在 processForm 方法中),然后在 setupForm 方法中检查(并删除它)。

编辑添加:如果手动执行此操作很痛苦,那么您可以编写一个 RedirectView 的子类,添加一个“消息”属性并将其插入会话中的过程。不过,不确定是否有一种简单的方法可以将消息从会话中返回...

老实说,我不认为有一个简单的答案——HTTP 重定向的本质是状态不会被转移;如果你想保持状态,你会被各种常用的方式来维护 Web 应用程序中的状态:会话、cookie、查询字符串......

【讨论】:

当然可以,但是由于我的应用程序比一个应用程序大得多,因此必须为每个表单都这样做是一件很痛苦的事情。 Struts 似乎提供了一种叫做 ActionMessages 的东西。我不完全确定它是什么。此外,使用 Ruby On Rails,他们提供了 flash[:notification]。这基本上就是我想要实现的目标。闪存消息被存储到下一个动作(导致重定向或你有什么)。似乎jroller.com/raible/entry/migrating_from_struts_to_spring 试图解决这个问题。他的方式似乎很有趣。 嗯,在我看来,他的方法基本上是按照我的想法包装会话并将消息放入会话中。但是他给出了实际的代码,所以肯定更有用。【参考方案6】:

嘿,你可以只做一件简单的事情,而不是使用模型来发送参数,使用 HttpServletRequest 对象并这样做

HttpServletRequest request;
request.setAttribute("param", "value")

现在您的参数将不会显示在您的 url 标头中,希望它可以工作:)

【讨论】:

【参考方案7】:
@RequestMapping(path="/apps/add", method=RequestMethod.POST)
public String addApps(String appUrl, Model model, final RedirectAttributes redirectAttrs) 
    if (!validate(appUrl)) 
       redirectAttrs.addFlashAttribute("error", "Validation failed");
    
    return "redirect:/apps/add"
 

@RequestMapping(path="/apps/add", method=RequestMethod.GET)
public String addAppss(Model model) 
    String error = model.asMap().get("error");

【讨论】:

以上是关于Spring MVC Controller 使用 URL 参数重定向而不是响应的主要内容,如果未能解决你的问题,请参考以下文章

Spring mvc Controller接口

servlet使用sessio和spring mvc中的controller使用session

Spring MVC Controller 使用 URL 参数重定向而不是响应

Spring MVC学习笔记——Controller

Spring MVC Controller中JsonView的动态选择

使用表单主体的 Spring MVC Controller 方法映射