Spring MVC 中的 forward 和 redirect
2015-09-22 11:32
561 查看
Spring MVC 中,我们在返回逻辑视图时,框架会通过viewResolver来解析得到具体的 View,然后向浏览器渲染。假设逻辑视图名为
实际上,框架还是通过 forward 的方式转发到了
现在有个问题,如果
同理,如果我们想重定向到某个资源,我们可以通过
如果想做转发操作,不需要写 contextPath;如果想做重定向操作,推荐写包括 contextPath 在内的 url。
仍然假设应用程序的
sendRedirect 方法没什么特别的,它就是调用
RedirectView 自身持有 contextRelative 属性,用于在程序中通过 new 操作符来构造一个 RedirectView 并可以设置 contextRelative。当处理请求的方法返回类型为 String 时,是通过 viewResolver 来解析得到 View 的。UrlBasedViewResolver 就是能够解析出 RedirectView 的 viewResolver。该 viewResolver 持有 redirectContextRelative 属性,当它发现逻辑视图名以 “redirect:” 开头时,会将自身持有的 redirectContextRelative 传入 RedirectView 的构造函数以创建 RedirectView。因此我们通过注册 UrlBasedViewResolver 时设置 redirectContextRelative 以达到控制 RedirectView 修改 url 的行为。UrlBasedViewResolver 解析出 View:
UrlBasedViewResolver 的 redirectContextRelative 的默认值为 true,这意味着,只要重定向的资源以 / 开头,那么 spring 会帮你添加 contextPath。站在 Spring MVC 的角度上来说,/ 开头的资源就是相对于当前应用程序,这和 forward 一样了。因此,如果你确定重定向操作是在同一应用程序中操作,那就使用 Spring MVC 的默认值吧,这样就不需要你写 contextPath 了。注意,这样做有隐患!当重定向的资源是其它应用程序时,除非你了解机制,否则请不要这么做!
分享到:
MyBatis 3 中使用存储过程 | Spring MVC 中处理静态资源
2012-12-28 20:53浏览 24747评论(0)分类:编程语言相关推荐
评论
hello,通过配置,我们配置某个
ViewResolver如下:
<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>
实际上,框架还是通过 forward 的方式转发到了
/WEB-INF/jsp/hello.jsp。如果逻辑视图名是
/hello,实际还是转发到了
/WEB-INF/jsp/hello.jsp,即
/WEB-INF/jsp//hello.jsp等同于
/WEB-INF/jsp/hello.jsp。
现在有个问题,如果
/hello就是某个controller的映射,我想转发到这个 controller,怎么办?我们可以通过forward前缀来达到转发到其它资源的目的:
public String handle() { // return "forward:/hello" => 转发到能够匹配 /hello 的 controller 上 // return "hello" => 实际上还是转发,只不过是框架会找到该逻辑视图名对应的 View 并渲染 // return "/hello" => 同 return "hello" return "forward:/hello"; }
同理,如果我们想重定向到某个资源,我们可以通过
redirect前缀来达到重定向到其它资源的目的:
public String handle() { // 重定向到 /hello 资源 return "redirect:/hello"; }
如果想做转发操作,不需要写 contextPath;如果想做重定向操作,推荐写包括 contextPath 在内的 url。
仍然假设应用程序的
contextPath为
/ctx。我们来看看
RedirectView.renderMergedOutputModel的片段:
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 方法没什么特别的,它就是调用
HttpServletResponse的
sendRedirect方法而已。因此,关键点就是 renderMergedOutputModel 方法对转发的资源的 url 进行处理了。最终的 url 与 contextRelative 和你要重定向的资源是否以 / 开头有关!当且仅当
renderMergedOutputModel为
true,并且你要重定向的资源是以
/开头,spring 会在该资源前添加
contextPath。
response.sendRedirect()的参数,如果不以 / 开头,那么容器最终计算出来的资源是相对于做重定向操作的资源的 url;如果以 / 开头,容器将它视为相对于主机的 url。如此说来,spring 的 RedirectView 怎么着都只能将资源重定向到当前应用程序上。将 url 开头的 / 去掉不是解决之道,因此本机的其它应用程序的 contextPath 必定是以 / 开头,因此我们要想办法设置
contextRelative了。
RedirectView 自身持有 contextRelative 属性,用于在程序中通过 new 操作符来构造一个 RedirectView 并可以设置 contextRelative。当处理请求的方法返回类型为 String 时,是通过 viewResolver 来解析得到 View 的。UrlBasedViewResolver 就是能够解析出 RedirectView 的 viewResolver。该 viewResolver 持有 redirectContextRelative 属性,当它发现逻辑视图名以 “redirect:” 开头时,会将自身持有的 redirectContextRelative 传入 RedirectView 的构造函数以创建 RedirectView。因此我们通过注册 UrlBasedViewResolver 时设置 redirectContextRelative 以达到控制 RedirectView 修改 url 的行为。UrlBasedViewResolver 解析出 View:
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 的默认值为 true,这意味着,只要重定向的资源以 / 开头,那么 spring 会帮你添加 contextPath。站在 Spring MVC 的角度上来说,/ 开头的资源就是相对于当前应用程序,这和 forward 一样了。因此,如果你确定重定向操作是在同一应用程序中操作,那就使用 Spring MVC 的默认值吧,这样就不需要你写 contextPath 了。注意,这样做有隐患!当重定向的资源是其它应用程序时,除非你了解机制,否则请不要这么做!
分享到:
MyBatis 3 中使用存储过程 | Spring MVC 中处理静态资源
2012-12-28 20:53浏览 24747评论(0)分类:编程语言相关推荐
评论
相关文章推荐
- 分享微信开发Html5轻游戏中的几个坑
- 一个jar包里的网站
- 一个jar包里的网站之文件上传
- 一个jar包里的网站之返回对媒体类型
- Zend的MVC机制使用分析(二)
- ASP.NET MVC 4 捆绑和缩小实例介绍
- ASP.NET MVC中将控制器分离到类库的实现
- asp.net实现在非MVC中使用Razor模板引擎的方法
- ASP.NET MVC中的AJAX应用
- 如何在MVC应用程序中使用Jquery
- ASP.NET MVC小结之基础篇(二)
- ASP.NET小结之MVC, MVP, MVVM比较以及区别(一)
- Asp.net实现MVC处理文件的上传下载功能实例教程
- ASP.NET MVC小结之基础篇(一)
- spring+html5实现安全传输随机数字密码键盘
- Spring中属性注入详解
- Flex中最好的MVC框架Mate框架
- struts2 spring整合fieldError问题
- ASP.NET MVC学习笔记
- 关于php mvc开发模式的感想