How do you set cache headers in Spring MVC?

89,666

Solution 1

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.

Solution 2

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 behaviour, plus path-specific overrides (with the same path-matcher behaviour 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.


If using a pure Java configuration:

@EnableWebMvc
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
  /* Time, in seconds, to have the browser cache static resources (one week). */
  private static final int BROWSER_CACHE_CONTROL = 604800;

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry
     .addResourceHandler("/images/**")
     .addResourceLocations("/images/")
     .setCachePeriod(BROWSER_CACHE_CONTROL);
  }
}

See also: http://docs.spring.io/spring-security/site/docs/current/reference/html/headers.html

Solution 3

The answer is quite simple:

@Controller
public class EmployeeController {
@RequestMapping(value = "/find/employer/{employerId}", method = RequestMethod.GET) public List getEmployees(@PathVariable("employerId") Long employerId, final HttpServletResponse response) { response.setHeader("Cache-Control", "no-cache"); return employeeService.findEmployeesForEmployer(employerId); }
}
Code above shows exactly what you want to achive. You have to do two things. Add "final HttpServletResponse response" as your parameter. And then set header Cache-Control to no-cache.

Solution 4

Starting with Spring 4.2 you can do this:

import org.springframework.http.CacheControl;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class CachingController {
    @RequestMapping(method = RequestMethod.GET, path = "/cachedapi")
    public ResponseEntity<MyDto> getPermissions() {

        MyDto body = new MyDto();

        return ResponseEntity.ok()
            .cacheControl(CacheControl.maxAge(20, TimeUnit.SECONDS))
            .body(body);
    }
}

CacheControl object is a builder with many configuration options, see JavaDoc

Solution 5

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");
Share:
89,666
D. Wroblewski
Author by

D. Wroblewski

Updated on July 05, 2022

Comments

  • D. Wroblewski
    D. Wroblewski almost 2 years

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

  • D. Wroblewski
    D. Wroblewski over 14 years
    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?
  • ChssPly76
    ChssPly76 over 14 years
    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: static.springsource.org/spring/docs/2.5.6/reference/… (disregard the init binder, you don't need it)
  • D. Wroblewski
    D. Wroblewski over 14 years
    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?
  • ChssPly76
    ChssPly76 over 14 years
    I've adressed that in my above comment. If you think you'll find a better solution I wish you luck.
  • D. Wroblewski
    D. Wroblewski over 14 years
    that's why I up-voted your comment. Why didn't you edit your answer instead?
  • yincrash
    yincrash almost 14 years
    this would have to be added to every request. not a good solution for adding the header to all requests across the board.
  • yincrash
    yincrash almost 14 years
    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.
  • Czar
    Czar over 13 years
    I tried to use this for images stored in the DB. I can easily retrieve them. They show up, but FireBug always keeps telling me status "200 Ok", so no caching. Any ideas?
  • Jesse Jashinsky
    Jesse Jashinsky over 11 years
    This won't work because I don't have a prefix of mvc, or p. What are they supposed to be?
  • Eric R. Rath
    Eric R. Rath over 11 years
    Jesse - check the root element of your context def file; you should have a namespace element like 'xmlns:mvc="springframework.org/schema/mvc"', and another attribute named 'xsi:schemaLocation' with a value that includes 'springframework.org/schema/mvc springframework.org/schema/mvc/spring-mvc-3.1.xsd'. See static.springsource.org/spring/docs/3.1.x/… for an example of a typical XML config.
  • BiAiB
    BiAiB over 10 years
    Can you tell which xml namespace p: refers to ?
  • Eric R. Rath
    Eric R. Rath over 10 years
    You should only need to add xmlns:p="http://www.springframework.org/schema/p" as long as you're using the 3.1 xsd.
  • Ryan
    Ryan almost 9 years
    @JesseJ What part didn't work? I tried and it works for me.
  • user590849
    user590849 over 8 years
    This setup is not working for me. I did not do the <p...> thing I explicity mentioned a <property name="cacheSeconds">2345</property>
  • Klesun
    Klesun almost 4 years
    @yincrash, quoting OP: what is the preferred way to set cache headers for a specific path