Provide controller level Cache-Control support
Prior to this commit, Cache-Control HTTP headers could be set using
a WebContentInterceptor and configured cache mappings.
This commit adds support for cache-related HTTP headers at the controller
method level, by returning a ResponseEntity instance:
ResponseEntity.status(HttpStatus.OK)
.cacheControl(CacheControl.maxAge(1, TimeUnit.HOURS).cachePublic())
.eTag("deadb33f8badf00d")
.body(entity);
Also, this change now automatically checks the "ETag" and
"Last-Modified" headers in ResponseEntity, in order to respond HTTP
"304 - Not Modified" if necessary.
Issue: SPR-8550
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,8 +18,12 @@ package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -106,7 +110,7 @@ public class HttpEntityMethodProcessorMockTests {
|
||||
returnTypeInt = new MethodParameter(getClass().getMethod("handle3"), -1);
|
||||
|
||||
mavContainer = new ModelAndViewContainer();
|
||||
servletRequest = new MockHttpServletRequest();
|
||||
servletRequest = new MockHttpServletRequest("GET", "/foo");
|
||||
servletResponse = new MockHttpServletResponse();
|
||||
webRequest = new ServletWebRequest(servletRequest, servletResponse);
|
||||
}
|
||||
@@ -320,6 +324,98 @@ public class HttpEntityMethodProcessorMockTests {
|
||||
assertEquals("headerValue", outputMessage.getValue().getHeaders().get("header").get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleReturnTypeLastModified() throws Exception {
|
||||
long currentTime = new Date().getTime();
|
||||
long oneMinuteAgo = currentTime - (1000 * 60);
|
||||
servletRequest.addHeader(HttpHeaders.IF_MODIFIED_SINCE, currentTime);
|
||||
HttpHeaders responseHeaders = new HttpHeaders();
|
||||
responseHeaders.setDate(HttpHeaders.LAST_MODIFIED, oneMinuteAgo);
|
||||
ResponseEntity<String> returnValue = new ResponseEntity<String>("body", responseHeaders, HttpStatus.OK);
|
||||
|
||||
given(messageConverter.canWrite(String.class, null)).willReturn(true);
|
||||
given(messageConverter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
|
||||
given(messageConverter.canWrite(String.class, MediaType.TEXT_PLAIN)).willReturn(true);
|
||||
|
||||
processor.handleReturnValue(returnValue, returnTypeResponseEntity, mavContainer, webRequest);
|
||||
|
||||
assertTrue(mavContainer.isRequestHandled());
|
||||
assertEquals(HttpStatus.NOT_MODIFIED.value(), servletResponse.getStatus());
|
||||
assertEquals(oneMinuteAgo/1000 * 1000, Long.parseLong(servletResponse.getHeader(HttpHeaders.LAST_MODIFIED)));
|
||||
assertEquals(0, servletResponse.getContentAsByteArray().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleReturnTypeEtag() throws Exception {
|
||||
String etagValue = "\"deadb33f8badf00d\"";
|
||||
servletRequest.addHeader(HttpHeaders.IF_NONE_MATCH, etagValue);
|
||||
HttpHeaders responseHeaders = new HttpHeaders();
|
||||
responseHeaders.set(HttpHeaders.ETAG, etagValue);
|
||||
ResponseEntity<String> returnValue = new ResponseEntity<String>("body", responseHeaders, HttpStatus.OK);
|
||||
|
||||
given(messageConverter.canWrite(String.class, null)).willReturn(true);
|
||||
given(messageConverter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
|
||||
given(messageConverter.canWrite(String.class, MediaType.TEXT_PLAIN)).willReturn(true);
|
||||
|
||||
processor.handleReturnValue(returnValue, returnTypeResponseEntity, mavContainer, webRequest);
|
||||
|
||||
assertTrue(mavContainer.isRequestHandled());
|
||||
assertEquals(HttpStatus.NOT_MODIFIED.value(), servletResponse.getStatus());
|
||||
assertEquals(etagValue, servletResponse.getHeader(HttpHeaders.ETAG));
|
||||
assertEquals(0, servletResponse.getContentAsByteArray().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleReturnTypeETagAndLastModified() throws Exception {
|
||||
long currentTime = new Date().getTime();
|
||||
long oneMinuteAgo = currentTime - (1000 * 60);
|
||||
String etagValue = "\"deadb33f8badf00d\"";
|
||||
servletRequest.addHeader(HttpHeaders.IF_MODIFIED_SINCE, currentTime);
|
||||
servletRequest.addHeader(HttpHeaders.IF_NONE_MATCH, etagValue);
|
||||
HttpHeaders responseHeaders = new HttpHeaders();
|
||||
responseHeaders.setDate(HttpHeaders.LAST_MODIFIED, oneMinuteAgo);
|
||||
responseHeaders.set(HttpHeaders.ETAG, etagValue);
|
||||
ResponseEntity<String> returnValue = new ResponseEntity<String>("body", responseHeaders, HttpStatus.OK);
|
||||
|
||||
given(messageConverter.canWrite(String.class, null)).willReturn(true);
|
||||
given(messageConverter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
|
||||
given(messageConverter.canWrite(String.class, MediaType.TEXT_PLAIN)).willReturn(true);
|
||||
|
||||
processor.handleReturnValue(returnValue, returnTypeResponseEntity, mavContainer, webRequest);
|
||||
|
||||
assertTrue(mavContainer.isRequestHandled());
|
||||
assertEquals(HttpStatus.NOT_MODIFIED.value(), servletResponse.getStatus());
|
||||
assertEquals(oneMinuteAgo/1000 * 1000, Long.parseLong(servletResponse.getHeader(HttpHeaders.LAST_MODIFIED)));
|
||||
assertEquals(etagValue, servletResponse.getHeader(HttpHeaders.ETAG));
|
||||
assertEquals(0, servletResponse.getContentAsByteArray().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleReturnTypeChangedETagAndLastModified() throws Exception {
|
||||
long currentTime = new Date().getTime();
|
||||
long oneMinuteAgo = currentTime - (1000 * 60);
|
||||
String etagValue = "\"deadb33f8badf00d\"";
|
||||
String changedEtagValue = "\"changed-etag-value\"";
|
||||
servletRequest.addHeader(HttpHeaders.IF_MODIFIED_SINCE, currentTime);
|
||||
servletRequest.addHeader(HttpHeaders.IF_NONE_MATCH, etagValue);
|
||||
HttpHeaders responseHeaders = new HttpHeaders();
|
||||
responseHeaders.setDate(HttpHeaders.LAST_MODIFIED, oneMinuteAgo);
|
||||
responseHeaders.set(HttpHeaders.ETAG, changedEtagValue);
|
||||
ResponseEntity<String> returnValue = new ResponseEntity<String>("body", responseHeaders, HttpStatus.OK);
|
||||
|
||||
given(messageConverter.canWrite(String.class, null)).willReturn(true);
|
||||
given(messageConverter.getSupportedMediaTypes()).willReturn(Collections.singletonList(MediaType.TEXT_PLAIN));
|
||||
given(messageConverter.canWrite(String.class, MediaType.TEXT_PLAIN)).willReturn(true);
|
||||
|
||||
processor.handleReturnValue(returnValue, returnTypeResponseEntity, mavContainer, webRequest);
|
||||
|
||||
assertTrue(mavContainer.isRequestHandled());
|
||||
assertEquals(HttpStatus.OK.value(), servletResponse.getStatus());
|
||||
assertEquals(oneMinuteAgo/1000 * 1000, Long.parseLong(servletResponse.getHeader(HttpHeaders.LAST_MODIFIED)));
|
||||
assertEquals(changedEtagValue, servletResponse.getHeader(HttpHeaders.ETAG));
|
||||
assertEquals(0, servletResponse.getContentAsByteArray().length);
|
||||
}
|
||||
|
||||
public ResponseEntity<String> handle1(HttpEntity<String> httpEntity, ResponseEntity<String> responseEntity, int i, RequestEntity<String> requestEntity) {
|
||||
return responseEntity;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user