Je reçois des données d'image (en tant que byte[]
) à partir de DB. Comment renvoyer cette image en @ResponseBody
?
MODIFIER
Je l'ai fait sans @ResponseBody
en utilisant HttpServletResponse
comme paramètre de méthode:
@RequestMapping("/photo1")
public void photo(HttpServletResponse response) throws IOException {
response.setContentType("image/jpeg");
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
IOUtils.copy(in, response.getOutputStream());
}
Utiliser @ResponseBody
avec le convertisseur org.springframework.http.converter.ByteArrayHttpMessageConverter
enregistré comme @Sid ne fonctionne pas pour moi :(.
@ResponseBody
@RequestMapping("/photo2")
public byte[] testphoto() throws IOException {
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
return IOUtils.toByteArray(in);
}
si vous utilisez la version 3.1 ou plus récente de Spring, vous pouvez spécifier "produit" dans l'annotation @RequestMapping
. L'exemple ci-dessous fonctionne pour moi en boîte. Pas besoin de convertisseur de registre ou quoi que ce soit d'autre si vous avez activé Web MVC (@EnableWebMvc
).
@ResponseBody
@RequestMapping(value = "/photo2", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
public byte[] testphoto() throws IOException {
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
return IOUtils.toByteArray(in);
}
Avec Spring 4.1 et les versions ultérieures, vous pouvez renvoyer à peu près n'importe quoi (images, fichiers PDF, documents, bocaux, zips, etc.) tout simplement, sans aucune dépendance supplémentaire. Par exemple, voici une méthode permettant de renvoyer la photo de profil d'un utilisateur à partir de MongoDB GridFS:
@RequestMapping(value = "user/avatar/{userId}", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<InputStreamResource> downloadUserAvatarImage(@PathVariable Long userId) {
GridFSDBFile gridFsFile = fileService.findUserAccountAvatarById(userId);
return ResponseEntity.ok()
.contentLength(gridFsFile.getLength())
.contentType(MediaType.parseMediaType(gridFsFile.getContentType()))
.body(new InputStreamResource(gridFsFile.getInputStream()));
}
Les choses à noter:
ResponseEntity avec InputStreamResource en tant que type de retour
Création du style de générateur ResponseEntity
Avec cette méthode, vous n'avez pas à vous soucier du câblage automatique dans HttpServletResponse, du lancement d'une exception IOException ou de la copie des données de flux.
En plus d'enregistrer une ByteArrayHttpMessageConverter
, vous pouvez utiliser une ResponseEntity
au lieu de @ResponseBody
. Le code suivant fonctionne pour moi:
@RequestMapping("/photo2")
public ResponseEntity<byte[]> testphoto() throws IOException {
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<byte[]>(IOUtils.toByteArray(in), headers, HttpStatus.CREATED);
}
En utilisant Spring 3.1.x et 3.2.x, voici comment procéder:
La méthode du contrôleur:
@RequestMapping("/photo2")
public @ResponseBody byte[] testphoto() throws IOException {
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
return IOUtils.toByteArray(in);
}
Et l'annotation MVC dans le fichier servlet-context.xml:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>image/jpeg</value>
<value>image/png</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
En plus de quelques réponses, voici quelques indications (Printemps 4.1).
Si vous n'avez aucun messageconverters configuré dans votre WebMvcConfig, avoir ResponseEntity
dans votre @ResponseBody
fonctionne bien.
Si vous le faites, c’est-à-dire que vous avez un MappingJackson2HttpMessageConverter
configuré (comme moi) à l’aide de la ResponseEntity
renvoie un org.springframework.http.converter.HttpMessageNotWritableException
.
La seule solution efficace dans ce cas consiste à envelopper un byte[]
dans le @ResponseBody
comme suit:
@RequestMapping(value = "/get/image/{id}", method=RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public @ResponseBody byte[] showImageOnId(@PathVariable("id") String id) {
byte[] b = whatEverMethodUsedToObtainBytes(id);
return b;
}
Dans ce cas, rappelez-vous de configurer correctement les messageconverters (et ajoutez un ByteArrayHttpMessageConverer
) dans votre WebMvcConfig, comme suit:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingJackson2HttpMessageConverter());
converters.add(byteArrayHttpMessageConverter());
}
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapper);
return converter;
}
@Bean
public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
arrayHttpMessageConverter.setSupportedMediaTypes(getSupportedMediaTypes());
return arrayHttpMessageConverter;
}
private List<MediaType> getSupportedMediaTypes() {
List<MediaType> list = new ArrayList<MediaType>();
list.add(MediaType.IMAGE_JPEG);
list.add(MediaType.IMAGE_PNG);
list.add(MediaType.APPLICATION_OCTET_STREAM);
return list;
}
@RequestMapping(value = "/get-image",method = RequestMethod.GET)
public ResponseEntity<byte[]> getImage() throws IOException {
RandomAccessFile f = new RandomAccessFile("/home/vivex/Apache-Tomcat-7.0.59/tmpFiles/1.jpg", "r");
byte[] b = new byte[(int)f.length()];
f.readFully(b);
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<byte[]>(b, headers, HttpStatus.CREATED);
}
Travaillé pour moi.
Dans votre contexte d'application, déclarez AnnotationMethodHandlerAdapter et registerByteArrayHttpMessageConverter:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<util:list>
<bean id="byteArrayMessageConverter" class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
</util:list>
</property>
</bean>
dans la méthode du gestionnaire, définissez également le type de contenu approprié pour votre réponse.
Je préfère celle-ci:
private ResourceLoader resourceLoader = new DefaultResourceLoader();
@ResponseBody
@RequestMapping(value = "/{id}", produces = "image/bmp")
public Resource texture(@PathVariable("id") String id) {
return resourceLoader.getResource("classpath:images/" + id + ".bmp");
}
Changez le type de support au format d'image que vous avez.
C'est un travail pour moi au printemps 4.
@RequestMapping(value = "/image/{id}", method = RequestMethod.GET)
public void findImage(@PathVariable("id") String id, HttpServletResponse resp){
final Foto anafoto = <find object>
resp.reset();
resp.setContentType(MediaType.IMAGE_JPEG_VALUE);
resp.setContentLength(anafoto.getImage().length);
final BufferedInputStream in = new BufferedInputStream(new ByteArrayInputStream(anafoto.getImageInBytes()));
try {
FileCopyUtils.copy(in, resp.getOutputStream());
resp.flushBuffer();
} catch (final IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Aucune des réponses ne fonctionnait pour moi, alors j'ai réussi à le faire comme ça:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("your content type here"));
headers.set("Content-Disposition", "attachment; filename=fileName.jpg");
headers.setContentLength(fileContent.length);
return new ResponseEntity<>(fileContent, headers, HttpStatus.OK);
Définition de l'en-tête Content-Disposition
J'ai été en mesure de télécharger le fichier avec l'annotation @ResponseBody
sur ma méthode.
Voici comment je le fais avec Spring Boot et Guava:
@RequestMapping(value = "/getimage", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
public void getImage( HttpServletResponse response ) throws IOException
{
ByteStreams.copy( getClass().getResourceAsStream( "/preview-image.jpg" ), response.getOutputStream() );
}
Je pense que vous avez peut-être besoin d'un service pour stocker le téléchargement de fichiers et obtenir ce fichier . Voir plus de détails dans ici
1) Créer un service de stockage
@Service
public class StorageService {
Logger log = LoggerFactory.getLogger(this.getClass().getName());
private final Path rootLocation = Paths.get("upload-dir");
public void store(MultipartFile file) {
try {
Files.copy(file.getInputStream(), this.rootLocation.resolve(file.getOriginalFilename()));
} catch (Exception e) {
throw new RuntimeException("FAIL!");
}
}
public Resource loadFile(String filename) {
try {
Path file = rootLocation.resolve(filename);
Resource resource = new UrlResource(file.toUri());
if (resource.exists() || resource.isReadable()) {
return resource;
} else {
throw new RuntimeException("FAIL!");
}
} catch (MalformedURLException e) {
throw new RuntimeException("FAIL!");
}
}
public void deleteAll() {
FileSystemUtils.deleteRecursively(rootLocation.toFile());
}
public void init() {
try {
Files.createDirectory(rootLocation);
} catch (IOException e) {
throw new RuntimeException("Could not initialize storage!");
}
}
}
2) Créer un contrôleur de repos pour télécharger et obtenir un fichier
@Controller
public class UploadController {
@Autowired
StorageService storageService;
List<String> files = new ArrayList<String>();
@PostMapping("/post")
public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file) {
String message = "";
try {
storageService.store(file);
files.add(file.getOriginalFilename());
message = "You successfully uploaded " + file.getOriginalFilename() + "!";
return ResponseEntity.status(HttpStatus.OK).body(message);
} catch (Exception e) {
message = "FAIL to upload " + file.getOriginalFilename() + "!";
return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(message);
}
}
@GetMapping("/getallfiles")
public ResponseEntity<List<String>> getListFiles(Model model) {
List<String> fileNames = files
.stream().map(fileName -> MvcUriComponentsBuilder
.fromMethodName(UploadController.class, "getFile", fileName).build().toString())
.collect(Collectors.toList());
return ResponseEntity.ok().body(fileNames);
}
@GetMapping("/files/{filename:.+}")
@ResponseBody
public ResponseEntity<Resource> getFile(@PathVariable String filename) {
Resource file = storageService.loadFile(filename);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"")
.body(file);
}
}
Au printemps 4, il est très facile de ne pas modifier les haricots Marquez uniquement votre type de retour sur @ResponseBody.
Exemple:-
@RequestMapping(value = "/image/{id}")
public @ResponseBody
byte[] showImage(@PathVariable Integer id) {
byte[] b;
/* Do your logic and return
*/
return b;
}
Vous devez spécifier le type de support dans la réponse. J'utilise une annotation @GetMapping avec producteurs = MediaType.IMAGE_JPEG_VALUE. @RequestMapping fonctionnera de la même manière.
@GetMapping(value="/current/chart",produces = MediaType.IMAGE_JPEG_VALUE)
@ResponseBody
public byte[] getChart() {
return ...;
}
Sans type de support, il est difficile de deviner ce qui est réellement renvoyé (quiconque lit le code, le navigateur et bien sûr Spring lui-même). Un octet [] n'est pas spécifique. La seule façon de déterminer le type de média à partir d'un octet [] consiste à renifler et à deviner.
La fourniture d'un type de support est juste meilleure pratique _