一、页面跳转控制
1、转发指令
1 2 3 4 5 6 7 8 9
| @RequestMapping("/dispatch/forward") public String testForward() {
return "forward:/WEB-INF/view/page.jsp"; }
|
测试的 index.jsp:
1 2
| <a href="${pageContext.request.contextPath}/dispatch/forward">测试forward指令</a ><br />
|
之前我们使用的 return “target” 本身就是转发。
Spring MVC 又提供给我们一个 forward 方式来实现转发。
forward 后面跟的是一个完整的转发路径,后面跟的是一个物理视图,而 return “target” 返回的是一个逻辑视图。
forward 一般用在某个拼前后缀无法到达的地址。
2、重定向指令
1 2 3 4 5 6 7 8
| @RequestMapping("/dispatch/redirect") public String testRedirect() {
return "redirect:/feature/user/show.jsp"; }
|
测试的 index.jsp:
1 2 3
| <a href="${pageContext.request.contextPath}/dispatch/redirect" >测试redirect指令</a ><br />
|
3、使用原生对象完成转发
1 2 3 4 5 6 7 8 9
| @RequestMapping("/dispatch/original/forward") public void originalForward( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/view/page.jsp").forward(request, response); }
|
测试的 index.jsp:
1 2 3
| <a href="${pageContext.request.contextPath}/dispatch/original/forward" >测试使用原生对象转发</a ><br />
|
你看,使用原生 request 对象执行转发后,handler 方法的返回值就必须是 void,意思是我们自己指定了响应方式,不需要 SpringMVC 再进行处理了。
一个请求只能有一个响应,不能在 handler 方法里面给一个,然后 SpringMVC 框架再给一个。
4、使用原生对象完成重定向
1 2 3 4 5 6 7 8 9
| @RequestMapping("/dispatch/original/redirect") public void originalRedirect( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendRedirect(request.getContextPath() + "/feature/user/show.jsp"); }
|
测试的 index.jsp:
1 2 3
| <a href="${pageContext.request.contextPath}/dispatch/original/redirect" >测试使用原生对象重定向</a ><br />
|
使用原生 response 对象执行重定向后,handler 方法的返回值同样需要设置为 void,原因同上。
二、属性域使用
1、request 域
在 SpringMVC 中,当我们想把一个对象存入请求域有很多种操作方式,用哪一个都可以。
① 使用 Model 对象
1 2 3 4 5 6 7 8 9
| @RequestMapping("/model/model") public String saveToModel(Model model) {
model.addAttribute("modelName", "modelValue");
return "target"; }
|
测试的 index.jsp:
1 2 3
| <a href="${pageContext.request.contextPath}/model/model" >测试使用Model类型对象</a ><br />
|
② 使用 ModelMap
1 2 3 4 5 6 7 8 9
| @RequestMapping("/model/modelMap") public String saveToModelMap(ModelMap modelMap) {
modelMap.addAttribute("modelMapName", "modelMapValue");
return "target"; }
|
测试的 index.jsp:
1 2 3
| <a href="${pageContext.request.contextPath}/model/modelMap" >测试使用ModelMap类型对象</a ><br />
|
③ 使用 Map
1 2 3 4 5 6 7 8 9
| @RequestMapping("/model/map") public String saveToMap(Map<String, Object> map) {
map.put("mapName", "mapValue");
return "target"; }
|
测试的 index.jsp:
1 2
| <a href="${pageContext.request.contextPath}/model/map">测试使用Map类型对象</a ><br />
|
④ 使用 HttpServletRequest
1 2 3 4 5 6 7 8
| @RequestMapping("/model/original/request") public String saveToRequest(HttpServletRequest request) {
request.setAttribute("requestName", "requestValue");
return "target"; }
|
测试的 index.jsp:
1 2 3
| <a href="${pageContext.request.contextPath}/model/original/request" >测试使用原生request对象</a ><br />
|
2、session 域
向 session 域存入数据,真正有效的办法只有一个
1 2 3 4 5 6 7 8
| @RequestMapping("/session/scope") public String testSession(HttpSession session) {
session.setAttribute("sessionName", "sessionValue");
return "target"; }
|
测试的 index.jsp:
1 2
| <a href="${pageContext.request.contextPath}/session/scope">测试使用会话域</a ><br />
|
3、application 域
向 application 域存入数据需要先拿到 ServletContext 对象。
拿到 ServletContext 对象后调用 setAttribute()方法。
1 2 3 4 5 6 7
| @RequestMapping("/application/scope") public String testAppScope() {
servletContext.setAttribute("appName", "appValue");
return "target"; }
|
测试的 index.jsp:
1 2
| <a href="${pageContext.request.contextPath}/application/scope">测试使用应用域</a ><br />
|
4、ModelAndView
在把数据存入请求域时还有一个方法:使用 ModelAndView 对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @RequestMapping("/model/and/view") public ModelAndView testModelAndView() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("mavName", "mavValue");
modelAndView.setViewName("redirect:/feature/user/show.jsp");
return modelAndView; }
|
见名知意,ModelAndView 就是把模型和视图封装到一起。其实即使我们没有明确使用 ModelAndView,SpringMVC 也会在 handler 方法执行完成后把模型和视图封装到 ModelAndView 对象中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
if (returnValue instanceof ModelAndView) { ModelAndView mav = (ModelAndView) returnValue; mav.getModelMap().mergeAttributes(implicitModel); return mav; }
else if (returnValue instanceof Model) { return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap()); }
else if (returnValue instanceof View) { return new ModelAndView((View) returnValue).addAllObjects(implicitModel); }
else if (returnValue instanceof Map) { return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map<String, ?>) returnValue); }
else if (returnValue instanceof String) { return new ModelAndView((String) returnValue).addAllObjects(implicitModel); }
|
三、静态资源访问
1.提出静态资源问题
Web 项目的开发不可避免的要使用静态资源。在我们的项目中图片文件、音视频文件、CSS 文件、JavaScript 文件、HTML 文件等等凡是浏览器直接可以使用且不需要 Tomcat 解析的资源都是静态资源。
那么静态资源在 SpringMVC 中有什么问题呢?
如果在 web.xml 中我们配置 ulr-pattern 为“/”,那么访问静态资源时会返回 404。
1 2 3 4
| <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
|
原因是参照<url-pattern>/</url-pattern>这个配置,任何请求都会先和<url-pattern>/</url-pattern>进行匹配,而 / 会匹配所有资源,所以SpringMVC 就交给 DispatcherServlet 来处理这个请求。
我们又没有任何一个@RequestMapping 和我们要访问的静态资源对应,所以 SpringMVC 认为并不存在这个资源,所以返回 404。
2、解决办法
① 解决办法 1
在 web.xml 配置文件中配置 ulr-pattern 配置扩展名,例如:<url-pattern>*.mvc</url-pattern>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <servlet> <servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param>
<load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.mvc</url-pattern> </servlet-mapping>
|
比如说测试的 index.jsp:
1 2 3
| <a href="${pageContext.request.contextPath}/application/scope.mvc" >测试使用应用域</a ><br />
|
加上扩展名以后 @RequestMapping(“/application/scope”) 依然可以正常解析 scope.mvc。
这样配置之后会有一个重要的、严格的限制:所有希望由 SpringMVC 来处理的请求,末尾都必须加上指定的扩展名,比如我们这个例子中的*.mvc。反之没有以*.mvc 结尾的请求都和 SpringMVC 无关,还是由 Tomcat 处理。
② 解决办法 2
还是保持<url-pattern>/</url-pattern>的配置,然后在 Spring 配置文件中加入如下配置:
1 2 3 4 5 6
| <mvc:default-servlet-handler/>
<mvc:annotation-driven/>
|
单独使用 mvc:default-servlet-handler 是不行的,必须配合 mvc:annotation-driven。
四、mvc:view-controller
假设有下面这样一个 handler 方法:
1 2 3 4
| @RequestMapping("/test/view/controller") public String testViewController() { return "result"; }
|
这个方法内部没有做任何处理,仅仅是把一个 URL 地址”/direct”映射到视图”result”。那么有没有办法简化一下呢?使用 mvc:view-controller 配置即可。
1 2 3 4
|
<mvc:view-controller path="/test/view/controller.mvc" view-name="target"/>
|
测试的 index.jsp
1 2 3
| <a href="${pageContext.request.contextPath}/test/view/controller.mvc" >测试view-controller</a ><br />
|
注意:mvc:view-controller 也必须搭配 mvc:annotation-driven。