@ -1911,39 +1911,6 @@ which case they apply to matching controllers. This provides an alternative to u
@@ -1911,39 +1911,6 @@ which case they apply to matching controllers. This provides an alternative to u
`WebBindingInitializer`. See the <<mvc-ann-controller-advice>> section for more details.
[[mvc-ann-lastmodified]]
==== Support for the Last-Modified Response Header To Facilitate Content Caching
An `@RequestMapping` method may wish to support `'Last-Modified'` HTTP requests, as
defined in the contract for the Servlet API's `getLastModified` method, to facilitate
content caching. This involves calculating a lastModified `long` value for a given
request, comparing it against the `'If-Modified-Since'` request header value, and
potentially returning a response with status code 304 (Not Modified). An annotated
controller method can achieve that as follows:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@RequestMapping
public String myHandleMethod(WebRequest webRequest, Model model) {
long lastModified = // 1. application-specific calculation
if (request.checkNotModified(lastModified)) {
// 2. shortcut exit - no further processing necessary
return null;
}
// 3. or otherwise further request processing, actually preparing content
model.addAttribute(...);
return "myViewName";
}
----
There are two key elements to note: calling `request.checkNotModified(lastModified)` and
returning `null`. The former sets the response status to 304 before it returns `true`.
The latter, in combination with the former, causes Spring MVC to do no further
processing of the request.
[[mvc-ann-controller-advice]]
==== Advising controllers with the `@ControllerAdvice` annotation
The `@ControllerAdvice` annotation is a component annotation allowing implementation
@ -4029,6 +3996,7 @@ You do not need to define a `DefaultRequestToViewNameTranslator` bean explicitly
@@ -4029,6 +3996,7 @@ You do not need to define a `DefaultRequestToViewNameTranslator` bean explicitly
like the default settings of the `DefaultRequestToViewNameTranslator`, you can rely on
the Spring Web MVC `DispatcherServlet` to instantiate an instance of this class if one
is not explicitly configured.
====
Of course, if you need to change the default settings, then you do need to configure
@ -4038,9 +4006,16 @@ that can be configured.
@@ -4038,9 +4006,16 @@ that can be configured.
[[mvc-caching]]
== HTTP caching support
A good HTTP caching strategy can significantly improve the performance of a web application
and the experience of its clients. The `'Cache-Control'` HTTP response header is mostly
responsible for this, along with conditional headers such as `'Last-Modified'` and `'ETag'`.
The `'Cache-Control'` HTTP response header advice private caches (e.g. browsers) and
public caches (e.g. proxies) on how they can cache HTTP responses for further reuse.
[[mvc-etag]]
== ETag support
An http://en.wikipedia.org/wiki/HTTP_ETag[ETag] (entity tag) is an HTTP response header
returned by an HTTP/1.1 compliant web server used to determine change in content at a
given URL. It can be considered to be the more sophisticated successor to the
@ -4048,6 +4023,163 @@ given URL. It can be considered to be the more sophisticated successor to the
@@ -4048,6 +4023,163 @@ given URL. It can be considered to be the more sophisticated successor to the
client can use this header in subsequent GETs, in an `If-None-Match` header. If the
content has not changed, the server returns `304: Not Modified`.
This section describes the different choices available to configure HTTP caching in a
Spring Web MVC application.
[[mvc-caching-cachecontrol]]
=== Cache-Control HTTP header
Spring Web MVC supports many use cases and ways to configure "Cache-Control" headers for
an application. While the https://tools.ietf.org/html/rfc7234#section-5.2.2[RFC 7234 Section 5.2.2]
completely describes that header and its possible directives, there are several ways to
address the most common cases.
Spring Web MVC is using a configuration convention in several of its APIs:
`setCachePeriod(int seconds)`:
* A `-1` value won't generate a `'Cache-Control'` response header
* A `0` value will prevent caching using the `'Cache-Control: no-store'` directive
* A `n > 0` value will cache the given response for `n` seconds using the
`'Cache-Control: max-age=n'` directive
The {javadoc-baseurl}/org/springframework/http/CacheControl.html[`CacheControl`] builder
class simply describes the available "Cache-Control" directives and makes it easier to
build your own HTTP caching strategy. Once built, a `CacheControl` instance can be then
taken as an argument in several Spring Web MVC APIs.
[source,java,indent=0]
[subs="verbatim,quotes"]
----
// Cache for an hour - "Cache-Control: max-age=3600"
Doing this will not only include `'ETag'` and `'Cache-Control'` headers in the response, it will **also convert the
response to a `HTTP 304 Not Modified` response with an empty body** if the conditional headers sent by the client
match the caching information set by the Controller.
An `@RequestMapping` method may also wish to support the same behavior.
This can be achieved as follows:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@RequestMapping
public String myHandleMethod(WebRequest webRequest, Model model) {
long lastModified = // 1. application-specific calculation
if (request.checkNotModified(lastModified)) {
// 2. shortcut exit - no further processing necessary
return null;
}
// 3. or otherwise further request processing, actually preparing content
model.addAttribute(...);
return "myViewName";
}
----
There are two key elements here: calling `request.checkNotModified(lastModified)` and
returning `null`. The former sets the response status to 304 before it returns `true`.
The latter, in combination with the former, causes Spring MVC to do no further
processing of the request.
Note that there are 3 variants for this:
* `request.checkNotModified(lastModified)` compares lastModified with the
`'If-Modified-Since'` request header
* `request.checkNotModified(eTag)` compares eTag with the `'ETag'` request header
* `request.checkNotModified(eTag, lastModified)` does both, meaning that both
conditions should be valid for the server to issue an `HTTP 304 Not Modified` response
[[mvc-httpcaching-shallowetag]]
=== Shallow ETag support
Support for ETags is provided by the Servlet filter `ShallowEtagHeaderFilter`. It is a
plain Servlet Filter, and thus can be used in combination with any web framework. The
`ShallowEtagHeaderFilter` filter creates so-called shallow ETags (as opposed to deep
@ -4059,6 +4191,10 @@ compares the two hashes. If they are equal, a `304` is returned. This filter wil
@@ -4059,6 +4191,10 @@ compares the two hashes. If they are equal, a `304` is returned. This filter wil
save processing power, as the view is still rendered. The only thing it saves is
bandwidth, as the rendered response is not sent back over the wire.
Note that this strategy saves network bandwidth but not CPU, as the full response must be
computed for each request. Other strategies at the controller level (described above) can
save network bandwidth and avoid computation.
You configure the `ShallowEtagHeaderFilter` in `web.xml`:
[source,xml,indent=0]
@ -4075,6 +4211,24 @@ You configure the `ShallowEtagHeaderFilter` in `web.xml`:
@@ -4075,6 +4211,24 @@ You configure the `ShallowEtagHeaderFilter` in `web.xml`:
</filter-mapping>
----
Or in Servlet 3.0+ environments,
[source,java,indent=0]
[subs="verbatim,quotes"]
----
public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {
// ...
@Override
protected Filter[] getServletFilters() {
return new Filter[] { new ShallowEtagHeaderFilter() };
}
}
----
See <<mvc-container-config>> for more details.
@ -4656,6 +4810,9 @@ And in XML:
@@ -4656,6 +4810,9 @@ And in XML: