EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
直接开始,原理就不讲了,需要了解的去官网看:
Alibaba Easy Excel - 简单、省内存的Java解析Excel工具 | 首页
1.首先导入依赖(IDEA需要安装lombok插件)
com.alibaba
easyexcel
2.2.7
com.alibaba
fastjson
1.2.75
org.projectlombok
lombok
true
2.编写工具类:ExcelUtils
/**
* Excel工具类
*/
@Slf4j
public class ExcelUtils {
/**
* 导出Excel(07版.xlsx)到指定路径下
*
* @param path 路径
* @param excelName Excel名称
* @param sheetName sheet页名称
* @param clazz Excel要转换的类型
* @param data 要导出的数据
*/
public static void export2File(String path, String excelName, String sheetName, Class clazz, List data) {
String fileName = path.concat(excelName).concat(ExcelTypeEnum.XLSX.getValue());
EasyExcel.write(fileName, clazz).sheet(sheetName).doWrite(data);
}
/**
* 导出Excel(07版.xlsx)到web
*
* @param response 响应
* @param excelName Excel名称
* @param sheetName sheet页名称
* @param clazz Excel要转换的类型
* @param data 要导出的数据
* @throws Exception
*/
public static void export2Web(HttpServletResponse response, String excelName, String sheetName, Class clazz, List data) throws Exception {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码
excelName = URLEncoder.encode(excelName, "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + excelName + ExcelTypeEnum.XLSX.getValue());
EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(data);
}
/**
* 将指定位置指定名称的Excel导出到web
*
* @param response 响应
* @param path 文件路径
* @param excelName 文件名称
* @return
* @throws UnsupportedEncodingException
*/
public static String export2Web4File(HttpServletResponse response, String path, String excelName) throws UnsupportedEncodingException {
File file = new File(path.concat(excelName).concat(ExcelTypeEnum.XLSX.getValue()));
if (!file.exists()) {
return "文件不存在!";
}
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码
excelName = URLEncoder.encode(excelName, "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + excelName + ExcelTypeEnum.XLSX.getValue());
try (
FileInputStream in = new FileInputStream(file);
ServletOutputStream out = response.getOutputStream();
) {
IOUtils.copy(in, out);
return "导出成功!";
} catch (Exception e) {
log.error("导出文件异常:", e);
}
return "导出失败!";
}
}
2.编写excel上传的工具类(这里上传的是物品类别Sorttype):TypeDataListener
@Slf4j
public class TypeDataListener extends AnalysisEventListener {
private TypeService typeService;
public TypeDataListener(TypeService typeService) {
this.typeService = typeService;
}
/**
* 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 5;
List list = new ArrayList();
@Override
public void invoke(Sorttype data, AnalysisContext context) {
log.info("解析到一条数据:{}", JSON.toJSONString(data));
list.add(data);
if (list.size() >= BATCH_COUNT) {
saveData();
list.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
saveData();
log.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
log.info("{}条数据,开始存储数据库!", list.size());
if (!CollectionUtils.isEmpty(list)) {
typeService.saveBatch(list);
}
log.info("存储数据库成功!");
}
}
3.用到的了service接口和实现类:
接口:TypeService
public interface TypeService {
// 查询所有用户信息
List getAll();
void saveBatch(List list);
}
实现类:TypeServiceImpl
@Service
public class TypeServiceImpl implements TypeService {
@Resource
private SorttypeMapper sorttypeMapper;
@Override
public List getAll() {
return sorttypeMapper.selectSorttypeList(null);
}
@Override
public void saveBatch(List list) {
for (Sorttype sorttype : list) {
sorttype.setCreatetime(new Date());
sorttypeMapper.add(sorttype);
}
}
}
这里Mapper就不写了,就是一个insert插入和一个查询所有,对应这个导入和导出
4.实体类Sorttype :
package com.module.pojo;
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 lombok.Data;
import java.util.Date;
/**
* 分类表 sorttype
*
*
*
*/
@Data
public class Sorttype {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@ExcelIgnore // 生成报表时忽略,不生成次字段
private Integer id;
/**
* 分类名称
*/
@ExcelProperty(value = "分类名称", index = 0) // 定义表头名称和位置,0代表第一列
private String sortname;
/**
* 分类描述
*/
@ExcelProperty(value = "分类描述", index = 1)
private String intro;
/**
* 创建时间
*/
@ColumnWidth(20) // 定义列宽
@DateTimeFormat(value = "yyyy-MM-dd HH:mm:ss")
@ExcelProperty(value = "创建时间", index = 2)
private Date createtime;
/**
* 设置:ID
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 获取:ID
*/
public Integer getId() {
return id;
}
/**
* 设置:分类名称
*/
public void setSortname(String sortname) {
this.sortname = sortname;
}
/**
* 获取:分类名称
*/
public String getSortname() {
return sortname;
}
/**
* 设置:分类描述
*/
public void setIntro(String intro) {
this.intro = intro;
}
/**
* 获取:分类描述
*/
public String getIntro() {
return intro;
}
/**
* 设置:创建时间
*/
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
/**
* 获取:创建时间
*/
public Date getCreatetime() {
return createtime;
}
}
5.controller中的上传和下载方法:
// easyexcel导出Excel到web
@GetMapping("manage/download")
public void export2Web(HttpServletResponse response) {
try {
ExcelUtils.export2Web(response, "类别表", "类别表", Sorttype.class, typeService.getAll());
} catch (Exception e) {
log.error("报表导出异常:", e);
}
}
// easyexcel上传文件
@PostMapping("/upload")
public String upload(MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(), Sorttype.class, new TypeDataListener(typeService)).sheet().doRead();
return "redirect:manage/sorttypeList";
}
这里要注意上传方法export2Web的返回值一定要是void,不然后台会报错!
6.页面和js:
//批量导入
$(".daoru").click(function () {
var url = ctx + "/manage/toUploadPage";
location.href = url; //路径跳转
})
//批量下载
$(".xiazai").click(function () {
var url = ctx + "/manage/download";
location.href = url; //路径跳转
})
表结构:
页面效果:
下载后的excle表: