当前位置: 首页 > news >正文

笔记:使用EasyExcel导入csv文件出现编码问题,导致导入数据全为null的解决方法

笔记:使用EasyExcel导入csv文件出现编码问题,导致导入数据全为null的解决方法

通常情况下,我们使用excel导入,但是部分情况下或者领导要求,我们需要使用csv导入文件,但是csv文件模板下载之后会变成系统当前编码,而不是固定为UTF-8,如果用excel的方式打开,写入数据之后,会提示你另存为xlsx,这也说明了csv和xlsx本质是完全不同的文件。
在这里插入图片描述
如果这种时候你使用EasyExcel默认的编码读取csv文件,你会发现读取的数据全部都是null,因为通常情况下,windows系统如果不特意设置编码格式,默认都为GBK,所以会导致导入数据无法读取的情况,当然excel并不会出现这种问题,所以如果不是特殊需求,导入还是推荐使用Excel文件。

这里分享一个导入方法,通过人为干预导入数据的方式,去判断是否读取成功,这里只用中国常用的UTF8GBK作为读取的编码,通常情况下是够用的,如果有需要,可以在charsets集合自行增加其他编码。

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.hexin.fms.common.excel.*;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.web.multipart.MultipartFile;import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;public class ExcelUtil {/*** 多编码转换导入数据* 目前使用常用编码utf8和gbk解析文件* 如使用csv导入出现编码问题的时候* @param file 导入文件* @param clazz 类对象* @param excelTypeEnum 导入文件类型* @return 文件数据*/public static <T> ExcelResult<T> importExcelByAnyCharset(MultipartFile file, Class<T> clazz, ExcelTypeEnum excelTypeEnum) throws Exception {DefaultExcelListener<T> listener = new DefaultExcelListener<>(false);return importExcelByAnyCharset(file, clazz, excelTypeEnum, listener);}/*** 多编码转换导入数据* 目前使用常用编码utf8和gbk解析文件* 如使用csv导入出现编码问题的时候* @param file 导入文件* @param clazz 类对象* @param excelTypeEnum 导入文件类型* @param listener 监听器* @return 文件数据*/public static <T> ExcelResult<T> importExcelByAnyCharset(MultipartFile file, Class<T> clazz, ExcelTypeEnum excelTypeEnum,ExcelListener<T> listener) throws Exception {//需要校验的全部编码List<Charset> charsets = new ArrayList<>();charsets.add(StandardCharsets.UTF_8);charsets.add(Charset.forName("GBK"));//开始解析文件ExcelResult<T> result = new DefaultExcelResult<>();for(Charset charset : charsets){result = importExcelByCharset(file.getInputStream(), clazz, excelTypeEnum, listener, charset);//校验实体数据是否全部为nullif(result != null && result.getList() != null){List<T> resultList = result.getList();int size = resultList.size();int nullNums = 0;for(T t : resultList){if(t == null){nullNums++;continue;}Class<?> tClass = t.getClass();Field[] fields = tClass.getDeclaredFields();int len = fields.length;int fieldNullNums = 0;for(Field field : fields){field.setAccessible(true);if(field.get(t) == null){fieldNullNums++;}}if(len == fieldNullNums){nullNums++;}else{break;}}if(nullNums != size){break;}}}return result;}/*** 获取导入数据* 只走utf8,不校验获取数据是否为null* 如果不能保证导入文件为utf8,请使用importExcelByAnyCharset方法* @param is 导入文件的文件流* @param clazz 类对象* @param excelTypeEnum 导入文件类型* @return 文件数据*/public static <T> ExcelResult<T> importExcelByUTF8(InputStream is, Class<T> clazz, ExcelTypeEnum excelTypeEnum) {DefaultExcelListener<T> listener = new DefaultExcelListener<>(false);return importExcelByCharset(is, clazz, excelTypeEnum, listener, StandardCharsets.UTF_8);}/*** 获取导入数据* @param is 导入文件的文件流* @param clazz 类对象* @param excelTypeEnum 导入文件类型* @param listener 监听器* @param charset 用于导入文件数据转换的编码* @return 文件数据*/public static <T> ExcelResult<T> importExcelByCharset(InputStream is, Class<T> clazz, ExcelTypeEnum excelTypeEnum,ExcelListener<T> listener, Charset charset) {EasyExcel.read(is, clazz, listener).excelType(excelTypeEnum).charset(charset).sheet().doRead();return listener.getExcelResult();}
}

下面是一个默认的监听器,其中isValidate可以去掉,个人不建议在监听器里面作校验,这样导入数据之间的唯一性或者其他一些关系可能无法校验或者校验起来很麻烦。

个人建议,还是先获取到表格数据,然后再进行校验。

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.hexin.fms.common.utils.JsonUtils;
import com.hexin.fms.common.utils.StreamUtils;
import com.hexin.fms.common.utils.ValidatorUtils;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Map;
import java.util.Set;@Slf4j
@NoArgsConstructor
public class DefaultExcelListener<T> extends AnalysisEventListener<T> implements ExcelListener<T> {/*** 是否Validator检验,默认为是*/private Boolean isValidate = Boolean.TRUE;/*** excel 表头数据*/private Map<Integer, String> headMap;/*** 导入回执*/private ExcelResult<T> excelResult;public DefaultExcelListener(boolean isValidate) {this.excelResult = new DefaultExcelResult<>();this.isValidate = isValidate;}/*** 处理异常** @param exception ExcelDataConvertException* @param context   Excel 上下文*/@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {String errMsg = null;if (exception instanceof ExcelDataConvertException) {// 如果是某一个单元格的转换异常 能获取到具体行号ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;Integer rowIndex = excelDataConvertException.getRowIndex();Integer columnIndex = excelDataConvertException.getColumnIndex();errMsg = StrUtil.format("第{}行-第{}列-表头{}: 解析异常<br/>",rowIndex + 1, columnIndex + 1, headMap.get(columnIndex));if (log.isDebugEnabled()) {log.error(errMsg);}}if (exception instanceof ConstraintViolationException) {ConstraintViolationException constraintViolationException = (ConstraintViolationException) exception;Set<ConstraintViolation<?>> constraintViolations = constraintViolationException.getConstraintViolations();String constraintViolationsMsg = StreamUtils.join(constraintViolations, ConstraintViolation::getMessage, ", ");errMsg = StrUtil.format("第{}行数据校验异常: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg);if (log.isDebugEnabled()) {log.error(errMsg);}}excelResult.getErrorList().add(errMsg);throw new ExcelAnalysisException(errMsg);}@Overridepublic void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {this.headMap = headMap;log.debug("解析到一条表头数据: {}", JsonUtils.toJsonString(headMap));}@Overridepublic void invoke(T data, AnalysisContext context) {if (isValidate) {ValidatorUtils.validate(data);}excelResult.getList().add(data);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {log.debug("所有数据解析完成!");}@Overridepublic ExcelResult<T> getExcelResult() {return excelResult;}}

用法如下:

    @PostMapping(value = "/importExcel", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)public R<Void> importExcel(@RequestPart("file") MultipartFile file) throws Exception {ExcelResult<ImportVo> result = ExcelUtil.importExcelByAnyCharset(file, ImportVo.class, ExcelTypeEnum.CSV);List<ImportVo> excelList = result.getList();return importService.importExcel(excelList);}

importService.importExcel(excelList)就是你校验和保存更新删除数据的方法。

http://www.lqws.cn/news/539425.html

相关文章:

  • Apache Kafka 面试应答指南
  • 那些不应该的优化
  • html配置rem实现页面自适应
  • Linux:从后往前查看日志命令
  • 编译原理---文法和语法分析
  • 基于全局构建版本和ES模块构建版本的vue3 快速上手
  • LLM驱动开发:正在重塑软件工程的下一场革命
  • Maven生命周期与阶段扩展深度解析
  • GO 语言学习 之 语句块
  • vscode把less文件生成css文件配置,设置生成自定义文件名称和路径
  • FlutterPackages中的animations库升级适配Flutter3.27
  • Ubuntu18.04/Mysql 5.7 建立主备模式Mysql集群
  • 华为云Flexus+DeepSeek征文|Dify平台开发搭建口腔牙科24小时在线问诊系统(AI知识库系统)
  • C++学习笔记
  • 16.3 Docker生产级部署:网络与存储高效配置实战,保障99.95%可用性
  • 387. 字符串中的第一个唯一字符
  • uni-app uts 插件 android 端 科大讯飞离线语音合成最新版
  • 修改表中满足特定条件的字段值
  • elementUI轮播图组件el-carousel适配移动端大小(图片加载好后根据大小适配)
  • 抽样分布与参数估计细节
  • 如何在安卓设备上发送长视频:6 种可行的解决方案
  • GitHub Actions与AWS OIDC实现安全的ECR/ECS自动化部署
  • 从输入到路径:AI赋能的地图语义解析与可视化探索之旅
  • 远程办公与协作新趋势:从远程桌面、VDI到边缘计算,打造高效、安全的混合办公环境
  • Java底层原理:深入理解JVM内存模型与线程安全
  • 开发数字化绿色低碳园区系统:分阶段实施指南
  • 数据获取
  • word中如何保存高清图片,并保存为高质量的pdf文件(图像不失真)
  • 【Linux】基础开发工具(2)
  • 架构轻巧的kokoro 文本转语音模型