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

キャッシュマネージャーにキャッシュResponseEntityを追加し、その内部にInputStreamResourceを追加します。初めてOKです。しかし、キャッシュResponseEntityが1回以上ストリームを読み取ることができないので、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フォルダを持っているように私には思える、そしてあなた毎日のキャッシュを持ちたいと思っているので、ディスクから常にロードする必要はありません。

これが当てはまる場合は、FileのコンテンツをByteArrayに読み込み、その代わりにキャッシュ/返すことをお勧めします。

+0

あなたの前提は完全に正しいです。 – membersound

関連する問題