Spring boot exception handling in five ways, Junit unit test, hot deployment

First of all, the version of Springboot 2.2.6.release is used here. Since the iteration of Springboot is very fast, pay attention to the version.

1. Exception handling in SpringBoot. There are five ways to handle exceptions in spring boot.

1.1. The first way is to customize the error page.

Spring boot's default exception handling mechanism: spring boot's default has provided a set of exception handling mechanisms. Once there is an exception in the program, SpringBoot will send the request like the url of / error. A basic exception controller is provided in spring boot to handle the / error request, and then jump to the default exception page to display the exception information.

The above interface is the default error interface provided by spring boot. We can modify the interface ourselves. If we need to jump all exceptions to the custom error page, we need to create the error.html page under the src/main/resources/templates directory. Note: the name of the error interface must be error.

Disadvantages: the user-defined error interface handles exceptions, and the granularity of exception information is relatively coarse, which does not conform to the principle of exception handling. Exception handling principle: display the concerned exceptions in one interface, and display the unconcerned exceptions in one interface.

 1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 2         "http://www.w3.org/TR/html4/loose.dtd">
 3 <html xmlns:th="http://www.w3.org/1999/xhtml">
 4 <head>
 5     <title>Error prompt page</title>
 6 </head>
 7 <body>
 8 
 9 There is an error. Please contact the administrator......
10 <!--<span th:text="${exception}"></span>-->
11 
12 </body>
13 </html>

1.2. In the second way, @ ExceptionHandle annotation handles exceptions.

 1 package com.bie.springboothello.controller;
 2 
 3 import org.springframework.stereotype.Controller;
 4 import org.springframework.ui.Model;
 5 import org.springframework.web.bind.annotation.ExceptionHandler;
 6 import org.springframework.web.bind.annotation.RequestMapping;
 7 import org.springframework.web.bind.annotation.ResponseBody;
 8 import org.springframework.web.servlet.ModelAndView;
 9 
10 /**
11  *
12  */
13 @Controller
14 public class DemoController {
15 
16     @RequestMapping(value = "/hello")
17     @ResponseBody
18     public String showUser(Model model) {
19         String str = null;
20         str.length();
21         return "hello";
22     }
23 
24     /**
25      * This method needs to return a ModelAndView, so that we can encapsulate the exception information and the specified parameter Exception e,
26      * The exception generating object is injected into the method.
27      * <p>
28      * <p>
29      * This method can handle arithmetic exception of ArithmeticException. If arithmetic exception is thrown in the program, this method can catch it.
30      * The Exception object Exception will be injected according to the operation defined in the method, so the Exception parameter is required.
31      *
32      * @param e
33      * @return
34      * @ExceptionHandler The value value of the annotation is an exception type that can handle that exception.
35      */
36     @ExceptionHandler(value = {java.lang.ArithmeticException.class})
37     public ModelAndView arithmeticExceptionHandler(Exception e) {
38         ModelAndView modelAndView = new ModelAndView();
39         modelAndView.addObject("error", e.toString());
40         modelAndView.setViewName("error1");
41         return modelAndView;
42     }
43 
44 
45     /**
46      * java.lang.NullPointerException
47      * <p>
48      * <p>
49      * This method needs to return a ModelAndView, so that we can encapsulate the exception information and the specified parameter Exception e of the view:
50      * Will inject the exception generating object into the method
51      *
52      * @param e
53      * @return
54      */
55     @ExceptionHandler(value = {java.lang.NullPointerException.class})
56     public ModelAndView nullPointerExceptionHandler(Exception e) {
57         ModelAndView mv = new ModelAndView();
58         mv.addObject("error", e.toString());
59         mv.setViewName("error2");
60         return mv;
61     }
62 
63 }

Different error prompt interfaces can be defined according to different errors. As follows, error1.html and error2.html are created.

 1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 2         "http://www.w3.org/TR/html4/loose.dtd">
 3 <html xmlns:th="http://www.w3.org/1999/xhtml">
 4 <head>
 5     <title>Error prompt page</title>
 6 </head>
 7 <body>
 8 
 9 java.lang.ArithmeticException There is an error. Please contact the administrator......
