首页 > 其他分享 >Excel动态表头导入

Excel动态表头导入

时间:2022-12-12 20:12:27浏览次数:43  
标签:int list Excel 表头 month 导入 context year

引入需要的依赖

<!--Excel导入 使用注解方式 可选-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>3.3.0</version>
        </dependency>
        <!-- 动态导入需要的依赖 少了报错 java.lang.NoClassDefFoundError: org/apache/poi/poifs/filesystem/FileMagic-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>

 

Controller层

public HashMap<String, Object> upload(@RequestParam(value = "file") MultipartFile file,
                                          @RequestParam(value = "ztId") int ztId,
                                          @RequestParam(value = "year") int year,
                                          @RequestParam(value = "month") int month) throws IOException {

        //初始化监听器
        ZwmxzListener zwmxzListener = new ZwmxzListener(zwmxzService, ztId, year, month);
        //解析数据
        EasyExcel.read(file.getInputStream(), zwmxzListener).sheet(0).doReadSync();

        HashMap<String, Object> hashMap = new HashMap<>();
        //获取校验错误信息,并返回给前端
        List<String> errMessage = zwmxzListener.getErrMessage();
        if (errMessage.isEmpty()) {
            hashMap.put("success", true);
        } else {
            hashMap.put("success", false);
            hashMap.put("errMessage", errMessage);
        }
        return hashMap;
    }

Listener监听器

//继承AnalysisEventListener<Map<Integer, String>>
@Data
@Slf4j
public class ZwmxzListener extends AnalysisEventListener<Map<Integer, String>> {
    //定义每多少条数据进行数据库保存
    private static final int BATCH_COUNT = 128;
    private int ztId;
    private int year;
    private int month;
    private ZwmxzService zwmxzService;
    //建一个errMessage集合保存校验有问题的结果
    private List<String> errMessage;
    //用list集合保存解析到的结果
    private List<Map<Integer, Map<Integer, String>>> list;


    //重构,把传来的值赋给对应的属性
    public ZwmxzListener(ZwmxzService zwmxzService, int ztId, int year, int month) {
        this.ztId = ztId;
        this.year = year;
        this.month = month;
        this.zwmxzService = zwmxzService;
        list = new ArrayList<>();
        errMessage = new ArrayList<>();
    }

