假如邏輯試圖名為"hello",因此viewResolver將解" />

亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Spring MVC 中的 forward 和 redirect

系統(tǒng) 2434 0

Spring MVC 中,我們在返回邏輯視圖時,框架會通過 viewResolver 來解析得到具體的 View,然后向瀏覽器渲染。假設(shè)邏輯視圖名為 hello,通過配置,我們 配置某個 ViewResolver 如下:

Xml代碼 復(fù)制代碼 ? 收藏代碼
  1. < bean ? class = "org.springframework.web.servlet.view.InternalResourceViewResolver" > ??
  2. ???? < description > ??
  3. ????????假如邏輯試圖名為?"hello",因此?viewResolver?將解析成?/WEB-INF/jsp/hello.jsp ??
  4. ???? </ description > ??
  5. ???? < property ? name = "order" ? value = "10" ? /> ??
  6. ???? < property ? name = "prefix" ? value = "/WEB-INF/jsp/" ? /> ??
  7. ???? < property ? name = "suffix" ? value = ".jsp" ? /> ??
  8. </ bean > ??
      <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<description>
		假如邏輯試圖名為 "hello",因此 viewResolver 將解析成 /WEB-INF/jsp/hello.jsp
	</description>
	<property name="order" value="10" />
	<property name="prefix" value="/WEB-INF/jsp/" />
	<property name="suffix" value=".jsp" />
</bean>

    


??????? 實(shí)際上,框架還是通過 forward 的方式轉(zhuǎn)發(fā)到了 /WEB-INF/jsp/hello.jsp。如果邏輯視圖名是 /hello,實(shí)際還是轉(zhuǎn)發(fā)到了 /WEB-INF/jsp/hello.jsp,即 /WEB-INF/jsp//hello.jsp 等同于 /WEB-INF/jsp/hello.jsp。

??????? 現(xiàn)在有個問題,如果 /hello 就是某個 controller 的映射,我想轉(zhuǎn)發(fā)到這個 controller,怎么辦?我們可以通過 forward 前綴來達(dá)到轉(zhuǎn)發(fā)到其它資源的目的:

Java代碼 復(fù)制代碼 ? 收藏代碼
  1. public ?String?handle()?{ ??
  2. ???? //?return?"forward:/hello"?=>?轉(zhuǎn)發(fā)到能夠匹配?/hello?的?controller?上 ??
  3. ???? //?return?"hello"?=>?實(shí)際上還是轉(zhuǎn)發(fā),只不過是框架會找到該邏輯視圖名對應(yīng)的?View?并渲染 ??
  4. ???? //?return?"/hello"?=>?同?return?"hello" ??
  5. ???? return ? "forward:/hello" ; ??
  6. }??
      public String handle() {
    // return "forward:/hello" => 轉(zhuǎn)發(fā)到能夠匹配 /hello 的 controller 上
    // return "hello" => 實(shí)際上還是轉(zhuǎn)發(fā),只不過是框架會找到該邏輯視圖名對應(yīng)的 View 并渲染
    // return "/hello" => 同 return "hello"
    return "forward:/hello";
}

    



??????? 同理,如果我們想重定向到某個資源,我們可以通過 redirect 前綴來達(dá)到重定向到其它資源的目的:

Java代碼 復(fù)制代碼 ? 收藏代碼
  1. public ?String?handle()?{ ??
  2. ???? //?重定向到?/hello?資源 ??
  3. ???? return ? "redirect:/hello" ; ??
  4. }??
      public String handle() {
    // 重定向到 /hello 資源
    return "redirect:/hello";
}

    


??????? 還記得 java web 中的轉(zhuǎn)發(fā)和重定向 這篇文章嗎?我強(qiáng)調(diào)過,如果想做轉(zhuǎn)發(fā)操作,不需要寫 contextPath;如果想做重定向操作,推薦寫包括 contextPath 在內(nèi)的 url。因此, 在使用 Spring MVC 的 redirect 前綴時,里面是有坑的!

??????? 仍然假設(shè)應(yīng)用程序的 contextPath 為 /ctx。我們來看看 RedirectView.renderMergedOutputModel 的片段:

Java代碼 復(fù)制代碼 ? 收藏代碼
  1. protected ? void ?renderMergedOutputModel( ??
  2. ????Map<String,?Object>?model,?HttpServletRequest?request,?HttpServletResponse?response) ??
  3. ???? throws ?IOException?{ ??
  4. ??
  5. ?? //?Prepare?target?URL. ??
  6. ??StringBuilder?targetUrl?=? new ?StringBuilder(); ??
  7. ?? if ?( this .contextRelative?&&?getUrl().startsWith( "/" ))?{ ??
  8. ???? //?Do?not?apply?context?path?to?relative?URLs. ??
  9. ????targetUrl.append(request.getContextPath()); ??
  10. ??} ??
  11. ??targetUrl.append(getUrl()); ??
  12. ??
  13. ?? //?... ??
  14. ??
  15. ??sendRedirect(request,?response,?targetUrl.toString(),? this .http10Compatible); ??
  16. } ??
  17. ??
  18. protected ? void ?sendRedirect( ??
  19. ????HttpServletRequest?request,?HttpServletResponse?response,?String?targetUrl,? boolean ?http10Compatible) ??
  20. ???? throws ?IOException?{ ??
  21. ??
  22. ?? if ?(http10Compatible)?{ ??
  23. ???? //?Always?send?status?code?302. ??
  24. ????response.sendRedirect(response.encodeRedirectURL(targetUrl)); ??
  25. ??} ??
  26. ?? else ?{ ??
  27. ????HttpStatus?statusCode?=?getHttp11StatusCode(request,?response,?targetUrl); ??
  28. ????response.setStatus(statusCode.value()); ??
  29. ????response.setHeader( "Location" ,?response.encodeRedirectURL(targetUrl)); ??
  30. ??} ??
  31. }??
      protected void renderMergedOutputModel(
    Map<String, Object> model, HttpServletRequest request, HttpServletResponse response)
    throws IOException {

  // Prepare target URL.
  StringBuilder targetUrl = new StringBuilder();
  if (this.contextRelative && getUrl().startsWith("/")) {
    // Do not apply context path to relative URLs.
    targetUrl.append(request.getContextPath());
  }
  targetUrl.append(getUrl());

  // ...

  sendRedirect(request, response, targetUrl.toString(), this.http10Compatible);
}

protected void sendRedirect(
    HttpServletRequest request, HttpServletResponse response, String targetUrl, boolean http10Compatible)
    throws IOException {

  if (http10Compatible) {
    // Always send status code 302.
    response.sendRedirect(response.encodeRedirectURL(targetUrl));
  }
  else {
    HttpStatus statusCode = getHttp11StatusCode(request, response, targetUrl);
    response.setStatus(statusCode.value());
    response.setHeader("Location", response.encodeRedirectURL(targetUrl));
  }
}

    


??????? sendRedirect 方法沒什么特別的,它就是調(diào)用 HttpServletResponse 的 sendRedirect 方法而已。因此,關(guān)鍵點(diǎn)就是 renderMergedOutputModel 方法對轉(zhuǎn)發(fā)的資源的 url 進(jìn)行處理了。最終的 url 與 contextRelative 和你要重定向的資源是否以 / 開頭有關(guān)!當(dāng)且僅當(dāng) renderMergedOutputModel 為 true,并且你要重定向的資源是以 / 開頭,spring 會在該資源前添加 contextPath。

??????? response.sendRedirect() 的參數(shù),如果不以 / 開頭,那么容器最終計算出來的資源是相對于 做重定向操作的資源的 url ;如果以 / 開頭,容器將它視為相對于主機(jī)的 url。如此說來,spring 的 RedirectView 怎么著都只能將資源重定向到當(dāng)前應(yīng)用程序上。將 url 開頭的 / 去掉不是解決之道,因此本機(jī)的其它應(yīng)用程序的 contextPath 必定是以 / 開頭,因此我們要想辦法設(shè)置 contextRelative 了。

