Spring MVC high-level framework

Spring MVC application

Spring MVC profile

  • Deep understanding of classic three-tier and MVC patterns

    Three layer architecture

    Our development architecture is generally based on two forms, one is C/S architecture, that is, client/server; The other is the B/S architecture, which is the browser server. In JavaEE development, almost all development is based on B/S architecture. Then in B/S architecture, the system standard three-layer architecture includes: presentation layer, business layer, and persistence layer.

    • Presentation layer: The presentation layer includes the presentation layer and the control layer: the control layer is responsible for receiving requests, and the presentation layer is responsible for displaying results. The presentation layer relies on the business layer. Upon receiving the client request, the business layer is generally called for business processing and responds to the client with the processing result. Presentation layer design typically uses the MVC model. (MVC is the design model of the presentation layer, and has no relationship with other layers)
    • Business layer: Also known as the Service layer. It handles business logic and is closely related to the requirements of our development project. The Web layer depends on the business layer, but the business layer does not depend on the Web layer. The business layer may rely on the persistence layer for business processing, and transaction consistency is required if data is to be persisted. (As we said, transactions should be controlled in the business layer)
    • Persistence layer: also known as dao layer. Responsible for data persistence, including data layer, namely database and data access layer, database is the carrier of data persistence, data access layer is the interface between business layer and persistence layer, the business layer needs to persist data into the database through the data access layer. Generally speaking, the persistence layer is to interact with the database, add, delete, change and check the database table.

    MVC Pattern (method/form of code organization)

    The full name of MVC is Model View Controller, which is the abbreviation of Model – View – Controller. It is a pattern used to design and create the presentation layer of Web applications. Each part of MVC does its job: Model: The Model contains the business Model and the data Model, the data Model is used to encapsulate the data, and the business Model is used to process the business. View: This usually refers to our JSP or HTML. It’s usually about presenting data. Views are usually created from model data. Controller: Is the part of the application that handles user interaction. The effect is generally processor logic. MVC advocates: each layer writes its own stuff and doesn’t write any other code; Stratification is for decoupling, decoupling is for maintenance convenience and division of labor and cooperation.

  • Spring MVC

    SpringMVC, full name of Spring Web MVC, is a java-based request-driven type of lightweight Web framework that implements MVC design model. It is a follow-up product of Spring Framework.

    SpringMVC has become one of the most mainstream MVC frameworks, and with the release of Spring3.0, it has comprehensively surpassed Struts2 and become the best MVC framework. All you need to do in SpringMVC to make a Java class capable of handling requests is add annotations. It uses a set of annotations to make a simple Java class a controller for handling requests without implementing any interfaces. It also supports RESTful programming style requests. To sum up: Spring MVC, like Struts2, is a Web framework designed to solve presentation problems, and both are based on MVC design patterns. The main responsibility of these presentation layer frameworks is to handle front-end HTTP requests. Spring MVC is essentially a servlet wrapper that simplifies our serlvet development role: 1) receiving requests and 2) returning responses to jump to pages

Spring Web MVC workflow

  • SpringMVC request processing flow parsing

    Step 1: The user sends a request to the front-end controller DispatcherServlet step 2: The DispatcherServlet receives the request and invokes the HandlerMapping processor mapper Step 3: The processor mapper finds the specific Handler (backend controller) based on the request Url, generates the processor object and the processor interceptor (if any) and returns it to the DispatcherServlet step 4: Handler Handler Handler Handler Handler Handler Handler Handler Handler Handler Handler Handler Handler Handler Handler The processor adapter returns the ModelAndView to the forward controller, which is an underlying object of the SpringMVC framework, including Model and View. Step 8: The front controller requests the view resolver to parse the view, resolving the real view based on the logical view name. Step 9: The View parser returns the View to the front end controller. Step 10: The front end controller renders the View, which is to fill the request field with model data (in the ModelAndView object). Step 11: The front end controller responds to the user

  • There are nine components of SpringMVC

    • HandlerMapping is used to find handlers, which can be classes or methods. For example, each method labeled @requestMapping can be considered a Handler. The Handler is responsible for the actual request processing. After the request arrives, the HandlerMapping function is to find the Handler and Interceptor corresponding to the request.

    • A HandlerAdapter is an adapter. Because the Spring MVC Handler can be any form, as long as it can handle it. However, when sending requests to servlets, since servlets have method structures in the form of doService(HttpServletRequest REq,HttpServletResponse RESP), It is the responsibility of the HandlerAdapter to have the fixed Servlet processing method call the Handler for processing.

    • HandlerExceptionResolver HandlerExceptionResolver Is used to handle exceptions generated by the Handler. What it does is set up the ModelAndView according to the exception, which is then rendered by the rendering method, which renders the ModelAndView as a page. ViewResolver

    • ViewResolver, used to resolve String View names and Locale to View views, has only one resolveViewName() method. As you can see from the method definition, the View name returned by the Controller layer as String viewName will eventually be resolved to View here. The View is used to render the page, that is, it fills the template with the parameters and data returned by the program to generate an HTML file. The ViewResolver does two main things in this process: the ViewResolver finds the template to render (the first big thing) and the technology to use (the second big thing, which is essentially finding the type of view, such as JSP) and fills in the parameters. By default, the Spring MVC will automatically configure an InternalResourceViewResolver for us, is only for the type of JSP view.

    • RequestToViewNameTranslator RequestToViewNameTranslator component gets ViewName role from the request. The ViewResolver will use this component to find the ViewName in the request, because the ViewResolver will use this component to find the ViewName in the request.

    • The LocaleResolver ViewResolver component’s resolveViewName method takes two arguments, the view name and the Locale. LocaleResolver is used to resolve Locale from the request. For example, Chinese Locale is zh-CN, which indicates a region. This component is also the basis of the I18N.

    • ThemeResolver ThemeResolver component is used to parse topics. A theme is a collection of styles, images, and the display effects they form. A set of themes in Spring MVC corresponds to a properties file, which holds all resources related to the current theme, such as tiles, CSS styles, and so on. Creating a theme is as simple as getting the resource ready, creating a new “theme name.properties” and setting it up in your classpath, and then you can use it in your page. The theme-related classes in SpringMVC are ThemeResolver, ThemeSource, and Theme. ThemeResolver is responsible for resolving the topic name from the request. The ThemeSource finds the specific topic based on the topic name. The abstraction is called Theme, which can be used to retrieve the topic and specific resources.

    • MultipartResolver MultipartResolver used to upload the request, through the common request packaging into MultipartHttpServletRequest for real now. MultipartHttpServletRequest can getFile () method is direct access to the file. If you upload multiple files, you can also call getFileMap() to get a Map structure. The MultipartResolver encapsulates a common request to have file upload functionality.

    • FlashMapManager FlashMap is used to transfer parameters during redirection. For example, when processing a user order, to avoid repeated submission, the FlashMap can be redirected to a GET request after processing a POST request. This GET request can be used to display information such as order details. This can avoid the problem of the user resubmitting the order, but where do you get the data to display the order information on this page? If you don’t want to write parameters into the URL (not recommended), you can pass them through a FlashMap. Only need to be passed before the redirect data to request (by ServletRequestAttributes. GetRequest () method) attribute OUTPUT_FLASH_MAP_ATTRIBUTE, Spring will then automatically set it to the Model in the Handler after the redirect, and the order information can be retrieved directly from the Model on the page that displays it. The FlashMapManager is used to manage FalshMap.

      These nine components are declared in the DispatcherServlet

      	/** MultipartResolver used by this servlet. */
      	@Nullable
      	private MultipartResolver multipartResolver;
      
      	/** LocaleResolver used by this servlet. */
      	@Nullable
      	private LocaleResolver localeResolver;
      
      	/** ThemeResolver used by this servlet. */
      	@Nullable
      	private ThemeResolver themeResolver;
      
      	/** List of HandlerMappings used by this servlet. */
      	@Nullable
      	private List<HandlerMapping> handlerMappings;
      
      	/** List of HandlerAdapters used by this servlet. */
      	@Nullable
      	private List<HandlerAdapter> handlerAdapters;
      
      	/** List of HandlerExceptionResolvers used by this servlet. */
      	@Nullable
      	private List<HandlerExceptionResolver> handlerExceptionResolvers;
      
      	/** RequestToViewNameTranslator used by this servlet. */
      	@Nullable
      	private RequestToViewNameTranslator viewNameTranslator;
      
      	/** FlashMapManager used by this servlet. */
      	@Nullable
      	private FlashMapManager flashMapManager;
      
      	/** List of ViewResolvers used by this servlet. */
      	@Nullable
      	private List<ViewResolver> viewResolvers;
      Copy the code
  • Url-pattern configuration and principle analysis

    web.xml

        <! -- Method one: with suffix, such as *.action *.do *.aaa this method is more accurate, convenient, in the past and now have a large proportion of use in the enterprise method two: / will not intercept.jsp, but will intercept. Js, CSS, PNG, etc.) other than servlets and JSPS are configured with/to block static resources. Because the Tomcat container has a web. XML (parent) and your project has a web. XML (child), The parent web. XML has a DefaultServlet, and the url-pattern is a /. Our own web. Because there is a JspServlet in the parent web.xml that intercepts the.jsp file, we did not override this configuration so SpringMVC does not intercept the JSP at this time, leaving the JSP handling to Tomcat how to resolve/intercept static resources? /* Intercepts everything, including.jsp -->
        <! -- Intercepting the url request for matching rules and entering the SpringMVC framework for processing -->
        <url-pattern>/</url-pattern>
    Copy the code

    springmvc.xml

        <! Static Resource Configuration, Solution 1 -->
        <! - principle: Configuration, add the tag will be in for SpringMVC context defines a DefaultServletHttpRequestHandler object This object as a inspection personnel, to enter the DispatcherServlet url request filtering screening, If it is found to be a static resource request, the request is forwarded to the Web Application server (Tomcat) default DefaultServlet for processing. If it is not a static resource request, the SpringMVC framework continues to process it.
        <! --<mvc:default-servlet-handler/>-->
    
    
    
        <! Static resource configuration, solution 2, SpringMVC framework handles static resource mapping: static resource url rule location: specified static resource location -->
        <mvc:resources location="classpath:/"  mapping="/resources/**"/>
        <mvc:resources location="/WEB-INF/js/" mapping="/js/**"/>
    Copy the code
  • Data output mechanism Model, Map, ModleMap

    SpringMVC passes in the Map, Model, and ModelMap parameters to the handler method and saves data to these parameters (into the request field), all of which are available on the page. What is the relationship between them? The specific type of the runtime is BindingAwareModelMap, which means that the data stored in BindingAwareModelMap is placed in the request domain.

    Map(interface in JDK)

    Model (Spring interface

    ModelMap(class, implementing Map interface)

    BindingAwareModelMap inherits ExtendedModelMap, which inherits ModelMap and implements the Model interface

Request parameter binding

  • The Servlet API is supported as a method parameter by default

    When you need to use native servlet objects such as HttpServletRequest, HttpServletResponse, and HttpSession, you can use the parameter declaration directly in the handler method.

  • Simple type parameter binding

    Simple data types: eight basic data types and their packaging types Parameter Type Packing data types are recommended, because the basic data types cannot be null Integer: Integer, int String: String Single precision: Float, Float Double, Double Boolean: Boolean, Boolean description: For Boolean type parameters, the request parameter value is true or false. (The parameter name and the passed parameter name should be the same. It is recommended to use wrapper type. If the parameter name and the passed parameter name are inconsistent, you can manually map them using @requestParam annotation.)

     public ModelAndView handle03(@RequestParam("ids") Integer id,Boolean
    flag) {
     Date date = new Date();
     ModelAndView modelAndView = new ModelAndView();
     modelAndView.addObject("date",date);
     modelAndView.setViewName("success");
     return modelAndView;
     }
    Copy the code
  • POJO type parameter

    /* * SpringMVC accepts poJO type arguments url: /demo/handle04? Id =1&username=zhangsan * * The poJO type parameter is received. The parameter name must be the same as the POJO attribute name */
     @RequestMapping("/handle04")
     public ModelAndView handle04(User user) {
     	Date date = new Date();
     	ModelAndView modelAndView = new ModelAndView();
     	modelAndView.addObject("date",date);
     	modelAndView.setViewName("success");
    	 return modelAndView;
     }
    Copy the code

    When a Pojo is a wrapper object

    public class QueryVo {
         private String mail;
         private String phone;
         // Another Pojo object is nested
         private User user;
         public String getMail(a) {
         return mail;
         }
         public void setMail(String mail) {
         this.mail = mail;
         }
         public String getPhone(a) {
         return phone;
         }
         public void setPhone(String phone) {
         this.phone = phone;
         }
         public User getUser(a) {
         return user;
         }
         public void setUser(User user) {
         this.user = user; }}Copy the code
    /* * SpringMVC receives the POJO wrapper type argument URL: /demo/handle05? User. id=1&user.username=zhangsan&mail=xx&phone=xx * Regardless of whether the Pojo is wrapped or not, it is first a Pojo, If the poJO attribute cannot be located, the attribute name + "." can be used to lock the poJO attribute * */
     @RequestMapping("/handle05")
     public ModelAndView handle05(QueryVo queryVo) {
     Date date = new Date();
     ModelAndView modelAndView = new ModelAndView();
     modelAndView.addObject("date",date);
     modelAndView.setViewName("success");
     return modelAndView;
     }
    Copy the code
  • Date type parameter

    Custom type converters are required and configured for date parameters.

    Custom type converter

    public class DateConverter implements Converter<String.Date> {
         @Override
         public Date convert(String source) {
             // Complete the conversion from string to date (according to the transfer date format)
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            try {
             Date parse = simpleDateFormat.parse(source);
             return parse;
            } catch (ParseException e) {
             e.printStackTrace();
            }
             return null; }}Copy the code

    Register custom type converters

    <! < MVC :annotation-driven ConversionService ="conversionServiceBean"/> <! <bean id="conversionServiceBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.lagou.edu.converter.DateConverter"> </bean> </set> </property> </bean>Copy the code

