View解析
定义请求处理函数可以返回不同内容,这几类都是有View相关的线索
- String:名称
- View
- ModelAndView
而下面这类并没有View的信息,只返回的Map和Model
- Map
- Model
View解析过程
首先每个项目都会有ViewResolver,ViewResolver是把函数处理结果返回的View名称,需要把View名称与视图展示的模板、JSP文件等等关联起来。ViewResolver的输出就是View。有时候我们要展示网页,有时候返回Json的数据,有时候返回PDF文件。
View解析
ViewResolver是抽象接口,可以定义不同的ViewResolver接口。
InernalResourceViewResolver
例如JSP可以用Spring提供的InernalResourceViewREsolver
,可以通过一些配置告诉Spring在碰到一些View名称时,会根据Resolver的路径设置,把View名称转换到本地JSP的文件。
FreeMarkerViewResolver
也有FreeMarkerViewResolver
,FreeMarker是模板引擎,可以通过类似于JSP,FreeMarker可以在模板文件中定义变量,在返回View时,可以把和View相关的数据进行返回。可以在FreeMarker的模板文件中引用所返回的数据。
ContentNegotiatingViewResolver
字面意思为内容协商ViewResolver,就是指并不是固定的ViewResolver,是多种ViewResolver的组合。可以处理不同的View解析的需要。可以把多个ViewResolver都配置到ContentNegotiatingViewResolver
,根据客户端传递给不同内容的Resolver返回不同的View
ViewResolver基本配置
InernalResourceViewResolver
- Servlet,JSP
- 基本配置
可以看到有两个属性,prefix是指要解析的文件在项目的什么位置,而suffix指要解析的文件后缀,如下例子是.jsp。 - 处理结果
我们通过String或者View返回相关的View对象,例如resultView,是View的名称,最终要渲染或者访问的资源是如下结果/WEB-INF/jsp/resultView.jsp
,会把我们之前在ViewResolver定义的prefix和view名称+后缀名称组合起来。形成完整路径。之后把内容返回给客户端,客户端显示JSP内容。
<!-- 定义JSP文件的位置 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
FreeMarkerViewResolver
- FreeMarker
是针对FreeMarker模板引擎,提供的对象就是FreeMarker模板引擎 - 基本配置
要是使用FreeMarkerViewResolver的需要定义跟FreeMarker相关的配置,这里配置是配置类FreeMarker的路径,这样告诉FreeMarker在碰到View解析需求的时候,去/WEB-INF/freemarker
目录查找freemarker相关的模板。
下面就定义prefix、suffix,这里prefix已经在config配置了路径。cache的值是是否重新查找映射结果。 - 处理结果
resultView的处理结果为/WEB-INF/freemarker/resultView.ftl
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker" />
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResovler">
<property name="cache" value="true" />
<property name="prefix" value="" />
<property name="suffix" value=".ftl" />
</bean>
ContentNegotiatingViewResolver
-
ViewResolver的组合
-
根据扩展名:user.json、user.xml、user.pdf
-
也可以根据Accept头(media types):application/json,application/xml
可以根据Request的媒体类型 -
配置
需要配置viewResolver,也就是说我们在view名称时,我们会碰到viewResolver进行解析。需要注意的是defaultViews的属性。配置了一个MappingJackson2JsonView,是一个Json的View。defaultViews是当如果通过viewResolver,没有办法进行处理,比如找不到view名称关联的模板文件。这时候通过defaultView处理返回结果。defaultView不指定prefix、suffix。会忽略view名称,直接解析成json数据。
<bean class="org.springframework.web.serlvet.view.ContentNegotiatingViewResolver">
<property name="viewResolvers">
<list>
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver" />
<property name="cache" value="true" />
<property name="prefix" value="" />
<property name="suffix" value=".ftl" />
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
</list>
</property>
</bean>
处理非View的Model
DefaultRequestToViewNameTranslator
客户端请求地址是example/display.html,当在处理这个请求时,函数没有返回View相关的名称,会进行请求地址转换为display,作为返回的view。
另外一个示例是exmaple/admin/index.html,默认会转换成admin/index,这里都是把应用名称的example当做前缀,后面的.html当做后缀。中间的部分就是请求的view名称。
代码示例
之前的Login改装,成FreeMarker,并且ViewResolver使用ContentNegotiatingViewResolver。
创建freemarker模板文件
在/WEB-INF下创建freemarker目录,在目录中创建文件login_user.ftl,内容如下:
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>用户信息</title>
</head>
<body>
<p>FreeMarker通过如下方式引用Model的数据</p>
<p>Username:${username}</p>
<p>Password:${password}</p>
</body>
</html>
在Spring配置中添加配置
<mvc:annotation-driven />
<!-- FreeMarket在这里进行prefix的设置 -->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker" />
</bean>
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="viewResolvers">
<!-- FreeMarker ViewResolver -->
<bean id="freeMarkerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true" />
<property name="suffix" value=".ftl" />
<property name="prefix" value="" />
<property name="contentType" value="text/html; charset=utf-8" />
</bean>
<!-- 这里还可以添加JSP的viewResolver -->
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
<!-- 可以添加更多的XML、PDF等 -->
</list>
</property>
</bean>
修改Login的函数返回
@RequestMapping(value = "/user_login/login")
public String login2(@RequestParam("username") String username,
@RequestParam("password") String password,
@RequestHeader("host") String host,
ModelMap modelMap) throws IOException{
System.out.println("username:" + username);
System.out.println("password:" + password);
// 向ModelMap添加内容
modelMap.addAttribute("username",username);
modelMap.addAttribute("password",password);
//由于没有@ResponseBody,则返回的是View
return "login_user";
}
**注意:**如果发生异常,则需要去服务器后端进输出行查看
添加FreeMarker的依赖
添加SpringFramework-context-support,该包包含与第三方工具的整合。例如缓存框架、其他视图框架。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.4</version>
</dependency>
Chrome运行结果
FreeMarker閫氳繃濡備笅鏂瑰紡寮曠敤Model鐨勬暟鎹�/p>
Username锛�123
Password锛�456
中文字符乱码问题
注意如果freemarker发生了中文字符乱码,可能是由很多问题导致的Tomcat与FreeMarker的设置,Resolver的设置有关。
**注意:**虽然课程中讲到在FreeMarkerViewResolver中添加,但是本人在实际解决是在Config中添加的配置
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker" />
<property name="freemarkerSettings">
<props>
<prop key="defaultEncoding">utf8</prop>
</props>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="viewResolvers">
<!-- FreeMarker ViewResolver -->
<bean id="freeMarkerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true" />
<property name="suffix" value=".ftl" />
<property name="prefix" value="" />
<property name="contentType" value="text/html; charset=utf-8" />
</bean>
<!-- 这里还可以添加JSP的viewResolver -->
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
<!-- 可以添加更多的XML、PDF等 -->
</list>
</property>
</bean>
返回的结果
FreeMarker通过如下方式引用Model的数据
Username:123
Password:456
#没有返回的View,或者找不到View 当我们返回没有添加user,没有指定view,则返回的是json文件
{"password":"456","username":"123"}