当前位置:网站首页>超好用的【通用Excel导入功能】
超好用的【通用Excel导入功能】
2022-04-23 03:15:00 【小道仙97】
文章目录
之前写过一个简单的Excel导入功能,大家可以先看这个: https://www.bilibili.com/video/BV1kf4y1i761?p=5
最近接到一个需求,做一个Excel的批量导入功能,具体的步骤如下:
一、需求
1-1、下载模板(excel)
| 姓名(2-4个字符) | 年纪(1-150) | 性别(男/女) |
|---|
1-2、数据填充并导入
| 姓名(2-4个字符) | 年纪(1-150) | 性别(男/女) |
|---|---|---|
| 张三丰 | 20 | 男 |
| 小道仙97 | 24 | 男 |
| 慕容晓晓 | 18 | 女性 |
1-3、导入结果展示

1-4、数据校验规则
- 姓名不能为空且只能是2-4个字符
- 年纪不能为空且只能是1-150
- 性别不能为空且只能是男/女
- 导入的数据不能有两个同名,如果存在则都导入失败
- 数据库如果有同名的人也不可以导入
二、方案思路
使用上面的Excel导入功能,把Excel模板数据解析成对应的 List<Map<String,Object>> 数据。
使用数据把对应的数据格式化成对应的实体,再依次循环按照条件去校验对应的数据。
其实除了导入数据校验规则之外,其它都是通用的,比如返回字段、解析excel并封装成bean,对异常数据进行处理等。
三、代码使用
3-1、新建一个VO,比如你导入的字段是 name、age、gender 那么你的实体应该如下:
注:省略了 get 、set 、和空参构造方法
public class TestImportExcelVo {
/** * 表头 */
public final static String[] HEADER = {
"name","age","gender"};
/** * 姓名 */
private String name;
/** * 年纪 */
private String age;
/** * 性别 */
private String gender;
}
可以看到唯一不同的就是多了一个常量HEADER,它的规则就是导入模板字段顺序
3-2、新增一个ImportExcel接口的实现类,实现里面的 check 方法(这个接口下面讲解)
@Service
public class TestImportExcelImpl implements ImportExcel<TestImportExcelVo> {
@Override
public String[] check(ImportItem importItem, List<TestImportExcelVo> successResult, List<ImportItem> errorResult) {
return new String[]{
"1",""};
}
}
3-3、调用
@RestController
public class ImportExcelController {
@Autowired
public TestImportExcelImpl testImportExcelImpl;
@PostMapping("/importExcel")
public Object importExcel(MultipartFile file) {
return testImportExcelImpl.importCheck(file, TestImportExcelVo.HEADER, TestImportExcelVo.class);
}
}
四、代码思路讲解
其实就是看接口 ImportExcel 里面的两个方法。
4-1、准备
这里使用了两个bean如下(去掉了get/set)
/** * 导出错误结果集实体bean * * 因为错误结果集需要多一个原因字段 * * @author 小道仙 * @date 2021年8月4日 */
public class ImportItem<T> {
private String errorReason;
public T t;
}
/** * 导入Excel返回结果实体 * * @author 小道仙 * @date 2021-08-04 */
public class ImportResultVo<T> {
/** * 总行数 */
private Integer totalRows;
/** * 错误行数 */
private Integer errorRows;
/** * 成功行数 */
private Integer successRows;
/** * 失败结果集 */
private List<T> errorResults;
/** * 成功结果集 */
private List<T> successResults;
public ImportResultVo() {
}
public ImportResultVo(Integer totalRows,Integer errorRows,Integer successRows,List<T> errorResults,List<T> successResults) {
this.totalRows = totalRows;
this.errorRows = errorRows;
this.successRows = successRows;
this.errorResults =errorResults;
this.successResults = successResults;
}
}
4-2、importCheck方法
这是一个默认方法完成一些通用的功能,如:excel解析、实体bean封装等
default ImportResultVo importCheck(MultipartFile file, String[] header,Class clazz){
// 从excel里面解析出来数据
List<Map<String, Object>> maps;
try {
maps = ExcelUtils.importExcel(file, header);
}catch (Exception e){
logger.error("解析失败,数据模板不对",e);
throw new RuntimeException("解析失败,数据模板不对");
}
if (CollectionUtils.isEmpty(maps)){
return new ImportResultVo(0,0,0,null,null);
}
// 对数据进行逐步的验证
int totalRows = 0;
int successRows = 0;
int errorRows = 0;
List<T> successResult = new ArrayList<>(50);
List<ImportItem> errorResult = new ArrayList<>(50);
for (Map map : maps) {
ImportItem<T> importItem = new ImportItem();
totalRows ++;
try {
Object tmpT = JsonUtils.objectToPojo(map, clazz);
importItem.setT((T)tmpT);
}catch (Exception e) {
errorRows ++;
logger.error("bean转换失败", e);
continue;
}
String[] check = check(importItem, successResult, errorResult);
if ("1".equals(check[0])) {
successRows ++;
successResult.add(importItem.getT());
}else if ("2".equals(check[0])) {
errorRows ++;
importItem.setErrorReason(check[1]);
errorResult.add(importItem);
}else if ("3".equals(check[0])){
successRows --;
errorRows ++;
importItem.setErrorReason(check[1]);
errorResult.add(importItem);
}
}
return new ImportResultVo(totalRows,errorRows,successRows,errorResult,successResult);
}
4-3、check 方法
这是一个接口方法,需要自己去实现具体的校验规则
/** * * @param t 当前需要校验的实体bean * @param successResult 已校验的正确结果集 * @param errorResult 已校验错误的结果集 * @return 第一个参数是校验结果,第二个是失败的原因 * 1 成功 * 2 正常失败(比如字段为空,字段格式不对,和数据库冲突等) * 3 异常失败(和之前已经成功的数据冲突,比如唯一性字段已经存在了) * 注:【异常失败】的时候,你需要在check方法里面去删除掉之前成功的数据,并把之前的数据插入到 errorResult 里面 */
String[] check(ImportItem t, List<T> successResult, List<ImportItem> errorResult);
4-4、其它
这里的excel导出工具类之前已经说过了,这里就简单的复制一下吧。
/** * Excel 导入 * @param file 文件 * @param keys 数据顺序 */
public static List<Map<String, Object>> importExcel(MultipartFile file, String[] keys) throws Exception{
Workbook wb = null;
String fileName = file.getOriginalFilename();
if (fileName.endsWith("xls")) {
POIFSFileSystem pois = new POIFSFileSystem(file.getInputStream());
wb = new HSSFWorkbook(pois);
} else if (fileName.endsWith("xlsx")) {
wb = new XSSFWorkbook(file.getInputStream());
}
Sheet sheet = wb.getSheetAt(0);
int rowCount = sheet.getPhysicalNumberOfRows();
if (sheet.getRow( 1).getPhysicalNumberOfCells() != keys.length){
throw new RuntimeException("导入的Excel和模板的列不匹配");
}
List<Map<String,Object>> result = new ArrayList<>();
for (int i = 0; i < rowCount - 1; i++) {
Row row = sheet.getRow(i + 1);
Map<String,Object> tmp = new HashMap<>();
for (int j = 0;j < keys.length; j++){
Cell cell = row.getCell(j);
if(cell == null) {
tmp.put(keys[j], null);
}else {
// 把类型转行Spring
cell.setCellType(CellType.STRING);
tmp.put(keys[j], cell.getStringCellValue());
}
}
result.add(tmp);
}
return result;
}
视频看讲解地址:https://www.bilibili.com/video/BV1kf4y1i761
关注微信公众号回复:xdxFrameSimple 获取源码。

版权声明
本文为[小道仙97]所创,转载请带上原文链接,感谢
https://blog.csdn.net/Tomwildboar/article/details/119487612
边栏推荐
- Top ten project management software similar to JIRA
- The most understandable life cycle of dependency injection
- “如何实现集中管理、灵活高效的CI/CD”在线研讨会精彩内容分享
- General testing technology [1] classification of testing
- General test technology [II] test method
- C syntax sugar empty merge operator [?] And null merge assignment operator [? =]
- 先中二叉建树
- Ningde's position in the times is not guaranteed?
- Why is bi so important to enterprises?
- js 中,为一个里面带有input 的label 绑定事件后在父元素绑定单机事件,事件执行两次,求解
猜你喜欢

. net tip: talk about the problem that the scoped service cannot be obtained in the middleware structure

Due to 3 ²+ four ²= five ², Therefore, we call '3,4,5' as the number of Pythagorean shares, and find the array of all Pythagorean shares within n (including n).

2022g2 boiler stoker examination question bank and online simulation examination

編碼電機PID調試(速度環|比特置環|跟隨)

Huawei mobile ADB devices connection device is empty

【VS Code】解决jupyter文件在vs code中显示异常的问题

荐读 | 分享交易员的书单,向名家请教交易之道,交易精彩无比

Data mining series (3)_ Data mining plug-in for Excel_ Estimation analysis

How to achieve centralized management, flexible and efficient CI / CD online seminar highlights sharing

ASP. Net 6 middleware series - execution sequence
随机推荐
Mysql database
C syntax pattern matching [switch expression]
Using stack to solve the problem of "mini parser"
This new feature of C 11, I would like to call it the strongest!
MySQL port is occupied when building xampp
C language to achieve address book - (static version)
“如何实现集中管理、灵活高效的CI/CD”在线研讨会精彩内容分享
Web Course Design - his system
Swap the left and right of each node in a binary tree
Aspnetcore configuration multi environment log4net configuration file
Mysql database design specification
How to achieve centralized management, flexible and efficient CI / CD online seminar highlights sharing
《C语言程序设计》(谭浩强第五版) 第7章 用函数实现模块化程序设计 习题解析与答案
OLED multi-level menu record
2022G2电站锅炉司炉考试题库及在线模拟考试
使用split来解决“最常见的单词”问题
Course design of Database Principle -- material distribution management system
What kind of experience is it to prepare for a month to participate in ACM?
数据挖掘系列(3)_Excel的数据挖掘插件_估计分析
ASP. Net 6 middleware series - execution sequence