欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > easyExcel 导入时,校验每个单元格数据

easyExcel 导入时,校验每个单元格数据

2024/10/26 1:21:15 来源:https://blog.csdn.net/liuao107329/article/details/141567098  浏览:    关键词:easyExcel 导入时,校验每个单元格数据

目录

1、定义excel导入文件对应的数据接收类 

2、定义属性转换器

3、定义数据解析监听器

4、解析文件


1、定义excel导入文件对应的数据接收类 
package com.ruoyi.project.domain.dto;import com.alibaba.excel.annotation.ExcelProperty;
import com.ruoyi.project.impot.convert.HeadUserExistConverter;
import com.ruoyi.project.impot.convert.ProjectNameConverter;
import com.ruoyi.project.impot.convert.ProjectNoConverter;
import lombok.Data;import java.math.BigDecimal;/*** 项目管理对象 t_project* * @author chance* @date 2024-07-24*/
@Data
public class ImportProjectDto {private static final long serialVersionUID = 1L;/*** $column.columnComment*/private Long id;/*** 项目名称*/@ExcelProperty(value = "项目名称",converter = ProjectNameConverter.class)private String projectName;/*** 项目编号*/@ExcelProperty(value = "项目编号",converter = ProjectNoConverter.class)private String projectNo;/*** 期初概算*/@ExcelProperty("期初概算")private BigDecimal initialBudgetEstimate;/*** 总概算*/@ExcelProperty("总概算")private BigDecimal generalEstimate;/*** 总概算*/@ExcelProperty("调整概算")private BigDecimal changeAmount;@ExcelProperty(value = "负责人",converter = HeadUserExistConverter.class)private String headUser;/*** 负责人id*/private Integer headUserId;
}

解释: 类中对“项目名称”、“项目编号”、 “负责人” 指定了转换器

ProjectNameConverter ,ProjectNoConverter ,HeadUserExistConverter

2、定义属性转换器

ProjectNameConverter.java 中的逻辑:

1、获取数据库中的项目名称集合(此集合是为了校验文件中项目名称是否和数据库中的项目名称重复)

2、定义excel中项目名称集合(每处理解析一行记录,则将项目名称加入集合,此集合是为了校验excel文件中项目名称是否重复)

如果1,2中的集合包含当前处理的数据记录,则抛出异常,这里异常会在后续自定义的listener中处理

package com.ruoyi.project.impot.convert;import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ReadConverterContext;
import com.alibaba.excel.converters.WriteConverterContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.project.mapper.ProjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;import java.util.LinkedList;
import java.util.List;@Slf4j
public class ProjectNameConverter implements Converter<String> {private List<String> dbProjectNameList = new LinkedList<>();private List<String> fileProjectNameList = new LinkedList<>();@Overridepublic Class<?> supportJavaTypeKey() {return String.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}/*** 这里读的时候会调用** @param context* @return*/@Overridepublic String convertToJavaData(ReadConverterContext<?> context)   {log.info("dbProjectNameList.size{}",dbProjectNameList.size());log.info("fileProjectNameList.size{}",fileProjectNameList.size());if(CollectionUtils.isEmpty(dbProjectNameList)){dbProjectNameList = SpringUtils.getBean(ProjectMapper.class).selectProjectNameList();}ReadCellData  readCellData= context.getReadCellData() ;String value = StringUtils.trim(readCellData.getStringValue());if (StringUtils.isNotEmpty(value)) {if(dbProjectNameList.contains(value)){throw new ExcelDataConvertException(readCellData.getRowIndex(),readCellData.getColumnIndex(),readCellData, context.getContentProperty(), "【"+ value + "】项目名称系统已存在");}if(fileProjectNameList.contains(value)){throw new ExcelDataConvertException(readCellData.getRowIndex(),readCellData.getColumnIndex(),readCellData, context.getContentProperty(),"文件中" + "【"+ value + "】项目名称编码重复");}fileProjectNameList.add(value);return value;}return null;}/*** 这里是写的时候会调用 不用管** @return*/@Overridepublic WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) {return new WriteCellData<>(context.getValue());}}
3、定义数据解析监听器
ProjectImportListener

这里的onException 方法会监听到转换器中抛出的异常,这里可以收集每条错误数据的原因,

