9.0 KiB
9.0 KiB
EasyExcel 上传(导入)
以人口(Population)导入为例:
-
包含 Excel实体类、错误实体类、导入监听器,其中 错误实体类 非必须。
-
如果不需要返回错误,可忽略输出错误文件的代码。
Excel实体类
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
}
错误试题类
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
}
监听器
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 层
@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 层
@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);
}
模板下载接口
@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");
}
列表导入按钮
<button type="button" class="layui-btn layui-btn-sm" id="uploadExcel">
<i class="fa fa-lg fa-cloud-upload"></i> 导入数据
</button>
列表导入事件
$(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();
}
});
});
导入页面代码
<!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>