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

excel导入,使用注解对字段进行逻辑判断(字段是否为空,数据结构等)条件

1.创建一个工具类

package com.yj.utils;

import cn.hutool.core.io.FileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.yj.annotation.ImportFieldCheckAnnotation;
import com.yj.exception.ServiceException;
import com.yj.service.SysDictDetailService;
import com.yj.utils.spring.SpringUtils;
import com.yj.vo.SysDictDetailVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;

import static com.yj.constant.ErrorCodeConstants.*;
import static com.yj.utils.ServiceExceptionUtil.exception;

/**
 * @Author: hjc
 * @Date: 2024/5/25 18:59
 * @Description:
 **/
@Slf4j
@Service
public class ExcelUtils<T> {
    /**
     * 校验表头是否正确
     *
     * @param wb
     * @param columnName
     * @return
     * @throws Exception
     */
    public static void verificationExcelHeadLine(int rowNum, Workbook wb, String[] columnName) {
        try {
            Sheet sheet = wb.getSheetAt(0);
            Row row = sheet.getRow(rowNum);
            if (row != null && row.getLastCellNum() == columnName.length) {
                int lastCellNum = row.getLastCellNum();
                for (int idx = 0; idx <lastCellNum ; idx++) {
                    String value = row.getCell(idx).getStringCellValue();
                    if (StringUtils.isBlank(value) || !value.trim().startsWith(columnName[idx])) {
                        throw  exception(FILE_HEAD_ERROR);
                    }
                }
            }else{
                throw  exception(FILE_HEAD_ERROR);
            }
        } catch (ServiceException e){
            throw e;
        } catch (Exception ex) {
            log.info("表头验证失败=={}",ex);
            throw  exception(FILE_HEAD_ERROR);
        }
    }

    /**
     * 保存失败文件
     * @param errorInfoList
     * @param aclass
     * @return
     */
    public  String saveFailResultFile(List<T> errorInfoList,Class aclass) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        String failResultFileName = "failresult" + UUID.randomUUID().toString().replace("-", "") + ".xlsx";
        ExcelWriter excelWriter = EasyExcel.write(os, aclass)
                .build();
        WriteSheet sheet = EasyExcel.writerSheet(0, "Sheet1").build();
        excelWriter.write(errorInfoList, sheet);
        excelWriter.finish();
        InputStream is = new ByteArrayInputStream(os.toByteArray());
        String tempPath=System.getProperty("user.dir")+File.separator+"temp"+ File.separator;
        File dir = new File(tempPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        FileUtil.writeFromStream(is, tempPath + failResultFileName);
        return failResultFileName;
    }
    /**
     * 文件类型校验
     * @param file
     * @return
     */
    @NotNull
    public static String fileTypeCheck(MultipartFile file) {
        if (file == null) {
            log.error("上传文件为空");
            throw exception(FILE_NOT_NULL);
        }
        //获取原始文件名
        String fileName = file.getOriginalFilename();
        //文件后缀名校验
        if (!(fileName.endsWith("xls") || fileName.endsWith("xlsx"))) {
            log.error("文件上传格式错误");
            exception(FILE_TYPE_ERROR);
        }
        return fileName;
    }
    /**
     * 设置响应结果
     *
     * @param response    响应结果对象
     * @param rawFileName 文件名
     * @throws UnsupportedEncodingException 不支持编码异常
     */
    public static  void setExcelResponseProp(HttpServletResponse response, String rawFileName) throws UnsupportedEncodingException {
        //设置内容类型
        response.setContentType("application/vnd.vnd.ms-excel");
        //设置编码格式
        response.setCharacterEncoding("utf-8");
        //设置导出文件名称(避免乱码)
        String fileName = URLEncoder.encode(rawFileName.concat(".xlsx"), "UTF-8");
        // 设置响应头
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
    }
    /**
     * 字段校验
     *
     * @param fields
     * @param t
     */
    public   List<String>  importCheck(Field[] fields, T t, List<String> errorTips) {
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                Object obj = field.get(t);
                ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
                ImportFieldCheckAnnotation classFieldTypeAnnotation = field.getAnnotation(ImportFieldCheckAnnotation.class);
                String[] chineseName = annotation.value();
                if (ObjectUtils.isNull(obj) &&!ObjectUtils.isNull(classFieldTypeAnnotation)&&!classFieldTypeAnnotation.permitNull()) {
                    errorTips.add(chineseName[0] + "不能为空");
                    continue;
                }
                if(!ObjectUtils.isNull(obj)&&!ObjectUtils.isNull(classFieldTypeAnnotation)&&classFieldTypeAnnotation.isNumber()){
                    if (!this.isNumeric((String) obj)) {
                        errorTips.add(chineseName[0]+"字段为整型");
                    }else{
                        String str= (String) obj;

                        int min = classFieldTypeAnnotation.min();
                        int max = classFieldTypeAnnotation.max();

                        if(str.length()>8||Integer.valueOf(str)>max||Integer.valueOf(str)<min){
                            errorTips.add(chineseName[0] + "数据范围"+min+"~"+max);
                        }
                    }
                }
                if(!ObjectUtils.isNull(obj)&&!ObjectUtils.isNull(classFieldTypeAnnotation)&&classFieldTypeAnnotation.isDouble()){
                    if (!this.doubleCheck((String) obj)) {
                        if(StringUtils.isNotBlank(classFieldTypeAnnotation.msg())){
                            errorTips.add(classFieldTypeAnnotation.msg());
                        }else {
                            errorTips.add(chineseName[0] + "字段格式错误");
                        }
                    }else{
                        String str= (String) obj;

                        int min = classFieldTypeAnnotation.min();
                        int max = classFieldTypeAnnotation.max();
                        if(str.length()>12||Double.valueOf(str)>max||Double.valueOf(str)<min){
                            errorTips.add(chineseName[0] + "数据范围"+min+"~"+max);
                        }
                    }
                }
                if(!ObjectUtils.isNull(classFieldTypeAnnotation)&&!ObjectUtils.isNull(obj)){
                    boolean isTtr = obj instanceof String;
                    if(isTtr) {
                        String str = (String) obj;
                        if (classFieldTypeAnnotation.length()!=0&&str.length() > classFieldTypeAnnotation.length()) {
                            if(StringUtils.isNotBlank(classFieldTypeAnnotation.msg())){
                                errorTips.add(classFieldTypeAnnotation.msg());
                            }else {
                                errorTips.add(chineseName[0] + "字符长度过长");
                            }
                        }
                    }
                }
                //校验下拉选的值
                if(!ObjectUtils.isNull(classFieldTypeAnnotation)&&!ObjectUtils.isNull(obj)&&StringUtils.isNotBlank(classFieldTypeAnnotation.dictCode())){
                    SysDictDetailService sysDictDetailService = SpringUtils.getBean(SysDictDetailService.class);
                    SysDictDetailVO sysDictDetailVO = new SysDictDetailVO();
                    sysDictDetailVO.setDictCode(classFieldTypeAnnotation.dictCode());
                    sysDictDetailVO.setDictLabel((String) obj);
                    List<SysDictDetailVO> list = sysDictDetailService.list(sysDictDetailVO);
                    if(CollectionUtils.isEmpty(list)){
                        errorTips.add(chineseName[0] + "不匹配");
                    }
                }
                //校验正则
                if(!ObjectUtils.isNull(classFieldTypeAnnotation)&&!ObjectUtils.isNull(obj)&&StringUtils.isNotBlank(classFieldTypeAnnotation.regex())){
                    boolean matches = this.regexCheck((String) obj,classFieldTypeAnnotation.regex());
                    if(!matches){
                        if(StringUtils.isNotBlank(classFieldTypeAnnotation.msg())){
                            errorTips.add(classFieldTypeAnnotation.msg());
                        }else {
                            errorTips.add(chineseName[0] + "字段格式错误");
                        }
                    }
                }
            }
        } catch (IllegalAccessException e) {
            log.info("导入失败",e);
            errorTips.add("导入失败");
        }
        return errorTips;
    }
    public boolean isNumeric(String str) {
        return str.matches("\\d+");
    }

    /**
     * 正则表达式校验
     * @param ipAddress
     * @param regex
     * @return
     */
    public  boolean regexCheck(String ipAddress,String regex) {
        if ((ipAddress != null) && (!ipAddress.isEmpty())) {
            return Pattern.matches(regex, ipAddress);
        }
        return false;
    }
    public boolean doubleCheck(String str) {
        return str.matches("\\d{1,6}(\\.?)(\\d{0,4})");
    }



}

2.自定义一个注解

package com.yj.annotation;

import java.lang.annotation.*;

/**
 * 字段注解
 *   @author hjc
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ImportFieldCheckAnnotation {

    /**
     * 数字类型
     */
    boolean isNumber() default false;
    boolean isDouble() default false;

    /**
     * 字符长度
     * @return
     */
    int length() default 0;

    /**
     * 最大值
     * @return
     */
    int max() default 0;

    /**
     * 最小值
     * @return
     */
    int min() default 0;

    /**
     * 字段是否可以为空
     * @return
     */
    boolean permitNull() default false;
    /**
     * 字典值校验
     * @return
     */
    String dictCode() default "";

    /**
     * 正则表达式校验
     */
    String regex() default "";

    /**
     * 提示
     */
    String msg() default "";

}

3.创建实体类,使用注解

@Data
public class Cloud {


    @ApiModelProperty(value = "区域")
    @ExcelProperty(value = "区域", index = 0)
    @ImportFieldCheckAnnotation(length = 100,dictCode = "region")
    private String regionName;
    @ApiModelProperty(value = "业务")
    @ExcelProperty(value = "业务", index = 1)
    @ImportFieldCheckAnnotation(length = 100)
    private String institution;
    @ExcelProperty(value = "名称", index = 2)
    @ApiModelProperty(value = "名称")
    @ImportFieldCheckAnnotation(length = 100)
    private String Name;
    @ExcelProperty(value = "实例", index = 3)
    @ApiModelProperty(value = "实例")
    @ImportFieldCheckAnnotation(permitNull = true,length = 100)
    private String instance
    @ExcelProperty(value = "天数", index = 4)
    @ApiModelProperty(value = "天数")
    @ImportFieldCheckAnnotation(permitNull = true,isNumber = true,max = 10000)
    private String testDays;


}

4.Controller

 public ResultVO<ExcelReturnVO> upload(MultipartFile file) {
        ExcelReturnVO excelReturnVO = new ExcelReturnVO();
        String fileName = ExcelUtils.fileTypeCheck(file);
        Workbook wb = null;
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
        try {
            InputStream fin = file.getInputStream();
            if ("xls".equals(suffix)) {
                wb = new HSSFWorkbook(fin);
            } else if ("xlsx".equals(suffix)) {
                wb = new XSSFWorkbook(fin);
            }
            String[] columnName =
                    {"区域", "业务", "名称", "时间", "实例", "天数"};
//判断导入表头是否正确
            ExcelUtils.verificationExcelHeadLine(1, wb, columnName);
//读取数据转换成实体类列表
//EasyExcel.read(file.getInputStream(),Cloud.class)
//从第二行开始读
//.headRowNumber(2)
//第一个表
//.sheet(0).doRead();
            

2.效验操作

private void checkData(Cloud inputEntity, List<CloudError> errorInfoList) {
   
        List<String> errorTips = new ArrayList<>();
       
     释放时间格式错误 格式:YYYY/MM/DD ");
        }
        //数据校验
//获取Cloud类 的所有属性
        Field[] declaredFields = inputEntity.getClass().getDeclaredFields();
        ExcelUtils<Cloud > excelUtils=new ExcelUtils();
//使用自定义的方法对所有属性进行解析效验
        excelUtils.importCheck(declaredFields, inputEntity, errorTips);


http://www.kler.cn/a/454582.html

相关文章:

  • QT-------认识QT
  • 自学记录HarmonyOS Next的HMS AI API 13:语音合成与语音识别
  • 【089】基于51单片机环境监测系统【Proteus仿真+Keil程序+报告+原理图】
  • 使用sam进行零样本、零学习的分割实践
  • 费舍尔信息矩阵全面讲述
  • 记录一次前端绘画海报的过程及遇到的几个问题
  • MATLAB中的sum函数介绍(包括与find函数的结合使用)
  • 【每日学点鸿蒙知识】屏幕高度、证书签名、深色模式对上架影响、Taskpool上下文、List触底加载更多
  • std::is_trivial
  • 龙智出席2024零跑智能汽车技术论坛,分享功能安全、需求管理、版本管理、代码扫描等DevSecOps落地实践
  • 聚类的主要算法和介绍
  • 25上半年软考初级信息处理技术员易混淆知识点
  • RabbitMQ中的批量Confirm模式:提升消息可靠性与性能
  • 王佩丰24节Excel学习笔记——第二十讲:图表基础
  • Elasticsearch 集群
  • WordPress TutorLMS插件 SQL注入漏洞复现(CVE-2024-10400)(附脚本)
  • 秒鲨后端之MyBatis【3】自定义映射resultMap、动态SQL、MyBatis的缓存、MyBatis的逆向工程、分页插件(30000字)
  • D类音频应用EMI管理
  • Day57 图论part07
  • JAVA开发初级入门之-如何快速将Java开发环境搭建,优雅草央千澈快速IDEA与JDK安装配置环境教程一文让你搞定-java开发必修课之一
  • OpenLinkSaas使用手册-简介
  • 【蓝桥杯】压缩字符串
  • Linux-----进程处理(文件IO资源使用)
  • 让 AMD GPU 在大语言模型推理中崭露头角:机遇与挑战
  • Unity如何判断Animator当前播放的动画已经结束
  • Go的Slice如何扩容