Spring MVC使用篇(四)——视图解析器
文章目录
1、视图解析器简介
在Spring MVC的流程中最终返回给用户的视图为具体的View对象,并且View对象中包含了model中的反馈数据。而视图解析器ViewResolver的作用就是,把一个逻辑上的视图名称解析为一个真正的视图,即将逻辑视图的名称解析为具体的View对象,让View对象去处理视图,并将带有返回数据的视图反馈给客户端。
2、演示案例环境搭建
本文仍以之前的水果商城显示全部水果信息为例,具体环境搭建分为以下几步:
- 第一步,在web.xml中配置前端控制器(DispatcherServlet),具体配置信息如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<!--post中文乱码过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<!--该配置表示,名为CharacterEncodingFilter的过滤器对所有请求进行过滤,然后该过滤器会
以encoding指定的编码格式对请求数据进行统一编码-->
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
- 第二步,在核心配置文件springmvc.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" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!--基于注解的方式配置处理器映射器和适配器方法一-->
<!--配置基于注解的处理器适配器与处理器映射器-->
<mvc:annotation-driven/>
<!--基于注解的方式配置处理器映射器和适配器方法二-->
<!--注解映射器-->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />-->
<!--注解适配器-->
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />-->
<!--使用扫描配置,对某一个包下面的所有类进行扫描,
找出所有使用@Controller注解的Handler控制器类-->
<context:component-scan base-package="com.ccff.controller"/>
<!--配置视图解析器-->
<!-- 添加接下来的各种视图解析器配置 -->
</beans>
- 第三步,基于注解的控制器Handler代码如下:
package com.ccff.controller;
import com.ccff.model.Fruits;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
//基于注解的Handler类
//使用@Controller来标识它是一个控制器
@Controller
@RequestMapping("/query")
public class FruitsController {
private FruitsService fruitsService = new FruitsService();
//@RequestMapping实现对方法和url进行映射,一个方法对应一个url
//一般建议将url和方法写成一样的
@RequestMapping("/queryAllFruits.action")
public String queryAllFruits(Model model){
//模拟service获取水果商品列表
List<Fruits> fruitsList = fruitsService.queryFruitsList();
//将结果放到model中传到显示页面中
model.addAttribute("fruitsList",fruitsList);
return "/fruits/fruitsList";
}
}
class FruitsService{
public List<Fruits> queryFruitsList(){
List<Fruits> fruitsList = new ArrayList<Fruits>();
Fruits apple = new Fruits();
apple.setId(1);
apple.setName("红富士苹果");
apple.setPrice(2.3);
apple.setProducing_area("山东");
Fruits banana = new Fruits();
banana.setId(2);
banana.setName("香蕉");
banana.setPrice(1.5);
banana.setProducing_area("上海");
fruitsList.add(apple);
fruitsList.add(banana);
return fruitsList;
}
}
- 第四步,jsp页面的编写,代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>水果列表</title>
</head>
<body>
<h3>水果列表</h3>
<table width="300px;" border=1>
<tr>
<td>编号</td>
<td>名称</td>
<td>价格</td>
<td>产地</td>
</tr>
<c:if test="${fruitsList==null}">
<b>水果商品信息为空!</b>
</c:if>
<c:forEach items="${fruitsList}" var="fruit">
<tr>
<td>${fruit.id }</td>
<td>${fruit.name }</td>
<td>${fruit.price }</td>
<td>${fruit.producing_area }</td>
</tr>
</c:forEach>
</table>
</body>
</html>
3、AbstractCa chingViewResolver
该类作为一个抽象类,实现了该抽象类的视图解析器会将其曾经解析过的视图进行缓存,当再次解析视图的时候,它会首先在缓存中寻找该视图,如果找到,就返回相应的视图对象,如果没有在缓存中找到,就创建一个新的视图对象,在返回的同时,将其放置到存放缓存数据的map对象中。实现该抽象类的视图解析器类,视图解析的能力会大大提高。
4、UrlBasedViewResolver
该类是对ViewResolver的一种简单实现,它继承了抽象类AbstractCachingViewResolver(也就是说它具有对已解析视图进行缓存的功能)。
UrlBasedViewResolver是一种通过拼接资源文件的URI路径来展示视图的一种解析器。
- 它通过prefix属性指定视图资源所在路径的前缀信息;
- 通过suffix属性指定视图资源所在路径的后缀信息(一般是视图文件的格式);
- 当ModelAndView对象返回具体的View名称时,它会将前缀prefix与后缀suffix与具体视图名称拼接,得到一个视图资源文件的具体加载路径,从而加载真正的视图文件并反馈给用户。
例如前缀属性prefix配置的值为“、WEB-INF/jsp”,后缀属性suffix配置的值为“.jsp”,ModelAndView中View视图的名称为“/user/login”,那么UrlBasedViewResolver最终解析出来的视图资源文件的加载路径就为“/WEB-INF/jsp/user/login/jsp”。需要注意的是,默认的prefix与suffix都为空值。
UrlBasedViewResolver支持返回的视图名称中含有“redirect:”及“forward:”前缀,即支持视图的“重定向”和“内部跳转”设置。例如,当视图名称为“redirect:login.action”时,UrlBasedViewResolver会把返回的视图名称前缀“redirect:”去掉,取后面的login.action组成一个RedirectView,在RedirectView中把请求返回的model模型属性组合成查询参数的形式,组合到redirect的URL后面,然后调用HttpServletRequest对象的sendRedirect方法进行重定向。而如果名称中包含“forward:”,视图名称会被封装成一个InternalResourceView对象,然后在服务器端利用RequestDispatcher的forward方式跳转到指定地址。
使用UrlBasedViewResolver除了要配置前缀属性prefix和后缀属性suffix之外,还要配置一个“viewClass”,表示解析成哪种视图。若展示JSP页面,出于安全性考虑,jsp文件通常放在WEB-INF目录下(该目录下内容是不能直接通过request请求的方式请求到的),而InternalResourceView在服务器端以跳转的方式可以很好的解决该问题。
注意:要使用jstl标签展现数据,就要使用JstlView。
在springmvc.xml中配置UrlBasedViewResolver视图解析器显示水果商城全部水果商品信息,配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!--基于注解的方式配置处理器映射器和适配器方法一-->
<!--配置基于注解的处理器适配器与处理器映射器-->
<mvc:annotation-driven/>
<!--使用扫描配置,对某一个包下面的所有类进行扫描,
找出所有使用@Controller注解的Handler控制器类-->
<context:component-scan base-package="com.ccff.controller"/>
<!--配置UrlBasedViewResolver视图解析器-->
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="prefix" value="/WEB-INF/jsp" />
<property name="suffix" value=".jsp" />
<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView" />
</bean>
</beans>
将项目部署到Tomcat上,运行后结果如下,说明UrlBasedViewResolver视图解析器配置正确,正常运行:
5、InternalResourceViewResolver
InternalResourceViewResolver名为“内部资源视图解析器”,是在日常开发中最常用的视图解析器类型。它是UrlBasedViewResolver的子类,拥有UrlBasedViewResolver的一切特性。
InternalResourceViewResolver自身的特点是:它会把返回的视图名称自动解析为InternalResourceView类型的对象,而InternalResourceView会把Controller处理器方法返回的模型属性都存放到对应的request属性中,然后通过RequestDispatcher在服务器端把请求重定向到目标URL。也就是说,InternalResourceViewResolver视图解析的时候,无须在单独执行viewClass属性了。
在springmvc.xml中配置InternalResourceViewResolver视图解析器显示水果商城全部水果商品信息,配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!--基于注解的方式配置处理器映射器和适配器方法一-->
<!--配置基于注解的处理器适配器与处理器映射器-->
<mvc:annotation-driven/>
<!--使用扫描配置,对某一个包下面的所有类进行扫描,
找出所有使用@Controller注解的Handler控制器类-->
<context:component-scan base-package="com.ccff.controller"/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
上面配置实现了,当一个被请求的Controller处理器方法返回一个名为“/fruits/fruitsList”的视图时,InternalResourceViewResolver会将“/fruits/fruitsList”解析成一个nternalResourceView的对象,然后将返回的model模型属性信息存放到对应的HttpServletRequest属性中,最后利用RequestDispatcher在服务器端把请求forward到“/WEB-INF/jsp/fruits/fruitsList.jsp”上。
将项目部署到Tomcat上,运行后结果如下,说明InternalResourceViewResolver视图解析器配置正确,正常运行:
6、XmlViewResolver
该视图解析器也继承了AbstractCachingViewResolver抽象类(具有缓存视图页面的能力)。
使用XmlViewResolver需要添加一个xml配置文件,用于定义视图的bean对象。当获得Controller方法返回的视图名称后,XmlViewResolver会到指定的配置文件中寻找对应name名称的视图bean配置,解析并处理该视图。
如果不指定XmlViewResolver的配置文件,那么默认配置文件为/WEB-INF/views.xml,如果不想使用默认值,可以在springmvc.xml的配置文件中配置XmlViewResolver时,指定其location属性,在value中指定配置文件所在的位置。
在springmvc.xml中配置XmlViewResolver视图解析器显示水果商城全部水果商品信息,配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!--基于注解的方式配置处理器映射器和适配器方法一-->
<!--配置基于注解的处理器适配器与处理器映射器-->
<mvc:annotation-driven/>
<!--使用扫描配置,对某一个包下面的所有类进行扫描,
找出所有使用@Controller注解的Handler控制器类-->
<context:component-scan base-package="com.ccff.controller"/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="location" value="/WEB-INF/config/views.xml" />
<property name="order" value="1" />
</bean>
</beans>
在上面的配置中,设置了一个属性“order”,它的作用是,在配置有多重类型的视图解析器的情况下(即使有ViewResolver链),order会指定该视图解析器的处理视图的优先级,order的值越小优先级越高。特别要说明的是,order属性在 所有实现Ordered接口的视图解析器中都适用。
视图XML配置文件views.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">
<!-- Controller中方法的返回值返回该视图的id -->
<bean id="fruitsList" class="org.springframework.web.servlet.view.InternalResourceView">
<property name="url" value="/WEB-INF/jsp/fruits/fruitsList.jsp" />
</bean>
</beans>
views.xml配置文件遵循的DTD规则和Spring的bean工厂配置文件相同,所以bean中的标签规范与springmvc.xml中的bean相关的规范相同。在上面的配置中添加了一个id为“fruitsList”的InternalResourceView视图类型的bean配置,其中配置了url的映射参数。当Controller返回一个名为“fruitsList”的视图时,XmlViewResolver会在views.xml配置文件中寻找相关的bean配置中包含的id的视图配置,并遵循bean配置的View视图类型进行视图的解析,将最终的视图页面显示给用户。因此,对于之前的FruitsController中的queryAllFruits方法的返回值稍作修改,具体代码如下:
package com.ccff.controller;
import com.ccff.model.Fruits;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
//基于注解的Handler类
//使用@Controller来标识它是一个控制器
@Controller
@RequestMapping("/query")
public class FruitsController {
private FruitsService fruitsService = new FruitsService();
//@RequestMapping实现对方法和url进行映射,一个方法对应一个url
//一般建议将url和方法写成一样的
@RequestMapping("/queryAllFruits.action")
public String queryAllFruits(Model model){
//模拟service获取水果商品列表
List<Fruits> fruitsList = fruitsService.queryFruitsList();
//将结果放到model中传到显示页面中
model.addAttribute("fruitsList",fruitsList);
return "fruitsList"; /**这里与之前的不同**/
}
}
class FruitsService{
public List<Fruits> queryFruitsList(){
List<Fruits> fruitsList = new ArrayList<Fruits>();
Fruits apple = new Fruits();
apple.setId(1);
apple.setName("红富士苹果");
apple.setPrice(2.3);
apple.setProducing_area("山东");
Fruits banana = new Fruits();
banana.setId(2);
banana.setName("香蕉");
banana.setPrice(1.5);
banana.setProducing_area("上海");
fruitsList.add(apple);
fruitsList.add(banana);
return fruitsList;
}
}
将项目部署到Tomcat上,运行后结果如下,说明XmlViewResolver视图解析器配置正确,正常运行:
7、BeanNameViewResolver
该视图解析器与XmlViewResolver解析器的配置模式类似,也是让返回的逻辑视图名称去匹配配置好的bean配置。与XmlViewResolver解析器不同的是,XmlViewResolver是将bean配置文件配置在外部的XML文件中,而BeanNameViewResolver将视图的bean配置信息仪器配置在Spring MVC的核心配置文件springmvc.xml中。
在springmvc.xml中配置BeanNameViewResolver视图解析器显示水果商城全部水果商品信息,配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!--基于注解的方式配置处理器映射器和适配器方法一-->
<!--配置基于注解的处理器适配器与处理器映射器-->
<mvc:annotation-driven/>
<!--使用扫描配置,对某一个包下面的所有类进行扫描,
找出所有使用@Controller注解的Handler控制器类-->
<context:component-scan base-package="com.ccff.controller"/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="1" />
</bean>
<!-- Controller中方法的返回值返回该视图的id -->
<bean id="fruitsList" class="org.springframework.web.servlet.view.InternalResourceView">
<property name="url" value="/WEB-INF/jsp/fruits/fruitsList.jsp" />
</bean>
</beans>
与之前的XmlViewResolver视图解析器同理,需要对之前的FruitsController中的queryAllFruits方法的返回值稍作修改,具体代码如下:
package com.ccff.controller;
import com.ccff.model.Fruits;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
//基于注解的Handler类
//使用@Controller来标识它是一个控制器
@Controller
@RequestMapping("/query")
public class FruitsController {
private FruitsService fruitsService = new FruitsService();
//@RequestMapping实现对方法和url进行映射,一个方法对应一个url
//一般建议将url和方法写成一样的
@RequestMapping("/queryAllFruits.action")
public String queryAllFruits(Model model){
//模拟service获取水果商品列表
List<Fruits> fruitsList = fruitsService.queryFruitsList();
//将结果放到model中传到显示页面中
model.addAttribute("fruitsList",fruitsList);
return "fruitsList";
}
}
class FruitsService{
public List<Fruits> queryFruitsList(){
List<Fruits> fruitsList = new ArrayList<Fruits>();
Fruits apple = new Fruits();
apple.setId(1);
apple.setName("红富士苹果");
apple.setPrice(2.3);
apple.setProducing_area("山东");
Fruits banana = new Fruits();
banana.setId(2);
banana.setName("香蕉");
banana.setPrice(1.5);
banana.setProducing_area("上海");
fruitsList.add(apple);
fruitsList.add(banana);
return fruitsList;
}
}
将项目部署到Tomcat上,运行后结果如下,说明BeannameViewResolver视图解析器配置正确,正常运行:
注意:BeannameViewResolver不会对视图进行缓存
8、ResourceBundleViewResolver
该视图解析器与XmlViewResolver解析器一样,继承了AbstractCachingViewResolver抽象类,并且也需要有一个配置文件来定义逻辑视图名称和真正的View对象的对应关系。与XmlViewResolver不同的是,ResourceBundleViewResolver的配置文件并不是XML文件,而是一个properties属性文件,且必须放置在classpath根目录下。
默认情况下,配置文件为classpath根目录下的view.properties,如果不想使用默认的文件,则可以在Spring MVC配置文件中定义ResourceBundleViewResolver的bean信息时,指定baseName为自定义的properties文件名称。或者为baseName属性指定一个模糊文件头信息,凡是包含该文件头的都可以被加载(如指定baseName的名称为view,那么view.properties、viewSource.properties等一切以view开头的properties都会被加载)。
首先在classpath根目录创建一个名为“viewResource”的属性文件,具体配置如下:
aaa.(class)=org.springframework.web.servlet.view.InternalResourceView
aaa.url=/WEB-INF/jsp/fruits/fruitsList.jsp
bbb.(class)=org.springframework.web.servlet.view.InternalResourceView
bbb.url=/WEB-INF/jsp/fruits/fruitsList.jsp
然后在Spring MVC的核心配置文件springmvc.xml中添加ResourceBundleViewResolver的bean配置,具体配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!--基于注解的方式配置处理器映射器和适配器方法一-->
<!--配置基于注解的处理器适配器与处理器映射器-->
<mvc:annotation-driven/>
<!--使用扫描配置,对某一个包下面的所有类进行扫描,
找出所有使用@Controller注解的Handler控制器类-->
<context:component-scan base-package="com.ccff.controller"/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basename">
<value>viewResource</value>
</property>
<property name="order" value="1" />
</bean>
</beans>
接着在FruitsController中添加对ResourceBundleViewResolver视图解析器的测试方法,具体代码如下:
package com.ccff.controller;
import com.ccff.model.Fruits;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
//基于注解的Handler类
//使用@Controller来标识它是一个控制器
@Controller
@RequestMapping("/query")
public class FruitsController {
private FruitsService fruitsService = new FruitsService();
//测试视图解析器ResourceBundleViewResolver
@RequestMapping("/testResourceBundleViewResolver1.action")
public String testResourceBundleViewResolver1(Model model){
//模拟service获取水果商品列表
List<Fruits> fruitsList = fruitsService.queryFruitsList();
//将结果放到model中传到显示页面中
model.addAttribute("fruitsList",fruitsList);
return "aaa";
}
@RequestMapping("/testResourceBundleViewResolver2.action")
public String testResourceBundleViewResolver2(Model model){
//模拟service获取水果商品列表
List<Fruits> fruitsList = fruitsService.queryFruitsList();
//将结果放到model中传到显示页面中
model.addAttribute("fruitsList",fruitsList);
return "bbb";
}
}
class FruitsService{
public List<Fruits> queryFruitsList(){
List<Fruits> fruitsList = new ArrayList<Fruits>();
Fruits apple = new Fruits();
apple.setId(1);
apple.setName("红富士苹果");
apple.setPrice(2.3);
apple.setProducing_area("山东");
Fruits banana = new Fruits();
banana.setId(2);
banana.setName("香蕉");
banana.setPrice(1.5);
banana.setProducing_area("上海");
fruitsList.add(apple);
fruitsList.add(banana);
return fruitsList;
}
}
最后将项目部署到Tomcat上,在浏览器上分别访问链接 “http://localhost:8080/query/testResourceBundleViewResolver1.action”和“http://localhost:8080/query/testResourceBundleViewResolver2.action”, 得到如下结果,说明ResourceBundleViewResolver视图解析器配置正确,正常运行:
注:ResourceBundleViewResolver也支持解析多种不同类型的View。
9、FreeMarkerViewResolver与VelocityViewResolver
一般来说,FreeMarkerResolver会将Controller返回的逻辑视图信息解析为FreeMarkerView类型,而VelocityViewResolver会将逻辑视图信息解析为VelocityView。
FreeMarkerResolver与VelocityViewResolver有一个共同点,就是他们都是UrlBasedViewResolver的子类,可以通过prefix属性指定视图资源所在路径的前缀信息,通过suffix属性指定视图资源所在路径的后缀信息。两者都不需要再指定viewClass属性,因为在ViewResolver中已经指定了viewClass的类型。
以FreeMarkerResolver为例,FreeMarkerResolver最终会解析逻辑视图配置,返回一种Freemarker模板,该模板负责将数据模型中的数据合并到模板中,从而生成标准输出(可以生成各种文本,包括HTML、XML、RTF、Java源代码等)。
首先,在使用FreeMarkerResolver视图解析器时,必须添加支持FreeMarker的freemarker.2.3.28.jar文件。
接着在Spring MVC的核心配置文件springmvc.xml中添加FreeMarkerResolver的bean配置以及前后缀和优先级。除此之外,还需要指定FreeMarkerView类型最终生成的实体视图(模板文件)的路径以及其他配置,所以需要给FreeMarkerResolver设置一个FreeMarkerConfig的bean对象来定义FreeMarker的配置信息。具体配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!--基于注解的方式配置处理器映射器和适配器方法一-->
<!--配置基于注解的处理器适配器与处理器映射器-->
<mvc:annotation-driven/>
<!--使用扫描配置,对某一个包下面的所有类进行扫描,
找出所有使用@Controller注解的Handler控制器类-->
<context:component-scan base-package="com.ccff.controller"/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="prefix" value="fm_" />
<property name="suffix" value=".ftl" />
<property name="contentType" value="text/html;charset=UTF-8"/>
<property name="order" value="1" />
</bean>
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker/template" />
<!-- 设置页面中文乱码问题 -->
<property name="freemarkerSettings">
<props>
<prop key="defaultEncoding">UTF-8</prop>
</props>
</property>
</bean>
</beans>
定义了templateLoaderPath属性后,Spring可以通过该属性找到FreeMarker的模板文件的具体路径。当有模板位于不同的路径时,可以配置templateLoaderPath属性,在其中指定多个资源路径。
然后在FruitsController中定义一个方法testFreeMarkerViewResolver,让其返回时定义一些返回参数和视图信息,具体代码如下:
package com.ccff.controller;
import com.ccff.model.Fruits;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
//基于注解的Handler类
//使用@Controller来标识它是一个控制器
@Controller
@RequestMapping("/query")
public class FruitsController {
private FruitsService fruitsService = new FruitsService();
@RequestMapping("/testFreeMarkerViewResolver.action")
public String testFreeMarkerViewResolver(Model model){
model.addAttribute("username","张三");
return "freemarker";
}
}
class FruitsService{
public List<Fruits> queryFruitsList(){
List<Fruits> fruitsList = new ArrayList<Fruits>();
Fruits apple = new Fruits();
apple.setId(1);
apple.setName("红富士苹果");
apple.setPrice(2.3);
apple.setProducing_area("山东");
Fruits banana = new Fruits();
banana.setId(2);
banana.setName("香蕉");
banana.setPrice(1.5);
banana.setProducing_area("上海");
fruitsList.add(apple);
fruitsList.add(banana);
return fruitsList;
}
}
当FreeMarkerViewResolver解析逻辑视图信息时,会生成一个URL为“前缀+视图名+后缀”(这里即“fm_freemaeker.ftl”)的FreeMarkerView对象,然后通过FreeMarkerConfigurer的配置找到templateLoaderPath对应的文本文件的路径,在该路径下找到该文本文件,从而FreeMarkerView就可以利用该模板文件进行视图的渲染,并将model数据封装到即将要显示页面上,最终展示给用户。这里需要特别注意的就是,当model对象中带有中文时,一定要注意解决中文乱码的配置。
最后,还要在“/WEB-INF/freemarker/template”文件夹下创建一个名为“fm_freemarker.ftl”的文本文件,具体内容如下:
<html>
<head>
<title>FreeMarkerTest</title>
</head>
<body>
<h1>My Page</h1>
<b>Welcome!</b><i> ${username} </i>
</body>
</html>
由上面的代码可以看出,在ftl格式的文件中也可以使用ongl方式获取在model中封装的数据。最终返回给用户的视图效果如下图所示:
小贴士:使用FreeMarkerViewResolver可以生成FreeMarker模板,次模板十分强大,你可以根据模板规则,合并数据模型中的数据生成各种类型的文本。如HTML、XML、RTF等。
10、ViewResolver链
原则上说,是可以在Spring MVC的核心配置文件springmvc.xml中配置多个视图解析器(ViewResolver)的,将这些ViewResolver配置在一起使用,就形成了一个ViewResolver链。这些视图解析器之间并不会冲突,因为所有的ViewResolver都实现了Ordered接口,只需要通过order属性为他们指定优先级即可(即按照哪种顺序去调用视图解析器)。order属性是Integer类型,order越小,对应的ViewResolver将有越高的解析视图的优先级。
当Controller返回一个逻辑视图名称时,ViewResolver链将根据其中ViewResolver的优先级来对逻辑视图进行处理,如果高优先级的ViewResolver没有解析出视图,说明该视图类型并不为此ViewResolver所兼容,此时就会让下一个优先级的ViewResolver去解析该视图。如果定义的所有ViewResolver都不能解析该视图,就抛出异常。
注意:建议在ViewResolver中,将InternalResourceViewResolver解析器优先级设置为最低,因为该解析器能解析所有类型的视图,并返回一个不为空的View对象。