簡體   English   中英

如何防止Spring 3.0 MVC @ModelAttribute變量出現在URL中?

[英]How do I prevent Spring 3.0 MVC @ModelAttribute variables from appearing in URL?

使用Spring MVC 3.0.0.RELEASE,我有以下Controller:

@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;

  }

}

Controller從填充HTML表單的命令對象中讀取Intake信息,驗證命令對象,將信息持久保存到數據庫,並返回案例編號。

一切都很好,除了當我重定向到intakeDetails.htm頁面時,我得到一個如下所示的URL:

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

如何防止用戶集合顯示在URL中?

model.asMap().clear();
return "redirect:" + news.getUrl();

:)

從Spring 3.1開始, RequestMappingHandlerAdapter提供了一個名為ignoreDefaultModelOnRedirect的標志,如果控制器重定向,您可以使用該標志來防止使用defautl模型的內容。

沒有好的方法可以解決這個問題(即沒有創建自定義組件,沒有過多的顯式xml配置,也沒有RedirectView手動實例化)。

您可以通過其4參數構造函數手動實例化RedirectView也可以在上下文中聲明以下bean(在其他視圖解析器附近):

public class RedirectViewResolver implements ViewResolver, Ordered {
    // Have a highest priority by default
    private int order = Integer.MIN_VALUE; 

    // Uses this prefix to avoid interference with the default behaviour
    public static final String REDIRECT_URL_PREFIX = "redirectWithoutModel:";     

    public View resolveViewName(String viewName, Locale arg1) throws Exception {
        if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
            String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
            return new RedirectView(redirectUrl, true, true, false);
        }
        return null;
    }

    public int getOrder() {
        return order;
    }

    public void setOrder(int order) {
        this.order = order;
    }
}

@ModelAttribute方法注釋旨在用於將參考數據公開給視圖層。 在你的情況下,我不能肯定地說,但我不會說一組用戶符合參考數據。 我建議您在@RequestMapping -annotated處理程序方法中明確地將此信息傳遞給模型。

如果你仍然想使用@ModelAttribute ,那么這里有一個討論重定向問題的博客條目。

但是所有前面的示例都有一個共同的問題,因為所有@ModelAttribute方法都在執行處理程序之前運行,如果處理程序返回重定向,則模型數據將作為查詢字符串添加到url中。 應該不惜一切代價避免這種情況,因為它可能會泄露一些關於如何整理應用程序的秘密。

他建議的解決方案(參見博客的第4部分)是使用HandlerInterceptorAdapter使公共參考數據對視圖可見。 由於參考數據不應與控制器緊密耦合,因此在設計方面不應造成問題。

我實現了Sid答案的變體,減少了復制和粘貼:

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:

<bean id="viewResolver" class="com.example.RedirectsNotExposingModelUrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
</bean>

我知道這個問題和答案是陳舊的,但我在自己遇到類似問題之后偶然發現了它,而且我找不到其他很多信息。

我認為接受的答案不是很好。 axtavt下方的答案要好得多。 問題不在於控制器上的注釋模型屬性是否有意義。 它是關於如何從通常使用ModelAttributes的控制器中發出“干凈”重定向。 控制器本身通常需要參考數據,但有時它需要在其他地方重定向以獲得異常條件或其他任何東西,並且傳遞參考數據沒有意義。 我認為這是一種有效且常見的模式。

(Fwiw,我在Tomcat中意外地遇到了這個問題。重定向根本就沒有用了,我得到了奇怪的錯誤消息,如:java.lang.ArrayIndexOutOfBoundsException:8192。我最終確定Tomcat的默認最大標頭長度是8192.我沒有' t意識到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>

手動創建一個RedirectView對象為我工作:

@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); 
}

恕我直言,這應該是重定向時的默認行為

以下是如何使用基於Java的配置(Spring 3.1+,我認為,使用4.2測試):

@Configuration
public class MvcConfig extends WebMvcConfigurationSupport {

    @Override
    @Bean
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
        RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
        adapter.setIgnoreDefaultModelOnRedirect(true);
        return adapter;
    }

    // possible other overrides as well

}

或者,將該請求設為POST。 獲取請求僅顯示模型屬性作為URL中出現的請求參數。

不要使用@ModelAttribute 將用戶顯式存儲在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()發生驗證錯誤。 如果您只想返回表單的邏輯名稱,您還必須記住與用戶重新填充模型,否則表單將無法正確設置。

嘗試將以下代碼添加到servlet-config.xml中

<mvc:annotation-driven ignoreDefaultModelOnRedirect="true" />

有時這會解決問題。

如果有助於您的事業,有一個解決方法。

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

在這里你已經返回String of Collection。 使其成為User的集合(它可以是表示用戶的類包裝字符串,或者是具有關於用戶的一堆數據的類)。 只有字符串才會出現問題。 如果返回的Collection包含任何其他對象,則不會發生這種情況。 但是,這只是一種解決方法,可能根本不需要。 只是我的兩分錢。 就這樣 -

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM