Spring Boot 全局异常处理
程序员文章站
2022-05-22 09:42:21
...
@ControllerAdvice源码
package org.springframework.web.bind.annotation;
import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<?>[] assignableTypes() default {};
Class<? extends Annotation>[] annotations() default {};
}
源码分析
@ ControllerAdvice是一个@ Component,
用于定义@ ExceptionHandler的,@InitBinder和@ModelAttribute方法,适用于所有使用@ RequestMapping方法,并处理所有@ RequestMapping标注方法出现异常的统一处理。
项目图片
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jege.spring.boot</groupId>
<artifactId>spring-boot-controller-advice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-controller-advice</name>
<url>http://maven.apache.org</url>
<!-- 公共spring-boot配置,下面依赖jar文件不用在写版本号 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 持久层 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- h2内存数据库 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<!-- 只在test测试里面运行 -->
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>spring-boot-controller-advice</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
全局异常处理类CommonExceptionAdvice
package com.jege.spring.boot.exception;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import com.jege.spring.boot.json.AjaxResult;
/**
* 全局异常处理
*/
@ControllerAdvice
@ResponseBody
public class CommonExceptionAdvice {
private static Logger logger = LoggerFactory.getLogger(CommonExceptionAdvice.class);
/**
* 400 - Bad Request
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MissingServletRequestParameterException.class)
public AjaxResult handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
logger.error("缺少请求参数", e);
return new AjaxResult().failure("required_parameter_is_not_present");
}
/**
* 400 - Bad Request
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMessageNotReadableException.class)
public AjaxResult handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
logger.error("参数解析失败", e);
return new AjaxResult().failure("could_not_read_json");
}
/**
* 400 - Bad Request
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public AjaxResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
logger.error("参数验证失败", e);
BindingResult result = e.getBindingResult();
FieldError error = result.getFieldError();
String field = error.getField();
String code = error.getDefaultMessage();
String message = String.format("%s:%s", field, code);
return new AjaxResult().failure(message);
}
/**
* 400 - Bad Request
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(BindException.class)
public AjaxResult handleBindException(BindException e) {
logger.error("参数绑定失败", e);
BindingResult result = e.getBindingResult();
FieldError error = result.getFieldError();
String field = error.getField();
String code = error.getDefaultMessage();
String message = String.format("%s:%s", field, code);
return new AjaxResult().failure(message);
}
/**
* 400 - Bad Request
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(ConstraintViolationException.class)
public AjaxResult handleServiceException(ConstraintViolationException e) {
logger.error("参数验证失败", e);
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
ConstraintViolation<?> violation = violations.iterator().next();
String message = violation.getMessage();
return new AjaxResult().failure("parameter:" + message);
}
/**
* 400 - Bad Request
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(ValidationException.class)
public AjaxResult handleValidationException(ValidationException e) {
logger.error("参数验证失败", e);
return new AjaxResult().failure("validation_exception");
}
/**
* 405 - Method Not Allowed
*/
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public AjaxResult handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
logger.error("不支持当前请求方法", e);
return new AjaxResult().failure("request_method_not_supported");
}
/**
* 415 - Unsupported Media Type
*/
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public AjaxResult handleHttpMediaTypeNotSupportedException(Exception e) {
logger.error("不支持当前媒体类型", e);
return new AjaxResult().failure("content_type_not_supported");
}
/**
* 500 - Internal Server Error
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(ServiceException.class)
public AjaxResult handleServiceException(ServiceException e) {
logger.error("业务逻辑异常", e);
return new AjaxResult().failure("业务逻辑异常:" + e.getMessage());
}
/**
* 500 - Internal Server Error
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public AjaxResult handleException(Exception e) {
logger.error("通用异常", e);
return new AjaxResult().failure("通用异常:" + e.getMessage());
}
/**
* 操作数据库出现异常:名称重复,外键关联
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(DataIntegrityViolationException.class)
public AjaxResult handleException(DataIntegrityViolationException e) {
logger.error("操作数据库出现异常:", e);
return new AjaxResult().failure("操作数据库出现异常:字段重复、有外键关联等");
}
}
自定义异常ServiceException
package com.jege.spring.boot.exception;
/**
* 自定义异常类
*/
public class ServiceException extends RuntimeException {
public ServiceException(String msg) {
super(msg);
}
}
不需要application.properties##
控制器AdviceController
package com.jege.spring.boot.controller;
import java.util.List;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.jege.spring.boot.exception.ServiceException;
/**
* 全局异常处理演示入口
*/
@RestController
public class AdviceController {
@RequestMapping("/hello1")
public String hello1() {
int i = 1 / 0;
return "hello";
}
@RequestMapping("/hello2")
public String hello2(Long id) {
String string = null;
string.length();
return "hello";
}
@RequestMapping("/hello3")
public List<String> hello3() {
throw new ServiceException("test");
}
}
进行访问
http://localhost:8080/hello1
{"meta":{"success":false,"message":"通用异常:/ by zero"},"data":null}
http://localhost:8080/hello2
{"meta":{"success":false,"message":"通用异常:null"},"data":null}
http://localhost:8080/hello3
{"meta":{"success":false,"message":"业务逻辑异常:test"},"data":null}
扫一扫关注我哟!!!