其他方法不做赘述了。

package com.ruoyi.project.impot.listener;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.project.domain.Project;
import com.ruoyi.project.domain.dto.ImportProjectDto;
import com.ruoyi.project.mapper.ProjectMapper;
import com.ruoyi.project.mapper.ProjectHeadUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** 读取转换异常** @author Jiaju Zhuang*/
@Slf4j
public class ProjectImportListener implements ReadListener<ImportProjectDto> {/*** 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收*/private static final int BATCH_COUNT = 100;private List<ImportProjectDto> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);private List<String> errorMsg = new LinkedList<>();private List<SysUser> userList = Lists.newArrayList();/*** 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。** @param exception* @param context* @throws Exception*/@Overridepublic void onException(Exception exception, AnalysisContext context) {log.error("解析失败,但是继续解析下一行:{}", exception.getMessage());// 如果是某一个单元格的转换异常 能获取到具体行号// 如果要获取头的信息 配合invokeHeadMap使用if (exception instanceof ExcelDataConvertException) {ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;log.error("第{}行,第{}列解析异常,数据为:{}", excelDataConvertException.getRowIndex(),excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData());errorMsg.add(String.format("第%s行,第%s列解析异常,数据为:%s,原因:%s", excelDataConvertException.getRowIndex()+1,excelDataConvertException.getColumnIndex()+1,excelDataConvertException.getCellData().getStringValue(),excelDataConvertException.getCause().getMessage()));}}/*** 这里会一行行的返回头** @param headMap* @param context*/@Overridepublic void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {log.info("解析到一条头数据:{}", JSON.toJSONString(headMap));}@Overridepublic void invoke(ImportProjectDto data, AnalysisContext context) {log.info("解析到一条数据:{}", JSON.toJSONString(data));cachedDataList.add(data);
//        if (cachedDataList.size() >= BATCH_COUNT) {
//            saveData();
//            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
//        }}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {saveData();log.info("所有数据解析完成!");}/*** 加上存储数据库*/private void saveData() {if (errorMsg.size() > 0 ){log.info("有%s条数据校验不通过,请检查", errorMsg.size());return;}log.info("{}条数据,开始存储数据库!", cachedDataList.size());ProjectMapper mapper =SpringUtils.getBean(ProjectMapper.class);ProjectHeadUserMapper userMapper =SpringUtils.getBean(ProjectHeadUserMapper.class);userList = userMapper.getUserList();Map<String,Long>  userNameIdMap = userList.stream().collect(Collectors.toMap(SysUser::getUserName, SysUser::getUserId));for (ImportProjectDto dto: cachedDataList) {Project project = new Project();BeanUtils.copyProperties(dto, project);project.setCreateBy(SecurityUtils.getUsername());project.setCreateTime(new Date());project.setGeneralEstimate(project.getInitialBudgetEstimate());project.setHeadUserId(userNameIdMap.get(dto.getHeadUser()).intValue());mapper.insertProject(project);}log.info("存储数据库成功!");}public List<String> getErrorMsg() {return errorMsg;}
}
4、解析文件
/*** @param file* @description: 导入项目* @return: com.ruoyi.common.core.domain.AjaxResult* @author 30864* @date: 2024/7/30 20:24*/@PostMapping("/importExcel")@PreAuthorize("@ss.hasPermi('project:project:import')")public AjaxResult importExcel(MultipartFile file) throws IOException {// 这里 需要指定读用哪个class去读,然后读取第一个sheetProjectImportListener listener = new ProjectImportListener();EasyExcel.read(file.getInputStream(), ImportProjectDto.class, listener).sheet().headRowNumber(1).doRead();List<String> errorMsg = listener.getErrorMsg();if (CollectionUtils.isNotEmpty(errorMsg)) {return AjaxResult.error(JSON.toJSONString(errorMsg), errorMsg);}return AjaxResult.success();}

总结:

此解析方法可以校验excel 中的每个单元格,且可以在listener 中获取到一行数据时,校验同行数据各属性间是否匹配,收集到错误数据,可以定位到行列号,具体实现可以自定义。

参考官网:读Excel | Easy Excel 官网 (alibaba.com)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com