easyPOI导出多Sheet

news2025/2/13 2:27:16

easyPOI导出多Sheet

声明,本文基于JAVA操作Excel(POI、easyPOI、easyExcel_我认不到你的博客-CSDN博客讲解,需要基础的可以看这篇,特别是@Excel注解

本篇最后有工具类和自定义的注解类,只需要傻瓜式复制粘贴应该就可以用

而且我感觉使用easyPOI做多Sheet导出没有easyExcel好用,但是easyPOI对于一对多数据的导出要比easyExcel友好

各有各的好处,目前就easyPOI导出多Sheet讲解,本篇用到的知识:easyPOI、反射、自定义注解

效果图

在这里插入图片描述

一、导包

 <!--easypoi-->
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-spring-boot-starter</artifactId>
            <version>4.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.1.2</version>
        </dependency>

二、自定义注解(用于导出Sheet名字)

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SheetName {
    /**
     * @return SheetName
     */
    String name();
}

二、实体类(三个)类名什么的都随意,主要是注解要用对

1、ExportEmployeeTemplateVo.java 用于导出全部的信息,这个类是我随便定义的,主要是把每一个Sheet的数据和@SheetName放在一个对象里面

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
// 类名随意,主要需要下面的多个 对象 的数据
// Excel为从上到下导出,比如把 公司和部门信息 和 员工信息 换个位置 公司和部门信息 就是第一页了
public class ExportEmployeeTemplateVo {

    // 这个第一页(Sheet)是模板所以没有放数据,到时候存个对象进去就可以了
    @SheetName(name = "员工信息")
    private EmployeesVo employeesVo;

    // 这个第二页(Sheet)这个是需要导出的list数据
    @SheetName(name = "公司和部门信息")
    private List<CompanyAndDepartmentInfoVo> companyAndDepartmentInfoVos;
    
    // 可以一直往下添加
    //@SheetName(name = "随意")
    //private List<随意> 随意;
}

2、EmployeesVo.java 这里面放的就是@Excel用于导出,这里只展示一个,其他的@Excel都删了,代码多了没什么必要

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class EmployeesVo {
	@Excel(name="*企业ID",  width = 30,needMerge = true,orderNum = "3")
	private String company_id;
}

3、CompanyAndDepartmentInfoVo.java 这里面放的就是@Excel用于导出,这里只展示一个,其他的@Excel都删了,代码多了没什么必要

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class CompanyAndDepartmentInfoVo {
    @Excel(name="id",  width = 30,needMerge = true)
    private String id;
}

三、用于讲解导出多Sheet的工具类代码,需要配合四、controller

(这里只展示用于导出多Sheet的代码,最后面有全的工具类)

	/**
     * 多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();

        // 这里就是需要上述的ExportEmployeeTemplateVo类的class对象
        Class<?> aClass = exportDataSet.getClass();
        // 获取到全部属性
        Field[] declaredFields = aClass.getDeclaredFields();
        // 循环拿到的数据
        for (Field field : declaredFields) {
            // 可以拿到private的属性
            field.setAccessible(true);
            // 获取属性上面的SheetName注解(就是自己定义的)
            SheetName annotation = field.getAnnotation(SheetName.class);
            // 获取自定义注解的值,就是Sheet的名字
            final String sheetName = annotation.name();
            
            // 这个map中需要三个值 (title、entity、data),因为easyPOI的源码中需要这三个参数来遍历
            Map<String, Object> exportMap = Maps.newHashMap();
            // 设置sheet名字
            final ExportParams exportParams = new ExportParams(null, sheetName);

            // 以下3个参数为easyPOI的源码中写死的参数名 分别是sheet配置/导出类(注解定义)/数据集
            exportMap.put("title", exportParams);
            // 获取list<?>中?的泛型
            if (field.getType().isAssignableFrom(List.class)){
                // 如果是List类型,得到其Generic的类型
                Type fc = field.getGenericType(); 
                if(fc instanceof ParameterizedType){
                    ParameterizedType pt = (ParameterizedType) fc;
                    // 得到泛型里的class类型对象。
                    Class genericClazz = (Class)pt.getActualTypeArguments()[0];
                    // 把泛型中的class对象塞进map中
                    exportMap.put("entity", genericClazz);
                }
                // 这里面就是数据
                exportMap.put("data", field.get(exportDataSet));
            }else { 
                // 如果不是list数据说明是模板
                exportMap.put("entity", field.getType());
                // 虽然模板没有数据,但是easypoi源码中需要data类型为集合(Collection)所以需要装一下
                // 又因为Collections.singletonList生成的集合对象,是一个内部类,需要用ArrayList装一下
                exportMap.put("data", new ArrayList<>(Collections.singletonList(field.get(exportDataSet))));
            }
            // 加入多sheet配置列表
            sheetsList.add(exportMap);
        }
        
		/*       =========================== 导出文件 ===========================       */
        
        // 核心方法:导出含多个sheet的excel文件 【HSSF导出的对应.xls文件,XSSF导出对应.xlsx文件,其实这两种都可以导出,但是导入的时候.xlsx文件会报错,暂时我没找出问题所在,所以就用的HSSF导出.xls文件】
        final Workbook workbook = ExcelExportUtil.exportExcel(sheetsList, ExcelType.HSSF);

        // 批注不为空的话,就写批注
        if(StringUtils.isNotBlank(remake)){
            // 添加批注格式 :0#姓名不能为空__1#学生性别 1:男 2:女__2#出生日期:yyyy-MM-dd__3#图片不能为空
        	// 说明 #前面数字是第几列,后面为批注的内容,__为隔断各个列的内容
            buildComment(workbook,0,remake);
        }
        response.setCharacterEncoding("UTF-8");
        response.setHeader("content-Type", "application/vnd.ms-excel");
        // 就像核心方法所示,导出.xlsx文件后,导入会报错,所以我就用写死.xls文件了,fileName,对应文件名
        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);
        }
    }

四、controller


    /**
     * 导出
     */    
	@RequestMapping("/?????随意随意")
    public void exportEmployeeTemplate(String id, HttpServletResponse response){
        try {
            log.info("exportEmployeeTemplate 入参:id = {}",id);
            // 这里数获取数据
            List<CompanyAndDepartmentInfoVo> companyAndDepartmentInfoVos = ecpEmployeeManagementService.exportEmployeeTemplate(id);
            // 这里是往ExportEmployeeTemplateVo对象中塞入 每个字段对应的数据
            ExportEmployeeTemplateVo exportEmployeeTemplateVo = new ExportEmployeeTemplateVo()
                    .setCompanyAndDepartmentInfoVos(companyAndDepartmentInfoVos)
                //EmployeesVo 为导出模板没有值
                    .setEmployeesVo(new EmployeesVo());
            
            // 添加批注格式 :0#姓名不能为空__1#学生性别 1:男 2:女__2#出生日期:yyyy-MM-dd__3#图片不能为空
            // 说明 #前面数字是第几列,后面为批注的内容,__为隔断各个列的内容
            
            String remake = "0#此为必填项__1#此为必填项__2#此为必填项,具体值请参照第二页的企业ID__3#此为必填项,具体值请参照第二页的部门ID__4#此为必填项__6#在职、离职和退休三个状态__8#请填写中国或其他__10#有身份证、护照和军官证三种类型__12#格式为yyyy-MM-dd HH:mm:ss__13#格式为yyyy-MM-dd HH:mm:ss";
            
            // 导出 Excel 为 员工管理.xls
            EasyPoiUtil.exportMultiSheetWorkbook("员工管理.xls",exportEmployeeTemplateVo,response,remake);
        } catch (Exception e) {
            log.error("exportEmployeeTemplate 导出失败:",e);
        }
    }


    /**
     * 导入
     */
    @RequestMapping("/随意随意")
    public void importEmployeeTemplate(MultipartFile file){
        try {
            List<EmployeesVo> employeesVos = EasyPoiUtil.importExcel(file, 0, 1, EmployeesVo.class);
            log.debug("employeesVos = {}",employeesVos);
        } catch (Exception e) {
            log.error("importEmployeeTemplate 导入失败:",e);
        }
    }

工具类

/**
 * @author ZHAOPINGAN
 * @Title: EasyPoiUtil
 * @ProjectName
 * @Description:
 */
public class EasyPoiUtil {

    /**
     * 导出excel
     *
     * @param list           数据list
     * @param title          标题
     * @param sheetName      sheet名称
     * @param pojoClass      实体的class
     * @param fileName       文件名称
     * @param isCreateHeader 是否创建头
     * @param response       响应
     */
    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 (UnsupportedEncodingException 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);
        }
    }
}


题外话:PostMan导入

Body中放文件
在这里插入图片描述
Headers中写格式 Content-Type || multipart/form-data ,好像这个可有可无
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/645612.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

与 NGINX 团队直接交流 | 微服务之月火热报名中

原文作者&#xff1a;NGINX 原文链接&#xff1a;与 NGINX 团队直接交流 | 微服务之月火热报名中 转载来源&#xff1a;NGINX 官方网站 NGINX 唯一中文官方社区 &#xff0c;尽在 nginx.org.cn 又是一个热情似火的六月&#xff0c;一年一度的 Microservices June 微服务之月再…

6.12 共享内存(内存映射的使用、注意事项、进程间通信、systemV共享内存)

目录 system V IPC 共享内存 共享内存使用步骤 system V IPC -key system V IPC -ftok system V IPC -ftok-示例 共享内存创建-shmget 共享内存创建-shmget-示例1 共享内存创建-shmget-示例2 共享内存映射-shmat 共享内存读写 - 示例 共享内存撤销映射 - shmdt 共享…

etcd基本使用

目录 CRUD1、基本的put/get/del2、获取当前所有的key3、获取/删除带有前缀的键 lease使用1、创建lease&#xff0c;续租lease&#xff0c;撤销lease2、将lease attach到key上 watch使用watch、watch_oncereplacedeletewatch_prefix、watch_prefix_oncecancel_watchadd_watch_ca…

抖音整治短剧类小程序内容

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 短剧CPS项目这两年不是挺火的吗&#xff0c;很多草根创业者都在做短剧CPS当副业。 前两天&#xff0c;抖音开放平台团队发布公告&#xff1a; 近期&#xff0c;在微短剧类小程序内容合规排查中&am…

【LeetCode】HOT 100(11)

题单介绍&#xff1a; 精选 100 道力扣&#xff08;LeetCode&#xff09;上最热门的题目&#xff0c;适合初识算法与数据结构的新手和想要在短时间内高效提升的人&#xff0c;熟练掌握这 100 道题&#xff0c;你就已经具备了在代码世界通行的基本能力。 目录 题单介绍&#…

工作多年的工作焦虑症-广泛性焦虑症

我相信工作多年的人都会有自己的工作焦虑症的情况&#xff0c;而我们普通人最多的最容易的也就是广泛性焦虑症&#xff0c;广泛性焦虑障碍&#xff08;GAD&#xff09;是一种常见的慢性焦虑障碍&#xff0c;患者长时间处于一种担心、紧张、无法放松的状态。它会让一种广泛的担心…

采购协同:企业数字化转型的关键环节

企业数字化转型已成为当今市场的主流趋势&#xff0c;而采购协同作为企业数字化转型的关键环节&#xff0c;对于企业的成本控制、供应链管理等方面都有着至关重要的影响。本文将围绕采购协同的重要性、数字化转型的方法和优势、以及实现采购协同的关键环节展开讨论。 一、采购协…

Java并发容器 并发队列

并发容器概览 ConcurrentHashMap : 线程安全的HashMap CopyOnWriteArrayList: 线程安全的List BlockingQueue:这是一个接口&#xff0c;表示阻塞队列&#xff0c;非常适合用于作为数据共享的通道 ConcurrentLinkedQueue : 高效的非阻塞并发队列&#xff0c;使用链表实现。可…

目标检测数据集---道路破损缺陷数据集

✨✨✨✨✨✨目标检测数据集✨✨✨✨✨✨ 本专栏提供各种场景的数据集,主要聚焦:工业缺陷检测数据集、小目标数据集、遥感数据集、红外小目标数据集,该专栏的数据集会在多个专栏进行验证,在多个数据集进行验证mAP涨点明显,尤其是小目标、遮挡物精度提升明显的数据集会在该…

Java list安全删除元素详解

