首先这篇博客可以告诉你什么?
- springboot中 如何用easypoi导出数据?
- 用ajax请求数据流,后台写入字节流无反应
- maven导入easypoi的 springboot版本后,报 ErrorWebMvc is registry 的错误
- easypoi的简单使用
在自己做的一个 SpringBoot 2.14Relese 版本的一个小系统中 有数据导出的需求。
以前是用 Apache的POI进行数据的导出, 但查到 有简单的封装插件 easypoi ,我决定用一下这个新东西。
首先介绍一下它的中文教程
这个插件通过注解的方式来实现自动添加列
这个注解就是 @Excel 这是最核心的注解,其他的可以看它教程中的具体参数就好
Maven的引入
注意 这里就产生了一个问题 ,之前我是 用 easypoi-spring-boot-starter ,它与 导入上面的3个包的功能是一样的,但是 在 springboot 2.1以上的版本,SpringBoot关于 SpringMVC 的自动配置 中 存在 ErrorWebMvc等类的命名注册冲突,所以还是用回 上面的那3个jar包吧!!
<!-- 集成easypoi组件 .导出excel http://easypoi.mydoc.io/ -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>3.2.0</version>
</dependency>
<!-- Excel 导出插件 但 与 springboot 2.1 版本冲突 -->
<!-- <dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>-->
我们需要导出的数据不一定要新建一个 pojo 类来 对应 列的关系数据
如果在现有的 bean中符合要求,可直接在现有的 bean 上添加 注解
需要导出那些字段上加上注解和相关参数
@EntityScan
public class Record {
private String rid;
@Excel(name = "修改人", width = 20)
private String modify_username;
@Excel(name = "工号", width = 20)
private String emp_id;
@Excel(name = "日期", width = 25,exportFormat = "yyyy-MM-dd HH:mm")
private Date create_date;
@Excel(name = "CAR号", width = 30)
private String leasts;
@Excel(name = "客户编码", width = 35)
private String customercode;
@Excel(name = "修改内容", width = 60)
private String content;
@Excel(name = "修改理由", width = 50)
private String reason;
// 省略get set
}
那么如果 是 存在一对多的关系咋办 ,比如 一个 班级 对应 一个老师,多个学生,导出班级的所有信息
在 Class classes 这个类的字段中对于对象 和 集合添加 @ExcelEntity 和 @ExcelCollection即可
当然ID是对应的, Teacher这个类上也要加@ExcelTarget (“teacher”)对应关系
@ExcelTarget("classes")
public class classes implements java.io.Serializable {
private String id;
@Excel(name = "课程名称", orderNum = "1", width = 25)
private String name;
@ExcelEntity(id = "teacher")
private Teacher teacher;
@ExcelCollection(name = "学生", orderNum = "4")
private List<Student> students;
}
Controller类中相关方法
@GetMapping("/export")
public void complaintChangeRecordToExcel(@RequestParam("startdate") String startdate,
@RequestParam("enddate") String enddate,
HttpServletResponse response) throws Exception {
// 如果要使用 自己设计的模板,而不是让 插件给你自动创建就引入模板,写入字节流
// TemplateExportParams params = new TemplateExportParams("com/suntak/eightdisciplines/doc/record.xlsx");
// params.setSheetName("客诉修改明细");
response.reset();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 由于传入的结束时间是 那天 的0点不符合实际需求,改为当天23:59分
Date startday = sdf.parse(startdate);
Date endday = sdf.parse(enddate);
Calendar cal = Calendar.getInstance();
cal.setTime(endday);
cal.add(Calendar.DAY_OF_MONTH,1);
endday = cal.getTime();
List<Record> list = recordService.getRecordByOptions(startday,endday,"");
//ExcelExportUtil.exportExcel( new ExportParams("8D客诉修改记录明细","客诉修改明细"),Record.class, list)
// 这种是帮你 自行创建 EXCEL表格
// 告诉浏览器用什么软件可以打开此文件
response.setHeader("content-Type", "application/vnd.ms-excel");
// 下载文件的默认名称
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("8D修改数据明细表","UTF-8") + ".xls");
//编码
response.setCharacterEncoding("UTF-8");
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), Record.class, list);
workbook.write(response.getOutputStream());
}
前端当时我是用ajax请求的,发现不报错但是也没反应。这就引发了这个问题
用ajax请求数据流,后台写入字节流无反应?
为什么呢? 这是因为 ajax 是无法直接导出excel的, ajax返回的数据格式是字符流,而导出excel是后台往浏览器中写入二进制的字节流。
字节流是 1byte : 8 bit
字符流是 1 char : 2 byte : 16 bit
那我们该如何 请求呢?
方法有很多,可以用一个内置表单来submit,也可以 window.open(),window.location.href
这里用 window.location.href
// 导出客诉修改EXCEL
$("#exportBtn").click(function(){
var start_day = $("#startdate").val();
var end_day = $("#enddate").val();
window.location.href = contextPath +"record/export?startdate="+start_day + "&enddate="+ end_day;
});
这样请求,浏览器就会直接接受到 Excel的字节流 生成一个 xlsx 的文件。
这里说一下如果是自己设计的模板写入字节流时,模板该怎么写, 注意不要用别名, 直接用 t作为数据对象 {{fe:list t.username,t.password }} ,让数据遍历每行就行。Controller类中的写法看中文文档。