1. 简介
SpringMVC的视图有View和ViewResolver共同来完成。在标有ReqeustMapping注解的函数中返回的情况有:String,Model,ModelAndView等多种情况。不管是哪种情况,都会最终转变为ModelAndView,然后通过ViewResolver最终转换为View。(SpringMVC中的视图就是View接口,其作用就是渲染数据,将模型Model中的数据展示给用户。)
2.SpringMVC中视图实现原理
2.1 SpringMVC中视图配置方式
2.1.1 通过XML文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--Spring MVC框架配置文件-->
<!--扫描组件: 自动扫描base-package路径下被注解@Controller的类-->
<context:component-scan base-package="com.kk.controller"></context:component-scan>
<!--配置视图解析器 Thymeleaf为例-->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<!--作用于视图渲染的过程,设置视图渲染后的编码格式-->
<property name="characterEncoding" value="UTF-8"/>
<!--如果配置多个视图解析器,它来决定视图解析器的使用顺序,数值越小,优先级越高-->
<property name="order" value="1"/>
<!--当-->
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!--设置模板文件位置(前缀)-->
<property name="prefix" value="/WEB-INF/templates"/>
<!--设置模板文件后缀-->
<property name="suffix" value=".html"/>
<!--设置模板类型-->
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>
<!--处理静态资源,例如html、js、css、jpg
若只设置该标签,则只能访问静态资源,其他请求则无法访问
此时必须设置<mvc:annotation-driven/>标签来解决问题-->
<!--<mvc:default-servlet-handler/>-->
<!--开启mvc注解驱动-->
<!--<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="defaultCharset" value="utf-8"/>
<property name="supportedMediaTypes">
<list>
<value>/html</value>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>-->
</beans>
2.1.2 通过YML文件配置
第一步在pom.xml文件中导入thymeleaf依赖
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
第二步在yml文件中配置视图解析器
spring:
thymeleaf:
cache: false #不开启缓存
prefix: classpath:/templates/ #配置文件前缀
suffix: .html #配置文件后缀
mode: HTML #配置文件格式
encoding: UTF-8 #配置编码格式
servlet:
content-type: text/html #配置文本格式
2.2 SpingMVC支持的常见视图
SpringMVC 支持的常见视图有
内部资源视图:InternalResourceView (SpringMVC内置的,专门负责解析JSP模板语法,另外也负责 forward 转发功能实现)
重定向视图:RedirectView(SpringMVC内置的,专门负责 redirect 重定向功能实现)
Thymeleaf视图:ThymeleafView (第三方视图,专门负责 Thymeleaf 模板语法解析)
FreeMarker视图:FreeMarkerView(第三方视图,专门负责 FreeMarker 模板)
Velocity视图:VelocityView(第三方视图,专门负责 Velocity 模板)
......
2.3 SpingMVC视图机制核心接口
原理描述:
1. DispaterServlet:前端控制器
负责接收前端请求:(/login)
根据请求路径找到对应的处理方法(UserController#login() )
执行处理器方法(执行UserController#login()),
核心代码 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
并最终返回 ModelAndView 对象
2. ViewResolve:视图解析器
无论是 InternalResourceViewResolve,还是 ThymeleafViewResolve,亦或是其他视图解析器都是实现了 ViewResolve接口
ViewResolve 作用:是将 逻辑视图名称 转换为 物理视图名称,并且最终返回一个 View 对象。(将单独视图名称 转换为 全路径视图名称)
ViewResolve 核心方法:View resolveViewName(String viewName, Locale locale) throws Exception;
3. View:视图接口
View 作用:负责将模板语法的字符串转换成html代码,并将代码响应给浏览器。
View 核心方法:void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
核心重要源码分析
public class DispatcherServlet extends FrameworkServlet {
//前端控制器核心方法,处理请求、返回视图、渲染视图,都说是在这个方法中完成的
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//1. 根据请求路径映射请求方法,处理器执行结束后,返回逻辑视图名称,返回逻辑视图名称之后,DispatcherServlet会将逻辑视图名称和model 封装成ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//2.处理视图的方法
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
}
//2.1
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
//渲染页面,将模板字符串转换成html代码响应到浏览器
this.render(mv, request, response);
}
//2.2
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
//2.2.1 调用resolveViewName方法 将 逻辑视图名称 转换成 物理视图名称,最终返回 view对象
view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
//2.2.2 真正将模板字符串转换成HTML代码响应给浏览器(渲染)
view.render(mv.getModelInternal(), request, response);
}
//2.2.1
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
//获取对应的视图解析器,并通过视图解析器将 逻辑视图名称 转换成 物理视图名称,最终返回 view对象
View view = viewResolver.resolveViewName(viewName, locale);
}
}
//2.2.1 通过视图解析器将 逻辑视图名称 转换成 物理视图名称,最终返回 view对象(各种视图都有各自的视图解析器,只不过底层都是继承了ViewResolver接口)
public interface ViewResolver {
@Nullable
View resolveViewName(String viewName, Locale locale) throws Exception;
}
//2.2.2 负责将模板字符串转换成HTML代码,相应给浏览器((视图有很多种,只不过底层都是继承了View接口))
public interface View {
void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}
2.4 视图解析器
不论控制器(就是我们使用@Controller注解标记的类)返回的是String,ModelAndView,View数据SpringMVC都会转换为ModelAndView对象,ModelAndView对象(包含了逻辑名和模型对象的视图)由视图解析器解析成视图对象,然后解析,进行页面的跳转。
2.4.1 视图解析器的作用
- 将逻辑视图解析为一个具体的视图对象。
- 在SpringMVC 中为逻辑视图名的解析提供了不同的策略,可以在 Spring WEB 上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。
- 每一种映射策略对应一个具体的视图解析器实现类。
- 所有的视图解析器都必须实现 ViewResolver 接口。
- 可以选择一种视图解析器或混用多种视图解析器使用,每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可以通过 order 属性指定解析器的优先顺序,order 越小优先级越高。
- SpringMVC 会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则将抛出 ServletException 异常。
JSP 是最常见的视图技术,可以使用 InternalResourceViewResolve作为视图解析器。
2.4.2 视图解析器分类
3. 转发与重定向
3.1 转发视图
在SpringMVC中转发视图默认就是 InternalResourceView,如果工程引入了 jstl 依赖,转发视图就会自动转换成 jstlView。
SpringMVC创建转发视图的方式:
当控制器方法中所返回的视图名称以 "forward:" 为前缀的时候,创建InternalResourceView视图,此时视图名称不会被SpringMVC配置文件中所配置的视图解析器所解析,而是将前缀去掉,将剩余部分作为路径去解析,通过转发的方式实现跳转。
//作为示例页面
@RequestMapping("/templates")
public String helloTemp(){
return "servlet-yu";
}
//通过视图转发的方式进行跳转
@RequestMapping("/interView")
public String interView(){
return "forward:/templates";
}
可以看见我访问 /templates路径会显示 servlet-yu.html页面,我在访问 /interView路径的时候方法返回的是一个路径,经过转发的方式重新按照新的路径找寻视图进行加载返回给浏览器显示。
转发过程: 客户端浏览器发送http请求 → web服务器接受此请求 → 调用内部的一个方法在容器内部完成请求处理和转发动作 → 将目标资源发送给客户。
3.2 重定向视图
SpringMVC中默认的重定向视图是 RedirectView
SpringMVC视图重定向的方式:
当控制器方法中做设置的视图名称以 "redirect: "为前缀时,创建RedirectView视图,此时视图名称不会被SpringMVC配置文件中的视图解析器所解析,而是会将前缀 "redirect: "去掉,將剩余部分最为新路径通过重定向的方式实现跳转。(重定向是重定向一个请求路径给浏览器,重新访问,而不是重定向一个视图。)
//通过重定向的方式进行跳转
@RequestMapping("/redirectView")
public String redirectView(){
//重定向是可以跨域的 示例:return "redirect:http://localhost:33921/mvc/templates";
return "redirect:/templates";
}
这里注意 第二张图片的访问路径是 localhost:8090/redirectView 但是访问后路径就会自动变换成 方法返回的路径,浏览器接收后,从新发送请求访问。
重定向过程: 客户端浏览器发送http请求 → web服务器接收后发送30X状态码响应及对应新的location给客户浏览器 → 客户浏览器发现是30X响应,则自动再发送一个新的http请求,请求url是新的location地址 → 服务器根据此请求寻找资源并发送给客户。
3.3 转发和重定向的区别
转发: 浏览器发起了一次请求(在服务器内部跳转),可以获取请求域中的数据(因为是同一个request域对象),可以访问WEB-INF下的资源,不可以跨域访问(服务器内部方法无法跨域访问,浏览器可以跨域访问)。
重定向: 浏览器发起两次请求,第一次访问servlet,第二次访问的是重定向的路径,不可以获取请求域中的数据(两次请求的request域对象不是同一个),不可以访问WEB-INF下的资源(因为WEB-INF下的资源具有安全性、隐藏性,只有服务器内部方法才可以访问,浏览器不可以直接访问),可以跨域访问。
4. <mvc:view-controller>
<mvc:view-controller> 配置在 springmvc.xml 文件用于将请求映射到特定的视图上,即通过URL找到特定的视图。它可以不用编写 controller 就可以根据URL找到指定视图。
在什么情况下使用?
1. 当控制器方法中,仅仅用来实现页面跳转,只需要设置视图名称时,可以将处理器方法使用 <mvc:view-controller> 标签进行标识。
2. 当SpringMVC中设置任何一个 <mvc:view-controller> 时,其他控制器中的请求映射注解将全部失效,此时需要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签:
<mvc:annotation-driven />
<!--
path:设置处理的请求地址
view-name:设置请求地址所对应的视图名称
-->
<mvc:view-controller path="/templates" view-name="servlet-yu"></mvc:view-controller>
5. <mvc:annotation-driven>
<mvc:annotation-driven> 开启注解驱动,配置在 springmvc.xml 文件中。
<!--开启mvc注解驱动-->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="defaultCharset" value="utf-8"/>
<property name="supportedMediaTypes">
<list>
<value>/html</value>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
6. 静态资源访问
假如在static文件夹下有一张 xx.jpg 图片,在浏览器上通过 http://localhost:33921/static/xx.jpg 是无法访问的,因为请求会被 DispatcherServlet 拦截,会报404。
6.1 <mvc:default-servlet-handler/>
<!-- 开启Servlet处理静态资源。DefaultSrvlet 由 tomcat提供,位于tomcat的/conf/web.xml文件中,默认不开启-->
<mvc:default-servlet-handler/>
<!-- 处理静态资源,例如html、js、css、jpg,若只设置该标签,则只能访问静态资源,其他请求则无法访问,此时必须设置<mvc:annotation-driven/>标签来解决问题 -->
6.2 <mvc:resources>
<!--开启注解驱动-->
<mvc:annotation-driven>
<!--配置静态资源,表示凡是请求路径是 /static/** 开始的,都区/static/路径下寻找-->
<mvc:resources mapping="/static/**" location="/static/">
<!--注意!注意!注意! 使用 <mvc:resources> 配置一定要开启注解驱动配置 -->