У меня есть API для отдыха в Spring для создания и загрузки PDF файла. Конфигурация контроллера следующая:
@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
.
Я пробовал решения по этому вопросу Stackoverflow, в частности, этот ответ, но он все еще терпит неудачу. Это решение, наряду с другими изменениями, предполагает удаление produces
часть из @RequestMapping
, но когда я отлажена в AbstractMessageConverterMethodProcessor.getProducibleMediaTypes
обнаруживает только приложения /JSON в качестве доступного типа реакции средств массовой информации.
tl; dr Как я могу заставить этот API вернуть файл на успех и правильно возвратить представление JSON класса исключения исключительного класса при ошибке.
У меня была такая же проблема с похожим кодом. Я просто удалил produces
атрибут из моего @PostMapping
, и я был в состоянии вернуть файл или JSON (когда апи есть некоторые ошибки):
@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());
}
Попробуйте реализовать свое действие как
@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)
и работать с ним.