Support for Restfu style requests

  • Deep understanding of Rest style

    Restful is a web software architecture style. It is neither a standard nor a protocol. It advocates a style of resource positioning and resource manipulation. What IS REST: REST (Representational State Transfer) describes an architectural style of network system, such as a Web application. It first appeared in 2000 in the doctoral dissertation of Roy Fielding, one of the main authors of the HTTP specification. Among the three main Web service interaction schemes, REST is more straightforward than SOAP (Simple Object Access Protocol) and XML-RPC. REST tends to be designed and implemented in simpler and lighter ways, whether it is handling urls or encoding payloads. It is important to note that REST does not have a clear standard, but is more of a design style. It itself is not practical, its core value lies in how to design a network interface in line with the REST style. The advantages of resource presentation layer state transfer Restful it is clear structure, standards, easy to understand, easy to expand, so it is being used by more and more websites. Restful Resources: An entity or specific piece of information on a network. It can be a text, a picture, a song, a service, or a concrete presence. You can point to it with a URI (uniform resource locator), and each resource has a specific URI. To get the resource, access its URI, so the URI is a unique identifier for each resource. Representations: The Representation of a resource is called its Representation. For example, text can be represented in TXT format, HTML format, XML format, JSON format, and even binary format. State Transfer: Each request represents an interaction between the client and the server. HTTP is a stateless protocol, that is, all states are stored on the server side. Therefore, if the client wants to manipulate the server, it must somehow make a State Transfer happen on the server side. This transformation is based on the presentation layer, so it is the “presentation layer state transformation”. To be specific, there are four verbs in the HTTP protocol that denote operation modes: GET, POST, PUT, and DELETE. They correspond to four basic operations: GET to obtain resources, POST to create resources, PUT to update resources, and DELETE to DELETE resources.

  • SpringMVC support for REST-style requests

    RESTful URL: All things on the Internet are resources. The URL must contain only the name of the resource and no verb. RESTful resource operations: Use method methods in HTTP requests to operate resources: PUT, Delete, POST, and GET. Should be added, deleted, modified, query. But generally post and GET are used. Put and DELETE are rarely used. RESTful resource representation: You can return different representations (that is, data types, such as XML or JSON) for the URL located resources as required. Spring MVC supports RESTful requests by using the @pathVariable annotation to retrieve path variables in RESTful request urls.

    The METHOD attribute in HTML can only be set to GET and POST. Therefore, you need to provide a name= “_method” parameter to configure PUT DELETE. And configure request mode filters in web.xml to convert specific POST requests to PUT and DELETE requests

    <! The springMVC request mode conversion filter will check whether the request parameter has _method parameter. If so, convert as requested --> <filter> <filter-name>hiddenHttpMethodFilter</filter-name> <filterclass>org.springframework.web.filter.HiddenHttpMethodFilter</filterclass> </filter> <filter-mapping> <filter-name>hiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>Copy the code
        /* * restful put /demo/handle/15/lisi */
        @RequestMapping(value = "/handle/{id}/{name}",method = {RequestMethod.PUT})
        public ModelAndView handlePut(@PathVariable("id") Integer id,@PathVariable("name") String username) {
    
            Date date = new Date();
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("date",date);
            modelAndView.setViewName("success");
            return modelAndView;
        }
    
    
        /* * restful delete /demo/handle/15 */
        @RequestMapping(value = "/handle/{id}",method = {RequestMethod.DELETE})
        public ModelAndView handleDelete(@PathVariable("id") Integer id) {
    
            Date date = new Date();
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("date",date);
            modelAndView.setViewName("success");
            return modelAndView;
        }
    
    Copy the code

Ajax Json interaction

Json is a language-independent format for data interaction. It is just a string with special symbols {} for objects, [] for groups of numbers, “” for attributes or values, and: for values of the former

Interaction: two directions 1) front-end to back-end: Front-end Ajax sends jSON-formatted strings and back-end receives poJO parameters directly, using annotations @RequstBody 2) back-end to front-end: The poJO object is returned directly from the background, and the json object or string is received directly from the front end, using the @responseBody annotation

  • @RequestBody

    It must be POST, and the JSON string sent by the front-end Ajax is stored in the requestBody

  • @ResposeBody

    The @responseBody annotation converts the object returned by the Controller method to the specified format through the appropriate converter and writes it to the body of the Response object, usually to return JSON data or XML data. Note: Using this annotation does not go through the view processor, but writes data directly to the input stream, which has the same effect as writing data in the specified format through the Response object

SpringMVC advanced technology

The use of Interceptor

Javaweb consists of servlets, filters, and listeners. Interceptor is implemented by SpringMVC, Struts, etc.

  • Comparison of listeners, filters, and interceptors

    • Servlet: Handles Request requests and Response responses

    • Filter: filters Request requests before servlets. If /* is set to Filter all resource access (servlets, JS/CSS static resources, etc.). For example, set an encoding filter for POST requests

    • Listener (the Listener) : has realized the javax.mail servlet. ServletContextListener interface server-side components, it along with the start of the Web application starts, initialized only once, and then will have been running monitoring, along with the stop of Web application.

      Part one: to do some initialization, the spring container to start the ContextLoaderListener role in web application 2: listen to a specific event in the web, such as the HttpSession ServletRequest creation and destruction; Creation, destruction, and modification of variables. You can add processing before and after certain actions to monitor the number of online users, for example, using HttpSessionLisener.

  • A single interceptor executes the process

    First let’s take a look at the source code:

    	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {...// Determine handler adapter for the current request.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); .//preHandle
    
    				if(! mappedHandler.applyPreHandle(processedRequest, response)) {return;
    				}
    
    				// Actually invoke the handler.
    				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
    				if (asyncManager.isConcurrentHandlingStarted()) {
    					return;
    				}
    
    				applyDefaultViewName(processedRequest, mv);
          			  //PostHandle
    				mappedHandler.applyPostHandle(processedRequest, response, mv);
    			}
    			catch(Exception ex) { dispatchException = ex; }...// triggerAfterCompletion is called in this method
                	processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    	
    	}
    Copy the code

    When running a program, interceptors are executed in a sequence that is related to the order in which interceptors are defined in the configuration file. The execution flow of a single interceptor in the program is shown below:

1) The program executes the preHandle() method first. If this method returns true, the program continues to execute the methods in the processor, otherwise it does not. 2) After the request is processed by the business processor (i.e. the Controller class), the postHandle() method is executed and the response is returned to the client via the DispatcherServlet. 3) afterCompletion() method is executed after the DispatcherServlet processes the request

  • Multiple interceptors execute the process

    Multiple interceptors (assuming that there are two interceptors Interceptor1 and Interceptor2, and that Interceptor1 comes first in the configuration file). The execution flow of the program is as follows:

As you can see from the figure, when there are multiple interceptors working at the same time, their preHandle() methods are executed in the configuration order of the interceptors in the configuration file, while their postHandle() and afterCompletion() methods are executed in reverse order.

Custom SpringMVC interceptor

/** * Custom SpringMVC interceptor */ public class MyIntercepter01 implements HandlerInterceptor {/** implements HandlerInterceptor before the handler method business logic is executed @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyIntercepter01 preHandle......" ); return true; } @param request @param Response @param handler @param modelAndView encapsulates the view and data. I haven't jumped to the page yet, Throws Exception */ @override public void postHandle(HttpServletRequest Request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("MyIntercepter01 postHandle......" ); * @param Request * @param Response * @param handler * @param ex Can catch exceptions * @throws Exception */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("MyIntercepter01 afterCompletion......" ); }}Copy the code

Handling multipart data (file upload)

Native servlets handle uploaded file data, which springMVC encapsulates

  • multipartResolver

    To configure multipartResolver, the id must be a fixed multipartResolver. (Default Settings)

    The required jars

    <! -- Jar coordinates required for file upload -->
    <dependency>
     <groupId>commons-fileupload</groupId>
     <artifactId>commons-fileupload</artifactId>
     <version>1.3.1</version>
    </dependency>
    Copy the code

    The front Form

    The < % -1 method="post"
     2 enctype="multipart/form-data"
     3 type="file"
    --%>
    <form method="post" enctype="multipart/form-data" action="/demo/upload">
     <input type="file" name="uploadFile"/>
     <input type="submit" value="Upload"/>
    </form>
    Copy the code

    Background Receiving Handler

    @RequestMapping("upload")
    public String upload(MultipartFile uploadFile, HttpServletRequest request)
    throws IOException {
     // The name of the file, such as xxx.jpg
     String originalFilename = uploadFile.getOriginalFilename();
     // Get the extension of the file, such as JPG
     String extendName =
    originalFilename.substring(originalFilename.lastIndexOf(".") + 1,
    originalFilename.length());
     String uuid = UUID.randomUUID().toString();
     // The new file name
     String newName = uuid + "." + extendName;
     String realPath =
    request.getSession().getServletContext().getRealPath("/uploads");
     // Save files by date
     String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
     File floder = new File(realPath + "/" + datePath);
     if(! floder.exists()) { floder.mkdirs(); } uploadFile.transferTo(new File(floder,newName));
     return "success";
    }
    Copy the code

Handle exceptions in the controller

  • @ControllerAdvice

  • @ExcecptionHandler

    // Allows us to gracefully catch all exceptions thrown by the Controller object handler method
    @ControllerAdvice
    public class GlobalExceptionResolver {
    
    
        @ExceptionHandler(Exception.class)
        public void handleException(Exception exception, HttpServletResponse response) {
    		// Exception handling logic
            System.out.println(exception.getMessage());
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("msg",exception.getMessage());
            modelAndView.setViewName("error");
            returnmodelAndView; }}Copy the code

    Written separately in Controller only applies to the current Controller

    @Controller
    public class Controller01 {
    
    
        @ExceptionHandler(Exception.class)
        public void handleException(Exception exception, HttpServletResponse response) {
    		// Exception handling logic
            System.out.println(exception.getMessage());
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("msg",exception.getMessage());
            modelAndView.setViewName("error");
            returnmodelAndView; }}Copy the code

