Spring MVC: Làm thế nào để trả lại hình ảnh trong @ResponseBody?


142

Tôi đang nhận dữ liệu hình ảnh (như byte[]) từ DB. Làm thế nào để trả lại hình ảnh này trong @ResponseBody?

BIÊN TẬP

Tôi đã làm điều đó mà không @ResponseBodysử dụng HttpServletResponsenhư tham số phương thức:

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

Sử dụng @ResponseBodyvới trình org.springframework.http.converter.ByteArrayHttpMessageConverterchuyển đổi đã đăng ký như @Sid nói không hoạt động đối với tôi :(.

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

Câu trả lời:


97

nếu bạn đang sử dụng phiên bản Spring 3.1 hoặc mới hơn, bạn có thể chỉ định "sản xuất" trong @RequestMappingchú thích. Ví dụ dưới đây làm việc cho tôi ra khỏi hộp. Không cần chuyển đổi đăng ký hoặc bất cứ điều gì khác nếu bạn đã bật 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);
}

77

Với Spring 4.1 trở lên, bạn có thể trả về khá nhiều thứ (như hình ảnh, pdf, tài liệu, bình, khóa, v.v.) khá đơn giản mà không cần phụ thuộc thêm. Ví dụ: sau đây có thể là một phương thức để trả về ảnh hồ sơ của người dùng từ 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()));
}

Những điều cần lưu ý:

  • FeedbackEntity với InputStreamResource là kiểu trả về

  • Tạo kiểu ứng dụng xây dựng FeedbackEntity

Với phương pháp này, bạn không phải lo lắng về việc tự động kích hoạt trong httpServletResponse, ném IOException hoặc sao chép dữ liệu luồng xung quanh.


1
Đây ném ngoại lệ sau đây, làm thế nào bạn serializing MyInputStream ?: Không thể nội dung ghi: Không serializer tìm thấy cho lớp com.mongodb.gridfs.GridFSDBFile $ MyInputStream
Nestor Ledon

Trong khi điều này chủ yếu là một ví dụ về những gì bạn có thể làm, Mongo-Java-Driver 3.0.3 với GridFsDBFile.getInputStream () không trả về một lớp ẩn danh có tên MyInputStream. Tôi sẽ kiểm tra phiên bản của bạn - có lẽ cập nhật?
Jaymes Bearden

4
Tôi thích cách này truyền phát tệp thay vì sao chép toàn bộ nội dung trong bộ nhớ. Xem thêm stackoverflow.com/questions/20333394/
Mạnh

60

Ngoài việc đăng ký a ByteArrayHttpMessageConverter, bạn có thể muốn sử dụng ResponseEntitythay vì @ResponseBody. Đoạn mã sau hoạt động với tôi:

@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

Bằng cách sử dụng Spring 3.1.x và 3.2.x, đây là cách bạn nên làm:

Phương thức điều khiển:

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

Và chú thích mvc trong tệp servlet-bối cảnh:

<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

Ngoài một vài câu trả lời ở đây, một vài gợi ý (Mùa xuân 4.1).

Trong trường hợp bạn không có bất kỳ bộ chuyển đổi lộn xộn nào được cấu hình trong WebMvcConfig của bạn, có ResponseEntitybên trong @ResponseBodyhoạt động tốt.

Nếu bạn làm như vậy, tức là bạn có một MappingJackson2HttpMessageConvertercấu hình (như tôi) bằng cách sử dụng ResponseEntitytrả về a org.springframework.http.converter.HttpMessageNotWritableException.

Giải pháp duy nhất làm việc trong trường hợp này là để bọc một byte[]trong @ResponseBodynhư sau:

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

Trong trường hợp này, hãy nhớ để định cấu hình bộ chuyển đổi messagecon đúng (và thêm a ByteArrayHttpMessageConverer) trong WebMvcConfig của bạn, như vậy:

@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

Trong ngữ cảnh ứng dụng của bạn, hãy khai báo AnnotationMethodHandlerAd CHƯƠNG và 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> 

cũng trong phương thức xử lý thiết lập loại nội dung phù hợp cho phản hồi của bạn.


@jsinghfoss tham khảo câu trả lời hàng đầu.
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);



}

Đã làm cho tôi.


5

Tôi đặt trước cái này:

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

Thay đổi loại phương tiện truyền thông thành định dạng hình ảnh bạn có.


1
Gọi tốt ResourceLoader, nhưng xây dựng một tên đường dẫn từ đầu vào bên ngoài như trong ví dụ của bạn là một ý tưởng tồi: cwe.mitre.org/data/def địnhs / 22.html
qerub

3

Đó là công việc cho tôi vào mùa xuân 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();
        }

}

2

Không có câu trả lời nào phù hợp với tôi, vì vậy tôi đã xoay sở để làm điều đó như thế:

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

Đặt Content-Dispositiontiêu đề Tôi có thể tải xuống tệp với @ResponseBodychú thích trên phương thức của mình.


1

Đây là cách tôi làm với Spring Boot và 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() );
}

1

Bạn nên chỉ định loại phương tiện trong phản hồi. Tôi đang sử dụng chú thích @GetMapping với produc = MediaType.IMAGE_JPEG_VALUE. @RequestMapping sẽ hoạt động tương tự.

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

Nếu không có loại phương tiện, thật khó để đoán những gì thực sự được trả lại (bao gồm bất kỳ ai đọc mã, trình duyệt và tất nhiên là chính Spring). Một byte [] chỉ không cụ thể. Cách duy nhất để xác định loại phương tiện từ một byte [] là đánh hơi và đoán xung quanh.

Cung cấp một loại phương tiện truyền thông chỉ là thực hành tốt nhất


Nó hoạt động với tôi trong Spring Boot 2.x. Cảm ơn bạn đã chia sẻ.
attacomsian

0

Vào mùa xuân 4, rất dễ dàng, bạn không cần thực hiện bất kỳ thay đổi nào trong đậu. Chỉ đánh dấu loại trả về của bạn thành @ResponseBody.

Thí dụ:-

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

1
Vấn đề tôi gặp phải với điều này là loại nội dung không được đặt đúng.
ETL

0

Tôi nghĩ rằng bạn có thể cần một dịch vụ để lưu trữ tệp tải lên và nhận tệp đó. Kiểm tra chi tiết hơn từ đây

1) Tạo dịch vụ lưu trữ

@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) Tạo Trình điều khiển nghỉ để tải lên và nhận tệp

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

}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.