spring mvc reference (1)
Spring Web MVC framework
A key design principle in Spring Web MVC :Open for extension, closed for modification.
Some methods in the core classes of Spring Web MVC are marked final.
You cannot add advice to final methods when you use Spring MVC.
In Spring Web MVC you can use any object as a command or form-backing object; you do not need to implement a framework-specific interface or base class.
Spring’s view resolution is extremely flexible. A Controller
is typically responsible for preparing a model Map
with data and selecting a view name but it can also write directly to the response stream and complete the request.
Flexible model transfer. Model transfer with a name/value Map
supports easy integration with any view technology.
Beans whose lifecycle is scoped to the current HTTP request or HTTP Session
.
The DispatcherServlet
Spring’s web MVC framework is, like many other web MVC frameworks, request-driven, designed around a central Servlet that dispatches requests to controllers and offers other functionality that facilitates the development of web applications. Spring’s DispatcherServlet
however, does more than just that. It is completely integrated with the Spring IoC container and as such allows you to use every other feature that Spring has.
The DispatcherServlet
is an actual Servlet
(it inherits from the HttpServlet
base class), and as such is declared in the web.xml
of your web application.
<web-app> <servlet> <servlet-name>example</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>example</servlet-name> <url-pattern>/example/*</url-pattern> </servlet-mapping> </web-app>
In the Web MVC framework, each DispatcherServlet
has its own WebApplicationContext
, which inherits all the beans already defined in the root WebApplicationContext
.
Spring MVC looks for a file named [servlet-name]-servlet.xml in the WEB-INF
directory of your web application and creates the beans defined there, overriding the definitions of any beans defined with the same name in the global scope.
You can change the exact location of this configuration file through a Servlet initialization parameter
<web-app> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/root-context.xml</param-value> </context-param> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value></param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
HandlerMapping: Maps incoming requests to handlers and a list of pre- and post-processors (handler interceptors) 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.
HandlerAdapter: Helps the DispatcherServlet
to invoke a handler mapped to a request regardless of the handler is actually invoked.
ViewResolver: Resolves logical String-based view names to actual View
types.
Default DispatcherServlet Configuration
DispatcherServlet
maintains a list of implementations to use by default. This information is kept in the file DispatcherServlet.properties
in the package org.springframework.web.servlet
.
once you configure a special bean such as an InternalResourceViewResolver
in yourWebApplicationContext
, you effectively override the list of default implementations.
DispatcherServlet Processing Sequence
After you set up a DispatcherServlet
, and a request comes in for that specific DispatcherServlet
, the DispatcherServlet
starts processing the request as follows:
- The
WebApplicationContext
is searched for and bound in the request as an attribute that the controller and other elements in the process can use. It is bound by default under the keyDispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
. - The locale resolver is bound to the request to enable elements in the process to resolve the locale to use when processing the request (rendering the view, preparing data, and so on). If you do not need locale resolving, you do not need it.
- The theme resolver is bound to the request to let elements such as views determine which theme to use. If you do not use themes, you can ignore it.
- If you specify a multipart file resolver, the request is inspected for multiparts; if multiparts are found, the request is wrapped in a
MultipartHttpServletRequest
for further processing by other elements in the process. - An appropriate handler is searched for. If a handler is found, the execution chain associated with the handler (preprocessors, postprocessors, and controllers) is executed in order to prepare a model or rendering.
- If a model is returned, the view is rendered. If no model is returned, (may be due to a preprocessor or postprocessor intercepting the request, perhaps for security reasons), no view is rendered, because the request could already have been fulfilled.
Handler exception resolvers that are declared in the WebApplicationContext
pick up exceptions that are thrown during processing of the request. Using these exception resolvers allows you to define custom behaviors to address exceptions.
Implementing Controllers
Controllers provide access to the application behavior that you typically define through a service interface. Controllers interpret user input and transform it into a model that is represented to the user by the view.
@Controller public class HelloWorldController { @RequestMapping("/helloWorld") public String helloWorld(Model model) { model.addAttribute("message", "Hello World!"); return "helloWorld"; } }
Defining a controller with @Controller
The @Controller
annotation indicates that a particular class serves the role of a controller.
The dispatcher scans such annotated classes for mapped methods and detects @RequestMapping
annotations.
To enable autodetection of such annotated controllers, you add component scanning to your configuration.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.springframework.samples.petclinic.web"/> <!-- ... --> </beans>
Mapping Requests With @RequestMapping
You use the @RequestMapping
annotation to map URLs such as /appointments
onto an entire class or a particular handler method. Typically the class-level annotation maps a specific request path (or path pattern) onto a form controller, with additional method-level annotations narrowing the primary mapping for a specific HTTP method request method ("GET", "POST", etc.) or an HTTP request parameter condition.
@Controller @RequestMapping("/appointments") public class AppointmentsController { private final AppointmentBook appointmentBook; @Autowired public AppointmentsController(AppointmentBook appointmentBook) { this.appointmentBook = appointmentBook; } @RequestMapping(method = RequestMethod.GET) public Map<String, Appointment> get() { return appointmentBook.getAppointmentsForToday(); } @RequestMapping(path = "/{day}", method = RequestMethod.GET) public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) { return appointmentBook.getAppointmentsForDay(day); } @RequestMapping(path = "/new", method = RequestMethod.GET) public AppointmentForm getNewForm() { return new AppointmentForm(); } @RequestMapping(method = RequestMethod.POST) public String add(@Valid AppointmentForm appointment, BindingResult result) { if (result.hasErrors()) { return "appointments/new"; } appointmentBook.addAppointment(appointment); return "redirect:/appointments"; } }
@RequestMapping usage on the type (class) level, which indicates that all handler methods in this controller are relative to the /appointments
path.
The getForDay()
method shows usage of @RequestMapping
: URI templates.
A @RequestMapping
on the class level is not required. Without it, all paths are simply absolute, and not relative.
Composed @RequestMapping Variants:
@Controller @RequestMapping("/appointments") public class AppointmentsController { private final AppointmentBook appointmentBook; @Autowired public AppointmentsController(AppointmentBook appointmentBook) { this.appointmentBook = appointmentBook; } @GetMapping public Map<String, Appointment> get() { return appointmentBook.getAppointmentsForToday(); } @GetMapping("/{day}") public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) { return appointmentBook.getAppointmentsForDay(day); } @GetMapping("/new") public AppointmentForm getNewForm() { return new AppointmentForm(); } @PostMapping public String add(@Valid AppointmentForm appointment, BindingResult result) { if (result.hasErrors()) { return "appointments/new"; } appointmentBook.addAppointment(appointment); return "redirect:/appointments"; } }
@Controller and AOP Proxying
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 <tx:annotation-driven/>
, change to <tx:annotation-driven proxy-target-class="true"/>
.