easyexcel导⼊获取表头并且表头为不固定列
1、Controller层
@PostMapping("upload")
@ResponseBody
public HashMap<String, Object> upload(@RequestParam(value = "file") MultipartFile file,
@RequestParam(value = "ztId") int ztId,
@RequestParam(value = "year") int year,
@RequestParam(value = "month") int month) throws IOException {
//初始化
ZwmxzListener zwmxzListener = new ZwmxzListener(zwmxzService, ztId, year, month);
//解析数据
HashMap<String, Object> hashMap = new HashMap<>();
//获取校验错误信息,并返回给前端
List<String> errMessage = ErrMessage();
if (errMessage.isEmpty()) {
hashMap.put("success", true);
} else {
hashMap.put("success", false);
hashMap.put("errMessage", errMessage);
}
return hashMap;
}
2、Listener
xxx.utils;
xxx.services.ZwmxzService;
import l.context.AnalysisContext;
import l.event.AnalysisEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//继承AnalysisEventListener<Map<Integer, String>>
public class ZwmxzListener extends AnalysisEventListener<Map<Integer, String>> {
//定义每多少条数据进⾏数据库保存
private static final int BATCH_COUNT = 128;
private int ztId;
private int year;
private int month;
private ZwmxzService zwmxzService;
//建⼀个errMessage集合保存校验有问题的结果
private List<String> errMessage;
/
/⽤list集合保存解析到的结果
private List<Map<Integer, Map<Integer, String>>> list;
//重构,把传来的值赋给对应的属性
public ZwmxzListener(ZwmxzService zwmxzService, int ztId, int year, int month) {
this.zwmxzService = zwmxzService;
list = new ArrayList<>();
errMessage = new ArrayList<>();
}
/
**
* 重写invokeHeadMap⽅法,获去表头,如果有需要获取第⼀⾏表头就重写这个⽅法,不需要则不需要重写
*
* @param headMap Excel每⾏解析的数据为Map<Integer, String>类型,Integer是Excel的列索引,String为Excel的单元格值
* @param context context能获取⼀些东西,⽐如adRowHolder().getRowIndex()为Excel的⾏索引,表头的⾏索引为0,0之后的都解析成数据 */
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
logger.info("解析到⼀条头数据:{}, currentRowHolder: {}", String(), adRowHolder().getRowIndex());
Map<Integer, Map<Integer, String>> map = new HashMap<>();
map.adRowHolder().getRowIndex(), headMap);
list.add(map);
}
* 重写invoke⽅法获得除Excel第⼀⾏表头之后的数据,
* 如果Excel第⼆⾏也是表头,那么也会解析到这⾥,如果不需要就通过判断adRowHolder().getRowIndex()跳过 *
* @param data 除了第⼀⾏表头外,数据都会解析到这个⽅法
* @param context 和上⾯解释⼀样
*/
@Override
public void invoke(Map<Integer, String> data, AnalysisContext context) {
logger.info("解析到⼀条数据:{}, currentRowIndex: {}----", String(), adRowHolder().getRowIndex()); Map<Integer, Map<Integer, String>> map = new HashMap<>();
map.adRowHolder().getRowIndex(), data);
list.add(map);
// 达到BATCH_COUNT了,需要去存储⼀次数据库,防⽌数据⼏万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 解析到最后会进⼊这个⽅法,需要重写这个doAfterAllAnalysed⽅法,然后⾥⾯调⽤⾃⼰定义好保存⽅法
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这⾥也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
logger.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
logger.info("{}条数据,开始存储数据库!", list.size());
//⽤errMessage集合保存zwmxzService.save()返回校验错误信息,根据⾃⼰需要来写就⾏了
errMessage.addAll(zwmxzService.save(list, ztId, year, month, errMessage.size() > 0));
}
public int getZtId() {
return ztId;
}
public void setZtId(int ztId) {
}
public int getYear() {
return year;
}
public void setYear(int year) {
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
}
public ZwmxzService getZwmxzService() {
return zwmxzService;
}
public void setZwmxzService(ZwmxzService zwmxzService) {
this.zwmxzService = zwmxzService;
}
public List<String> getErrMessage() {
return errMessage;
}
public void setErrMessage(List<String> errMessage) {
}
public List<Map<Integer, Map<Integer, String>>> getList() {
return list;
public void setList(List<Map<Integer, Map<Integer, String>>> list) {
this.list = list;
}
private final static Logger logger = Logger(ZwmxzListener.class);
}
3、ServiceImpl实现类写导⼊的数据校验,根据⾃⼰的业务需求来写校验规则,当然也可以在⾥⾯就校验,然后调⽤ServiceImpl实现类来保存数据
@Transactional(rollbackFor = Exception.class)
@Override
public List<String> save(List<Map<Integer, Map<Integer, String>>> list, int ztId, int year, int month, boolean hasErr) {
logger.info("--start---导⼊判断----");
List<String> error = new ArrayList<>();
List<Zwmxz> newZwmxz = new ArrayList<>();
String pattern = "^[-]?\\d+(\\.\\d+)?$";
//遍历传过来的数据集合
for (var item : list) {
//每⼀⾏
for (var row : Set()) {
//获取⾏的索引
Integer rowIndex = Key();
//索引为0表⽰为表头
if (rowIndex == 0) {
String leftYear = Value().get(1);
String rightYear = Value().get(2);
logger.info("---leftYear={}--------rightYear={}----------", leftYear, rightYear);
String left = judgeYear(leftYear, year, "B");
if (left != null) {
error.add(left);
}
String right = judgeYear(rightYear, year, "C");
if (right != null) {
error.add(right);
}
} else {
rowIndex++;
logger.info("---rowIndex={}--------", rowIndex);
Zwmxz it = new Zwmxz();
//遍历每⼀⾏的每⼀列数据,并校验
bigdecimal转换为integer
for (var col : Value().entrySet()) {
switch (Key()) {
case 1:
if (Value() == null) {
error.add("序号为【" + rowIndex + "】的数据的B列【⽉份】不可为空!");
} else {
if (Pattern.matches(pattern, Value().trim())) {
if (Integer.Value().trim()) == month) {
it.setMonth(month);
} else {
error.add("序号为【" + rowIndex + "】的数据的B列【⽉份】与当前期间的⽉份不⼀致!");
}
} else {
error.add("序号为【" + rowIndex + "】的数据的B列【⽉份】需要是正常的阿拉伯数字⽉份!");
}
}
break
......................................................case 16:
if (Value() == null) {
it.setYe(BigDecimal.ZERO);
} else {
if (Pattern.matches(pattern, Value().trim())) {
it.setYe(new Value()));
} else {
it.setYe(BigDecimal.ZERO);
}
}
break;
case 17:
it.Value());
break;
default:
break;
}
}
it.setZtId(ztId);
it.setYear(year);
Date date = new Date();
it.setUpdatedAt(date);
it.setCreatedAt(date);
}
}
}
// 以上数据若存在⼀条报错的数据,则全部导⼊失败!
if (error.size() > 0 || hasErr) {
zwmxzRepository.deleteAllByZtIdAndYearAndMonth(ztId, year, month);
} else {
for (var it : newZwmxz) {
zwmxzRepository.save(it);
}
}
return error;
}
private String judgeYear(String year1, int year2, String position) {
String pattern = "^[0-9]+$";
if (year1 == null) {
return "Excel的" + position + "列的表头年份不可为空!";
} else {
String trim = im();
if (trim.length() >= 4) {
String substring = trim.substring(0, 4);
logger.info("-----year1:{}", substring);
if (Pattern.matches(pattern, substring)) {
if (Integer.parseInt(substring) != year2) {
return "Excel的" + position + "列的表头年份与当前期间年份不⼀致!";
}
} else {
return "Excel的" + position + "列的表头年份不规范!";
}
} else {
return "Excel的" + position + "列的表头年份不规范!";
}
}
return null;
}
注意:
(上⾯的代码就不更改了,下⾯说⼀下特殊情况)
List<Map<Integer, Map<Integer, String>>> list⾥⾯,每次最好第⼀个Map<Integer, Map<Integer, String>>都是表头,然后在获取数据的时候,根据表头的map来遍历,根据表头的key去拿每⼀⾏数据的value,判空!因为有些excel⾏的数据是不跟表头⼀⼀对应的,⽐如说列数据少了或是多了,⽐如说表头map={0='序号',1='编号',2='姓名',3='性别',4='年龄',5='收⼊'},⽽数据map可能是{0='1',1='xxx01',2='⼩武',3='男'},也可能是{0='1',1='xxx01',2='⼩武',3='男',4='',5=''},还可能是多出的数据{0='1',1='xxx01',2='⼩武',3='男',4='',5='',6='**asd'},主要看excel是怎么操作的,⽐如删除列数据⽤delete键删除的是第⼀种,注意这⽅⾯的特殊性。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论