我在Spring中有一个用于生成和下载PDF文件的rest API。控制器定义如下 -
@RequestMapping(
value = "/foo/bar/pdf",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@ResponseBody
@Nullable
public ByteArrayResource downloadPdf(@RequestParam int userId) {
byte[] result = null;
ByteArrayResource byteArrayResource = null;
result = service.generatePdf(userId);
if (result != null) {
byteArrayResource = new ByteArrayResource(result);
}
return byteArrayResource;
}
我使用Jackson进行JSON处理JSON并使用Exception处理程序ControllerAdvice。问题是当此API生成异常并返回自定义异常类(包含消息和一个附加字段)时。
正如我已经指定produces = MediaType.APPLICATION_OCTET_STREAM_VALUE
,这个自定义类也试图被Spring转换为八位字节流,它失败并生成HttpMediaTypeNotAcceptableException: Could not find acceptable representation
。
我在this Stackoverflow问题上尝试过解决方案,尤其是this answer,但它仍然失败。此解决方案以及其他更改建议从produces
中删除@RequestMapping
部分,但当我调试到AbstractMessageConverterMethodProcessor.getProducibleMediaTypes
时,它仅将application / json检测为可用的响应媒体类型。
TL;博士 如何让此API在成功时返回文件,并在出错时正确返回自定义异常类的JSON表示。
答案 0 :(得分:1)
尝试将您的操作实现为
@RequestMapping(
value = "/foo/bar/pdf",
method = RequestMethod.GET)
@ResponseBody
public HttpEntity<byte[]> downloadPdf(@RequestParam int userId) {
byte[] result = service.generatePdf(userId);
HttpHeaders headers = new HttpHeaders();
if (result != null) {
headers.setContentType(new MediaType("application", "pdf"));
headers.set("Content-Disposition", "inline; filename=export.pdf");
headers.setContentLength(result.length);
return new HttpEntity(result, headers);
}
return new HttpEntity<>(header)
}
关于异常处理,例如,您可以抛出YourCustomError
,并在带有@ControllerAdvice
注释的控制器中使用@ExceptionHandler(YourCustomError.class)
注释方法并使用它。
答案 1 :(得分:1)
我遇到了类似代码的问题。我刚刚从produces
删除了@PostMapping
属性,我能够返回文件或json(当api出现错误时):
@Override
@PostMapping
public ResponseEntity<InputStreamResource> generate(
@PathVariable long id
) {
Result result = service.find(id);
return ResponseEntity
.ok()
.cacheControl(CacheControl.noCache())
.contentLength(result.getSize())
.contentType(MediaType.parseMediaType(MediaType.APPLICATION_PDF_VALUE))
.body(new InputStreamResource(result.getFile()));
}
发生错误时,我有@ExceptionHandler
来处理:
@ExceptionHandler
public ResponseEntity<ApiErrorResponse> handleApiException(ApiException ex) {
ApiErrorResponse error = new ApiErrorResponse(ex);
return new ResponseEntity<>(error, ex.getHttpStatus());
}