Bahar MVC: @ResponseBody'de görüntü nasıl döndürülür?


142

byte[]DB görüntü verileri (as ) alıyorum . Bu görüntü nasıl geri gönderilir @ResponseBody?

DÜZENLE

Yöntem parametresi olarak @ResponseBodykullanmadan yaptım HttpServletResponse:

@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());
}

@Sid dediğim gibi @ResponseBodykayıtlı org.springframework.http.converter.ByteArrayHttpMessageConverterdönüştürücü ile kullanmak benim için çalışmıyor :(.

@ResponseBody
@RequestMapping("/photo2")
public byte[] testphoto() throws IOException {
    InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
    return IOUtils.toByteArray(in);
}

Yanıtlar:


97

3.1 veya daha yeni bir Spring sürümünü kullanıyorsanız @RequestMappingek açıklamada "üretir" belirtebilirsiniz . Aşağıdaki örnek benim için hazır. Web mvc etkinse ( @EnableWebMvc) kayıt dönüştürücüsüne veya başka bir şeye gerek yoktur .

@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);
}

78

Bahar 4.1 ve üstü ile, herhangi bir ekstra bağımlılık olmadan hemen hemen her şeyi (resimler, pdf'ler, belgeler, kavanozlar, fermuarlar, vb.) Örneğin, aşağıdakiler kullanıcının profil resmini MongoDB GridFS'den döndürmek için bir yöntem olabilir:

@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()));
}

Dikkat edilmesi gerekenler:

  • Dönüş türü olarak InputStreamResource ile ResponseEntity

  • ResponseEntity oluşturucu stili oluşturma

Bu yöntemle, HttpServletResponse'deki otomatik kablolama, bir IOException özel durumu oluşturma veya akış verilerini etrafa kopyalama konusunda endişelenmenize gerek yoktur.


1
Bu, aşağıdaki istisnayı atar, MyInputStream'i nasıl serileştiriyorsunuz ?: İçerik yazılamadı: com.mongodb.gridfs.GridFSDBFile $ MyInputStream
Nestor Ledon

Bu esas olarak yapabileceğinizin bir örneği olarak, ancak GridFsDBFile.getInputStream () ile Mongo-Java-Driver 3.0.3 MyInputStream adlı anonim bir sınıf döndürmez. Sürümlerinizi kontrol ederdim - belki güncelleme?
Jaymes Bearden

4
Bunun, bellekteki her şeyi kopyalamak yerine dosyayı nasıl akışa aldığını seviyorum. Ayrıca bkz. Stackoverflow.com/questions/20333394/…
Wim Deblauwe

60

A kaydına ek olarak ByteArrayHttpMessageConverter, ResponseEntityyerine kullanmak isteyebilirsiniz @ResponseBody. Aşağıdaki kod benim için çalışıyor:

@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);
}

16

Spring 3.1.x ve 3.2.x kullanarak, bunu şu şekilde yapmanız gerekir:

Denetleyici yöntemi:

@RequestMapping("/photo2")
public @ResponseBody byte[] testphoto() throws IOException {
    InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
    return IOUtils.toByteArray(in);
}

Ve servlet-context.xml dosyasındaki mvc ek açıklaması:

<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>

13

Burada birkaç cevaba ek olarak birkaç işaretçi (Bahar 4.1).

WebMvcConfig'nizde yapılandırılmış herhangi bir ileti dönüştürücü yoksa, çalışmalarınızın ResponseEntityiçinde iyi @ResponseBodyçalışır.

Bunu yaparsanız, yani döndürmeleri MappingJackson2HttpMessageConverterkullanarak yapılandırılmış bir (benim gibi) var .ResponseEntityorg.springframework.http.converter.HttpMessageNotWritableException

Bu durumda tek çalışma çözüm sarılmasıdır byte[]içinde @ResponseBodyaşağıdaki gibi:

@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;
}

Bu durumda ByteArrayHttpMessageConverer, ileti dönüştürücüleri WebMvcConfig konsolunuzda düzgün şekilde yapılandırın (ve a ) ekleyin ;

@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;
}

6

Uygulama bağlamınızda bir AnnotationMethodHandlerAdapter bildirin ve 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> 

ayrıca işleyici yönteminde yanıtınız için uygun içerik türünü ayarlayın.


@jsinghfoss en üstteki cevaba bakınız.
Peymankh

6
 @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);



}

Benim için çalıştı.


5

Bunu tercih ederim:

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");
}

Ortam türünü, sahip olduğunuz görüntü formatıyla değiştirin.


1
İyi bir çağrı yapın ResourceLoader, ancak örneğinizde olduğu gibi harici girişten bir yol adı oluşturmak kötü bir fikirdir: cwe.mitre.org/data/definitions/22.html
qerub

3

Bahar 4'te benim için iş.

@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();
        }

}

2

Cevapların hiçbiri benim için işe yaramadı, bu yüzden böyle yapmayı başardım:

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);

Content-DispositionÜstbilgiyi ayarlama Dosyayı @ResponseBodyyöntemime ek açıklama ile indirebildim .


2

Yanıtta ortam türünü belirtmelisiniz. Ben bir = GetMapping ek açıklama ile üretir = MediaType.IMAGE_JPEG_VALUE. @RequestMapping aynı şekilde çalışır.

@GetMapping(value="/current/chart",produces = MediaType.IMAGE_JPEG_VALUE)
@ResponseBody
public byte[] getChart() {
    return ...;
}

Bir medya türü olmadan, gerçekte ne döndürüldüğünü tahmin etmek zordur (kodu, tarayıcıyı ve elbette Spring'i okuyan herkesi içerir). Bir bayt [] sadece spesifik değildir. Bir bayttan [] ortam türünü belirlemenin tek yolu koklamak ve tahmin etmektir.

Bir medya türü sağlamak en iyi uygulamadır


Benim için Spring Boot 2.x'te çalışıyor. Paylaşım için teşekkürler.
attacomsian

1

Spring Boot ve Guava ile bunu nasıl yaparım:

@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() );
}

0

İlkbaharda, fasulyede herhangi bir değişiklik yapmanız gerekmez. Dönüş türünüzü yalnızca @ResponseBody olarak işaretleyin.

Misal:-

@RequestMapping(value = "/image/{id}")
    public @ResponseBody
    byte[] showImage(@PathVariable Integer id) {
                 byte[] b;
        /* Do your logic and return 
               */
        return b;
    }

1
Bununla ilgili sorun içerik türü düzgün ayarlanmamış olmasıdır.
ETL

0

Dosya yüklemeyi saklamak ve bu dosyayı almak için bir servise ihtiyacınız olduğunu düşünüyorum. Buradan daha fazla ayrıntı kontrol edin

1) Depolama Sevice Oluşturun

@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) Dosya yüklemek ve almak için Rest Controller oluşturun

@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);
}

}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.