前言
今天在使用@ControllerAdvice
进行统一异常处理类时, 没有起作用。先贴一下异常处理类的代码
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 源码如下:
@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
(推荐此方法) - 在启动类上定义扫描包的路径
//此处写上要扫描包的路径
@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 猿记】