284 lines
9.0 KiB
Markdown
284 lines
9.0 KiB
Markdown
# EasyExcel 上传(导入)
|
||
|
||
以人口(Population)导入为例:
|
||
|
||
1. 包含 **Excel实体类**、**错误实体类**、**导入监听器**,其中 **错误实体类** 非必须。
|
||
|
||
2. 如果不需要返回错误,可忽略输出错误文件的代码。
|
||
|
||
## Excel实体类
|
||
|
||
```java
|
||
import com.alibaba.excel.annotation.ExcelProperty;
|
||
|
||
public class PopulationExcel {
|
||
|
||
@ExcelProperty(index = 0)
|
||
private String name;
|
||
@ExcelProperty(index = 1)
|
||
private String idCard;
|
||
@ExcelProperty(index = 2)
|
||
private String areaCode;
|
||
@ExcelProperty(index = 3)
|
||
private String homeAddress;
|
||
|
||
// get set
|
||
}
|
||
|
||
```
|
||
|
||
## 错误试题类
|
||
|
||
```java
|
||
import com.alibaba.excel.annotation.ExcelProperty;
|
||
|
||
public class PopulationExcelError {
|
||
|
||
@ExcelProperty(index = 0)
|
||
private String name;
|
||
@ExcelProperty(index = 1)
|
||
private String idCard;
|
||
@ExcelProperty(index = 2)
|
||
private String areaCode;
|
||
@ExcelProperty(index = 3)
|
||
private String homeAddress;
|
||
@ExcelProperty(index = 4)
|
||
private String reason;
|
||
|
||
// get set
|
||
}
|
||
|
||
```
|
||
|
||
## 监听器
|
||
|
||
```java
|
||
import com.alibaba.excel.context.AnalysisContext;
|
||
import com.alibaba.excel.event.AnalysisEventListener;
|
||
|
||
import java.util.ArrayList;
|
||
import java.util.List;
|
||
|
||
public abstract class PopulationExcelListener extends AnalysisEventListener<PopulationExcel> {
|
||
|
||
private static final Integer MAX_READ_COUNT = 100;
|
||
private List<PopulationExcel> populationExcels = new ArrayList<>();
|
||
|
||
@Override
|
||
public void invoke(PopulationExcel populationExcel, AnalysisContext analysisContext) {
|
||
if (populationExcels.size() > MAX_READ_COUNT) {
|
||
// 超过读取最大量,执行保存,
|
||
handle(populationExcels);
|
||
populationExcels.clear();
|
||
} else {
|
||
// 未达到读取最大量,继续读取
|
||
populationExcels.add(populationExcel);
|
||
}
|
||
}
|
||
|
||
@Override
|
||
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
|
||
handle(populationExcels);
|
||
populationExcels.clear();
|
||
}
|
||
|
||
/**
|
||
* 处理
|
||
*
|
||
* @param rows
|
||
*/
|
||
public abstract void handle(List<PopulationExcel> rows);
|
||
|
||
}
|
||
```
|
||
|
||
## 导入代码
|
||
|
||
### controller 层
|
||
|
||
```java
|
||
@ApiOperation(value = "试题Excel", notes = "试题Excel接口")
|
||
@ApiImplicitParams({
|
||
@ApiImplicitParam(name = "excel", value = "文件名称", paramType = "form"),
|
||
})
|
||
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||
@PostMapping("import-excel")
|
||
public UploadExcelResultDTO importExcel(MultipartFile excel) throws IOException {
|
||
if (Objects.isNull(excel)) {
|
||
throw new ParamsException("Excel不能为空");
|
||
}
|
||
// 判断后缀
|
||
if (!excel.getOriginalFilename().endsWith(IFileConstant.EXCEL_SUFFIX_XLS)
|
||
&& !excel.getOriginalFilename().endsWith(IFileConstant.EXCEL_SUFFIX_XLSX)) {
|
||
throw new ParamsException("文件格式为Excel");
|
||
}
|
||
return populationService.importExcel(excel);
|
||
}
|
||
```
|
||
|
||
### service 层
|
||
|
||
```java
|
||
@Override
|
||
public UploadExcelResultDTO importExcel(MultipartFile excel) throws IOException {
|
||
|
||
// 要输出的错误内容
|
||
List<PopulationExcelError> populationExcelErrors = new ArrayList<>();
|
||
|
||
long startTime = System.currentTimeMillis();
|
||
// 读取 Excel
|
||
EasyExcel.read(excel.getInputStream(), PopulationExcel.class, new PopulationExcelListener() {
|
||
@Override
|
||
public void handle(List<PopulationExcel> populationExcels) {
|
||
// 这里处理数据,一般是入库
|
||
|
||
}
|
||
}).headRowNumber(2).sheet().doRead();
|
||
long endTime = System.currentTimeMillis();
|
||
|
||
// 生成的错误文件ID,下载时使用
|
||
String excelFileId = null;
|
||
if (populationExcelErrors.size() > 0) {
|
||
excelFileId = new AbstractErrorExcelHandler<PopulationExcelError>(fileService) {
|
||
@Override
|
||
public List<List<String>> excelHeaderNames() {
|
||
// 构建错误 Excel 标题,与错误类对应
|
||
return simpleExcelHeader(new String[]{"序号", "姓名", "身份证", "错误原因"});
|
||
}
|
||
}.saveErrorExcel(populationExcelErrors);
|
||
}
|
||
// 返回实体类,
|
||
return new UploadExcelResultDTO(populationExcelErrors.size(), endTime - startTime, excelFileId);
|
||
}
|
||
```
|
||
|
||
## 模板下载接口
|
||
```java
|
||
@GetMapping("upload/upload-excel-template")
|
||
public void excelTemplate(HttpServletResponse response) throws IOException {
|
||
InputStream inputStream = PopulationRouteController.class.getClassLoader().getResourceAsStream("templates/population/upload/upload-excel-template.xls");
|
||
RequestUtil.download(response, inputStream, "人口导入模板.xls");
|
||
}
|
||
```
|
||
|
||
## 列表导入按钮
|
||
|
||
```html
|
||
<button type="button" class="layui-btn layui-btn-sm" id="uploadExcel">
|
||
<i class="fa fa-lg fa-cloud-upload"></i> 导入数据
|
||
</button>
|
||
```
|
||
|
||
## 列表导入事件
|
||
|
||
```javascript
|
||
$(document).on('click', '#uploadExcel', function() {
|
||
top.dialog.open({
|
||
url: top.restAjax.path('route/population/upload/upload-excel', []),
|
||
title: '导入人口数据',
|
||
width: '300px',
|
||
height: '196px',
|
||
onClose: function() {
|
||
reloadTable();
|
||
}
|
||
});
|
||
});
|
||
```
|
||
|
||
|
||
## 导入页面代码
|
||
|
||
```html
|
||
<!doctype html>
|
||
<html xmlns:th="http://www.thymeleaf.org">
|
||
<head>
|
||
<base th:href="${#request.getContextPath() + '/'}">
|
||
<meta charset="utf-8">
|
||
<meta name="renderer" content="webkit">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
|
||
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
|
||
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
|
||
</head>
|
||
<body>
|
||
<div class="layui-anim layui-anim-fadein">
|
||
<div class="layui-card" style="text-align: center;">
|
||
<div class="layui-card-body" style="padding: 15px;">
|
||
<blockquote class="layui-elem-quote">下载“下载模板”整理数据,点击“导入数据”上传,格式为xls或xlsx</blockquote>
|
||
<button id="downloadFile" type="button" class="layui-btn layui-btn" onclick="window.open('route/population/upload/upload-excel-template', 'downloadTarget')">
|
||
<i class="fa fa-lg fa-cloud-download"></i> 下载模板
|
||
</button>
|
||
<button type="button" class="layui-btn layui-btn" id="uploadExcel">
|
||
<i class="fa fa-lg fa-cloud-upload"></i> 导入数据
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<iframe style="display: none" name="downloadTarget"></iframe>
|
||
</div>
|
||
<script src="assets/layuiadmin/layui/layui.js"></script>
|
||
<script>
|
||
layui.config({
|
||
base: 'assets/layuiadmin/' //静态资源所在路径
|
||
}).extend({
|
||
index: 'lib/index' //主入口模块
|
||
}).use(['index', 'upload', 'common'], function(){
|
||
var $ = layui.$;
|
||
var form = layui.form;
|
||
var common = layui.common;
|
||
|
||
function closeBox() {
|
||
parent.layer.close(parent.layer.getFrameIndex(window.name));
|
||
}
|
||
|
||
// 初始化Excel上传
|
||
function initExcelUpload() {
|
||
// Excel上传
|
||
var uploadLoading;
|
||
layui.upload.render({
|
||
elem: '#uploadExcel',
|
||
url: 'api/population/import-excel',
|
||
accept: 'file',
|
||
exts: 'xls|xlsx',
|
||
field: 'excel',
|
||
before: function() {
|
||
uploadLoading = layer.msg('正在上传,请稍后...', {icon: 16, time: 0, shade: 0.3});
|
||
},
|
||
done: function(data) {
|
||
layer.close(uploadLoading);
|
||
if(data.failedCount > 0) {
|
||
layer.open({
|
||
type: 1,
|
||
title: false,
|
||
closeBtn: 0,
|
||
shadeClose: true,
|
||
skin: '',
|
||
content: '<div style="padding: 15px;">' +
|
||
'<div>失败数量:'+ data.failedCount +'</div><br/>' +
|
||
'<div><a class="error-excel" href="javascript:void(0);" onclick="window.open(\'route/file/download/false/'+ data.errorExcel +'\');" target="downloadTarget">点击下载错误信息</a></div>' +
|
||
'</div>'
|
||
});
|
||
} else {
|
||
layer.msg('导入成功', {time: 2000}, function() {
|
||
closeBox();
|
||
});
|
||
}
|
||
},
|
||
error: function(data, index){
|
||
layer.close(uploadLoading);
|
||
if(data != null) {
|
||
top.dialog.msg(data.msg);
|
||
}
|
||
},
|
||
});
|
||
}
|
||
initExcelUpload();
|
||
|
||
$('.close').on('click', function() {
|
||
closeBox();
|
||
});
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|
||
``` |