Java 如何防止Spring3.0MVC@ModelAttribute变量出现在URL中?

Java 如何防止Spring3.0MVC@ModelAttribute变量出现在URL中?,java,spring,spring-mvc,Java,Spring,Spring Mvc,使用Spring MVC 3.0.0.0版本,我有以下控制器: @Controller @RequestMapping("/addIntake.htm") public class AddIntakeController{ private final Collection<String> users; public AddIntakeController(){ users = new ArrayList<String>(); users.add

使用Spring MVC 3.0.0.0版本,我有以下控制器:

@Controller
@RequestMapping("/addIntake.htm")
public class AddIntakeController{

  private final Collection<String> users;

  public AddIntakeController(){
    users = new ArrayList<String>();
    users.add("user1");
    users.add("user2");
    // ...
    users.add("userN");
  }

  @ModelAttribute("users")
  public Collection<String> getUsers(){
    return this.users;
  }

  @RequestMapping(method=RequestMethod.GET)
  public String setupForm(ModelMap model){

    // Set up command object
    Intake intake = new Intake();
    intake.setIntakeDate(new Date());
    model.addAttribute("intake", intake);

    return "addIntake";
  }

  @RequestMapping(method=RequestMethod.POST)
  public String addIntake(@ModelAttribute("intake")Intake intake, BindingResult result){

    // Validate Intake command object and persist to database
    // ...

    String caseNumber = assignIntakeACaseNumber();

    return "redirect:intakeDetails.htm?caseNumber=" + caseNumber;

  }

}
@控制器
@请求映射(“/addIntake.htm”)
公共类附加控制器{
私人最终收藏用户;
公共附加控制器(){
users=newarraylist();
用户。添加(“用户1”);
用户。添加(“用户2”);
// ...
用户。添加(“用户n”);
}
@ModelAttribute(“用户”)
公共集合getUsers(){
将此文件返回给用户;
}
@RequestMapping(method=RequestMethod.GET)
公共字符串设置窗体(ModelMap模型){
//设置命令对象
进气=新进气();
setIntakeDate(新日期());
model.addAttribute(“摄入”,摄入);
返回“addIntake”;
}
@RequestMapping(method=RequestMethod.POST)
公共字符串addIntake(@ModelAttribute(“摄入”)摄入,BindingResult){
//验证接收命令对象并持久化到数据库
// ...
字符串caseNumber=AssignIntakeAccasEnumber();
return“redirect:intakdetails.htm?caseNumber=“+caseNumber;
}
}
控制器从HTML表单填充的命令对象中读取接收信息,验证命令对象,将信息持久化到数据库,并返回案例编号

一切都很好,除了当我重定向到IntakDetails.htm页面时,我得到的URL如下所示:

http://localhost:8080/project/intakeDetails.htm?caseNumber=1&users=user1&users=user2&users=user3&users=user4...


如何防止用户集合显示在URL中

没有解决此问题的好方法(即不创建自定义组件、不进行过多的显式xml配置以及不手动实例化
重定向视图

您可以通过其4参数构造函数手动实例化
RedirectView
,或者在上下文中声明以下bean(靠近其他视图解析器):


不要使用
@modeldattribute
。显式地将用户存储在
ModelMap
中。不管怎样,您在命令对象上也做了同样多的工作

@RequestMapping(method=RequestMethod.GET)
    public String setupForm(ModelMap model){

        // Set up command object
        Intake intake = new Intake();
        intake.setIntakeDate(new Date());
        model.addAttribute("intake", intake);

        model.addAttribute("users", users);

        return "addIntake";
    }

这样做的缺点是如果在
addIntake()
中发生验证错误。如果只想返回表单的逻辑名称,还必须记住使用用户重新填充模型,否则表单将无法正确设置。

方法注释用于视图层。在您的情况下,我不能肯定,但我不会说一组用户可以作为参考数据。我建议您在
@RequestMapping
注释的处理程序方法中显式地将此信息传递给模型

如果仍要使用
@modeldattribute
,这里有一个条目讨论重定向问题

但是前面所有的例子都有一个 常见问题,如所有@modeldattribute 方法在处理程序启动之前运行 如果处理程序返回 重定向将添加的模型数据 以查询字符串的形式添加到url。这 应该不惜一切代价避免它 可能会泄露一些你的秘密 我已经准备好了你的申请表


他建议的解决方案(参见博客的第4部分)是使用一个工具使公共参考数据对视图可见。由于参考数据不应与控制器紧密耦合,因此从设计角度来看,这不应造成问题

我知道这个问题和答案很古老,但我自己也遇到过类似的问题,所以才偶然发现了它,而且我找不到很多其他信息

我认为公认的答案不是很好。axtavt在其下方给出的答案要好得多。问题不在于在控制器上注释模型属性是否有意义。这是关于如何从通常使用ModelAttributes的控制器中发出“干净”重定向。控制器本身通常需要引用数据,但有时它需要重定向到其他地方,以防出现异常情况或其他情况,传递引用数据是没有意义的。我认为这是一种有效且普遍的模式

(Fwiw,我在Tomcat上意外遇到了这个问题。重定向根本不起作用,我收到了一些奇怪的错误消息,如:java.lang.ArrayIndexOutOfBoundsException:8192。我最终确定Tomcat的默认最大头长度为8192。我没有意识到ModelAttributes会自动添加到重定向URL,并且这导致标头长度超过Tomcat的最大标头长度。)


:)

在我的应用程序中,我没有在重定向中公开模型属性的任何用例,因此我扩展了org.springframework.web.servlet.view.UrlBasedViewResolver以覆盖createView方法并在应用程序上下文中声明:

public class UrlBasedViewResolverWithouthIncludingModeAtttributesInRedirect extends   UrlBasedViewResolver {

        @Override
        protected View createView(String viewName, Locale locale) throws Exception {
            // If this resolver is not supposed to handle the given view,
            // return null to pass on to the next resolver in the chain.
            if (!canHandle(viewName, locale)) {
                return null;
            }
            // Check for special "redirect:" prefix.
            if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
                String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
                boolean exposeModelAttributes = false;
                return new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible(), exposeModelAttributes);
            }
            // Check for special "forward:" prefix.
            if (viewName.startsWith(FORWARD_URL_PREFIX)) {
                String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
                return new InternalResourceView(forwardUrl);
            }
            // Else fall back to superclass implementation: calling loadView.
            return super.createView(viewName, locale);
        }

}


  <bean id="viewResolver" class="com.acme.spring.UrlBasedViewResolverWithouthIncludingModeAtttributesInRedirect">

  </bean>
