EasyExcel的导入导出使用

EasyExcel的导入导出使用

/**
 * @ClassName: CellWidthStyleHandler
 * @Description: 设置表头的调整宽策略
 * @Author: 
 * @Date: 
 */
public class CellWidthStyleHandler extends AbstractColumnWidthStyleStrategy {

    // 可以根据这里的最大宽度,按自己需要进行调整,搭配单元格样式实现类中的,自动换行,效果更好
    private static final int MAX_COLUMN_WIDTH = 50;
    private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap(8);

    /**
     * 是否设置固定宽度
     */
    private boolean fixed;

    /**
     * 固定宽度
     */
    private int fixedWidth;

    public CellWidthStyleHandler() {
    }

    public CellWidthStyleHandler(boolean fixed, int fixedWidth) {
        this.fixed = fixed;
        this.fixedWidth = (fixedWidth == 0 ? 15 : fixedWidth);
    }

    @Override
    protected void setColumnWidth(CellWriteHandlerContext context) {
        boolean needSetWidth = context.getHead() || !CollUtil.isEmpty(context.getCellDataList());
        if (!needSetWidth) {
            return;
        }
        WriteSheetHolder writeSheetHolder = context.getWriteSheetHolder();
        // 设置固定宽度
        if (fixed) {
            Cell cell = context.getCell();
            writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), fixedWidth * 256);
            return;
        }
        // 设置自动调整宽度
        Map<Integer, Integer> maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo());
        if (maxColumnWidthMap == null) {
            maxColumnWidthMap = new HashMap(16);
            CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
        }
        Cell cell = context.getCell();
        int columnWidth = this.dataLength(context.getCellDataList(), cell, context.getHead());
        if (columnWidth >= 0) {
            if (columnWidth > MAX_COLUMN_WIDTH) {
                columnWidth = MAX_COLUMN_WIDTH;
            }
            Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
            if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
                maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
                writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256);
            }
        }
    }

    private int dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {
        if (isHead) {
            return cell.getStringCellValue().getBytes().length;
        } else {
            CellData cellData = cellDataList.get(0);
            CellDataTypeEnum type = cellData.getType();
            if (type == null) {
                return -1;
            } else {
                switch (type) {
                    case STRING:
                        return cellData.getStringValue().getBytes().length;
                    case BOOLEAN:
                        return cellData.getBooleanValue().toString().getBytes().length;
                    case NUMBER:
                        return cellData.getNumberValue().toString().getBytes().length;
                    default:
                        return -1;
                }
            }
        }
    }
}
/**
 * @ClassName: DefaultExcelHeadHandler
 * @Description: 默认自定义表头样式拦截器
 * @Author: 
 * @Date: 
 */
public class DefaultExcelHeadHandler extends HorizontalCellStyleStrategy {

    //设置头样式
    @Override
    protected void setHeadCellStyle(CellWriteHandlerContext context) {
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 11);
        headWriteFont.setColor(IndexedColors.BLACK.getIndex());
        headWriteCellStyle.setWriteFont(headWriteFont);
        if (stopProcessing(context)) {
            return;
        }
        WriteCellData<?> cellData = context.getFirstCellData();
        WriteCellStyle.merge(headWriteCellStyle, cellData.getOrCreateStyle());
    }
}
/**
 * @ClassName: EasyExcelUtil
 * @Description: excel导入导出工具类
 * @Author: 
 * @Date: 
 */
public class EasyExcelUtil {

    /**
     * 导入-读取一页sheet
     *
     * @param inputStream 文件流
     * @param clazz       数据对象
     * @param sheetName   要读取的sheet (不传,默认读取第一个sheet)
     * @throws Exception
     */
    public static <T> List<T> importExcel(InputStream inputStream, Class<T> clazz, String sheetName, ReadExcelListener readExcelListener) throws Exception {
        ExcelReaderBuilder builder = EasyExcelFactory.read(inputStream, clazz, readExcelListener);
        if (StringUtils.isBlank(sheetName)) {
            builder.sheet().doRead();
        } else {
            builder.sheet(sheetName).doRead();
        }
        return readExcelListener.getList();
    }

    /**
     * 导入-读取多个sheet
     *
     * @param inputStream  文件流
     * @param sheetNum     需要读取的sheet个数(默认0开始,如果传入2,则读取0、1)
     * @param sheetObjList 每个sheet里面需要封装的对象(如果index为2,则需要传入对应的2个对象)
     * @param <T>
     * @return
     */
    public static <T> List<List<T>> importExcels(InputStream inputStream, int sheetNum, List<T> sheetObjList, ReadExcelListener<T> readExcelListener) throws Exception {
        List<List<T>> resultList = new LinkedList<>();
        for (int index = 0; index < sheetNum; index++) {
            Class<T> tClass = (Class<T>) sheetObjList.get(index).getClass();
            EasyExcelFactory.read(inputStream, tClass, readExcelListener).sheet(index).doRead();
            List<T> list = readExcelListener.getList();
            resultList.add(list);
        }
        return resultList;
    }

