EasyExcel使用ResponseEntity导出excel

本文介绍如何使用EasyExcel配合ResponseEntity直接将excel文件返回给前端,避免先保存到服务器再下载的步骤。详细讲解了controller、service、实体类、工具类以及自定义样式策略的实现,并提醒在设置HTTP状态码时避免偶发问题。

之前写过一篇使用EasyExcel导出excel到项目服务器中,然后在下载页面点击下载之后根据路径进行下载的。在这篇文章中我将用ResponseEntity直接返回excel到前端,记录一下该方法,同时也给大家一个参考。
1、controller层代码(根据前端的需求来)

	@GetMapping("/export_excel")
    public ResponseEntity exportExcel(@RequestBody List<PrdRequest> prdRequest) {
        return prdService.exportExcel(prdRequest);
    }

2、service层实现代码

public ResponseEntity exportExcel(List<PrdRequest> prdRequest) {
        try {
        	//根据条件进行查询
        	List<PrdVo> prdVoList = prdMapper.selectPrd(prdRequest);
            //数据写入到字节流
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            String sheetName = "产品信息查询导出表";
            boolean flag = ExcelUtils.writeExcel(bos, PrdVo.class, prdVoList , sheetName);
            //下载文件
            String fileName = sheetName + ".xlsx";
            //excel导出
            if (flag) {
                return ExcelUtils.downloadExcel(fileName, bos);
            }
        } catch (Exception e) {
            log.error("产品信息导出异常", e);
        }
        return null;
    }

3、导出结果实体类

@ApiModel(value = "PrdVo", description = "产品信息excel导出实体")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PrdVo implements Serializable {

    @ExcelProperty(value = "产品名称", index = 0)
    private String prdName;

    @ExcelProperty(value = "产品编码", index = 1)
    private String prdCode;

    @ExcelProperty(value = "厂商名称", index = 2)
    private String manufacturerName;
    。。。其它的字段
}

4、ExcelUtils工具类

@Slf4j
public class ExcelUtils {

