From d4677be5c080b2ce502c281ab116c1e5a2589047 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Fri, 6 Oct 2017 21:29:36 -0400 Subject: [PATCH] Improve Web Servlet section structure --- src/docs/asciidoc/web/webflux.adoc | 9 +- src/docs/asciidoc/web/webmvc.adoc | 3718 ++++++++++++-------------- src/docs/asciidoc/web/websocket.adoc | 8 +- 3 files changed, 1707 insertions(+), 2028 deletions(-) diff --git a/src/docs/asciidoc/web/webflux.adoc b/src/docs/asciidoc/web/webflux.adoc index d5911efc5ce..5f49082d15b 100644 --- a/src/docs/asciidoc/web/webflux.adoc +++ b/src/docs/asciidoc/web/webflux.adoc @@ -544,7 +544,7 @@ In this example the methods returns a String to be written to the response body. [[webflux-ann-controller]] -=== @Controller declaration +=== @Controller [.small]#<># You can define controller beans using a standard Spring bean definition. @@ -567,13 +567,10 @@ your Java configuration: } ---- -[NOTE] -==== -`@RestController` is a composed annotation that is itself annotated with `@Controller` and -`@ResponseBody` indicating a controller whose every method inherits the type-level +`@RestController` is a composed annotation that is itself annotated with +`@Controller` and `@ResponseBody` indicating a controller whose every method inherits the type-level `@ResponseBody` annotation and therefore writes to the response body (vs model-and-vew rendering). -==== [[webflux-ann-requestmapping]] diff --git a/src/docs/asciidoc/web/webmvc.adoc b/src/docs/asciidoc/web/webmvc.adoc index 40a14cff233..79c0f1d5c12 100644 --- a/src/docs/asciidoc/web/webmvc.adoc +++ b/src/docs/asciidoc/web/webmvc.adoc @@ -35,7 +35,7 @@ handling, <>. Below is an example of the Java configuration that registers and initializes the `DispatcherServlet`. This class is auto-detected by the Servlet container -(see <>): +(see <>): [source,java,indent=0] [subs="verbatim,quotes"] @@ -213,7 +213,7 @@ customize, extend, or replace them. | Bean type| Explanation | <> -| Map a request to a handler along with a list of `HandlerInterceptor`s for +| Map a request to a handler along with a list of ``HandlerInterceptor``'s for pre- and post-processing. The mapping is based on some criteria the details of which vary by `HandlerMapping` implementation. The most popular implementation supports annotated controllers but other implementations exists as well. @@ -249,7 +249,6 @@ customize, extend, or replace them. |=== - [[mvc-servlet-config]] === Initialization For each type of special bean, the `DispatcherServlet` checks for the `WebApplicationContext` first. @@ -268,9 +267,124 @@ provides many extra convenient options on top. ==== +[[mvc-container-config]] +=== Servlet Config API + +In a Servlet 3.0+ environment, you have the option of configuring the Servlet container +programmatically as an alternative or in combination with a `web.xml` file. Below is an +example of registering a `DispatcherServlet`: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + import org.springframework.web.WebApplicationInitializer; + + public class MyWebApplicationInitializer implements WebApplicationInitializer { + + @Override + public void onStartup(ServletContext container) { + XmlWebApplicationContext appContext = new XmlWebApplicationContext(); + appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml"); + + ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(appContext)); + registration.setLoadOnStartup(1); + registration.addMapping("/"); + } + + } +---- + +`WebApplicationInitializer` is an interface provided by Spring MVC that ensures your +implementation is detected and automatically used to initialize any Servlet 3 container. +An abstract base class implementation of `WebApplicationInitializer` named +`AbstractDispatcherServletInitializer` makes it even easier to register the +`DispatcherServlet` by simply overriding methods to specify the servlet mapping and the +location of the `DispatcherServlet` configuration. + +This is recommended for applications that use Java-based Spring configuration: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { + + @Override + protected Class[] getRootConfigClasses() { + return null; + } + + @Override + protected Class[] getServletConfigClasses() { + return new Class[] { MyWebConfig.class }; + } + + @Override + protected String[] getServletMappings() { + return new String[] { "/" }; + } + + } +---- + +If using XML-based Spring configuration, you should extend directly from +`AbstractDispatcherServletInitializer`: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class MyWebAppInitializer extends AbstractDispatcherServletInitializer { + + @Override + protected WebApplicationContext createRootApplicationContext() { + return null; + } + + @Override + protected WebApplicationContext createServletApplicationContext() { + XmlWebApplicationContext cxt = new XmlWebApplicationContext(); + cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml"); + return cxt; + } + + @Override + protected String[] getServletMappings() { + return new String[] { "/" }; + } + + } +---- + +`AbstractDispatcherServletInitializer` also provides a convenient way to add `Filter` +instances and have them automatically mapped to the `DispatcherServlet`: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class MyWebAppInitializer extends AbstractDispatcherServletInitializer { + + // ... + + @Override + protected Filter[] getServletFilters() { + return new Filter[] { + new HiddenHttpMethodFilter(), new CharacterEncodingFilter() }; + } + } +---- + +Each filter is added with a default name based on its concrete type and automatically +mapped to the `DispatcherServlet`. + +The `isAsyncSupported` protected method of `AbstractDispatcherServletInitializer` +provides a single place to enable async support on the `DispatcherServlet` and all +filters mapped to it. By default this flag is set to `true`. + +Finally, if you need to further customize the `DispatcherServlet` itself, you can +override the `createDispatcherServlet` method. + [[mvc-servlet-sequence]] -=== Processing Sequence +=== Processing [.small]#<># The `DispatcherServlet` processes requests as follows: @@ -333,1042 +447,1327 @@ initialization parameters ( `init-param` elements) to the Servlet declaration in |=== +[[mvc-handlermapping-interceptor]] +=== HandlerInterceptor +The two main `HandlerMapping` implementations are `RequestMappingHandlerMapping` which +supports `@RequestMapping` annotated methods and `SimpleUrlHandlerMapping` which maintains +explicit registrations of URI path patterns to handlers. -[[mvc-controller]] -== Annotated Controllers -[.small]#<># +All `HandlerMapping` implementations supports handler interceptors that are useful when +you want to apply specific functionality to certain requests, for example, checking for +a principal. -Spring MVC provides an annotation-based programming model where `@Controller` and -`@RestController` components use annotations to express request mappings, request input, -exception handling, and more. Annotated controllers have flexible method signatures and -do not have to extend base classes nor implement specific interfaces. +Interceptors must implement `HandlerInterceptor` from the `org.springframework.web .servlet` +package with three methods that should provide enough flexibility to do all kinds of +pre-processing and post-processing.: -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - public class HelloController { +* `preHandle(..)` -- __before__ the actual handler is executed +* `postHandle(..)` -- __after__ the handler is executed +* `afterCompletion(..)` -- __after the complete request has finished__ - @GetMapping("/hello") - public String handle(Model model) { - model.addAttribute("message", "Hello World!"); - return "index"; - } - } ----- +The `preHandle(..)` method returns a boolean value. You can use this method to break or +continue the processing of the execution chain. When this method returns `true`, the +handler execution chain will continue; when it returns false, the `DispatcherServlet` +assumes the interceptor itself has taken care of requests (and, for example, rendered an +appropriate view) and does not continue executing the other interceptors and the actual +handler in the execution chain. -In this particular example the method accepts a `Model` and returns a view name as a `String` -but many other options exist and are explained further below in this chapter. +See <> in the section on MVC configuration for examples of how to +configure interceptors. You can also register them directly via setters on individual +`HandlerMapping` implementations. -[TIP] +[CAUTION] ==== -Guides and tutorials on https://spring.io/guides[spring.io] use the annotation-based -programming model described in this section. +`postHandle` is less useful with `@ResponseBody` and `ResponseEntity` methods for which a +the response is written and committed within the `HandlerAdapter` and before `postHandle`. +That means its too late to make any changes to the response such as adding an extra header. +For such scenarios you can implement `ResponseBodyAdvice` and either declare it as an +<> bean or configure it directly on `RequestMappingHandlerAdapter`. ==== +[[mvc-localeresolver]] +=== Locales +Most parts of Spring's architecture support internationalization, just as the Spring web +MVC framework does. `DispatcherServlet` enables you to automatically resolve messages +using the client's locale. This is done with `LocaleResolver` objects. -[[mvc-ann-controller]] -=== @Controller Declaration -[.small]#<># +When a request comes in, the `DispatcherServlet` looks for a locale resolver, and if it +finds one it tries to use it to set the locale. Using the `RequestContext.getLocale()` +method, you can always retrieve the locale that was resolved by the locale resolver. -You can define controller beans using a standard Spring bean definition in the -Servlet's `WebApplicationContext`. The `@Controller` stereotype allows for auto-detection, -aligned with Spring general support for detecting `@Component` classes in the classpath -and auto-registering bean definitions for them. It also acts as a stereotype for the -annotated class, indicating its role as a web component. +In addition to automatic locale resolution, you can also attach an interceptor to the +handler mapping (see <> for more information on handler +mapping interceptors) to change the locale under specific circumstances, for example, +based on a parameter in the request. -To enable auto-detection of such `@Controller` beans, you can add component scanning to -your Java configuration: +Locale resolvers and interceptors are defined in the +`org.springframework.web.servlet.i18n` package and are configured in your application +context in the normal way. Here is a selection of the locale resolvers included in +Spring. -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @ComponentScan("org.example.web") - public class WebConfig { - // ... - } ----- -The XML configuration equivalent: +[[mvc-timezone]] +==== TimeZone +In addition to obtaining the client's locale, it is often useful to know their time zone. +The `LocaleContextResolver` interface offers an extension to `LocaleResolver` that allows +resolvers to provide a richer `LocaleContext`, which may include time zone information. + +When available, the user's `TimeZone` can be obtained using the +`RequestContext.getTimeZone()` method. Time zone information will automatically be used +by Date/Time `Converter` and `Formatter` objects registered with Spring's +`ConversionService`. + + + +[[mvc-localeresolver-acceptheader]] +==== Header resolver +This locale resolver inspects the `accept-language` header in the request that was sent +by the client (e.g., a web browser). Usually this header field contains the locale of +the client's operating system. __Note that this resolver does not support time zone +information.__ + + + +[[mvc-localeresolver-cookie]] +==== Cookie resolver + +This locale resolver inspects a `Cookie` that might exist on the client to see if a +`Locale` or `TimeZone` is specified. If so, it uses the specified details. Using the +properties of this locale resolver, you can specify the name of the cookie as well as the +maximum age. Find below an example of defining a `CookieLocaleResolver`. [source,xml,indent=0] [subs="verbatim,quotes"] ---- - - + - + - + + - + ---- -[NOTE] -==== -`@RestController` is a composed annotation that is itself annotated with `@Controller` and -`@ResponseBody` indicating a controller whose every method inherits the type-level -`@ResponseBody` annotation and therefore writes to the response body (vs model-and-vew -rendering). -==== +[[mvc-cookie-locale-resolver-props-tbl]] +.CookieLocaleResolver properties +[cols="1,1,4"] +|=== +| Property| Default| Description +| cookieName +| classname + LOCALE +| The name of the cookie +| cookieMaxAge +| Servlet container default +| The maximum time a cookie will stay persistent on the client. If -1 is specified, the + cookie will not be persisted; it will only be available until the client shuts down + their browser. -[[mvc-ann-requestmapping]] -=== Mapping Requests -[.small]#<># +| cookiePath +| / +| Limits the visibility of the cookie to a certain part of your site. When cookiePath is + specified, the cookie will only be visible to that path and the paths below it. +|=== -The `@RequestMapping` annotation is used to map requests to controllers methods. It has -various attributes to match by URL, HTTP method, request parameters, headers, and media -types. It can be used at the class-level to express shared mappings or at the method level -to narrow down to a specific endpoint mapping. -There are also HTTP method specific shortcut variants of `@RequestMapping`: -- `@GetMapping` -- `@PostMapping` -- `@PutMapping` -- `@DeleteMapping` -- `@PatchMapping` +[[mvc-localeresolver-session]] +==== Session resolver -The shortcut variants are -https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model#composed-annotations[composed annotations] --- themselves annotated with `@RequestMapping`. They are commonly used at the method level. -At the class level an `@RequestMapping` is more useful for expressing shared mappings. +The `SessionLocaleResolver` allows you to retrieve `Locale` and `TimeZone` from the +session that might be associated with the user's request. In contrast to +`CookieLocaleResolver`, this strategy stores locally chosen locale settings in the +Servlet container's `HttpSession`. As a consequence, those settings are just temporary +for each session and therefore lost when each session terminates. -[source,java,indent=0] -[subs="verbatim,quotes"] +Note that there is no direct relationship with external session management mechanisms +such as the Spring Session project. This `SessionLocaleResolver` will simply evaluate and +modify corresponding `HttpSession` attributes against the current `HttpServletRequest`. + + + +[[mvc-localeresolver-interceptor]] +==== Locale interceptor + +You can enable changing of locales by adding the `LocaleChangeInterceptor` to one of the +handler mappings (see <>). It will detect a parameter in the request +and change the locale. It calls `setLocale()` on the `LocaleResolver` that also exists +in the context. The following example shows that calls to all `{asterisk}.view` resources +containing a parameter named `siteLanguage` will now change the locale. So, for example, +a request for the following URL, `http://www.sf.net/home.view?siteLanguage=nl` will +change the site language to Dutch. + +[source,xml,indent=0] +[subs="verbatim"] ---- - @RestController - @RequestMapping("/persons") - class PersonController { + + + - @GetMapping("/{id}") - public Person getPerson(@PathVariable Long id) { - // ... - } + - @PostMapping - @ResponseStatus(HttpStatus.CREATED) - public void add(@RequestBody Person person) { - // ... - } - } + + + + + + + + /**/*.view=someController + + ---- -[[mvc-ann-requestmapping-proxying]] -==== AOP proxies -In some cases a controller may need to be decorated with an AOP proxy at runtime. -One example is if you choose to have `@Transactional` annotations directly on the -controller. When this is the case, for controllers specifically, we recommend -using class-based proxying. This is typically the default choice with controllers. -However if a controller must implement an interface that is not a Spring Context -callback (e.g. `InitializingBean`, `*Aware`, etc), you may need to explicitly -configure class-based proxying. For example with ``, -change to ``. +[[mvc-themeresolver]] +=== Themes -[[mvc-ann-requestmapping-uri-templates]] -==== URI patterns -[.small]#<># +You can apply Spring Web MVC framework themes to set the overall look-and-feel of your +application, thereby enhancing user experience. A theme is a collection of static +resources, typically style sheets and images, that affect the visual style of the +application. -You can map requests using glob patterns and wildcards: -* `?` matches one character -* `*` matches zero or more characters within a path segment -* `**` match zero or more path segments +[[mvc-themeresolver-defining]] +==== Define a theme +To use themes in your web application, you must set up an implementation of the +`org.springframework.ui.context.ThemeSource` interface. The `WebApplicationContext` +interface extends `ThemeSource` but delegates its responsibilities to a dedicated +implementation. By default the delegate will be an +`org.springframework.ui.context.support.ResourceBundleThemeSource` implementation that +loads properties files from the root of the classpath. To use a custom `ThemeSource` +implementation or to configure the base name prefix of the `ResourceBundleThemeSource`, +you can register a bean in the application context with the reserved name `themeSource`. +The web application context automatically detects a bean with that name and uses it. -You can also declare URI variables and access their values with `@PathVariable`: +When using the `ResourceBundleThemeSource`, a theme is defined in a simple properties +file. The properties file lists the resources that make up the theme. Here is an example: -[source,java,indent=0] +[literal] [subs="verbatim,quotes"] ---- - @GetMapping("/owners/{ownerId}/pets/{petId}") - public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) { - // ... - } +styleSheet=/themes/cool/style.css +background=/themes/cool/img/coolBg.jpg ---- -URI variables can be declared at the class and method level: -[source,java,intent=0] +The keys of the properties are the names that refer to the themed elements from view +code. For a JSP, you typically do this using the `spring:theme` custom tag, which is +very similar to the `spring:message` tag. The following JSP fragment uses the theme +defined in the previous example to customize the look and feel: + +[source,xml,indent=0] [subs="verbatim,quotes"] ---- -@Controller -@RequestMapping("/owners/{ownerId}") -public class OwnerController { - - @GetMapping("/pets/{petId}") - public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) { - // ... - } -} + <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + + + ... + + ---- -URI variables are automatically converted to the appropriate type or`TypeMismatchException` -is raised. Simple types -- `int`, `long`, `Date`, are supported by default and you can -register support for any other data type. -See <> and <>. +By default, the `ResourceBundleThemeSource` uses an empty base name prefix. As a result, +the properties files are loaded from the root of the classpath. Thus you would put the +`cool.properties` theme definition in a directory at the root of the classpath, for +example, in `/WEB-INF/classes`. The `ResourceBundleThemeSource` uses the standard Java +resource bundle loading mechanism, allowing for full internationalization of themes. For +example, we could have a `/WEB-INF/classes/cool_nl.properties` that references a special +background image with Dutch text on it. -URI variables can be named explicitly -- e.g. `@PathVariable("customId")`, but you can -leave that detail out if the names are the same and your code is compiled with debugging -information or with the `-parameters` compiler flag on Java 8. -The syntax `{varName:regex}` declares a URI variable with a regular expressions with the -syntax `{varName:regex}` -- e.g. given URL `"/spring-web-3.0.5 .jar"`, the below method -extracts the name, version, and file extension: -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}") - public void handle(@PathVariable String version, @PathVariable String ext) { - // ... - } ----- +[[mvc-themeresolver-resolving]] +==== Resolve themes +After you define themes, as in the preceding section, you decide which theme to use. The +`DispatcherServlet` will look for a bean named `themeResolver` to find out which +`ThemeResolver` implementation to use. A theme resolver works in much the same way as a +`LocaleResolver`. It detects the theme to use for a particular request and can also +alter the request's theme. The following theme resolvers are provided by Spring: -URI path patterns can also have embedded `${...}` placeholders that are resolved on startup - via `PropertyPlaceHolderConfigurer` against local, system, environment, and other property -sources. This can be used for example to parameterize a base URL based on some external -configuration. +[[mvc-theme-resolver-impls-tbl]] +.ThemeResolver implementations +[cols="1,4"] +|=== +| Class| Description -[NOTE] -==== -Spring MVC uses the `PathMatcher` contract and the `AntPathMatcher` implementation from -`spring-core` for URI path matching. -==== +| `FixedThemeResolver` +| Selects a fixed theme, set using the `defaultThemeName` property. +| `SessionThemeResolver` +| The theme is maintained in the user's HTTP session. It only needs to be set once for + each session, but is not persisted between sessions. -[[mvc-ann-requestmapping-pattern-comparison]] -==== Pattern comparison -[.small]#<># +| `CookieThemeResolver` +| The selected theme is stored in a cookie on the client. +|=== -When multiple patterns match a URL, they must be compared to find the best match. This done -via `AntPathMatcher.getPatternComparator(String path)` which looks for patterns that more -specific. +Spring also provides a `ThemeChangeInterceptor` that allows theme changes on every +request with a simple request parameter. -A pattern is less specific if it has a lower count of URI variables and single wildcards -counted as 1 and double wildcards counted as 2. Given an equal score, the longer pattern is -chosen. Given the same score and length, the pattern with more URI variables than wildcards -is chosen. -The default mapping pattern `/{asterisk}{asterisk}` is excluded from scoring and always -sorted last. Also prefix patterns such as `/public/{asterisk}{asterisk}` are considered less -specific than other pattern that don't have double wildcards. +[[mvc-multipart]] +=== MultipartResolver -For the full details see `AntPatternComparator` in `AntPathMatcher` and also keep mind that -the `PathMatcher` implementation used can be customized. See <> -in the configuration section. +Spring has built-in support for multipart requests including file uploads. +You enable this multipart support with pluggable `MultipartResolver` objects, defined in the +`org.springframework.web.multipart` package. Spring provides one `MultipartResolver` +implementation for use with http://jakarta.apache.org/commons/fileupload[__Commons +FileUpload__] and another for use with Servlet 3.0 multipart request parsing. +By default, Spring does no multipart handling, because some developers want to handle +multiparts themselves. You enable Spring multipart handling by adding a multipart +resolver to the web application's context. Each request is inspected to see if it +contains a multipart. If no multipart is found, the request continues as expected. If a +multipart is found in the request, the `MultipartResolver` that has been declared in +your context is used. After that, the multipart attribute in your request is treated +like any other attribute. -[[mvc-ann-requestmapping-suffix-pattern-match]] -==== Suffix match -By default Spring MVC performs `".{asterisk}"` suffix pattern matching so that a -controller mapped to `/person` is also implicitly mapped to `/person.{asterisk}`. -This is used for URL based content negotiation, e.g. `/person.pdf`, `/person.xml`, etc. +[[mvc-multipart-resolver-commons]] +==== __Commons FileUpload__ -Suffix pattern matching was quite helpful when browsers used to send Accept headers that -are hard to interpet consistently. In the present, and for REST services, the `Accept` -header should be the preferred choice. +To use Apache Commons FileUpload, configure a bean of type `CommonsMultipartResolver` with +the name `multipartResolver`. Of course you also need to have `commons-fileupload` as a +dependency on your classpath. -Suffix patterns can cause ambiguity and complexity in combination with path parameters, -encoded characters, and URI variables. It also makes it harder to reason about URL-based -authorization rules and security (see <>). +When the Spring `DispatcherServlet` detects a multipart request, it activates the +resolver that has been declared in your context and hands over the request. The resolver +then wraps the current `HttpServletRequest` into a `MultipartHttpServletRequest` that +supports multipart file uploads. Using the `MultipartHttpServletRequest`, you can get +information about the multiparts contained by this request and actually get access to +the multipart files themselves in your controllers. -Suffix pattern matching can be turned off completely or restricted to a set of explicitly -registered path extensions. We strongly recommend using of one those options. See -<> and <>. If you need URL based -content negotiation consider using query parameters instead. +[[mvc-multipart-resolver-standard]] +==== __Servlet 3.0__ -[[mvc-ann-requestmapping-rfd]] -==== Suffix match and RFD +In order to use Servlet 3.0 based multipart parsing, you need to mark the +`DispatcherServlet` with a `"multipart-config"` section in `web.xml`, or with a +`javax.servlet.MultipartConfigElement` in programmatic Servlet registration, or in case +of a custom Servlet class possibly with a `javax.servlet.annotation.MultipartConfig` +annotation on your Servlet class. Configuration settings such as maximum sizes or +storage locations need to be applied at that Servlet registration level as Servlet 3.0 +does not allow for those settings to be done from the MultipartResolver. -Reflected file download (RFD) attack is similar to XSS in that it relies on request input, -e.g. query parameter, URI variable, being reflected in the response. However instead of -inserting JavaScript into HTML, an RFD attack relies on the browser switching to perform a -download and treating the response as an executable script when double-clicked later. +Once Servlet 3.0 multipart parsing has been enabled in one of the above mentioned ways +you can add a bean of type `StandardServletMultipartResolver` and with the name +`multipartResolver` to your Spring configuration. -In Spring MVC `@ResponseBody` and `ResponseEntity` methods are at risk because -they can render different content types which clients can request via URL path extensions. -Disabling suffix pattern matching and the use of path extensions for content negotiation -lower the risk but are not sufficient to prevent RFD attacks. +[[filters]] +== Filters -To prevent RFD attacks, prior to rendering the response body Spring MVC adds a -`Content-Disposition:inline;filename=f.txt` header to suggest a fixed and safe download -file. This is done only if the URL path contains a file extension that is neither whitelisted -nor explicitly registered for content negotiation purposes. However it may potentially have -side effects when URLs are typed directly into a browser. +The `spring-web` module provides some useful filters. -Many common path extensions are whitelisted by default. Applications with custom -`HttpMessageConverter` implementations can explicitly register file extensions for content -negotiation to avoid having a `Content-Disposition` header added for those extensions. -See <>. +[[filters-http-put]] +=== HTTP PUT Form -Check http://pivotal.io/security/cve-2015-5211[CVE-2015-5211] for additional -recommendations related to RFD. +Browsers can only submit form data via HTTP GET or HTTP POST but non-browser clients can also +use HTTP PUT and PATCH. The Servlet API requires `ServletRequest.getParameter{asterisk}()` +methods to support form field access only for HTTP POST. +The `spring-web` module provides `HttpPutFormContentFilter` that intercepts HTTP PUT and +PATCH requests with content type `application/x-www-form-urlencoded`, reads the form data from +the body of the request, and wraps the `ServletRequest` in order to make the form data +available through the `ServletRequest.getParameter{asterisk}()` family of methods. -[[mvc-ann-matrix-variables]] -==== Matrix variables -The URI specification http://tools.ietf.org/html/rfc3986#section-3.3[RFC 3986] defines -the possibility of including name-value pairs within path segments. There is no specific -term used in the spec. The general "URI path parameters" could be applied although the -more unique http://www.w3.org/DesignIssues/MatrixURIs.html["Matrix URIs"], originating -from an old post by Tim Berners-Lee, is also frequently used and fairly well known. -Within Spring MVC these are referred to as matrix variables. +[[filters-forwarded-headers]] +=== Forwarded Headers -Matrix variables can appear in any path segment, each matrix variable separated with a -";" (semicolon). For example: `"/cars;color=red;year=2012"`. Multiple values may be -either "," (comma) separated `"color=red,green,blue"` or the variable name may be -repeated `"color=red;color=green;color=blue"`. +As a request goes through proxies such as load balancers the host, port, and +scheme may change presenting a challenge for applications that need to create links +to resources since the links should reflect the host, port, and scheme of the +original request as seen from a client perspective. -If a URL is expected to contain matrix variables, the request mapping pattern must -represent them with a URI template. This ensures the request can be matched correctly -regardless of whether matrix variables are present or not and in what order they are -provided. +https://tools.ietf.org/html/rfc7239[RFC 7239] defines the "Forwarded" HTTP header +for proxies to use to provide information about the original request. There are also +other non-standard headers in use such as "X-Forwarded-Host", "X-Forwarded-Port", +and "X-Forwarded-Proto". -Below is an example of extracting the matrix variable "q": +`ForwardedHeaderFilter` detects, extracts, and uses information from the "Forwarded" +header, or from "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto". +It wraps the request in order to overlay its host, port, and scheme and also "hides" +the forwarded headers for subsequent processing. -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // GET /pets/42;q=11;r=22 +Note that there are security considerations when using forwarded headers as explained +in Section 8 of RFC 7239. At the application level it is difficult to determine whether +forwarded headers can be trusted or not. This is why the network upstream should be +configured correctly to filter out untrusted forwarded headers from the outside. - @GetMapping("/pets/{petId}") - public void findPet(@PathVariable String petId, @MatrixVariable int q) { +Applications that don't have a proxy and don't need to use forwarded headers can +configure the `ForwardedHeaderFilter` to remove and ignore such headers. - // petId == 42 - // q == 11 +[[filters-shallow-etag]] +=== Shallow ETag - } ----- +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 +ETags, more about that later).The filter caches the content of the rendered JSP (or +other content), generates an MD5 hash over that, and returns that as an ETag header in +the response. The next time a client sends a request for the same resource, it uses that +hash as the `If-None-Match` value. The filter detects this, renders the view again, and +compares the two hashes. If they are equal, a `304` is returned. -Since all path segments may contain matrix variables, in some cases you need to be more -specific to identify where the variable is expected to be: +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. -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // GET /owners/42;q=11/pets/21;q=22 +This filter has a `writeWeakETag` parameter that configures the filter to write Weak ETags, +like this: `W/"02a2d595e6ed9a0b24f027f2b63b134d6"`, as defined in +https://tools.ietf.org/html/rfc7232#section-2.3[RFC 7232 Section 2.3]. - @GetMapping("/owners/{ownerId}/pets/{petId}") - public void findPet( - @MatrixVariable(name="q", pathVar="ownerId") int q1, - @MatrixVariable(name="q", pathVar="petId") int q2) { - // q1 == 11 - // q2 == 22 - } ----- +[[mvc-controller]] +== Annotated Controllers +[.small]#<># -A matrix variable may be defined as optional and a default value specified: +Spring MVC provides an annotation-based programming model where `@Controller` and +`@RestController` components use annotations to express request mappings, request input, +exception handling, and more. Annotated controllers have flexible method signatures and +do not have to extend base classes nor implement specific interfaces. [source,java,indent=0] [subs="verbatim,quotes"] ---- - // GET /pets/42 - - @GetMapping("/pets/{petId}") - public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) { - - // q == 1 + @Controller + public class HelloController { + @GetMapping("/hello") + public String handle(Model model) { + model.addAttribute("message", "Hello World!"); + return "index"; + } } ---- -All matrix variables may be obtained in a Map: +In this particular example the method accepts a `Model` and returns a view name as a `String` +but many other options exist and are explained further below in this chapter. -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // GET /owners/42;q=11;r=12/pets/21;q=22;s=23 +[TIP] +==== +Guides and tutorials on https://spring.io/guides[spring.io] use the annotation-based +programming model described in this section. +==== - @GetMapping("/owners/{ownerId}/pets/{petId}") - public void findPet( - @MatrixVariable MultiValueMap matrixVars, - @MatrixVariable(pathVar="petId"") MultiValueMap petMatrixVars) { - // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23] - // petMatrixVars: ["q" : 22, "s" : 23] - } ----- +[[mvc-ann-controller]] +=== @Controller +[.small]#<># -Note that to enable the use of matrix variables, you must set the -`removeSemicolonContent` property of `RequestMappingHandlerMapping` to `false`. By -default it is set to `true`. +You can define controller beans using a standard Spring bean definition in the +Servlet's `WebApplicationContext`. The `@Controller` stereotype allows for auto-detection, +aligned with Spring general support for detecting `@Component` classes in the classpath +and auto-registering bean definitions for them. It also acts as a stereotype for the +annotated class, indicating its role as a web component. -[TIP] -==== +To enable auto-detection of such `@Controller` beans, you can add component scanning to +your Java configuration: -The MVC Java config and the MVC namespace both provide options for enabling the use of -matrix variables. +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + @ComponentScan("org.example.web") + public class WebConfig { -If you are using Java config, The <> section describes how the `RequestMappingHandlerMapping` can -be customized. + // ... + } +---- -In the MVC namespace, the `` element has an -`enable-matrix-variables` attribute that should be set to `true`. By default it is set -to `false`. +The XML configuration equivalent: [source,xml,indent=0] [subs="verbatim,quotes"] ---- + http://www.springframework.org/schema/context + http://www.springframework.org/schema/context/spring-context.xsd"> - + + + ---- -==== -[[mvc-ann-requestmapping-consumes]] -==== Consumable media types -[.small]#<># +`@RestController` is a composed annotation that is itself annotated with +`@Controller` and `@ResponseBody` indicating a controller whose every method inherits the type-level +`@ResponseBody` annotation and therefore writes to the response body (vs model-and-vew +rendering). -You can narrow the request mapping based on the `Content-Type` of the request: +[[mvc-ann-controller-advice]] +=== @ControllerAdvice + +The `@ControllerAdvice` annotation is a component annotation allowing implementation +classes to be auto-detected through classpath scanning. It is automatically enabled when +using the MVC namespace or the MVC Java config. + +Classes annotated with `@ControllerAdvice` can contain `@ExceptionHandler`, +`@InitBinder`, and `@ModelAttribute` annotated methods, and these methods will apply to +`@RequestMapping` methods across all controller hierarchies as opposed to the controller +hierarchy within which they are declared. + +`@RestControllerAdvice` is an alternative where `@ExceptionHandler` methods +assume `@ResponseBody` semantics by default. + +Both `@ControllerAdvice` and `@RestControllerAdvice` can target a subset of controllers: [source,java,indent=0] [subs="verbatim,quotes"] ---- - @PostMapping(path = "/pets", **consumes = "application/json"**) - public void addPet(@RequestBody Pet pet) { - // ... - } + // Target all Controllers annotated with @RestController + @ControllerAdvice(annotations = RestController.class) + public class AnnotationAdvice {} + + // Target all Controllers within specific packages + @ControllerAdvice("org.example.controllers") + public class BasePackageAdvice {} + + // Target all Controllers assignable to specific classes + @ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class}) + public class AssignableTypesAdvice {} ---- -The consumes attribute also supports negation expressions -- e.g. `!text/plain` means any -content type other than "text/plain". +Check out the +{api-spring-framework}/web/bind/annotation/ControllerAdvice.html[`@ControllerAdvice` +documentation] for more details. -You can declare a shared consumes attribute at the class level. Unlike most other request -mapping attributes however when used at the class level, a method-level consumes attribute -will overrides rather than extend the class level declaration. -[TIP] -==== -`MediaType` provides constants for commonly used media types -- e.g. -`APPLICATION_JSON_VALUE`, `APPLICATION_JSON_UTF8_VALUE`. -==== +[[mvc-ann-requestmapping]] +=== Mapping Requests +[.small]#<># + +The `@RequestMapping` annotation is used to map requests to controllers methods. It has +various attributes to match by URL, HTTP method, request parameters, headers, and media +types. It can be used at the class-level to express shared mappings or at the method level +to narrow down to a specific endpoint mapping. +There are also HTTP method specific shortcut variants of `@RequestMapping`: -[[mvc-ann-requestmapping-produces]] -==== Producible media types -[.small]#<># +- `@GetMapping` +- `@PostMapping` +- `@PutMapping` +- `@DeleteMapping` +- `@PatchMapping` -You can narrow the request mapping based on the `Accept` request header and the list of -content types that a controller method produces: +The shortcut variants are +https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model#composed-annotations[composed annotations] +-- themselves annotated with `@RequestMapping`. They are commonly used at the method level. +At the class level an `@RequestMapping` is more useful for expressing shared mappings. [source,java,indent=0] [subs="verbatim,quotes"] ---- - @GetMapping(path = "/pets/{petId}", **produces = "application/json;charset=UTF-8"**) - @ResponseBody - public Pet getPet(@PathVariable String petId) { - // ... - } ----- + @RestController + @RequestMapping("/persons") + class PersonController { -The media type can specify a character set. Negated expressions are supported -- e.g. -`!text/plain` means any content type other than "text/plain". + @GetMapping("/{id}") + public Person getPerson(@PathVariable Long id) { + // ... + } -You can declare a shared produces attribute at the class level. Unlike most other request -mapping attributes however when used at the class level, a method-level produces attribute -will overrides rather than extend the class level declaration. + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public void add(@RequestBody Person person) { + // ... + } + } +---- -[TIP] -==== -`MediaType` provides constants for commonly used media types -- e.g. -`APPLICATION_JSON_VALUE`, `APPLICATION_JSON_UTF8_VALUE`. -==== + +[[mvc-ann-requestmapping-proxying]] +==== AOP proxies + +In some cases a controller may need to be decorated with an AOP proxy at runtime. +One example is if you choose to have `@Transactional` annotations directly on the +controller. When this is the case, for controllers specifically, we recommend +using class-based proxying. This is typically the default choice with controllers. +However if a controller must implement an interface that is not a Spring Context +callback (e.g. `InitializingBean`, `*Aware`, etc), you may need to explicitly +configure class-based proxying. For example with ``, +change to ``. -[[mvc-ann-requestmapping-params-and-headers]] -==== Parameters, headers -[.small]#<># -You can narrow request mappings based on request parameter conditions. You can test for the -presence of a request parameter (`"myParam"`), for the absence (`"!myParam"`), or for a -specific value (`"myParam=myValue"`): +You can map requests using glob patterns and wildcards: + +* `?` matches one character +* `*` matches zero or more characters within a path segment +* `**` match zero or more path segments + +You can also declare URI variables and access their values with `@PathVariable`: [source,java,indent=0] [subs="verbatim,quotes"] ---- - @GetMapping(path = "/pets/{petId}", **params = "myParam=myValue"**) - public void findPet(@PathVariable String petId) { + @GetMapping("/owners/{ownerId}/pets/{petId}") + public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) { // ... } ---- -You can also use the same with request header conditions: +URI variables can be declared at the class and method level: +[source,java,intent=0] +[subs="verbatim,quotes"] +---- +@Controller +@RequestMapping("/owners/{ownerId}") +public class OwnerController { + + @GetMapping("/pets/{petId}") + public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) { + // ... + } +} +---- + +URI variables are automatically converted to the appropriate type or`TypeMismatchException` +is raised. Simple types -- `int`, `long`, `Date`, are supported by default and you can +register support for any other data type. +See <> and <>. + +URI variables can be named explicitly -- e.g. `@PathVariable("customId")`, but you can +leave that detail out if the names are the same and your code is compiled with debugging +information or with the `-parameters` compiler flag on Java 8. + +The syntax `{varName:regex}` declares a URI variable with a regular expressions with the +syntax `{varName:regex}` -- e.g. given URL `"/spring-web-3.0.5 .jar"`, the below method +extracts the name, version, and file extension: [source,java,indent=0] [subs="verbatim,quotes"] ---- - @GetMapping(path = "/pets", **headers = "myHeader=myValue"**) - public void findPet(@PathVariable String petId) { + @GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}") + public void handle(@PathVariable String version, @PathVariable String ext) { // ... } ---- -[TIP] +URI path patterns can also have embedded `${...}` placeholders that are resolved on startup + via `PropertyPlaceHolderConfigurer` against local, system, environment, and other property +sources. This can be used for example to parameterize a base URL based on some external +configuration. + +[NOTE] ==== -You can match `Content-Type` and `Accept` with the headers condition but it is better to use -<> and <> -instead. +Spring MVC uses the `PathMatcher` contract and the `AntPathMatcher` implementation from +`spring-core` for URI path matching. ==== -[[mvc-ann-requestmapping-head-options]] -==== HTTP HEAD, OPTIONS -[.small]#<># - -`@GetMapping` -- and also `@RequestMapping(method=HttpMethod.GET)`, support HTTP HEAD -transparently for request mapping purposes. Controller methods don't need to change. -A response wrapper, applied in `javax.servlet.http.HttpServlet`, ensures a `"Content-Length"` -header is set to the number of bytes written and without actually writing to the response. +[[mvc-ann-requestmapping-pattern-comparison]] +==== Pattern comparison +[.small]#<># -`@GetMapping` -- and also `@RequestMapping(method=HttpMethod.GET)`, are implicitly mapped to -and also support HTTP HEAD. An HTTP HEAD request is processed as if it were HTTP GET except -but instead of writing the body, the number of bytes are counted and the "Content-Length" -header set. +When multiple patterns match a URL, they must be compared to find the best match. This done +via `AntPathMatcher.getPatternComparator(String path)` which looks for patterns that more +specific. -By default HTTP OPTIONS is handled by setting the "Allow" response header to the list of HTTP -methods listed in all `@RequestMapping` methods with matching URL patterns. +A pattern is less specific if it has a lower count of URI variables and single wildcards +counted as 1 and double wildcards counted as 2. Given an equal score, the longer pattern is +chosen. Given the same score and length, the pattern with more URI variables than wildcards +is chosen. -For a `@RequestMapping` without HTTP method declarations, the "Allow" header is set to -`"GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS"`. Controller methods should always declare the -supported HTTP methods for example by using the HTTP method specific variants -- -`@GetMapping`, `@PostMapping`, etc. +The default mapping pattern `/{asterisk}{asterisk}` is excluded from scoring and always +sorted last. Also prefix patterns such as `/public/{asterisk}{asterisk}` are considered less +specific than other pattern that don't have double wildcards. -`@RequestMapping` method can be explicitly mapped to HTTP HEAD and HTTP OPTIONS, but that -is not necessary in the common case. +For the full details see `AntPatternComparator` in `AntPathMatcher` and also keep mind that +the `PathMatcher` implementation used can be customized. See <> +in the configuration section. -[[mvc-ann-methods]] -=== Handler Methods -[.small]#<># +[[mvc-ann-requestmapping-suffix-pattern-match]] +==== Suffix match -`@RequestMapping` handler methods have a flexible signature and can choose from a range of -supported controller method arguments and return values. +By default Spring MVC performs `".{asterisk}"` suffix pattern matching so that a +controller mapped to `/person` is also implicitly mapped to `/person.{asterisk}`. +This is used for URL based content negotiation, e.g. `/person.pdf`, `/person.xml`, etc. -[[mvc-ann-arguments]] -==== Method Arguments -[.small]#<># +Suffix pattern matching was quite helpful when browsers used to send Accept headers that +are hard to interpet consistently. In the present, and for REST services, the `Accept` +header should be the preferred choice. -The table below shows supported controller method arguments. Reactive types are not supported -for any arguments. +Suffix patterns can cause ambiguity and complexity in combination with path parameters, +encoded characters, and URI variables. It also makes it harder to reason about URL-based +authorization rules and security (see <>). -JDK 1.8's `java.util.Optional` is supported as a method argument in combination with -annotations that have a `required` attribute -- e.g. `@RequestParam`, `@RequestHeader`, -etc, and is equivalent to `required=false`. +Suffix pattern matching can be turned off completely or restricted to a set of explicitly +registered path extensions. We strongly recommend using of one those options. See +<> and <>. If you need URL based +content negotiation consider using query parameters instead. -[cols="1,2", options="header"] -|=== -|Controller method argument|Description -|`WebRequest`, `NativeWebRequest` -|Generic access to request parameters, request & session attributes, without direct -use of the Servlet API. +[[mvc-ann-requestmapping-rfd]] +==== Suffix match and RFD -|`javax.servlet.ServletRequest`, `javax.servlet.ServletResponse` -|Choose any specific request or response type -- e.g. `ServletRequest`, `HttpServletRequest`, -or Spring's `MultipartRequest`, `MultipartHttpServletRequest`. +Reflected file download (RFD) attack is similar to XSS in that it relies on request input, +e.g. query parameter, URI variable, being reflected in the response. However instead of +inserting JavaScript into HTML, an RFD attack relies on the browser switching to perform a +download and treating the response as an executable script when double-clicked later. -|`javax.servlet.http.HttpSession` -|Enforces the presence of a session. As a consequence, such an argument is never `null`. + -**Note:** Session access is not thread-safe. Consider setting the -``RequestMappingHandlerAdapter``'s "synchronizeOnSession" flag to "true" if multiple -requests are allowed to access a session concurrently. +In Spring MVC `@ResponseBody` and `ResponseEntity` methods are at risk because +they can render different content types which clients can request via URL path extensions. +Disabling suffix pattern matching and the use of path extensions for content negotiation +lower the risk but are not sufficient to prevent RFD attacks. -|`javax.servlet.http.PushBuilder` -|Servlet 4.0 push builder API for programmatic HTTP/2 resource pushes. +To prevent RFD attacks, prior to rendering the response body Spring MVC adds a +`Content-Disposition:inline;filename=f.txt` header to suggest a fixed and safe download +file. This is done only if the URL path contains a file extension that is neither whitelisted +nor explicitly registered for content negotiation purposes. However it may potentially have +side effects when URLs are typed directly into a browser. -|`java.security.Principal` -|Currently authenticated user; possibly a specific `Principal` implementation class if known. +Many common path extensions are whitelisted by default. Applications with custom +`HttpMessageConverter` implementations can explicitly register file extensions for content +negotiation to avoid having a `Content-Disposition` header added for those extensions. +See <>. -|`HttpMethod` -|The HTTP method of the request. +Check http://pivotal.io/security/cve-2015-5211[CVE-2015-5211] for additional +recommendations related to RFD. -|`java.util.Locale` -|The current request locale, determined by the most specific `LocaleResolver` available, in -effect, the configured `LocaleResolver`/`LocaleContextResolver`. -|Java 6+: `java.util.TimeZone` + -Java 8+: `java.time.ZoneId` -|The time zone associated with the current request, as determined by a `LocaleContextResolver`. -|`java.io.InputStream`, `java.io.Reader` -|For access to the raw request body as exposed by the Servlet API. +[[mvc-ann-matrix-variables]] +==== Matrix variables +The URI specification http://tools.ietf.org/html/rfc3986#section-3.3[RFC 3986] defines +the possibility of including name-value pairs within path segments. There is no specific +term used in the spec. The general "URI path parameters" could be applied although the +more unique http://www.w3.org/DesignIssues/MatrixURIs.html["Matrix URIs"], originating +from an old post by Tim Berners-Lee, is also frequently used and fairly well known. +Within Spring MVC these are referred to as matrix variables. -|`java.io.OutputStream`, `java.io.Writer` -|For access to the raw response body as exposed by the Servlet API. +Matrix variables can appear in any path segment, each matrix variable separated with a +";" (semicolon). For example: `"/cars;color=red;year=2012"`. Multiple values may be +either "," (comma) separated `"color=red,green,blue"` or the variable name may be +repeated `"color=red;color=green;color=blue"`. -|`@PathVariable` -|For access to URI template variables. See <>. +If a URL is expected to contain matrix variables, the request mapping pattern must +represent them with a URI template. This ensures the request can be matched correctly +regardless of whether matrix variables are present or not and in what order they are +provided. -|`@MatrixVariable` -|For access to name-value pairs in URI path segments. See <>. +Below is an example of extracting the matrix variable "q": -|`@RequestParam` -|For access to Servlet request parameters. Parameter values are converted to the declared -method argument type. See <>. +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // GET /pets/42;q=11;r=22 -|`@RequestHeader` -|For access to request headers. Header values are converted to the declared method argument -type. See <>. + @GetMapping("/pets/{petId}") + public void findPet(@PathVariable String petId, @MatrixVariable int q) { -|`@RequestBody` -|For access to the HTTP request body. Body content is converted to the declared method -argument type using ``HttpMessageConverter``s. See <>. + // petId == 42 + // q == 11 -|`HttpEntity` -|For access to request headers and body. The body is converted with ``HttpMessageConverter``s. -See <>. + } +---- -|`@RequestPart` -|For access to a part in a "multipart/form-data" request. -See <> and <>. +Since all path segments may contain matrix variables, in some cases you need to be more +specific to identify where the variable is expected to be: -|`java.util.Map`, `org.springframework.ui.Model`, `org.springframework.ui.ModelMap` -|For access and updates of the implicit model that is exposed to the web view. - -|`RedirectAttributes` -|Specify attributes to use in case of a redirect -- i.e. to be appended to the query -string, and/or flash attributes to be stored temporarily until the request after redirect. -See <> and <>. - -|Command or form object (with optional `@ModelAttribute`) -|Command object whose properties to bind to request parameters -- via setters or directly to -fields, with customizable type conversion, depending on `@InitBinder` methods and/or the -HandlerAdapter configuration (see the `webBindingInitializer` property on -`RequestMappingHandlerAdapter`). +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // GET /owners/42;q=11/pets/21;q=22 -Command objects along with their validation results are exposed as model attributes, by -default using the command class name - e.g. model attribute "orderAddress" for a command -object of type "some.package.OrderAddress". `@ModelAttribute` can be used to customize the -model attribute name. + @GetMapping("/owners/{ownerId}/pets/{petId}") + public void findPet( + @MatrixVariable(name="q", pathVar="ownerId") int q1, + @MatrixVariable(name="q", pathVar="petId") int q2) { -|`Errors`, `BindingResult` -|Validation results for the command/form object data binding; this argument must be -declared immediately after the command/form object in the controller method signature. + // q1 == 11 + // q2 == 22 -|`SessionStatus` -|For marking form processing complete which triggers cleanup of session attributes -declared through a class-level `@SessionAttributes` annotation. + } +---- -|`UriComponentsBuilder` -|For preparing a URL relative to the current request's host, port, scheme, context path, and -the literal part of the servlet mapping also taking into account `Forwarded` and -`X-Forwarded-*` headers. +A matrix variable may be defined as optional and a default value specified: -|`@SessionAttribute` -|For access to any session attribute; in contrast to model attributes stored in the session -as a result of a class-level `@SessionAttributes` declaration. +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // GET /pets/42 -|`@RequestAttribute` -|For access to request attributes. -|=== + @GetMapping("/pets/{petId}") + public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) { -[[mvc-ann-return-types]] -==== Return Values -[.small]#<># + // q == 1 -The table below shows supported controller method return values. Reactive types are -supported for all return values, see below for more details. + } +---- -[cols="1,2", options="header"] -|=== -|Controller method return value|Description +All matrix variables may be obtained in a Map: -|`@ResponseBody` -|The return value is converted through ``HttpMessageConverter``s and written to the -response. See <>. +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // GET /owners/42;q=11;r=12/pets/21;q=22;s=23 -|`HttpEntity`, `ResponseEntity` -|The return value specifies the full response including HTTP headers and body be converted -through ``HttpMessageConverter``s and written to the response. See <>. + @GetMapping("/owners/{ownerId}/pets/{petId}") + public void findPet( + @MatrixVariable MultiValueMap matrixVars, + @MatrixVariable(pathVar="petId"") MultiValueMap petMatrixVars) { -|`HttpHeaders` -|For returning a response with headers and no body. + // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23] + // petMatrixVars: ["q" : 22, "s" : 23] -|`String` -|A view name to be resolved with ``ViewResolver``'s and used together with the implicit -model -- determined through command objects and `@ModelAttribute` methods. The handler -method may also programmatically enrich the model by declaring a `Model` argument (see -above). + } +---- -|`View` -|A `View` instance to use for rendering together with the implicit model -- determined -through command objects and `@ModelAttribute` methods. The handler method may also -programmatically enrich the model by declaring a `Model` argument (see above). +Note that to enable the use of matrix variables, you must set the +`removeSemicolonContent` property of `RequestMappingHandlerMapping` to `false`. By +default it is set to `true`. -|`java.util.Map`, `org.springframework.ui.Model` -|Attributes to be added to the implicit model with the view name implicitly determined -through a `RequestToViewNameTranslator`. +[TIP] +==== -|`ModelAndView` object -|The view and model attributes to use, and optionally a response status. +The MVC Java config and the MVC namespace both provide options for enabling the use of +matrix variables. -|`void` -|For use in methods that declare a `ServletResponse` or `OutputStream` argument and write -to the response body; or if the view name is supposed to be implicitly determined through a -`RequestToViewNameTranslator`. +If you are using Java config, The <> section describes how the `RequestMappingHandlerMapping` can +be customized. -|`Callable` -|Produce any of the above return values asynchronously in a Spring MVC managed thread. +In the MVC namespace, the `` element has an +`enable-matrix-variables` attribute that should be set to `true`. By default it is set +to `false`. -|`DeferredResult` -|Produce any of the above return values asynchronously from any thread -- e.g. possibly as a -result of some event or callback. +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + -|`ListenableFuture`, -`java.util.concurrent.CompletionStage`, -`java.util.concurrent.CompletableFuture` -|Alternative to `DeferredResult` as a convenience for example when an underlying service -returns one of those. + -|`ResponseBodyEmitter`, `SseEmitter` -|Emit a stream of objects asynchronously to be written to the response with -``HttpMessageConverter``'s; also supported as the body of a `ResponseEntity`. + +---- +==== -|`StreamingResponseBody` -|Write to the response `OutputStream` asynchronously; also supported as the body of a -`ResponseEntity`. +[[mvc-ann-requestmapping-consumes]] +==== Consumable media types +[.small]#<># -|Reactive types -- Reactor, RxJava, or others via `ReactiveAdapterRegistry` -|Alternative to ``DeferredResult` with multi-value streams (e.g. `Flux`, `Observable`) -collected to a `List`. +You can narrow the request mapping based on the `Content-Type` of the request: -For streaming scenarios -- .e.g. `text/event-stream`, `application/json+stream`, -`SseEmitter` and `ResponseBodyEmitter` are used instead, where `ServletOutputStream` blocking -I/O is performed on a Spring MVC managed thread and back pressure applied against the -completion of each write. +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @PostMapping(path = "/pets", **consumes = "application/json"**) + public void addPet(@RequestBody Pet pet) { + // ... + } +---- -See <>. +The consumes attribute also supports negation expressions -- e.g. `!text/plain` means any +content type other than "text/plain". -|Any other return type -|A single model attribute to be added to the implicit model with the view name implicitly -determined through a `RequestToViewNameTranslator`; the attribute name may be specified -through a method-level `@ModelAttribute` or otherwise a name is selected based on the -class name of the return type. -|=== +You can declare a shared consumes attribute at the class level. Unlike most other request +mapping attributes however when used at the class level, a method-level consumes attribute +will overrides rather than extend the class level declaration. +[TIP] +==== +`MediaType` provides constants for commonly used media types -- e.g. +`APPLICATION_JSON_VALUE`, `APPLICATION_JSON_UTF8_VALUE`. +==== -[[mvc-ann-requestparam]] -==== @RequestParam -Use the `@RequestParam` annotation to bind request parameters to a method parameter in -your controller. +[[mvc-ann-requestmapping-produces]] +==== Producible media types +[.small]#<># -The following code snippet shows the usage: +You can narrow the request mapping based on the `Accept` request header and the list of +content types that a controller method produces: [source,java,indent=0] [subs="verbatim,quotes"] ---- - @Controller - @RequestMapping("/pets") - @SessionAttributes("pet") - public class EditPetForm { - - // ... - - @GetMapping - public String setupForm(**@RequestParam("petId") int petId**, ModelMap model) { - Pet pet = this.clinic.loadPet(petId); - model.addAttribute("pet", pet); - return "petForm"; - } - + @GetMapping(path = "/pets/{petId}", **produces = "application/json;charset=UTF-8"**) + @ResponseBody + public Pet getPet(@PathVariable String petId) { // ... - } ---- -Parameters using this annotation are required by default, but you can specify that a -parameter is optional by setting ``@RequestParam``'s `required` attribute to `false` -(e.g., `@RequestParam(name="id", required=false)`). +The media type can specify a character set. Negated expressions are supported -- e.g. +`!text/plain` means any content type other than "text/plain". -Type conversion is applied automatically if the target method parameter type is not -`String`. See <>. +You can declare a shared produces attribute at the class level. Unlike most other request +mapping attributes however when used at the class level, a method-level produces attribute +will overrides rather than extend the class level declaration. -When an `@RequestParam` annotation is used on a `Map` or -`MultiValueMap` argument, the map is populated with all request -parameters. +[TIP] +==== +`MediaType` provides constants for commonly used media types -- e.g. +`APPLICATION_JSON_VALUE`, `APPLICATION_JSON_UTF8_VALUE`. +==== -[[mvc-ann-requestbody]] -==== @RequestBody -The `@RequestBody` method parameter annotation indicates that a method parameter should -be bound to the value of the HTTP request body. For example: +[[mvc-ann-requestmapping-params-and-headers]] +==== Parameters, headers +[.small]#<># + +You can narrow request mappings based on request parameter conditions. You can test for the +presence of a request parameter (`"myParam"`), for the absence (`"!myParam"`), or for a +specific value (`"myParam=myValue"`): [source,java,indent=0] [subs="verbatim,quotes"] ---- - @PutMapping("/something") - public void handle(@RequestBody String body, Writer writer) throws IOException { - writer.write(body); + @GetMapping(path = "/pets/{petId}", **params = "myParam=myValue"**) + public void findPet(@PathVariable String petId) { + // ... } ---- -You convert the request body to the method argument by using an `HttpMessageConverter`. -`HttpMessageConverter` is responsible for converting from the HTTP request message to an -object and converting from an object to the HTTP response body. The -`RequestMappingHandlerAdapter` supports the `@RequestBody` annotation with the following -default `HttpMessageConverters`: - -* `ByteArrayHttpMessageConverter` converts byte arrays. -* `StringHttpMessageConverter` converts strings. -* `FormHttpMessageConverter` converts form data to/from a MultiValueMap. -* `SourceHttpMessageConverter` converts to/from a javax.xml.transform.Source. +You can also use the same with request header conditions: -For more information on these converters, see <>. Also note that if using the MVC namespace or the MVC Java config, a -wider range of message converters are registered by default. See <> for -more information. - -If you intend to read and write XML, you will need to configure the -`MarshallingHttpMessageConverter` with a specific `Marshaller` and an `Unmarshaller` -implementation from the `org.springframework.oxm` package. The example below shows how -to do that directly in your configuration but if your application is configured through -the MVC namespace or the MVC Java config see <> instead. - -[source,xml,indent=0] +[source,java,indent=0] [subs="verbatim,quotes"] ---- - - - - - - - - - - - - - - - - - + @GetMapping(path = "/pets", **headers = "myHeader=myValue"**) + public void findPet(@PathVariable String petId) { + // ... + } ---- -An `@RequestBody` method parameter can be annotated with `@Valid`, in which case it will -be validated using the configured `Validator` instance. When using the MVC namespace or -the MVC Java config, a JSR-303 validator is configured automatically assuming a JSR-303 -implementation is available on the classpath. - -Just like with `@ModelAttribute` parameters, an `Errors` argument can be used to examine -the errors. If such an argument is not declared, a `MethodArgumentNotValidException` -will be raised. The exception is handled in the `DefaultHandlerExceptionResolver`, which -sends a `400` error back to the client. - -[NOTE] +[TIP] ==== -Also see <> for -information on configuring message converters and a validator through the MVC namespace -or the MVC Java config. +You can match `Content-Type` and `Accept` with the headers condition but it is better to use +<> and <> +instead. ==== -[[mvc-ann-responsebody]] -==== @ResponseBody - -The `@ResponseBody` annotation is similar to `@RequestBody`. This annotation can be placed -on a method and indicates that the return type should be written straight to the HTTP -response body (and not placed in a Model, or interpreted as a view name). For example: +[[mvc-ann-requestmapping-head-options]] +==== HTTP HEAD, OPTIONS +[.small]#<># -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @GetMapping("/something") - @ResponseBody - public String helloWorld() { - return "Hello World"; - } ----- +`@GetMapping` -- and also `@RequestMapping(method=HttpMethod.GET)`, support HTTP HEAD +transparently for request mapping purposes. Controller methods don't need to change. +A response wrapper, applied in `javax.servlet.http.HttpServlet`, ensures a `"Content-Length"` +header is set to the number of bytes written and without actually writing to the response. -The above example will result in the text `Hello World` being written to the HTTP -response stream. +`@GetMapping` -- and also `@RequestMapping(method=HttpMethod.GET)`, are implicitly mapped to +and also support HTTP HEAD. An HTTP HEAD request is processed as if it were HTTP GET except +but instead of writing the body, the number of bytes are counted and the "Content-Length" +header set. -As with `@RequestBody`, Spring converts the returned object to a response body by using -an `HttpMessageConverter`. For more information on these converters, see the previous -section and <>. +By default HTTP OPTIONS is handled by setting the "Allow" response header to the list of HTTP +methods listed in all `@RequestMapping` methods with matching URL patterns. -[[mvc-ann-restcontroller]] -==== @RestController +For a `@RequestMapping` without HTTP method declarations, the "Allow" header is set to +`"GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS"`. Controller methods should always declare the +supported HTTP methods for example by using the HTTP method specific variants -- +`@GetMapping`, `@PostMapping`, etc. -It's a very common use case to have Controllers implement a REST API, thus serving only -JSON, XML or custom MediaType content. For convenience, instead of annotating all your -`@RequestMapping` methods with `@ResponseBody`, you can annotate your controller Class -with `@RestController`. +`@RequestMapping` method can be explicitly mapped to HTTP HEAD and HTTP OPTIONS, but that +is not necessary in the common case. -{api-spring-framework}/web/bind/annotation/RestController.html[`@RestController`] -is a stereotype annotation that combines `@ResponseBody` and `@Controller`. More than -that, it gives more meaning to your Controller and also may carry additional semantics -in future releases of the framework. -As with regular ``@Controller``s, a `@RestController` may be assisted by -`@ControllerAdvice` or `@RestControllerAdvice` beans. See the <> -section for more details. -[[mvc-ann-httpentity]] -==== HttpEntity +[[mvc-ann-methods]] +=== Handler Methods +[.small]#<># -The `HttpEntity` is similar to `@RequestBody` and `@ResponseBody`. Besides getting -access to the request and response body, `HttpEntity` (and the response-specific -subclass `ResponseEntity`) also allows access to the request and response headers, like -so: +`@RequestMapping` handler methods have a flexible signature and can choose from a range of +supported controller method arguments and return values. -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @RequestMapping("/something") - public ResponseEntity handle(HttpEntity requestEntity) throws UnsupportedEncodingException { - String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader"); - byte[] requestBody = requestEntity.getBody(); +[[mvc-ann-arguments]] +==== Method Arguments +[.small]#<># - // do something with request header and body +The table below shows supported controller method arguments. Reactive types are not supported +for any arguments. - HttpHeaders responseHeaders = new HttpHeaders(); - responseHeaders.set("MyResponseHeader", "MyValue"); - return new ResponseEntity("Hello World", responseHeaders, HttpStatus.CREATED); - } ----- +JDK 1.8's `java.util.Optional` is supported as a method argument in combination with +annotations that have a `required` attribute -- e.g. `@RequestParam`, `@RequestHeader`, +etc, and is equivalent to `required=false`. -The above example gets the value of the `MyRequestHeader` request header, and reads the -body as a byte array. It adds the `MyResponseHeader` to the response, writes `Hello -World` to the response stream, and sets the response status code to 201 (Created). +[cols="1,2", options="header"] +|=== +|Controller method argument|Description -As with `@RequestBody` and `@ResponseBody`, Spring uses `HttpMessageConverter` to -convert from and to the request and response streams. For more information on these -converters, see the previous section and <>. +|`WebRequest`, `NativeWebRequest` +|Generic access to request parameters, request & session attributes, without direct +use of the Servlet API. +|`javax.servlet.ServletRequest`, `javax.servlet.ServletResponse` +|Choose any specific request or response type -- e.g. `ServletRequest`, `HttpServletRequest`, +or Spring's `MultipartRequest`, `MultipartHttpServletRequest`. -[[mvc-ann-modelattrib-methods]] -==== @ModelAttribute method +|`javax.servlet.http.HttpSession` +|Enforces the presence of a session. As a consequence, such an argument is never `null`. + +**Note:** Session access is not thread-safe. Consider setting the +``RequestMappingHandlerAdapter``'s "synchronizeOnSession" flag to "true" if multiple +requests are allowed to access a session concurrently. -The `@ModelAttribute` annotation can be used on methods or on method arguments. This -section explains its usage on methods while the next section explains its usage on -method arguments. +|`javax.servlet.http.PushBuilder` +|Servlet 4.0 push builder API for programmatic HTTP/2 resource pushes. -An `@ModelAttribute` on a method indicates the purpose of that method is to add one or -more model attributes. Such methods support the same argument types as `@RequestMapping` -methods but cannot be mapped directly to requests. Instead `@ModelAttribute` methods in -a controller are invoked before `@RequestMapping` methods, within the same controller. A -couple of examples: +|`java.security.Principal` +|Currently authenticated user; possibly a specific `Principal` implementation class if known. -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // Add one attribute - // The return value of the method is added to the model under the name "account" - // You can customize the name via @ModelAttribute("myAccount") +|`HttpMethod` +|The HTTP method of the request. - @ModelAttribute - public Account addAccount(@RequestParam String number) { - return accountManager.findAccount(number); - } +|`java.util.Locale` +|The current request locale, determined by the most specific `LocaleResolver` available, in +effect, the configured `LocaleResolver`/`LocaleContextResolver`. - // Add multiple attributes +|Java 6+: `java.util.TimeZone` + +Java 8+: `java.time.ZoneId` +|The time zone associated with the current request, as determined by a `LocaleContextResolver`. - @ModelAttribute - public void populateModel(@RequestParam String number, Model model) { - model.addAttribute(accountManager.findAccount(number)); - // add more ... - } ----- +|`java.io.InputStream`, `java.io.Reader` +|For access to the raw request body as exposed by the Servlet API. -`@ModelAttribute` methods are used to populate the model with commonly needed attributes -for example to fill a drop-down with states or with pet types, or to retrieve a command -object like Account in order to use it to represent the data on an HTML form. The latter -case is further discussed in the next section. +|`java.io.OutputStream`, `java.io.Writer` +|For access to the raw response body as exposed by the Servlet API. -Note the two styles of `@ModelAttribute` methods. In the first, the method adds an -attribute implicitly by returning it. In the second, the method accepts a `Model` and -adds any number of model attributes to it. You can choose between the two styles -depending on your needs. +|`@PathVariable` +|For access to URI template variables. See <>. -A controller can have any number of `@ModelAttribute` methods. All such methods are -invoked before `@RequestMapping` methods of the same controller. +|`@MatrixVariable` +|For access to name-value pairs in URI path segments. See <>. -`@ModelAttribute` methods can also be defined in an ``@ControllerAdvice``-annotated class -and such methods apply to many controllers. See the <> section -for more details. +|`@RequestParam` +|For access to Servlet request parameters. Parameter values are converted to the declared +method argument type. See <>. -[TIP] -==== +|`@RequestHeader` +|For access to request headers. Header values are converted to the declared method argument +type. See <>. -What happens when a model attribute name is not explicitly specified? In such cases a -default name is assigned to the model attribute based on its type. For example if the -method returns an object of type `Account`, the default name used is "account". You can -change that through the value of the `@ModelAttribute` annotation. If adding attributes -directly to the `Model`, use the appropriate overloaded `addAttribute(..)` method - -i.e., with or without an attribute name. -==== +|`@RequestBody` +|For access to the HTTP request body. Body content is converted to the declared method +argument type using ``HttpMessageConverter``s. See <>. -The `@ModelAttribute` annotation can be used on `@RequestMapping` methods as well. In -that case the return value of the `@RequestMapping` method is interpreted as a model -attribute rather than as a view name. The view name is then derived based on view name -conventions instead, much like for methods returning `void` -- see <>. +|`HttpEntity` +|For access to request headers and body. The body is converted with ``HttpMessageConverter``s. +See <>. +|`@RequestPart` +|For access to a part in a "multipart/form-data" request. +See <> and <>. -[[mvc-ann-modelattrib-method-args]] -==== @ModelAttribute arguments +|`java.util.Map`, `org.springframework.ui.Model`, `org.springframework.ui.ModelMap` +|For access and updates of the implicit model that is exposed to the web view. -As explained in the previous section `@ModelAttribute` can be used on methods or on -method arguments. This section explains its usage on method arguments. +|`RedirectAttributes` +|Specify attributes to use in case of a redirect -- i.e. to be appended to the query +string, and/or flash attributes to be stored temporarily until the request after redirect. +See <> and <>. -An `@ModelAttribute` on a method argument indicates the argument should be retrieved -from the model. If not present in the model, the argument should be instantiated first -and then added to the model. Once present in the model, the argument's fields should be -populated from all request parameters that have matching names. This is known as data -binding in Spring MVC, a very useful mechanism that saves you from having to parse each -form field individually. +|Command or form object (with optional `@ModelAttribute`) +|Command object whose properties to bind to request parameters -- via setters or directly to +fields, with customizable type conversion, depending on `@InitBinder` methods and/or the +HandlerAdapter configuration (see the `webBindingInitializer` property on +`RequestMappingHandlerAdapter`). -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @PostMapping("/owners/{ownerId}/pets/{petId}/edit") - public String processSubmit(**@ModelAttribute Pet pet**) { } ----- +Command objects along with their validation results are exposed as model attributes, by +default using the command class name - e.g. model attribute "orderAddress" for a command +object of type "some.package.OrderAddress". `@ModelAttribute` can be used to customize the +model attribute name. -Given the above example where can the Pet instance come from? There are several options: +|`Errors`, `BindingResult` +|Validation results for the command/form object data binding; this argument must be +declared immediately after the command/form object in the controller method signature. + +|`SessionStatus` +|For marking form processing complete which triggers cleanup of session attributes +declared through a class-level `@SessionAttributes` annotation. + +|`UriComponentsBuilder` +|For preparing a URL relative to the current request's host, port, scheme, context path, and +the literal part of the servlet mapping also taking into account `Forwarded` and +`X-Forwarded-*` headers. + +|`@SessionAttribute` +|For access to any session attribute; in contrast to model attributes stored in the session +as a result of a class-level `@SessionAttributes` declaration. + +|`@RequestAttribute` +|For access to request attributes. +|=== + +[[mvc-ann-return-types]] +==== Return Values +[.small]#<># + +The table below shows supported controller method return values. Reactive types are +supported for all return values, see below for more details. + +[cols="1,2", options="header"] +|=== +|Controller method return value|Description + +|`@ResponseBody` +|The return value is converted through ``HttpMessageConverter``s and written to the +response. See <>. + +|`HttpEntity`, `ResponseEntity` +|The return value specifies the full response including HTTP headers and body be converted +through ``HttpMessageConverter``s and written to the response. See <>. + +|`HttpHeaders` +|For returning a response with headers and no body. + +|`String` +|A view name to be resolved with ``ViewResolver``'s and used together with the implicit +model -- determined through command objects and `@ModelAttribute` methods. The handler +method may also programmatically enrich the model by declaring a `Model` argument (see +above). + +|`View` +|A `View` instance to use for rendering together with the implicit model -- determined +through command objects and `@ModelAttribute` methods. The handler method may also +programmatically enrich the model by declaring a `Model` argument (see above). + +|`java.util.Map`, `org.springframework.ui.Model` +|Attributes to be added to the implicit model with the view name implicitly determined +through a `RequestToViewNameTranslator`. + +|`ModelAndView` object +|The view and model attributes to use, and optionally a response status. + +|`void` +|For use in methods that declare a `ServletResponse` or `OutputStream` argument and write +to the response body; or if the view name is supposed to be implicitly determined through a +`RequestToViewNameTranslator`. + +|`Callable` +|Produce any of the above return values asynchronously in a Spring MVC managed thread. + +|`DeferredResult` +|Produce any of the above return values asynchronously from any thread -- e.g. possibly as a +result of some event or callback. + +|`ListenableFuture`, +`java.util.concurrent.CompletionStage`, +`java.util.concurrent.CompletableFuture` +|Alternative to `DeferredResult` as a convenience for example when an underlying service +returns one of those. + +|`ResponseBodyEmitter`, `SseEmitter` +|Emit a stream of objects asynchronously to be written to the response with +``HttpMessageConverter``'s; also supported as the body of a `ResponseEntity`. + +|`StreamingResponseBody` +|Write to the response `OutputStream` asynchronously; also supported as the body of a +`ResponseEntity`. + +|Reactive types -- Reactor, RxJava, or others via `ReactiveAdapterRegistry` +|Alternative to ``DeferredResult` with multi-value streams (e.g. `Flux`, `Observable`) +collected to a `List`. + +For streaming scenarios -- .e.g. `text/event-stream`, `application/json+stream`, +`SseEmitter` and `ResponseBodyEmitter` are used instead, where `ServletOutputStream` blocking +I/O is performed on a Spring MVC managed thread and back pressure applied against the +completion of each write. + +See <>. + +|Any other return type +|A single model attribute to be added to the implicit model with the view name implicitly +determined through a `RequestToViewNameTranslator`; the attribute name may be specified +through a method-level `@ModelAttribute` or otherwise a name is selected based on the +class name of the return type. +|=== + + +[[mvc-ann-requestparam]] +==== @RequestParam + +Use the `@RequestParam` annotation to bind request parameters to a method parameter in +your controller. + +The following code snippet shows the usage: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + @RequestMapping("/pets") + @SessionAttributes("pet") + public class EditPetForm { + + // ... + + @GetMapping + public String setupForm(**@RequestParam("petId") int petId**, ModelMap model) { + Pet pet = this.clinic.loadPet(petId); + model.addAttribute("pet", pet); + return "petForm"; + } + + // ... + + } +---- + +Parameters using this annotation are required by default, but you can specify that a +parameter is optional by setting ``@RequestParam``'s `required` attribute to `false` +(e.g., `@RequestParam(name="id", required=false)`). + +Type conversion is applied automatically if the target method parameter type is not +`String`. See <>. + +When an `@RequestParam` annotation is used on a `Map` or +`MultiValueMap` argument, the map is populated with all request +parameters. + + +[[mvc-ann-typeconversion]] +==== Type Conversion +String-based values extracted from the request including request parameters, path +variables, request headers, and cookie values may need to be converted to the target +type of the method parameter or field (e.g., binding a request parameter to a field in +an `@ModelAttribute` parameter) they're bound to. If the target type is not `String`, +Spring automatically converts to the appropriate type. All simple types such as int, +long, Date, etc. are supported. You can further customize the conversion process through +a `WebDataBinder`, see <>, or by registering `Formatters` with +the `FormattingConversionService`, see <>. + + +[[mvc-ann-requestheader]] +==== @RequestHeader +The `@RequestHeader` annotation allows a method parameter to be bound to a request header. + +Here is a sample request header: + +[literal] +[subs="verbatim,quotes"] +---- +Host localhost:8080 +Accept text/html,application/xhtml+xml,application/xml;q=0.9 +Accept-Language fr,en-gb;q=0.7,en;q=0.3 +Accept-Encoding gzip,deflate +Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 +Keep-Alive 300 +---- + +The following code sample demonstrates how to get the value of the `Accept-Encoding` and +`Keep-Alive` headers: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @RequestMapping("/displayHeaderInfo.do") + public void displayHeaderInfo(**@RequestHeader("Accept-Encoding")** String encoding, + **@RequestHeader("Keep-Alive")** long keepAlive) { + //... + } +---- + +Type conversion is applied automatically if the method parameter is not `String`. See +<>. + +When an `@RequestHeader` annotation is used on a `Map`, +`MultiValueMap`, or `HttpHeaders` argument, the map is populated +with all header values. + + +[TIP] +==== +Built-in support is available for converting a comma-separated string into an +array/collection of strings or other types known to the type conversion system. For +example a method parameter annotated with `@RequestHeader("Accept")` may be of type +`String` but also `String[]` or `List`. +==== + + + +[[mvc-ann-cookievalue]] +==== @CookieValue + +The `@CookieValue` annotation allows a method parameter to be bound to the value of an +HTTP cookie. + +Let us consider that the following cookie has been received with an http request: + +[literal] +[subs="verbatim,quotes"] +---- +JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84 +---- + +The following code sample demonstrates how to get the value of the `JSESSIONID` cookie: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @RequestMapping("/displayHeaderInfo.do") + public void displayHeaderInfo(**@CookieValue("JSESSIONID")** String cookie) { + //... + } +---- + +Type conversion is applied automatically if the target method parameter type is not +`String`. See <>. + + +[[mvc-ann-modelattrib-method-args]] +==== @ModelAttribute + +As explained in the previous section `@ModelAttribute` can be used on methods or on +method arguments. This section explains its usage on method arguments. + +An `@ModelAttribute` on a method argument indicates the argument should be retrieved +from the model. If not present in the model, the argument should be instantiated first +and then added to the model. Once present in the model, the argument's fields should be +populated from all request parameters that have matching names. This is known as data +binding in Spring MVC, a very useful mechanism that saves you from having to parse each +form field individually. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @PostMapping("/owners/{ownerId}/pets/{petId}/edit") + public String processSubmit(**@ModelAttribute Pet pet**) { } +---- + +Given the above example where can the Pet instance come from? There are several options: * It may already be in the model due to use of `@SessionAttributes` -- see <>. @@ -1496,10 +1895,87 @@ See <> and <> for details on how to configure and use validation. - -[[mvc-ann-sessionattributes]] -==== @SessionAttributes - +[[mvc-multipart-forms]] +==== File upload +After the `MultipartResolver` completes its job, the request is processed like any +other. First, create a form with a file input that will allow the user to upload a form. +The encoding attribute ( `enctype="multipart/form-data"`) lets the browser know how to +encode the form as multipart request: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + Upload a file please + + +

