Как вернуть изображение в 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}