Как вернуть изображение в Spring Контроллер загрузки и служить файловой системой

Я пробовал различные способы, заданные в Stackoverflow, возможно, я что-то пропустил.

У меня есть клиент Android (код которого я не могу изменить), который в настоящее время получает изображение следующим образом:

HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();

Где url - местоположение изображения (статический ресурс на CDN). Теперь моя конечная точка API загрузки Spring должна вести себя как файловый ресурс таким же образом, чтобы один и тот же код мог получать изображения из API (Spring версия для загрузки 1.3.3).

Итак, у меня есть это:

@ResponseBody
@RequestMapping(value = "/Image/{id:.+}", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE, produces = MediaType.IMAGE_JPEG_VALUE)
public ResponseEntity<byte[]> getImage(@PathVariable("id")String id) {
    byte[] image = imageService.getImage(id);  //this just gets the data from a database
    return ResponseEntity.ok(image);
}

Теперь, когда код Android пытается получить http://someurl/image1.jpg, я получаю эту ошибку в своих журналах:

Разрешение исключения из обработчика [public org.springframework.http.ResponseEntity com.myproject.MyController.getImage(java.lang.String)]: org.springframework.web.HttpMediaTypeNotAcceptableException: не удалось найти приемлемое представление

То же самое происходит при подключении http://someurl/image1.jpg к браузеру.

Как ни странно, мои тесты проверяются нормально:

Response response = given()
            .pathParam("id", "image1.jpg")
            .when()
            .get("MyController/Image/{id}");

assertEquals(HttpStatus.OK.value(), response.getStatusCode());
byte[] array = response.asByteArray(); //byte array is identical to test image

Как мне заставить это вести себя, как образ, подаваемый обычным способом? (Примечание. Я не могу изменить заголовок содержимого, который отправляет код Android).

ИЗМЕНИТЬ

Код после комментариев (задайте тип контента, выньте produces):

@RequestMapping(value = "/Image/{id:.+}", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE)
public ResponseEntity<byte[]> getImage(@PathVariable("id")String id, HttpServletResponse response) {
    byte[] image = imageService.getImage(id);  //this just gets the data from a database
    response.setContentType(MediaType.IMAGE_JPEG_VALUE);
    return ResponseEntity.ok(image);
}

В браузере это, похоже, дает сжатый барахл (байт, который я думаю). В Android это не ошибка, но изображение не отображается.

Ответ 1

Наконец, исправлено это... Мне пришлось добавить ByteArrayHttpMessageConverter к моему подклассу WebMvcConfigurerAdapter:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    final ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
    final List<MediaType> list = new ArrayList<>();
    list.add(MediaType.IMAGE_JPEG);
    list.add(MediaType.APPLICATION_OCTET_STREAM);
    arrayHttpMessageConverter.setSupportedMediaTypes(list);
    converters.add(arrayHttpMessageConverter);

    super.configureMessageConverters(converters);
}

Ответ 2

Я считаю, что это должно работать:

@RequestMapping(value = "/Image/{id:.+}", method = RequestMethod.GET)
public ResponseEntity<byte[]> getImage(@PathVariable("id") String id) {
    byte[] image = imageService.getImage(id);
    return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(image);
}

Обратите внимание, что тип содержимого установлен для ResponseEntity, а не для HttpServletResponse.

Ответ 3

В случае, если вы не знаете тип файла /mime, вы можете сделать это.... Я сделал это, где я беру загруженный файл и заменяю имя файла на guid без расширения, и браузеры/смартфоны могут загрузить изображение без проблем. второе - предоставить файл для загрузки.

@RestController
@RequestMapping("img")
public class ImageController {

@GetMapping("showme")
public ResponseEntity<byte[]> getImage() throws IOException{
    File img = new File("src/main/resources/static/test.jpg");
    return ResponseEntity.ok().contentType(MediaType.valueOf(FileTypeMap.getDefaultFileTypeMap().getContentType(img))).body(Files.readAllBytes(img.toPath()));
}
@GetMapping("thing")
public ResponseEntity<byte[]> what() throws IOException{
    File file = new File("src/main/resources/static/thing.pdf");
    return ResponseEntity.ok()
            .header("Content-Disposition", "attachment; filename=" +file.getName())
            .contentType(MediaType.valueOf(FileTypeMap.getDefaultFileTypeMap().getContentType(file)))
            .body(Files.readAllBytes(file.toPath()));
}


}   

ОБНОВЛЕНИЕ в java 9+ вам нужно добавить compile 'com.sun.activation:javax.activation:1.2.0' к вашим зависимостям, которые также были перемещены или подобраны Джакартой. увидеть этот пост

Ответ 4

Используя Apache Commons, вы можете сделать это и выставить изображение на конечную точку

@RequestMapping(value = "/image/{imageid}",method= RequestMethod.GET,produces = MediaType.IMAGE_JPEG_VALUE)
public @ResponseBody byte[] getImageWithMediaType(@PathVariable int imageid) throws IOException {
    InputStream in = new ByteArrayInputStream(getImage(imageid));
    return IOUtils.toByteArray(in);
    }

Все изображения будут обслуживаться в конечной точке /image/{imageid}