Spring MVC:将异常处理程序绑定到特定方法

V. *_*hov 15 java spring-mvc

美好的一天!

我有一个@Controller.它的一些方法抛出相同的异常,但我想以不同的方式处理这些异常.

有没有办法如何绑定@ExceptionHandler到特定的方法?

小智 5

您需要使用 AOP 工具(如CDI InterceptorAspectJ)来实现这种横切关注点。关注点是一个术语,指的是根据功能划分的系统的一部分。

基本上,这种类型的功能用于处理日志记录、安全性以及处理错误……这不是您的业务逻辑的一部分……

就像如果您想将应用程序的记录器从 log4j 更改为 sl4j,那么您需要遍历使用过 log4j 的每个类并进行更改。但是如果你使用过 AOP 工具,那么你只需要去拦截器类并更改实现。像即插即用和非常强大的工具。

这是使用 JavaEE CDI 拦截器的代码片段

/*
    Creating the interceptor binding
*/
@InterceptorBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface BindException {

}
Run Code Online (Sandbox Code Playgroud)

在我们定义了拦截器绑定之后,我们需要定义拦截器绑定的实现

/*
    Creating the interceptor implementation
*/
@Interceptor
@BindException
public class ExceptionCDIInterceptor {

    @AroundInvoke
    public Object methodInterceptor(InvocationContext ctx) throws Exception {
        System.out.println("Invoked method " + ctx.getMethod().getName());
        try {
            return ctx.proceed(); // this line will try to execute your method
                                 // and if the method throw the exception it will be caught  
        } catch (Exception ex) {
            // here you can check for your expected exception 
            // code for Exception handler
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

现在我们只需要对我们的方法应用拦截器

/*
    Some Service class where you want to implement the interceptor
*/
@ApplicationScoped
public class Service {

    // adding annotation to thisMethodIsBound method to intercept
    @BindException
    public String thisMethodIsBound(String uid) {
        // codes....

        // if this block throw some exception then it will be handled by try catch block
        // from ExceptionCDIInterceptor
    }
}
Run Code Online (Sandbox Code Playgroud)

您也可以使用 AspectJ 实现相同的功能。

/*
    Creating the Aspect implementation
*/
@Aspect
public class  ExceptionAspectInterceptor {

    @Around("execution(* com.package.name.SomeService.thisMethodIsBound.*(..))")
    public Object methodInterceptor(ProceedingJoinPoint ctx) throws Throwable {
        System.out.println("Invoked method " + ctx.getSignature().getName());
        try {
            return ctx.proceed(); // this line will try to execute your method
                                 // and if the method throw the exception it will be caught  
        } catch (Exception ex) {
            // here you can check for your expected exception 
            // codes for Exception handler
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们只需要在我们的应用程序配置中启用 AspectJ

/*
    Enable the AspectJ in your application
*/
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

    @Bean
    public SomeService SomeService() {
        return new SomeService();
    }

}

/*
    Some Service class where you want to implement the Aspect
*/
package com.package.name;
public class SomeService {

    public String thisMethodIsBound(String uid) {
        // codes....

        // if this block throw some exception then it will be handled by try catch block
        // from ExceptionAspectInterceptor
    }
}
Run Code Online (Sandbox Code Playgroud)

我的 git repo https://github.com/prameshbhattarai/javaee-exceptionBinding 中有代码示例,使用 CDI 拦截器。


小智 1

我不认为您可以@ExceptionHandler为方法指定特定的,但您可以将@ExceptionHandler方法绑定到特定的Exception

因此,如果您想以DataIntegrityViolationException一种方式处理所有其他异常,而以另一种方式处理所有其他异常,您应该能够通过以下方式实现:

@ExceptionHandler(DataIntegrityViolationException.class)
public void handleIntegrityViolation() {
    // do stuff for integrity violation here
}

@ExceptionHandler(Exception.class)
public void handleEverythingElse() {
    // do stuff for everything else here
}
Run Code Online (Sandbox Code Playgroud)