Please upload a file

+
+ + + +
+ + +---- + +The next step is to create a controller that handles the file upload. This controller is +very similar to a <>, except that we +use `MultipartHttpServletRequest` or `MultipartFile` in the method parameters: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + public class FileUploadController { + + @PostMapping("/form") + public String handleFormUpload(@RequestParam("name") String name, + @RequestParam("file") MultipartFile file) { + + if (!file.isEmpty()) { + byte[] bytes = file.getBytes(); + // store the bytes somewhere + return "redirect:uploadSuccess"; + } + + return "redirect:uploadFailure"; + } + + } +---- + +Note how the `@RequestParam` method parameters map to the input elements declared in the +form. In this example, nothing is done with the `byte[]`, but in practice you can save +it in a database, store it on the file system, and so on. + +When using Servlet 3.0 multipart parsing you can also use `javax.servlet.http.Part` for +the method parameter: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + public class FileUploadController { + + @PostMapping("/form") + public String handleFormUpload(@RequestParam("name") String name, + @RequestParam("file") Part file) { + + InputStream inputStream = file.getInputStream(); + // store bytes from uploaded file somewhere + + return "redirect:uploadSuccess"; + } + + } +---- + + +[[mvc-ann-sessionattributes]] +==== @SessionAttributes + `@SessionAttributes` is used to store model attributes in the HTTP session between requests. It is a type-level annotation that declares session attributes used by a specific handler. This will typically list the names of model attributes or types of @@ -1561,271 +2037,219 @@ access pre-existing request attributes created by a filter or interceptor: ---- +[[mvc-multipart-forms-non-browsers]] +==== @RequestPart +Multipart requests can also be submitted from non-browser clients in a RESTful service +scenario. All of the above examples and configuration apply here as well. However, +unlike browsers that typically submit files and simple form fields, a programmatic +client can also send more complex data of a specific content type -- for example a +multipart request with a file and second part with JSON formatted data: - -[[mvc-ann-form-urlencoded-data]] -==== HTTP PUT form data - -The previous sections covered use of `@ModelAttribute` to support form submission -requests from browser clients. The same annotation is recommended for use with requests -from non-browser clients as well. However there is one notable difference when it comes -to working with HTTP PUT requests. Browsers can submit form data via HTTP GET or HTTP -POST. Non-browser clients can also submit forms via HTTP PUT. This presents a challenge -because the Servlet specification requires the `ServletRequest.getParameter{asterisk}()` family -of methods to support form field access only for HTTP POST, not for HTTP PUT. - -To support HTTP PUT and PATCH requests, the `spring-web` module provides the filter -`HttpPutFormContentFilter`, which can be configured in `web.xml`: - -[source,xml,indent=0] +[literal] [subs="verbatim,quotes"] ---- - - httpPutFormFilter - org.springframework.web.filter.HttpPutFormContentFilter - +POST /someUrl +Content-Type: multipart/mixed - - httpPutFormFilter - dispatcherServlet - +--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp +Content-Disposition: form-data; name="meta-data" +Content-Type: application/json; charset=UTF-8 +Content-Transfer-Encoding: 8bit - - dispatcherServlet - org.springframework.web.servlet.DispatcherServlet - +{ + "name": "value" +} +--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp +Content-Disposition: form-data; name="file-data"; filename="file.properties" +Content-Type: text/xml +Content-Transfer-Encoding: 8bit +... File Data ... ---- -The above filter intercepts HTTP PUT and PATCH requests with content type -`application/x-www-form-urlencoded`, reads the form data from the body of the request, -and wraps the `ServletRequest` in order to make the form data available through the -`ServletRequest.getParameter{asterisk}()` family of methods. +You could access the part named "meta-data" with a `@RequestParam("meta-data") String +metadata` controller method argument. However, you would probably prefer to accept a +strongly typed object initialized from the JSON formatted data in the body of the +request part, very similar to the way `@RequestBody` converts the body of a +non-multipart request to a target object with the help of an `HttpMessageConverter`. -[NOTE] -==== -As `HttpPutFormContentFilter` consumes the body of the request, it should not be -configured for PUT or PATCH URLs that rely on other converters for -`application/x-www-form-urlencoded`. This includes `@RequestBody MultiValueMap` and `HttpEntity>`. -==== +You can use the `@RequestPart` annotation instead of the `@RequestParam` annotation for +this purpose. It allows you to have the content of a specific multipart passed through +an `HttpMessageConverter` taking into consideration the `'Content-Type'` header of the +multipart: +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @PostMapping("/someUrl") + public String onSubmit(**@RequestPart("meta-data") MetaData metadata, + @RequestPart("file-data") MultipartFile file**) { -[[mvc-ann-cookievalue]] -==== @CookieValue + // ... -The `@CookieValue` annotation allows a method parameter to be bound to the value of an -HTTP cookie. + } +---- -Let us consider that the following cookie has been received with an http request: +Notice how `MultipartFile` method arguments can be accessed with `@RequestParam` or with +`@RequestPart` interchangeably. However, the `@RequestPart("meta-data") MetaData` method +argument in this case is read as JSON content based on its `'Content-Type'` header and +converted with the help of the `MappingJackson2HttpMessageConverter`. -[literal] -[subs="verbatim,quotes"] ----- -JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84 ----- -The following code sample demonstrates how to get the value of the `JSESSIONID` cookie: +[[mvc-ann-requestbody]] +==== @RequestBody +The `@RequestBody` method parameter annotation indicates that a method parameter should +be bound to the value of the HTTP request body. For example: [source,java,indent=0] [subs="verbatim,quotes"] ---- - @RequestMapping("/displayHeaderInfo.do") - public void displayHeaderInfo(**@CookieValue("JSESSIONID")** String cookie) { - //... + @PutMapping("/something") + public void handle(@RequestBody String body, Writer writer) throws IOException { + writer.write(body); } ---- -Type conversion is applied automatically if the target method parameter type is not -`String`. See <>. +You convert the request body to the method argument by using an `HttpMessageConverter`. +`HttpMessageConverter` is responsible for converting from the HTTP request message to an +object and converting from an object to the HTTP response body. The +`RequestMappingHandlerAdapter` supports the `@RequestBody` annotation with the following +default `HttpMessageConverters`: +* `ByteArrayHttpMessageConverter` converts byte arrays. +* `StringHttpMessageConverter` converts strings. +* `FormHttpMessageConverter` converts form data to/from a MultiValueMap. +* `SourceHttpMessageConverter` converts to/from a javax.xml.transform.Source. -[[mvc-ann-requestheader]] -==== @RequestHeader -The `@RequestHeader` annotation allows a method parameter to be bound to a request header. +For more information on these converters, see <>. Also note that if using the MVC namespace or the MVC Java config, a +wider range of message converters are registered by default. See <> for +more information. -Here is a sample request header: +If you intend to read and write XML, you will need to configure the +`MarshallingHttpMessageConverter` with a specific `Marshaller` and an `Unmarshaller` +implementation from the `org.springframework.oxm` package. The example below shows how +to do that directly in your configuration but if your application is configured through +the MVC namespace or the MVC Java config see <> instead. -[literal] +[source,xml,indent=0] [subs="verbatim,quotes"] ---- -Host localhost:8080 -Accept text/html,application/xhtml+xml,application/xml;q=0.9 -Accept-Language fr,en-gb;q=0.7,en;q=0.3 -Accept-Encoding gzip,deflate -Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 -Keep-Alive 300 ----- + + + + + + + + -The following code sample demonstrates how to get the value of the `Accept-Encoding` and -`Keep-Alive` headers: + -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @RequestMapping("/displayHeaderInfo.do") - public void displayHeaderInfo(**@RequestHeader("Accept-Encoding")** String encoding, - **@RequestHeader("Keep-Alive")** long keepAlive) { - //... - } ----- + + + + -Type conversion is applied automatically if the method parameter is not `String`. See -<>. + +---- -When an `@RequestHeader` annotation is used on a `Map`, -`MultiValueMap`, or `HttpHeaders` argument, the map is populated -with all header values. +An `@RequestBody` method parameter can be annotated with `@Valid`, in which case it will +be validated using the configured `Validator` instance. When using the MVC namespace or +the MVC Java config, a JSR-303 validator is configured automatically assuming a JSR-303 +implementation is available on the classpath. +Just like with `@ModelAttribute` parameters, an `Errors` argument can be used to examine +the errors. If such an argument is not declared, a `MethodArgumentNotValidException` +will be raised. The exception is handled in the `DefaultHandlerExceptionResolver`, which +sends a `400` error back to the client. -[TIP] +[NOTE] ==== -Built-in support is available for converting a comma-separated string into an -array/collection of strings or other types known to the type conversion system. For -example a method parameter annotated with `@RequestHeader("Accept")` may be of type -`String` but also `String[]` or `List`. +Also see <> for +information on configuring message converters and a validator through the MVC namespace +or the MVC Java config. ==== -[[mvc-ann-typeconversion]] -==== Type Conversion -String-based values extracted from the request including request parameters, path -variables, request headers, and cookie values may need to be converted to the target -type of the method parameter or field (e.g., binding a request parameter to a field in -an `@ModelAttribute` parameter) they're bound to. If the target type is not `String`, -Spring automatically converts to the appropriate type. All simple types such as int, -long, Date, etc. are supported. You can further customize the conversion process through -a `WebDataBinder` (see <>) or by registering `Formatters` with -the `FormattingConversionService` (see <>). +[[mvc-ann-httpentity]] +==== HttpEntity +`HttpEntity` is similar to `@RequestBody` but also with access to request headers: -[[mvc-ann-initbinder]] -==== @InitBinder methods +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @RequestMapping("/something") + public ResponseEntity handle(HttpEntity requestEntity) throws UnsupportedEncodingException { + String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader"); + byte[] requestBody = requestEntity.getBody(); + // ... + } +---- -To customize request parameter binding with PropertyEditors through Spring's -`WebDataBinder`, you can use `@InitBinder`-annotated methods within your controller, -`@InitBinder` methods within an `@ControllerAdvice` class, or provide a custom -`WebBindingInitializer`. See the <> section for more details. +The above example gets the value of the `MyRequestHeader` request header, and reads the +body as a byte array. As with `@RequestBody`, Spring uses `HttpMessageConverter` to +convert from and to the request and response streams. For more information on these +converters, see the previous section and <>. -Annotating controller methods with `@InitBinder` allows you to configure web data -binding directly within your controller class. `@InitBinder` identifies methods that -initialize the `WebDataBinder` that will be used to populate command and form object -arguments of annotated handler methods. -Such init-binder methods support all arguments that `@RequestMapping` methods support, -except for command/form objects and corresponding validation result objects. Init-binder -methods must not have a return value. Thus, they are usually declared as `void`. -Typical arguments include `WebDataBinder` in combination with `WebRequest` or -`java.util.Locale`, allowing code to register context-specific editors. +[[mvc-ann-responsebody]] +==== @ResponseBody -The following example demonstrates the use of `@InitBinder` to configure a -`CustomDateEditor` for all `java.util.Date` form properties. +The `@ResponseBody` annotation is similar to `@RequestBody`. This annotation can be placed +on a method and indicates that the return type should be written straight to the HTTP +response body (and not placed in a Model, or interpreted as a view name). For example: [source,java,indent=0] [subs="verbatim,quotes"] ---- - @Controller - public class MyFormController { - - **@InitBinder** - protected void initBinder(WebDataBinder binder) { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - dateFormat.setLenient(false); - binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); - } - - // ... + @GetMapping("/something") + @ResponseBody + public String helloWorld() { + return "Hello World"; } ---- -Alternatively, as of Spring 4.2, consider using `addCustomFormatter` to specify -`Formatter` implementations instead of `PropertyEditor` instances. This is -particularly useful if you happen to have a `Formatter`-based setup in a shared -`FormattingConversionService` as well, with the same approach to be reused for -controller-specific tweaking of the binding rules. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - public class MyFormController { - - **@InitBinder** - protected void initBinder(WebDataBinder binder) { - binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); - } +The above example will result in the text `Hello World` being written to the HTTP +response stream. - // ... - } ----- +As with `@RequestBody`, Spring converts the returned object to a response body by using +an `HttpMessageConverter`. For more information on these converters, see the previous +section and <>. -[[mvc-ann-webbindinginitializer]] -==== WebBindingInitializer -To externalize data binding initialization, you can provide a custom implementation of -the `WebBindingInitializer` interface, which you then enable by supplying a custom bean -configuration for an `RequestMappingHandlerAdapter`, thus overriding the default -configuration. +[[mvc-ann-responseentity]] +==== ResponseEntity -The following example from the PetClinic application shows a configuration using a -custom implementation of the `WebBindingInitializer` interface, -`org.springframework.samples.petclinic.web.ClinicBindingInitializer`, which configures -PropertyEditors required by several of the PetClinic controllers. +The is similar to `@ResponseBody` but besides providing the response body, `ResponseEntity` +also allows setting response headers: -[source,xml,indent=0] +[source,java,indent=0] [subs="verbatim,quotes"] ---- - - - - - - + @PostMapping("/something") + public ResponseEntity handle() { + // ... + URI location = ... ; + return new ResponseEntity.created(location).build(); + } ---- -`@InitBinder` methods can also be defined in an ``@ControllerAdvice``-annotated class in -which case they apply to matching controllers. This provides an alternative to using a -`WebBindingInitializer`. See the <> section for more details. - - -[[mvc-ann-controller-advice]] -==== @ControllerAdvice - -The `@ControllerAdvice` annotation is a component annotation allowing implementation -classes to be auto-detected through classpath scanning. It is automatically enabled when -using the MVC namespace or the MVC Java config. - -Classes annotated with `@ControllerAdvice` can contain `@ExceptionHandler`, -`@InitBinder`, and `@ModelAttribute` annotated methods, and these methods will apply to -`@RequestMapping` methods across all controller hierarchies as opposed to the controller -hierarchy within which they are declared. - -`@RestControllerAdvice` is an alternative where `@ExceptionHandler` methods -assume `@ResponseBody` semantics by default. - -Both `@ControllerAdvice` and `@RestControllerAdvice` can target a subset of controllers: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // Target all Controllers annotated with @RestController - @ControllerAdvice(annotations = RestController.class) - public class AnnotationAdvice {} +As with `@ResponseBody`, Spring uses `HttpMessageConverter` to +convert from and to the request and response streams. For more information on these +converters, see the previous section and <>. - // Target all Controllers within specific packages - @ControllerAdvice("org.example.controllers") - public class BasePackageAdvice {} - // Target all Controllers assignable to specific classes - @ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class}) - public class AssignableTypesAdvice {} ----- -Check out the -{api-spring-framework}/web/bind/annotation/ControllerAdvice.html[`@ControllerAdvice` -documentation] for more details. +[[mvc-ann-jackson]] +==== Jackson JSON [[mvc-ann-jsonview]] -==== Jackson views +===== Jackson serialization views It can sometimes be useful to filter contextually the object that will be serialized to the HTTP response body. In order to provide such capability, Spring MVC has built-in support for @@ -1903,7 +2327,7 @@ to the model: ---- [[mvc-ann-jsonp]] -==== Jackson JSONP +===== Jackson JSONP In order to enable http://en.wikipedia.org/wiki/JSONP[JSONP] support for `@ResponseBody` and `ResponseEntity` methods, declare an `@ControllerAdvice` bean that extends @@ -1927,6 +2351,135 @@ request has a query parameter named `jsonp` or `callback`. Those names can be customized through `jsonpParameterNames` property. +[[mvc-ann-modelattrib-methods]] +=== Model methods + +The `@ModelAttribute` annotation can be used on methods or on method arguments. This +section explains its usage on methods while the next section explains its usage on +method arguments. + +An `@ModelAttribute` on a method indicates the purpose of that method is to add one or +more model attributes. Such methods support the same argument types as `@RequestMapping` +methods but cannot be mapped directly to requests. Instead `@ModelAttribute` methods in +a controller are invoked before `@RequestMapping` methods, within the same controller. A +couple of examples: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // Add one attribute + // The return value of the method is added to the model under the name "account" + // You can customize the name via @ModelAttribute("myAccount") + + @ModelAttribute + public Account addAccount(@RequestParam String number) { + return accountManager.findAccount(number); + } + + // Add multiple attributes + + @ModelAttribute + public void populateModel(@RequestParam String number, Model model) { + model.addAttribute(accountManager.findAccount(number)); + // add more ... + } +---- + +`@ModelAttribute` methods are used to populate the model with commonly needed attributes +for example to fill a drop-down with states or with pet types, or to retrieve a command +object like Account in order to use it to represent the data on an HTML form. The latter +case is further discussed in the next section. + +Note the two styles of `@ModelAttribute` methods. In the first, the method adds an +attribute implicitly by returning it. In the second, the method accepts a `Model` and +adds any number of model attributes to it. You can choose between the two styles +depending on your needs. + +A controller can have any number of `@ModelAttribute` methods. All such methods are +invoked before `@RequestMapping` methods of the same controller. + +`@ModelAttribute` methods can also be defined in an ``@ControllerAdvice``-annotated class +and such methods apply to many controllers. See the <> section +for more details. + +[TIP] +==== + +What happens when a model attribute name is not explicitly specified? In such cases a +default name is assigned to the model attribute based on its type. For example if the +method returns an object of type `Account`, the default name used is "account". You can +change that through the value of the `@ModelAttribute` annotation. If adding attributes +directly to the `Model`, use the appropriate overloaded `addAttribute(..)` method - +i.e., with or without an attribute name. +==== + +The `@ModelAttribute` annotation can be used on `@RequestMapping` methods as well. In +that case the return value of the `@RequestMapping` method is interpreted as a model +attribute rather than as a view name. The view name is then derived based on view name +conventions instead, much like for methods returning `void` -- see <>. + + +[[mvc-ann-initbinder]] +=== Binder methods + +To customize request parameter binding with PropertyEditors through Spring's +`WebDataBinder`, you can use `@InitBinder`-annotated methods within your controller, +`@InitBinder` methods within an `@ControllerAdvice` class, or provide a custom +`WebBindingInitializer`. See the <> section for more details. + +Annotating controller methods with `@InitBinder` allows you to configure web data +binding directly within your controller class. `@InitBinder` identifies methods that +initialize the `WebDataBinder` that will be used to populate command and form object +arguments of annotated handler methods. + +Such init-binder methods support all arguments that `@RequestMapping` methods support, +except for command/form objects and corresponding validation result objects. Init-binder +methods must not have a return value. Thus, they are usually declared as `void`. +Typical arguments include `WebDataBinder` in combination with `WebRequest` or +`java.util.Locale`, allowing code to register context-specific editors. + +The following example demonstrates the use of `@InitBinder` to configure a +`CustomDateEditor` for all `java.util.Date` form properties. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + public class MyFormController { + + **@InitBinder** + protected void initBinder(WebDataBinder binder) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + + // ... + } +---- + +Alternatively, as of Spring 4.2, consider using `addCustomFormatter` to specify +`Formatter` implementations instead of `PropertyEditor` instances. This is +particularly useful if you happen to have a `Formatter`-based setup in a shared +`FormattingConversionService` as well, with the same approach to be reused for +controller-specific tweaking of the binding rules. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + public class MyFormController { + + **@InitBinder** + protected void initBinder(WebDataBinder binder) { + binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); + } + + // ... + } +---- + + [[mvc-ann-async]] === Async requests @@ -2300,177 +2853,25 @@ the timeout value. The class constructor of `WebAsyncTask` also allows providing [[mvc-ann-tests]] === Testing -The `spring-test` module offers first class support for testing annotated controllers. +The `spring-test` contains a framework for testing annotated controllers with a +`DispatcherServlet` and complete Spring MVC infrastructure but without an HTTP server. + See <>. +[[mvc-viewresolver]] +== View resolution +All MVC frameworks for web applications provide a way to address views. Spring provides +view resolvers, which enable you to render models in a browser without tying you to a +specific view technology. Out of the box, Spring enables you to use JSPs, FreeMarker +templates and XSLT views, for example. See <> for a discussion of how to integrate +and use a number of disparate view technologies. -[[mvc-handlermapping]] -== Handler mappings -In previous versions of Spring, users were required to define one or more -`HandlerMapping` beans in the web application context to map incoming web requests to -appropriate handlers. With the introduction of annotated controllers, you generally -don't need to do that because the `RequestMappingHandlerMapping` automatically looks for -`@RequestMapping` annotations on all `@Controller` beans. However, do keep in mind that -all `HandlerMapping` classes extending from `AbstractHandlerMapping` have the following -properties that you can use to customize their behavior: - -* `interceptors` List of interceptors to use. ``HandlerInterceptor``s are discussed in - <>. -* `defaultHandler` Default handler to use, when this handler mapping does not result in - a matching handler. -* `order` Based on the value of the order property (see the - `org.springframework.core.Ordered` interface), Spring sorts all handler mappings - available in the context and applies the first matching handler. -* `alwaysUseFullPath` If `true` , Spring uses the full path within the current Servlet - context to find an appropriate handler. If `false` (the default), the path within the - current Servlet mapping is used. For example, if a Servlet is mapped using - `/testing/{asterisk}` and the `alwaysUseFullPath` property is set to true, - `/testing/viewPage.html` is used, whereas if the property is set to false, - `/viewPage.html` is used. -* `urlDecode` Defaults to `true`, as of Spring 2.5. If you prefer to compare encoded - paths, set this flag to `false`. However, the `HttpServletRequest` always exposes the - Servlet path in decoded form. Be aware that the Servlet path will not match when - compared with encoded paths so you cannot use `urlDecode=false` with prefix-based Servlet - mappings and likewise must also set `alwaysUseFullPath=true`. - -The following example shows how to configure an interceptor: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - ----- - - - -[[mvc-handlermapping-interceptor]] -=== HandlerInterceptor - -Spring's handler mapping mechanism includes handler interceptors, which are useful when -you want to apply specific functionality to certain requests, for example, checking for -a principal. - -Interceptors located in the handler mapping must implement `HandlerInterceptor` from the -`org.springframework.web.servlet` package. This interface defines three methods: -`preHandle(..)` is called __before__ the actual handler is executed; `postHandle(..)` is -called __after__ the handler is executed; and `afterCompletion(..)` is called __after -the complete request has finished__. These three methods should provide enough -flexibility to do all kinds of preprocessing and postprocessing. - -The `preHandle(..)` method returns a boolean value. You can use this method to break or -continue the processing of the execution chain. When this method returns `true`, the -handler execution chain will continue; when it returns false, the `DispatcherServlet` -assumes the interceptor itself has taken care of requests (and, for example, rendered an -appropriate view) and does not continue executing the other interceptors and the actual -handler in the execution chain. - -Interceptors can be configured using the `interceptors` property, which is present on -all `HandlerMapping` classes extending from `AbstractHandlerMapping`. This is shown in -the example below: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - ----- - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package samples; - - public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { - - private int openingTime; - private int closingTime; - - public void setOpeningTime(int openingTime) { - this.openingTime = openingTime; - } - - public void setClosingTime(int closingTime) { - this.closingTime = closingTime; - } - - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, - Object handler) throws Exception { - Calendar cal = Calendar.getInstance(); - int hour = cal.get(HOUR_OF_DAY); - if (openingTime <= hour && hour < closingTime) { - return true; - } - response.sendRedirect("http://host.com/outsideOfficeHours.html"); - return false; - } - } ----- - -Any request handled by this mapping is intercepted by the `TimeBasedAccessInterceptor`. -If the current time is outside office hours, the user is redirected to a static HTML -file that says, for example, you can only access the website during office hours. - -[NOTE] -==== -When using the `RequestMappingHandlerMapping` the actual handler is an instance of -`HandlerMethod` which identifies the specific controller method that will be invoked. -==== - -As you can see, the Spring adapter class `HandlerInterceptorAdapter` makes it easier to -extend the `HandlerInterceptor` interface. - -[TIP] -==== - -In the example above, the configured interceptor will apply to all requests handled with -annotated controller methods. If you want to narrow down the URL paths to which an -interceptor applies, you can use the MVC namespace or the MVC Java config, or declare -bean instances of type `MappedInterceptor` to do that. See <>. -==== - -Note that the `postHandle` method of `HandlerInterceptor` is not always ideally suited for -use with `@ResponseBody` and `ResponseEntity` methods. In such cases an `HttpMessageConverter` -writes to and commits the response before `postHandle` is called which makes it impossible -to change the response, for example to add a header. Instead an application can implement -`ResponseBodyAdvice` and either declare it as an `@ControllerAdvice` bean or configure it -directly on `RequestMappingHandlerAdapter`. - - - -[[mvc-viewresolver]] -== View resolution -All MVC frameworks for web applications provide a way to address views. Spring provides -view resolvers, which enable you to render models in a browser without tying you to a -specific view technology. Out of the box, Spring enables you to use JSPs, FreeMarker -templates and XSLT views, for example. See <> for a discussion of how to integrate -and use a number of disparate view technologies. - -The two interfaces that are important to the way Spring handles views are `ViewResolver` -and `View`. The `ViewResolver` provides a mapping between view names and actual views. -The `View` interface addresses the preparation of the request and hands the request over -to one of the view technologies. +The two interfaces that are important to the way Spring handles views are `ViewResolver` +and `View`. The `ViewResolver` provides a mapping between view names and actual views. +The `View` interface addresses the preparation of the request and hands the request over +to one of the view technologies. @@ -2892,721 +3293,255 @@ __Post/Redirect/Get__ pattern. Flash attributes are saved temporarily before the redirect (typically in the session) to be made available to the request after the redirect and removed immediately. -Spring MVC has two main abstractions in support of flash attributes. `FlashMap` is used -to hold flash attributes while `FlashMapManager` is used to store, retrieve, and manage -`FlashMap` instances. - -Flash attribute support is always "on" and does not need to enabled explicitly although -if not used, it never causes HTTP session creation. On each request there is an "input" -`FlashMap` with attributes passed from a previous request (if any) and an "output" -`FlashMap` with attributes to save for a subsequent request. Both `FlashMap` instances -are accessible from anywhere in Spring MVC through static methods in -`RequestContextUtils`. - -Annotated controllers typically do not need to work with `FlashMap` directly. Instead an -`@RequestMapping` method can accept an argument of type `RedirectAttributes` and use it -to add flash attributes for a redirect scenario. Flash attributes added via -`RedirectAttributes` are automatically propagated to the "output" FlashMap. Similarly, -after the redirect, attributes from the "input" `FlashMap` are automatically added to the -`Model` of the controller serving the target URL. - -.Matching requests to flash attributes -**** -The concept of flash attributes exists in many other Web frameworks and has proven to be -exposed sometimes to concurrency issues. This is because by definition flash attributes -are to be stored until the next request. However the very "next" request may not be the -intended recipient but another asynchronous request (e.g. polling or resource requests) -in which case the flash attributes are removed too early. - -To reduce the possibility of such issues, `RedirectView` automatically "stamps" -`FlashMap` instances with the path and query parameters of the target redirect URL. In -turn the default `FlashMapManager` matches that information to incoming requests when -looking up the "input" `FlashMap`. - -This does not eliminate the possibility of a concurrency issue entirely but nevertheless -reduces it greatly with information that is already available in the redirect URL. -Therefore the use of flash attributes is recommended mainly for redirect scenarios . -**** - - - - -[[mvc-uri-building]] -== URI links - -Spring MVC provides a mechanism for building and encoding a URI using -`UriComponentsBuilder` and `UriComponents`. - -For example you can expand and encode a URI template string: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - UriComponents uriComponents = UriComponentsBuilder.fromUriString( - "http://example.com/hotels/{hotel}/bookings/{booking}").build(); - - URI uri = uriComponents.expand("42", "21").encode().toUri(); ----- - -Note that `UriComponents` is immutable and the `expand()` and `encode()` operations -return new instances if necessary. - -You can also expand and encode using individual URI components: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - UriComponents uriComponents = UriComponentsBuilder.newInstance() - .scheme("http").host("example.com").path("/hotels/{hotel}/bookings/{booking}").build() - .expand("42", "21") - .encode(); ----- - -In a Servlet environment the `ServletUriComponentsBuilder` sub-class provides static -factory methods to copy available URL information from a Servlet requests: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - HttpServletRequest request = ... - - // Re-use host, scheme, port, path and query string - // Replace the "accountId" query param - - ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromRequest(request) - .replaceQueryParam("accountId", "{id}").build() - .expand("123") - .encode(); ----- - -Alternatively, you may choose to copy a subset of the available information up to and -including the context path: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // Re-use host, port and context path - // Append "/accounts" to the path - - ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromContextPath(request) - .path("/accounts").build() ----- - -Or in cases where the `DispatcherServlet` is mapped by name (e.g. `/main/{asterisk}`), you can -also have the literal part of the servlet mapping included: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // Re-use host, port, context path - // Append the literal part of the servlet mapping to the path - // Append "/accounts" to the path - - ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromServletMapping(request) - .path("/accounts").build() ----- - -[[mvc-links-to-controllers]] -=== Links to controllers - -Spring MVC also provides a mechanism for building links to controller methods. For example, given: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - @RequestMapping("/hotels/{hotel}") - public class BookingController { - - @GetMapping("/bookings/{booking}") - public String getBooking(@PathVariable Long booking) { - - // ... - } - } ----- - -You can prepare a link by referring to the method by name: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - UriComponents uriComponents = MvcUriComponentsBuilder - .fromMethodName(BookingController.class, "getBooking", 21).buildAndExpand(42); - - URI uri = uriComponents.encode().toUri(); ----- - -In the above example we provided actual method argument values, in this case the long value 21, -to be used as a path variable and inserted into the URL. Furthermore, we provided the -value 42 in order to fill in any remaining URI variables such as the "hotel" variable inherited -from the type-level request mapping. If the method had more arguments you can supply null for -arguments not needed for the URL. In general only `@PathVariable` and `@RequestParam` arguments -are relevant for constructing the URL. - -There are additional ways to use `MvcUriComponentsBuilder`. For example you can use a technique -akin to mock testing through proxies to avoid referring to the controller method by name -(the example assumes static import of `MvcUriComponentsBuilder.on`): - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - UriComponents uriComponents = MvcUriComponentsBuilder - .fromMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42); - - URI uri = uriComponents.encode().toUri(); ----- - -The above examples use static methods in `MvcUriComponentsBuilder`. Internally they rely -on `ServletUriComponentsBuilder` to prepare a base URL from the scheme, host, port, -context path and servlet path of the current request. This works well in most cases, -however sometimes it may be insufficient. For example you may be outside the context of -a request (e.g. a batch process that prepares links) or perhaps you need to insert a path -prefix (e.g. a locale prefix that was removed from the request path and needs to be -re-inserted into links). - -For such cases you can use the static "fromXxx" overloaded methods that accept a -`UriComponentsBuilder` to use base URL. Or you can create an instance of `MvcUriComponentsBuilder` -with a base URL and then use the instance-based "withXxx" methods. For example: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - UriComponentsBuilder base = ServletUriComponentsBuilder.fromCurrentContextPath().path("/en"); - MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base); - builder.withMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42); - - URI uri = uriComponents.encode().toUri(); ----- - - -[[mvc-links-to-controllers-forwarded-headers]] -=== "Forwarded" Headers - -As a request goes through proxies such as load balancers the host, port, and -scheme may change presenting a challenge for applications that need to create links -to resources since the links should reflect the host, port, and scheme of the -original request as seen from a client perspective. - -https://tools.ietf.org/html/rfc7239[RFC 7239] defines the "Forwarded" HTTP header -for proxies to use to provide information about the original request. There are also -other non-standard headers in use such as "X-Forwarded-Host", "X-Forwarded-Port", -and "X-Forwarded-Proto". - -Both `ServletUriComponentsBuilder` and `MvcUriComponentsBuilder` detect, extract, and use -information from the "Forwarded" header, or from "X-Forwarded-Host", "X-Forwarded-Port", -and "X-Forwarded-Proto" if "Forwarded" is not present, so that the resulting links reflect -the original request. - -The `ForwardedHeaderFilter` provides an alternative to do the same once and globally for -the entire application. The filter wraps the request in order to overlay host, port, and -scheme information and also "hides" any forwarded headers for subsequent processing. - -Note that there are security considerations when using forwarded headers as explained -in Section 8 of RFC 7239. At the application level it is difficult to determine whether -forwarded headers can be trusted or not. This is why the network upstream should be -configured correctly to filter out untrusted forwarded headers from the outside. - -Applications that don't have a proxy and don't need to use forwarded headers can -configure the `ForwardedHeaderFilter` to remove and ignore such headers. - - - -[[mvc-links-to-controllers-from-views]] -=== Links in views - -You can also build links to annotated controllers from views such as JSP, Thymeleaf, -FreeMarker. This can be done using the `fromMappingName` method in `MvcUriComponentsBuilder` -which refers to mappings by name. - -Every `@RequestMapping` is assigned a default name based on the capital letters of the -class and the full method name. For example, the method `getFoo` in class `FooController` -is assigned the name "FC#getFoo". This strategy can be replaced or customized by creating -an instance of `HandlerMethodMappingNamingStrategy` and plugging it into your -`RequestMappingHandlerMapping`. The default strategy implementation also looks at the -name attribute on `@RequestMapping` and uses that if present. That means if the default -mapping name assigned conflicts with another (e.g. overloaded methods) you can assign -a name explicitly on the `@RequestMapping`. - -[NOTE] -==== -The assigned request mapping names are logged at TRACE level on startup. -==== - -The Spring JSP tag library provides a function called `mvcUrl` that can be used to -prepare links to controller methods based on this mechanism. - -For example given: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @RequestMapping("/people/{id}/addresses") - public class PersonAddressController { - - @RequestMapping("/{country}") - public HttpEntity getAddress(@PathVariable String country) { ... } - } ----- - -You can prepare a link from a JSP as follows: - -[source,jsp,indent=0] -[subs="verbatim,quotes"] ----- -<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %> -... -Get Address ----- - -The above example relies on the `mvcUrl` JSP function declared in the Spring tag library -(i.e. META-INF/spring.tld). For more advanced cases (e.g. a custom base URL as explained -in the previous section), it is easy to define your own function, or use a custom tag file, -in order to use a specific instance of `MvcUriComponentsBuilder` with a custom base URL. - - -[[mvc-localeresolver]] -== Locales -Most parts of Spring's architecture support internationalization, just as the Spring web -MVC framework does. `DispatcherServlet` enables you to automatically resolve messages -using the client's locale. This is done with `LocaleResolver` objects. - -When a request comes in, the `DispatcherServlet` looks for a locale resolver, and if it -finds one it tries to use it to set the locale. Using the `RequestContext.getLocale()` -method, you can always retrieve the locale that was resolved by the locale resolver. - -In addition to automatic locale resolution, you can also attach an interceptor to the -handler mapping (see <> for more information on handler -mapping interceptors) to change the locale under specific circumstances, for example, -based on a parameter in the request. - -Locale resolvers and interceptors are defined in the -`org.springframework.web.servlet.i18n` package and are configured in your application -context in the normal way. Here is a selection of the locale resolvers included in -Spring. - - - -[[mvc-timezone]] -=== TimeZone -In addition to obtaining the client's locale, it is often useful to know their time zone. -The `LocaleContextResolver` interface offers an extension to `LocaleResolver` that allows -resolvers to provide a richer `LocaleContext`, which may include time zone information. - -When available, the user's `TimeZone` can be obtained using the -`RequestContext.getTimeZone()` method. Time zone information will automatically be used -by Date/Time `Converter` and `Formatter` objects registered with Spring's -`ConversionService`. - - - -[[mvc-localeresolver-acceptheader]] -=== Header resolver -This locale resolver inspects the `accept-language` header in the request that was sent -by the client (e.g., a web browser). Usually this header field contains the locale of -the client's operating system. __Note that this resolver does not support time zone -information.__ - - - -[[mvc-localeresolver-cookie]] -=== Cookie resolver - -This locale resolver inspects a `Cookie` that might exist on the client to see if a -`Locale` or `TimeZone` is specified. If so, it uses the specified details. Using the -properties of this locale resolver, you can specify the name of the cookie as well as the -maximum age. Find below an example of defining a `CookieLocaleResolver`. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - ----- - -[[mvc-cookie-locale-resolver-props-tbl]] -.CookieLocaleResolver properties -[cols="1,1,4"] -|=== -| Property| Default| Description - -| cookieName -| classname + LOCALE -| The name of the cookie - -| cookieMaxAge -| Servlet container default -| The maximum time a cookie will stay persistent on the client. If -1 is specified, the - cookie will not be persisted; it will only be available until the client shuts down - their browser. - -| cookiePath -| / -| Limits the visibility of the cookie to a certain part of your site. When cookiePath is - specified, the cookie will only be visible to that path and the paths below it. -|=== - - - -[[mvc-localeresolver-session]] -=== Session resolver - -The `SessionLocaleResolver` allows you to retrieve `Locale` and `TimeZone` from the -session that might be associated with the user's request. In contrast to -`CookieLocaleResolver`, this strategy stores locally chosen locale settings in the -Servlet container's `HttpSession`. As a consequence, those settings are just temporary -for each session and therefore lost when each session terminates. - -Note that there is no direct relationship with external session management mechanisms -such as the Spring Session project. This `SessionLocaleResolver` will simply evaluate and -modify corresponding `HttpSession` attributes against the current `HttpServletRequest`. - - - -[[mvc-localeresolver-interceptor]] -=== Locale interceptor - -You can enable changing of locales by adding the `LocaleChangeInterceptor` to one of the -handler mappings (see <>). It will detect a parameter in the request -and change the locale. It calls `setLocale()` on the `LocaleResolver` that also exists -in the context. The following example shows that calls to all `{asterisk}.view` resources -containing a parameter named `siteLanguage` will now change the locale. So, for example, -a request for the following URL, `http://www.sf.net/home.view?siteLanguage=nl` will -change the site language to Dutch. - -[source,xml,indent=0] -[subs="verbatim"] ----- - - - - - - - - - - - - - - /**/*.view=someController - - ----- - - - - -[[mvc-themeresolver]] -== Themes - -You can apply Spring Web MVC framework themes to set the overall look-and-feel of your -application, thereby enhancing user experience. A theme is a collection of static -resources, typically style sheets and images, that affect the visual style of the -application. - - -[[mvc-themeresolver-defining]] -=== Define a theme -To use themes in your web application, you must set up an implementation of the -`org.springframework.ui.context.ThemeSource` interface. The `WebApplicationContext` -interface extends `ThemeSource` but delegates its responsibilities to a dedicated -implementation. By default the delegate will be an -`org.springframework.ui.context.support.ResourceBundleThemeSource` implementation that -loads properties files from the root of the classpath. To use a custom `ThemeSource` -implementation or to configure the base name prefix of the `ResourceBundleThemeSource`, -you can register a bean in the application context with the reserved name `themeSource`. -The web application context automatically detects a bean with that name and uses it. - -When using the `ResourceBundleThemeSource`, a theme is defined in a simple properties -file. The properties file lists the resources that make up the theme. Here is an example: - -[literal] -[subs="verbatim,quotes"] ----- -styleSheet=/themes/cool/style.css -background=/themes/cool/img/coolBg.jpg ----- - -The keys of the properties are the names that refer to the themed elements from view -code. For a JSP, you typically do this using the `spring:theme` custom tag, which is -very similar to the `spring:message` tag. The following JSP fragment uses the theme -defined in the previous example to customize the look and feel: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> - - - - - - ... - - ----- - -By default, the `ResourceBundleThemeSource` uses an empty base name prefix. As a result, -the properties files are loaded from the root of the classpath. Thus you would put the -`cool.properties` theme definition in a directory at the root of the classpath, for -example, in `/WEB-INF/classes`. The `ResourceBundleThemeSource` uses the standard Java -resource bundle loading mechanism, allowing for full internationalization of themes. For -example, we could have a `/WEB-INF/classes/cool_nl.properties` that references a special -background image with Dutch text on it. - - - -[[mvc-themeresolver-resolving]] -=== Resolve themes -After you define themes, as in the preceding section, you decide which theme to use. The -`DispatcherServlet` will look for a bean named `themeResolver` to find out which -`ThemeResolver` implementation to use. A theme resolver works in much the same way as a -`LocaleResolver`. It detects the theme to use for a particular request and can also -alter the request's theme. The following theme resolvers are provided by Spring: +Spring MVC has two main abstractions in support of flash attributes. `FlashMap` is used +to hold flash attributes while `FlashMapManager` is used to store, retrieve, and manage +`FlashMap` instances. -[[mvc-theme-resolver-impls-tbl]] -.ThemeResolver implementations -[cols="1,4"] -|=== -| Class| Description +Flash attribute support is always "on" and does not need to enabled explicitly although +if not used, it never causes HTTP session creation. On each request there is an "input" +`FlashMap` with attributes passed from a previous request (if any) and an "output" +`FlashMap` with attributes to save for a subsequent request. Both `FlashMap` instances +are accessible from anywhere in Spring MVC through static methods in +`RequestContextUtils`. -| `FixedThemeResolver` -| Selects a fixed theme, set using the `defaultThemeName` property. +Annotated controllers typically do not need to work with `FlashMap` directly. Instead an +`@RequestMapping` method can accept an argument of type `RedirectAttributes` and use it +to add flash attributes for a redirect scenario. Flash attributes added via +`RedirectAttributes` are automatically propagated to the "output" FlashMap. Similarly, +after the redirect, attributes from the "input" `FlashMap` are automatically added to the +`Model` of the controller serving the target URL. -| `SessionThemeResolver` -| The theme is maintained in the user's HTTP session. It only needs to be set once for - each session, but is not persisted between sessions. +.Matching requests to flash attributes +**** +The concept of flash attributes exists in many other Web frameworks and has proven to be +exposed sometimes to concurrency issues. This is because by definition flash attributes +are to be stored until the next request. However the very "next" request may not be the +intended recipient but another asynchronous request (e.g. polling or resource requests) +in which case the flash attributes are removed too early. -| `CookieThemeResolver` -| The selected theme is stored in a cookie on the client. -|=== +To reduce the possibility of such issues, `RedirectView` automatically "stamps" +`FlashMap` instances with the path and query parameters of the target redirect URL. In +turn the default `FlashMapManager` matches that information to incoming requests when +looking up the "input" `FlashMap`. -Spring also provides a `ThemeChangeInterceptor` that allows theme changes on every -request with a simple request parameter. +This does not eliminate the possibility of a concurrency issue entirely but nevertheless +reduces it greatly with information that is already available in the redirect URL. +Therefore the use of flash attributes is recommended mainly for redirect scenarios . +**** -[[mvc-multipart]] -== Multipart, File Upload +[[mvc-uri-building]] +== URI links -Spring's built-in multipart support handles file uploads in web applications. You enable -this multipart support with pluggable `MultipartResolver` objects, defined in the -`org.springframework.web.multipart` package. Spring provides one `MultipartResolver` -implementation for use with http://jakarta.apache.org/commons/fileupload[__Commons -FileUpload__] and another for use with Servlet 3.0 multipart request parsing. +Spring MVC provides a mechanism for building and encoding a URI using +`UriComponentsBuilder` and `UriComponents`. -By default, Spring does no multipart handling, because some developers want to handle -multiparts themselves. You enable Spring multipart handling by adding a multipart -resolver to the web application's context. Each request is inspected to see if it -contains a multipart. If no multipart is found, the request continues as expected. If a -multipart is found in the request, the `MultipartResolver` that has been declared in -your context is used. After that, the multipart attribute in your request is treated -like any other attribute. +For example you can expand and encode a URI template string: +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + UriComponents uriComponents = UriComponentsBuilder.fromUriString( + "http://example.com/hotels/{hotel}/bookings/{booking}").build(); + URI uri = uriComponents.expand("42", "21").encode().toUri(); +---- -[[mvc-multipart-resolver-commons]] -=== __Commons FileUpload__ +Note that `UriComponents` is immutable and the `expand()` and `encode()` operations +return new instances if necessary. -The following example shows how to use the `CommonsMultipartResolver`: +You can also expand and encode using individual URI components: -[source,xml,indent=0] +[source,java,indent=0] [subs="verbatim,quotes"] ---- - + UriComponents uriComponents = UriComponentsBuilder.newInstance() + .scheme("http").host("example.com").path("/hotels/{hotel}/bookings/{booking}").build() + .expand("42", "21") + .encode(); +---- - - +In a Servlet environment the `ServletUriComponentsBuilder` sub-class provides static +factory methods to copy available URL information from a Servlet requests: - +[source,java,indent=0] +[subs="verbatim,quotes"] ---- + HttpServletRequest request = ... -Of course you also need to put the appropriate jars in your classpath for the multipart -resolver to work. In the case of the `CommonsMultipartResolver`, you need to use -`commons-fileupload.jar`. - -When the Spring `DispatcherServlet` detects a multi-part request, it activates the -resolver that has been declared in your context and hands over the request. The resolver -then wraps the current `HttpServletRequest` into a `MultipartHttpServletRequest` that -supports multipart file uploads. Using the `MultipartHttpServletRequest`, you can get -information about the multiparts contained by this request and actually get access to -the multipart files themselves in your controllers. + // Re-use host, scheme, port, path and query string + // Replace the "accountId" query param + ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromRequest(request) + .replaceQueryParam("accountId", "{id}").build() + .expand("123") + .encode(); +---- +Alternatively, you may choose to copy a subset of the available information up to and +including the context path: -[[mvc-multipart-resolver-standard]] -=== __Servlet 3.0__ +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // Re-use host, port and context path + // Append "/accounts" to the path -In order to use Servlet 3.0 based multipart parsing, you need to mark the -`DispatcherServlet` with a `"multipart-config"` section in `web.xml`, or with a -`javax.servlet.MultipartConfigElement` in programmatic Servlet registration, or in case -of a custom Servlet class possibly with a `javax.servlet.annotation.MultipartConfig` -annotation on your Servlet class. Configuration settings such as maximum sizes or -storage locations need to be applied at that Servlet registration level as Servlet 3.0 -does not allow for those settings to be done from the MultipartResolver. + ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromContextPath(request) + .path("/accounts").build() +---- -Once Servlet 3.0 multipart parsing has been enabled in one of the above mentioned ways -you can add the `StandardServletMultipartResolver` to your Spring configuration: +Or in cases where the `DispatcherServlet` is mapped by name (e.g. `/main/{asterisk}`), you can +also have the literal part of the servlet mapping included: -[source,xml,indent=0] +[source,java,indent=0] [subs="verbatim,quotes"] ---- - - + // Re-use host, port, context path + // Append the literal part of the servlet mapping to the path + // Append "/accounts" to the path + + ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromServletMapping(request) + .path("/accounts").build() ---- +[TIP] +==== +Both `ServletUriComponentsBuilder` and `MvcUriComponentsBuilder` detect, extract, and use +information from the "Forwarded" header, or from "X-Forwarded-Host", "X-Forwarded-Port", +and "X-Forwarded-Proto" if "Forwarded" is not present, so that the resulting links reflect +the original request. Note that you can also use the +<> to the same once, globally. +==== -[[mvc-multipart-forms]] -=== Browser upload -After the `MultipartResolver` completes its job, the request is processed like any -other. First, create a form with a file input that will allow the user to upload a form. -The encoding attribute ( `enctype="multipart/form-data"`) lets the browser know how to -encode the form as multipart request: +[[mvc-links-to-controllers]] +=== Links to Controllers -[source,xml,indent=0] +Spring MVC also provides a mechanism for building links to controller methods. For example, given: + +[source,java,indent=0] [subs="verbatim,quotes"] ---- - - - Upload a file please - - -

Please upload a file

-
- - - -
- - + @Controller + @RequestMapping("/hotels/{hotel}") + public class BookingController { + + @GetMapping("/bookings/{booking}") + public String getBooking(@PathVariable Long booking) { + + // ... + } + } ---- -The next step is to create a controller that handles the file upload. This controller is -very similar to a <>, except that we -use `MultipartHttpServletRequest` or `MultipartFile` in the method parameters: +You can prepare a link by referring to the method by name: [source,java,indent=0] [subs="verbatim,quotes"] ---- - @Controller - public class FileUploadController { + UriComponents uriComponents = MvcUriComponentsBuilder + .fromMethodName(BookingController.class, "getBooking", 21).buildAndExpand(42); - @PostMapping("/form") - public String handleFormUpload(@RequestParam("name") String name, - @RequestParam("file") MultipartFile file) { + URI uri = uriComponents.encode().toUri(); +---- - if (!file.isEmpty()) { - byte[] bytes = file.getBytes(); - // store the bytes somewhere - return "redirect:uploadSuccess"; - } +In the above example we provided actual method argument values, in this case the long value 21, +to be used as a path variable and inserted into the URL. Furthermore, we provided the +value 42 in order to fill in any remaining URI variables such as the "hotel" variable inherited +from the type-level request mapping. If the method had more arguments you can supply null for +arguments not needed for the URL. In general only `@PathVariable` and `@RequestParam` arguments +are relevant for constructing the URL. - return "redirect:uploadFailure"; - } +There are additional ways to use `MvcUriComponentsBuilder`. For example you can use a technique +akin to mock testing through proxies to avoid referring to the controller method by name +(the example assumes static import of `MvcUriComponentsBuilder.on`): - } +[source,java,indent=0] +[subs="verbatim,quotes"] ---- + UriComponents uriComponents = MvcUriComponentsBuilder + .fromMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42); -Note how the `@RequestParam` method parameters map to the input elements declared in the -form. In this example, nothing is done with the `byte[]`, but in practice you can save -it in a database, store it on the file system, and so on. + URI uri = uriComponents.encode().toUri(); +---- -When using Servlet 3.0 multipart parsing you can also use `javax.servlet.http.Part` for -the method parameter: +The above examples use static methods in `MvcUriComponentsBuilder`. Internally they rely +on `ServletUriComponentsBuilder` to prepare a base URL from the scheme, host, port, +context path and servlet path of the current request. This works well in most cases, +however sometimes it may be insufficient. For example you may be outside the context of +a request (e.g. a batch process that prepares links) or perhaps you need to insert a path +prefix (e.g. a locale prefix that was removed from the request path and needs to be +re-inserted into links). + +For such cases you can use the static "fromXxx" overloaded methods that accept a +`UriComponentsBuilder` to use base URL. Or you can create an instance of `MvcUriComponentsBuilder` +with a base URL and then use the instance-based "withXxx" methods. For example: [source,java,indent=0] [subs="verbatim,quotes"] ---- - @Controller - public class FileUploadController { + UriComponentsBuilder base = ServletUriComponentsBuilder.fromCurrentContextPath().path("/en"); + MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base); + builder.withMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42); - @PostMapping("/form") - public String handleFormUpload(@RequestParam("name") String name, - @RequestParam("file") Part file) { + URI uri = uriComponents.encode().toUri(); +---- - InputStream inputStream = file.getInputStream(); - // store bytes from uploaded file somewhere - return "redirect:uploadSuccess"; - } +[[mvc-links-to-controllers-from-views]] +=== Links in views - } ----- +You can also build links to annotated controllers from views such as JSP, Thymeleaf, +FreeMarker. This can be done using the `fromMappingName` method in `MvcUriComponentsBuilder` +which refers to mappings by name. + +Every `@RequestMapping` is assigned a default name based on the capital letters of the +class and the full method name. For example, the method `getFoo` in class `FooController` +is assigned the name "FC#getFoo". This strategy can be replaced or customized by creating +an instance of `HandlerMethodMappingNamingStrategy` and plugging it into your +`RequestMappingHandlerMapping`. The default strategy implementation also looks at the +name attribute on `@RequestMapping` and uses that if present. That means if the default +mapping name assigned conflicts with another (e.g. overloaded methods) you can assign +a name explicitly on the `@RequestMapping`. +[NOTE] +==== +The assigned request mapping names are logged at TRACE level on startup. +==== +The Spring JSP tag library provides a function called `mvcUrl` that can be used to +prepare links to controller methods based on this mechanism. -[[mvc-multipart-forms-non-browsers]] -=== REST multipart -Multipart requests can also be submitted from non-browser clients in a RESTful service -scenario. All of the above examples and configuration apply here as well. However, -unlike browsers that typically submit files and simple form fields, a programmatic -client can also send more complex data of a specific content type -- for example a -multipart request with a file and second part with JSON formatted data: +For example given: -[literal] +[source,java,indent=0] [subs="verbatim,quotes"] ---- -POST /someUrl -Content-Type: multipart/mixed - ---edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp -Content-Disposition: form-data; name="meta-data" -Content-Type: application/json; charset=UTF-8 -Content-Transfer-Encoding: 8bit + @RequestMapping("/people/{id}/addresses") + public class PersonAddressController { -{ - "name": "value" -} ---edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp -Content-Disposition: form-data; name="file-data"; filename="file.properties" -Content-Type: text/xml -Content-Transfer-Encoding: 8bit -... File Data ... + @RequestMapping("/{country}") + public HttpEntity getAddress(@PathVariable String country) { ... } + } ---- -You could access the part named "meta-data" with a `@RequestParam("meta-data") String -metadata` controller method argument. However, you would probably prefer to accept a -strongly typed object initialized from the JSON formatted data in the body of the -request part, very similar to the way `@RequestBody` converts the body of a -non-multipart request to a target object with the help of an `HttpMessageConverter`. - -You can use the `@RequestPart` annotation instead of the `@RequestParam` annotation for -this purpose. It allows you to have the content of a specific multipart passed through -an `HttpMessageConverter` taking into consideration the `'Content-Type'` header of the -multipart: +You can prepare a link from a JSP as follows: -[source,java,indent=0] +[source,jsp,indent=0] [subs="verbatim,quotes"] ---- - @PostMapping("/someUrl") - public String onSubmit(**@RequestPart("meta-data") MetaData metadata, - @RequestPart("file-data") MultipartFile file**) { - - // ... - - } +<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %> +... +Get Address ---- -Notice how `MultipartFile` method arguments can be accessed with `@RequestParam` or with -`@RequestPart` interchangeably. However, the `@RequestPart("meta-data") MetaData` method -argument in this case is read as JSON content based on its `'Content-Type'` header and -converted with the help of the `MappingJackson2HttpMessageConverter`. - +The above example relies on the `mvcUrl` JSP function declared in the Spring tag library +(i.e. META-INF/spring.tld). For more advanced cases (e.g. a custom base URL as explained +in the previous section), it is easy to define your own function, or use a custom tag file, +in order to use a specific instance of `MvcUriComponentsBuilder` with a custom base URL. @@ -3872,89 +3807,6 @@ Another option is to use a framework dedicated to Web Security. http://hdiv.org/[HDIV] is one such framework and integrates with Spring MVC. - - -[[mvc-coc]] -== Convention over configuration support -For a lot of projects, sticking to established conventions and having reasonable -defaults is just what they (the projects) need, and Spring Web MVC now has explicit -support for __convention over configuration__. What this means is that if you establish -a set of naming conventions and suchlike, you can __substantially__ cut down on the -amount of configuration that is required to set up handler mappings, view resolvers, -`ModelAndView` instances, etc. This is a great boon with regards to rapid prototyping, -and can also lend a degree of (always good-to-have) consistency across a codebase should -you choose to move forward with it into production. - -Convention-over-configuration support addresses the three core areas of MVC: models, -views, and controllers. - - - -[[mvc-coc-ccnhm]] -=== The Controller ControllerClassNameHandlerMapping - -The `ControllerClassNameHandlerMapping` class is a `HandlerMapping` implementation that -uses a convention to determine the mapping between request URLs and the `Controller` -instances that are to handle those requests. - -Consider the following simple `Controller` implementation. Take special notice of the -__name__ of the class. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class **ViewShoppingCartController** implements Controller { - - public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { - // the implementation is not hugely important for this example... - } - - } ----- - -Here is a snippet from the corresponding Spring Web MVC configuration file: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - ----- - -The `ControllerClassNameHandlerMapping` finds all of the various handler (or -`Controller`) beans defined in its application context and strips `Controller` off the -name to define its handler mappings. Thus, `ViewShoppingCartController` maps to the -`/viewshoppingcart{asterisk}` request URL. - -Let's look at some more examples so that the central idea becomes immediately familiar. -(Notice all lowercase in the URLs, in contrast to camel-cased `Controller` class names.) - -* `WelcomeController` maps to the `/welcome{asterisk}` request URL -* `HomeController` maps to the `/home{asterisk}` request URL -* `IndexController` maps to the `/index{asterisk}` request URL -* `RegisterController` maps to the `/register{asterisk}` request URL - -In the case of `MultiActionController` handler classes, the mappings generated are -slightly more complex. The `Controller` names in the following examples are assumed to -be `MultiActionController` implementations: - -* `AdminController` maps to the `/admin/{asterisk}` request URL -* `CatalogController` maps to the `/catalog/{asterisk}` request URL - -If you follow the convention of naming your `Controller` implementations as -`xxxController`, the `ControllerClassNameHandlerMapping` saves you the tedium of -defining and maintaining a potentially __looooong__ `SimpleUrlHandlerMapping` (or -suchlike). - -The `ControllerClassNameHandlerMapping` class extends the `AbstractHandlerMapping` base -class so you can define `HandlerInterceptor` instances and everything else just as you -would with many other `HandlerMapping` implementations. - - - [[mvc-coc-modelmap]] === The Model ModelMap (ModelAndView) @@ -4288,182 +4140,12 @@ will check that the resource has not been modified and if it has been, it will r [[mvc-httpcaching-shallowetag]] -=== Shallow ETag - -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 -ETags, more about that later).The filter caches the content of the rendered JSP (or -other content), generates an MD5 hash over that, and returns that as an ETag header in -the response. The next time a client sends a request for the same resource, it uses that -hash as the `If-None-Match` value. The filter detects this, renders the view again, and -compares the two hashes. If they are equal, a `304` is returned. - -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. - -This filter has a `writeWeakETag` parameter that configures the filter to write Weak ETags, -like this: `W/"02a2d595e6ed9a0b24f027f2b63b134d6"`, as defined in -https://tools.ietf.org/html/rfc7232#section-2.3[RFC 7232 Section 2.3]. - -You configure the `ShallowEtagHeaderFilter` in `web.xml`: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - etagFilter - org.springframework.web.filter.ShallowEtagHeaderFilter - - - - - etagFilter - petclinic - ----- - -Or in Servlet 3.0+ environments, +=== ETag filter -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class MyWebAppInitializer extends AbstractDispatcherServletInitializer { - - // ... - - @Override - protected Filter[] getServletFilters() { - return new Filter[] { new ShallowEtagHeaderFilter() }; - } - - } ----- - -See <> for more details. - - - -[[mvc-container-config]] -== WebApplicationInitializer -In a Servlet 3.0+ environment, you have the option of configuring the Servlet container -programmatically as an alternative or in combination with a `web.xml` file. Below is an -example of registering a `DispatcherServlet`: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - import org.springframework.web.WebApplicationInitializer; - - public class MyWebApplicationInitializer implements WebApplicationInitializer { - - @Override - public void onStartup(ServletContext container) { - XmlWebApplicationContext appContext = new XmlWebApplicationContext(); - appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml"); - - ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(appContext)); - registration.setLoadOnStartup(1); - registration.addMapping("/"); - } - - } ----- - -`WebApplicationInitializer` is an interface provided by Spring MVC that ensures your -implementation is detected and automatically used to initialize any Servlet 3 container. -An abstract base class implementation of `WebApplicationInitializer` named -`AbstractDispatcherServletInitializer` makes it even easier to register the -`DispatcherServlet` by simply overriding methods to specify the servlet mapping and the -location of the `DispatcherServlet` configuration. - -This is recommended for applications that use Java-based Spring configuration: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { - - @Override - protected Class[] getRootConfigClasses() { - return null; - } - - @Override - protected Class[] getServletConfigClasses() { - return new Class[] { MyWebConfig.class }; - } - - @Override - protected String[] getServletMappings() { - return new String[] { "/" }; - } - - } ----- - -If using XML-based Spring configuration, you should extend directly from -`AbstractDispatcherServletInitializer`: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class MyWebAppInitializer extends AbstractDispatcherServletInitializer { - - @Override - protected WebApplicationContext createRootApplicationContext() { - return null; - } - - @Override - protected WebApplicationContext createServletApplicationContext() { - XmlWebApplicationContext cxt = new XmlWebApplicationContext(); - cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml"); - return cxt; - } - - @Override - protected String[] getServletMappings() { - return new String[] { "/" }; - } - - } ----- - -`AbstractDispatcherServletInitializer` also provides a convenient way to add `Filter` -instances and have them automatically mapped to the `DispatcherServlet`: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class MyWebAppInitializer extends AbstractDispatcherServletInitializer { - - // ... - - @Override - protected Filter[] getServletFilters() { - return new Filter[] { new HiddenHttpMethodFilter(), new CharacterEncodingFilter() }; - } - - } ----- - -Each filter is added with a default name based on its concrete type and automatically -mapped to the `DispatcherServlet`. - -The `isAsyncSupported` protected method of `AbstractDispatcherServletInitializer` -provides a single place to enable async support on the `DispatcherServlet` and all -filters mapped to it. By default this flag is set to `true`. - -Finally, if you need to further customize the `DispatcherServlet` itself, you can -override the `createDispatcherServlet` method. +There is a built-in filter that provides shallow ETag support. It is called shallow +because it relies on computing teh ETag from the actual content written at the end. +See <> for more details. diff --git a/src/docs/asciidoc/web/websocket.adoc b/src/docs/asciidoc/web/websocket.adoc index d737f864d5b..b93648dda8b 100644 --- a/src/docs/asciidoc/web/websocket.adoc +++ b/src/docs/asciidoc/web/websocket.adoc @@ -48,7 +48,7 @@ and also provides additional value-add as explained in the rest of the introduct [[websocket-into-fallback-options]] -=== WebSocket Fallback Options +=== Fallback Options An important challenge to adoption is the lack of support for WebSocket in some browsers. Notably the first Internet Explorer version to support WebSocket is version 10 (see http://caniuse.com/websockets for support by browser versions). @@ -67,7 +67,7 @@ application otherwise. [[websocket-intro-architecture]] -=== A Messaging Architecture +=== Messaging Aside from short-to-midterm adoption challenges, using WebSocket brings up important design considerations that are important to recognize early on, especially in contrast to what we know about building web applications today. @@ -94,7 +94,7 @@ annotation based programming model. [[websocket-intro-sub-protocol]] -=== Sub-Protocol Support in WebSocket +=== WebSocket Sub-Protocol WebSocket does imply a __messaging architecture__ but does not mandate the use of any specific __messaging protocol__. It is a very thin layer over TCP that transforms a stream of bytes into a stream of messages @@ -127,7 +127,7 @@ WebSocket and over the web. [[websocket-intro-when-to-use]] -=== Should I Use WebSocket? +=== Do I Use WebSocket? With all the design considerations surrounding the use of WebSocket, it is reasonable to ask, "When is it appropriate to use?".