我目前有一个ExceptionAdvice类,它处理所有基本(400,405,404和其他)异常。例如,我有一个默认的建议,它处理所有MethodArgumentNotValidExceptions并返回400 Bad Request Error。例如
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Error handleBadRequestException(Exception exception) {
return buildError(extractTriggerElement(exception), exception);
}
我还有一个不同的切入点建议,目标是处理MethodArgumentNotValidException的一个控制器方法,因为我需要为这种情况创建一个自定义错误消息。像这样的东西
@AfterThrowing(pointcut = "execution(*
package.controller.MyController*.updateSomething(*))", throwing = "ex")
private Error handleCustomError(MethodArgumentNotValidException ex) {
return buildCustomError(ex);
}
问题是控制器建议首先被调用,但是它会被默认建议覆盖,所以我得到了默认的错误消息。
当其他建议已经处理它时,有没有办法忽略默认建议中的@ExceptionHandler
所以我可以得到customError消息?
答案 0 :(得分:0)
如何使用annotations
类的ControllerAdvice
属性。
假设您有一个控制器c1,其方法为m1,m2和m3。
@RestController
class c1 {
m1() {.. }
m2() {.. }
m3() {.. } //let's assume m3 is the one you don't want to be handled by controller advice
}
你可以把它分成两个这样的控制器
@RestController
@SomeCustomAnnotation
class c1 {
m1() {.. }
m2() {.. }
}
和
@RestController
class c2 {
m3() {.. }
}
现在在建议课中你可以做这样的事情
@ControllerAdvice(annotations = {SomeCustomAnnotation.class})
class YourControllerAdviceClass {
.....
}
您必须像这样创建自定义注释
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeCustomAnnotation {
public String myValue();
}
这样,您的controlleradvice将只处理来自具有SomeCustomAnnotation
的控制器的异常。
这是更多的代码。但我觉得这更清洁了。
答案 1 :(得分:0)
你误解了@AfterThrowing
:
您只能使用这种建议,以便在方法退出异常之后,抛出之前以及可能由另一段代码处理之前执行某些操作。 您无法更改应用程序流程,例如捕获异常或操纵方法结果。
此外,由于我刚才解释的原因,@AfterThrowing
建议必须返回void
。您的建议甚至不应该编译,但编译器应该产生错误“此建议必须返回void”。至少这是我的AspectJ编译器所做的(我使用完整的AspectJ,而不是名为Spring AOP的“lite”版本,但结果应该是相同的。)
有关@AfterThrowing
的更多信息,请参阅Spring AOP manual。
解释一下,你能做什么?我将在纯Java + AspectJ示例中向您展示,以便让Spring脱离等式。您可以自己轻松地将知识传递给Spring AOP和Spring MVC错误处理程序:
为了更改应用程序流程,您需要的是@Around
建议。如果您在特殊方法中捕获错误并返回错误对象,那么默认的Spring异常处理程序甚至不会看到存在异常,因为它已被方面捕获。即默认处理程序将只处理方面未处理的所有其他错误。
以下是一些完全自洽且可编译的示例代码:
响应类:
我们在示例应用程序中使用这些,以模拟正常和错误响应,如Spring。
package de.scrum_master.app;
public interface Response {
String getMessage();
}
package de.scrum_master.app;
public class NormalResponse implements Response {
private String message = "OK";
@Override
public String getMessage() {
return message;
}
@Override
public String toString() {
return "NormalResponse [message=" + message + "]";
}
}
package de.scrum_master.app;
public class ErrorResponse implements Response {
private String message;
private Exception exeception;
public ErrorResponse(String message, Exception exeception) {
this.message = message;
this.exeception = exeception;
}
@Override
public String getMessage() {
return message;
}
public Exception getExeception() {
return exeception;
}
@Override
public String toString() {
return "ErrorResponse [message=" + message + ", exeception=" + exeception + "]";
}
}
驱动程序应用程序:
应用程序有两种方法,它们都随机产生正常或错误响应。方法produceSpecialException()
是我们希望稍后由方面处理的方法。
我们通过try-catch块模拟默认处理程序,然后调用辅助方法defaultHandler(Exception e)
。
package de.scrum_master.app;
import java.util.Random;
public class Application {
private final static Random RANDOM = new Random();
public Response produceException() throws Exception {
if (RANDOM.nextBoolean())
throw new Exception("normal error");
return new NormalResponse();
}
public Response produceSpecialException() throws Exception {
if (RANDOM.nextBoolean())
throw new Exception("special error");
return new NormalResponse();
}
public static ErrorResponse defaultHandler(Exception e) {
return new ErrorResponse("default handler", e);
}
public static void main(String[] args) {
Application application = new Application();
for (int i = 0; i < 5; i++) {
try {
System.out.println(application.produceException());
} catch (Exception e) {
System.out.println(defaultHandler(e));
}
try {
System.out.println(application.produceSpecialException());
} catch (Exception e) {
System.out.println(defaultHandler(e));
}
}
}
}
没有方面的控制台日志:
ErrorResponse [message=default handler, exeception=java.lang.Exception: normal error]
NormalResponse [message=OK]
ErrorResponse [message=default handler, exeception=java.lang.Exception: normal error]
ErrorResponse [message=default handler, exeception=java.lang.Exception: special error]
NormalResponse [message=OK]
NormalResponse [message=OK]
ErrorResponse [message=default handler, exeception=java.lang.Exception: normal error]
ErrorResponse [message=default handler, exeception=java.lang.Exception: special error]
NormalResponse [message=OK]
NormalResponse [message=OK]
如上所示,所有错误都由默认处理程序处理。这里不足为奇。
<强>方面:强>
方面仅处理“特殊”错误,忽略其他错误。
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import de.scrum_master.app.ErrorResponse;
import de.scrum_master.app.Response;
@Aspect
public class ErrorHandler {
@Around("execution(de.scrum_master.app.Response produceSpecialException(..))")
public Response handleError(ProceedingJoinPoint thisJoinPoint) throws Throwable {
try {
return (Response) thisJoinPoint.proceed();
}
catch (Exception e) {
return new ErrorResponse("aspect handler", e);
}
}
}
带方面的控制台日志:
ErrorResponse [message=default handler, exeception=java.lang.Exception: normal error]
ErrorResponse [message=aspect handler, exeception=java.lang.Exception: special error]
NormalResponse [message=OK]
ErrorResponse [message=aspect handler, exeception=java.lang.Exception: special error]
ErrorResponse [message=default handler, exeception=java.lang.Exception: normal error]
NormalResponse [message=OK]
ErrorResponse [message=default handler, exeception=java.lang.Exception: normal error]
ErrorResponse [message=aspect handler, exeception=java.lang.Exception: special error]
NormalResponse [message=OK]
NormalResponse [message=OK]
如上所示,现在有些错误由aspect handler
(“特殊错误”)处理,而所有其他错误仍由default handler
处理(“正常错误”)。
我希望这会有所帮助。享受!