介绍
在项目开发中,如果每个 Controller 都增加 try catch 方法去捕获异常及处理,就会导致代码变得很繁琐、效率低下,而大部分异常是不能直接向外抛出,需要有个统一的显示处理方法,因此需要加上全局异常捕获统一获取并进行异常处理,而不会因为一个异常的抛出导致程序的报错或者崩溃。
通常会将各种类型的异常处理过程进行解耦,保证业务逻辑单一,相关异常处理单一。对异常信息的返回进行封装,保证错误信息对用户的友好性,避免将异常、错误直接抛出给用户。
对比
对比未添加全局异常捕获和添加全局异常捕获后的区别。
添加一个 Post 方法,用浏览器去访问。
UserController.java
package com.lm.system.controller;
import com.lm.system.common.ResultBody;
import com.lm.system.common.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: DuHaoLin
* @Date: 2024/7/26
*/
@Slf4j
@RestController
@Api(tags = "用户接口")
public class UserController {
@GetMapping("user")
@ApiOperation("获取用户信息")
public String user() {
User user = User.builder()
.name("Tom")
.age(18)
.gender(0)
.build();
return ResultBody
.build(HttpStatus.OK)
.setData(user)
.setCount(1)
.getReturn();
}
@GetMapping("addUser")
@ApiOperation("添加用户信息")
public String addUser(@RequestBody User user) {
log.info("user: {}", user);
return ResultBody
.build(HttpStatus.OK)
.getReturn();
}
}
添加全局异常捕获前
添加全局异常捕获后
添加全局异常捕获前,返回的错误信息看着很乱,错误原因看起来不够清晰;添加全局异常捕获后,返回的错误信息很清晰,简单易懂,便于前端开发及用户查看。
代码实现
在 system 目录下,新建一个 handler 目录,在 handler 目录下,新建一个 GlobalExceptionHandler 类。
GlobalExceptionHandler.java
package com.lm.system.handler;
import com.lm.system.common.ResultBody;
import com.lm.system.exception.DataBaseException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
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 javax.servlet.http.HttpServletRequest;
/**
* @Author: DuHaoLin
* @Date: 2024/7/27
*/
@Slf4j
@ResponseBody
@ControllerAdvice
public class GlobalExceptionHandler {
public GlobalExceptionHandler() {}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({HttpMessageNotReadableException.class})
public String handleHttpMessageNotReadableException(Exception e, HttpServletRequest request) {
log.error("400-参数解析失败,{},{}", e.getMessage(), request.getServletPath());
e.printStackTrace();
return ResultBody
.build(HttpStatus.BAD_REQUEST)
.setMsg("参数解析失败")
.getReturn();
}
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
@ExceptionHandler({HttpRequestMethodNotSupportedException.class})
public String handleHttpRequestMethodNotSupportedException(Exception e, HttpServletRequest request) {
log.error("405-不支持当前请求方法,{},{}", e.getMessage(), request.getServletPath());
e.printStackTrace();
return ResultBody
.build(HttpStatus.METHOD_NOT_ALLOWED)
.setMsg("不支持当前请求方法")
.getReturn();
}
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
@ExceptionHandler({HttpMediaTypeNotSupportedException.class})
public String handleHttpMediaTypeNotSupportedException(Exception e, HttpServletRequest request) {
log.error("415-不支持当前媒体类型,{},{}", e.getMessage(), request.getServletPath());
e.printStackTrace();
return ResultBody
.build(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
.setMsg("不支持当前媒体类型")
.getReturn();
}
@ExceptionHandler({DataBaseException.class})
public String handleDataBaseException(Exception e, HttpServletRequest request) {
log.error("500-数据库操作失败,{},{}", e.getMessage(), request.getServletPath());
e.printStackTrace();
return ResultBody
.build(HttpStatus.INTERNAL_SERVER_ERROR)
.setMsg("数据库操作失败")
.getReturn();
}
@ExceptionHandler({Exception.class})
public String handleException(Exception e, HttpServletRequest request) {
log.error("500-系统内部错误,{},{}", e.getMessage(), request.getServletPath());
e.printStackTrace();
return ResultBody
.build(HttpStatus.INTERNAL_SERVER_ERROR)
.setMsg("系统内部错误")
.getReturn();
}
}