1

이미지를 InputStreamResource으로 리턴하는 서블릿이 있습니다. 일부 get query 매개 변수를 기반으로 반환되는 약 50 개의 정지 이미지가 있습니다.RestController에서 InputStreamResource를 캐시하는 방법은 무엇입니까?

이러한 이미지 (매우 자주)이 요청 될 때마다 각을 찾아 볼 필요가없는 경우

, 나는 그 이미지 응답을 캐시하고 싶습니다.

@RestController 
public class MyRestController { 
    //code is just example; may be any number of parameters 
    @RequestMapping("/{code}") 
    @Cachable("code.cache") 
    public ResponseEntity<InputStreamResource> getCodeLogo(@PathVariable("code") String code) { 
     FileSystemResource file = new FileSystemResource("d:/images/" + code + ".jpg"); 
     return ResponseEntity.ok() 
      .contentType("image/jpg") 
      .lastModified(file.lastModified()) 
      .contentLength(file.contentLength()) 
      .body(new InputStreamResource(file.getInputStream())); 

    } 
} 

다음과 같은 예외지고, I_'m을합니다 (RestMapping 방법에 경우 직접 상관없이 또는 외부 서비스에 리팩토링)을 @Cacheable 주석을 사용하여 :

cause: java.lang.IllegalStateException: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times - error: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times 
org.springframework.core.io.InputStreamResource.getInputStream(InputStreamResource.java:96) 
org.springframework.http.converter.ResourceHttpMessageConverter.writeInternal(ResourceHttpMessageConverter.java:100) 
org.springframework.http.converter.ResourceHttpMessageConverter.writeInternal(ResourceHttpMessageConverter.java:47) 
org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:195) 
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:238) 
org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:183) 
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81) 
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126) 
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:832) 
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:743) 

질문을 : 어떻게 그런 다음 InputStreamResource 유형의 ResponseEntity을 캐시합니다.

+0

한 번만 읽어야합니까? 또는 디스크의 파일을 변경 사항에 대해 모니터링해야합니까? – Niels

+0

밤이나 매주와 같이 고정 된 기간에'@ EvictCache'를 호출하고 싶습니다. 따라서 일반적으로 한 번만 준비한 다음 파일을 로컬에서 검색하지 않고 다시 사용해야합니다. – membersound

+3

지우기. 그렇지 않으면 컨트롤러 초기화 중에 한 번 파일을 읽고 ByteArrayResource에로드 할 수 있습니다. – Niels

답변

2

캐시 관리자는 내부 InputStreamResource와 캐시 ResponseEntity에 추가됩니다. 처음에는 괜찮을거야. 그러나 캐시 된 ResponseEntity은 한 번 이상 스트림을 읽을 수 없기 때문에 두 번째로 InputStreamResouce을 읽으려고하면 예외가 발생합니다.

해결 방법 : InputStreamResouce 자체를 캐시하지만, 스트림의 내용을 캐시하지 않습니다.

@RestController 
public class MyRestController {  
    @RequestMapping("/{code}") 
    @Cachable("code.cache") 
    public ResponseEntity<byte[]> getCodeLogo(@PathVariable("code") String code) { 
     FileSystemResource file = new FileSystemResource("d:/images/" + code + ".jpg"); 

     byte [] content = new byte[(int)file.contentLength()]; 
     IOUtils.read(file.getInputStream(), content); 

     return ResponseEntity.ok() 
      .contentType(MediaType.IMAGE_JPEG) 
      .lastModified(file.lastModified()) 
      .contentLength(file.contentLength()) 
      .body(content); 
    } 
} 

나는 배열에 스트림에서 바이트를 복사, org.apache.commons.io에서 IOUtils.read()을 사용했지만, 당신은 어떤 선호하는 방법으로 그것을 할 수 있습니다.

1

당신은 스트림을 캐시 할 수 있습니다. 일단 그들이 읽히면, 그들은 없어집니다. 오류 메시지가 그것에 대해 매우 분명하다 : 코드 및 설명으로

InputStream has already been read - 
do not use InputStreamResource if a stream needs to be read multiple times 

, 당신이 (추가, 삭제 또는 수정 될 수 있습니다) JPG 로고와 큰 images 폴더가 나에게 것, 그리고 당신 하나의 당신이 요청을 받고있어의 매일 캐시를 갖고 싶어, 그래서 당신은 항상 디스크에서 다시로드 할 필요가 없습니다. 그런 경우에는

, 당신의 최선의 선택은 그 대신 ByteArray의 캐시/반품에 파일의 내용을 읽을 것입니다.

+0

전제가 완전히 틀립니다. – membersound

관련 문제