    /**
     * 表头进行自动扩展的导出
     *
     * @param os        文件输出流
     * @param clazz     Excel实体映射类
     * @param data      导出数据
     * @param sheetName sheet名称
     * @return
     */
    public static Boolean writeExcel(OutputStream os, Class clazz, List<?> data, String sheetName) {
        try (BufferedOutputStream bos = new BufferedOutputStream(os)) {
            EasyExcel.write(bos, clazz)
                    .sheet(sheetName)
                    //使用该方法对表头的宽度进行扩展
                    .registerWriteHandler(new ColumnWidthStyleStrategy())
                    .doWrite(data);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    /**
     * ResponseEntity下载文件
     *
     * @param fileName
     * @param byteOutPutStream
     */
    public static ResponseEntity<byte[]> downloadExcel(String fileName, ByteArrayOutputStream byteOutPutStream) {
        //下载文件
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            // 文件名称
            headers.setContentDispositionFormData("attachment",
                    new String(fileName.getBytes("GBK"), "ISO8859-1"));
            ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(byteOutPutStream.toByteArray(), headers, HttpStatus.OK);
            return responseEntity;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

5、ColumnWidthStyleStrategy类,不能使用自带的,因为使用自带的只有第一次导出的时候会格式化

public class ColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {
    private static final int MAX_COLUMN_WIDTH = 255;

    private final Map<Integer, Map<Integer, Integer>> CACHE = new HashMap<Integer, Map<Integer, Integer>>(8);

    @Override
    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head,
                                  Integer relativeRowIndex, Boolean isHead) {
        boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
        if (!needSetWidth) {
            return;
        }
        Map<Integer, Integer> maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo());
        if (maxColumnWidthMap == null) {
            maxColumnWidthMap = new HashMap<Integer, Integer>(16);
            CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
        }
        Integer columnWidth = dataLength(cellDataList, cell, isHead);
        if (columnWidth < 0) {
            return;
        }
        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 Integer dataLength(List<CellData> cellDataList, Cell cell, Boolean isHead) {
        if (isHead) {
            return cell.getStringCellValue().getBytes(CommonConstant.UTF_8).length;
        }
        CellData cellData = cellDataList.get(0);
        CellDataTypeEnum type = cellData.getType();
        if (type == null) {
            return -1;
        }
        switch (type) {
            case STRING:
                return cellData.getStringValue().getBytes(CommonConstant.UTF_8).length;
            case BOOLEAN:
                return cellData.getBooleanValue().toString().getBytes(CommonConstant.UTF_8).length;
            case NUMBER:
                return cellData.getNumberValue().toString().getBytes(CommonConstant.UTF_8).length;
            default:
                return -1;
        }
    }
}

mapper文件中进行查询的语句没有放在里面,感觉都很简单,没有必要,需要注意的是第四步的时候使用HttpStatus.OK,因为我之前使用了HttpStatus.CREATED,导出的报表会偶发性的出一点问题。
希望这篇文章能够帮助到需要的人,欢迎大家转载收藏。

<think>好的,用户的问题是关于如何使用EasyExcel导出Excel文件并通过OpenFeign传输到另一台服务器。首先,我需要回忆一下EasyExcel和OpenFeign的基本用法,然后考虑如何将两者结合起来处理文件传输。 首先,EasyExcel是阿里巴巴的一个库,用于简化Excel的读写操作。用户需要导出Excel文件,这部分应该比较直接,可以用EasyExcel的API来生成文件。但生成后的文件需要传输到另一个服务,这时候要用到OpenFeign,而Feign默认可能不支持文件传输,需要检查是否要使用MultipartFile或者其他的处理方式。 接下来,文件传输通常涉及到HTTP的multipart/form-data格式。OpenFeign需要正确的配置才能处理文件上传。可能需要添加依赖,比如feign-form模块,以支持文件上传。同时,服务提供方的接口需要能够接收文件,可能是一个POST接口,参数是MultipartFile。 然后,用户的问题可能涉及到服务之间的调用,所以需要确保服务消费者能够通过Feign客户端调用提供方的上传接口。这可能需要定义一个Feign客户端接口,使用@RequestPart注解来处理文件参数。 另外,还要考虑文件在传输过程中的处理。例如,EasyExcel生成的文件可能是临时文件,需要在传输后删除,避免占用磁盘空间。同时,异常处理也需要考虑,比如文件生成失败、传输失败等情况,应该给出适当的提示或重试机制。 可能还需要考虑性能问题,比如大文件传输时的内存管理。EasyExcel本身是省内存的,但传输大文件时可能需要分块或者流式处理,不过Feign可能默认不支持流式上传,需要确认是否有更好的方法。 最后,需要验证整个流程是否正确,包括生成Excel、调用Feign客户端传输、服务提供方接收并保存文件。可能还需要提供代码示例,帮助用户理解具体实现步骤。 总结一下,步骤应该是:1. 使用EasyExcel导出Excel到本地或字节流;2. 配置OpenFeign支持文件上传;3. 定义Feign客户端接口;4. 调用接口传输文件;5. 服务提供方处理并保存文件。同时,处理异常和资源清理。</think>### 分步解答:使用EasyExcel导出Excel并通过OpenFeign传输 #### 一、Excel文件生成(EasyExcel实现) 1. **创建数据模型类** 定义需要导出的数据结构,使用`@ExcelProperty`注解标注表头: ```java @Data public class UserDTO { @ExcelProperty("用户ID") private Long id; @ExcelProperty("用户名") private String name; } ``` 2. **生成Excel文件** 使用EasyExcel将数据写入临时文件或字节数组: ```java public File generateExcel(List<UserDTO> dataList) throws IOException { File tempFile = File.createTempFile("export_", ".xlsx"); EasyExcel.write(tempFile, UserDTO.class) .sheet("用户列表") .doWrite(dataList); return tempFile; } ``` #### 二、OpenFeign文件传输配置 1. **添加依赖** 在pom.xml中添加OpenFeign文件传输支持: ```xml <dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form</artifactId> <version>3.8.0</version> </dependency> <dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form-spring</artifactId> <version>3.8.0</version> </dependency> ``` 2. **定义Feign客户端接口** 使用`@RequestPart`注解接收文件参数: ```java @FeignClient(name = "file-server") public interface FileTransferClient { @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) ResponseEntity<String> uploadFile(@RequestPart("file") MultipartFile file); } ``` #### 三、文件传输实现 1. **转换文件为MultipartFile** 将生成的Excel文件转换为Spring支持的传输格式: ```java public MultipartFile convertToMultipart(File file) throws IOException { FileInputStream input = new FileInputStream(file); return new MockMultipartFile( "file", file.getName(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", IOUtils.toByteArray(input) ); } ``` 2. **发起远程调用** 通过Feign客户端发送文件: ```java @Autowired private FileTransferClient fileTransferClient; public void executeExport(List<UserDTO> data) { try { File excelFile = generateExcel(data); MultipartFile multipartFile = convertToMultipart(excelFile); ResponseEntity<String> response = fileTransferClient.uploadFile(multipartFile); excelFile.delete(); // 清理临时文件 } catch (IOException e) { throw new RuntimeException("文件传输失败", e); } } ``` #### 四、服务端接收实现(目标服务器) 1. **创建接收接口** 在目标服务中定义接收端点: ```java @RestController public class FileController { @PostMapping("/upload") public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file) { if (!file.isEmpty()) { String fileName = "received_" + System.currentTimeMillis() + ".xlsx"; file.transferTo(new File("/storage/" + fileName)); return ResponseEntity.ok("文件上传成功"); } return ResponseEntity.badRequest().body("空文件"); } } ``` #### 五、关键配置注意事项 1. **HTTP客户端配置** 在application.yml中增大请求大小限制: ```yaml spring: servlet: multipart: max-file-size: 100MB max-request-size: 100MB ``` 2. **Feign客户端配置类** 启用表单编码支持: ```java @Configuration public class FeignConfig { @Bean public Encoder feignFormEncoder() { return new SpringFormEncoder(); } } ```
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值