preface

It doesn’t work today when using @ControllerAdvice for a unified exception handling class. First post the code for the exception handling class


package com.fxt.common.exception;
@Slf4j
// The new annotation used here is equivalent to a combination of @controllerAdvice and @@responseBody.
@RestControllerAdvice
public class GlobalExceptionAdvice {

    /** * Check failure exception processing *@paramE Exception class *@return  com.fxt.common.utils.R
     * @author  fuxintong
     * @date2021/1/26 therefore * /
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R validHander(MethodArgumentNotValidException e){
        log.error("Exception information {}, exception class: {}",e.getMessage(),e.getClass());
        BindingResult result = e.getBindingResult();
        Map<String,Object> resMap = new HashMap<>(10);
        if (result.hasErrors()) {
            result.getFieldErrors().forEach(fieldError -> {
                resMap.put("Field."+fieldError.getField(),"Exception:"+fieldError.getDefaultMessage());
            });
        }
        return R.error(ExceptionCodeEnum.VAILID.getCode(),ExceptionCodeEnum.VAILID.getMessage()).put("data",resMap); }}Copy the code

process

After discovering that the unified exception handling class didn’t work, I started to look for the reason. At first, I thought it was because the @RestControllerAdvice annotation was not used properly, but baidu found that there was nothing wrong.

Since my exception handling class is placed separately under common in the public service, I put this exception handling class under the business service for testing. A test using ==Postman== returns the following

Based on the results, the exception handling class works well in business services, but not in public services, which was confusing at the time

Just as I was messing around with the code, I made an important discoveryThe diagram below:

The exception handler class is missing a small icon in the red box. That icon means that the class is registered with the Spring container. This little icon appears when a class is registered with the Spring container using @Component. Because SpringBoot itself is going to annotate the boot class with @SpringBootApplication which is a boot class, and it’s going to scan all the components that are in the path of the boot class. The source code for @springBootApplication is as follows:

@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration

// Scan all components in the startup classpath.
@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 {};
 }
Copy the code

After discovering the above problem, I searched my project and found that the path of my unified exception handling class is different from the path of the service startup class. As a result, when the service is not detected, the unified exception class @RestControllerAdvice will not work. The path is shown below.

To solve

There are two solutions:

  • Change the hierarchy of the unified exception handling class to the same as the business service, bothcom.fxt.mall.xxxxx(Recommended)
  • Define the path to scan packages on the startup class
// Here is the path of the packet to scan
@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); }}Copy the code

A lone walker on a yard road

Wechat search “Java Ape”