java实现excel的导入导出(带参数校验:非空校验、数据格式校验)

您所在的位置:网站首页 模板导入数据出现错误怎么回事 java实现excel的导入导出(带参数校验:非空校验、数据格式校验)

java实现excel的导入导出(带参数校验:非空校验、数据格式校验)

#java实现excel的导入导出(带参数校验:非空校验、数据格式校验)| 来源: 网络整理| 查看: 265

一、简单说明

本次封装引入阿里开源框架EasyExcel,EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。 github地址:GitHub - alibaba/easyexcel: 快速、简洁、解决大文件内存溢出的java处理Excel工具 。64M内存20秒读取75M(46W行25列)的Excel(3.0.2+版本)

com.alibaba easyexcel 3.1.1

结构图如下:

1.1结构说明:

1.annotation:注解

@ExcelPropertyCheck(自己写的注解用作导入数据校验)

@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface ExcelPropertyCheck { boolean required() default true; ----是否为空,默认不为空。 boolean checkFormat() default false; ----是否进行格式检验,默认不进行。 int type() default -1; ----格式检验类型,int 已经支持的类型有 0->ip、1->端口、2->时间日期格式 int length() default -1; ----长度校验, int 字符串的长度,-1不进行校验 }

@ExcelProperty(框架自带的,用于标记excel传输类和一些通用的导入导出配置)

@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ExcelProperty { String[] value() default {""}; ----导出时对应字段的表头名称 int index() default -1;----排列顺序,最好不要配默认按字段顺序。 int order() default Integer.MAX_VALUE; ----同上 Class> converter() default AutoConverter.class; ----转换器 String format() default ""; ----格式划输出 }

特别提醒:!!!

@ExcelPropertyCheck该注解作用类上时只支持required,其余属性无效。字段上的注解配置会覆盖类上的配置。  

2.constant:常量类,格式校验的类型定义,如电话号码、日期、IP地址等。

/** * excel导入字段类型常量 */ public class ExcelPropertyType { //时间日期格式校验 public static final int DATE_TIME = 0; }

3.converter:转换器

读写均可使用,实现Converter重写方法即可。

如将excel 中的日期转为 LocalDateTime 或者将LocalDateTime 转为excel表中的日期

或者将数据库的枚举值0,1,2,3导入到excel文件变成对应的中文汉字

/** * String and string converter * */ public class CustomStringStringConverter implements Converter { /** * 这里读的时候会调用 * * @param context * @return */ @Override public String convertToJavaData(ReadConverterContext context) { return "自定义:" + context.getReadCellData().getStringValue(); } /** * 这里是写的时候会调用 不用管 * * @return */ @Override public WriteCellData convertToExcelData(WriteConverterContext context) { return new WriteCellData(context.getValue()); } }

上述代码中泛型为String 表示此字段经过处理后最后返回的类型为String 

4.listener:监听器

ReadListener(EasyExcel提供的)

ReadListener读监听器,框架提供。提供读取excel不同时期的监听方法。 分别为: onException()-------------->“读取发生异常时监听”、 invokeHead()----------------->“读取表头信息监听”、 invoke()--------------------->“读取每行数据监听”、 doAfterAllAnalysed()----------->“所有数据读取完毕监听”。

BaseListener我们自己封装的读监听器,在里面结合注解配置完成数据校验。

BaseListener我们自己封装的读监听器,在里面结合注解配置完成数据校验。 对外提供的字段: private final List mapData = new ArrayList(); private final List data = new ArrayList(); private final Map errorMessageMap = new HashMap(); //非空校验map private final Map nullAbleFieldMap = new HashMap(); //格式校验map private final Map checkFormatFieldMap = new HashMap(); //长度校验map private final Map checkLengthFieldMap = new HashMap(); //枚举值校验map private final Map checkEnumFieldMap = new HashMap(); 字段描述备注       mapDataexcel读取完毕的Map数据Mapdataexcel读取完毕的对于实体ListListerrorMessageMap错误信息mapMap;key为错误行号,value为描述。 nullAbleFieldMap 非空校验map Map checkFormatFieldMap 格式校验map:电话号码,ip,日期 Map checkLengthFieldMap 长度校验map Map checkEnumFieldMap 枚举值检验map Map

  

结合注解做参数校验或者格式校验的实现思路(反射加泛型)

 步骤一:在表头读取的监听方法里利用反射判断检验注解ExcelPropertyCheck加在了那些ExcelDTO哪些属性上,并且ExcelPropertyCheck注解的具体属性是什么将这些存入分门别类的map里面。

步骤二:在读取每行数据的时候,结合步骤一的map,判断数据是否需要校验,并且从map中取出校验的类型是什么,再去完成校验,如果校验失败则将错误信息放入errorMessageMap,当前读取的excel这一行数据全部校验通过则数据放入data 里面

完整的BaseListener代码如下:

import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.metadata.data.ReadCellData; import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; import com.baomidou.mybatisplus.core.toolkit.BeanUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; import java.lang.reflect.Field; import java.util.*; public class BaseListener implements ReadListener { private final Logger logger = LoggerFactory.getLogger(BaseListener.class); private Class headClazz; //读取数据map形式 private final List mapData = new ArrayList(); //读取数据实体类泛型形式 private final List data = new ArrayList(); //非空校验map private final Map nullAbleFieldMap = new HashMap(); //格式校验map private final Map checkFormatFieldMap = new HashMap(); //长度校验map private final Map checkLengthFieldMap = new HashMap(); //枚举值校验map private final Map checkEnumFieldMap = new HashMap(); //数据校验错误信息map key:错误的行号 value:错误信息描述 private final Map errorMessageMap = new HashMap(); public List getMapData() { return mapData; } public List getData() { return data; } public Map getErrorMessageMap() { return errorMessageMap; } public BaseListener() { } /** * @param headClazz excel model 类对象 */ public BaseListener(Class headClazz) { this.headClazz = headClazz; } /** * 读取发生异常时的方法 * * @param exception * @param context * @throws Exception */ @Override public void onException(Exception exception, AnalysisContext context) throws Exception { logger.debug("发生了异常"); } /** * 读取头信息 * * @param headMap * @param context */ @Override public void invokeHead(Map clazz) throws IOException { try { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); // 这里需要设置不关闭流 EasyExcel.write(response.getOutputStream(), clazz).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).autoCloseStream(Boolean.FALSE).sheet("sheet1") .doWrite(data); } catch (Exception e) { // 重置response response.reset(); response.setContentType("application/json"); response.setCharacterEncoding("utf-8"); Map map = MapUtils.newHashMap(); map.put("status", "failure"); map.put("message", "下载文件失败" + e.getMessage()); response.getWriter().println(JSON.toJSONString(map)); } } /** * 读取excel 文件 * * @param file 文件 * @param cl 类对象 * @param listener 参数校验监听器 */ public static Map importExcel(MultipartFile file, Class cl, BaseListener listener) { try { EasyExcel.read(file.getInputStream(), cl, listener).sheet().doRead(); return listener.getErrorMessageMap(); } catch (IOException e) { return null; } } /** * excleDto 转为对应model实体类 * * @param data * @param t * @param * @return */ public static List dto2model(Collection data, T t) { return data.stream().map(e -> { T t1 = null; try { t1 = (T) t.getClass().newInstance(); } catch (Exception exception) { exception.printStackTrace(); } BeanUtils.copyProperties(e, t1); return t1; }).collect(Collectors.toList()); } }

四、总结:

经过简单的封装完成了一个带参数校验的简单使用案例,直接引入项目后在controller直接调用EasyExcelUtils的 "importExcel"方法和"downloadExcel"就能实现excel的导入导出,是不是很方便呢。

有问题留言大家一起交流学习。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3