Interceptorを使ってResponse Headerをセットする

# 概要

ハンドラーメソッド（コントローラークラスのメソッド）に付加したマーカーアノテーションを判別してResponse HeaderにCache-Controlをセットするサンプルコードです。

**環境**

* Windows10 Professional
* Java 1.8.0_101
* Spring Boot 1.4.1
 * Spring Framework 4.3.3

**参考**

* [InterceptorRegistry] (http://docs.spring.io/spring/docs/4.3.3.RELEASE/javadoc-api/org/springframework/web/servlet/config/annotation/InterceptorRegistry.html)
* [HandlerInterceptorAdapter] (http://docs.spring.io/spring/docs/4.3.3.RELEASE/javadoc-api/org/springframework/web/servlet/handler/HandlerInterceptorAdapter.html)
* [ブラウザのキャッシュコントロールを正しく理解する] (http://qiita.com/hkusu/items/d40aa8a70bacd2015dfa)
* [[spring mvc]ロケールをURL(パス)の一部で切り替える] (http://zero-config.com/java/spring-002.html)

# サンプルコード

## Interceptor

HandlerInterceptorAdapterを継承して独自のInterceptorを実装します。

```java:MyCustomHandlerInterceptor
public class MyCustomHandlerInterceptor extends HandlerInterceptorAdapter {

  @Override
  public void postHandle(HttpServletRequest request
                       , HttpServletResponse response
                       , Object handler
                       , ModelAndView modelAndView) throws Exception {
    if (!(handler instanceof HandlerMethod)) {
      return;
    }

    HandlerMethod handlerMethod = (HandlerMethod) handler;

    if (handlerMethod.hasMethodAnnotation(NoCacheAnnotation.class)) {
      addNoCacheHeaders(response);

    } else if (handlerMethod.hasMethodAnnotation(CacheAnnotation.class)) {
      CacheAnnotation annotation = handlerMethod.getMethodAnnotation(CacheAnnotation.class);
      int maxAge = (int) AnnotationUtils.getValue(annotation, "maxAge");
      addCacheHeaders(response, maxAge);
    }

  }

  private void addNoCacheHeaders(HttpServletResponse response) {
    response.addHeader("Cache-Control", "no-store");
  }

  private void addCacheHeaders(HttpServletResponse response, int maxAge) {
    response.addHeader("Cache-Control", "max-age=" + maxAge);
    //response.addDateHeader("Expires", new Date().getTime() + (long)(maxAge * 1000));
  }

}
```

## Annotation

Response Headerを付加するかどうかを判別するマーカーアノテーションを実装します。
このアノテーションはハンドラーメソッドに付加します。

キャッシュしないハンドラーメソッド用のアノテーション

```java:NoCacheAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface NoCacheAnnotation {
}
```

キャッシュするハンドラーメソッド用のアノテーション

```java:CacheAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface CacheAnnotation {
  public int maxAge();
}
```

## Configuration

WebMvcConfigurerAdapterを継承したクラスを実装して独自のInterceptorを登録します。

```java
@Configuration
public class MyWebMvcConfigurer extends WebMvcConfigurerAdapter {
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new MyCustomHandlerInterceptor())
      .addPathPatterns("/**")
      .excludePathPatterns("/static/**");
  }
}
```

## Controller

検証用のコントローラーです。

```java
@Controller
@RequestMapping(value = "/cache")
public class CacheController {

  @CacheAnnotation(maxAge = 600)
  @RequestMapping(value = "/cache", method = RequestMethod.GET)
  public String cache() {
    return "cache/cache";
  }

  @NoCacheAnnotation
  @RequestMapping(value = "/nocache", method = RequestMethod.GET)
  public String noCache() {
    return "cache/nocache";
  }

  @RequestMapping(value = "/nothing", method = RequestMethod.GET)
  public String nothing() {
    return "cache/nothing";
  }

}
```

### Response Headers

**/cache/cache**

```text
Cache-Control:max-age=600
Content-Language:ja
Content-Type:text/html;charset=UTF-8
Date:Tue, 08 Nov 2016 17:19:50 GMT
```

**/cache/nocache**

```text
HTTP/1.1 200
Cache-Control: no-store
Content-Type: text/html;charset=UTF-8
Content-Language: ja
Transfer-Encoding: chunked
Date: Tue, 08 Nov 2016 17:23:45 GMT
```

**/cache/nothing**

```text
HTTP/1.1 200
Content-Type: text/html;charset=UTF-8
Content-Language: ja
Transfer-Encoding: chunked
Date: Tue, 08 Nov 2016 17:23:24 GMT
```