Cross-redirect request data transfer based on Flash attributes

The request parameters will be lost during redirection, and we often need to re-carry the request parameters. We can perform manual parameter stitching as follows:

return "redirect:handle01? name=" + name;

However, the above method of splicing parameters is a GET request, which has limited parameter length and low parameter security. At this time, we can use the Flash attribute mechanism provided by SpringMVC to add flash attribute to the context, and the framework will record the attribute value in the session. When jumping to the page, the frame will automatically delete the Flash attribute, which does not need to be manually deleted. In this way, the parameter length and security are guaranteed as follows:

@RequestMapping("/handleRedirect")
     public String handleRedirect(String name,RedirectAttributes redirectAttributes) {
     //return "redirect:handle01? name=" + name; // Both the security and length of the splicing parameters are availablelimited// The addFlashAttribute method sets a flash-type attribute that is temporarily stored in the sessionJump to the page after the property destroyed redirectAttributes. AddFlashAttribute ("name",name);
     return "redirect:handle01";
 }
Copy the code

SpringMVC source code analysis

DispatcherServlet inheritance structure

General process for processing requests

  • doDispatch

    DispacherServlet#doDispathchs is the core method to handle the request flow.

    The SpringMVC process for handling requests is as follows:

    Org. Springframework. Web. Servlet. DispatcherServlet# doDispatch method execution process, 1) Call getHandler() to get the HandlerExecutionChain (Handler+ interceptor) that can handle the current request. 2) Call getHandlerAdapter(); 3) The adapter calls the Handler to execute ha.handle (always returns a ModelAndView object). 4) Calls the processDispatchResult() method to complete the view rendering jump

    protected void doDispatch(HttpServletRequest request, HttpServletResponse
    response) throws Exception {
     HttpServletRequest processedRequest = request;
     HandlerExecutionChain mappedHandler = null;
     boolean multipartRequestParsed = false;
     WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
     try {
         ModelAndView mv = null;
         Exception dispatchException = null;
         try {
         // 1 Check whether it is a file upload requestprocessedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest ! = request);// Determine handler for the current request.
         /* 2 gets the Controller that handles the current request, which is also called Handler, so instead of returning Controller directly, Instead, it returns the HandlerExecutionChain request Handler object that encapsulates Handler and Inteceptor */
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
         // If handler is empty, 404 is returned
         noHandlerFound(processedRequest, response);
         return;
         }
         // Determine handler adapter for the current request.
         // 3 Get the HandlerAdapter that handles the request
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
         // Process last-modified header, if supported by the handler.
         // Process the last-Modified request header
         String method = request.getMethod();
         boolean isGet = "GET".equals(method);
         if (isGet || "HEAD".equals(method)) {
         long lastModified = ha.getLastModified(request,
            mappedHandler.getHandler());
             if (new ServletWebRequest(request,
            response).checkNotModified(lastModified) && isGet) {
             return; }}if(! mappedHandler.applyPreHandle(processedRequest, response)) {return;
             }
             // Actually invoke the handler.
             // 4 The actual handler processes the request and returns the result view object
             mv = ha.handle(processedRequest, response,
            mappedHandler.getHandler());
             if (asyncManager.isConcurrentHandlingStarted()) {
             return;
             }
             // Result view object processing
             applyDefaultViewName(processedRequest, mv);
             mappedHandler.applyPostHandle(processedRequest, response, mv);
             }
             catch (Exception ex) {
             dispatchException = ex;
             }
             catch (Throwable err) {
             // As of 4.3, we're processing Errors thrown from handler methods
            as well,
             // making them available for @ExceptionHandler methods and other
            scenarios.
             dispatchException = new NestedServletException("Handler dispatch failed", err);
             }
             // 5 Jump to page and render the view
             processDispatchResult(processedRequest, response, mappedHandler, mv,
            dispatchException);
             }
             catch (Exception ex) {
             // The afterCompletion method of the HandlerInterceptor will eventually be called
             triggerAfterCompletion(processedRequest, response, mappedHandler,
            ex);
             }
             catch (Throwable err) {
             // The afterCompletion method of the HandlerInterceptor will eventually be called
             triggerAfterCompletion(processedRequest, response, mappedHandler,
             new NestedServletException("Handler processing failed", err));
             }
             finally {
             if (asyncManager.isConcurrentHandlingStarted()) {
             // Instead of postHandle and afterCompletion
             if(mappedHandler ! =null) {
    			// The afterCompletion method of the HandlerInterceptor will eventually be calledmappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); }}else {
             // Clean up any resources used by a multipart request.
             if(multipartRequestParsed) { cleanupMultipart(processedRequest); }}}}Copy the code

GetHandler method

org.springframework.web.servlet.DispatcherServlet#getHandler

	/**
	 * Return the HandlerExecutionChain for this request.
	 * <p>Tries all handler mappings in order.
	 * @param request current HTTP request
	 * @return the HandlerExecutionChain, or {@code null} if no handler could be found
	 */
	@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings ! =null) {
			for (HandlerMapping mapping : this.handlerMappings) {
                // Iterate through all HandlerMapping
                / / BeanNameUrlHandlerMapping and RequestMappingHandlerMapping
				HandlerExecutionChain handler = mapping.getHandler(request);
				if(handler ! =null) {
					returnhandler; }}}return null;
	}
Copy the code

Continue to call org. Springframework. Web. Servlet. Handler. AbstractHandlerMapping# getHandlerExecutionChain

	/**
	 * Build a {@link HandlerExecutionChain} for the given handler, including
	 * applicable interceptors.
	 * <p>The default implementation builds a standard {@link HandlerExecutionChain}
	 * with the given handler, the handler mapping's common interceptors, and any
	 * {@link MappedInterceptor MappedInterceptors} matching to the current request URL. Interceptors
	 * are added in the order they were registered. Subclasses may override this
	 * in order to extend/rearrange the list of interceptors.
	 * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a
	 * pre-built {@link HandlerExecutionChain}. This method should handle those
	 * two cases explicitly, either building a new {@link HandlerExecutionChain}
	 * or extending the existing chain.
	 * <p>For simply adding an interceptor in a custom subclass, consider calling
	 * {@code super.getHandlerExecutionChain(handler, request)} and invoking
	 * {@link HandlerExecutionChain#addInterceptor} on the returned chain object.
	 * @param handler the resolved handler instance (never {@code null})
	 * @param request current HTTP request
	 * @return the HandlerExecutionChain (never {@code null})
	 * @see #getAdaptedInterceptors()
	 */
	protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); }}else{ chain.addInterceptor(interceptor); }}return chain;
	}
