前言

今天在使用@ControllerAdvice进行统一异常处理类时,没有起作用。先贴一下异常处理类的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

package com.fxt.common.exception;
@Slf4j
//此处使用新的注解,相当于@ControllerAdvice和@@ResponseBody 结合体。
@RestControllerAdvice
public class GlobalExceptionAdvice {

/**
* 校验失败异常处理
* @param e 异常类
* @return com.fxt.common.utils.R
* @author fuxintong
* @date 2021/1/26 15:58
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R validHander(MethodArgumentNotValidException e){
log.error("异常信息{},异常类:{}",e.getMessage(),e.getClass());
BindingResult result = e.getBindingResult();
Map<String,Object> resMap = new HashMap<>(10);
if (result.hasErrors()) {
result.getFieldErrors().forEach(fieldError -> {
resMap.put("字段:"+fieldError.getField(),"异常:"+fieldError.getDefaultMessage());
});
}
return R.error(ExceptionCodeEnum.VAILID.getCode(),ExceptionCodeEnum.VAILID.getMessage()).put("data",resMap);
}
}

过程

在发现统一异常处理类不起作用后,开始寻找原因,一开始以为是@RestControllerAdvice注解的使用方法不对造成的,但百度了一波发现,并没有任何问题。

因为我的异常处理类是单独放在了公共服务中common下,所以我将这个异常处理类,放到业务服务下进行测试。使用==Postman==进行测试返回如下

返回样例

根据结果来看,放在业务服务下,异常处理类好用的,但放在公共服务时却不好用,当时就很疑惑

就在我疑惑中瞎点代码时候,有个重大发现 如下图:

以上两图比对,会发现画红框的地方异常处理类的地方缺少一个小图标,那个图标意思是 该类注册到了Spring 容器中;使用 @Component将类中注册到Spring 容器后的就会出现这个小图标。因为 SpringBoot 本身在启动类上会使用 @SpringBootApplication 进行标注这是个启动类,并且会扫描启动类所在路径下的所有组件信息。@SpringBootApplication 源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration

// 此处就是扫描启动类路径下的所有 组件。
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
@AliasFor(
annotation = EnableAutoConfiguration.class
)
Class<?>[] exclude() default {};
}

发现以上问题后,查找我的项目发现,我的统一异常处理类所在路径业务服务启动类所在的路径不同,导致当业务服务启动时没有扫描到,统一异常类才会出现 @RestControllerAdvice的不起作用;路径如下图

解决

两种方法解决:

  • 将统一异常处理类的层级改成跟业务服务一样,都改成com.fxt.mall.xxxxx(推荐此方法)
  • 在启动类上定义扫描包的路径
1
2
3
4
5
6
7
8
9
10
11
12
//此处写上要扫描包的路径
@SpringBootApplication(scanBasePackages = {"com.fxt.mall","com.fxt.common"})
@MapperScan("com.fxt.mall.product.dao")
@EnableDiscoveryClient
@EnableFeignClients
public class SmallMallProductApplication {

public static void main(String[] args) {
SpringApplication.run(SmallMallProductApplication.class, args);
}

}

一个在码农道路上孤独行走的人

微信搜索【Java猿记】