spring boot数据导出excel

Controller:

java 复制代码
 @PostMapping(value = "/export",
            produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE, MediaType.APPLICATION_JSON_VALUE})
    public void RApiExport(HttpServletResponse response, @RequestBody SearchListReqDto reqDto) throws Exception {
        rapiSearchConfigService.exportData(response, reqDto);
    }

service

java 复制代码
   public void exportData(HttpServletResponse response, SearchListReqDto reqDto) throws IOException, IllegalAccessException {
        //excel对应多sheet实体类
        ExportRApiDataTemplate exportRApiDataTemplate = new ExportRApiDataTemplate();

        String statisticalStart = reqDto.getStatisticalStart();
        String statisticalEnd = reqDto.getStatisticalEnd();
        List<String> keywords = getKeywords(reqDto);


        List<SearchUserInfo> searchUserInfoList = new ArrayList<>();
        List<RapiSearchUser> searchUserList = rapiSearchUserDao.selectByCreateTime(statisticalStart, statisticalEnd, null, null, keywords);
        searchUserList.forEach(r -> {
            SearchUserInfo searchUserInfo = BeanConvertUtils.convertTo(r, SearchUserInfo::new);
            searchUserInfo.setCreateTime(DateUtil.toString(r.getCreateTime(), DateUtil.yyyy_MM_ddHHmmss_format));
            searchUserInfo.setUserHomePage(getUserShareUrl(r.getSearchUserInfo()));
            searchUserInfoList.add(searchUserInfo);
        });
        exportRApiDataTemplate.setSearchUserInfoList(searchUserInfoList);
        String nowDate = DateUtil.toString(new Date(), DateUtil.yyMMddHHmmss_format);
        //调用工具类导出
        EasyPoiUtils.exportMultiSheetWorkbook(nowDate + "RApi数据统计", exportRApiDataTemplate, response);
    }

excel导出模版对应实体类(注:子类不序列化会抛错)

java 复制代码
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class ExportRApiDataTemplate {

    @SheetName(name = "人员信息")
    private List<SearchUserInfo> searchUserInfoList;

   /* @SheetName(name = "帖子信息")
    private List<SearchPostsInfo> searchPostsInfoList;

    @SheetName(name = "标签信息")
    private List<SearchHashTagInfo> searchHashTagInfoList;
*/
}
java 复制代码
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
public class SearchUserInfo implements Serializable {

    @Excel(name = "用户id")
    private String uid;

    @Excel(name = "用户名称",width = 30)
    private String name;

    @Excel(name = "已关注数量")
    private String followingCount;

    @Excel(name = "点赞数")
    private String totalFavorited;

    @Excel(name = "粉丝数量")
    private String followerCount;

    @Excel(name = "insId")
    private String insId;

    @Excel(name = "邮箱")
    private String email;

    @Excel(name = "用户主页链接")
    private String userHomePage;

    @Excel(name = "统计时间")
    private String createTime;

    @Excel(name = "数据抓取关键字",width = 50)
    private String dataSource;

}

EasyPoiUtils 工具类

java 复制代码
package com.seezoon.admin.modules.sys.utils;


import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.exception.excel.ExcelExportException;
import cn.afterturn.easypoi.exception.excel.ExcelImportException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.seezoon.admin.modules.sys.dto.excel.kol.SheetName;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.util.*;

import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


/**
 * @Classname EasyPoiUtils
 * @Description
 * @Date 2023/8/31 11:59
 * @Created by jyl
 */
public class EasyPoiUtils {
        static final Logger logger = LoggerFactory.getLogger(EasyPoiUtils.class);
        private static final String XLS = "xls";
        private static final String XLSX = "xlsx";
        private static final String SPLIT = ".";

        public static void newExportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response){
            newExport(list, fileName, response);
        }


        private static void newDownLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
            try {
                response.setCharacterEncoding("UTF-8");
                response.setHeader("content-Type", "application/vnd.ms-excel");
                response.setHeader("Content-Disposition",
                        "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
                workbook.write(response.getOutputStream());
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage());
            }
        }
        private static void newExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) {
            Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
            if (workbook != null);
            newDownLoadExcel(fileName, response, workbook);
        }



        public static <T> List<T> newImportExcelMore(MultipartFile file, Class<T> pojoClass, ImportParams params){
            if (file == null){
                return null;
            }

            List<T> list = null;
            try {
                list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
            }catch (NoSuchElementException e){
                throw new RuntimeException("excel文件不能为空");
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }
            return list;
        }

        public static Workbook newGetWorkbook(MultipartFile file) {
            Workbook workbook=null;
            try {
                // 获取Excel后缀名
                String fileName = file.getOriginalFilename();
                if (StringUtils.isEmpty(fileName) || fileName.lastIndexOf(SPLIT) < 0) {
                    logger.warn("解析Excel失败,因为获取到的Excel文件名非法!");
                    return null;
                }
                String fileType = fileName.substring(fileName.lastIndexOf(SPLIT) + 1, fileName.length());
                // 获取Excel工作簿
                if (fileType.equalsIgnoreCase(XLS)) {
                    workbook = new HSSFWorkbook(file.getInputStream());
                } else if (fileType.equalsIgnoreCase(XLSX)) {
                    workbook = new XSSFWorkbook(file.getInputStream());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return workbook;
        }


    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, boolean isCreateHeader, HttpServletResponse response) {
        ExportParams exportParams = new ExportParams(title, sheetName);
        exportParams.setCreateHeadRows(isCreateHeader);
        defaultExport(list, pojoClass, fileName, response, exportParams);

    }

    /**
     * 导出excel
     *
     * @param list      数据list
     * @param title     标题
     * @param sheetName sheet名称
     * @param pojoClass 实体class
     * @param fileName  文件名
     * @param response  响应
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, HttpServletResponse response) {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=GBK");
        try {
            response.setHeader("content-disposition",
                    "attachment;filename=" + java.net.URLEncoder.encode(fileName, "GBK")
                            + ";filename*=GBK''" + java.net.URLEncoder.encode(fileName, "GBK"));
        } catch (Exception e) {
            // ...
        }
        defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName));
    }

    /**
     * 导出excel
     *
     * @param list     多个Map key title 对应表格Title key entity 对应表格对应实体 key data
     * @param fileName 标题
     * @param response 响应
     */
    public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) {
        defaultExport(list, fileName, response);
    }

    /**
     * 导出多个excel
     *
     * @param workbooks 多个excel文件 通过ExcelExportUtil.exportExcel往workbooks内放入excel
     * @param fileNames 文件名 每个excel文件的名称顺序必须一致且名称请务必保证不重复
     * @param fileName  压缩包文件名
     * @param response  标题
     */
    public static void exportExcels(List<Workbook> workbooks, List<String> fileNames, String fileName, HttpServletResponse response) {
        try {
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".zip");
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            ZipOutputStream zipOut = new ZipOutputStream(toClient);
            for (int i = 0; i < workbooks.size(); i++) {
                ZipEntry entry = new ZipEntry(fileNames.get(i) + ".xls");
                zipOut.putNextEntry(entry);
                workbooks.get(i).write(zipOut);
            }
            zipOut.flush();
            zipOut.close();
        } catch (IOException e) {
            throw new ExcelExportException(e.getMessage());
        }
    }

    /**
     * 导出excel
     *
     * @param list      数据list
     * @param pojoClass 实体class
     * @param fileName  文件名
     * @param response  响应
     */
    private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) {
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
        downLoadExcel(fileName, response, workbook);
    }

    private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
        try {
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            workbook.write(response.getOutputStream());
            workbook.close();
        } catch (IOException e) {
            throw new ExcelImportException(e.getMessage());
        }
    }

    private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) {
        Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
        downLoadExcel(fileName, response, workbook);
    }

    public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) {
        if (StringUtils.isBlank(filePath)) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
        } catch (NoSuchElementException e) {
            throw new ExcelImportException("模板不能为空");
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExcelImportException(e.getMessage());
        }
        return list;
    }

    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) {
        if (file == null) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);//标题占几行,从哪行开始读取
        params.setHeadRows(headerRows);//header占几行
        params.setSheetNum(1);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
        } catch (NoSuchElementException e) {
            throw new ExcelImportException("excel文件不能为空");
        } catch (Exception e) {
            throw new ExcelImportException(e.getMessage());
        }
        return list;
    }


    /**
     * 多Sheet导出,不需要批注
     * @param fileName 文件名
     * @param exportDataSet 导出的类对象
     * @param response
     * @throws IllegalAccessException
     * @throws IOException
     */
    public static <T> void exportMultiSheetWorkbook(String fileName,T exportDataSet, HttpServletResponse response) throws IOException, IllegalAccessException {
        exportMultiSheetWorkbook(fileName,exportDataSet,response,null);
    }

    /**
     * 多Sheet导出,需要批注
     * @param fileName 文件名
     * @param exportDataSet 导出的类对象
     * @param response
     * @throws IllegalAccessException
     * @throws IOException
     */
    public static <T> void exportMultiSheetWorkbook(String fileName,T exportDataSet, HttpServletResponse response,String remake) throws IllegalAccessException, IOException {
        // 多个sheet配置参数
        final List<Map<String, Object>> sheetsList = Lists.newArrayList();

        Class<?> aClass = exportDataSet.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            SheetName annotation = field.getAnnotation(SheetName.class);
            final String sheetName = annotation.name();
            Map<String, Object> exportMap = Maps.newHashMap();
            final ExportParams exportParams = new ExportParams(null, sheetName);

            // 以下3个参数为API中写死的参数名 分别是sheet配置/导出类(注解定义)/数据集
            exportMap.put("title", exportParams);
            // 获取list<?>中?的泛型
            if (field.getType().isAssignableFrom(List.class)){
                Type fc = field.getGenericType(); //如果是List类型,得到其Generic的类型
                if(fc instanceof ParameterizedType){
                    ParameterizedType pt = (ParameterizedType) fc;
                    //得到泛型里的class类型对象。
                    Class genericClazz = (Class)pt.getActualTypeArguments()[0];
                    exportMap.put("entity", genericClazz);
                }
                exportMap.put("data", field.get(exportDataSet));
            }else {
                exportMap.put("entity", field.getType());
                exportMap.put("data", new ArrayList<>(Collections.singletonList(field.get(exportDataSet))));
            }
            // 加入多sheet配置列表
            sheetsList.add(exportMap);
        }

        // 导出文件

        // 核心方法:导出含多个sheet的excel文件 【注意,该方法第二个参数必须与上述的ExportParams对象指定的导出类型一致,默认ExcelType.HSSF格式,否则执行此方法时会报错!!!】
        final Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);

        // 添加批注格式 :0#姓名不能为空__1#学生性别 1:男 2:女__2#出生日期:yyyy-MM-dd__3#图片不能为空
        if(StringUtils.isNotBlank(remake)){
            buildComment(workbook,0,remake);
        }
        response.setCharacterEncoding("UTF-8");
        response.setHeader("content-Type", "application/vnd.ms-excel");
        response.setHeader("Content-Disposition",
                "attachment;filename=" + URLEncoder.encode(fileName + ".xls", "UTF-8"));

        workbook.write(response.getOutputStream());
        // 写完数据关闭流
        workbook.close();
    }

    public static void buildComment(Workbook workbook, int titleRowsIndex, String commentStr) {
        Sheet sheet = workbook.getSheetAt(0);
        //创建一个图画工具
        Drawing<?> drawing = sheet.createDrawingPatriarch();
        Row row = sheet.getRow(titleRowsIndex);
        if (StringUtils.isNotBlank(commentStr)) {
            //解析批注,并传换成map
            Map<Integer, String> commentMap = getCommentMap(commentStr);
            for (Map.Entry<Integer, String> entry : commentMap.entrySet()) {
                Cell cell = row.getCell(entry.getKey());
                //创建批注
                Comment comment = drawing.createCellComment(newClientAnchor(workbook));
                //输入批注信息
                comment.setString(newRichTextString(workbook, entry.getValue()));
                //将批注添加到单元格对象中
                cell.setCellComment(comment);

                if (entry.getValue().contains("必填项")){
                    //设置单元格背景颜色
                    CellStyle cellStyle = workbook.createCellStyle();
                    //通过workbook获得文字处理类
                    Font font = workbook.createFont();
                    font.setColor(Font.COLOR_RED);
                    //水平居中
                    cellStyle.setAlignment(HorizontalAlignment.CENTER);
                    //垂直居中
                    cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
                    cellStyle.setFont(font);
                    cell.setCellStyle(cellStyle);
                }
            }
        }
    }
    /**
     * 批注信息,默认解析:批注#列索引,比如用户名不允许重复#0。可覆盖此方法,解析自定义的批注格式
     *
     * @param commentStr 当前行的所有批注信息
     * @return key:列索引,value:对应列的所有批注信息
     */
    protected static  Map<Integer, String> getCommentMap(String commentStr) {
        //每行的所有单元格的批注都在commentStr里,并用"__"分隔
        String[] split = commentStr.split("__");
        Map<Integer, String> commentMap = new HashMap<>();
        for (String msg : split) {
            String[] cellMsg = msg.split("#");
            //如果当前列没有批注,会将该列的索引作为key存到map里;已有批注,以","分隔继续拼接
            int cellIndex = Integer.parseInt(cellMsg[0]);
            if (commentMap.get(cellIndex) == null) {
                commentMap.put(cellIndex, cellMsg[1]);
            } else {
                commentMap.replace(cellIndex, commentMap.get(cellIndex) + "," + cellMsg[1]);
            }
        }
        return commentMap;
    }
    private static  ClientAnchor newClientAnchor(Workbook workbook) {
        //xls
        if (workbook instanceof HSSFWorkbook) {
            return new HSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6);
        }
        //xlsx
        else {
            return new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6);
        }
    }
    private static  RichTextString newRichTextString(Workbook workbook, String msg) {
        //xls
        if (workbook instanceof HSSFWorkbook) {
            return new HSSFRichTextString(msg);
        }
        //xlsx
        else {
            return new XSSFRichTextString(msg);
        }
    }


}
相关推荐
儿时可乖了11 分钟前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
ruleslol12 分钟前
java基础概念37:正则表达式2-爬虫
java
xmh-sxh-131429 分钟前
jdk各个版本介绍
java
星星会笑滴37 分钟前
vue+node+Express+xlsx+emements-plus实现导入excel,并且将数据保存到数据库
vue.js·excel·express
天天扭码1 小时前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶1 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺1 小时前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序1 小时前
vue3 封装request请求
java·前端·typescript·vue
陈王卜1 小时前
django+boostrap实现发布博客权限控制
java·前端·django
小码的头发丝、1 小时前
Spring Boot 注解
java·spring boot