Copy the code

org.springframework.web.servlet.HandlerExecutionChain

/**
 * Handler execution chain, consisting of handler object and any handler interceptors.
 * Returned by HandlerMapping's {@link HandlerMapping#getHandler} method.
 *
 * @author Juergen Hoeller
 * @since 20.06.2003
 * @see HandlerInterceptor
 */
public class HandlerExecutionChain {

	private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);

	private final Object handler;

	@Nullable
	private HandlerInterceptor[] interceptors;

	@Nullable
	private List<HandlerInterceptor> interceptorList;

	private int interceptorIndex = -1; .Copy the code

getHandlerAdapter

	/**
	 * Return the HandlerAdapter for this handler object.
	 * @param handler the handler object to find an adapter for
	 * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
	 */
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters ! =null) {
            / / traverse handlerAdapter
			for (HandlerAdapter adapter : this.handlerAdapters) {
                The supports method is judged by type
				if (adapter.supports(handler)) {
					returnadapter; }}}throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}
Copy the code

org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports

	/**
	 * This implementation expects the handler to be an {@link HandlerMethod}.
	 * @param handler the handler instance to check
	 * @return whether or not this adapter can adapt the given handler
	 */
	@Override
	public final boolean supports(Object handler) {
		return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
	}
Copy the code

Handler method execution details

1. Enter the Handle method first

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
Copy the code

2.RequestMappingHandlerAdapter#handleInternal

	@Override
	protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ModelAndView mav;
		checkRequest(request);

		// Execute invokeHandlerMethod in synchronized block if required.
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if(session ! =null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized(mutex) { mav = invokeHandlerMethod(request, response, handlerMethod); }}else {
				// No HttpSession available -> no mutex necessarymav = invokeHandlerMethod(request, response, handlerMethod); }}else {
			// No synchronization on session demanded at all...
            // If no session synchronization is required, the thief calls this method
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		if(! response.containsHeader(HEADER_CACHE_CONTROL)) {if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else{ prepareResponse(response); }}return mav;
	}
Copy the code

3.RequestMappingHandlerAdapter#invokeHandlerMethod

	/**
	 * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
	 * if view resolution is required.
	 * @since 4.2
	 * @see #createInvocableHandlerMethod(HandlerMethod)
	 */
	@Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
            // Do some data binding before calling methods, return values, handlers
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			if (this.argumentResolvers ! =null) {
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
			if (this.returnValueHandlers ! =null) {
				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			}
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

			AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
			asyncWebRequest.setTimeout(this.asyncRequestTimeout);

			WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
			asyncManager.setTaskExecutor(this.taskExecutor);
			asyncManager.setAsyncWebRequest(asyncWebRequest);
			asyncManager.registerCallableInterceptors(this.callableInterceptors);
			asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

			if (asyncManager.hasConcurrentResult()) {
				Object result = asyncManager.getConcurrentResult();
				mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0]; asyncManager.clearConcurrentResult(); LogFormatUtils.traceDebug(logger, traceOn -> { String formatted = LogFormatUtils.formatValue(result, ! traceOn);return "Resume with async result [" + formatted + "]";
				});
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}
			// Call handler
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}
			// Get a mv return from mavContainer modelFactory webRequest
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally{ webRequest.requestCompleted(); }}Copy the code

4.org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle

	/**
	 * Invoke the method and handle the return value through one of the
	 * configured {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers}.
	 * @param webRequest the current request
	 * @param mavContainer the ModelAndViewContainer for this request
	 * @param providedArgs "given" arguments matched by type (not resolved)
	 */
	public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
		// make the call
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		setResponseStatus(webRequest);

		if (returnValue == null) {
			if(isRequestNotModified(webRequest) || getResponseStatus() ! =null || mavContainer.isRequestHandled()) {
				disableContentCachingIfNecessary(webRequest);
				mavContainer.setRequestHandled(true);
				return; }}else if (StringUtils.hasText(getResponseStatusReason())) {
			mavContainer.setRequestHandled(true);
			return;
		}

		mavContainer.setRequestHandled(false);
		Assert.state(this.returnValueHandlers ! =null."No return value handlers");
		try {
			this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
		catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(formatErrorForReturnValue(returnValue), ex);
			}
			throwex; }}Copy the code

5.org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest

	/**
	 * Invoke the method after resolving its argument values in the context of the given request.
	 * <p>Argument values are commonly resolved through
	 * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
	 * The {@code providedArgs} parameter however may supply argument values to be used directly,
	 * i.e. without argument resolution. Examples of provided argument values include a
	 * {@link WebDataBinder}, a {@link SessionStatus}, or a thrown exception instance.
	 * Provided argument values are checked before argument resolvers.
	 * <p>Delegates to {@link #getMethodArgumentValues} and calls {@link #doInvoke} with the
	 * resolved arguments.
	 * @param request the current request
	 * @param mavContainer the ModelAndViewContainer for this request
	 * @param providedArgs "given" arguments matched by type, not resolved
	 * @return the raw value returned by the invoked method
	 * @throws Exception raised if no suitable argument resolver can be found,
	 * or if the method raised an exception
	 * @see #getMethodArgumentValues
	 * @see #doInvoke
	 */
	@Nullable
	public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Arguments: " + Arrays.toString(args));
		}
		return doInvoke(args);
	}
Copy the code

