介绍
请求处理方法执行完成后,最终返回一个ModelAndView对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个 ModelAndView 对象, 它包含了视图逻辑名和模型对象的信息
Spring MVC 借助视图解析器(ViewResolver)得到最终 的视图对象(View),最终的视图可以是 JSP ,也可能是 Excel、JFreeChart 等各种表现形式的视图。 对于最终究竟采取何种视图对象对模型数据进行渲染,后端控制器并不关心,后端控制器工作重点聚焦在生产模型数据的工 作上,从而实现 MVC 的充分解耦。
1.认识视图
-
视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户。视图对象可以是常见 JSP,还可以是Excel或PDF等形式不一的媒体形式。
-
为了实现视图模型和具体实现技术的解耦,Spring 在 org.springframework.web.servlet 包中定义了一个高度抽象的 View 接口,该接口有两个方法
String getContentType():返回视图的内容
void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response):将模型数据以某种MIME类型渲染出来
-
视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们 不会有线程安全的问题
不同类型的视图实现技术对应不同的View实现类,这些视图实现类都位于org.springframeworkd.web.servlet.view包中,具体视图如下
视图类型 | 简介 | |
---|---|---|
URL视图资源图 | InternalResourceView | 将JSP或其他资源封装成一个视图。被视图解析器InternalResourceViewResolver默认使用。 |
JstlView | InternalResourceView的子类。如果JSP中使用了JSTL的国际化标签,就需要使用该视图类。 | |
文档视图 | AbstractExcelView | Excel文档视图的抽象类。 |
AbstractPdfView | PDF文档视图的抽象类 | |
报表视图 | ConfigurableJasperReportsView JasperReportsHtmlView JasperReportsPdfView JasperReportsXlsView | 常用的JasperReports报表视图 |
JSON视图 | MappingJackson2JsonView | 将数据通过Jackson框架的ObjectMapper对象,以JSON方式输出 |
2视图解析器
视图解析器
SpringMVC为逻辑视图名的解析提供了不同和策略,一个SpringMVC的上下文中可以包含多种解析策略,并指定他们的优先顺序。
每种解析策略对应一个具体的视图解析器实现类。这些视图解析器实现同一个接口,这个接口就是ViewResolver.此接口只有一个方法
View resolveViewName(String viewName, Locale locale)
作用是,根据逻辑视图名和本地对象得到一个视图对象。
Spring的常用视图解析器如下所示
视图解析器类型 | 简介 | |
---|---|---|
解析为bean | BeanNameViewResolver | 将视图解析后,映射成一个bean,视图的名字就是bean的id。 |
解析为映射文件 | InternalResourceViewResolver | 将视图解析后,映射成一个资源文件。例如将一个视图名为字符串“success.jsp”的视图解析后,映射成一个名为success的JSP文件。 |
JasperReportsViewResolver | 将视图解析后,映射成一个报表文件。 | |
解析为模板文件 | FreeMarkerViewResolver | 将视图解析后,映射成一个FreeMarker模板文件。 |
VelocityViewResolver | 将视图解析后,映射成一个Velocity模板文件。 | |
VelocityLayoutViewResolver |
视图解析器举例
-
InternalResourceViewResolver是JSP最常用的视图解析器,可以通过
prefix
给响应字符串加上前缀,通过suffix
加上后缀。例如我们之前曾在springMVC的配置文件中配置了一个视图解析器InternalResourceViewResolver,如下:<!-- 视图解析器 --> <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 后缀 --> <property name="suffix" value=".jsp" /> </bean>
InternalResourceViewResolver默认使用InternalResourceView作为视图实现类。如果JSP文件使用了JSTL的国际化功能,确切地说,当JSP页面使用JSTL的fmt:message时,用户需要使用JstlView替换默认的视图实现类。即、
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
-
Excel
如果希望使用Excel展示用户列表 ,则仅需要扩展Spring的AbstractExcelView或AbstractJExcelView即可。实现buildExcelDocument()方法,在方法中使用模型数据对象即可构造Excel文档。AbstractExcelView基于POI,而AbstractJExcelView基于JExcelAPI,下面通过扩展AbstractExcelView宝定义显示用户列表 的Excel视图类;在Spring5中,分别使用了
AbstractXlsxView
andAbstractXlsxStreamingView
,取代了之前过时的类;代码如下;<!--导入三个包--> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>4.1.0</version> </dependency>
/**自定义excel视图**/ package com.oracle.view; import java.net.URLEncoder; import java.util.Date; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.springframework.web.servlet.view.document.AbstractXlsxView; import com.oracle.vo.Book; /**spring 5后,使用AbstractXlsxView 替代原有的类**/ public class UserListExcelView extends AbstractXlsxView { @Override protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception { // 自定义文件名称 String excelName = "图书_"+DateUtil.getExcelDate(new Date()) + ".xlsx"; String Agent = request.getHeader("User-Agent"); if (null != Agent) { Agent = Agent.toLowerCase(); System.out.println(Agent); // 针对火狐乱码的处理 if (Agent.indexOf("firefox") != -1) { System.out.println("fireFox"); response.setHeader("content-disposition", String.format("attachment;filename*=utf-8'zh_cn'%s", URLEncoder.encode(excelName, "utf-8"))); } else { System.out.println("other"); response.setHeader("content-disposition", "inline;filename=" + URLEncoder.encode(excelName, "utf-8")); } } response.setContentType("application/ms-excel; charset=UTF-8"); //表单 Sheet sheet = workbook.createSheet("User Detail"); sheet.setDefaultColumnWidth(20); sheet.setHorizontallyCenter(true); //创建行的头部 Row header = sheet.createRow(0); header.createCell(0).setCellValue("id"); header.createCell(1).setCellValue("书名"); //单元格 Cell c=header.createCell(2); c.setCellValue("作者"); @SuppressWarnings("unchecked") List<Book> list=(List<Book>) model.get("list"); int i=1; for(Book b:list) { Row r = sheet.createRow(i++); r.createCell(0).setCellValue(b.getBookid()); r.createCell(1).setCellValue(b.getName()); r.createCell(2).setCellValue(b.getAuthor()); } } }
<!-- 定义视图解析器,顺序在jspViewResolver之前 --> <bean class ="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="10"></bean> <!-- 视图 --> <bean id="excel" class="com.oracle.view.UserListExcelView"></bean>
/** 控制器 **/ @Controller public class ExcelHandler { @RequestMapping("/excel") public String excel(Map<String,Object> map) { List<Book> list=new ArrayList<Book>(); list.add(new Book(1,"战争与和平","列夫,托尔斯泰",45)); list.add(new Book(2,"红与黑","斯汤达",45)); list.add(new Book(3,"国富论","亚当,思密",45)); map.put("list", list); //返回指定有视图 return "excel"; } }