浏览代码

excel导入

24282 1 年之前
父节点
当前提交
d76645c99c

+ 35 - 0
sd-framework/src/main/java/com/sd/framework/util/excel/listener/DataListener.java

@@ -0,0 +1,35 @@
+package com.sd.framework.util.excel.listener;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Excel监听器
+ *
+ * @author Chill
+ */
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public class DataListener<T> extends AnalysisEventListener<T> {
+
+    /**
+     * 缓存的数据列表
+     */
+    private final List<T> dataList = new ArrayList<>();
+
+    @Override
+    public void invoke(T data, AnalysisContext analysisContext) {
+        dataList.add(data);
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+
+    }
+
+}

+ 56 - 0
sd-framework/src/main/java/com/sd/framework/util/excel/listener/ImportListener.java

@@ -0,0 +1,56 @@
+package com.sd.framework.util.excel.listener;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import com.sd.framework.util.excel.support.ExcelImporter;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Excel监听器
+ *
+ * @author Chill
+ */
+@Data
+@RequiredArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class ImportListener<T> extends AnalysisEventListener<T> {
+
+    /**
+     * 数据导入类
+     */
+    private final ExcelImporter<T> importer;
+    /**
+     * 默认每隔3000条存储数据库
+     */
+    private int batchCount = 3000;
+    /**
+     * 缓存的数据列表
+     */
+    private List<T> list = new ArrayList<>();
+
+    @Override
+    public void invoke(T data, AnalysisContext analysisContext) {
+        list.add(data);
+        // 达到BATCH_COUNT,则调用importer方法入库,防止数据几万条数据在内存,容易OOM
+        if (list.size() >= batchCount) {
+            // 调用importer方法
+            importer.save(list);
+            // 存储完成清理list
+            list.clear();
+        }
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+        // 调用importer方法
+        importer.save(list);
+        // 存储完成清理list
+        list.clear();
+    }
+
+}

+ 14 - 0
sd-framework/src/main/java/com/sd/framework/util/excel/support/ExcelException.java

@@ -0,0 +1,14 @@
+package com.sd.framework.util.excel.support;
+
+/**
+ * Excel异常处理类
+ *
+ * @author Chill
+ */
+public class ExcelException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public ExcelException(String message) {
+        super(message);
+    }
+}

+ 19 - 0
sd-framework/src/main/java/com/sd/framework/util/excel/support/ExcelImporter.java

@@ -0,0 +1,19 @@
+package com.sd.framework.util.excel.support;
+
+import java.util.List;
+
+/**
+ * Excel统一导入接口
+ *
+ * @author Chill
+ */
+public interface ExcelImporter<T> {
+
+    /**
+     * 导入数据逻辑
+     *
+     * @param data 数据集合
+     */
+    void save(List<T> data);
+
+}

+ 179 - 0
sd-framework/src/main/java/com/sd/framework/util/excel/util/ExcelUtil.java