10 <span th:text="${error}"></span>
11 
12 </body>
13 </html>
 1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 2         "http://www.w3.org/TR/html4/loose.dtd">
 3 <html xmlns:th="http://www.w3.org/1999/xhtml">
 4 <head>
 5     <title>Error prompt page</title>
 6 </head>
 7 <body>
 8 
 9 java.lang.NullPointerException There is an error. Please contact the administrator......
10 <span th:text="${error}"></span>
11 
12 </body>
13 </html>

Disadvantages: if the Controller needs to handle more exceptions, it will cause redundancy to the code. This method can only handle exceptions of the Controller, not across controllers.

1.3. In the third way, @ ControllerAdvice+@ExceptionHandler annotation handles exceptions.

 1 package com.bie.springboothello.controller;
 2 
 3 import org.springframework.web.bind.annotation.ControllerAdvice;
 4 import org.springframework.web.bind.annotation.ExceptionHandler;
 5 import org.springframework.web.servlet.ModelAndView;
 6 
 7 /**
 8  * Global exception handling class.
 9  * You need to create a global exception class that can handle exceptions. The @ ControllerAdvice annotation needs to be added to this class
10  */
11 @ControllerAdvice // This annotation can realize global exception handling
12 public class GlobalException {
13 
14 
15     /**
16      * java.lang.ArithmeticException. 
17      * <p>
18      * This method needs to return a ModelAndView, so that we can encapsulate the exception information and the specified parameters of the view
19      * Exception e:The exception generating object is injected into the method.
20      *
21      * @param e
22      * @return
23      */
24     @ExceptionHandler(value = {java.lang.ArithmeticException.class})
25     public ModelAndView arithmeticExceptionHandler(Exception e) {
26         ModelAndView mv = new ModelAndView();
27         mv.addObject("error", e.toString());
28         mv.setViewName("error1");
29         return mv;
30     }
31 
32 
33     /**
34      * java.lang.NullPointerException. 
35      * <p>
36      * This method needs to return a ModelAndView: the purpose is to let us encapsulate the exception information and the specified parameters of the view
37      * Exception e:The exception generating object is injected into the method.
38      *
39      * @param e
40      * @return
41      */
42     @ExceptionHandler(value = {java.lang.NullPointerException.class})
43     public ModelAndView nullPointerExceptionHandler(Exception e) {
44         ModelAndView mv = new ModelAndView();
45         mv.addObject("error", e.toString());
46         mv.setViewName("error2");
47         return mv;
48     }
49 
50 }

Different error prompt interfaces can be defined according to different errors. As follows, error1.html and error2.html are created. The error interface error1.htm and error2.html created above are directly used here.

1.4. The fourth way is to configure SimpleMappingExceptionResolver to handle exceptions. This handling method is a simplification of the third handling exception.

 1 package com.bie.springboothello.controller;
 2 
 3 
 4 import org.springframework.context.annotation.Bean;
 5 import org.springframework.context.annotation.Configuration;
 6 import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
 7 
 8 import java.util.Properties;
 9 
10 /**
11  * Global exception handling through SimpleMappingExceptionResolver
12  */
13 @Configuration
14 public class GlobalException {
15 
16     @Bean
17     public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver() {
18         SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
19         Properties mappings = new Properties();
20         // Parameter 1: the type of exception. Note that it must be the full name of the exception type
21         // Parameter 2: view name
22         mappings.put("java.lang.ArithmeticException", "error1");
23         mappings.put("java.lang.NullPointerException", "error2");
24         // Set exception and view mapping information
25         resolver.setExceptionMappings(mappings);
26         return resolver;
27     }
28 
29 
30 }

Different error prompt interfaces can be defined according to different errors. As follows, error1.html and error2.html are created. The error interface error1.htm and error2.html created above are directly used here.

Disadvantage: compared with the third method, it can't transfer exception object information, just jump to the specified exception error interface.