??????? RedirectView 自身持有 contextRelative 屬性,用于在程序中通過 new 操作符來構(gòu)造一個 RedirectView 并可以設(shè)置 contextRelative。當(dāng)處理請求的方法返回類型為 String 時,是通過 viewResolver 來解析得到 View 的。UrlBasedViewResolver 就是能夠解析出 RedirectView 的 viewResolver。該 viewResolver 持有 redirectContextRelative 屬性,當(dāng)它發(fā)現(xiàn)邏輯視圖名以 "redirect:" 開頭時,會將自身持有的 redirectContextRelative 傳入 RedirectView 的構(gòu)造函數(shù)以創(chuàng)建 RedirectView。因此我們通過注冊 UrlBasedViewResolver 時設(shè)置 redirectContextRelative 以達(dá)到控制 RedirectView 修改 url 的行為。 UrlBasedViewResolver 解析出 View:

Java代碼 復(fù)制代碼 ? 收藏代碼
  1. protected ?View?createView(String?viewName,?Locale?locale)? throws ?Exception?{ ??
  2. ?? //?If?this?resolver?is?not?supposed?to?handle?the?given?view, ??
  3. ?? //?return?null?to?pass?on?to?the?next?resolver?in?the?chain. ??
  4. ?? if ?(!canHandle(viewName,?locale))?{ ??
  5. ???? return ? null ; ??
  6. ??} ??
  7. ?? //?Check?for?special?"redirect:"?prefix. ??
  8. ?? if ?(viewName.startsWith(REDIRECT_URL_PREFIX))?{ ??
  9. ????String?redirectUrl?=?viewName.substring(REDIRECT_URL_PREFIX.length()); ??
  10. ???? return ? new ?RedirectView(redirectUrl,?isRedirectContextRelative(),?isRedirectHttp10Compatible()); ??
  11. ??} ??
  12. ?? //?Check?for?special?"forward:"?prefix. ??
  13. ?? if ?(viewName.startsWith(FORWARD_URL_PREFIX))?{ ??
  14. ????String?forwardUrl?=?viewName.substring(FORWARD_URL_PREFIX.length()); ??
  15. ???? return ? new ?InternalResourceView(forwardUrl); ??
  16. ??} ??
  17. ?? //?Else?fall?back?to?superclass?implementation:?calling?loadView. ??
  18. ?? return ? super .createView(viewName,?locale); ??
  19. }??
      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());
    return new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
  }
  // 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);
}

    


??????? UrlBasedViewResolver 的 redirectContextRelative 的默認(rèn)值為 true,這意味著,只要重定向的資源以 / 開頭,那么 spring 會幫你添加 contextPath。站在 Spring MVC 的角度上來說,/ 開頭的資源就是相對于當(dāng)前應(yīng)用程序,這和 forward 一樣了。因此,如果你確定重定向操作是在同一應(yīng)用程序中操作,那就使用 Spring MVC 的默認(rèn)值吧,這樣就不需要你寫 contextPath 了。注意,這樣做有隱患!當(dāng)重定向的資源是其它應(yīng)用程序時,除非你了解機(jī)制,否則請不要這么做!

Spring MVC 中的 forward 和 redirect


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。?!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 欧美天天影院 | 国产精品入口麻豆午夜 | 亚洲国产精品免费 | 奇米色7777| 综合色播| 久久国产精品一国产精品 | 免费色片网站 | 国产成人aa在线观看视频 | 天天干人人 | 久久香蕉国产线 | 国产99久久| 免费观看日本污污ww网站精选 | 成人精品视频网站 | www.狠狠| 久久久久久91 | 手机看片亚洲 | 成人日韩视频 | 99久久免费国产特黄 | 黄色片网站大全 | 九九视频免费在线 | 国产精品福利一区二区 | 国产男女爽爽爽免费视频 | 亚洲我射 | 亚洲欧美日韩一区二区在线观看 | 久久精品香蕉视频 | 亚洲精品久久婷婷爱久久婷婷 | 日本在线精品视频 | 自拍亚洲国产 | 日本另类αv欧美另类aⅴ | 久久久鲁| 天天操夜 | 四虎私人影院 | 国产精品久久久亚洲第一牛牛 | 四虎影永久在线高清免费 | 日韩51| 在线综合+亚洲+欧美中文字幕 | 俄罗斯一级毛片免费视频 | 亚洲国产精品专区 | 女人牲交视频一级毛片 | 久久狠狠色狠狠色综合 | 欧美中文字幕在线观看 |