Spring Web MVC
Spring web MVC is built on the servlet API and has been included in the Spring framework from the very beginning. The formal name, "Spring Web MVC", comes from the name of its source module(spring-webmvc), but it is more commonly known as "Spring MVC"
Servlet means Server Component. Here, the let means component.
Spring MVC follows the front controller pattern, which stands for the core of the framework. It accepts the Http requests from the clients and mapping them to the corresponding handlers(controllers), which are also servlets.
DispatcherServlet
Spring MVC is designed around the front controller. It is a central servlet, i.e. dispatcher servlet, which provides a shared algorithm for request processing. However, actual works are performed by configurable delegators. This model is flexible and supports diverse workflows.
DispatcherServlet works like web.xml to mapping the request to its handler. Meaning that web.xml defines the mapping to locate the resource.
Traditionally, the developer needs to tell Spring container to bootstrap a servlet dispatcher by implements WebApplicationInitializer, where we may tell the container to instantiate a dispatcher servlet in the highest priority, meanwhile designating a specific WebApplicationContext, for instance, an AnnotationConfigWebApplicatoinContext. WebApplicationInitializer implementations are detected automatically, so you may package them within the application as you see fit.
public class MyWebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
XmlWebApplicationContext appContext = new XmlWebApplicationContext();
appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet(appContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
In the above, WEB-INF/web.xml was replaced with code in the form of a WebApplicationInitializer, but the actual dispatcher-config.xml Spring configuration remained XML-based. This can be configured in a 100% code-based approach.
public class MyWebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext =
new AnnotationConfigWebApplicationContext();
dispatcherContext.register(DispatcherConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
In the Spring boot, the dispatcher servlet doesn't need to be initialized but auto-generated by the Spring container.
Whatever the ApplicationConfig is required, it extends from WebMvcConfiguartionSupport, which implements ApplicationContextAware and ServletContextAware. Because the Aware interface, Application context will transfer back its instance to the WebAMvcConfigurationSupport. This is the main class providing the configuration behind the MVC java config. It is typically imported by adding @EnableWebMvc to an application @Configuation class.
Within ApplicationConfig, we need to define InternalResourceViewResolver, which declares ①viewClass=org.thymeleaf.spring5.view;②prefix=/resource/templates/ ;③ suffix =.html
They are all resources but located inside the project. That is why it is called Internal resources. The view class is dependent on which view technique is applied in the project; the prefix is put before the logic view name, and the suffix is put after the logic view name; so that they together form a directory tree.
InternalResourceViewResolver is the most popular view-resolver, but there are other variants.
Special bean types:
- HandlerMapping: maps request to the handler.
- HandlerAdapter: invokes a handler.
- HandlerExceptionResolver: helps with exception handling.
- ViewResolver: helps resolve views.
- LocaleResolver: helps for l10n and i18n support.
- ThemeResolver: helps with stylized look and feel
Java-Based config:
We can now do completely in Java what used to be done in web.xml and Spring bean definition XML files.
- Web application initializer
- Root application context configuration
- Dispatcher no.1 config: /main/*
- Dispatcher no.2 config:/api/*
Controller
Controller Types: @Controller and @RestController
@RestController only return @ResponseBody; but@Controller returns view(a logical string) and model.
Controller methods decorated by @RestMapping are handlers, which response the request from the clients.
Request mapping by:
- URI pattern with @PathVariable
- @RequestParameter and parameter condition
- @ModelAttribute: binding form fields to the java POJO attributes
Method input arguments:
25 supported
Method return values:
15 supported
Data Binding
Collecting data from view fields and binding them into java object, or in another way around, the java data model that is fetched from the controller, and then presented on the view (Html and JSP page)
From a view to a controller:
@ModelAttributes can be used at the method level or method parameter level.
When @ModelAttributes used at the method level. it is always called before any request handler(controller method decorated by a request mapping); meaning that, any model required has to be created before any request handler that can be carried out. This is used to instantiate models and giving them default values.
When @ModelAtrtributes used at the method parameter level, a form of a view can be bound into a java POJO model.
From controller to view:
The model can supply attributes used for rendering views. To provide a view with usable data, we simply add this data to its Model object. It is used as a Map, storing the data with a key. The Model can be directly injected from the controller method argument.
Data Validation:
Data could be polluted in the views as reaching the controllers. so it needs to be validated.
Spring validator interface for application-specific objects.
JSR 380(javax.validation) bean validation API is the standard. It goes well with Spring 5.1.
Using annotations to add validation rules on java bean attributes. Then the Spring framework will do validation for us.
Using annotation @Valid to Enable validation in the Controller method argument. The validation result is contained a BindingResult parameter, which must be declared immediately after the validated target.
Data Converter
For Http requests, string-based values are extracted from the request including request parameters, path variables, request headers, and cookie values. They may need to be converted to the target type of the method parameter or field they are expected to.
method parameters and type conversion
Binder methods:
Data transferred from the view normally in strings. @ModelAttribute can do field-to-attribute binding, mapping a string to string. In a case, binding a string to a specific java type, we have to declare a binder-method, which is used to register an object conversion or formating within a controller or globally across a group of controllers.
@InitBinderpublic void initBinder(WebDataBinder binder){
binder.registerCustomEditor(Date.class, "dateOfBirth",
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));}
@InitBinder method is applied to the request parameter data, URI variables, and form beans
customizing data binding with @InitBinder
- Bind request parameters(that is, form or query data) to an object(model)
- Convert String-based request values(request parameters, path variables, headers, cookies, and others) to the target type of controller method arguments.
- Format model object values as String values when rendering HTML forms.
Exception Handling
- Handled by DispatcherServlet
- Delegates to handlerExceptionResolver beans
- What does exception handling mean in an application
Implementations for exception handling:
- ExceptionHandlerExceptionResolver: define exception handler methods in controllers
- SimpleMappingExceptionResolver: map each exception class with an error page
- DefaultHandlerExceptionResolver: default which maps exceptions to error codes
- ResponseStatusExceptionResolver: resloves customer exceptions using @ResponseStatus
Handling exception locally in a controller scope.
@ExceptionHandler modifies a method that should be invoked to handle an exception.
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity handle(IOException ex) {
}
Handling exception globally in a controller advice class.
Applying globally and across all @RequestMapping methods when defined with an @ControllerAdvice class or @RestContollerAdvice.
Annotating Business Exceptions with @ResponseStatus
A business exception can be annotated with @ResponseStatus. When the exception is raised, the ResponseStatusExceptionResolver handles it by setting the status of the response accordingly. By default, the DispatherServlet registers the ResponseStatusExceptionResolver and it is available for use.
Controller advice:
It is an aspect implementation relating to common concerns of controllers. If applying @ExceptionHandler, @ModelAttribute, and @InitBinder globally across all controllers, then you need to declare then within the class decorated with @ControllerAdvice or @RestControllerAdvice.
The controller advice class is applied on every request, every controller; meanwhile, it allows to specify certain types of controllers(@Controller or @RestController), only for certain packages, or specific controllers. @ControllerAdvice(assignableTypes={A.class,B.class}).
On startup, the infrastructure classes for @RequestMapping and @ExceptionHandler methods detect Spring beans annotated with @ControllerAdvice and then apply their methods at runtime. Global @ExceptionHandler methods (from a @ControllerAdvice) are applied after local ones (from the @Controller). By contrast, global @ModelAttribute and @InitBinder methods are applied before local ones.
Async Request Processing
The request may be blocked due to a heavy task, which takes a long time to process. Async request processing use Thread-1 to response Http Request thread, subsequently it uses Thread-2, which is A task executor thread in a thread pool, to handle the blocking task. The controller returns Callable or DeferredResult.
Set the Mvc async processing flag to be true, so as to enable the async processing. Spring boot enables async-request processing by default. So, we don't need concern about this.
Configuring async processing in web-mvc-configuration: ➊ declare async task executor bean; ❷ set task executor within the asyncSupportConfigurer.
@Override
protected void configureAsyncSupport(AsyncSupportConfigurer asyncSupportConfigurer) {
asyncSupportConfigurer.setDefaultTimeout(10000);
asyncSupportConfigurer.setTaskExecutor(mvcAsyncTaskExecutor());}
@Bean
public AsyncTaskExecutor mvcAsyncTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("hplusapp-thread-");
return threadPoolTaskExecutor;}
View Resolver
The view resolver provides a mapping between view names and actual views. The controller returns a view name in a string. According to the name, view resolver picks up the view template from a pre-defined folder, and then return to the client as an HTTP response.
There are many types of view resolvers:
InternalResourceViewResolver is used to pick up the JSP template in a correct folder in the project.
this is used to map a view name to its JSPs.
Employing a properties file to resolve views, which is done by a
ResourceBundleViewResolver.
Meaning that defining all view names and map it to the correct JSPs in a properties file.
XmlViewResolver: implementation of ViewResolver that accepts a configuration file written in XML with the same DTD as Spring's XML bean factories.
VelocityViewResolver/FreeMarkerViewResolver
Convenient subclass of UrlBasedViewResolver that supports FreeMarkerView and custom subclasses of them.
Interceptor
The concept of interceptions in Spring MVC is very similar to the filter components in the Servlet JSP API, which is used for pre- and post-processing of the request.
Built-in and customer interceptors
- ThemChangeTnterceptor
- LocalChangeInterceptor
- Custom interceptors should extend HandlerInterceptorAdaper
Custom interceptors need to be registered in WebConfig class that implements
WebMvcConfigurerSupport
@Overrideprotected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoggingInterceptor()).addPathPatterns("/*");
registry.addInterceptor(new ThemeChangeInterceptor());}
Session
A session may link several controllers.
@SessoinAttributes (used in class level)
Themes
An application may have different themes. A theme stands for a different feel and a look of the view, which is defined by different CSS, images, icon ket, and font kit etc.
Define theme using org.springframework.ui.context.ThemeSource.
The default implementation is ResourceBundleThemeSource.
ThemeResolver decides which theme to use
- CookieThemeResolver
- SessionThemeResolver
- FixedThemeResolver
Create theme properties file under the resource folder.
In ApplicationConfig, register ThemChangeInterceptor and creating bean ThemeResolver.
Used
to refer themed keys from .properties file on the JSP.
L10n and i18n
Problem: common label or message may be fetched from a central place. Language may be presented differently in different countries.
LocaleResolver into play
Default implementation: AcceptHeaderLocaleResolver
Add message properties files for different locales on the classpath.
In spring boot defines messages-langShortName.properties
language short name is here
i8n code
fx: for Swedish, its short name is 'sv', and then the name for 'properties' file should be
messages-sv.properties
Creating message property files, key-value standing for the same label but different languages.
Note:
In IntelliJ, finding File Encoding file, making sure default property file encoding is UTF-8, and also
including the 'Global encoding' and 'Project encoding'.
Chrome: settings: language. order preference of language
LocalResolver and CookieLocaleInterceptor
default key = 'locale'
Rest Controller
Access resource on the web; return data (ResponseEntity); MVC controller return view name;
Injecting Custom Arguments
When using Spring MVC you can add certain arguments to your controllers and the framework injects those arguments for you, fx: HttpServletRequest, Model, Locale, OutputStream etc.
Spring MVC provides us with an interface designed to allow us to inject parameters to our controller methods:
HandlerMethodArgumentResolver.
Injecting custom method arguments
Inject your custom method argument in Spring MVC using HandlerMethodArgumentResolver