    /**
     * 导出excel表格-列不确定情况;只导出模板【一个处理器】
     *
     * @param response
     * @param headList     表头列表
     * @param dataList     数据列表
     * @param fileName     文件名称
     * @param sheetName    sheet名称
     * @param writeHandler 处理器
     * @throws Exception
     */
    public static <T> void exportExcel(HttpServletResponse response, List<List<String>> headList, List<List<T>> dataList, String fileName, String sheetName, WriteHandler writeHandler) throws Exception {
        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 + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
        // 这里注意如果同一个sheet只要创建一次
        ExcelWriterSheetBuilder sheetBuilder = EasyExcel.writerSheet(sheetName).head(headList);
        if (null != writeHandler) {
            sheetBuilder.registerWriteHandler(writeHandler);
        }
        WriteSheet writeSheet = sheetBuilder.build();
        excelWriter.write(dataList, writeSheet);
        excelWriter.finish();
    }

    /**
     * 导出excel表格-列不确定情况;只导出模板【多个处理器】
     *
     * @param response
     * @param headList      表头列表
     * @param dataList      数据列表
     * @param fileName      文件名称
     * @param sheetName     sheet名称
     * @param writeHandlers 处理器集合
     * @throws Exception
     */
    public static <T> void exportExcel(HttpServletResponse response, List<List<String>> headList, List<List<T>> dataList, String fileName, String sheetName, List<WriteHandler> writeHandlers) throws Exception {
        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 + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
        // 这里注意如果同一个sheet只要创建一次
        ExcelWriterSheetBuilder sheetBuilder = EasyExcel.writerSheet(sheetName).head(headList);
        if (CollUtil.isNotEmpty(writeHandlers)) {
            for (WriteHandler writeHandler : writeHandlers) {
                sheetBuilder.registerWriteHandler(writeHandler);
            }
        }
        WriteSheet writeSheet = sheetBuilder.build();
        excelWriter.write(dataList, writeSheet);
        excelWriter.finish();
    }

    /**
     * 导出excel表格-不支持设置样式
     *
     * @param response
     * @param dataList  数据列表
     * @param clazz     数据对象
     * @param fileName  文件名称
     * @param sheetName sheet名称
     * @throws Exception
     */
    public static <T> void exportExcel(HttpServletResponse response, List<T> dataList, Class<T> clazz, String fileName, String sheetName) throws Exception {
        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 + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());
        EasyExcelFactory.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(dataList);
    }

    /**
     * 导出excel表格-支设置单元格样式
     *
     * @param response
     * @param dataList     数据列表
     * @param clazz        数据对象
     * @param fileName     文件名称
     * @param sheetName    sheet名称
     * @param writeHandler 处理器
     * @throws Exception
     */
    public static <T> void exportWriteHandlerExcel(HttpServletResponse response, List<T> dataList, Class<T> clazz, String fileName, String sheetName, WriteHandler writeHandler) throws Exception {
        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 + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), clazz).build();
        // 这里注意如果同一个sheet只要创建一次
        WriteSheet writeSheet = EasyExcel.writerSheet(sheetName)
                .registerWriteHandler(writeHandler).build();
        excelWriter.write(dataList, writeSheet);
        excelWriter.finish();
    }


    /**
     * 导出多个sheet
     *
     * @param response
     * @param dataList 多个sheet数据列表
     * @param clazzMap 对应每个sheet列表里面的数据对应的sheet名称
     * @param fileName 文件名
     * @param <T>
     * @throws Exception
     */
    public static <T> void exportExcels(HttpServletResponse response, List<List<?>> dataList, Map<Integer, String> clazzMap, String fileName) throws Exception {
        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 + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
        int sheetNum = dataList.size();
        for (int i = 0; i < sheetNum; i++) {
            List<?> objects = dataList.get(i);
            Class<?> aClass = objects.get(0).getClass();
            WriteSheet writeSheet0 = EasyExcel.writerSheet(i, clazzMap.get(i)).head(aClass).build();
            excelWriter.write(objects, writeSheet0);
        }
        excelWriter.finish();
    }

    /**
     * 根据模板将集合对象填充表格
     *
     * @param inputStream 模板文件输入流
     * @param response    模板文件输出流
     * @param list        填充对象集合
     * @param fileName    文件名称
     * @param sheetName   需要写入的sheet(不传:填充到第一个sheet)
     * @throws Exception
     */
    public static <T> void exportTemplateExcelList(InputStream inputStream, HttpServletResponse response, List<T> list, String fileName, String sheetName) throws Exception {
        // 全部填充:全部加载到内存中一次填充
        if (StringUtils.isBlank(sheetName)) {
            EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).sheet().doFill(list);
        } else {
            EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).sheet(sheetName).doFill(list);
        }
    }


    /**
     * 根据模板将集合对象填充表格-单个sheet
     *
     * @param inputStream 模板文件输入流
     * @param list        填充对象集合-元素对应模板中的.{}
     * @param object      填充对象-元素对应模板中的{}
     * @param fileName    文件名称
     * @throws Exception
     */
    public static <T> void exportTemplateSheet(InputStream inputStream, HttpServletResponse response, List<T> list, Object object, String fileName) throws Exception {
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        ExcelWriter excelWriter = EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).build();
        WriteSheet writeSheet0 = EasyExcelFactory.writerSheet(0).build();
        // 全部填充:全部加载到内存中一次填充
        excelWriter.fill(object, fillConfig, writeSheet0);
        excelWriter.fill(list, fillConfig, writeSheet0);
        // 可分多次填充,使用文件缓存(省内存)
        // excelWriter.fill(list1, writeSheet);
        // excelWriter.fill(list2, writeSheet);
        excelWriter.finish();
    }

    /**
     * 根据模板将集合对象填充表格-多个sheet
     *
     * @param inputStream 模板文件输入
     * @param response    模板文件输出流
     * @param list1       填充对象集合-元素对应模板中的.{}
     * @param list2
     * @param object1     填充对象-元素对应模板中的{}
     * @param object2
     * @param fileName    文件名称
     * @throws Exception
     */
    public static <T> void exportTemplateSheets(InputStream inputStream, HttpServletResponse response, List<T> list1, List<T> list2,
                                                Object object1, Object object2, String fileName) throws Exception {
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        ExcelWriter excelWriter = EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).build();
        WriteSheet writeSheet0 = EasyExcelFactory.writerSheet(0).build();
        WriteSheet writeSheet1 = EasyExcelFactory.writerSheet(1).build();
        excelWriter.fill(object1, fillConfig, writeSheet0);
        excelWriter.fill(list1, fillConfig, writeSheet0);
        excelWriter.fill(object2, fillConfig, writeSheet1);
        excelWriter.fill(list2, fillConfig, writeSheet1);
        excelWriter.finish();
    }

    /**
     * 构建输出流
     *
     * @param fileName 文件名称
     * @param response 模板文件输出流
     * @param response
     * @return
     * @throws Exception
     */
    private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
        fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + FileTypeEnum.TEMPLATE_SUFFIX.getDesc());
        return response.getOutputStream();
    }

    /**
     * 文件格式校验
     *
     * @param file
     */
    public static void checkFile(MultipartFile file) {
        if (file == null) {
            throw new RuntimeException("文件不能为空!");
        }
        String fileName = file.getOriginalFilename();
        if (StringUtils.isEmpty(fileName)) {
            throw new RuntimeException("文件名称不能为空!");
        }
        if (!fileName.endsWith(FileTypeEnum.TEMPLATE_SUFFIX.getDesc())
                && !fileName.endsWith(FileTypeEnum.TEMPLATE_SUFFIX_XLS.getDesc())) {
            throw new RuntimeException("请上传.xlsx或.xls文件!");
        }
    }
}
/**
 * @ClassName: ExcelHeadStyles
 * @Description: excel表头颜色定义
 * @Author: 
 * @Date: 
 */
@Data
public class ExcelHeadStyles {

    /**
     * 表头横坐标 - 行
     */
    private Integer rowIndex;

    /**
     * 表头纵坐标 - 列
     */
    private Integer columnIndex;

    /**
     * 内置颜色
     */
    private Short indexColor;

    /**
     * 字体颜色
     */
    private Short fontColor;

    public ExcelHeadStyles(Integer columnIndex, Short fontColor) {
        this.columnIndex = columnIndex;
        this.fontColor = fontColor;
    }

    public ExcelHeadStyles(Integer rowIndex, Integer columnIndex, Short fontColor) {
        this.rowIndex = rowIndex;
        this.columnIndex = columnIndex;
        this.fontColor = fontColor;
    }

}
/**
 * @ClassName: FileTypeEnum
 * @Description: 文件类型枚举
 * @Author: 
 * @Date: 
 */
@Getter
public enum FileTypeEnum {
    /**
     * 模板格式
     */
    TEMPLATE_SUFFIX("xlsx", ".xlsx"),
    TEMPLATE_SUFFIX_XLS("xls", ".xls"),
    TEMPLATE_SUFFIX_DOCX("docx", ".docx");
    private final String code;
    private final String desc;

    FileTypeEnum(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    /**
     * 通过code获取msg
     *
     * @param code 枚举值
     * @return
     */
    public static String getMsgByCode(String code) {
        if (code == null) {
            return null;
        }
        FileTypeEnum enumList = getByCode(code);
        if (enumList == null) {
            return null;
        }
        return enumList.getDesc();
    }

    public static String getCode(FileTypeEnum enumList) {
        if (enumList == null) {
            return null;
        }
        return enumList.getCode();
    }

    public static FileTypeEnum getByCode(String code) {
        for (FileTypeEnum enumList : values()) {
            if (enumList.getCode().equals(code)) {
                return enumList;
            }
        }
        return null;
    }
}
/**
 * @ClassName: ReadExcelListener
 * @Description: 读取excel文件数据监听器
 * @Author: 
 * @Date: 
 */
@Slf4j
public abstract class ReadExcelListener<T> extends AnalysisEventListener<T> {

    private static final int BATCH_COUNT = 10000;

    /**
     * 数据集
     */
    private final List<T> list = new ArrayList<>();

    /**
     * 表头数据
     */
    private Map<Integer, String> headMap = null;

    private Map<String, Object> params;

    // 获取数据集
    public List<T> getList() {
        return this.list;
    }

    // 获取表头数据
    public Map<Integer, String> getHeadMap() {
        return this.headMap;
    }

