Spring - 无法为API返回ByteArrayResource发送错误消息

时间:2016-12-09 10:47:19

标签: java json spring spring-mvc

我在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表示。

2 个答案:

答案 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());
}