excel转List 搞懂java反射机制(一) (两种解析方式)

excel转List 搞懂java反射机制(一) (两种解析方式)

概述

业务开发当中难免遇到excel导入功能,通过本文学习,构建属于自己的导入工具

一.创建注解

import java.lang.annotation.*;

/**
 * 文件导入  配合ExcelImportUtils
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ImportColumn {
    /**
     * 字段在excel中列位置
     */
    int index();

    /**
     * 是否必填
     */
    boolean require() default false;

    /**
     * 字段名称
     * @return
     */
    String name();
}

2.创建工具类

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 导入excel 文件转List工具类  配合ImportColumn注解
 */
@Component
@Slf4j
public class ExcelImportUtils {
    /**
     *
     * @param list 需要返回的list
     * @param cls  转换对象Class
     * @param file  excel文件
     * @param titles  标题头
     * @return  结果
     */
    public <T> List<T> convertExcelToList (List<T> list, Class cls, MultipartFile file,String titles){
        XSSFWorkbook workbook = null;
        try {
            workbook = new XSSFWorkbook(file.getInputStream());
            if (Objects.isNull(workbook)) {
                throw new MyRuntimeException("文件获取失败");
            }
        } catch (IOException e) {
            log.error("file转换workbook发生io异常:{}",e.getMessage());
        }
        return convertExcelToList ( list,  cls,  workbook, titles);
    }

    /**
     * 一个文件需要转多个文件 建议调取这个方法,减少读取文件的时间
     * @param list 需要返回的list
     * @param cls  转换对象Class
     * @param workbook  excel文件
     * @param titles  标题头
     * @return  结果
     */
    public <T> List<T> convertExcelToList (List<T> list, Class cls, XSSFWorkbook workbook,String titles){
        try {
            //遍历sheet
            XSSFSheet sheet = workbook.getSheetAt(0);//获取当前sheet对象
            if (sheet.getPhysicalNumberOfRows() > 1) {//如果行数据不为空

                for (int j = 0; j < sheet.getPhysicalNumberOfRows(); j++) {//遍历行信息
                    XSSFRow row = sheet.getRow(j);
                    if (j != 0) {
                        //去掉整行的数据都是空的  直接返回结果
                        if (StringUtils.isEmpty(row.getCell(0).getStringCellValue().trim())) {
                            return list;
                        }
                    }
                    //构建对象
                    list.add((T) buildEntity( cls, row));
                    if (j == 0) {//获取第一行标题,判断模板是否正确
                        boolean isRigtTemplate = checkTitle(row, titles);
                        if (!isRigtTemplate) {
                            throw new MyRuntimeException("模板不正确,请下载模板完善后上传");
                        }
                    }
                }
            }

        }catch (Exception e){
            log.error("convertExcelToList发生io异常:{}",e.getMessage());
            throw new MyRuntimeException(e.getMessage());
        }
        return list;
    }

    /**
     * 构建参数
     * @param cls
     * @param row
     * @return
     */
    public  Object buildEntity(Class cls,XSSFRow row){
        Object obj = null;
        try {
            Constructor<?> constructor = cls.getDeclaredConstructor();
            //忽略修饰访问所有字段与方法
            constructor.setAccessible(true);
            //创建实例
            obj = constructor.newInstance();
            //通过反射获取方法成员变量名称  getDeclaredFields 忽略修饰符
            Field[] filds = cls.getDeclaredFields();
            //遍历字段赋值
            for(int index = 0;index < filds.length; index++){
                Field field = filds[index];
                //获取ImportColumn 注解  如果没有绕过
                ImportColumn[] importColumn = field.getAnnotationsByType(ImportColumn.class);
                if(Objects.nonNull(importColumn) && importColumn.length > 0){
                    //获取当前格子值
                    Object value = getValue( field.getGenericType().getTypeName(),
                            row.getCell(importColumn[0].index()));
                    //校验是否必填
                    if(importColumn[0].require() && Objects.isNull(value)){
                        throw new MyRuntimeException(String.format("必填字段%s为null",importColumn[0].name()));
                    }
                    //为字段赋值
                    field.set(obj, value);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 根据类型名称获取值
     * @param typeName 字段类型名称
     * @param cell  单元格
     * @return
     */
    private Object getValue(String typeName, XSSFCell cell){
        Object value = null;
        switch (typeName){
            case "java.lang.Integer"://处理int类型字段
                value = getInteger(cell);
                break;
            case "java.util.String"://处理字符串
                value = cell.getStringCellValue();
                break;
            case "java.util.Date"://处理日期
                value = getDateValue(cell);
                break;
            case "java.math.BigDecimal"://处理 BigDecimal
                value = getBigDecimal(cell);
                break;
            case "java.lang.Double"://处理 Double
                value = getDouble(cell);
                break;
            case "java.lang.Long"://处理 Long
                value = getLong(cell);
                break;
            case "boolean"://处理 boolean
                value = getBoolean(cell);
                break;
            case "int"://处理 int
                value = Optional.ofNullable(getInteger(cell)).orElse(0);
                break;
            case "double"://处理 double
                value = Optional.ofNullable(getDouble(cell)).orElse(0.0);
                break;
            case "long"://处理 long
                value = Optional.ofNullable(getLong(cell)).orElse(0L);
                break;
        }
        return value;
    }

    /**
     * 校验表头
     * @param firstRow
     * @param titles
     * @return
     */
    private boolean checkTitle(XSSFRow firstRow, String titles) {
        boolean flag = true;
        String[] titleArr = titles.split(",");
        for (int i = 0; i < titleArr.length; i++) {
            if (!titleArr[i].equals(firstRow.getCell(i).getStringCellValue())) {
                flag = false;
                break;
            }
        }
        return flag;
    }

    private Date getDateValue(XSSFCell cell){
        try {
            return cell.getDateCellValue();
        }catch (Exception e){
            return null;
        }
    }
    private BigDecimal getBigDecimal(XSSFCell cell){
        try {
            String cellvalue = cell.getStringCellValue();
            return StringUtils.isEmpty(cellvalue) ? null :BigDecimal.valueOf(Double.parseDouble(cellvalue));
        }catch (Exception e){
            return null;
        }
    }

    private Integer getInteger(XSSFCell cell){
        try {
            return (int)cell.getNumericCellValue();
        }catch (Exception e){
            return null;
        }
    }
    private Double getDouble(XSSFCell cell){
        try {
            return cell.getNumericCellValue();
        }catch (Exception e){
            return null;
        }
    }
    private Long getLong(XSSFCell cell){
        try {
            Double cellValue = cell.getNumericCellValue();
            return cellValue.longValue();
        }catch (Exception e){
            return null;
        }
    }

    private boolean getBoolean(XSSFCell cell){
        try {
            return cell.getBooleanCellValue();
        }catch (Exception e){
            return false;
        }
    }


}

3.调用方式

List<MyOrder> list = new ArrayList<>();
list = excelImportUtils.convertExcelToList(list,MyOrder.class,file,"");

4.总结

	本文介绍的是固定模板上传,下文介绍通过标题导入    有问题欢迎指正
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值