    /**
     * 每条数据都会进入
     *
     * @param object
     * @param analysisContext
     */
    @Override
    public void invoke(T object, AnalysisContext analysisContext) {
        this.list.add(object);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (list.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            list.clear();
        }
    }

    /**
     * 数据解析完调用
     *
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        log.info("所有数据解析完成!");
    }

    /**
     * 读取到的表头信息
     *
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        this.headMap = headMap;
    }

    /**
     * 异常时调用
     *
     * @param exception:
     * @param context:
     * @throws Exception
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        // 数据解析异常
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
            throw new RuntimeException("第" + excelDataConvertException.getRowIndex() + "行" + excelDataConvertException.getColumnIndex() + "列" + "数据解析异常");
        }
        // 其他异常...
    }

    /**
     * 数据存储到数据库
     */
    public abstract boolean saveData();
}
/**
 * @ClassName: RowMergeStrategy
 * @Description: 自定义行合并策略
 * @Author: 
 * @Date: 
 */
public class RowMergeStrategy extends AbstractMergeStrategy {

    /**
     * 分组,每几行合并一次
     */
    private List<Integer> exportFieldGroupCountList;

    /**
     * 目标合并列index
     */
    private Integer targetColumnIndex;

    // 需要开始合并单元格的首行index
    private Integer rowIndex;

    // exportDataList为待合并目标列的值
    public RowMergeStrategy(List<String> exportDataList, Integer targetColumnIndex) {
        this.exportFieldGroupCountList = getGroupCountList(exportDataList);
        this.targetColumnIndex = targetColumnIndex;
    }

    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer integer) {
        if (null == rowIndex) {
            rowIndex = cell.getRowIndex();
        }
        // 仅从首行以及目标列的单元格开始合并,忽略其他
        if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == targetColumnIndex) {
            mergeGroupColumn(sheet);
        }
    }

    private void mergeGroupColumn(Sheet sheet) {
        int rowCount = rowIndex;
        for (Integer count : exportFieldGroupCountList) {
            if (count == 1) {
                rowCount += count;
                continue;
            }
            // 合并单元格
            CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1, targetColumnIndex, targetColumnIndex);
            sheet.addMergedRegionUnsafe(cellRangeAddress);
            rowCount += count;
        }
    }

    // 该方法将目标列根据值是否相同连续可合并,存储可合并的行数
    private List<Integer> getGroupCountList(List<String> exportDataList) {
        if (CollUtil.isEmpty(exportDataList)) {
            return new ArrayList<>();
        }
        List<Integer> groupCountList = new ArrayList<>();
        int count = 1;
        for (int i = 1; i < exportDataList.size(); i++) {
            if (exportDataList.get(i).equals(exportDataList.get(i - 1))) {
                count++;
            } else {
                groupCountList.add(count);
                count = 1;
            }
        }
        groupCountList.add(count);
        return groupCountList;
    }
}
/**
 * @ClassName: ImportDataListener
 * @Description: 导入数据监听器
 * @Author: 
 * @Date: 
 */
@Component
public class ImportDataListener extends ReadExcelListener {

    @Resource
    private IStudentService studentService;

    /**
     * 实现数据保存逻辑-直接操作表头和行数据
     *
     * @return
     */
    @Override
    public boolean saveData() {
        Map<Integer, String> headMap = getHeadMap();
        List dataList = getList();
        if (CollUtil.isEmpty(headMap) || CollUtil.isEmpty(dataList)) {
            return false;
        }
        return studentService.batchSaveStudent(dataList, headMap);
    }
}
/**
 * @ClassName: ImportStudentListener
 * @Description: 导入学生excel数据监听器
 * @Author: 
 * @Date: 
 */
@Component
public class ImportUserListener extends ReadExcelListener {

    @Resource
    private IStudentService studentService;
    @Resource
    private ITeacherService teacherService;

    /**
     * 实现数据保存逻辑
     *
     * @return
     */
    @Override
    public boolean saveData() {
        List dataList = getList();
        if (CollUtil.isEmpty(dataList)) {
            return false;
        }
        Object obj = dataList.get(0);
        if (obj instanceof Student) {
            return studentService.batchSaveStudent(dataList);
        } else if (obj instanceof Teacher) {
            return teacherService.batchSaveTeacher(dataList);
        }
        return true;
    }
}
/**
 * @ClassName: UserExcelHeadHandler
 * @Description: 用户相关excel处理器
 * @Author: 
 * @Date: 
 */
public class UserExcelHeadHandler extends HorizontalCellStyleStrategy {

    private ExcelHeadStyles excelHeadStyle;


    public UserExcelHeadHandler(ExcelHeadStyles excelHeadStyle) {
        this.excelHeadStyle = excelHeadStyle;
    }

