-
Spring MVC and Request Life CycleFramework/SPRING 2020. 2. 3. 13:29
1. Overview
1.1 Spring MVC
Spring MVC is a web application framework that implements the Model View Controller pattern. It allows to implement controller classes equipped with mapping annotations to map HTTP requests into method invocations and bind request parameters and payloads to method arguments.
@RestController // 1 class MyController { @GetMapping("/hello") // 2 String sayHelloTo(@RequestParam Optional<String> name) { // 3 return String.format("Hello, %s!", name.orElse("world")); } }
- @RestController: An annotation to make the component known to the framework and assign it a given role (here: a Spring WebMVC controller).
- @GetMapping: An annotation to make the component known to the framework and assign it a given role (here: a Spring WebMVC controller).
- @RequestParam: An annotated parameter to express we want to get access to the request parameter named name. Wrapped into an Optional as the request might not include that parameter and we have to handle that case in the implementation.
2. Components
2.1 Filter
A filter is an object that performs filtering tasks on either the request to a resource (a servlet or static content), or on the response from a resource, or both.
- The filter applies to every request
- Filter precede DispacherServlet
- A filter is a J2EE standard specification
2.2 Dispatcher servlet
The servlet analyzes the requests and dispatches them to the appropriate controller for processing.
- Request-driven, designed around a central servlet that dispatches, or delegate, requests to controllers and offers other functionality that facilitates the development of web applications
- An actual Servlet (it inherits from the HttpServlet base class), and as such is declared in the web.xml of your web application
- You need to map requests that you want the DispatcherServlet to handle, by using a URL mapping in the same web.xml file
<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>*.form</url-pattern> </servlet-mapping> </web-app>
2.3 Common Service
The common services will apply to every request to provide supports including i18n, theme, file upload, and so on. Their configuration is defined in the DispatcherServlet’s WebApplicationContext.
2.4 Handler mapping
This maps the request to the handler (a method within a Spring MVC controller class). Since Spring 2.5, in most situations, the configuration is not required because Spring MVC will automatically register the org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping class that maps handlers based on HTTP paths expressed through the @RequestMapping annotation at the type or method level within controller classes.
2.5 Handler Interceptor
In Spring MVC, you can register interceptors for the handlers for implementing common checking or logic such as checking and ensuring that only the handlers can be invoked during office hours.
2.5.1 Configuration
@Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new SomeLogicInterceptor()); } }
2.5.2 Adding HandlerInterceptor
You can implement the HandlerInterceptor and put your pre-processing logic into the preHandle method:
public class SomeLogicInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; SomeAnnotation someAnnotation = handlerMethod.getMethodAnnotation(SomeAnnotation.class); if (someAnnotation != null) { // Put your logic here } } return true; // return false if you want to abort the execution chain } }
2.6 Handler exception resolver
In Spring MVC, the HandlerExceptionResolver interface (under the package org.springframework.web.servlet) is designed to deal with unexpected exceptions thrown during request processing by handlers.
2.7 View resolver
Spring MVC’s ViewResolver interface (under the package org.springframework.web.servlet) supports view resolution based on a logical name returned by the controller.
3. Returning JSON Object as Response
In Spring REST JSON example, we will learn to write RESTful webservices capable of returning JSON representations of resources. We will use MappingJackson2JsonView to resolve views to JSON body.
3.1 pom.xml
<!-- Jackson JSON Processor --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.4.1</version> </dependency>
3.2 Spring REST JSON – @ResponseBody Annotation
This first technique is simple and easy. We have to include only jackson dependencies into classpath of the application and spring will register Jackson2JsonMessageConverter class automatically into context. Whenever we ask for a resource from REST API and provide http header “accept: application/json“, we will get back the json representation of resource.
@RestController public class EmployeeRESTController { @RequestMapping(value = "/employees") public EmployeeListVO getAllEmployees() { EmployeeListVO employees = new EmployeeListVO(); EmployeeVO empOne = new EmployeeVO(1,"Lokesh","Gupta","howtodoinjava@gmail.com"); EmployeeVO empTwo = new EmployeeVO(2,"Amit","Singhal","asinghal@yahoo.com"); EmployeeVO empThree = new EmployeeVO(3,"Kirti","Mishra","kmishra@gmail.com"); employees.getEmployees().add(empOne); employees.getEmployees().add(empTwo); employees.getEmployees().add(empThree); return employees; } @RequestMapping(value = "/employees/{id}") public ResponseEntity<EmployeeVO> getEmployeeById (@PathVariable("id") int id) { if (id <= 3) { EmployeeVO employee = new EmployeeVO(1,"Lokesh","Gupta","howtodoinjava@gmail.com"); return new ResponseEntity<EmployeeVO>(employee, HttpStatus.OK); } return new ResponseEntity(HttpStatus.NOT_FOUND); } }
3.3 Spring REST JSON – MappingJackson2JsonView Support
This is second technique. The MappingJackson2JsonView class also depends on the presence of the Jackson JSON processor library in classpath, so you don’t need to add anything extra. Complete pom.xml looks like this
3.3.1 pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.howtodoinjava.demo</groupId> <artifactId>springrestexample</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>springrestexample Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- Spring MVC support --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.1.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.1.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.1.4.RELEASE</version> </dependency> <!-- Jackson JSON Processor --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.4.1</version> </dependency> </dependencies> <build> <finalName>springrestexample</finalName> </build> </project>
3.3.2 Add MappingJackson2JsonView view
When you are using MappingJackson2JsonView class, you will need to return a view name of type MappingJackson2JsonView. So you will need to change two places.
3.3.3 Controller change
You will need to return viewName from controller method. In our case, view name is “jsonTemplate“.
package com.howtodoinjava.demo.controller; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import com.howtodoinjava.demo.model.EmployeeListVO; import com.howtodoinjava.demo.model.EmployeeVO; @Controller public class EmployeeRESTController { private EmployeeListVO getEmployeesCollection() { EmployeeListVO employees = new EmployeeListVO(); EmployeeVO empOne = new EmployeeVO(1,"Lokesh","Gupta","howtodoinjava@gmail.com"); EmployeeVO empTwo = new EmployeeVO(2,"Amit","Singhal","asinghal@yahoo.com"); EmployeeVO empThree = new EmployeeVO(3,"Kirti","Mishra","kmishra@gmail.com"); employees.getEmployees().add(empOne); employees.getEmployees().add(empTwo); employees.getEmployees().add(empThree); return employees; } @RequestMapping(value = "/employees") public String getAllEmployeesJSON(Model model) { model.addAttribute("employees", getEmployeesCollection()); return "jsonTemplate"; } }
3.3.4 Configuration Change
You will need to configure viewName “jsonTemplate” as bean of type MappingJackson2JsonView. And you will need to configure view resolver of type BeanNameViewResolver. This way viewName “jsonTemplate” will be matched with MappingJackson2JsonView and parsed JSON response will be returned to client.
@Configuration public class RESTConfiguration { @Bean public View jsonTemplate() { MappingJackson2JsonView view = new MappingJackson2JsonView(); view.setPrettyPrint(true); return view; } @Bean public ViewResolver viewResolver() { return new BeanNameViewResolver(); } }
Equivalent XML configuration to above java configuration is as below.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" 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 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.howtodoinjava.demo" /> <mvc:annotation-driven /> <!-- JSON Support --> <bean name="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"/> <bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/> </beans>
4. Returning JSON object as response in Spring Boot
As you are using Spring Boot web, Jackson dependency is implicit and we do not have to define explicitly. You can check for Jackson dependency in your pom.xml in the dependency hierarchy tab if using eclipse.
And as you have annotated with @RestController there is no need to do explicit json conversion. Just return a POJO and jackson serializer will take care of converting to json. It is equivalent to using @ResponseBody when used with @Controller. Rather than placing @ResponseBody on every controller method we place @RestController instead of vanilla @Controller and @ResponseBody by default is applied on all resources in that controller.
5. Request Life cycle Procedure
5. Reference
https://howtodoinjava.com/spring-restful/spring-rest-hello-world-xml-example/
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc
https://stackoverflow.com/questions/44839753/returning-json-object-as-response-in-spring-boot
https://howtodoinjava.com/spring-restful/spring-rest-hello-world-json-example/
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-return-types
https://www.baeldung.com/spring-mvc-handlerinterceptor
https://stackoverflow.com/questions/38102569/spring-mvc-how-to-get-a-handler-method-for-a-request
http://static.olivergierke.de/lectures/spring/#spring.psa
https://justforchangesake.wordpress.com/2014/05/07/spring-mvc-request-life-cycle/
https://javaee.github.io/javaee-spec/javadocs/javax/servlet/Filter.html
https://docs.spring.io/spring/docs/3.0.0.M4/spring-framework-reference/html/ch15s02.html
https://www.journaldev.com/1933/java-servlet-filter-example-tutorial
https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/spring-mvc-intro.html
'Framework > SPRING' 카테고리의 다른 글
Spring Inversion of Control (IoC) (0) 2020.02.06 Spring Framework (0) 2020.02.06 Spring Bean Scopes (0) 2019.09.29 DispatcherServlet in Spring (0) 2019.09.28 Spring Security (0) 2019.09.20