1.5. The fifth way is to customize HandlerExceptionResolver class to handle exceptions. The HandlerExceptionResolver interface needs to be implemented in the global exception handling class.

 1 package com.bie.springboothello.controller;
 2 
 3 
 4 import org.springframework.context.annotation.Configuration;
 5 import org.springframework.web.servlet.HandlerExceptionResolver;
 6 import org.springframework.web.servlet.ModelAndView;
 7 
 8 import javax.servlet.http.HttpServletRequest;
 9 import javax.servlet.http.HttpServletResponse;
10 
11 /**
12  * Global exception handling through the implementation of HandlerExceptionResolver interface
13  */
14 @Configuration
15 public class GlobalException implements HandlerExceptionResolver {
16 
17     @Override
18     public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
19         ModelAndView mv = new ModelAndView();
20         // Judge different types of exceptions and jump to different views
21         if (ex instanceof ArithmeticException) {
22             mv.setViewName("error1");
23         }
24         if (ex instanceof NullPointerException) {
25             mv.setViewName("error2");
26         }
27         mv.addObject("error", ex.toString());
28         return mv;
29     }
30 
31 
32 }

Different error prompt interfaces can be defined according to different errors. As follows, error1.html and error2.html are created. The error interface error1.htm and error2.html created above are directly used here.

 

2. Spring Boot integrates junit unit tests. Add junit's startup class dependency package to the pom.xml configuration file.

 1 <!-- add to junit Environmental jar package -->
 2 <dependency>
 3     <groupId>org.springframework.boot</groupId>
 4     <artifactId>spring-boot-starter-test</artifactId>
 5     <scope>test</scope>
 6     <!--<exclusions>
 7         <exclusion>
 8             <groupId>org.junit.vintage</groupId>
 9             <artifactId>junit-vintage-engine</artifactId>
10         </exclusion>
11     </exclusions>-->
12 </dependency>

Spring Boot integrates Junit unit test, and the code is as follows:

 1 package com.bie.springboothello;
 2 
 3 import com.bie.springboothello.po.Users;
 4 import com.bie.springboothello.service.UsersService;
 5 import org.junit.jupiter.api.Test;
 6 import org.junit.runner.RunWith;
 7 import org.springframework.beans.factory.annotation.Autowired;
 8 import org.springframework.boot.test.context.SpringBootTest;
 9 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
10 
11 /**
12  * Springboot Test class.
13  *
14  * @RunWith:Starter. Spring junit 4classrunner. Class: let junit integrate with the spring environment.
15  * @SpringBootTest(classes={SpringbootHelloApplication.class}) In the first layer, the current class is a test class of springBoot.
16  * @SpringBootTest(classes={SpringbootHelloApplication.class}) In the second layer, load the springboot startup class. Start springboot.
17  * <p>
18  * junit Integrate @ contextconfiguration ("classpath: ApplicationContext. XML") with spring
19  */
20 @RunWith(value = SpringJUnit4ClassRunner.class)
21 @SpringBootTest(classes = {SpringbootHelloApplication.class})
22 class SpringbootHelloApplicationTests {
23 
24     @Autowired
25     private UsersService usersService;
26 
27     @Test
28     public void testAddUser() {
29         System.out.println("start---------------------------------------------");
30         this.usersService.addUser(new Users("No, sir", 25));
31         System.out.println("end---------------------------------------------");
32     }
33 
34 }

 

3. Spring Boot hot deployment. The hot deployment of Spring Boot is to complete the deployment processing of the project without stopping the service. It means that you can see the effect immediately after modifying the system, and you don't need to restart the project.

There are two hot deployment methods of SprigBoot: the first is the spring loader plug-in and the second is the DevTools tool.

Make complaints about love eclipse and idea, I prefer eclipse to eclipse, because eclipse is free, ha ha ha, idea charges, although you can buy or find a solution, but I love eclipse, though idea is a really good source of springboot, eclipse also integrates the plug-in created by springboot, but it is built into It also needs simple configuration, otherwise pom.xml always reports errors, which is also very unpleasant. Another case is just like this. If idea wants to run the project in maven mode, it may not be familiar with idea itself. Well, this case is replaced by eclipse creation and hot deployment practice.

