如何在Spring MVC中设置缓存头?

时间:2009-09-01 14:56:31

标签: java spring caching spring-mvc

在基于注释的Spring MVC控制器中,为特定路径设置缓存头的首选方法是什么?

10 个答案:

答案 0 :(得分:65)

我刚遇到同样的问题,并找到了框架已经提供的一个很好的解决方案。 org.springframework.web.servlet.mvc.WebContentInterceptor类允许您定义默认缓存行为,以及特定于路径的覆盖(在其他地方使用相同的路径匹配器行为)。我的步骤是:

  1. 确保我的org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter实例没有设置“cacheSeconds”属性。
  2. 添加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>
    
  3. 在这些更改之后,/ foo下的响应包括阻止缓存的标头,/ cache / me下的响应包括鼓励缓存的标头,以及/ cache / agnostic下的响应包括没有与缓存相关的标头。


    如果使用纯Java配置:

    @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);
      }
    }
    

    另请参阅:http://docs.spring.io/spring-security/site/docs/current/reference/html/headers.html

答案 1 :(得分:29)

答案很简单:

@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); }
}
上面的代码显示了您想要实现的目标。你必须做两件事。添加“final HttpServletResponse response”作为参数。然后将标头Cache-Control设置为no-cache。

答案 2 :(得分:18)

org.springframework.web.servlet.support.WebContentGenerator,它是所有Spring控制器的基类,有很多处理缓存头的方法:

/* 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);

可以在内容生成之前在控制器中调用它们,也可以在Spring上下文中将它们指定为bean属性。

答案 3 :(得分:15)

Spring 4.2开始,您可以这样做:

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对象是一个包含许多配置选项的构建器,请参阅JavaDoc

答案 4 :(得分:10)

您可以使用Handler拦截器并使用它提供的postHandle方法:

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) 

然后只需在方法中添加如下标题:

response.setHeader("Cache-Control", "no-cache");

答案 5 :(得分:4)

您可以为此定义一个anotation:@CacheControl(isPublic = true, maxAge = 300, sMaxAge = 300),然后使用Spring MVC拦截器将此anotation呈现给HTTP Header。或动态:

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);
}

蕴涵可以在这里找到:优雅的Builder模式

BTW:我刚刚发现Spring MVC内置了对缓存控制的支持: 谷歌WebContentInterceptor或CacheControlHandlerInterceptor或CacheControl,你会发现它。

答案 6 :(得分:3)

我知道这是一个非常古老的,但谷歌搜索的人可能有所帮助:

@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);
}

答案 7 :(得分:1)

您可以扩展AnnotationMethodHandlerAdapter以查找自定义缓存控件注释并相应地设置http标头。

答案 8 :(得分:1)

在您的控制器中,您可以直接设置响应标头。

response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);

答案 9 :(得分:0)

我发现WebContentInterceptor是最简单的方法。

@Override
public void addInterceptors(InterceptorRegistry registry)
{
    WebContentInterceptor interceptor = new WebContentInterceptor();
    interceptor.addCacheMapping(CacheControl.noCache(), "/users", "admin");
    registry.addInterceptor(interceptor);
}