公共类UrlBasedViewResolver不包含modeattributesinrect扩展UrlBasedViewResolver{
@凌驾
受保护视图createView(字符串viewName、区域设置)引发异常{
//如果此解析器不应处理给定视图,
//返回null以传递给链中的下一个解析器。
如果(!canHandle(视图名称、区域设置)){
返回null;
}
//检查特殊的“重定向:”前缀。
if(viewName.startsWith(重定向\ URL \前缀)){
String redirectUrl=viewName.substring(REDIRECT_URL_PREFIX.length());
布尔exposeModelAttributes=false;
返回新的RedirectView(redirectUrl、isRedirectContextRelative()、isRedirectHttp10Compatible()、exposeModelAttributes);
}
//检查特殊的“转发:”前缀。
if(viewName.startsWith(转发\ URL \前缀)){
String forwardUrl=viewName.substring(FORWARD_URL_PREFIX.length());
返回新的内部
model.asMap().clear();
return "redirect:" + news.getUrl();
public class UrlBasedViewResolverWithouthIncludingModeAtttributesInRedirect extends   UrlBasedViewResolver {

        @Override
        protected View createView(String viewName, Locale locale) throws Exception {
            // If this resolver is not supposed to handle the given view,
            // return null to pass on to the next resolver in the chain.
            if (!canHandle(viewName, locale)) {
                return null;
            }
            // Check for special "redirect:" prefix.
            if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
                String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
                boolean exposeModelAttributes = false;
                return new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible(), exposeModelAttributes);
            }
            // Check for special "forward:" prefix.
            if (viewName.startsWith(FORWARD_URL_PREFIX)) {
                String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
                return new InternalResourceView(forwardUrl);
            }
            // Else fall back to superclass implementation: calling loadView.
            return super.createView(viewName, locale);
        }

}


  <bean id="viewResolver" class="com.acme.spring.UrlBasedViewResolverWithouthIncludingModeAtttributesInRedirect">

  </bean>
@RequestMapping(method=RequestMethod.POST)
public ModelAndView addIntake(@ModelAttribute("intake")Intake intake, BindingResult result){

    // Validate Intake command object and persist to database
    // ...

    String caseNumber = assignIntakeACaseNumber();

    RedirectView rv = new RedirectView("redirect:intakeDetails.htm?caseNumber=" + caseNumber);
    rv.setExposeModelAttributes(false);
    return new ModelAndView(rv); 
}
      @ModelAttribute("users")
      public Collection<String> getUsers(){
           return this.users;
      }
      @ModelAttribute("users")
      public Collection<User> getUsers(){
           return this.users;
      }
public class RedirectsNotExposingModelUrlBasedViewResolver extends UrlBasedViewResolver {

    @Override
    protected View createView(String viewName, Locale locale) throws Exception {
        View view = super.createView(viewName, locale);
        if (view instanceof RedirectView) {
            ((RedirectView) view).setExposeModelAttributes(false);
        }
        return view;
    }

}
<bean id="viewResolver" class="com.example.RedirectsNotExposingModelUrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
</bean>
<mvc:annotation-driven ignoreDefaultModelOnRedirect="true" />