Streamlined WebContentGenerator API variants: checkRequest, prepareResponse, applyCacheControl, applyCacheSeconds
Issue: SPR-11792
This commit is contained in:
parent
b277c081e7
commit
7c22d60fd8
|
@ -25,7 +25,7 @@ import org.springframework.web.servlet.support.WebContentGenerator;
|
|||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
* <p>Convenient superclass for controller implementations, using the Template Method
|
||||
* Convenient superclass for controller implementations, using the Template Method
|
||||
* design pattern.
|
||||
*
|
||||
* <p><b><a name="workflow">Workflow
|
||||
|
@ -130,7 +130,8 @@ public abstract class AbstractController extends WebContentGenerator implements
|
|||
throws Exception {
|
||||
|
||||
// Delegate to WebContentGenerator for checking and preparing.
|
||||
checkAndPrepare(request, response);
|
||||
checkRequest(request);
|
||||
prepareResponse(response);
|
||||
|
||||
// Execute handleRequestInternal in synchronized block if required.
|
||||
if (this.synchronizeOnSession) {
|
||||
|
@ -152,6 +153,6 @@ public abstract class AbstractController extends WebContentGenerator implements
|
|||
* @see #handleRequest
|
||||
*/
|
||||
protected abstract ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception;
|
||||
throws Exception;
|
||||
|
||||
}
|
||||
|
|
|
@ -35,13 +35,14 @@ import org.springframework.web.servlet.support.WebContentGenerator;
|
|||
import org.springframework.web.util.UrlPathHelper;
|
||||
|
||||
/**
|
||||
* Interceptor that checks and prepares request and response. Checks for supported
|
||||
* methods and a required session, and applies the specified {@link org.springframework.http.CacheControl}.
|
||||
* Handler interceptor that checks the request and prepares the response.
|
||||
* Checks for supported methods and a required session, and applies the
|
||||
* specified {@link org.springframework.http.CacheControl} builder.
|
||||
* See superclass bean properties for configuration options.
|
||||
*
|
||||
* <p>All the settings supported by this interceptor can also be set on AbstractController.
|
||||
* This interceptor is mainly intended for applying checks and preparations to a set of
|
||||
* controllers mapped by a HandlerMapping.
|
||||
* <p>All the settings supported by this interceptor can also be set on
|
||||
* {@link AbstractController}. This interceptor is mainly intended for applying
|
||||
* checks and preparations to a set of controllers mapped by a HandlerMapping.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Brian Clozel
|
||||
|
@ -58,9 +59,10 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
|
|||
|
||||
private Map<String, CacheControl> cacheControlMappings = new HashMap<String, CacheControl>();
|
||||
|
||||
|
||||
public WebContentInterceptor() {
|
||||
// no restriction of HTTP methods by default,
|
||||
// in particular for use with annotated controllers
|
||||
// No restriction of HTTP methods by default,
|
||||
// in particular for use with annotated controllers...
|
||||
super(false);
|
||||
}
|
||||
|
||||
|
@ -134,11 +136,9 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
|
|||
* <p>Overrides the default cache seconds setting of this interceptor.
|
||||
* Can specify a empty {@link org.springframework.http.CacheControl} instance
|
||||
* to exclude a URL path from default caching.
|
||||
*
|
||||
* <p>Supports direct matches, e.g. a registered "/test" matches "/test",
|
||||
* and a various Ant-style pattern matches, e.g. a registered "/t*" matches
|
||||
* both "/test" and "/team". For details, see the AntPathMatcher javadoc.
|
||||
*
|
||||
* @param cacheControl the {@code CacheControl} to use
|
||||
* @param paths URL paths that will map to the given {@code CacheControl}
|
||||
* @see #setCacheSeconds
|
||||
|
@ -151,7 +151,6 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the PathMatcher implementation to use for matching URL paths
|
||||
* against registered URL patterns, for determining cache mappings.
|
||||
|
@ -168,7 +167,9 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
|
|||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws ServletException {
|
||||
throws ServletException {
|
||||
|
||||
checkRequest(request);
|
||||
|
||||
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
@ -181,19 +182,19 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
|
|||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Applying CacheControl to [" + lookupPath + "]");
|
||||
}
|
||||
checkAndPrepare(request, response, cacheControl);
|
||||
applyCacheControl(response, cacheControl);
|
||||
}
|
||||
else if (cacheSeconds != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Applying CacheControl to [" + lookupPath + "]");
|
||||
}
|
||||
checkAndPrepare(request, response, cacheSeconds);
|
||||
applyCacheSeconds(response, cacheSeconds);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Applying default cache seconds to [" + lookupPath + "]");
|
||||
}
|
||||
checkAndPrepare(request, response);
|
||||
prepareResponse(response);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -209,10 +210,10 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
|
|||
* @see org.springframework.util.AntPathMatcher
|
||||
*/
|
||||
protected CacheControl lookupCacheControl(String urlPath) {
|
||||
// direct match?
|
||||
// Direct match?
|
||||
CacheControl cacheControl = this.cacheControlMappings.get(urlPath);
|
||||
if (cacheControl == null) {
|
||||
// pattern match?
|
||||
// Pattern match?
|
||||
for (String registeredPath : this.cacheControlMappings.keySet()) {
|
||||
if (this.pathMatcher.match(registeredPath, urlPath)) {
|
||||
cacheControl = this.cacheControlMappings.get(registeredPath);
|
||||
|
@ -232,10 +233,10 @@ public class WebContentInterceptor extends WebContentGenerator implements Handle
|
|||
* @see org.springframework.util.AntPathMatcher
|
||||
*/
|
||||
protected Integer lookupCacheSeconds(String urlPath) {
|
||||
// direct match?
|
||||
// Direct match?
|
||||
Integer cacheSeconds = this.cacheMappings.get(urlPath);
|
||||
if (cacheSeconds == null) {
|
||||
// pattern match?
|
||||
// Pattern match?
|
||||
for (String registeredPath : this.cacheMappings.keySet()) {
|
||||
if (this.pathMatcher.match(registeredPath, urlPath)) {
|
||||
cacheSeconds = this.cacheMappings.get(registeredPath);
|
||||
|
|
|
@ -138,8 +138,7 @@ import org.springframework.web.util.WebUtils;
|
|||
* @see #setMethodNameResolver
|
||||
* @see #setWebBindingInitializer
|
||||
* @see #setSessionAttributeStore
|
||||
*
|
||||
* @deprecated in Spring 3.2 in favor of
|
||||
* @deprecated as of Spring 3.2, in favor of
|
||||
* {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter RequestMappingHandlerAdapter}
|
||||
*/
|
||||
@Deprecated
|
||||
|
@ -411,13 +410,10 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
|
|||
}
|
||||
|
||||
if (annotatedWithSessionAttributes) {
|
||||
// Always prevent caching in case of session attribute management.
|
||||
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers);
|
||||
// Prepare cached set of session attributes names.
|
||||
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
|
||||
}
|
||||
else {
|
||||
// Uses configured default cacheSeconds setting.
|
||||
checkAndPrepare(request, response);
|
||||
checkAndPrepare(request, response, true);
|
||||
}
|
||||
|
||||
// Execute invokeHandlerMethod in synchronized block if required.
|
||||
|
|
|
@ -705,13 +705,13 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
|
|||
protected ModelAndView handleInternal(HttpServletRequest request,
|
||||
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
|
||||
|
||||
checkRequest(request);
|
||||
|
||||
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
|
||||
// Always prevent caching in case of session attribute management.
|
||||
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers);
|
||||
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
|
||||
}
|
||||
else {
|
||||
// Uses configured default cacheSeconds setting.
|
||||
checkAndPrepare(request, response);
|
||||
prepareResponse(response);
|
||||
}
|
||||
|
||||
// Execute invokeHandlerMethod in synchronized block if required.
|
||||
|
|
|
@ -39,9 +39,7 @@ import org.springframework.core.io.Resource;
|
|||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpRange;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
@ -52,6 +50,8 @@ import org.springframework.util.StreamUtils;
|
|||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.HttpRequestHandler;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.support.WebContentGenerator;
|
||||
|
||||
|
@ -91,7 +91,8 @@ import org.springframework.web.servlet.support.WebContentGenerator;
|
|||
* @author Arjen Poutsma
|
||||
* @since 3.0.4
|
||||
*/
|
||||
public class ResourceHttpRequestHandler extends WebContentGenerator implements HttpRequestHandler, InitializingBean, CorsConfigurationSource {
|
||||
public class ResourceHttpRequestHandler extends WebContentGenerator
|
||||
implements HttpRequestHandler, InitializingBean, CorsConfigurationSource {
|
||||
|
||||
private static final String CONTENT_ENCODING = "Content-Encoding";
|
||||
|
||||
|
@ -171,6 +172,12 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
|
|||
this.corsConfiguration = corsConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
|
||||
return this.corsConfiguration;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (logger.isWarnEnabled() && CollectionUtils.isEmpty(this.locations)) {
|
||||
|
@ -180,11 +187,6 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
|
|||
initAllowedLocations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
|
||||
return corsConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a {@link org.springframework.web.servlet.resource.PathResourceResolver}
|
||||
* among the {@link #getResourceResolvers() resource resolvers} and configure
|
||||
|
@ -207,6 +209,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes a resource request.
|
||||
* <p>Checks for the existence of the requested resource in the configured list of locations.
|
||||
|
@ -223,9 +226,10 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
|
|||
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
checkAndPrepare(request, response);
|
||||
// Supported methods and required session
|
||||
checkRequest(request);
|
||||
|
||||
// check whether a matching resource exists
|
||||
// Check whether a matching resource exists
|
||||
Resource resource = getResource(request);
|
||||
if (resource == null) {
|
||||
logger.trace("No matching resource found - returning 404");
|
||||
|
@ -233,13 +237,16 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
|
|||
return;
|
||||
}
|
||||
|
||||
// header phase
|
||||
// Header phase
|
||||
if (new ServletWebRequest(request, response).checkNotModified(resource.lastModified())) {
|
||||
logger.trace("Resource not modified - returning 304");
|
||||
return;
|
||||
}
|
||||
|
||||
// check the resource's media type
|
||||
// Apply cache settings, if any
|
||||
prepareResponse(response);
|
||||
|
||||
// Check the resource's media type
|
||||
MediaType mediaType = getMediaType(resource);
|
||||
if (mediaType != null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
|
@ -252,7 +259,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
|
|||
}
|
||||
}
|
||||
|
||||
// content phase
|
||||
// Content phase
|
||||
if (METHOD_HEAD.equals(request.getMethod())) {
|
||||
setHeaders(response, resource, mediaType);
|
||||
logger.trace("HEAD request - skipping content");
|
||||
|
@ -532,15 +539,12 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
|
|||
}
|
||||
|
||||
private void copyRange(InputStream in, OutputStream out, long start, long end) throws IOException {
|
||||
|
||||
long skipped = in.skip(start);
|
||||
|
||||
if (skipped < start) {
|
||||
throw new IOException("Skipped only " + skipped + " bytes out of " + start + " required.");
|
||||
}
|
||||
|
||||
long bytesToCopy = end - start + 1;
|
||||
|
||||
byte buffer[] = new byte[StreamUtils.BUFFER_SIZE];
|
||||
while (bytesToCopy > 0) {
|
||||
int bytesRead = in.read(buffer);
|
||||
|
@ -561,8 +565,7 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ResourceHttpRequestHandler [locations=" +
|
||||
getLocations() + ", resolvers=" + getResourceResolvers() + "]";
|
||||
return "ResourceHttpRequestHandler [locations=" + getLocations() + ", resolvers=" + getResourceResolvers() + "]";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,22 +16,18 @@
|
|||
|
||||
package org.springframework.web.servlet.support;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.HttpSessionRequiredException;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.web.context.support.WebApplicationObjectSupport;
|
||||
|
||||
/**
|
||||
|
@ -41,19 +37,22 @@ import org.springframework.web.context.support.WebApplicationObjectSupport;
|
|||
* Can also be used for custom handlers that have their own
|
||||
* {@link org.springframework.web.servlet.HandlerAdapter}.
|
||||
*
|
||||
* <p>Supports HTTP cache control options. The usage of corresponding
|
||||
* HTTP headers can be controlled via the "setCacheSeconds" or "setCacheControl" properties.
|
||||
* As of 4.2, its default behavior changed when using only {@link #setCacheSeconds(int)}, sending
|
||||
* HTTP response headers that are more in line with current browsers and proxies implementations.
|
||||
* <p>Supports HTTP cache control options. The usage of corresponding HTTP
|
||||
* headers can be controlled via the {@link #setCacheSeconds "cacheSeconds"
|
||||
* and {@link #setCacheControl "cacheControl"} properties.
|
||||
*
|
||||
* <p>Reverting to the previous behavior can be easily done by using one of the nealy deprecated methods
|
||||
* {@link #setUseExpiresHeader}, {@link #setUseCacheControlHeader}, {@link #setUseCacheControlNoStore} or
|
||||
* {@link #setAlwaysMustRevalidate}.
|
||||
* <p><b>NOTE:</b> As of Spring 4.2, this generator's default behavior changed when
|
||||
* using only {@link #setCacheSeconds)}, sending HTTP response headers that are in line
|
||||
* with current browsers and proxies implementations (i.e. no HTTP 1.0 headers anymore)
|
||||
* Reverting to the previous behavior can be easily done by using one of the newly
|
||||
* deprecated methods {@link #setUseExpiresHeader}, {@link #setUseCacheControlHeader},
|
||||
* {@link #setUseCacheControlNoStore} or {@link #setAlwaysMustRevalidate}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Brian Clozel
|
||||
* @see #setCacheSeconds
|
||||
* @see #setCacheControl
|
||||
* @see #setRequireSession
|
||||
*/
|
||||
public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
||||
|
@ -79,10 +78,12 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||
|
||||
private boolean requireSession = false;
|
||||
|
||||
private CacheControl cacheControl;
|
||||
|
||||
private int cacheSeconds = -1;
|
||||
|
||||
/** Use HTTP 1.0 expires header? */
|
||||
private boolean useExpiresHeader = true;
|
||||
private boolean useExpiresHeader = false;
|
||||
|
||||
/** Use HTTP 1.1 cache-control header? */
|
||||
private boolean useCacheControlHeader = true;
|
||||
|
@ -92,10 +93,6 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||
|
||||
private boolean alwaysMustRevalidate = false;
|
||||
|
||||
private boolean usePreviousHttpCachingBehavior = false;
|
||||
|
||||
private CacheControl cacheControl;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new WebContentGenerator which supports
|
||||
|
@ -167,40 +164,60 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||
/**
|
||||
* Set the {@link org.springframework.http.CacheControl} instance to build
|
||||
* the Cache-Control HTTP response header.
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
public void setCacheControl(CacheControl cacheControl) {
|
||||
public final void setCacheControl(CacheControl cacheControl) {
|
||||
this.cacheControl = cacheControl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link org.springframework.http.CacheControl} instance
|
||||
* that builds the Cache-Control HTTP response header.
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
public CacheControl getCacheControl() {
|
||||
return cacheControl;
|
||||
public final CacheControl getCacheControl() {
|
||||
return this.cacheControl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use the HTTP 1.0 expires header. Default is "false".
|
||||
* Cache content for the given number of seconds, by writing
|
||||
* cache-related HTTP headers to the response:
|
||||
* <ul>
|
||||
* <li>seconds == -1 (default value): no generation cache-related headers</li>
|
||||
* <li>seconds == 0: "Cache-Control: no-store" will prevent caching</li>
|
||||
* <li>seconds > 0: "Cache-Control: max-age=seconds" will ask to cache content</li>
|
||||
* </ul>
|
||||
* <p>For more specific needs, a custom {@link org.springframework.http.CacheControl}
|
||||
* should be used.
|
||||
* @see #setCacheControl
|
||||
*/
|
||||
public final void setCacheSeconds(int seconds) {
|
||||
this.cacheSeconds = seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of seconds that content is cached.
|
||||
*/
|
||||
public final int getCacheSeconds() {
|
||||
return this.cacheSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use the HTTP 1.0 expires header. Default is "false",
|
||||
* as of 4.2.
|
||||
* <p>Note: Cache headers will only get applied if caching is enabled
|
||||
* (or explicitly prevented) for the current request.
|
||||
*
|
||||
* @deprecated in favor of {@link #setCacheSeconds} or {@link #setCacheControl}.
|
||||
* @deprecated as of 4.2, since going forward, the HTTP 1.1 cache-control
|
||||
* header will be required, with the HTTP 1.0 headers disappearing
|
||||
*/
|
||||
@Deprecated
|
||||
public final void setUseExpiresHeader(boolean useExpiresHeader) {
|
||||
this.useExpiresHeader = useExpiresHeader;
|
||||
this.usePreviousHttpCachingBehavior = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the HTTP 1.0 expires header is used.
|
||||
*
|
||||
* @deprecated in favor of {@link #getCacheControl}.
|
||||
* @deprecated as of 4.2, in favor of {@link #getCacheControl()}
|
||||
*/
|
||||
@Deprecated
|
||||
public final boolean isUseExpiresHeader() {
|
||||
|
@ -211,19 +228,17 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||
* 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.
|
||||
*
|
||||
* @deprecated in favor of {@link #setCacheSeconds} or {@link #setCacheControl}.
|
||||
* @deprecated as of 4.2, since going forward, the HTTP 1.1 cache-control
|
||||
* header will be required, with the HTTP 1.0 headers disappearing
|
||||
*/
|
||||
@Deprecated
|
||||
public final void setUseCacheControlHeader(boolean useCacheControlHeader) {
|
||||
this.useCacheControlHeader = useCacheControlHeader;
|
||||
this.usePreviousHttpCachingBehavior = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the HTTP 1.1 cache-control header is used.
|
||||
*
|
||||
* @deprecated in favor of {@link #getCacheControl}.
|
||||
* @deprecated as of 4.2, in favor of {@link #getCacheControl()}
|
||||
*/
|
||||
@Deprecated
|
||||
public final boolean isUseCacheControlHeader() {
|
||||
|
@ -233,19 +248,16 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||
/**
|
||||
* Set whether to use the HTTP 1.1 cache-control header value "no-store"
|
||||
* when preventing caching. Default is "true".
|
||||
*
|
||||
* @deprecated in favor of {@link #setCacheSeconds} or {@link #setCacheControl}.
|
||||
* @deprecated as of 4.2, in favor of {@link #setCacheControl}
|
||||
*/
|
||||
@Deprecated
|
||||
public final void setUseCacheControlNoStore(boolean useCacheControlNoStore) {
|
||||
this.useCacheControlNoStore = useCacheControlNoStore;
|
||||
this.usePreviousHttpCachingBehavior = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the HTTP 1.1 cache-control header value "no-store" is used.
|
||||
*
|
||||
* @deprecated in favor of {@link #getCacheControl}.
|
||||
* @deprecated as of 4.2, in favor of {@link #getCacheControl()}
|
||||
*/
|
||||
@Deprecated
|
||||
public final boolean isUseCacheControlNoStore() {
|
||||
|
@ -253,125 +265,34 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||
}
|
||||
|
||||
/**
|
||||
* An option to add 'must-revalidate' to every Cache-Control header. This
|
||||
* may be useful with annotated controller methods, which can
|
||||
* programmatically do a lastModified calculation as described in
|
||||
* {@link WebRequest#checkNotModified(long)}. Default is "false".
|
||||
*
|
||||
* @deprecated in favor of {@link #setCacheSeconds} or {@link #setCacheControl}.
|
||||
* An option to add 'must-revalidate' to every Cache-Control header.
|
||||
* This may be useful with annotated controller methods, which can
|
||||
* programmatically do a last-modified calculation as described in
|
||||
* {@link org.springframework.web.context.request.WebRequest#checkNotModified(long)}.
|
||||
* <p>Default is "false".
|
||||
* @deprecated as of 4.2, in favor of {@link #setCacheControl}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setAlwaysMustRevalidate(boolean mustRevalidate) {
|
||||
public final void setAlwaysMustRevalidate(boolean mustRevalidate) {
|
||||
this.alwaysMustRevalidate = mustRevalidate;
|
||||
this.usePreviousHttpCachingBehavior = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether 'must-revalidate' is added to every Cache-Control header.
|
||||
*
|
||||
* @deprecated in favor of {@link #getCacheControl}.
|
||||
* @deprecated as of 4.2, in favor of {@link #getCacheControl()}
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isAlwaysMustRevalidate() {
|
||||
return alwaysMustRevalidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache content for the given number of seconds, by writing
|
||||
* cache-related HTTP headers to the response:
|
||||
* <ul>
|
||||
* <li>seconds == -1 (default value): no generation cache-related headers</li>
|
||||
* <li>seconds == 0: "Cache-Control: no-store" will prevent caching</li>
|
||||
* <li>seconds > 0: "Cache-Control: max-age=seconds" will ask to cache content</li>
|
||||
* </ul>
|
||||
* <p>For more specific needs, a custom {@link org.springframework.http.CacheControl} should be used.
|
||||
*
|
||||
* @see #setCacheControl
|
||||
*/
|
||||
public final void setCacheSeconds(int seconds) {
|
||||
this.cacheSeconds = seconds;
|
||||
if (!this.usePreviousHttpCachingBehavior) {
|
||||
if (cacheSeconds > 0) {
|
||||
this.cacheControl = CacheControl.maxAge(seconds, TimeUnit.SECONDS);
|
||||
}
|
||||
else if (cacheSeconds == 0) {
|
||||
this.cacheControl = CacheControl.noStore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of seconds that content is cached.
|
||||
*/
|
||||
public final int getCacheSeconds() {
|
||||
return this.cacheSeconds;
|
||||
public final boolean isAlwaysMustRevalidate() {
|
||||
return this.alwaysMustRevalidate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check and prepare the given request and response according to the settings
|
||||
* of this generator. Checks for supported methods and a required session,
|
||||
* and applies the number of cache seconds specified for this generator.
|
||||
* Check the given request for supported methods and a required session, if any.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @throws ServletException if the request cannot be handled because a check failed
|
||||
* @since 4.2
|
||||
*/
|
||||
protected final void checkAndPrepare(
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException {
|
||||
|
||||
checkAndPrepare(request, response, this.cacheControl);
|
||||
}
|
||||
|
||||
/**
|
||||
* * Check and prepare the given request and response according to the settings
|
||||
* of this generator. Checks for supported methods and a required session,
|
||||
* and applies the number of cache seconds specified for this generator.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param lastModified whether the underlying handler writes "Last-Modified" headers; in that case,
|
||||
* a "Cache-Control: must-revalidate" directive is set in the response.
|
||||
* @throws ServletException if the request cannot be handled because a check failed
|
||||
* @deprecated in favor of {@link #checkAndPrepare(HttpServletRequest, HttpServletResponse, CacheControl)}.
|
||||
*/
|
||||
@Deprecated
|
||||
protected final void checkAndPrepare(
|
||||
HttpServletRequest request, HttpServletResponse response, boolean lastModified)
|
||||
throws ServletException {
|
||||
|
||||
if (lastModified) {
|
||||
checkAndPrepare(request, response, this.cacheControl.mustRevalidate());
|
||||
}
|
||||
else {
|
||||
checkAndPrepare(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
protected final void checkAndPrepare(
|
||||
HttpServletRequest request, HttpServletResponse response, int cacheSeconds) throws ServletException {
|
||||
|
||||
CacheControl cControl;
|
||||
if (cacheSeconds > 0) {
|
||||
cControl = CacheControl.maxAge(cacheSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
else if (cacheSeconds == 0) {
|
||||
cControl = CacheControl.noStore();
|
||||
}
|
||||
else {
|
||||
cControl = CacheControl.empty();
|
||||
}
|
||||
checkRequest(request);
|
||||
if (this.usePreviousHttpCachingBehavior) {
|
||||
addHttp10CacheHeaders(cacheSeconds, response);
|
||||
}
|
||||
else {
|
||||
String ccValue = cControl.getHeaderValue();
|
||||
if (ccValue != null) {
|
||||
response.setHeader(HEADER_CACHE_CONTROL, ccValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final void checkRequest(HttpServletRequest request) throws ServletException {
|
||||
// Check whether we should support the request method.
|
||||
String method = request.getMethod();
|
||||
|
@ -387,46 +308,143 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check and prepare the given request and response according to the settings
|
||||
* of this generator. Checks for supported methods and a required session
|
||||
* specified for this generator. Also applies the {@link org.springframework.http.CacheControl}
|
||||
* given as a parameter.
|
||||
* @param request current HTTP request
|
||||
* Prepare the given response according to the settings of this generator.
|
||||
* Applies the number of cache seconds specified for this generator.
|
||||
* @param response current HTTP response
|
||||
* @param cacheControl the {@link org.springframework.http.CacheControl} to use
|
||||
* @throws ServletException if the request cannot be handled because a check failed
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
protected final void checkAndPrepare(
|
||||
HttpServletRequest request, HttpServletResponse response, CacheControl cacheControl)
|
||||
throws ServletException {
|
||||
|
||||
checkRequest(request);
|
||||
|
||||
if (this.usePreviousHttpCachingBehavior) {
|
||||
addHttp10CacheHeaders(this.cacheSeconds, response);
|
||||
protected final void prepareResponse(HttpServletResponse response) {
|
||||
if (this.cacheControl != null) {
|
||||
applyCacheControl(response, this.cacheControl);
|
||||
}
|
||||
else if (cacheControl != null) {
|
||||
String ccValue = cacheControl.getHeaderValue();
|
||||
if (ccValue != null) {
|
||||
response.setHeader(HEADER_CACHE_CONTROL, ccValue);
|
||||
if (response.containsHeader(HEADER_PRAGMA)) {
|
||||
response.setHeader(HEADER_PRAGMA, "");
|
||||
}
|
||||
else {
|
||||
applyCacheSeconds(response, this.cacheSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HTTP Cache-Control header according to the given settings.
|
||||
* @param response current HTTP response
|
||||
* @param cacheControl the pre-configured cache control settings
|
||||
* @since 4.2
|
||||
*/
|
||||
protected final void applyCacheControl(HttpServletResponse response, CacheControl cacheControl) {
|
||||
String ccValue = cacheControl.getHeaderValue();
|
||||
if (ccValue != null) {
|
||||
// Set computed HTTP 1.1 Cache-Control header
|
||||
response.setHeader(HEADER_CACHE_CONTROL, ccValue);
|
||||
|
||||
if (response.containsHeader(HEADER_PRAGMA)) {
|
||||
// Reset HTTP 1.0 Pragma header if present
|
||||
response.setHeader(HEADER_PRAGMA, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final void addHttp10CacheHeaders(int cacheSeconds, HttpServletResponse response) {
|
||||
/**
|
||||
* Apply the given cache seconds and generate corresponding HTTP headers,
|
||||
* i.e. allow caching for the given number of seconds in case of a positive
|
||||
* value, prevent caching if given a 0 value, do nothing else.
|
||||
* Does not tell the browser to revalidate the resource.
|
||||
* @param response current HTTP response
|
||||
* @param cacheSeconds positive number of seconds into the future that the
|
||||
* response should be cacheable for, 0 to prevent caching
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected final void applyCacheSeconds(HttpServletResponse response, int cacheSeconds) {
|
||||
if (this.useExpiresHeader || !this.useCacheControlHeader) {
|
||||
// Deprecated HTTP 1.0 cache behavior, as in previous Spring versions
|
||||
if (cacheSeconds > 0) {
|
||||
cacheForSeconds(response, cacheSeconds);
|
||||
}
|
||||
else if (cacheSeconds == 0) {
|
||||
preventCaching(response);
|
||||
}
|
||||
}
|
||||
else {
|
||||
CacheControl cControl;
|
||||
if (cacheSeconds > 0) {
|
||||
cControl = CacheControl.maxAge(cacheSeconds, TimeUnit.SECONDS);
|
||||
if (this.alwaysMustRevalidate) {
|
||||
cControl = cControl.mustRevalidate();
|
||||
}
|
||||
}
|
||||
else if (cacheSeconds == 0) {
|
||||
cControl = (this.useCacheControlNoStore ? CacheControl.noStore() : CacheControl.noCache());
|
||||
}
|
||||
else {
|
||||
cControl = CacheControl.empty();
|
||||
}
|
||||
applyCacheControl(response, cControl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see #checkRequest(HttpServletRequest)
|
||||
* @see #prepareResponse(HttpServletResponse)
|
||||
* @deprecated as of 4.2, since the {@code lastModified} flag is effectively ignored,
|
||||
* with a must-revalidate header only generated if explicitly configured
|
||||
*/
|
||||
@Deprecated
|
||||
protected final void checkAndPrepare(
|
||||
HttpServletRequest request, HttpServletResponse response, boolean lastModified) throws ServletException {
|
||||
|
||||
checkRequest(request);
|
||||
prepareResponse(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #checkRequest(HttpServletRequest)
|
||||
* @see #applyCacheSeconds(HttpServletResponse, int)
|
||||
* @deprecated as of 4.2, since the {@code lastModified} flag is effectively ignored,
|
||||
* with a must-revalidate header only generated if explicitly configured
|
||||
*/
|
||||
@Deprecated
|
||||
protected final void checkAndPrepare(
|
||||
HttpServletRequest request, HttpServletResponse response, int cacheSeconds, boolean lastModified)
|
||||
throws ServletException {
|
||||
|
||||
checkRequest(request);
|
||||
applyCacheSeconds(response, cacheSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given cache seconds and generate respective HTTP headers.
|
||||
* <p>That is, allow caching for the given number of seconds in the
|
||||
* case of a positive value, prevent caching if given a 0 value, else
|
||||
* do nothing (i.e. leave caching to the client).
|
||||
* @param response the current HTTP response
|
||||
* @param cacheSeconds the (positive) number of seconds into the future
|
||||
* that the response should be cacheable for; 0 to prevent caching; and
|
||||
* a negative value to leave caching to the client.
|
||||
* @param mustRevalidate whether the client should revalidate the resource
|
||||
* (typically only necessary for controllers with last-modified support)
|
||||
* @deprecated as of 4.2, in favor of {@link #applyCacheControl}
|
||||
*/
|
||||
@Deprecated
|
||||
protected final void applyCacheSeconds(HttpServletResponse response, int cacheSeconds, boolean mustRevalidate) {
|
||||
if (cacheSeconds > 0) {
|
||||
cacheForSeconds(response, cacheSeconds, this.alwaysMustRevalidate);
|
||||
cacheForSeconds(response, cacheSeconds, mustRevalidate);
|
||||
}
|
||||
else if (cacheSeconds == 0) {
|
||||
preventCaching(response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set HTTP headers to allow caching for the given number of seconds.
|
||||
* Does not tell the browser to revalidate the resource.
|
||||
* @param response current HTTP response
|
||||
* @param seconds number of seconds into the future that the response
|
||||
* should be cacheable for
|
||||
* @deprecated as of 4.2, in favor of {@link #applyCacheControl}
|
||||
*/
|
||||
@Deprecated
|
||||
protected final void cacheForSeconds(HttpServletResponse response, int seconds) {
|
||||
cacheForSeconds(response, seconds, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set HTTP headers to allow caching for the given number of seconds.
|
||||
* Tells the browser to revalidate the resource if mustRevalidate is
|
||||
|
@ -436,38 +454,48 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
|
|||
* should be cacheable for
|
||||
* @param mustRevalidate whether the client should revalidate the resource
|
||||
* (typically only necessary for controllers with last-modified support)
|
||||
* @deprecated as of 4.2, in favor of {@link #applyCacheControl}
|
||||
*/
|
||||
@Deprecated
|
||||
protected final void cacheForSeconds(HttpServletResponse response, int seconds, boolean mustRevalidate) {
|
||||
if (this.useExpiresHeader) {
|
||||
// HTTP 1.0 header
|
||||
response.setDateHeader(HEADER_EXPIRES, System.currentTimeMillis() + seconds * 1000L);
|
||||
}
|
||||
|
||||
if (this.useCacheControlHeader) {
|
||||
// HTTP 1.1 header
|
||||
String headerValue = "max-age=" + seconds;
|
||||
if (mustRevalidate) {
|
||||
if (mustRevalidate || this.alwaysMustRevalidate) {
|
||||
headerValue += ", must-revalidate";
|
||||
}
|
||||
response.setHeader(HEADER_CACHE_CONTROL, headerValue);
|
||||
}
|
||||
|
||||
if (response.containsHeader(HEADER_PRAGMA)) {
|
||||
// Reset HTTP 1.0 Pragma header if present
|
||||
response.setHeader(HEADER_PRAGMA, "");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent the response from being cached.
|
||||
* See {@code http://www.mnot.net/cache_docs}.
|
||||
* Only called in HTTP 1.0 compatibility mode.
|
||||
* <p>See {@code http://www.mnot.net/cache_docs}.
|
||||
* @deprecated as of 4.2, in favor of {@link #applyCacheControl}
|
||||
*/
|
||||
@Deprecated
|
||||
protected final void preventCaching(HttpServletResponse response) {
|
||||
response.setHeader(HEADER_PRAGMA, "no-cache");
|
||||
|
||||
if (this.useExpiresHeader) {
|
||||
// HTTP 1.0 header
|
||||
response.setDateHeader(HEADER_EXPIRES, System.currentTimeMillis());
|
||||
// HTTP 1.0 Expires header
|
||||
response.setDateHeader(HEADER_EXPIRES, 1L);
|
||||
}
|
||||
|
||||
if (this.useCacheControlHeader) {
|
||||
// HTTP 1.1 header: "no-cache" is the standard value,
|
||||
// "no-store" is necessary to prevent caching on FireFox.
|
||||
// HTTP 1.1 Cache-Control header: "no-cache" is the standard value,
|
||||
// "no-store" is necessary to prevent caching on Firefox.
|
||||
response.setHeader(HEADER_CACHE_CONTROL, "no-cache");
|
||||
if (this.useCacheControlNoStore) {
|
||||
response.addHeader(HEADER_CACHE_CONTROL, "no-store");
|
||||
|
|
|
@ -392,8 +392,6 @@ public class MvcNamespaceTests {
|
|||
ResourceHttpRequestHandler.class);
|
||||
assertNotNull(handler);
|
||||
assertEquals(3600, handler.getCacheSeconds());
|
||||
assertThat(handler.getCacheControl().getHeaderValue(),
|
||||
Matchers.equalTo(CacheControl.maxAge(1, TimeUnit.HOURS).getHeaderValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -90,8 +90,6 @@ public class ResourceHandlerRegistryTests {
|
|||
|
||||
this.registration.setCachePeriod(0);
|
||||
assertEquals(0, getHandler("/resources/**").getCacheSeconds());
|
||||
assertThat(getHandler("/resources/**").getCacheControl().getHeaderValue(),
|
||||
Matchers.equalTo(CacheControl.noStore().getHeaderValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -137,6 +137,7 @@ public class WebContentInterceptorTests {
|
|||
public void http10CachingConfigAndSpecificMapping() throws Exception {
|
||||
WebContentInterceptor interceptor = new WebContentInterceptor();
|
||||
interceptor.setCacheSeconds(0);
|
||||
interceptor.setUseExpiresHeader(true);
|
||||
interceptor.setAlwaysMustRevalidate(true);
|
||||
Properties mappings = new Properties();
|
||||
mappings.setProperty("**/*.cache.html", "10");
|
||||
|
|
|
@ -110,7 +110,7 @@ public class ResourceHttpRequestHandlerTests {
|
|||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
public void getResourcePreviousBehaviorCache() throws Exception {
|
||||
public void getResourceHttp10BehaviorCache() throws Exception {
|
||||
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css");
|
||||
this.handler.setCacheSeconds(3600);
|
||||
this.handler.setUseExpiresHeader(true);
|
||||
|
@ -126,15 +126,17 @@ public class ResourceHttpRequestHandlerTests {
|
|||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
public void getResourcePreviousBehaviorNoCache() throws Exception {
|
||||
public void getResourceHttp10BehaviorNoCache() throws Exception {
|
||||
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "foo.css");
|
||||
this.handler.setCacheSeconds(0);
|
||||
this.handler.setUseCacheControlNoStore(true);
|
||||
this.handler.setUseExpiresHeader(true);
|
||||
this.handler.setUseCacheControlNoStore(false);
|
||||
this.handler.setUseCacheControlHeader(true);
|
||||
this.handler.handleRequest(this.request, this.response);
|
||||
|
||||
assertEquals("no-cache", this.response.getHeader("Pragma"));
|
||||
assertThat(this.response.getHeaderValues("Cache-Control"), Matchers.contains("no-cache", "no-store"));
|
||||
assertThat(this.response.getHeaderValues("Cache-Control"), Matchers.iterableWithSize(1));
|
||||
assertEquals("no-cache", this.response.getHeader("Cache-Control"));
|
||||
assertTrue(dateHeaderAsLong("Expires") <= System.currentTimeMillis());
|
||||
assertTrue(this.response.containsHeader("Last-Modified"));
|
||||
assertEquals(dateHeaderAsLong("Last-Modified") / 1000, resourceLastModified("test/foo.css") / 1000);
|
||||
|
|
Loading…
Reference in New Issue