spring boot使用AbstractXlsView导出excel

一、maven依赖jar包

 <dependency>
     <groupId>org.apache.poi</groupId>
     <artifactId>poi-ooxml</artifactId>
     <version>3.14</version>
 </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

二、导出view

public class ExportMemberVo {
    private String name;

    private Integer gender;

    private String idCard;

    private String bankNo;

    private String bankName;

    private String phone;

    /**
     * 性别处理
     */
    public String getGender() {
        return gender == 0 ? "男" : "女";
    }
    /****为了节省篇幅,省略setter/getter/constructor****/
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

三、导出Excel核心处理代码,继承自AbstractXlsView ,并实现buildExcelDocument

import export.entity.ExportMemberVo;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.springframework.web.servlet.view.document.AbstractXlsView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;

/**
 * @Author Kent.Wang
 * @Date 2017/6/26
 */
public abstract class ExcelView extends AbstractXlsView {

    @Override
    protected void buildExcelDocument(Map<String, Object> map,
                                      Workbook workbook,
                                      HttpServletRequest request,
                                      HttpServletResponse response) throws Exception {
        String excelName = map.get("name").toString() + ".xls";
        response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(excelName,"utf-8"));
        response.setContentType("application/ms-excel; charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        @SuppressWarnings("unchecked")
        List<ExportMemberVo> list = (List<ExportMemberVo>) map.get("members");
        Sheet sheet = workbook.createSheet("User Detail");
        sheet.setDefaultColumnWidth(30);
        CellStyle style = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setFontName("Arial");
        style.setFillForegroundColor(HSSFColor.BLUE.index);
        style.setFillPattern((short) 1);
        font.setBold(true);
        font.setColor(HSSFColor.WHITE.index);
        style.setFont(font);
        Row header = sheet.createRow(0);
        header.createCell(0).setCellValue("姓名");
        header.getCell(0).setCellStyle(style);
        header.createCell(1).setCellValue("性别");
        header.getCell(1).setCellStyle(style);
        header.createCell(2).setCellValue("手机号");
        header.getCell(2).setCellStyle(style);
        header.createCell(3).setCellValue("身份证号");
        header.getCell(3).setCellStyle(style);
        header.createCell(4).setCellValue("银行卡号");
        header.getCell(4).setCellStyle(style);
        int rowCount = 1;
        for (ExportMemberVo user : list) {
            Row userRow = sheet.createRow(rowCount++);
            userRow.createCell(0).setCellValue(user.getName());
            userRow.createCell(1).setCellValue(user.getGender());
            userRow.createCell(2).setCellValue(user.getPhone());
            userRow.createCell(3).setCellValue(user.getIdCard());
            userRow.createCell(4).setCellValue(user.getBankNo());
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

四、controller代码

 @RequestMapping(value = "", method = RequestMethod.GET)
  public ModelAndView download() {

      List<ExportMemberVo> list = new ArrayList<ExportMemberVo>();
      for (int i = 0; i < 5; i++) {
          ExportMemberVo exportMemberVo = new ExportMemberVo();
          exportMemberVo.setName("Kent" + i);
          @SuppressWarnings("unchecked")
          int gender = ThreadLocalRandom.current().nextInt(0, 2);
          exportMemberVo.setGender(gender);
          exportMemberVo.setPhone("182xxxxxxxx");
          exportMemberVo.setBankName("建设银行");
          list.add(exportMemberVo);
      }

      Map<String, Object> map = new HashMap<String, Object>();
      map.put("members", list);
      map.put("name", "魅力城市");
      ExcelView excelView = new UserInfoExcelView();
      return new ModelAndView(excelView, map);
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

运行,访问download结果如下: 

这是网络上一般的导出方法,没什么特别的,拿来即用,在使用的过程中也碰到一些问题,和疑问,下面谈谈我自己的理解。

五、火狐浏览器导出excel中文乱码问题

 这个问题是因浏览器的不同所造成的,那只要对response.setHeader做些处理就可以了。我只测试了chrome和firefox,其他浏览器或许还有些差异,在此不一一枚举。

String Agent = request.getHeader("User-Agent");
if (null != Agent) {
    Agent = Agent.toLowerCase();
    if (Agent.indexOf("firefox") != -1) {
        response.setHeader("content-disposition", String.format("attachment;filename*=utf-8‘zh_cn‘%s", URLEncoder.encode(excelName, "utf-8")));

    } else {
        response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(excelName, "utf-8"));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

六、buildExcelDocument是怎么被调用的

 我们看到继承自AbstractXlsView 的buildExcelDocument方法是protected的,只能被同一包下面和子类调用,理论上controller不会去继承ExcelView ,也不会在同一包下,那我们如何去调用他,在springMVC和spring boot下,我们需要用到ModelAndView。 
我通过两幅图来列举下buildExcelDocument调用的过程:

download方法执行return之后会大致执行如下过程,我们可以看到buildExcelDocument是如何被调用的,具体过程有兴趣可以自己debug。

其中比较重要的一个环节是view.render,这里用到了Java的多态特性,AbstractView是继承自View的,ExcelView自然也继承View,所以获取到的ModelAndView中的view执行view.render实际上会去调用AbstractView的render方法,然后AbstractView中有个抽象方法renderMergeOutputModel,供子类实现不同的输出模型,输出Excel文件就是其中的一个子类,还有输出PDF文件也是同理实现该方法。

具体handle方法返回ModelAndView的过程如下: 

七、包装一下Excel输出模版

 我们可能需要输出许多Excel,有成员信息,商品信息,规格信息等等。所以将所有设置Excel的代码全放在ExcelView类中有点不合时宜,很显然至少列名和值的绑定都写死了,难以扩展。

仿照AbstractView中用到的模板方法模式,我们也可以将具体设置Sheet提取出来,写个抽象方法,由子类去实现具体设置Sheet.

修改过的ExcelView如下:

public CellStyle cellStyle;

/**
 * 设置样式
 *
 * @param workbook
 */
protected abstract void setStyle(Workbook workbook);

/**
 * 设置Row,由子类实现
 *
 * @param sheet
 * @param map
 */
protected abstract void setRow(Sheet sheet, Map<String, Object> map);

@Override
protected void buildExcelDocument(Map<String, Object> map,
                                  Workbook workbook,
                                  HttpServletRequest request,
                                  HttpServletResponse response) throws Exception {
    String excelName = map.get("name").toString() + ".xls";
    String Agent = request.getHeader("User-Agent");
    if (null != Agent) {
        Agent = Agent.toLowerCase();
        if (Agent.indexOf("firefox") != -1) {
            response.setHeader("content-disposition", String.format("attachment;filename*=utf-8‘zh_cn‘%s", URLEncoder.encode(excelName, "utf-8")));

        } else {
            response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(excelName, "utf-8"));
        }
    }
    response.setContentType("application/ms-excel; charset=UTF-8");
    Sheet sheet = workbook.createSheet("User Detail");
    sheet.setDefaultColumnWidth(30);
    this.setStyle(workbook);
    setRow(sheet, map);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

 我们写个导出成员信息UserInfoExcelView ,所有Sheet设置都在这里完成:

public class UserInfoExcelView extends ExcelView {

    @Override
    public void setRow(Sheet sheet, Map<String, Object> map) {

        // create header row
        Row header = sheet.createRow(0);
        header.createCell(0).setCellValue("姓名");
        header.getCell(0).setCellStyle(super.cellStyle);
        header.createCell(1).setCellValue("性别");
        header.getCell(1).setCellStyle(super.cellStyle);
        header.createCell(2).setCellValue("手机号");
        header.getCell(2).setCellStyle(super.cellStyle);
        header.createCell(3).setCellValue("身份证号");
        header.getCell(3).setCellStyle(super.cellStyle);
        header.createCell(4).setCellValue("银行卡号");
        header.getCell(4).setCellStyle(super.cellStyle);

        @SuppressWarnings("unchecked")
        List<ExportMemberVo> list = (List<ExportMemberVo>) map.get("members");
        int rowCount = 1;
        for (ExportMemberVo user : list) {
            Row userRow = sheet.createRow(rowCount++);
            userRow.createCell(0).setCellValue(user.getName());
            userRow.createCell(1).setCellValue(user.getGender());
            userRow.createCell(2).setCellValue(user.getPhone());
            userRow.createCell(3).setCellValue(user.getIdCard());
            userRow.createCell(4).setCellValue(user.getBankNo());
        }
    }

    @Override
    protected void setStyle(Workbook workbook) {
        DefaultCellStyle defaultCellStyle = new DefaultCellStyleImpl();
        super.cellStyle = defaultCellStyle.setCellStyle(workbook);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

如果还需要导出其他excel,同样继承下ExcelView并实现setRow和setStyle就可以了。

由于样式可能会设置通用的,但又有扩展的可能性,所以可以实现一个默认样式接口。

DefaultCellStyle.class

public interface DefaultCellStyle {
    CellStyle setCellStyle(Workbook workbook);
}
  • 1
  • 2
  • 3

DefaultCellStyleImpl.class

public class DefaultCellStyleImpl implements DefaultCellStyle {
    @Override
    public CellStyle setCellStyle(Workbook workbook) {
        // create style for header cells
        CellStyle cellStyle = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setFontName("Arial");
        cellStyle.setFillForegroundColor(HSSFColor.BLUE.index);
        cellStyle.setFillPattern((short) 1);
        font.setBold(true);
        font.setColor(HSSFColor.WHITE.index);
        cellStyle.setFont(font);
        return cellStyle;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

https://blog.csdn.net/wang124454731/article/details/73850645

原文地址:https://www.cnblogs.com/softidea/p/9363963.html

时间: 2024-10-31 16:48:26

spring boot使用AbstractXlsView导出excel的相关文章

spring boot 使用POI导出数据到Excel表格

摘自:https://www.cnblogs.com/hopeofthevillage/p/12099807.html spring boot 使用POI导出数据到Excel表格 2019-12-26 00:17  全me村的希望  阅读(42)  评论(0)  编辑收藏 在spring boot 的项目经常碰到将数据导出到Excel表格的需求,而POI技术则对于java操作Excel表格提供了API,POI中对于多种类型的文档都提供了操作的接口,但是其对于Excel表格的操作无疑是最强大的.

一、【Spring Boot】 Excel文件导出下载

   Spring Boot Excel 文件导出 目标: 实现Excel文件的直接导出下载,后续开发不需要开发很多代码,直接继承已经写好的代码,增加一个Xml配置就可以直接导出. 实现: 1.抽象类 BaseExcelView 继承 webmvc 的 AbstractXlsxStreamingView 抽象类, AbstractXlsxStreamingView 是webmvc继承了最顶层View接口,是可以直接大量数据导出的不会造成内存泄漏问题,即 SXSSFWorkbook 解决了内存问题

Spring Boot导出jar包发布

一:事由 现在的项目组开发项目使用的是Spring Boot的技术,开发的时候是直接通过一个入口主函数来启动项目的.如果将项目交给客户,怎样才能正确的发布运行呢?百度了一下有关的知识,大概了解到是通过导出jar包,直接运行来实现的.不过从网上查阅的资料,都不太理想,于是自己和另外一个同事就倒腾开了.倒腾了好一会,最终找到了一个比较简单有效的方法来实现,现在分享如下. 二:从Eclipse中导出对应的可运行的jar包(这一步是最为关键的) 1:选中对应的java项目——右键——导出 2:选择导出j

spring mvc 导出 excel

1 // js 触发导出 excel 方法 导出当前页的数据 含有条件查询的结果 2 // js 框架使用的 是 easyui 3 function doExport(){ 4 5 6 var optins = $("#grid").datagrid("getPager").data("pagination").options; 7 var page = optins.pageNumber; 8 var rows = optins.pageSiz

spring+struts2+mybatis中poi导出excel数据

1.html <div id="formDiv"> <form id="dynamicForm" target="_blank"> </form> </div> <a href="javascript:void(0);" id="exporExcel" class="easyui-linkbutton" iconCls="i

Spring boot 项目导出可执行jar

配置文件中添加插件 <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.0.5.RELEASE</version> <executions> <execution> <goals> <goal>repa

【每日一点】1. Java如何实现导出Excel单表头或多表头

一.背景 在后台项目中,经常会遇到将呈现的内容导出到Excel的需求,通过都是导出单个表头的Excel文件,如果存在级联关系的情况下,也就需要导出多表头的场景.今天这篇文章就是分享导出Excel单表头或多表头的实现,目前实现方案仅支持2行表头场景.如有更复杂的3行表头.4行表头复杂需求可以自行实现. 二.实现思路 1. 借助POI包实现表头的写入.每个表头其实就是一行,如果是多个表头,无非就是将写多行表头,然后将需要合并的表头进行合并,借助POI的函数为addMergedRegion. 2. 将

超级简单POI多sheet导出Excel实战

本章节主要基于上一章节单sheet导出的基础上进行改造实现多sheet的导出,上一章节参考地址:https://www.cnblogs.com/sunny1009/p/11437005.html 1.数据准备 这里导出两个sheet为例进行讲解,第一个sheet导出学生基本信息,表结构和数据参考上一章节,第二个sheet导出区域基本信息,具体数据和脚本如下 CREATE TABLE `td_area` ( `id` mediumint(7) unsigned NOT NULL AUTO_INCR

spring boot + quartz 集群

spring boot bean配置: @Configuration public class QuartzConfig { @Value("${quartz.scheduler.instanceName}") private String quartzInstanceName; @Value("${org.quartz.dataSource.myDS.driver}") private String myDSDriver; @Value("${org.q