在OpenApi生成的Spring资源方法中处理OutputStream
解决方案
问题1:在生成的方法中获取Servlet OutputStream
有两种实用方案:
- 通过Spring请求上下文获取
无需修改生成的方法签名,直接在实现类里借助RequestContextHolder拿到当前请求的HttpServletResponse,进而获取输出流:
@Override public ResponseEntity<Resource> getApiReasonMyReasonCategorization() { // 从上下文提取响应对象 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes == null) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } HttpServletResponse response = attributes.getResponse(); if (response == null) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } // 设置Excel响应头 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment; filename=reason-categorization.xlsx"); try (ServletOutputStream outputStream = response.getOutputStream()) { // 调用Excel生成逻辑 createExcel(outputStream); outputStream.flush(); return ResponseEntity.ok().build(); } catch (IOException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } }
注意:该方式依赖Web请求线程上下文,不适用于异步执行场景。
- 修改OpenApi定义注入响应对象
在openapi.yaml的目标GET接口中添加扩展参数,让生成器自动注入HttpServletResponse:
/api/reason/my-reason-categorization: get: summary: 导出分类Excel parameters: - name: response in: header required: false schema: type: string x-spring-param-type: servletResponse responses: 200: description: Excel文件 content: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet: schema: type: string format: binary
重新生成代码后,接口方法会自动带上HttpServletResponse response参数,直接在实现类中使用即可。
问题2:让OpenApi直接生成支持OutputStream的资源方法
可以通过两种方式实现:
- 自定义生成器模板
复制openapi-generator官方的Spring模板(比如api.mustache)到项目目录,修改方法签名:
将返回类型从ResponseEntity<Resource>改为void,并添加HttpServletResponse response参数。
然后在Maven插件配置中指定自定义模板路径:
<plugin> <groupId>org.openapitools</groupId> <artifactId>openapi-generator-maven-plugin</artifactId> <version>5.1.0</version> <executions> <execution> <goals> <goal>generate</goal> </goals> <configuration> <generatorName>spring</generatorName> <inputSpec>${project.basedir}/src/main/resources/openapi.yaml</inputSpec> <templateDirectory>${project.basedir}/src/main/resources/templates</templateDirectory> <!-- 其他配置项 --> </configuration> </execution> </executions> </plugin>
修改后的模板方法示例:
{{#operation}} {{#isGet}} @GetMapping("{{path}}") {{/isGet}} public void {{operationId}}(HttpServletResponse response) { // 生成的方法占位逻辑 } {{/operation}}
生成后的方法可直接操作输出流,无需返回ResponseEntity。
- 通过OpenApi扩展修改返回类型
在openapi.yaml的接口响应中添加x-spring-response-type扩展,指定返回类型为void,同时保留问题1中的响应对象注入参数:
/api/reason/my-reason-categorization: get: summary: 导出分类Excel parameters: - name: response in: header required: false schema: type: string x-spring-param-type: servletResponse responses: 200: description: Excel文件 content: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet: schema: type: string format: binary x-spring-response-type: void
重新生成代码后,方法签名会变为:
void getApiReasonMyReasonCategorization(HttpServletResponse response);
实现时直接写入输出流即可,无需返回值。
内容的提问来源于stack exchange,提问作者andy
相关产品推荐
相关产品推荐

