java实现excel导入与导出(总结与实现)
SpringBoot项目集成
1.创建一个springboot项目,我所使用的版本是2.2.4
2.导入EasyExcel的pom依赖,和lombok依赖。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
EasyExcel版本选择
全部使用教程可以EasyExcel官网查看EasyExcel官方文档
一.excle文件导出下载
实体类的创建
这里创建一个实体类,用于封装数据
- 常用注解说明
注解 | 参数 | 说明 |
ExcelIgnore | 无 | 导出时忽略该字段 |
ExcelProperty | value,index,order,converter | value设置该列的名称,order优先级高于value,会根据order的顺序来匹配实体和excel中数据的顺序index 优先级高于value和order,会根据index直接指定写到第几列,默认根据成员变量排序。value指定写入的名称,默认成员变量的名字,多个value可以参照快速开始中的复杂头 ,converter 是自定义转换器 |
DateTimeFormat | string | 日期的格式化 |
ColumnWidth(20) | int | 设置表格列的宽度为20 |
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
@Data
public class PromptInformationDown {
//提示信息表id
@TableId
//导出时忽略该字段
@ExcelIgnore
private Long id;
//角色id(比如经理,财务之类)
//设置该列的名称为角色
@ExcelProperty("角色")
@ColumnWidth(20)
private Long roleId;
//自定义转换器
@ExcelProperty(value ="提示信息类型" ,converter = TipEnum.class)
@ColumnWidth(20)
//提示信息(员工转正1,员工合同到期2,员工退休3,请假4)
private Integer tip;
@ExcelProperty("员工名")
@ColumnWidth(20)
//禁戒的员工名
private String employeeName;
@ColumnWidth(20)
@ExcelProperty("提示创建时间")
@DateTimeFormat("yyyy-MM-dd")
//创建时间
private Date creatTime;
@ColumnWidth(20)
@ExcelProperty("提示最后期限")
@DateTimeFormat("yyyy-MM-dd")
//最后期限
private Date lastTime;
@ColumnWidth(20)
@ExcelProperty("最后处理时间")
@DateTimeFormat("yyyy-MM-dd")
//修改时间
private Date updateTime;
}
自定义转换器
转换器用于将自定义的特殊数字转换成相对应的字符(例如:数据库0,1分别代表男女进行存储,通过转换器在excle中显示的将不是0,1,而是相对应的男女)
注意:不同版本的convertToJavaData,convertToExcelData有些许的不同
package com.wedu.modules.excleUpOrDo;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class TipEnum implements Converter<Integer> {
//提示信息(员工转正1,员工合同到期2,员工退休3,请假4)
private static final String ONE="员工转正";
private static final String TWO="合同到期";
private static final String TREE="员工退休";
private static final String FOUR="请假";
@Override
public Class supportJavaTypeKey() {
return Integer.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public Integer convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
// 从Cell中读取数据
String gender = cellData.getStringValue();
// 判断Excel中的值,将其转换为预期的数值
if (ONE.equals(gender)) {
return 1;
} else if (TWO.equals(gender)) {
return 2;
}else if (TREE.equals(gender)) {
return 3;
}else if (FOUR.equals(gender)) {
return 4;
}
return null;
}
@Override
public CellData convertToExcelData(Integer integer, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
// 判断实体类中获取的值,转换为Excel预期的值,并封装为CellData对象
if (integer == null) {
return new CellData<>("");
} else if (integer == 1) {
return new CellData<>(ONE);
} else if (integer == 2) {
return new CellData<>(TWO);
}else if (integer == 3) {
return new CellData<>(TREE);
}else if (integer == 4) {
return new CellData<>(FOUR);
}
return new CellData<>("");
}
}
数据库数据封装
这里将数据库所得到的数据封装到PromptInformationDown 这个excle的实体类中
这里我使用的是Mybatis Plus去获取数据库中的数据,在service层中进行业务逻辑代码的实现。
excle导出接口
@Override
public List<PromptInformationDown> getAllMember() {
List<PromptInformationDown> list = new ArrayList<>();
//Mybatis Plus自带的list方法,获取所有数据封装到实体类中返回实体类的列表
List<PromptInformationEntity> list1 = this.list();
//通过循环将所得到的数据封装到PromptInformationDown 中
list1.stream().forEach(a -> {
PromptInformationDown d = new PromptInformationDown();
d.setCreatTime(a.getCreatTime());
d.setEmployeeId(a.getEmployeeId());
d.setEmployeeName(a.getEmployeeName());
d.setId(a.getId());
d.setInformationId(a.getInformationId());
d.setLastTime(a.getLastTime());
d.setRoleId(a.getRoleId());
d.setStatus(a.getStatus());
d.setTip(a.getTip());
d.setUpdateTime(a.getUpdateTime());
//将装好的实体类添加进总list中
list.add(d);
});
return list;
}
导出实现
这里实现是在controller中进行实现的
package com.wedu.modules.excleUpOrDo;
import com.alibaba.excel.EasyExcel;
import com.wedu.modules.sys.service.PromptInformationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@Controller
@RequestMapping("/excle")
public class ExcleUpOrDoController {
@Autowired
PromptInformationService informationService;
//文件下载
@PostMapping("/get")
public void getExcle(HttpServletResponse response) throws IOException {
List<PromptInformationDown> members = informationService.getAllMember();
// 设置文本内省
response.setContentType("application/vnd.ms-excel");
// 设置字符编码
response.setCharacterEncoding("utf-8");
// 设置响应头
response.setHeader("Content-disposition", "attachment;filename=demo.xlsx");
EasyExcel.write(response.getOutputStream(), PromptInformationDown.class)
.sheet("消息列表").doWrite(members);
}
}
测试
通过ApiPost软件进行测试
下载之后会得到表格
excle表格的各种样式
这里我们写一个类CustomSheetWriteHandler类,用于美化excle表格
- 这里我将以下拉框举例子(该代码是直接cv上方官方文档中的代码并添加了一些所需,如果需要其他格式,可以去官方文档中查找使用)
package com.wedu.modules.excleUpOrDo;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 自定义拦截器.对第一列第一行和第二行的数据新增下拉框,显示 测试1 测试2
*
* @author Jiaju Zhuang
*/
public class CustomSheetWriteHandler implements SheetWriteHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomSheetWriteHandler.class);
@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
("第{}个Sheet写入成功。", writeSheetHolder.getSheetNo());
// 区间设置 第一列第一行和第二行的数据。由于第一行是头,所以第一、二行的数据实际上是第二三行
//这里1048575是行最大数,超出有可能会报错
CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 1048575, 1, 1);
DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper();
//下拉框中的数据选项
DataValidationConstraint constraint = helper.createExplicitListConstraint(new String[] {"员工转正", "合同到期","员工退休","请假"});
DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
writeSheetHolder.getSheet().addValidationData(dataValidation);
}
}
这里的controller层需要添加一点东西,用于使用该类的渲染
//文件下载
@PostMapping("/get")
public void getExcle(HttpServletResponse response) throws IOException {
List<PromptInformationDown> members = informationService.getAllMember();
// 设置文本内省
response.setContentType("application/vnd.ms-excel");
// 设置字符编码
response.setCharacterEncoding("utf-8");
// 设置响应头
response.setHeader("Content-disposition", "attachment;filename=demo.xlsx");
EasyExcel.write(response.getOutputStream(), PromptInformationDown.class)
//---------------------------------添加下面这句话进行调用----------------------------------
.registerWriteHandler(new CustomSheetWriteHandler())
//---------------------------------------------------------------------------------------
.sheet("消息列表").doWrite(members);
}
直接展示结果
二.文件导入
controller层接口
文件导入会将数据重新分装进导出的实体类中,如果要使用的话可以将该数据封装进自己所需的实体类中
package com.wedu.modules.excleUpOrDo;
import com.alibaba.excel.EasyExcel;
import com.wedu.modules.sys.service.PromptInformationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@Controller
@RequestMapping("/excle")
public class ExcleUpOrDoController {
@Autowired
PromptInformationService informationService;
//文件导入
@PostMapping("/uplode")
public void uplodeExcle(@RequestPart("file")MultipartFile file) throws IOException {
List<PromptInformationDown> list = EasyExcel.read(file.getInputStream())
.head(PromptInformationDown.class)
.sheet()
.doReadSync();
for (PromptInformationDown member : list) {
//输出封装完成的数据
System.out.println(member.setPromptInformationEntity());
}
}
实体类封装
我在导出的实体类PromptInformationDown中加入了一个封装方法
//将文件类进行封装成实体类
public PromptInformationEntity setPromptInformationEntity(){
PromptInformationEntity d=new PromptInformationEntity();
d.setCreatTime(this.getCreatTime());
d.setEmployeeId(this.getEmployeeId());
d.setEmployeeName(this.getEmployeeName());
d.setId(this.getId());
d.setInformationId(this.getInformationId());
d.setLastTime(this.getLastTime());
d.setRoleId(this.getRoleId());
d.setStatus(this.getStatus());
d.setTip(this.getTip());
d.setUpdateTime(this.getUpdateTime());
return d;
}
进行测试
这里报错是因为没有返回的响应数据,不影响
后端得到数据