--Catch exceptions qui se produisent dans la classe de contrôleur dans l'application Spring Boot -Dans la classe avec @ControllerAdvice, attraper chaque classe d'exception avec la méthode avec @ExceptionHandler
├── pom.xml
└── src
└── main
├── java
│ └── com
│ └── example
│ └── my
│ ├── MyApplication.java
│ ├── MyController.java
│ ├── MyControllerAdvice.java
│ ├── MyException.java
│ └── MyHandlerExceptionResolver.java
└── resources
└── templates
└── myview.html
MyApplication.java
Classe de démarrage Spring Boot.
package com.example.my;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
MyException.java
Une classe d'exception simple préparée pour ce contrôle d'opération.
package com.example.my;
public class MyException extends Exception {
}
MyController.java
Une classe de contrôleur qui gère le routage. Déclenchez une exception MyException lors de l'accès à http: // localhost: 8080 / myexception. Soulevez une exception d'exception lorsque l'accès à http: // localhost: 8080 / exception arrive.
package com.example.my;
import org.springframework.boot.SpringApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class MyController {
public static void main(String[] args) {
SpringApplication.run(MyController.class, args);
}
@RequestMapping("/")
public ModelAndView handleTop(ModelAndView mav) {
mav.addObject("mymessage", "Hello, world.");
mav.setViewName("myview");
return mav;
}
@RequestMapping("/myexception")
public ModelAndView handleMyException(ModelAndView mav) throws MyException {
throw new MyException();
}
@RequestMapping("/exception")
public ModelAndView handleException(ModelAndView mav) throws Exception {
throw new Exception();
}
}
MyControllerAdvice.java
MyException Une classe pour intercepter les exceptions. Annotez la classe avec @ControllerAdvice. L'annotation @ExceptionHandler est ajoutée à la méthode pour intercepter l'exception et MyException.class est spécifié. Référence: [ExceptionHandler \ (Spring Framework 5 \ .1 \ .9 \ .RELEASE API )](https://docs.spring.io/spring/docs/5.1.9.RELEASE/javadoc-api/org/springframework /web/bind/annotation/ExceptionHandler.html)
package com.example.my;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class MyControllerAdvice {
@ExceptionHandler({MyException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ModelAndView handleMyException(Exception e, WebRequest req) {
System.out.println("MyControllerAdvice#handleMyException");
ModelAndView mav = new ModelAndView();
mav.addObject("myerror", "MyControllerAdvice#handleMyException");
mav.setViewName("myview");
return mav;
}
}
MyHandlerExceptionResolver.java
Une classe pour intercepter les exceptions que @ExceptionHandler ne gère pas. Implémente l'interface HandlerExceptionResolver. Ajoutez l'annotation @Component à la classe pour l'enregistrer dans le conteneur DI en tant que bean. Référence: [HandlerExceptionResolver \ (Spring Framework 5 \ .1 \ .9 \ .RELEASE API )](https://docs.spring.io/spring/docs/5.1.9.RELEASE/javadoc-api/org/springframework /web/servlet/HandlerExceptionResolver.html)
package com.example.my;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("MyHandlerExceptionResolver#resolveException");
System.out.println(handler.getClass());
System.out.println(handler);
ModelAndView mav = new ModelAndView();
mav.addObject("myerror", "MyHandlerExceptionResolver#resolveException");
mav.setViewName("myview");
mav.setStatus(HttpStatus.INTERNAL_SERVER_ERROR);
return mav;
}
}
myview.html
Fichier modèle Thymeleaf pour la sortie HTML. Affichez des informations telles que des erreurs.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:if="${myerror}">
<div>Error: <span th:text="${myerror}"></span></div>
</div>
<div th:if="${mymessage}">
<div>Message: <span th:text="${mymessage}"></span></div>
</div>
</body>
</html>
pom.xml
Fichier de configuration pour la construction avec Maven.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>my</artifactId>
<version>0.0.1</version>
<name>my</name>
<description>My project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Générez un fichier JAR avec la commande mvn package de Maven.
$ mvn package
Spécifiez le fichier JAR généré et démarrez le serveur Web par Spring Boot avec la commande java.
$ java -jar target/my-0.0.1.jar
http://localhost:8080/myexception
Accès avec curl. Vous pouvez voir qu'il est géré par la méthode handleMyException de la classe MyControllerAdvice.
$ curl http://localhost:8080/myexception
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<div>Error: <span>MyControllerAdvice#handleMyException</span></div>
</div>
</body>
</html>
Sortie côté Spring Boot Server.
MyControllerAdvice#handleMyException
Accès avec curl. Vous pouvez voir qu'il est géré par la méthode resolverException de la classe MyHandlerExceptionResolver.
$ curl http://localhost:8080/exception
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<div>Error: <span>MyHandlerExceptionResolver#resolveException</span></div>
</div>
</body>
</html>
Sortie côté Spring Boot Server.
MyHandlerExceptionResolver#resolveException
class org.springframework.web.method.HandlerMethod
public org.springframework.web.servlet.ModelAndView com.example.my.MyController.handleException(org.springframework.web.servlet.ModelAndView) throws java.lang.Exception
La classe DispatcherServlet gère plusieurs objets HandlerExceptionResolver.
La classe ExceptionHandlerExceptionResolver, la classe ResponseStatusExceptionResolver, la classe DefaultHandlerExceptionResolver sont préparées et ces classes gèrent les exceptions avec leurs rôles respectifs.
Parmi eux, la classe ExceptionHandlerExceptionResolver est en train d'appeler la méthode avec l'annotation @ExceptionHandler.
DispatcherServlet (Spring Framework 5.1.9.RELEASE API)
The dispatcher's exception resolution strategy can be specified via a HandlerExceptionResolver, for example mapping certain exceptions to error pages. Default are ExceptionHandlerExceptionResolver, ResponseStatusExceptionResolver, and DefaultHandlerExceptionResolver. These HandlerExceptionResolvers can be overridden through the application context. HandlerExceptionResolver can be given any bean name (they are tested by type).
Affichez le code source de la classe Spring Web MVC DispatcherServlet.
spring-framework/DispatcherServlet.java at v5.1.9.RELEASE · spring-projects/spring-framework
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {
// Success and error responses may use different content types
request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
// Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
if (this.handlerExceptionResolvers != null) {
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
exMv = resolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
}
Dans la méthode processHandlerException, l'objet HandlerExceptionResolver est acquis un par un à partir de this.handlerExceptionResolvers et la méthode resolException est appelée. La méthode resolException de chaque objet gère l'exception et renvoie un objet ModelAndView.
Jetons un coup d'œil à l'objet en cours de traitement par le débogueur IntelliJ IDEA.
Vous pouvez voir que l'objet HandlerExceptionResolverComposite gère les ExceptionHandlerExceptionResolver, ResponseStatusExceptionResolver et DefaultHandlerExceptionResolver.
L'objet ExceptionHandlerExceptionResolver a une variable d'instance appelée exceptionHandlerAdviceCache, qui contient un objet de la classe annoté avec @ControllerAdvice.
Si vous regardez le code source de ExceptionHandlerExceptionResolver, vous pouvez voir qu'il est inscrit dans exceptionHandlerAdviceCache.
private void initExceptionHandlerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
AnnotationAwareOrderComparator.sort(adviceBeans);
for (ControllerAdviceBean adviceBean : adviceBeans) {
Class<?> beanType = adviceBean.getBeanType();
if (beanType == null) {
throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
}
ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
if (resolver.hasExceptionMappings()) {
this.exceptionHandlerAdviceCache.put(adviceBean, resolver);
}
if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
this.responseBodyAdvice.add(adviceBean);
}
}
private void detectAnnotationExceptionMappings(Method method, List<Class<? extends Throwable>> result) {
ExceptionHandler ann = AnnotatedElementUtils.findMergedAnnotation(method, ExceptionHandler.class);
Assert.state(ann != null, "No ExceptionHandler annotation");
result.addAll(Arrays.asList(ann.value()));
}
Recommended Posts