背景 前一段时间被问到了关于 List 集合的安全删除元素问题。一时间没反应过来这问题问的是什么&#xff0c;安全体现在什么地方&#xff0c;线程安全&#xff1f;线程安全可以保证元素粒度的数据唯一吗&#xff1f;删除是指什么&#xff0c;list.remove()&#xff1f; 带着这…

5外包功能测试做完,人废了一半····

先说一下自己的情况。大专生&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近5年的点点点&#xff0c;今年年上旬&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01;而我已经在一个企业干了五年的功能测试…

剑指offer35 复杂链表的复制

复杂链表的复制 文章目录 复杂链表的复制方法一 回溯哈希表第二种解释 方法二&#xff1a;拼接拆分算法流程 参考文献 本题要求我们对一个复杂链表进行复制。在复杂链表中&#xff0c;每个节点除了有一个next指针指向下一个节点&#xff0c;还有一个random指针指向链表中的任意…

SpringBoot+Vue 车辆充电桩系统

文章目录 1、效果演示效果图技术栈 2、 前言介绍&#xff08;完整源码请私聊&#xff09;3、主要技术3.4.1 数据库概念结构设计3.4.2 数据库具体设计 4 系统功能的具体实现4.1 前台功能模块4.1.1 首页功能4.1.2 用户后台管理 4.2 后台功能模块4.2.1 管理员功能4.2.2 维修员功能…

后端(三):后端实战(表白墙的设计)

上一章结束了 Servlet 的学习&#xff0c;ok&#xff0c;现在我们已经学会了 1 1 了&#xff0c;现在开始我们要学会 百以内的加减乘除法。 本章就做一个最简单的 小小项目&#xff1a;表白墙。 在开始表白墙项目开始之间&#xff0c;我们先提前说好&#xff0c;这里主要跟关…

海思3559万能平台搭建:SPI输出h264码流

前言 面对各种各样的客户需求&#xff0c;spi接口也是一种传码流的形式&#xff0c;spi同步422可以保证抗干扰能力强的同时传输距离也很长&#xff0c;本文会介绍海思平台spi作为主机的发送功能以及发送码流的处理方式 1. 管脚复用&#xff1a; 首先需要配置的肯定是管脚复用&…

java容器排序

Java的容器 在Java中&#xff0c;我们想要保存对象可以使用很多种手段。最简单的就是数组。但是数组具有固定的尺寸&#xff0c;而通常来说&#xff0c;程序总是在运行时根据条件来创建对象&#xff0c;我们无法预知将要创建对象的个数以及类型&#xff0c;所以Java推出了容器…

动态规划-最长的回文序列

这里写自定义目录标题 1 描述2 样例2.1 样例12.2 样例2 3 解题思路以及实现方法3.1 解题思路3.1.1 确定状态3.1.2 转移方程3.1.3 初始条件和边界情况3.1.4 计算顺序 3.2 题解3.2.1 C实现3.2.2 java实现 该题是lintcode上 667 最长的回文序列&#xff0c;该题的解题思路亦是参…

方法选对,事半功倍:数据分析方法

人们发明了数据可视化&#xff0c;利用人类大脑更善于处理图像信息的特点&#xff0c;透过图形化的手段&#xff0c;用图表清晰有效地传达和沟通信息。把以往庞杂、繁乱的数据报表转化成简洁明了的可视化图表。 通过数据可视化制作出的图表&#xff0c;不再像传统分析方案那样…

JavaScript Web APIs学习总结

以后声明变量我们有限使用哪一个&#xff1f; const 有了变量先给const&#xff0c;如果发现它后面是要被修改的&#xff0c;再改为let 为什么const声明的对象可以修改里面的属性&#xff1f; 因为对象是引用类型&#xff0c;里面存储的是地址&#xff0c;只要地址不变&…

月入6000+的CSGO游戏搬砖项目操作细节和要求

月入6000的CSGO游戏搬砖项目操作细节和要求 最近咨询CSGO搬砖项目的人较多&#xff0c;在此整理一份统一的项目操作细节和要求。 1、什么是国外Steam游戏装备汇率差项目&#xff1f; 这个项目的基本原理是&#xff1a;购买国外Steam游戏平台上的装备&#xff0c;再在国内网易…