一、视图解析
新建maven项目spring-mvc-view,项目创建过程与配置方式及其maven依赖,创建过程参考QA 由浅入深 Spring Framework 5.0(十)- Spring MVC Restful,这里不在赘述。
转发forward
在spring-mvc-view项目中controller包下新增一个ForwardControlle。
@Controller public class ForwardController { @RequestMapping("/forward_jsp") public String forward2JSP(){ // 相对路径,视图解析器会进行拼串 // return "../../hello"; System.out.println("hello"); return "forward:/hello.jsp"; } } 复制代码
在web目录下新建一个jsp页面hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Hello</title> </head> <body> <h2>通过转发或者重定向到达此页面</h2> </body> </html> 复制代码
重新启动Tomcat,浏览器输入http://localhost:8080/forward_jsp
使用forward关键字可以完成转发操作
转发到其他请求,增加forward2URI方法
@RequestMapping("/forward_uri") public String forward2URI(){ return "forward:/forward_jsp"; } 复制代码
重新启动Tomcat,浏览器输入http://localhost:8080/forward_uri
使用forward关键字可以转发到一个页面或者请求,使用时一定加上/,如果不加就是相对路径,使用了关键字forward:之后,视图解析器不会对页面进行拼串
重定向redirect
controller包下新建一个RedirectController,并新增两个方法分别是redirect2JSP、redirect2URI
@Controller public class RedirectController { // 重定向到其他jsp页面 @RequestMapping("/redirect_jsp") public String redirect2JSP(){ return "redirect:/hello.jsp"; } // 重定向到其他请求 @RequestMapping("/redirect_uri") public String redirect2URI(){ return "redirect:/redirect_jsp"; } } 复制代码
重启Tomcat,浏览器中先后输入http://localhost:8080/redirect_jsp 和 http://localhost:8080/redirect_uri, 最后都会重定向到hello.jsp页面
redirect的用法与forward用法一致
Spring MVC 视图解析的原理
在浏览器中输入URL地址后会先进入DispatchServlet类中的doDispatch方法,通过调用doDispatch方法完成响应,doDispatch执行过程中的关键步骤如下:
1)根据当前请求地址获取一个handler来处理,如果没有找到就报404
// Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } 复制代码
2)根据handler获取handlerAdapter适配器
// Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); 复制代码
3)执行目标方法,返回ModelAndView
// Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 复制代码
4)根据方法最终执行完成后封装的ModelAndView渲染页面
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); 复制代码
而processDispatchResult方法中又会调用同一类下的render方法,当mv不为空时,调用render方法渲染页面
render方法中再调用视图解析器的resolveViewName方法来解析ViewName获取View,这里通过for循环获取视图解析器数组中的所有视图解析器来解析ViewName
if (viewName != null) { // We need to resolve the view name. view = resolveViewName(viewName, mv.getModelInternal(), locale, request); 复制代码
进入resolveViewName,在通过调用createView方法创建View
而在createView方法中会通过判断前缀中是否包含forward:、redirect: 来创建不同的View
视图解析器得到View对象的流程就是,所有配置的视图解析器都来尝试根据视图名(返回值)得到View(视图)对象;如果能得到就返回,得不到就换下一个视图解析器。
视图对象才能真正的转发(将模型数据全部放在请求域中)或者重定向到页面,才能真正的渲染视图;
视图解析器
- Spring MVC为解析逻辑视图提供了多种方式,可以在Spring MVC配置文件上下文中配置一种或者多种解析策略,并规定他们之间的先后顺序,每种映射策略对应一个具体的视图解析器实现类
- 将逻辑视图解析为一个具体的视图对象
- 所有的视图解析器都必须实现ViewResolver接口
视图
- 视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给用户
- 为了实现视图模型和具体实现技术的解耦,Spring 定义了一个高度抽象的View接口
- 视图由视图解析器负责实例化,视图是无状态的,不会设计线程安全问题
视图和视图解析器
- 请求处理方法(handler方法)执行完成之后,最终会返回一个ModelAndView对象,对于返回String、View、ModelMap等类型的处理方法,Spring MVC会在内部把他们装配成ModelAndView对象,包含了逻辑名和模型对象的视图
- Spring MVC借助视图解析器(View Resolver)得到最终的视图对象(View),最终的视图可以是JSP,也可以是其他形式的视图
- 对于最终要采用哪一种视图对模型数据渲染,处理器不关心,处理器关心的是生产模型数据,从而实现MVC的充分解耦
常用的视图实现类(View的实现类)
- InternalResourceView:URL资源视图,将JSP或者其他资源封装成一个视图,是InternalResourceView提供的默认视图实现类
- JstlView:URL资源视图,如果JSP中使用了JSTL国际化标签的功能,则需要使用JstlView来实现
- MappingJacksonJsonView:将模型数据通过Jackson开源框架ObjectMapper及Json方式输出
- 其他如文档视图实现类AbstractExcelView、AbstractPdfView以及一些报表视图JasperReportsCsvView、JasperReportsHtmlView等等
JstlView实现国际化
将dispatchServlet-servlet.xml中的视图解析器配置增加一个viewClass属性,指定视图解析器获取JstlView,代替默认的InternaleResourceView
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"></property> <property name="suffix" value=".jsp"></property> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property> </bean> 复制代码
新建一个LoginController,增加login方法,该方法返回login.jsp页面
@Controller public class LoginController { @RequestMapping("/login") public String login(){ return "login"; } } 复制代码
login.jsp页面
<h2>Login</h2> <form action=""> 用户名 :<input type="text" name="username"> <br> 密码:<input type="password" name="password"> <br> <input type="submit" value='登录'> </form> 复制代码
重启Tomcat,浏览器输入http://localhost:8080/login, login.jsp页面可以正常返回和显示
接着在resources目录下增加国际化配置
message_en.properties
username=USERNAME password=PASSWORD loginBtn=LOGIN 复制代码
message_zh.properties
username=\u7528\u6237\u540D password=\u5BC6\u7801 loginBtn=\u767B\u9646 复制代码
在disptachServlet-servlet.xml配置文件中增加管理国际化的配置
<!--国际化资源文件配置,id不可以更改一定要命名为messageSource--> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="i18n"></property> </bean> 复制代码
pom.xml中增加jstl依赖
<dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> 复制代码
页面顶部导入标签
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 复制代码
修改登录表单
<form action=""> <fmt:message key="username" /> :<input type="text" name="username"> <br> <fmt:message key="password" />:<input type="password" name="password"> <br> <input type="submit" value="<fmt:message key="loginBtn" />"> </form> 复制代码
重启tomcat,浏览器输入地址http://localhost:8080/login
切换页面语言后刷新页面
XML中配置请求映射
<mvc:view-controller path="/login" view-name="login" /> <!--开启mvc注解驱动模式--> <mvc:annotation-driven></mvc:annotation-driven> 复制代码
参数
- path:指定请求路径
- view-name:指定映射的页面
重启Tomcat,将原Controller中的login方法注释,浏览器输入 http://localhost:8080/login
页面可以正常显示