Spring MVC : @ResponseBody에서 이미지를 반환하는 방법은 무엇입니까?


142

byte[]DB에서 이미지 데이터 ( )를 가져옵니다. 이 이미지를 어떻게 반환 @ResponseBody합니까?

편집하다

메소드 매개 변수로 @ResponseBody사용 하지 않고 수행했습니다 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 @ResponseBody가 등록 된 org.springframework.http.converter.ByteArrayHttpMessageConverter변환기 와 함께 사용하면 작동하지 않습니다 :(.

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

답변:


97

3.1 이상의 Spring 버전을 사용하는 경우 @RequestMapping주석에 "produces"를 지정할 수 있습니다 . 아래 예제는 즉시 사용할 수 있습니다. 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);
}

78

Spring 4.1 이상을 사용하면 추가 종속성없이 거의 모든 것을 (예 : 그림, pdf, 문서, 항아리, 우편 번호 등) 반환 할 수 있습니다. 예를 들어 다음은 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()));
}

참고 사항 :

  • InputStreamResource를 리턴 유형으로하는 ResponseEntity

  • ResponseEntity 빌더 스타일 작성

이 방법을 사용하면 HttpServletResponse의 자동 배선, IOException 발생 또는 스트림 데이터 복사에 대해 걱정할 필요가 없습니다.


1
이것은 다음과 같은 예외가 발생합니다, 당신은? 쓰기 내용을 MyInputStream을 할 수 없습니다 직렬화 방법 : 없음 시리얼 클래스 com.mongodb.gridfs.GridFSDBFile $ MyInputStream에 대한 발견
네스터 LEDON

이것은 주로 가능한 일의 예이지만 GridFsDBFile.getInputStream ()을 사용하는 Mongo-Java-Driver 3.0.3은 MyInputStream이라는 익명 클래스를 반환하지 않습니다. 나는 당신의 버전을 확인합니다-아마도 업데이트?
Jaymes Bearden 2012 년

4
나는 이것이 메모리에 모든 것을 복사하는 대신 파일을 스트리밍하는 방법을 좋아합니다. 또한 참조 stackoverflow.com/questions/20333394/...
빔 Deblauwe에게

60

을 등록하는 ByteArrayHttpMessageConverter것 외에도을 (를) ResponseEntity대신 사용할 수 있습니다 @ResponseBody. 다음 코드는 저에게 효과적입니다.

@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 및 3.2.x를 사용하면 다음과 같이해야합니다.

컨트롤러 방법 :

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

servlet-context.xml 파일의 mvc 주석 :

<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

여기에 몇 가지 대답 외에도 몇 가지 지침 (Spring 4.1)이 있습니다.

당신이 가진, 당신의 WebMvcConfig에 구성된 모든 messageconverters이없는 못했을 경우에 대비 ResponseEntity하여 내부에서 @ResponseBody잘 작동합니다.

당신이하는 경우, 즉 당신은 반환을 MappingJackson2HttpMessageConverter사용하여 (나와 같이) 구성 ResponseEntity했습니다 org.springframework.http.converter.HttpMessageNotWritableException.

이 경우 작동하는 유일한 해결책은 다음과 같이 포장하는 것 byte[]입니다 @ResponseBody.

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

이 경우 다음 ByteArrayHttpMessageConverer과 같이 WebMvcConfig에서 메시지 변환기를 올바르게 구성하고를 추가 하십시오.

@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

응용 프로그램 컨텍스트에서 AnnotationMethodHandlerAdapter 및 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> 

또한 핸들러 메소드에서 응답에 적합한 컨텐츠 유형을 설정하십시오.


@jsinghfoss는 최고의 답변을 나타냅니다.
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);



}

나를 위해 일했다.


5

나는 이것을 선호한다 :

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

미디어 유형을 현재 이미지 형식으로 변경하십시오.


1
호출은 ResourceLoader좋지만 예제와 같이 외부 입력에서 경로 이름을 구성하는 것은 좋지 않습니다. cwe.mitre.org/data/definitions/22.html
qerub

3

그것은 봄 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

대답 중 하나가 저에게 효과적이지 않으므로 다음과 같이 관리했습니다.

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헤더 설정 @ResponseBody방법에 주석이 달린 파일을 다운로드 할 수있었습니다 .


2

응답에 미디어 유형을 지정해야합니다. produce = MediaType.IMAGE_JPEG_VALUE와 함께 @GetMapping 주석을 사용하고 있습니다. @RequestMapping도 동일하게 작동합니다.

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

미디어 타입이 없다면 실제로 리턴되는 것을 추측하기 어렵다 (코드, 브라우저, 물론 Spring 자체를 읽는 사람 포함). 바이트 []는 구체적이지 않습니다. byte []에서 미디어 타입을 결정하는 유일한 방법은 스니핑과 추측입니다.

미디어 유형을 제공하는 것이 가장 좋습니다


Spring Boot 2.x에서 작동합니다. 공유해 주셔서 감사합니다.
attacomsian

1

이것이 Spring Boot와 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() );
}

0

봄 4에서는 콩을 변경할 필요가 없습니다. 반환 유형을 @ResponseBody로만 표시하십시오.

예:-

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

1
문제는 콘텐츠 유형이 올바르게 설정되지 않은 것입니다.
ETL

0

파일 업로드를 저장하고 해당 파일을 가져 오기 위해 서비스가 필요하다고 생각합니다. 여기 에서 자세한 내용을 확인 하십시오

1) 스토리지 서비스 생성

@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) Rest Controller를 생성하여 파일 업로드 및 가져 오기

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

}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.