3.1. Mode 1: use spring loader in maven plug-in mode. Add plug-in configuration in POM file. The springloader plug-in is added to the pom.xml configuration file to import the plug-in's dependency package into maven.

 1 <!-- springloader plug-in unit -->
 2 <build>
 3     <plugins>
 4         <plugin>
 5             <groupId>org.springframework.boot</groupId>
 6             <artifactId>spring-boot-maven-plugin</artifactId>
 7             <dependencies>
 8                 <dependency>
 9                     <groupId>org.springframework</groupId>
10                     <artifactId>springloaded</artifactId>
11                     <version>1.2.5.RELEASE</version>
12                 </dependency>
13             </dependencies>
14         </plugin>
15     </plugins>
16 </build>

The complete pom.xml configuration file is as follows:

Note: the initial use is Springboot2.2.7.RELEASE Version, it can't be modified in the background. The hot deployment starts. It's changed to 1.5.10.RELEASE I don't think I will use this method to implement hot deployment.

 1 <project xmlns="http://maven.apache.org/POM/4.0.0"
 2     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
 4     http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6     <parent>
 7         <groupId>org.springframework.boot</groupId>
 8         <artifactId>spring-boot-starter-parent</artifactId>
 9         <!-- Due to the hot deployment of learning, it was replaced by eclipse establish springboot Project, this case uses springboot1.5.10.RELEASE edition -->
10         <version>1.5.10.RELEASE</version>
11     </parent>
12     <groupId>com.bie.springboot</groupId>
13     <artifactId>springboot-world</artifactId>
14     <version>0.0.1-SNAPSHOT</version>
15 
16 
17     <properties>
18         <java.version>1.8</java.version>
19         <!-- solve eclipse use springboot Plug in creation springboot project pom.xml Configuration file error -->
20         <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
21         <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
22         <thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
23     </properties>
24 
25     <dependencies>
26         <dependency>
27             <groupId>org.springframework.boot</groupId>
28             <artifactId>spring-boot-starter-web</artifactId>
29         </dependency>
30 
31         <!-- thymeleaf Starter for -->
32         <dependency>
33             <groupId>org.springframework.boot</groupId>
34             <artifactId>spring-boot-starter-thymeleaf</artifactId>
35         </dependency>
36 
37     </dependencies>
38 
39     <!-- springloader plug-in unit -->
40     <build>
41         <plugins>
42             <plugin>
43                 <groupId>org.springframework.boot</groupId>
44                 <artifactId>spring-boot-maven-plugin</artifactId>
45                 <dependencies>
46                     <dependency>
47                         <groupId>org.springframework</groupId>
48                         <artifactId>springloaded</artifactId>
49                         <version>1.2.5.RELEASE</version>
50                     </dependency>
51                 </dependencies>
52             </plugin>
53         </plugins>
54     </build>
55 
56 </project>

Note: if the command of Maven is used to start, if the main method is still used to start, the plug-in is not used. Therefore, the hot deployment effect can only be achieved by using the command of maven, but this plug-in can only be modified in the background without starting, and the front-end html can't be hot deployed if it is modified.

Using maven's command spring-boot:run To start the project.

The defect of spring loader plug-in is that Java code is deployed, but it can't help the page.  

The effect is as follows:

Note: the disadvantage of this method is that the spring loader hot deployer runs as a process in the background of the system, which needs to be closed manually. Well, I don't want to choose this way to do hot deployment.

View process and end process command under Windows. View the process number that occupies port 8080.

netstat -aon | findstr "8080"

It can be seen that the process with process number 10968 occupies port 8080. You can use the command tasklist | findstr "10968" to further view the specific information of 10968 process. It can be seen that the 10968 process is javaw.exe .  

tasklist | findstr "10968"

Kill the process, tskill 10968.

If the display 'tskill' is not an internal or external command, or a runnable program or batch file. Then use task manager to find pid to end the process.

Or directly use the jar package in the project, add the jar package of springloader, and add the jar package of springloader under the lib directory of the project. Then use maven's command to start at startup.

Start command:- javaagent:.\lib\springloaded-1.2.5.RELEASE.jar -noverify

Three point one , method 2: use the devtools tool to modify the pom.xml Configuration files add dependencies for devtools.

Note: the difference between spring loader and DevTools:

1) Spring loader: spring loader uses the hot deployment method when deploying projects.