@@ -0,0 +1,179 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *  Neither the name of the dreamlu.net developer nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ *  Author: Chill 庄骞 (smallchill@163.com)
+ */
+package com.sd.framework.util.excel.util;
+
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.read.builder.ExcelReaderBuilder;
+import com.alibaba.excel.read.listener.ReadListener;
+import com.alibaba.excel.util.DateUtils;
+import com.alibaba.excel.write.handler.WriteHandler;
+import com.sd.framework.util.excel.listener.DataListener;
+import com.sd.framework.util.excel.listener.ImportListener;
+import com.sd.framework.util.excel.support.ExcelException;
+import com.sd.framework.util.excel.support.ExcelImporter;
+import lombok.SneakyThrows;
+import org.apache.commons.codec.Charsets;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Excel工具类
+ *
+ * @author Chill
+ * @apiNote { https://www.yuque.com/easyexcel/doc/easyexcel }
+ */
+public class ExcelUtil {
+
+    /**
+     * 读取excel的所有sheet数据
+     *
+     * @param excel excel文件
+     * @return List<Object>
+     */
+    public static <T> List<T> read(MultipartFile excel, Class<T> clazz) {
+        DataListener<T> dataListener = new DataListener<>();
+        ExcelReaderBuilder builder = getReaderBuilder(excel, dataListener, clazz);
+        builder.doReadAll();
+        return dataListener.getDataList();
+    }
+
+    /**
+     * 读取excel的指定sheet数据
+     *
+     * @param excel   excel文件
+     * @param sheetNo sheet序号(从0开始)
+     * @return List<Object>
+     */
+    public static <T> List<T> read(MultipartFile excel, int sheetNo, Class<T> clazz) {
+        return read(excel, sheetNo, 1, clazz);
+    }
+
+    /**
+     * 读取excel的指定sheet数据
+     *
+     * @param excel         excel文件
+     * @param sheetNo       sheet序号(从0开始)
+     * @param headRowNumber 表头行数
+     * @return List<Object>
+     */
+    public static <T> List<T> read(MultipartFile excel, int sheetNo, int headRowNumber, Class<T> clazz) {
+        DataListener<T> dataListener = new DataListener<>();
+        ExcelReaderBuilder builder = getReaderBuilder(excel, dataListener, clazz);
+        builder.sheet(sheetNo).headRowNumber(headRowNumber).doRead();
+        return dataListener.getDataList();
+    }
+
+    /**
+     * 读取并导入数据
+     *
+     * @param excel    excel文件
+     * @param importer 导入逻辑类
+     * @param <T>      泛型
+     */
+    public static <T> void save(MultipartFile excel, ExcelImporter<T> importer, Class<T> clazz) {
+        ImportListener<T> importListener = new ImportListener<>(importer);
+        ExcelReaderBuilder builder = getReaderBuilder(excel, importListener, clazz);
+        builder.doReadAll();
+    }
+
+    /**
+     * 导出excel
+     *
+     * @param response 响应类
+     * @param dataList 数据列表
+     * @param clazz    class类
+     * @param <T>      泛型
+     */
+    @SneakyThrows
+    public static <T> void export(HttpServletResponse response, List<T> dataList, Class<T> clazz) {
+        export(response, DateUtils.format(new Date(), DateUtils.DATE_FORMAT_14), "导出数据", dataList, clazz);
+    }
+
+    /**
+     * 导出excel
+     *
+     * @param response  响应类
+     * @param fileName  文件名
+     * @param sheetName sheet名
+     * @param dataList  数据列表
+     * @param clazz     class类
+     * @param <T>       泛型
+     */
+    @SneakyThrows
+    public static <T> void export(HttpServletResponse response, String fileName, String sheetName, List<T> dataList, Class<T> clazz) {
+        response.setContentType("application/vnd.ms-excel");
+        response.setCharacterEncoding(Charsets.UTF_8.name());
+        fileName = URLEncoder.encode(fileName, Charsets.UTF_8.name());
+        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
+        EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(dataList);
+    }
+
+    /**
+     * 导出excel
+     *
+     * @param response     响应类
+     * @param fileName     文件名
+     * @param sheetName    sheet名
+     * @param dataList     数据列表
+     * @param clazz        class类
+     * @param writeHandler 自定义处理器
+     * @param <T>          泛型
+     */
+    @SneakyThrows
+    public static <T> void export(HttpServletResponse response, String fileName, String sheetName, List<T> dataList, WriteHandler writeHandler, Class<T> clazz) {
+        response.setContentType("application/vnd.ms-excel");
+        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
+        fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
+        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
+        EasyExcel.write(response.getOutputStream(), clazz).registerWriteHandler(writeHandler).sheet(sheetName).doWrite(dataList);
+    }
+
+    /**
+     * 获取构建类
+     *
+     * @param excel        excel文件
+     * @param readListener excel监听类
+     * @return ExcelReaderBuilder
+     */
+    public static <T> ExcelReaderBuilder getReaderBuilder(MultipartFile excel, ReadListener<T> readListener, Class<T> clazz) {
+        String filename = excel.getOriginalFilename();
+        if (ObjectUtils.isEmpty(filename)) {
+            throw new ExcelException("请上传文件!");
+        }
+        if ((!StringUtils.endsWithIgnoreCase(filename, ".xls") && !StringUtils.endsWithIgnoreCase(filename, ".xlsx"))) {
+            throw new ExcelException("请上传正确的excel文件!");
+        }
+        InputStream inputStream;
+        try {
+            inputStream = new BufferedInputStream(excel.getInputStream());
+            return EasyExcel.read(inputStream, clazz, readListener);
+        } catch (IOException e) {
+            throw new ExcelException("读取文件失败!");
+        }
+    }
+
+}

+ 52 - 0
sd-starter/src/test/java/B1_SyncSkuTest.java

@@ -0,0 +1,52 @@
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.read.builder.ExcelReaderBuilder;
+import com.sd.SdApplication;
+import com.sd.framework.util.excel.listener.DataListener;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.SneakyThrows;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.FileInputStream;
+import java.util.List;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = SdApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
+public class B1_SyncSkuTest {
+
+
+    @SneakyThrows
+    @Transactional
+    @Test
+    public void test() {
+
+        DataListener<ExcelData> listener = new DataListener<>();
+
+        FileInputStream fileInputStream = new FileInputStream("E:\\峰燕-胜德体育-品号汇总模板-2 (1).xlsx");
+
+        ExcelReaderBuilder read = EasyExcel.read(fileInputStream, ExcelData.class, listener);
+        read.sheet(0).doRead();
+        List<ExcelData> dataList = listener.getDataList();
+
+        System.out.println();
+
+    }
+
+    @Getter
+    @Setter
+    public static final class ExcelData {
+
+        @ExcelProperty("SKU")
+        private String code;
+
+        @ExcelProperty("图稿类型")
+        private String machinedPanelStr;
+
+    }
+
+}