ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring MVC and Request Life Cycle
    Framework/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/32905917/how-to-return-json-data-from-spring-controller-using-responsebody/35822500#35822500

    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://dzone.com/articles/using-the-spring-requestmapping-annotation#:~:text=Request%20Mapping%20Basics&text=When%20configuring%20Spring%20MVC%2C%20you,method%2Dlevel%20in%20a%20controller.

    https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestmapping

    https://stackoverflow.com/questions/29365833/what-are-valid-return-types-of-a-spring-mvc-controller-method

    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

    댓글

Designed by Tistory.