    /**
     * 重写invokeHeadMap方法,获去表头,如果有需要获取第一行表头就重写这个方法,不需要则不需要重写
     *
     * @param headMap Excel每行解析的数据为Map<Integer, String>类型,Integer是Excel的列索引,String为Excel的单元格值
     * @param context context能获取一些东西,比如context.readRowHolder().getRowIndex()为Excel的行索引,表头的行索引为0,0之后的都解析成数据
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        logger.info("解析到一条头数据:{}, currentRowHolder: {}", headMap.toString(), context.readRowHolder().getRowIndex());
        Map<Integer, Map<Integer, String>> map = new HashMap<>();
        map.put(context.readRowHolder().getRowIndex(), headMap);
        list.add(map);
    }

    /**
     * 重写invoke方法获得除Excel第一行表头之后的数据,
     * 如果Excel第二行也是表头,那么也会解析到这里,如果不需要就通过判断context.readRowHolder().getRowIndex()跳过
     *
     * @param data    除了第一行表头外,数据都会解析到这个方法
     * @param context 和上面解释一样
     */
    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        logger.info("解析到一条数据:{}, currentRowIndex: {}----", data.toString(), context.readRowHolder().getRowIndex());
        Map<Integer, Map<Integer, String>> map = new HashMap<>();
        map.put(context.readRowHolder().getRowIndex(), data);
        list.add(map);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (list.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            list.clear();
        }
    }

    /**
     * 解析到最后会进入这个方法,需要重写这个doAfterAllAnalysed方法,然后里面调用自己定义好保存方法
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        logger.info("所有数据解析完成!");
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
        logger.info("{}条数据,开始存储数据库!", list.size());
        //用errMessage集合保存zwmxzService.save()返回校验错误信息,根据自己需要来写就行了
        errMessage.addAll(zwmxzService.save(list, ztId, year, month, errMessage.size() > 0));
    }

}

 

Service层

@Transactional(rollbackFor = Exception.class)
    @Override
    public List<String> save(List<Map<Integer, Map<Integer, String>>> list, int ztId, int year, int month, boolean hasErr) {
        logger.info("--start---导入判断----");
        List<String> error = new ArrayList<>();
        List<Zwmxz> newZwmxz = new ArrayList<>();
        String pattern = "^[-]?\\d+(\\.\\d+)?$";
        //遍历传过来的数据集合
        for (var item : list) {
            //每一行
            for (var row : item.entrySet()) {
                //获取行的索引
                Integer rowIndex = row.getKey();
                //索引为0表示为表头
                if (rowIndex == 0) {
                    String leftYear = row.getValue().get(1);
                    String rightYear = row.getValue().get(2);
                    logger.info("---leftYear={}--------rightYear={}----------", leftYear, rightYear);
                    String left = judgeYear(leftYear, year, "B");
                    if (left != null) {
                        error.add(left);
                    }
                    String right = judgeYear(rightYear, year, "C");
                    if (right != null) {
                        error.add(right);
                    }
                } else {
                    rowIndex++;
                    logger.info("---rowIndex={}--------", rowIndex);
                    Zwmxz it = new Zwmxz();
                    //遍历每一行的每一列数据,并校验
                    for (var col : row.getValue().entrySet()) {
                        switch (col.getKey()) {
                            case 1:
                                if (col.getValue() == null) {
                                    error.add("序号为【" + rowIndex + "】的数据的B列【月份】不可为空!");
                                } else {
                                    if (Pattern.matches(pattern, col.getValue().trim())) {
                                        if (Integer.parseInt(col.getValue().trim()) == month) {
                                            it.setMonth(month);
                                        } else {
                                            error.add("序号为【" + rowIndex + "】的数据的B列【月份】与当前期间的月份不一致!");
                                        }
                                    } else {
                                        error.add("序号为【" + rowIndex + "】的数据的B列【月份】需要是正常的阿拉伯数字月份!");
                                    }
                                }
                                break
                           ......................................................case 16:
                                if (col.getValue() == null) {
                                    it.setYe(BigDecimal.ZERO);
                                } else {
                                    if (Pattern.matches(pattern, col.getValue().trim())) {
                                        it.setYe(new BigDecimal(col.getValue()));
                                    } else {
                                        it.setYe(BigDecimal.ZERO);
                                    }
                                }
                                break;
                            case 17:
                                it.setSdocId(col.getValue());
                                break;
                            default:
                                break;
                        }
                    }
                    it.setZtId(ztId);
                    it.setYear(year);
                    Date date = new Date();
                    it.setUpdatedAt(date);
                    it.setCreatedAt(date);
                    newZwmxz.add(it);
                }
            }
        }
        // 以上数据 若存在一条报错的数据,则全部导入失败!
        if (error.size() > 0 || hasErr) {
            zwmxzRepository.deleteAllByZtIdAndYearAndMonth(ztId, year, month);
        } else {
            for (var it : newZwmxz) {
                zwmxzRepository.save(it);
            }
        }
        return error;
    }


 private String judgeYear(String year1, int year2, String position) {
        String pattern = "^[0-9]+$";
        if (year1 == null) {
            return "Excel的" + position + "列的表头年份不可为空!";
        } else {
            String trim = year1.trim();
            if (trim.length() >= 4) {
                String substring = trim.substring(0, 4);
                logger.info("-----year1:{}", substring);
                if (Pattern.matches(pattern, substring)) {
                    if (Integer.parseInt(substring) != year2) {
                        return "Excel的" + position + "列的表头年份与当前期间年份不一致!";
                    }
                } else {
                    return "Excel的" + position + "列的表头年份不规范!";
                }
            } else {
                return "Excel的" + position + "列的表头年份不规范!";
            }
        }
        return null;
    }

 

//可以先存储表头,然后再根据动态表头获取表格中数据

 

标签:int,list,Excel,表头,month,导入,context,year
From: https://www.cnblogs.com/cgy-home/p/16976979.html

相关文章