2) DevTools: DevTools uses the method of redeployment when deploying a project.

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 4     <modelVersion>4.0.0</modelVersion>
 5     <parent>
 6         <groupId>org.springframework.boot</groupId>
 7         <artifactId>spring-boot-starter-parent</artifactId>
 8         <version>2.2.6.RELEASE</version>
 9         <relativePath/> <!-- lookup parent from repository -->
10     </parent>
11     <groupId>com.bie</groupId>
12     <artifactId>springboot-hello</artifactId>
13     <version>0.0.1-SNAPSHOT</version>
14     <name>springboot-hello</name>
15     <description>Demo project for Spring Boot</description>
16 
17     <properties>
18         <java.version>1.8</java.version>
19     </properties>
20 
21     <dependencies>
22         <dependency>
23             <groupId>org.springframework.boot</groupId>
24             <artifactId>spring-boot-starter-web</artifactId>
25         </dependency>
26         <!-- add to junit Environmental jar package -->
27         <dependency>
28             <groupId>org.springframework.boot</groupId>
29             <artifactId>spring-boot-starter-test</artifactId>
30             <scope>test</scope>
31             <!--<exclusions>
32                 <exclusion>
33                     <groupId>org.junit.vintage</groupId>
34                     <artifactId>junit-vintage-engine</artifactId>
35                 </exclusion>
36             </exclusions>-->
37         </dependency>
38         <!-- thymeleaf Starter for -->
39         <dependency>
40             <groupId>org.springframework.boot</groupId>
41             <artifactId>spring-boot-starter-thymeleaf</artifactId>
42         </dependency>
43         <!-- mybatis Starter for -->
44         <dependency>
45             <groupId>org.mybatis.spring.boot</groupId>
46             <artifactId>mybatis-spring-boot-starter</artifactId>
47             <version>2.1.1</version>
48         </dependency>
49         <!-- mysql Database driven dependency package -->
50         <dependency>
51             <groupId>mysql</groupId>
52             <artifactId>mysql-connector-java</artifactId>
53         </dependency>
54         <!-- druid Database connection pool -->
55         <dependency>
56             <groupId>com.alibaba</groupId>
57             <artifactId>druid</artifactId>
58             <version>1.1.10</version>
59         </dependency>
60         <dependency>
61             <groupId>junit</groupId>
62             <artifactId>junit</artifactId>
63             <scope>test</scope>
64         </dependency>
65         <!-- DevTools Coordinates of -->
66         <dependency>
67             <groupId>org.springframework.boot</groupId>
68             <artifactId>spring-boot-devtools</artifactId>
69             <!-- Indicates that the current dependency is not passed down -->
70             <optional>true</optional>
71         </dependency>
72     </dependencies>
73 
74     <build>
75         <plugins>
76             <plugin>
77                 <groupId>org.springframework.boot</groupId>
78                 <artifactId>spring-boot-maven-plugin</artifactId>
79             </plugin>
80         </plugins>
81         <!-- This configuration can be resolved if*.mapper.xml Profile put into src/main/java,Unable to load mybatis Problems with mapping files -->
82         <!--<resources>
83             <resource>
84                 <directory>src/main/java</directory>
85                 <includes>
86                     <include>**/*.xml</include>
87                 </includes>
88             </resource>
89         </resources>-->
90     </build>
91 
92 
93 </project>

If idea can realize hot deployment as usual, it may be the configuration problem of idea, DevTools and Loader. Intellij IEDA and eclipse are different. Eclipse generally sets automatic compilation, and idea needs to be opened by itself.

Find Build Project Automatically in setting - > build, execution, deployment - > compiler. This option is open by default in Eclipse, and open manually in IDEA.

Then find a place ctrl+shift+alt + / to call up the maintenance console and select registry.

Check auto making when app running. Just restart Idea.

After restart, hot deployment can be realized by modifying the front-end or the back-end. If the back-end is modified, the Idea console will be redeployed. If the front-end interface is modified, it will not be redeployed, but it has also been refreshed. It greatly saves time and energy.

Tags: Spring Java Maven SpringBoot

Posted on Sun, 17 May 2020 03:00:32 -0400 by naomi385