7.视图解析器
1.视图解析器和视图
ModelAndview: 模型数据 (存储业务数据) 和视图
Model: 模型数据(存储模型层中查询到的数据)
View:视图(页面属于视图中的一种)
控制单元执行完成后,无论什么类型返回值,都会封装为ModelAndview。
Model中存储了业务数据,view通常存储视图名。最终目的:将Model 中的业务数据使用视图进行渲染到客户端
底层源码:
ModelAndview mv;
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()):
执行控制单元,控制单元返回结果封装为ModelAndview。
控制单元返回的结果固定被封装为ModelAndview。
视图解析器: ViewResolver (接口),解析不同的视图,使用不同的实现类视图解析器,解析控制单元返回的ModelAndview,经过解析返回具体的view对象。
以.jsp视图为例:
1.控制单元执行后,经过springmvc的封装,返回ModelAndview(viewname为index.jsp)
2.获取到ModelAndView后,执行render(mv,request,response);
3.在render万法中调用了view = resolveViewName(viewName, mv.getModelInternal(), locale, request):
4.在resolveviewName方法中, 视图解析器 根据视图名找到对应的视图对象- 默认的使用的视图解析器: InternalResourceViewResourceView
.jsp使用的视图对象: InternalResourceView
5.返回视图对象后,调用view.render(mv.getModelInternal(),reguest,response);(使用视图对象完成客户端响应结果的渲染)实际完成Mode1中的数据通过视图响应回到客户端
jsp的InternalResourceView的视图对象渲染时:
1.将Mode1中的数据存储大请求域对象中
2.将请求转发到.jsp -> java (获取请求去对象中的数据) -> .class -> 将结果输出到客户端
2. 自定义视图解析器
例如有下面的文件结构,suiyi.jsp和suiyi2.jsp都放在了WEB-INF/page目录下。
由于文件必须通过控制器转发才能访问,所以控制器应该写成下面这种效果。
@RequestMapping("/showSuiyi")
public String showSuiyi(){
return "/WEB-INF/page/suiyi.jsp";
}
@RequestMapping("/showSuiyi2")
public String showSuiyi2(){
return "/WEB-INF/page/suiyi2.jsp";
}
在上面代码中,return后面的内容有两份是重复的:
(1)前面的/WEB-INF/page/
(2)后面的.jsp
对于这种,项目结构比较固定,页面按照一定规则放在特定位置,且返回值内容比较长时,就可以配置视图解析器。在springmvc.xml配置下面内容。
小提示:
其中id="viewResolver"的取值是任意的,也可以省略id属性不写。
<!--配置自定义试图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/page/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
当配置了视图解析器后,控制单元返回值就不需要写前缀和后缀的内容了,写起来更加简单。
3. 自定义视图解析器下跳转到其他控制器
当自定义视图解析器后,返回值前面和后面都会固定拼接字符串(在没有使用其他注解情况下)。但是如果控制单元执行完,并不希望跳转到视图,而是跳转到控制器,这时需要在返回值前面明确添加forward:或redirect: ,这样就不走视图解析器了。
@RequestMapping("/showSuiyi3")
public String showSuiyi3(){
return "suiyi3";// 跳转到 /WEB-INF/page/suiyi3.jsp
}
@RequestMapping("/demo")
public String demo(){
return "forward:/showSuiyi3"; // 不走视图解析器了。跳转到/showSuiyi3控制器单元
}
8.静态资源放行
1. 静态资源放行
按照SpringMVC的使用流程,需要在web.xml文件中配置DispatcherServlet的拦截范围,而我们配置的拦截范围为”/”,表示拦截除jsp请求以外的所有请求。这样造成,请求是js,css,图片等静态资源的请求,也会被拦截,调用对应的单元方法来处理请求。但是,我们是一个静态资源的请求,不应该按照普通单元方法请求的流程来处理,而是将对应的静态资源响应给浏览器使用。
Spring MVC 支持静态资源配置,当URL满足指定路径要求时不再去找控制单元,而是直接转发到特定路径中静态资源。
例如项目结构:
需要在springmvc.xml中配置静态资源放行
<!--配置静态资源放行-->
<!--mapping:当URI是什么样格式时,不再执行控制器,而是寻找静态资源。 ** 是通配符,表示任意层路径 -->
<!--location:去哪个目录中寻找静态资源。mapping中**的值是什么,就去location目录中找对应资源-->
<!--例如URL是http://localhost:8080/bjsxt/js/jquery.js 其中mapping的**就是jquery.js,就会去location的/js/目录中寻找jquery.js -->
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/images/"></mvc:resources>
如果把静态资源放在WEB-INF中,例如项目结构:
需要在springmvc.xml中配置
<mvc:resources mapping="/js/**" location="/WEB-INF/js/"></mvc:resources>
<mvc:resources mapping="/css/**" location="/WEB-INF/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="/WEB-INF/images/"></mvc:resources>
方式二:
<mvc:default-servlet-handler/>
9.控制单元的方法参数(接受请求参数)
1. 控制单元方法参数写法
控制单元方法参数一共有两种写法:
(1)紧耦方式。获取原生Servlet API,通过原生Servlet API获取请求参数、设置响应内容、设置作用域的值。
(2)解耦方式。使用Spring MVC提供的方式获取请求参数、设置响应内容、设置作用域的值。
2. 紧耦方式
这种需要在控制单元方法参数中注入Servlet API的方式,称为Spring MVC 紧耦方法。因为使用的是原生Servlet API,和原生Servlet API紧耦。
3. 解耦方式
解耦方式是Spring MVC独有方式。是Spring MVC给开发者提供的:
(1)获取请求中内容
(2)设置作用域值
(3)设置响应内容
等写法。今天主要看解耦方式下如何获取请求参数和如何设置作用域的值。
3.1 获取请求中内容
请求参数根据参数的类型分为多种写法。
(1)普通表单参数
(2)多个同名参数
(3)日期类型数据
(4)请求头数据
(5)请求体数据
3.1.1 获取普通表单参数
获取普通表单参数,只需要包含在控制单元中提供与请求参数同名的方法参数即可。
Spring MVC会自动进行类型转换
建议使用封装类型,请求数据中没有携带该参数时,自动赋值为null,基本数据类型会报错。
3.1.2 @RequestParam 注解
当请求参数名和控制单元参数名不一致时可使用该注解
3.1.3 使用JavaBean作为参数(使用类对象作为控制单元参数)
3.1.5 接收多个同名表单参数
在提交表单数据时,可能在里面包含复选框。当选中多个复选框时会出现多个同名参数。在Spring MVC中可以使用数组和List接收多个同名参数。
如果是JavaBean中的属性为list集合接受多个同名属性,不需要进行额外处理。
3.1.6 接收日期类型参数
第一种用在参数前面
第二种用在实体类的属性前面
3.1.7 接收请求头数据(了解)
在控制单元方法参数中添加对应名称的参数,并在参数前面添加@RequestHeader注解
3.2 设置作用域的值
10.Spring MVC中文乱码问题
1. GET方式中文乱码解决
本机的tomcat自动设置了get请求的乱码问题,插件中的问题需要我们自己解决
2. POST方式中文乱码解决
在web.xml中设置过滤器,过滤器需要放在上面