In an annotation-based Spring MVC controller, what is the preferred way to set cache headers for a specific path?
You could use a Handler Interceptor and use the postHandle method provided by it:
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");
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.
You could extend AnnotationMethodHandlerAdapter to look for a custom cache control annotation and set the http headers accordingly.
Steven Willems encountered the same problem and describes different solutions and one proposal for a new annotation in his blog:
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:
- Ensure my instance of
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
does not have the "cacheSeconds" property set. 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.