6. org.springframework.web.method.support.invocablehandlermethod#doinvoke by reflecting the real call

	/** * Invoke the handler method with the given argument values. */
	@Nullable
	protected Object doInvoke(Object... args) throws Exception {
		ReflectionUtils.makeAccessible(getBridgedMethod());
		try {
            // reflection calls
			return getBridgedMethod().invoke(getBean(), args);
		}
		catch(IllegalArgumentException ex) { assertTargetBean(getBridgedMethod(), getBean(), args); String text = (ex.getMessage() ! =null ? ex.getMessage() : "Illegal argument");
			throw new IllegalStateException(formatInvokeError(text, args), ex);
		}
		catch (InvocationTargetException ex) {
			// Unwrap for HandlerExceptionResolvers ...
			Throwable targetException = ex.getTargetException();
			if (targetException instanceof RuntimeException) {
				throw (RuntimeException) targetException;
			}
			else if (targetException instanceof Error) {
				throw (Error) targetException;
			}
			else if (targetException instanceof Exception) {
				throw (Exception) targetException;
			}
			else {
				throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); }}}}Copy the code

Jump to page, render view

1. Call org. Springframework. Web. Servlet. DispatcherServlet# processDispatchResult method

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

2. First determine whether an exception occurs and generate an abnormal ModelAndView, and then render MV

	/** * Handle the result of handler selection and handler invocation, which is * either a ModelAndView or an Exception to be resolved to a ModelAndView. */
	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

		boolean errorView = false;

		if(exception ! =null) {
			if (exception instanceof ModelAndViewDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else{ Object handler = (mappedHandler ! =null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv ! =null); }}// Did the handler return a view to render?
		if(mv ! =null && !mv.wasCleared()) {
            // Render method
			render(mv, request, response);
			if(errorView) { WebUtils.clearErrorRequestAttributes(request); }}else {
			if (logger.isTraceEnabled()) {
				logger.trace("No view rendering, null ModelAndView returned."); }}if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Concurrent handling started during a forward
			return;
		}

		if(mappedHandler ! =null) {
			mappedHandler.triggerAfterCompletion(request, response, null); }}Copy the code

3.org.springframework.web.servlet.DispatcherServlet#render

	/**
	 * Render the given ModelAndView.
	 * <p>This is the last stage in handling a request. It may involve resolving the view by name.
	 * @param mv the ModelAndView to render
	 * @param request current HTTP servlet request
	 * @param response current HTTP servlet response
	 * @throws ServletException if view is missing or cannot be resolved
	 * @throws Exception if there's a problem rendering the view
	 */
	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// Determine locale for request and apply it to the response.
		Locale locale =
				(this.localeResolver ! =null ? this.localeResolver.resolveLocale(request) : request.getLocale());
		response.setLocale(locale);

		View view;
		String viewName = mv.getViewName();
		if(viewName ! =null) {
			// We need to resolve the view name.
            // Parse the View object (In the process of parsing the View object will determine whether to redirect, forward, etc., different cases encapsulate different View implementation. And resolve the logical view name to the physical view name)
			view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
			if (view == null) {
				throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
						"' in servlet with name '" + getServletName() + "'"); }}else {
			// No need to lookup: the ModelAndView object contains the actual View object.
			view = mv.getView();
			if (view == null) {
				throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
						"View object in servlet with name '" + getServletName() + "'"); }}// Delegate to the View object for rendering.
		if (logger.isTraceEnabled()) {
			logger.trace("Rendering view [" + view + "]");
		}
		try {
			if(mv.getStatus() ! =null) {
				response.setStatus(mv.getStatus().value());
			}
            // Delegate the rendering to the view object
			view.render(mv.getModelInternal(), request, response);
		}
		catch (Exception ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Error rendering view [" + view + "]", ex);
			}
			throwex; }}Copy the code

4.org.springframework.web.servlet.view.AbstractView#render

	/**
	 * Prepares the view given the specified model, merging it with static
	 * attributes and a RequestContext attribute, if necessary.
	 * Delegates to renderMergedOutputModel for the actual rendering.
	 * @see #renderMergedOutputModel
	 */
	@Override
	public void render(@NullableMap<String, ? > model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		if (logger.isDebugEnabled()) {
			logger.debug("View " + formatViewName() +
					", model "+ (model ! =null ? model : Collections.emptyMap()) +
					(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
		}

		Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
		prepareResponse(request, response);
        // Render data
		renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
	}
Copy the code

5.org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel

	/** * Render the internal resource given the specified model. * This includes setting the model as request attributes. * /
	@Override
	protected void renderMergedOutputModel( Map
       
         model, HttpServletRequest request, HttpServletResponse response)
       ,> throws Exception {

		// Expose the model object as request attributes.
		exposeModelAsRequestAttributes(model, request);

		// Expose helpers as request attributes, if any.
		exposeHelpers(request);

		// Determine the path for the request dispatcher.
		String dispatcherPath = prepareForRendering(request, response);

		// Obtain a RequestDispatcher for the target resource (typically a JSP).
		RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
		if (rd == null) {
			throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
					"]: Check that the corresponding file exists within your web application archive!");
		}

		// If already included or response already committed, perform include, else forward.
		if (useInclude(request, response)) {
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
				logger.debug("Including [" + getUrl() + "]");
			}
			rd.include(request, response);
		}

		else {
			// Note: The forwarded resource is supposed to determine the content type itself.
			if (logger.isDebugEnabled()) {
				logger.debug("Forwarding to [" + getUrl() + "]");
			}
            // Delegate the distribution object to jump to the page, which is already the underlying objectrd.forward(request, response); }}Copy the code

6. org.springframework.web.servlet.view.abstractview#exposemodelasrequestattributes set data Model objects data to request domain, This will fetch the data in the JSP page

	/**
	 * Expose the model objects in the given map as request attributes.
	 * Names will be taken from the model Map.
	 * This method is suitable for all resources reachable by {@link javax.servlet.RequestDispatcher}.
	 * @param model a Map of model objects to expose
	 * @param request current HTTP request
	 */
	protected void exposeModelAsRequestAttributes(Map
       
         model, HttpServletRequest request)
       ,> throws Exception {

		model.forEach((name, value) -> {
			if(value ! =null) {
				request.setAttribute(name, value);
			}
			else{ request.removeAttribute(name); }}); }Copy the code

Nine components are initialized

  • onRefresh()

    SpirngMVC in org. Springframework. Web. Servlet. DispatcherServlet# onRefresh of nine components of initialization.

    	/**
    	 * This implementation calls {@link #initStrategies}.
    	 */
    	@Override
    	protected void onRefresh(ApplicationContext context) {
    		initStrategies(context);
    	}
    
    	/** * Initialize the strategy objects that this servlet uses. * 

    May be overridden in subclasses in order to initialize further strategy objects. */

    protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); } Copy the code

    By looking at the method call stack

    We found onfresh method is in org. Springframework. Context. Support. AbstractApplicationContext# calls refresh. This method is the primary method for performing container initialization in the Spring framework. The event is published in the finishRefresh() method. To execute the onRefresh method.

    The nine component initialization processes are basically the same. Let’s take initHandlerMappings as an example

    	/** * Initialize the HandlerMappings used by this class. * 

    If no HandlerMapping beans are defined in the BeanFactory for this namespace, * we default to BeanNameUrlHandlerMapping. */

    // If it exists in BeanFactory, use the default if it does not private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true.false); if(! matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<>(matchingBeans.values()); // We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings); }}else { // If you don't need to probe all HandlerMapping, fix ID () to look for it //public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter"; try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later.}}// Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. if (this.handlerMappings == null) { / / by DispatcherServlet. The properties for the default HandlerMapping this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isTraceEnabled()) { logger.trace("No HandlerMappings declared for servlet '" + getServletName() + "': using default strategies from DispatcherServlet.properties"); }}}Copy the code

    DispatcherServlet.properties

    org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
    
    org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
    
    org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
    
    org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
    
    org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
    
    org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
    
    org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
    
    org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
    Copy the code

