springmvc–表格视图原理
文章目录
1 介绍
上一篇文章springmvc–jsp视图解析响应原理,详细的介绍了jsp
的解析响应原理,但是这项技术毕竟已经过时了,所以本篇文章我们来介绍点不一样的,使用视图来实现xlsx
表格下载功能。我们使用poi
来构建表格,如果对poi
技术不了解,建议先看一下这篇文章POI
的简单使用
2 例子
这个例子我们来实现表格下载功能,我们先创建一个springmvc
应用
2.1 依赖
除了springmvc
相关依赖外,只需要额外导入poi
的依赖即可
<!-- poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</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.2</version>
</dependency>
2.2 实现表格下载功能的视图
//我们将这个视图放入容器中,取名为xlsxView
@Component(value = "xlsxView")
public class XlsxView extends AbstractXlsxView {
/**
* Application-provided subclasses must implement this method to populate
* the Excel workbook document, given the model.
*
* @param model the model Map
* @param workbook the Excel workbook to populate
* @param request in case we need locale etc. Shouldn't look at attributes.
* @param response in case we need to set cookies. Shouldn't write to it.
*/
@Override
protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
//创建一个sheet
XSSFSheet sheet = (XSSFSheet) workbook.createSheet("test1");
XSSFRow row1 = sheet.createRow(3);
XSSFCell cell1 = row1.createCell(3);
//设置单元格值类型
cell1.setCellType(CellType.STRING);
//设置单元格内容
cell1.setCellValue(43543);
//设置单元格样式
//单元格样式要从工作空间创建,不能直接new
XSSFCellStyle cellStyle = (XSSFCellStyle) workbook.createCellStyle();
//设置单元格顶部线条的粗细程度
cellStyle.setBorderTop(BorderStyle.THIN);
//设置单元格顶部边框颜色为红色
cellStyle.setBorderColor(XSSFCellBorder.BorderSide.TOP, new XSSFColor(Color.RED));
cell1.setCellStyle(cellStyle);
//设置字体
XSSFFont font = (XSSFFont) workbook.createFont();
font.setColor(IndexedColors.LEMON_CHIFFON.getIndex());
cellStyle.setFont(font);
}
}
springmvc
已经为我们提供了一个抽象类AbstractXlsxView
,它已经为我们做了如下工作
- 工作空间的创建
- 文件下载响应头的设置
- 表格文件写入响应体
这三部分是固定不变的,所以
springmvc
将它们抽取出来,放到父类中,子类只需要实现在工作空间中创建一个表格即可。典型的模板方法模式。
2.3 配置类
@Configuration
@EnableWebMvc
@ComponentScan({"cn.lx.spring.controller","cn.lx.spring.view"})
public class MvcConfig implements WebMvcConfigurer {
public void configureViewResolvers(ViewResolverRegistry registry) {
//创建视图解析器,根据视图名从容器中取出视图对象
BeanNameViewResolver viewResolver = new BeanNameViewResolver();
registry.viewResolver(viewResolver);
}
public void addViewControllers(ViewControllerRegistry registry) {
//添加视图映射
registry.addViewController("/xlsx").setViewName("xlsxView");
}
}
配置了一个视图解析器,并添加视图关系映射
2.4 测试
启动程序,当我们访问
http://localhost:8080/项目名/xlsx
时,服务器就会使用BeanNameViewResolver
这个视图解析器从容器中取出beanName
为xlsxView
的视图对象,然后调用视图对象的render()
方法渲染视图,完成表格的下载。
3 原理
为什么我们只需要写短短几行代码就能实现表格下载功能呢,这个因为其他事情springmvc
已经自动帮我们做了。
先来看一下我们编写的视图类的继承关系
AbstractView
这个类源码在springmvc–jsp视图解析响应原理这篇文章中说过,这里不再贴出源码了。该类只是简单的定义渲染视图的流程,如下所示
createMergedOutputModel(model, request, response);
方法:合并模型数据和静态数据prepareResponse(request, response);
方法:响应之前的准备工作renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
方法:渲染视图AbstractXlsView
:添加对XLS
格式的表格下载的功能AbstractXlsxView
:添加对XLSX
格式的表格下载的功能
接下来,我们一个一个的看后面两个类的源码
3.1 AbstractXlsView
该类重写了它父类的两个方法,分别为
-
generatesDownloadContent()
方法,返回true
表示文件下载 -
renderMergedOutputModel(model, request, response)
方法,渲染视图的过程
3.1.1 generatesDownloadContent()
@Override
protected boolean generatesDownloadContent() {
return true;
}
简单的返回一个
true
,表示文件下载。它父类会根据这个方法的返回值设置文件下载的响应头
3.1.2 renderMergedOutputModel(model, request, response)
/**
* Renders the Excel view, given the specified model.
*/
@Override
protected final void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Create a fresh workbook instance for this render step.
//创建命名空间,见3.1.2.1
Workbook workbook = createWorkbook(model, request);
// Delegate to application-provided document code.
//设置表格内容和样式,见3.1.2.2
buildExcelDocument(model, workbook, request, response);
// Set the content type.
//设置响应的内容类型,见3.1.2.3
response.setContentType(getContentType());
// Flush byte array to servlet output stream.
//渲染视图,见3.1.2.4
renderWorkbook(workbook, response);
}
该方法定义了表格创建过程的模板
- 创建命名空间
- 设置表格内容和样式
- 设置响应的内容类型
- 渲染视图,就是将表格写入响应体中
3.1.2.1 创建命名空间
/**
* Template method for creating the POI {@link Workbook} instance.
* <p>The default implementation creates a traditional {@link HSSFWorkbook}.
* Spring-provided subclasses are overriding this for the OOXML-based variants;
* custom subclasses may override this for reading a workbook from a file.
* @param model the model Map
* @param request current HTTP request (for taking the URL or headers into account)
* @return the new {@link Workbook} instance
*/
protected Workbook createWorkbook(Map<String, Object> model, HttpServletRequest request) {
return new HSSFWorkbook();
}
简单的
new
了一个HSSFWorkbook
对象,它生成Microsoft Excel XLS
格式的表格如果需要
Microsoft Excel OOXML XLSX
格式的表格,只需要重写这个方法即可,事实上,它的子类AbstractXlsxView
就是这么做的
3.1.2.2 设置表格内容和样式
/**
* Application-provided subclasses must implement this method to populate
* the Excel workbook document, given the model.
* @param model the model Map
* @param workbook the Excel workbook to populate
* @param request in case we need locale etc. Shouldn't look at attributes.
* @param response in case we need to set cookies. Shouldn't write to it.
*/
protected abstract void buildExcelDocument(
Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response)
throws Exception;
抽象方法,具体表格的内容和样式应该由用户自己设置,我们的视图
XlsxView
就是重写的这个方法,实现表格内容和格式的定制化
3.1.2.3 设置响应的内容类型
getContentType()
方法是父类AbstractView
的方法,它返回contentType
字段值,而这个字段值如果用户不修改的话,默认为"text/html;charset=ISO-8859-1"
。但是需要注意,在AbstractXlsView
类构造方法中给这个字段重新赋值了
/**
* Default Constructor.
* Sets the content type of the view to "application/vnd.ms-excel".
*/
public AbstractXlsView() {
setContentType("application/vnd.ms-excel");
}
响应的内容类型为
application/vnd.ms-excel
3.1.2.4 渲染视图,就是将表格写入响应体中
/**
* The actual render step: taking the POI {@link Workbook} and rendering
* it to the given response.
* @param workbook the POI Workbook to render
* @param response current HTTP response
* @throws IOException when thrown by I/O methods that we're delegating to
*/
protected void renderWorkbook(Workbook workbook, HttpServletResponse response) throws IOException {
//响应体输出流
ServletOutputStream out = response.getOutputStream();
//写入表格
workbook.write(out);
//关流
workbook.close();
}
这里没什么好说的,就是简单的将表格写入响应体中
3.2 AbstractXlsxView
抽象类,仅仅重写了父类的
createWorkbook(model, request)
方法,创建生成Microsoft Excel OOXML XLSX
格式表格的命名空间
/**
* This implementation creates an {@link XSSFWorkbook} for the XLSX format.
*/
@Override
protected Workbook createWorkbook(Map<String, Object> model, HttpServletRequest request) {
return new XSSFWorkbook();
}