Spring - невозможно отправить сообщение об ошибке для API, возвращающего ByteArrayResource

2

У меня есть 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 класса исключения исключительного класса при ошибке.

Теги:
spring
spring-mvc

2 ответа

1

У меня была такая же проблема с похожим кодом. Я просто удалил 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());
}
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) и работать с ним.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню