POI的使用
先导包
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.11</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.11</version>
</dependency>
通过代码写一个九九乘法表在Excel里面
// 通过代码写一个九九乘法表
@Test
public void myTest() throws Exception{
//先创建一个Excel文件
SXSSFWorkbook wb = new SXSSFWorkbook();
// 创建一张表
Sheet sheet = wb.createSheet("九九乘法口诀");
// 创建相应的行
for (int i=1;i<=9;i++){
Row row = sheet.createRow(i-1);
//创建每行里面的格子
for (int j=1;j<=i;j++){
Cell cell = row.createCell(j);
// 在单元格里面填入数据
cell.setCellValue(i+"*"+j+"="+(i*j));
}
}
FileOutputStream out = new FileOutputStream("temp/99.xlsx");
wb.write(out);//保存Excel文件
out.close();//关闭文件流
}
通过代码读取xlsx文件
//通过代码来读取外部Excel文件
@Test
public void testRead() throws Exception{
// 先将文件直接读取到内存中来
Workbook wb = WorkbookFactory.create(new File("temp/emp.xlsx"));
// 根据文件拿到对应的表
Sheet sheet = wb.getSheetAt(0);
// 拿到对应的行
// 先通过拿最后一行,得到总行数
int lastRowNum = sheet.getLastRowNum();
//遍历行
for (int i=2;i<=lastRowNum;i++){
// 拿到对应的行
Row row = sheet.getRow(i);
//通过行,拿到每行对应的单元格
// 先通过获取最后一个单元格,来得到每行总的格数
short lastCellNum = row.getLastCellNum();
// 遍历每一行的每一个单元格
for (int j=0;j<lastCellNum;j++){
// 拿到该单元格的内容
Cell cell = row.getCell(j);
System.out.print(cell.getStringCellValue()+" ");
}
System.out.println();
}
}
学习怎样使用Easypoi
导入EasyPoi之前要将之前导入的POI包,删除。不然会有冲突
<!-- easypoi的支持 -->
<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>
在test里面准备一个domain POIEmployee
写一个EasyPOITest
在domain里面,如果那个字段要导出,就写上@Excel加一个name
// 添加上下面的注解,就代表哪个字段需要导出
@Excel(name = "用戶名")
private String name;
@Excel(name = "邮箱",width =20)
private String email;
替换功能:
将true改为男,false改为女
//想让导出的文件在性别显示的地方,显示男或者女,而不是显示true或者false
@Excel(name = "性别",replace = {"男_true","女_false"})
private Boolean sex=true;
解决日期问题
//导出时间,并设置导出的时间格式
@Excel(name = "出生日期",format = "yyyy-MM-dd")
private Date bornDate=new Date();
头像问题解决
// 导出图片
@Excel(name = "用户头像",type = 2,height = 35,width = 50)
private String headImage;
关联表
ExcelEmployee
@ExcelTarget("emp")
public class ExcelEmployee implements Serializable{
private Long id;
// 添加上下面的注解,就代表哪个字段需要导出
@Excel(name = "用戶名")
private String name;
@Excel(name = "邮箱",width =20)
private String email;
//想让导出的文件在性别显示的地方,显示男或者女,而不是显示true或者false
@Excel(name = "性别",replace = {"男_true","女_false"})
private Boolean sex=true;
//导出时间,并设置导出的时间格式
@Excel(name = "出生日期",format = "yyyy-MM-dd")
private Date bornDate=new Date();
// 导出图片
@Excel(name = "用户头像",type = 2,height = 35,width = 50)
private String headImage;
// 关联部门
@ExcelEntity
private POIDepartment department;
POIDepartment
@ExcelTarget("dept")
public class POIDepartment {
private Long id;
// 给两个表配置@ExcelTarget,然后在下面配置@Excel的name,表示当导出部门表的时候
// 显示名称,导出员工数据的时候显示部门名称
@Excel(name = "部门名称_emp,名称_dept")
private String name;
@Excel(name = "部门地址_emp,名称_dept")
private String address="簇锦街道";
导入
// 导入我们之前导出的数据
@Test
public void testRead() throws Exception{
// 设置的导入参数
ImportParams params = new ImportParams();
params.setTitleRows(1);
params.setHeadRows(1);
List<ExcelEmployee> list = ExcelImportUtil.importExcel(new File("temp/employee.xls"),
ExcelEmployee.class,params
);
list.forEach(excelEmployee -> System.out.println(excelEmployee));
}
和项目相结合,实现导出功能。
第一步,先加注解
名字,邮箱,年龄,头像,部门,给部门添加的注解用@EntityExcel,在部门domain里面对name添加@Excel
第二步:添加一个按钮
<a href="/employee/export" data-method="search" class="easyui-linkbutton" iconCls="icon-search">导出</a>
在EmployeeController里面添加一个路径方法
@RequestMapping(“/export”)
public String export(ModelMap map){
//怎么从数据库中拿到数据,并变成Excel中的数据,并且要导出到前台
查看EasyPOI教程,注解导出view的用法
}
然后在注解目录扫描的时候加上cn.afterturn.easypoi.view
扫描Excel的View包,在applicationContext-mvc
<!--扫描Excel的view包-->
<context:component-scan base-package="cn.afterturn.easypoi.view"/>
<bean id="beanNameViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"
p:order="0"/>
使用了p:order=”0”的时候,会添加一个假的头。
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
实现员工头像的导出
// 以图片的样式来导出员工的图片路径
// 先拿到图片的真实路径
String realPath = request.getServletContext().getRealPath("");
list.forEach(e->{
e.setHeadImage(e.getHeadImage());
});
如果只想导出单个部门的所有数据
给查询部件的form添加一个method=“post”
和action=”/employee/export”
并将导出变成按钮格式
<button class=”easyui-linkbutton” iconCls=”icon-search”>导出</button>
前台传入相应的查询数据
<form id="searchForm" method="post" action="/employee/download">
用户名: <input name="username" class="easyui-textbox" style="width:80px">
邮件: <input name="email" class="easyui-textbox" style="width:80px">
部门:
<input name="departmentId" class="easyui-combobox"
data-options="panelHeight:'auto',valueField:'id',textField:'name',url:'/util/deptlist'" />
<a href="javascript:;" data-method="search" class="easyui-linkbutton" iconCls="icon-search">查询</a>
<!-- button不写type,它就是提交 -->
<button class="easyui-linkbutton" iconCls="icon-redo">导出</button>
</form>
写一个导入管理的页面,ImportController
package cn.cxm.aisell.web.controller;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.cxm.aisell.common.EmployeeExcelVerifyHandler;
import cn.cxm.aisell.domain.Department;
import cn.cxm.aisell.domain.Employee;
import cn.cxm.aisell.service.IDepartmentService;
import cn.cxm.aisell.service.IEmployeeService;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.OutputStream;
import java.util.List;
@Controller
@RequestMapping("/import")
public class ImportController {
@Autowired
private IEmployeeService employeeService;
@Autowired
private IDepartmentService departmentService;
@Autowired
private EmployeeExcelVerifyHandler employeeExcelVerifyHandler;
// 上传页面
@RequestMapping("/index")
public String index() {
return "import";
}
// 上传Excel的功能实现
@RequestMapping("/employeeXlsx")
public String employeeXlsx(MultipartFile empFile, HttpServletResponse response) throws Exception{
//设置导入参数
ImportParams params = new ImportParams();
params.setHeadRows(1);
// 为true表示这里需要验证
params.setNeedVerfiy(true);
// 加入自定义验证
params.setVerifyHandler(employeeExcelVerifyHandler);
ExcelImportResult<Employee> result=ExcelImportUtil.importExcelMore(
empFile.getInputStream(), Employee.class, params);
// 拿到数据将其保存到数据库里面
List<Employee> list = result.getList();
list.forEach(e -> {
// 从数据库中查询到部门的名字
String deptName = e.getDepartment().getName();
// 通过部门的名字来查找部门的其他信息
Department byName = departmentService.findByName(deptName);
e.setDepartment(byName);
// 这里我们给他设置一个初始密码
e.setPassword("123");
employeeService.save(e);
});
// 利用之前学过的下载功能将文件写出
Workbook failWorkbook = result.getFailWorkbook();
//大佬说下面设置好直接使用即可导出
//设置响应的文件类型 mime类型
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//attachment:表示不要用浏览器打开
response.setHeader("Content-disposition", "attachment;filename=empFail.xlsx");
response.setHeader("Pragma", "No-cache");//设置不要缓存
OutputStream ouputStream = response.getOutputStream();
failWorkbook.write(ouputStream);
ouputStream.flush();
ouputStream.close();
return "import";
}
}
导入的时候应该做一下验证
导入验证包
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
自定义验证用户是否存在
这个类型是需要Spring扫描
/*把普通javaBean实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>
* */
@Component
public class EmployeeExcelVerifyHandler implements IExcelVerifyHandler<Employee> {
@Autowired
private IEmployeeService employeeService;
@Override
public ExcelVerifyHandlerResult verifyHandler(Employee employee) {
// 自定义验证,验证新导入的用户名是否重复
boolean checkName = employeeService.checkName(employee.getUsername());
if (checkName){
// 如果核对后显示为true,就代表该用户名可用
return new ExcelVerifyHandlerResult(true);
}
return new ExcelVerifyHandlerResult(false,"该用户名已被使用");
}
}
导入功能修改
要验证,必需设置 params.setNeedVerfiy(true);
自定义验证:params.setVerifyHandler(employeeExcelVerifyHandler);
result.getList(); 拿到所有通过验证的数据 result.getFailList():拿到所有错误的数据 result.getFailWorkbook();拿到错误的文本
@Autowired
private EmployeeExcelVerifyHandler employeeExcelVerifyHandler;
...
@RequestMapping("/empXlsx")
public String empXlsx(MultipartFile empFile, HttpServletResponse response) throws Exception{
//准备一些导入的参数
ImportParams params = new ImportParams();
params.setTitleRows(1);
params.setHeadRows(1);
params.setNeedVerfiy(true); //需要做验证
//设置验证处理器
params.setVerifyHandler(employeeExcelVerifyHandler);
//把上传的excel文件中的数据变成Employee
ExcelImportResult<Employee> result = ExcelImportUtil.importExcelMore(
empFile.getInputStream(),
Employee.class, params);
//拿到相应的值
List<Employee> list = result.getList();
//把员工进行保存
list.forEach(e -> {
//设置一个默认密码
e.setPassword("123456");
//根据名称到数据库中拿到部门
Department department = e.getDepartment();
if(department!=null){
Department dbDept = departmentService.findByName(department.getName());
e.setDepartment(dbDept);
}
employeeService.save(e);
});
//拿到错误的值
// List<Employee> errList = result.getFailList();
// errList.forEach(e -> System.out.println("错误的:"+e));
//有错误的情况进行导出
if(result.isVerfiyFail()){
//拿到错误的文件
Workbook failWorkbook = result.getFailWorkbook();
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();
failWorkbook.write(ouputStream);
ouputStream.flush();
ouputStream.close();
}
return "import";
}