    //设置头样式
    @Override
    protected void setHeadCellStyle(CellWriteHandlerContext context) {
        int columnNo = excelHeadStyle.getColumnIndex();
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 11);
        if (context.getColumnIndex() <= columnNo) {
            headWriteFont.setColor(excelHeadStyle.getFontColor());
        } else {
            headWriteFont.setColor(IndexedColors.BLACK.getIndex());
        }
        headWriteCellStyle.setWriteFont(headWriteFont);
        if (stopProcessing(context)) {
            return;
        }
        WriteCellData<?> cellData = context.getFirstCellData();
        WriteCellStyle.merge(headWriteCellStyle, cellData.getOrCreateStyle());
    }
}
/**
 * @ClassName: ExportController
 * @Description: 导出前端控制器
 * @Author: 
 * @Date: 
 */
@Slf4j
@RestController
public class ExportController {

    @Resource
    private IStudentService studentService;
    @Resource
    private ITeacherService teacherService;

    private static final String[] USER_HEAD_FIELDS = new String[]{"序号", "学号", "姓名", "性别"};

    /**
     * 导出学生数据-一个sheet
     *
     * @param response
     */
    @GetMapping("/student/export/sheet")
    public void exportSheetStudent(HttpServletResponse response) {
        List<Student> students = studentService.listStudent(10L);
        log.info("单sheet学生数据开始导出...");
        long startTimeL = System.currentTimeMillis();
        try {
            EasyExcelUtil.exportExcel(response, students, Student.class, "导出学生数据-一个sheet", "第一页");
        } catch (Exception e) {
            log.error("单sheet学生数据导出异常!", e);
        }
        log.info("单sheet学生数据导出完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);
    }

    /**
     * 导出学生数据-多个sheet
     *
     * @param response
     */
    @GetMapping("/student/export/sheets")
    public void exportSheetsStudent(HttpServletResponse response) {
        log.info("多sheet学生数据开始导出...");
        long startTimeL = System.currentTimeMillis();
        try {
            List<List<?>> sheetList = new ArrayList<>();
            List<Student> students1 = studentService.listStudent(10L);
            List<Student> students2 = studentService.listStudent(20L);
            sheetList.add(students1);
            sheetList.add(students2);
            Map<Integer, String> clazzMap = new HashMap<>();
            clazzMap.put(0, "sheet1");
            clazzMap.put(1, "sheet2");
            EasyExcelUtil.exportExcels(response, sheetList, clazzMap, "导出学生数据-多个sheet");
        } catch (Exception e) {
            log.error("多sheet学生数据导出失败!", e);
        }
        log.info("多sheet学生数据导出完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);
    }


    /**
     * 导出学生数据-重复行合并格式
     *
     * @param response
     */
    @GetMapping("/student/export/mergeRow")
    public void exportMergeRowStudent(HttpServletResponse response) {
        log.info("合并格式学生数据开始导出...");
        long startTimeL = System.currentTimeMillis();
        try {
            List<Student> students = studentService.listStudent(10L);
            List<String> mergeDataList = students.stream().map(Student::getSex).collect(Collectors.toList());
            EasyExcelUtil.exportWriteHandlerExcel(response, students, Student.class, "学生重复数据表格合并", "第一页", new RowMergeStrategy(mergeDataList, 3));
        } catch (Exception e) {
            log.error("合并格式学生数据导出失败!", e);
        }
        log.info("合并格式学生数据导出完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);
    }

    /**
     * 下载导入学生数据的模板【一个自定义Handler】
     *
     * @param response
     */
    @GetMapping("/student/downTemplate001")
    public void downTemplateStudent001(HttpServletResponse response) {
        log.info("设置单元格宽度-学生数据模板开始下载...");
        long startTimeL = System.currentTimeMillis();
        try {
            List<List<String>> headList = Arrays.stream(USER_HEAD_FIELDS).map(field -> CollUtil.newArrayList(field)).
                    collect(Collectors.toList());
            CellWidthStyleHandler columnWidthHandler = new CellWidthStyleHandler(true, 15);
            EasyExcelUtil.exportExcel(response, headList, Collections.EMPTY_LIST, "学生数据导入模板-设置单元格宽度", "student", columnWidthHandler);
        } catch (Exception e) {
            log.error("设置单元格宽度-学生数据模板下载失败!", e);
        }
        log.info("设置单元格宽度-学生数据模板下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);
    }

    /**
     * 下载导入学生数据的模板【多个自定义Handler】
     *
     * @param response
     */
    @GetMapping("/student/downTemplate002")
    public void downTemplateStudent002(HttpServletResponse response) {
        log.info("设置单元格宽度+字体-学生数据模板开始下载...");
        long startTimeL = System.currentTimeMillis();
        try {
            List<List<String>> headList = Arrays.stream(USER_HEAD_FIELDS).map(field -> CollUtil.newArrayList(field)).
                    collect(Collectors.toList());
            // 表头第一行的指定前3列字标红
            ExcelHeadStyles excelHeadStyle = new ExcelHeadStyles(0, 3, IndexedColors.RED1.getIndex());
            UserExcelHeadHandler headHandler = new UserExcelHeadHandler(excelHeadStyle);
            CellWidthStyleHandler columnWidthHandler = new CellWidthStyleHandler(true, 15);
            EasyExcelUtil.exportExcel(response, headList, Collections.EMPTY_LIST, "学生数据导入模板-设置单元格宽度+字体", "student", CollUtil.newArrayList(headHandler, columnWidthHandler));
        } catch (Exception e) {
            log.error("设置单元格宽度+字体-学生数据模板下载失败!", e);
        }
        log.info("设置单元格宽度+字体-学生数据模板下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);
    }


    /**************以下填充模板数据的接口测试说明:可改为get请求,InputStream可使用本地文件输入流,然后变可通过浏览器下载。******************************/
    /**
     * 根据模板将集合对象填充表格-list
     *
     * @param template
     * @param response
     */
    @PostMapping("/student/template/fill-list")
    public void exportFillTemplateList(@RequestParam("template") MultipartFile template, HttpServletResponse response) {
        log.info("根据模板填充学生数据,list,文件开始下载...");
        long startTimeL = System.currentTimeMillis();
        try {
            List students = studentService.listStudent(10L);
            EasyExcelUtil.exportTemplateExcelList(template.getInputStream(), response, students, "填充学生模板数据-list", "students");
        } catch (Exception e) {
            log.error("根据模板填充学生数据,list,文件下载失败!", e);
        }
        log.info("根据模板填充学生数据,list,文件下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);
    }

    /**
     * 根据模板将集合对象填充表格-单个sheet
     *
     * @param template
     * @param response
     */
    @PostMapping("/student/template/fill-sheet")
    public void exportFillTemplateSheet(@RequestParam("template") MultipartFile template, HttpServletResponse response) {
        log.info("根据模板填充学生数据,单个sheet,文件开始下载...");
        long startTimeL = System.currentTimeMillis();
        try {
            List<Student> students = studentService.listStudent(10L);
            Map<String, Object> map = new HashMap<>(3);
            map.put("startMonth", "2023-8-10");
            map.put("endMonth", "2023-8-12");
            EasyExcelUtil.exportTemplateSheet(template.getInputStream(), response, students, map, "填充学生模板数据-sheet");
        } catch (Exception e) {
            log.error("根据模板填充学生数据,单个sheet,文件下载失败!", e);
        }
        log.info("根据模板填充学生数据,单个sheet,文件下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);
    }

    /**
     * 根据模板将集合对象填充表格-多个sheet
     *
     * @param template
     * @param response
     */
    @PostMapping("/student/template/fill-sheets")
    public void exportFillTemplateSheets(@RequestParam("template") MultipartFile template, HttpServletResponse response) {
        log.info("根据模板填充数据,多个sheet,文件开始下载...");
        long startTimeL = System.currentTimeMillis();
        try {
            List students = studentService.listStudent(10L);
            Map<String, Object> map = new HashMap<>(2);
            map.put("startMonth", "2023-8-10");
            map.put("endMonth", "2023-8-12");
            List teachers = teacherService.listTeacher(10L);
            Map<String, Object> map2 = new HashMap<>(1);
            map2.put("illustrate", "老师人员列表");
            EasyExcelUtil.exportTemplateSheets(template.getInputStream(), response, students, teachers, map, map2, "填充学生模板数据-sheets");
        } catch (Exception e) {
            log.error("根据模板填充数据,多个sheet,文件下载失败!", e);
        }
        log.info("根据模板填充数据,多个sheet,文件下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);
    }

    /********转为get请求测试示例********/
    /**
     * get请求测试
     *
     * @param response
     */
    @GetMapping("/student/template/test")
    public void test(HttpServletResponse response) throws FileNotFoundException {
        File file = new File("C:\\Users\\Administrator\\Desktop\\test.xlsx");
        FileInputStream inputStream = new FileInputStream(file);
        log.info("根据模板填充学生数据,单个sheet,文件开始下载...");
        long startTimeL = System.currentTimeMillis();
        try {
            List<Student> students = studentService.listStudent(10L);
            Map<String, Object> map = new HashMap<>(3);
            map.put("startMonth", "2023-8-10");
            map.put("endMonth", "2023-8-12");
            EasyExcelUtil.exportTemplateSheet(inputStream, response, students, map, "填充学生模板数据-sheet");
        } catch (Exception e) {
            log.error("根据模板填充学生数据,单个sheet,文件下载失败!", e);
        }
        log.info("根据模板填充学生数据,单个sheet,文件下载完成:{}秒", (System.currentTimeMillis() - startTimeL) / 1000);
    }
}
/**
 * @ClassName: ImportController
 * @Description: 导入前端控制器
 * @Author: 
 * @Date: 
 */
@Slf4j
@RestController
public class ImportController {

    @Resource
    private ImportUserListener importUserListener;

    /**
     * 导入一个sheet学生数据
     *
     * @param file
     */
    @PostMapping("/student/import/sheet")
    public boolean importSheetStudent(@RequestParam("file") MultipartFile file) {
        EasyExcelUtil.checkFile(file);
        log.info("一个sheet学生数据开始导入...");
        long startTime = System.currentTimeMillis();
        List<Student> dataList = null;
        try {
            dataList = EasyExcelUtil.importExcel(file.getInputStream(), null, null, importUserListener);
            // 数据录入
            Assert.isFalse(CollUtil.isEmpty(dataList), "未解析到导入的数据!");
        } catch (Exception e) {
            log.error("一个sheet学生数据导入失败!", e);
        }
        log.info("一个sheet学生数据导入成功,共:{}条,消耗总时间:{}秒", dataList.size(), ((System.currentTimeMillis() - startTime) / 1000));
        return true;
    }

    /**
     * 导入多个sheet学生数据
     *
     * @param file
     */
    @PostMapping("/student/import/sheets")
    public boolean importSheets(@RequestParam("file") MultipartFile file) {
        EasyExcelUtil.checkFile(file);
        log.info("多个sheet数据开始导入...");
        long startTime = System.currentTimeMillis();
        List<Student> dataList = null;
        try {
            List sheetObjList = new ArrayList(2);
            sheetObjList.add(Student.class);
            sheetObjList.add(Teacher.class);
            dataList = EasyExcelUtil.importExcels(file.getInputStream(), 2, sheetObjList, importUserListener);
            // 数据录入
            Assert.isFalse(CollUtil.isEmpty(dataList), "未解析到导入的数据!");
        } catch (Exception e) {
            log.error("多个sheet数据导入失败!", e);
        }
        log.info("多个sheet数据导入成功,共:{}条,消耗总时间:{}秒", dataList.size(), ((System.currentTimeMillis() - startTime) / 1000));
        return true;
    }
}
/**
 * @ClassName: Student
 * @Description: 学生
 * @Author: 
 * @Date: 
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    @ExcelProperty("序号")
    private Integer num;
    @ExcelProperty("学号")
    private String sno;
    @ExcelProperty("学生名字")
    private String name;
    @ExcelProperty("性别")
    private String sex;
}
/**
 * @ClassName: Teacher
 * @Description: 老师
 * @Author: 
 * @Date: 
 **/
@Data
public class Teacher {
    @ExcelProperty("编号")
    private String sno;
    @ExcelProperty("老师名字")
    private String name;
    @ExcelProperty("性别")
    private String sex;
}
/**
 * @ClassName: TeacherServiceImpl
 * @Description: 老师相关接口实现
 * @Author: 
 * @Date: 
 */
@Slf4j
@Service
public class TeacherServiceImpl implements ITeacherService {

    @Override
    public List<Teacher> listTeacher(Long limit) {
        List<Teacher> teachers = new ArrayList<>();
        for (int i = 0; i < limit; i++) {
            Teacher teacher = new Teacher();
            teacher.setSex("女");
            teacher.setName("老师A" + i);
            teacher.setSno(UUID.fastUUID().toString());
            teachers.add(teacher);
        }
        return teachers;
    }

    @Override
    public boolean batchSaveTeacher(List<Teacher> teachers) {
        // 调用dao层接口保存数据...
        log.info("批量保存老师数据,共:{}条数据", teachers.size());
        return true;
    }

}
/**
 * @ClassName: StudentServiceImpl
 * @Description: 学生相关接口实现
 * @Author: 
 * @Date: 
 */
@Slf4j
@Service
public class StudentServiceImpl implements IStudentService {

    @Override
    public List<Student> listStudent(Long limit) {
        List<Student> students = new ArrayList<>();
        for (int i = 0; i < limit; i++) {
            Student student = new Student();
            student.setSex("男");
            student.setNum(i);
            student.setName("小A" + i);
            student.setSno(UUID.fastUUID().toString());
            students.add(student);
        }
        return students;
    }

    @Override
    public boolean batchSaveStudent(List<Student> students) {
        // 调用dao层接口保存数据...
        log.info("批量保存学生数据,共:{}条数据", students.size());
        return true;
    }

    @Override
    public boolean batchSaveStudent(List<Map<Integer, String>> dataList, Map<Integer, String> headMap) {
        // 这里可以针对读取到的表头数据和对应的行数据,这种应用场景适用于导入的excel中数据需要我们自己解析做其他业务处理,或者表头列是动态的,我们
        // 没有办法使用一个固定的实体做映射
        log.info("表头列数据:{}", headMap.values());
        log.info("批量保存学生数据,共:{}条数据", dataList.size());
        return true;
    }
}
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Spring Boot 是一个用于创建基于 Spring 框架的独立、生产级别的应用程序的框架。EasyExcel 是一个基于 Java 的开源框架,可以方便地读写 Excel 文件。使用 EasyExcel 可以轻松地进行 Excel 文件的导入导出,非常适合在 Spring Boot 项目中使用。 下面是在 Spring Boot 项目中使用 EasyExcel 进行 Excel 文件导入导出的基本步骤: 1. 添加 EasyExcel 依赖 在项目的 pom.xml 文件中添加 EasyExcel 依赖: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.10</version> </dependency> ``` 2. 编写 Excel 导出代码 使用 EasyExcel 可以非常方便地进行 Excel 文件的导出。例如,以下代码可以将一个 List 对象导出为 Excel 文件: ```java // 定义 Excel 表头 List<List<String>> head = new ArrayList<>(); head.add(Arrays.asList("姓名", "年龄")); // 定义 Excel 数据 List<List<Object>> data = new ArrayList<>(); data.add(Arrays.asList("张三", 18)); data.add(Arrays.asList("李四", 20)); data.add(Arrays.asList("王五", 22)); // 导出 Excel 文件 String fileName = "example.xlsx"; String sheetName = "Sheet1"; EasyExcel.write(fileName).sheet(sheetName).head(head).sheet().doWrite(data); ``` 3. 编写 Excel 导入代码 使用 EasyExcel 进行 Excel 文件的导入也非常方便。例如,以下代码可以从 Excel 文件中读取数据并转换为一个 List 对象: ```java // 定义读取 Excel 文件的监听器 public class ExcelListener extends AnalysisEventListener<Object> { private List<Object> data = new ArrayList<>(); @Override public void invoke(Object object, AnalysisContext context) { data.add(object); } @Override public void doAfterAllAnalysed(AnalysisContext context) {} public List<Object> getData() { return data; } } // 读取 Excel 文件 String fileName = "example.xlsx"; ExcelListener listener = new ExcelListener(); EasyExcel.read(fileName, listener).sheet().doRead(); List<Object> data = listener.getData(); ``` 4. 将 Excel 文件导入到数据库 读取 Excel 文件之后,可以将数据存入数据库中。以下代码演示了将读取的 Excel 文件中的数据存入 MySQL 数据库的过程: ```java // 定义实体类 @Data public class Person { private String name; private Integer age; } // 保存数据到数据库 List<Person> persons = new ArrayList<>(); for (Object obj : data) { List<Object> row = (List<Object>) obj; Person person = new Person(); person.setName((String) row.get(0)); person.setAge((Integer) row.get(1)); persons.add(person); } personRepository.saveAll(persons); ``` 以上就是使用 EasyExcel 进行 Excel 文件导入导出的基本步骤。根据实际需求,可以对以上代码进行相应的修改和扩展。 ### 回答2: Spring Boot 是一个开源的Java开发框架,可以帮助开发人员快速构建基于Spring的应用程序。EasyExcel 是一种基于Java的Excel读写工具,它提供了简单便捷的API,可以方便地实现Excel的导入导出功能。 在Spring Boot中使用EasyExcel进行导入导出操作非常简单。首先,我们需要在pom.xml文件中添加EasyExcel的依赖项,以便可以使用它的功能。然后,我们可以创建一个Controller类来处理导入导出的请求。 对于导入操作,我们可以使用EasyExcel提供的@ExcelProperty注解来标记实体类的字段与Excel的列的映射关系。然后,我们可以使用EasyExcel的read方法来读取Excel文件,并将数据转换为实体类对象。最后,我们可以对读取到的数据进行相应的业务操作,比如存储到数据库中。 对于导出操作,我们可以使用EasyExcel的@ExcelProperty注解标记实体类的字段,并使用EasyExcel的write方法来将实体类列表写入Excel文件。我们可以通过指定文件路径或输出流的方式进行导出。 除了基本的导入导出功能,EasyExcel还提供了一些高级特性,比如读取大文件、多sheet处理、自定义读写处理器等。这些特性可以帮助我们更好地应对复杂的Excel导入导出需求。 总而言之,Spring Boot结合EasyExcel提供了一种简单快捷的方式来实现Excel的导入导出功能。无论是处理简单的Excel文件还是应对复杂的导入导出需求,Spring Boot和EasyExcel都能够提供强大的支持。 ### 回答3: Spring Boot 是一种简化了开发过程的Java框架,而EasyExcel是一种用于操作Excel文件的开源库。通过结合使用Spring Boot和EasyExcel,我们可以方便地实现Excel文件的导入导出功能。下面将详细介绍如何使用Spring Boot和EasyExcel来实现导入导出功能。 首先,我们需要在Spring Boot的项目中引入EasyExcel的依赖。在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.6</version> </dependency> ``` 接着,我们可以创建一个Controller类来处理导入导出的请求。在该类中,我们可以定义两个方法,一个用于导入Excel文件,另一个用于导出Excel文件。 对于导入功能,我们可以使用EasyExcel提供的`read()`方法来读取Excel文件,并将读取到的数据转换为一个List对象。以下是一个简单的导入方法的示例代码: ```java @PostMapping("/import") public void importExcel(@RequestParam("file") MultipartFile file) throws IOException { List<DataDTO> dataList = EasyExcel.read(file.getInputStream()).head(DataDTO.class).sheet().doReadSync(); // 处理导入的数据 } ``` 对于导出功能,我们可以使用EasyExcel提供的`write()`方法来创建一个Excel文件,并将数据写入到该文件中。以下是一个简单的导出方法的示例代码: ```java @GetMapping("/export") public void exportExcel(HttpServletResponse response) throws IOException { List<DataDTO> dataList = getDataList(); // 获取导出的数据 response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("data.xlsx", "utf-8")); EasyExcel.write(response.getOutputStream()).sheet("Data").doWrite(dataList); } ``` 在上述代码中,我们首先获取需要导出的数据(getDataList()方法需要根据实际情况实现),然后设置响应头信息,最后使用`write()`方法将数据写入到响应的输出流中。 通过以上步骤,我们在Spring Boot项目中成功实现了使用EasyExcel进行Excel文件的导入导出功能。我们可以根据具体需求对导入的数据进行处理,也可以根据实际情况设置导出文件的格式和名称。同时,EasyExcel还提供了更多的功能和选项,如设置表头导入数据校验等,可以根据具体需求进行使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

princeAladdin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值