In an annotation-based Spring MVC controller, what is the preferred way to set cache headers for a specific path?
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.
I know this is a really old one, but those who are googling, this might help:
@Override
protected void addInterceptors(InterceptorRegistry registry) {
WebContentInterceptor interceptor = new WebContentInterceptor();
Properties mappings = new Properties();
mappings.put("/", "2592000");
mappings.put("/admin", "-1");
interceptor.setCacheMappings(mappings);
registry.addInterceptor(interceptor);
}
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:
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.
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
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
you can define a anotation for this: @CacheControl(isPublic = true, maxAge = 300, sMaxAge = 300)
, then render this anotation to HTTP Header with Spring MVC interceptor. or do it dynamic:
int age = calculateLeftTiming();
String cacheControlValue = CacheControlHeader.newBuilder()
.setCacheType(CacheType.PUBLIC)
.setMaxAge(age)
.setsMaxAge(age).build().stringValue();
if (StringUtils.isNotBlank(cacheControlValue)) {
response.addHeader("Cache-Control", cacheControlValue);
}
Implication can be found here: 优雅的Builder模式
BTW: I just found that Spring MVC has build-in support for cache control: Google WebContentInterceptor or CacheControlHandlerInterceptor or CacheControl, you will find it.
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");