предисловие
В этой статье в основном представлен проект SpringBoot для глобальной обработки исключений.
Подготовка глобального исключения SpringBoot
Примечание. Если вы хотите получить проект напрямую, вы можете сразу перейти к нижней части и загрузить код проекта по ссылке.
подготовка к разработке
Требования к окружающей среде JDK: 1,8SpringBoot: 1.5.17.РЕЛИЗ
Прежде всего, связанные зависимости Maven:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.17.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<!-- Spring Boot Web 依赖 核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Test 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.41</version>
</dependency>
</dependencies>
Конфигурационный файл в принципе менять не нужно, а обработку глобальных исключений нужно только реализовать в коде.
написание кода
Проект SpringBoot уже обрабатывал определенные исключения, но он может не подойти нам, разработчикам, поэтому нам необходимо единообразно перехватывать и обрабатывать эти исключения. В SpringBoot есть одинControllerAdvice
Аннотация, используйте эту аннотацию, чтобы указать, что захват глобальных исключений включен, нам нужно использовать ее только в пользовательском методе.ExceptionHandler
Аннотируйте, а затем определите тип захваченных исключений для единообразной обработки этих захваченных исключений.
Давайте посмотрим, как используется аннотация, согласно следующему примеру.
Образец кода:
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(value =Exception.class)
public String exceptionHandler(Exception e){
System.out.println("未知异常!原因是:"+e);
return e.getMessage();
}
}
В приведенном выше примере мы выполняем простую вторичную обработку захваченного исключения и возвращаем информацию об исключении.Хотя это позволяет нам узнать причину исключения, во многих случаях это может быть недостаточно удобным для человека, чтобы удовлетворить наши потребности. . Затем мы можем получить данные, которые нам нужны, с помощью пользовательских классов исключений и классов перечисления.
Пользовательский базовый класс интерфейса
Сначала определите базовый класс интерфейса, а пользовательский класс перечисления описания ошибки должен реализовать этот интерфейс.код показывает, как показано ниже:
public interface BaseErrorInfoInterface {
/** 错误码*/
String getResultCode();
/** 错误描述*/
String getResultMsg();
}
пользовательский класс перечисления
Затем мы настраиваем здесь класс перечисления и реализуем интерфейс.код показывает, как показано ниже:
public enum CommonEnum implements BaseErrorInfoInterface {
// 数据操作错误定义
SUCCESS("200", "成功!"),
BODY_NOT_MATCH("400","请求的数据格式不符!"),
SIGNATURE_NOT_MATCH("401","请求的数字签名不匹配!"),
NOT_FOUND("404", "未找到该资源!"),
INTERNAL_SERVER_ERROR("500", "服务器内部错误!"),
SERVER_BUSY("503","服务器正忙,请稍后再试!")
;
/** 错误码 */
private String resultCode;
/** 错误描述 */
private String resultMsg;
CommonEnum(String resultCode, String resultMsg) {
this.resultCode = resultCode;
this.resultMsg = resultMsg;
}
@Override
public String getResultCode() {
return resultCode;
}
@Override
public String getResultMsg() {
return resultMsg;
}
}
пользовательский класс исключений
Затем мы определяем класс исключений для обработки наших бизнес-исключений.код показывает, как показано ниже:
public class BizException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
protected String errorCode;
/**
* 错误信息
*/
protected String errorMsg;
public BizException() {
super();
}
public BizException(BaseErrorInfoInterface errorInfoInterface) {
super(errorInfoInterface.getResultCode());
this.errorCode = errorInfoInterface.getResultCode();
this.errorMsg = errorInfoInterface.getResultMsg();
}
public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
super(errorInfoInterface.getResultCode(), cause);
this.errorCode = errorInfoInterface.getResultCode();
this.errorMsg = errorInfoInterface.getResultMsg();
}
public BizException(String errorMsg) {
super(errorMsg);
this.errorMsg = errorMsg;
}
public BizException(String errorCode, String errorMsg) {
super(errorCode);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public BizException(String errorCode, String errorMsg, Throwable cause) {
super(errorCode, cause);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public String getMessage() {
return errorMsg;
}
@Override
public Throwable fillInStackTrace() {
return this;
}
}
пользовательский формат данных
Кстати, здесь мы определяем формат передачи данных.код показывает, как показано ниже:
public class ResultBody {
/**
* 响应代码
*/
private String code;
/**
* 响应消息
*/
private String message;
/**
* 响应结果
*/
private Object result;
public ResultBody() {
}
public ResultBody(BaseErrorInfoInterface errorInfo) {
this.code = errorInfo.getResultCode();
this.message = errorInfo.getResultMsg();
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
/**
* 成功
*
* @return
*/
public static ResultBody success() {
return success(null);
}
/**
* 成功
* @param data
* @return
*/
public static ResultBody success(Object data) {
ResultBody rb = new ResultBody();
rb.setCode(CommonEnum.SUCCESS.getResultCode());
rb.setMessage(CommonEnum.SUCCESS.getResultMsg());
rb.setResult(data);
return rb;
}
/**
* 失败
*/
public static ResultBody error(BaseErrorInfoInterface errorInfo) {
ResultBody rb = new ResultBody();
rb.setCode(errorInfo.getResultCode());
rb.setMessage(errorInfo.getResultMsg());
rb.setResult(null);
return rb;
}
/**
* 失败
*/
public static ResultBody error(String code, String message) {
ResultBody rb = new ResultBody();
rb.setCode(code);
rb.setMessage(message);
rb.setResult(null);
return rb;
}
/**
* 失败
*/
public static ResultBody error( String message) {
ResultBody rb = new ResultBody();
rb.setCode("-1");
rb.setMessage(message);
rb.setResult(null);
return rb;
}
@Override
public String toString() {
return JSONObject.toJSONString(this);
}
}
Пользовательский глобальный класс обработки исключений
Наконец, мы пишем собственный глобальный класс обработки исключений.код показывает, как показано ниже:
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 处理自定义的业务异常
* @param req
* @param e
* @return
*/
@ExceptionHandler(value = BizException.class)
@ResponseBody
public ResultBody bizExceptionHandler(HttpServletRequest req, BizException e){
logger.error("发生业务异常!原因是:{}",e.getErrorMsg());
return ResultBody.error(e.getErrorCode(),e.getErrorMsg());
}
/**
* 处理空指针的异常
* @param req
* @param e
* @return
*/
@ExceptionHandler(value =NullPointerException.class)
@ResponseBody
public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e){
logger.error("发生空指针异常!原因是:",e);
return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
}
/**
* 处理其他异常
* @param req
* @param e
* @return
*/
@ExceptionHandler(value =Exception.class)
@ResponseBody
public ResultBody exceptionHandler(HttpServletRequest req, Exception e){
logger.error("未知异常!原因是:",e);
return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
}
}
Потому что здесь мы используем только для функциональной реализации и тестирования глобальной обработки исключений, поэтому здесь нам нужно только добавить класс сущности и класс уровня управления.
класс сущности
Еще одна универсальная пользовательская таблица (^▽^)
код показывает, как показано ниже:
public class User implements Serializable{
private static final long serialVersionUID = 1L;
/** 编号 */
private int id;
/** 姓名 */
private String name;
/** 年龄 */
private int age;
public User(){
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return JSONObject.toJSONString(this);
}
}
Уровень управления контроллером
Слой управления также относительно прост, используется CRUD-функция, реализованная в стиле Restful, разница в том, что я намеренно сделал некоторые исключения, чтобы эти исключения можно было отловить и обработать. Среди этих исключений есть настраиваемые исключения, исключения нулевого указателя и, конечно же, непредсказуемые исключения (здесь вместо этого я использую исключения преобразования типов), затем давайте посмотрим на эти исключения после того, как мы закончим писать код. Можно ли их захватить и обработать. успешно!
код показывает, как показано ниже:
@RestController
@RequestMapping(value = "/api")
public class UserRestController {
@PostMapping("/user")
public boolean insert(@RequestBody User user) {
System.out.println("开始新增...");
//如果姓名为空就手动抛出一个自定义的异常!
if(user.getName()==null){
throw new BizException("-1","用户姓名不能为空!");
}
return true;
}
@PutMapping("/user")
public boolean update(@RequestBody User user) {
System.out.println("开始更新...");
//这里故意造成一个空指针的异常,并且不进行处理
String str=null;
str.equals("111");
return true;
}
@DeleteMapping("/user")
public boolean delete(@RequestBody User user) {
System.out.println("开始删除...");
//这里故意造成一个异常,并且不进行处理
Integer.parseInt("abc123");
return true;
}
@GetMapping("/user")
public List<User> findByUser(User user) {
System.out.println("开始查询...");
List<User> userList =new ArrayList<>();
User user2=new User();
user2.setId(1L);
user2.setName("xuwujing");
user2.setAge(18);
userList.add(user2);
return userList;
}
}
Запись приложения
Это в основном то же самое, что и обычный проект SpringBoot.
код показывает, как показано ниже:
@SpringBootApplication
public class App
{
public static void main( String[] args )
{
SpringApplication.run(App.class, args);
System.out.println("程序正在运行...");
}
}
функциональный тест
После того, как мы успешно запустили программу, мы используем инструмент Postman для тестирования интерфейса.
Сначала сделайте запрос, чтобы узнать, работает ли программа нормально или нет, и используйте метод GET, чтобы сделать запрос.
Возвращаемый параметр:
{"id":1,"name":"xuwujing","age":18}
пример графика:
Видно, что программа возвращается нормально и на нее не влияет пользовательское глобальное исключение.Затем мы проверим, может ли пользовательское исключение быть правильно перехвачено и обработано.
Сделать запрос методом POST
Параметры кузова:
{"id":1,"age":18}
Возвращаемый параметр:
{"code":"-1","message":"Имя пользователя не может быть пустым!","result":null}
пример графика:
Видно, что выбрасываемое нами исключение инкапсулируется в данные, а затем возвращается исключение.Затем мы проверим, можно ли правильно перехватить и обработать исключение нулевого указателя. В пользовательском глобальном исключении, в дополнение к определению обработки исключений нулевых указателей, мы также определяем один из самых высоких уровней исключений Exception.После того, как здесь возникает исключение нулевого указателя, какой из них используется первым? Вот и тестируем.
Используйте метод PUT, чтобы сделать запрос.
Параметры кузова:
{"id":1,"age":18}
Возвращаемый параметр:
{"code":"400","message":"Запрошенный формат данных не соответствует!","result":null}
пример графика:
Мы видим, что именно обработка исключений действительно возвращает нулевой указатель, и можно сделать вывод, что глобальная обработка исключений отдает приоритет исключениям подклассов.Затем давайте попробуем обработать неуказанные исключения, чтобы увидеть, можно ли их перехватить.
Используйте метод DELETE, чтобы сделать запрос.
Параметры кузова:
{"id":1}
Возвращаемый параметр:
{"code":"500","message":"Внутренняя ошибка сервера!","result":null}
Здесь вы можете видеть, что он использует метод обработки исключений Exception в нашем пользовательском глобальном классе обработки исключений.
На этом испытание закончено. Кстати, в дополнение к вышеуказанному формату данных, пользовательская глобальная обработка исключений также может обрабатывать переходы по страницам, просто заполните путь перехода в обработке возврата вновь добавленного метода исключения и не используйте его.ResponseBody
Просто аннотируйте. Внимательные одноклассники могут обнаружить, что вGlobalExceptionHandler
Используемый классControllerAdvice
аннотации, неRestControllerAdvice
Аннотация, если используетсяRestControllerAdvice
аннотации, он автоматически преобразует данные в формат JSON, который используется вController
а такжеRestController
Аналогично, поэтому мы можем выбрать гибкую обработку после использования глобальной обработки исключений.
разное
Статья об элегантной глобальной обработке исключений SpringBoot объясняется здесь Если что-то не так, поправьте меня!
адрес проекта
Адрес проекта глобальной обработки исключений SpringBoot:GitHub.com/nihilty/tickets…
Адрес всей коллекции SpringBoot:GitHub.com/nihilty/tickets…
Статьи из серии SpringBoot Integration
-
Чтение конфигурационных файлов SpringBoot и использование фильтров и перехватчиков
-
SpringBoot+Mybatis+Druid+PageHelper реализует несколько источников данных и пейджинг
-
SpringBoot интегрирует ElasticSearch для обеспечения совместимости с несколькими версиями.
-
SpringBoot интегрирует Netty и использует Protobuf для передачи данных.
-
SpringBoot интегрирует Redis и использует стиль Restful для реализации функций CRUD.
музыкальная рекомендация
Оригинал не просто, если вы чувствуете себя хорошо, я надеюсь дать рекомендацию! Ваша поддержка - самая большая мотивация для моего письма! Уведомление об авторских правах: Автор: ничтожество Источник блога сада:www.cnblogs.com/xuwujingИсточник CSDN:blog.csdn.net/qazwsxpcm Источник личного блога:www.panchengming.com