views:

2336

answers:

6

In an annotation-based Spring MVC controller, what is the preferred way to set cache headers for a specific path?

+2  A: 

You could use a Handler Interceptor and use the postHandle method provided by it:

http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/web/servlet/HandlerInterceptor.html

postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

then just add a header as follows in the method:

response.setHeader("Cache-Control", "no-cache");
Jon
+1  A: 

org.springframework.web.servlet.support.WebContentGenerator, which is the base class for all Spring controllers has quite a few methods dealing with cache headers:

/* Set whether to use the HTTP 1.1 cache-control header. Default is "true".
 * <p>Note: Cache headers will only get applied if caching is enabled
 * (or explicitly prevented) for the current request. */
public final void setUseCacheControlHeader();

/* Return whether the HTTP 1.1 cache-control header is used. */
public final boolean isUseCacheControlHeader();

/* Set whether to use the HTTP 1.1 cache-control header value "no-store"
 * when preventing caching. Default is "true". */
public final void setUseCacheControlNoStore(boolean useCacheControlNoStore);

/* Cache content for the given number of seconds. Default is -1,
 * indicating no generation of cache-related headers.
 * Only if this is set to 0 (no cache) or a positive value (cache for
 * this many seconds) will this class generate cache headers.
 * The headers can be overwritten by subclasses, before content is generated. */
public final void setCacheSeconds(int seconds);

They can either be invoked within your controller prior to content generation or specified as bean properties in Spring context.

ChssPly76
But, as I wrote in my question, I use an annotation-based controller that doesn't subclass from any spring base class. How will this help me?
D. Wroblewski
If you want to alter cache settings depending on **specific path**, extending `AbstractController` is by far the easiest solution. If you want to apply your cache settings to all controllers, you can specify them on `AnnotationMethodHandlerAdapter` instance in Spring context for annotation-based controllers. Here's an example: http://static.springsource.org/spring/docs/2.5.6/reference/mvc.html#mvc-ann-initbinder (disregard the init binder, you don't need it)
ChssPly76
Why the downvote?
ChssPly76
Because my question concerned how to do this with an annotations-based controller. Your solution only applies to controllers that subclass WebContentGenerator. Isn't it so?
D. Wroblewski
I've adressed that in my above comment. If you think you'll find a better solution I wish you luck.
ChssPly76
that's why I up-voted your comment. Why didn't you edit your answer instead?
D. Wroblewski
To clarify, AnnotationMethodHandlerAdapter does extend WebContentGenerator which gives you all the cache header options. Remember, you need to set <property name="cacheSeconds" value="0" /> or a positive value for any of the cache headers to show up.
yincrash
A: 
goroncy
this would have to be added to every request. not a good solution for adding the header to all requests across the board.
yincrash
A: 

You could extend AnnotationMethodHandlerAdapter to look for a custom cache control annotation and set the http headers accordingly.

Alex M
A: 

Steven Willems encountered the same problem and describes different solutions and one proposal for a new annotation in his blog:

the blog entry spring-mvc-3-0-http-cache-control-headers

risadinha
+1  A: 

I just encountered the same problem, and found a good solution already provided by the framework. The org.springframework.web.servlet.mvc.WebContentInterceptor class allows you to define default caching behavior, plus path-specific overrides (with the same path-matcher behavior used elsewhere). The steps for me were:

  1. Ensure my instance of org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter does not have the "cacheSeconds" property set.
  2. Add an instance of WebContentInterceptor:

    <mvc:interceptors>
    ...
    <bean class="org.springframework.web.servlet.mvc.WebContentInterceptor" p:cacheSeconds="0" p:alwaysUseFullPath="true" >
        <property name="cacheMappings">
            <props>
                <!-- cache for one month -->
                <prop key="/cache/me/**">2592000</prop>
                <!-- don't set cache headers -->
                <prop key="/cache/agnostic/**">-1</prop>
            </props>
        </property>
    </bean>
    ...
    </mvc-interceptors>
    

After these changes, responses under /foo included headers to discourage caching, responses under /cache/me included headers to encourage caching, and responses under /cache/agnostic included no cache-related headers.

Eric Rath