咱们现在开发前端都是直接使用SpringMVC,因此,EasyPoi也直接提供了对SpringMVC的支持!
要想操作excel表格的导入导出,只需要引入easypoi就可以简单的操作
以下为官方的介绍:
easypoi view 项目是为了更简单的方便搭建在导出时候的操作,利用spring mvc 的view 封装,更加符合spring mvc的风格 view下面包括多个 view的实现
EasypoiBigExcelExportView 大=数据量导出
EasypoiMapExcelView= map 列表导出
EasypoiPDFTemplateV=iew pdf导出
EasypoiSingleE=xcelView 注解导出
EasypoiTemplateExcelView 模板导出
EasypoiTemplateWordView word模板导出
MapGraphExcelView 图表导出
view的是使用方法大同小异,都有一个对应的bean,里面保护指定的参数常量 同意用modelmap.put(‘常量参数名’,‘值’)就可以,最后返回这个view名字
注解目录扫描的时候加上 cn.afterturn.easypoi.view 就可以使用了
导入jar包
cn.afterturn
easypoi-base
3.2.0
cn.afterturn
easypoi-web
3.2.0
cn.afterturn
easypoi-annotation
3.2.0
在浏览器点击导出从数据库导出数据
实体类employee,department
在需要导出的字段上打上注解
一些注解的语法:
1.年龄_emp
必需保证类的ExcelTarget的id是emp才会展示
2.format = “yyyy-MM-dd”:日期的格式
注:如果数据库是varchar,还需要配置databaseFormat
3.replace={“男_true”,“女_false”}
如果值是true,那么展示男,如果是false,则在页面展示女
4.@ExcelEntity(id=“emp”):对应另一个关连对象
id是为这个实体取一个名称,和关连的导出对应
5.type = 2 :代表这是一个图片展示
6.如果需要在指定表显示指定的字段需要给表取名字
然后想要的字段就在设置名字的时候加上别名,比如:
详细注解参考文档
@Entity
@Table(name="employee")
public class Employee extends BaseDomain {
@Excel(name = "用户名")
private String username;
private String password;
@Excel(name = "邮件",width = 25)
private String email;
@Excel(name = "年纪")
private Integer age;
@Excel(name = "头像",type = 2,width = 10 , height = 20)
//加入头像字段
private String headImage;
@ExcelEntity
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "department_id")
@JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"})
private Department department;
省略getset...
}
1.准备导出页面,以实体类employee为例
在高级查询条中加入导出功能
<%--高级查询查询条--%>
为什么需要高级查询?
@RequestMapping("/download")
public String download(EmployeeQuery query,ModelMap map, HttpServletRequest request) {
List list = employeeService.findByQuery(query);
//搞定路径问题
list.forEach(e -> {
String realPath = request.getServletContext().getRealPath("");
e.setHeadImage(realPath+e.getHeadImage());
});
ExportParams params = new ExportParams("员工数据", "测试", ExcelType.XSSF);
params.setFreezeCol(2); //设置固定列
map.put(NormalExcelConstants.DATA_LIST, list); // 数据集合
map.put(NormalExcelConstants.CLASS, Employee.class);//导出实体
map.put(NormalExcelConstants.PARAMS, params);//参数
map.put(NormalExcelConstants.FILE_NAME, "员工信息");//文件名称
return NormalExcelConstants.EASYPOI_EXCEL_VIEW;
}
点击导出报错
原因是配置了视图解析器,响应的时候会自动使用我们的视图解析器,自动加上后缀
解决方法:
applicationContext-mvc.xml注解目录扫描的时候加上 cn.afterturn.easypoi.view
//到处excel表格 /employee/download
@RequestMapping("/download")
public String download(EmployeeQuery query,ModelMap map, HttpServletRequest request) {
System.out.println("=================================adasd");
List list = iEmployeeService.findByQuery(query);
//修改当前员工的头像路径 -> 真实路径
String realPath = request.getServletContext().getRealPath("");
list.forEach(e->{
e.setHeadImage(realPath + e.getHeadImage());
});
ExportParams params = new ExportParams("员工数据", "测试", ExcelType.XSSF);
//params.setFreezeCol(2); 冻结相应的列
map.put(NormalExcelConstants.DATA_LIST, list); // 数据集合
map.put(NormalExcelConstants.CLASS, Employee.class);//导出实体
map.put(NormalExcelConstants.PARAMS, params);//参数
map.put(NormalExcelConstants.FILE_NAME, "employee");//文件名称
//return "easypoiExcelView";
return NormalExcelConstants.EASYPOI_EXCEL_VIEW;//View名称
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%@include file="/WEB-INF/views/head.jsp" %>
${count}
ImportController层的准备
@Controller
@RequestMapping("/import")
public class ImportController {
@RequestMapping("/index")
public String index(){
System.out.println("进入导入功能");
return "import";
}
@RequestMapping("/xlsx")
public String importEmployee(MultipartFile xlsxFile,HttpServletResponse response) throws Exception {
return "import";
}
从外部将数据导入数据库
controller层代码
@RequestMapping("/xlsx")
public String importEmployee(MultipartFile xlsxFile) throws Exception {
InputStream inputStream = xlsxFile.getInputStream();
ImportParams params = new ImportParams();
//没有注释之前查出来是null
params.setTitleRows(1);
List list = ExcelImportUtil.importExcel(
inputStream,
Employee.class, params);
list.forEach(u -> u);
return "import";
}
@RequestMapping("/xlsx")
public String importEmployee(MultipartFile xlsxFile) throws Exception {
InputStream inputStream = xlsxFile.getInputStream();
ImportParams params = new ImportParams();
//没有注释之前查出来是null
params.setTitleRows(1);
List list = ExcelImportUtil.importExcel(
inputStream,
Employee.class, params);
list.forEach(u -> iEmployeeService.save(u));
return "import";
}
因为我们在保存时将密码加密了,如果导入的用户密码为空,就会报错
所以在保存时设置初始密码123
继续测试又报错
个人理解:
我们前台直接添加时,持久层保存都是save方法,没有id可以自动创建,
保存employee时也没有传id为什么就不会报错?因为在封装employee之前jpa会自动去查询到部门,封装到员工对象,然后再保存员工
但是
现在使用的是easypoi,能自动识别吗?
不能,只通过一个部门的名称,不能封装成对象存入employee对象,id都为null,现在部门就只存了一个部门名字
employee对象中,就只有一个id为空的部门对象,只根据这个部门名称并不能确定部门对象
我们表中有什么数据,对应得上实体类的字段,就可以存入
Easypoi只能封装对象的字段,和对应的另一个实体类对象字段,而且是打了注解的才可以
思路整理
@RequestMapping("/xlsx")
public String importEmployee(MultipartFile xlsxFile) throws Exception {
InputStream inputStream = xlsxFile.getInputStream();
ImportParams params = new ImportParams();
//没有注释之前查出来是null
params.setTitleRows(1);;
List list = ExcelImportUtil.importExcel(
inputStream,
Employee.class, params);
for (Employee e : list) {
e.setPassword("123");
//通过员工的
if (e.getDepartment()!=null){
//Department{name='IT部', id=null} 现在部门的id是空,前台导入的时候不能确定部门,报错
//通过名字将部门查出来,再存入到这个员工对象中
System.out.println(iDepartmentService);
Department department = iDepartmentService.findByName(e.getDepartment().getName());
e.setDepartment(department);
}
iEmployeeService.save(e);
}
return "import";
}
基本的导入功能完成,但是用户名重复,年龄等等不符合标准
所以需要验证
实体类注解
@Entity
@Table(name="employee")
public class Employee extends BaseDomain {
@Excel(name = "用户名")
@NotBlank(message = "用户名不能为空")
private String username;
private String password;
@Excel(name = "邮件",width = 25)
private String email;
@Max(value =60,message = "年纪最大为60岁")
@Excel(name = "年纪")
private Integer age;
@Excel(name = "头像",type = 2,width = 10 , height = 20)
//加入头像字段
private String headImage;
}
Controller层启用验证
//设置启用 验证
params.setNeedVerfiy(true);
获得导入的数据
//获取到所有导入的数据
ExcelImportResult result = ExcelImportUtil.importExcelMore(inputStream, Employee.class, params);
注意现在是使用 ExcelImportUtil.importExcelMore获取导入 数据
现在控制层就只将通过验证的数据保存
@RequestMapping("/xlsx")
public String importEmployee(MultipartFile xlsxFile,HttpServletResponse response) throws Exception {
InputStream inputStream = xlsxFile.getInputStream();
/* 获取导入参数*/
ImportParams params = new ImportParams();
//没有注释之前查出来是null
params.setTitleRows(1);
//设置启用 验证
params.setNeedVerfiy(true);
//获取到所有导入的数据
ExcelImportResult result = ExcelImportUtil.importExcelMore(inputStream, Employee.class, params);
/*得到成功的数据*/
for (Employee e : result.getList()) {
System.out.println(e+"成功的数据===============================");
e.setPassword("123");
//通过员工的
if (e.getDepartment()!=null){
//Department{name='IT部', id=null} 现在部门的id是空,前台导入的时候不能确定部门,报错
//通过名字将部门查出来,再存入到这个员工对象中
System.out.println(iDepartmentService);
Department department = iDepartmentService.findByName(e.getDepartment().getName());
e.setDepartment(department);
}
iEmployeeService.save(e);
}
return "import";
}
1.实现接口
2.确定泛型
3.开启扫描,告诉springMvc这个类
4.通过查询数据库判断是否重复用户名
5.@Component注解 组件 交给spring管理
@Component
public class MyExcelVerifyHandler implements IExcelVerifyHandler {
//确定泛型
@Autowired
private IEmployeeService iEmployeeService;
@Override
public ExcelVerifyHandlerResult verifyHandler(Employee employee) {
ExcelVerifyHandlerResult result = new ExcelVerifyHandlerResult();
//判断是否重名,如果用户名能用,返回true
Boolean bool = iEmployeeService.checkName(employee.getUsername());
if (!bool){
result.setMsg("用户名重复了");
result.setSuccess(false);
return result;
}
/*没有重复就返回true,通过验证*/
result.setSuccess(true);
return result;
}
}
错误文件
easyPOI已经自动将错误文件生成了,直接使用
文件下载功能,直接返回浏览器,下载错误文件
if (result.isVerfiyFail()){
//错误的文件
//easyPOI自动已经生成了错误文件
Workbook wb = result.getFailWorkbook();
System.out.println(wb);
//选择文件的类型,从tomcat的conf打开web.xml选择对应的文件类型
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); //mime类型
response.setHeader("Content-disposition", "attachment;filename=error.xlsx");
//设置不要缓存
response.setHeader("Pragma", "No-cache");
OutputStream ouputStream = response.getOutputStream();
wb.write(ouputStream);
ouputStream.flush();
ouputStream.close();
}
@RequestMapping("/xlsx")
public String importEmployee(MultipartFile xlsxFile,HttpServletResponse response) throws Exception {
InputStream inputStream = xlsxFile.getInputStream();
/* 获取导入参数*/
ImportParams params = new ImportParams();
//没有注释之前查出来是null
params.setTitleRows(1);
//设置启用 验证
params.setNeedVerfiy(true);
//放入自定义验证
params.setVerifyHandler(myExcelVerifyHandler);
//获取到所有导入的数据
ExcelImportResult result = ExcelImportUtil.importExcelMore(inputStream, Employee.class, params);
/*得到成功的数据*/
for (Employee e : result.getList()) {
System.out.println(e+"成功的数据===============================");
e.setPassword("123");
//通过员工的
if (e.getDepartment()!=null){
//Department{name='IT部', id=null} 现在部门的id是空,前台导入的时候不能确定部门,报错
//通过名字将部门查出来,再存入到这个员工对象中
System.out.println(iDepartmentService);
Department department = iDepartmentService.findByName(e.getDepartment().getName());
e.setDepartment(department);
}
iEmployeeService.save(e);
}
if (result.isVerfiyFail()){
//错误的文件
//easyPOI自动已经生成了错误文件
Workbook wb = result.getFailWorkbook();
System.out.println(wb);
//选择文件的类型,从tomcat的conf打开web.xml选择对应的文件类型
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); //mime类型
response.setHeader("Content-disposition", "attachment;filename=error.xlsx");
//设置不要缓存
response.setHeader("Pragma", "No-cache");
OutputStream ouputStream = response.getOutputStream();
wb.write(ouputStream);
ouputStream.flush();
ouputStream.close();
}
return "import";
}