一、统一异常处理实现
统一在base基础工程实现统一异常处理,各模块依赖了base基础工程都 可以使用。
首先在base基础工程添加需要依赖的包:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
1、定义一些通用的异常信息
拷贝CommonError枚举类到base工程。
package com.xuecheng.base.execption;
/**
* @description 通用错误信息
* @author Mr.M
* @date 2022/9/6 11:29
* @version 1.0
*/
public enum CommonError {
UNKOWN_ERROR("执行过程异常,请重试。"),
PARAMS_ERROR("非法参数"),
OBJECT_NULL("对象为空"),
QUERY_NULL("查询结果为空"),
REQUEST_NULL("请求参数为空");
private String errMessage;
public String getErrMessage() {
return errMessage;
}
private CommonError( String errMessage) {
this.errMessage = errMessage;
}
}
2、自定义异常类型
package com.xuecheng.base.execption;
/**
* @description 学成在线项目异常类
* @author Mr.M
* @date 2022/9/6 11:29
* @version 1.0
*/
public class XueChengPlusException extends RuntimeException {
private static final long serialVersionUID = 5565760508056698922L;
private String errMessage;
public XueChengPlusException() {
super();
}
public XueChengPlusException(String errMessage) {
super(errMessage);
this.errMessage = errMessage;
}
public String getErrMessage() {
return errMessage;
}
public static void cast(CommonError commonError){
throw new XueChengPlusException(commonError.getErrMessage());
}
public static void cast(String errMessage){
throw new XueChengPlusException(errMessage);
}
}
3、响应用户的统一类型
package com.xuecheng.base.execption;
import java.io.Serializable;
/**
* 错误响应参数包装
*/
public class RestErrorResponse implements Serializable {
private String errMessage;
public RestErrorResponse(String errMessage){
this.errMessage= errMessage;
}
public String getErrMessage() {
return errMessage;
}
public void setErrMessage(String errMessage) {
this.errMessage = errMessage;
}
}
4、全局异常处理器
从 Spring 3.0 - Spring 3.2 版本之间,对 Spring 架构和 SpringMVC 的Controller 的异常捕获提供了相应的异常处理。
-
@ExceptionHandler
Spring3.0提供的标识在方法上或类上的注解,用来表明方法的处理异常类型。
-
@ControllerAdvice
Spring3.2提供的新注解,从名字上可以看出大体意思是控制器增强, 在项目中来增强SpringMVC中的Controller。通常和**
@ExceptionHandler
** 结合使用,来处理SpringMVC的异常信息。 -
@ResponseStatus
Spring3.0提供的标识在方法上或类上的注解,用状态代码和应返回的原因标记方法或异常类。
调用处理程序方法时,状态代码将应用于HTTP响应。
通过上面的两个注解便可实现微服务端全局异常处理,具体代码如下:
package com.xuecheng.base.execption;
import lombok.extern.slf4j.Slf4j;
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.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* @description 全局异常处理器
* @author Mr.M
* @date 2022/9/6 11:29
* @version 1.0
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(XueChengPlusException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public RestErrorResponse customException(XueChengPlusException e) {
log.error("【系统异常】{}",e.getErrMessage(),e);
return new RestErrorResponse(e.getErrMessage());
}
@ResponseBody
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public RestErrorResponse exception(Exception e) {
log.error("【系统异常】{}",e.getMessage(),e);
return new RestErrorResponse(CommonError.UNKOWN_ERROR.getErrMessage());
}
}
二、 异常处理测试
在内容管理的api工程添加base工程的依赖
<dependency>
<groupId>com.xuecheng</groupId>
<artifactId>xuecheng-plus-base</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
在异常处理测试之前首先在代码中抛出自定义类型的异常,这里以新增课程的service方法为例进行代码修改。
@Override
public CourseBaseInfoDto createCourseBase(Long companyId,AddCourseDto dto) {
...
//合法性校验
if (StringUtils.isBlank(dto.getName())) {
throw new XueChengPlusException("课程名称为空");
}
if (StringUtils.isBlank(dto.getMt())) {
throw new XueChengPlusException("课程分类为空");
}
if (StringUtils.isBlank(dto.getSt())) {
throw new XueChengPlusException("课程分类为空");
}
if (StringUtils.isBlank(dto.getGrade())) {
throw new XueChengPlusException("课程等级为空");
}
if (StringUtils.isBlank(dto.getTeachmode())) {
throw new XueChengPlusException("教育模式为空");
}
if (StringUtils.isBlank(dto.getUsers())) {
throw new XueChengPlusException("适应人群");
}
if (StringUtils.isBlank(dto.getCharge())) {
throw new XueChengPlusException("收费规则为空");
}
。。。
if ("201001".equals(charge)) {
BigDecimal price = dto.getPrice();
if (ObjectUtils.isEmpty(price)) {
throw new XueChengPlusException("收费课程价格不能为空");
}
courseMarketNew.setPrice(dto.getPrice().floatValue());
}
。。。
1、首先使用httpclient测试
请求新增课程接口,故意将必填项课程名称设置为空。
测试结果与预期一致,可以捕获异常并响应异常信息,如下:
http://localhost:63040/content/course
HTTP/1.1 500
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 07 Sep 2022 13:17:14 GMT
Connection: close
{
"errMessage": "课程名称为空。"
}
三、面试
1、系统如何处理异常?
我们自定义一个统一的异常处理器去捕获并处理异常。
使用控制器增加注解@ControllerAdvice和异常处理注解@ExceptionHandler来实现。
- 处理自定义异常
程序在编写代码时根据校验结果主动抛出自定义异常类对象,抛出异常时指定详细的异常信息,异常处理器捕获异常信息记录异常日志并响应给用户。
- 处理未知异常
接口执行过程中的一些运行时异常也会由异常处理器统一捕获,记录异常日志,统一响应给用户500错误。
在异常处理器中还可以针对某个异常类型进行单独处理。