Integration of SSM

SSM = Spring + Mybatis + Mybatis = (Spring + Mybatis) + Spring + Mybatis

Mybatis integration of Spring

  • The integration target database connection pool and transaction management should be handled by the Spring container and the SqlSessionFactory object should be managed by Spring as a singleton object and the Mapper dynamic proxy object should be handled by Spring, We get the Proxy object for Mapper directly from the Spring container

  • Mybatis Jar (3.4.5) Spring-related JARS (Spring-Context, spring-test, spring-JDBC, spring-tx, spring-AOP, AspectJweaver) Jar (Mybatis -spring-xx.jar) Mysql database driver jar Druid database connection pool JAR

  • Pom coordinates after integration

        <! --junit-->
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
        </dependency>
        <! --mybatis-->
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>3.4.5</version>
        </dependency>
        <! - spring related -- -- >
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>5.1.12. RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-test</artifactId>
          <version>5.1.12. RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>5.1.12. RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-tx</artifactId>
          <version>5.1.12. RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aop</artifactId>
          <version>5.1.12. RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
          <version>1.8.9</version>
        </dependency>
        <! Mybatis with Spring integration package -->
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis-spring</artifactId>
          <version>The 2.0.3</version>
        </dependency>
        <! Database driver jar-->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.46</version>
        </dependency>
        <! --druid connection pool -->
        <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>1.1.21</version>
        </dependency>
    Copy the code
  • Spring configuration file

    applicationContext-dao.xml

    
            
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           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/tx http://www.springframework.org/schema/tx/spring-tx.xsd ">
    
        <! -- Packet scanning -->
        <context:component-scan base-package="com.lagou.edu.mapper"/>
    
    
        <! The database connection pooling and transaction management are left to the Spring container.
    
            <! -- Import external resource file -->
            <context:property-placeholder location="classpath:jdbc.properties"/>
    
            <! A bean in a third-party JAR is defined in XML.
            <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
                <property name="driverClassName" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </bean>
    
    
    
        <! The SqlSessionFactory object should be managed as a singleton object in the Spring container.
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <! -- Alias mapping scan -->
            <property name="typeAliasesPackage" value="com.lagou.edu.pojo"/><! -<! Mapper dynamic proxy object to Spring management, we directly from the Spring container to obtain Mapper proxy object.
            <! -- Scan mapper interface, generate proxy objects, generated proxy objects will be stored in ioc container -->
            <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
                <! -- Mapper package path configuration -->
                <property name="basePackage" value="com.lagou.edu.mapper"/>
                <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
            </bean>--><property name="dataSource" ref="dataSource"/>
        </bean>
    
    
    </beans>
    Copy the code

    applicationContext-service.xml

    
            
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           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/tx http://www.springframework.org/schema/tx/spring-tx.xsd ">
    
        <! -- Packet scanning -->
        <context:component-scan base-package="com.lagou.edu.service"/>
    
    
    
        <! -- Transaction Management -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <! Transaction management annotation-driven -->
        <tx:annotation-driven transaction-manager="transactionManager"/>
    
    
    
    </beans>
    Copy the code

Integration for SpringMVC

  • Introduce POM coordinates

    <! --SpringMVC-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.1.12. RELEASE</version>
        </dependency>
        <! --jsp-api&servlet-api-->
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>jsp-api</artifactId>
          <version>2.0</version>
          <scope>provided</scope>
        </dependency>
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
          <scope>provided</scope>
        </dependency>
        <! -- Page using JSTL expression -->
        <dependency>
          <groupId>jstl</groupId>
          <artifactId>jstl</artifactId>
          <version>1.2</version>
        </dependency>
        <dependency>
          <groupId>taglibs</groupId>
          <artifactId>standard</artifactId>
          <version>1.1.2</version>
        </dependency>
    
        <! -- jar for json data interaction, start-->
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-core</artifactId>
          <version>2.9.0</version>
        </dependency>
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.9.0</version>
        </dependency>
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-annotations</artifactId>
          <version>2.9.0</version>
        </dependency>
        <! -- JAR required for json data interaction, end-->
    Copy the code
  • web.xml

    <! DOCTYPEweb-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
    
    
    
      <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:applicationContext*.xml</param-value>
      </context-param>
      <! -- Spring Framework startup -->
      <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
    
    
      <! - for springmvc start -- >
      <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath*:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>
    
      
      <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
    </web-app>
    Copy the code