如何使用自定义处理程序处理方面抛出的异常

How to handle exception thrown by aspect using custom handler

我正在与 AOP 和自定义错误处理程序作斗争。 我有一个控制器 "WorkingController" - 它按预期工作。

@Controller
public class WorkingController extends BaseController {
    ​
    @RequestMapping("/welcome")
    public ModelAndView helloWorld() {
        return new ModelAndView("welcome", "message", "<h3>********** Hello World, Success!</h3>");
    }
    ​
    @RequestMapping("/success")
    public void test(HttpServletResponse response) {
        writeResponse(response, "Success!", ContentType.TEXT_JSON);
    }
    ​
    @RequestMapping("/test")
    public void test2(HttpServletResponse response) throws IOException {
        throw new IOException("This exception should be handled by custom handler.");
    }
    ​
    @InterestingMethod
    @RequestMapping("/aspect")
    public void test3(@InterestingArg @RequestParam(value = "id", required = false) String id,
                      HttpServletResponse response) throws IOException, AccessDeniedException {
        throw new IOException("This exception should also be handled by custom handler.");
    }
}
​
class BaseController {

    @ExceptionHandler(Exception.class)
    public void handleException(Throwable ex, HttpServletRequest request, HttpServletResponse response) {
        System.out.println("Exception handled by BaseController, great work!: " + ex.getMessage());
        ServletUtil.writeResponse(response, JSONObject.fromObject("Error").toString(),
                ContentType.TEXT_JSON.toString(), false, "UTF-8");
    }
    ​
    void writeResponse(HttpServletResponse response, String data, ContentType contentType) {
        ServletUtil.writeResponse(response, data, contentType.toString(), false, "UTF-8");
    }
    ​
}

我的情况迫使我创建界面,标记我的控制器,Aspect 将检查用户是否有权访问给定端点 - 所以我有 MarkedController 界面和 NotWorkingController。

@Controller
public class NotWorkingController extends BaseController implements MarkedController {

    public void test2(HttpServletResponse response) throws IOException {
        throw new IOException("NotWorkingController, This exception should be handled by custom handler.");
    }
    ​
    @InterestingMethod
    public void test3(@InterestingArg String id,
                      HttpServletResponse response) throws IOException, AccessDeniedException {
        throw new IOException("NotWorkingController, This exception should also be handled by custom handler.");
    }
}
​
@Controller
public interface MarkedController {
    ​
    @RequestMapping("/test2")
    void test2(HttpServletResponse response) throws IOException;

    @RequestMapping("/aspect2")
    void test3(@RequestParam(value = "id", required = false) String id,
               HttpServletResponse response) throws IOException, AccessDeniedException;
}

@Aspect
public class InterestingMethodAspect {
    @Pointcut("@annotation(interestingMethod)")
    public void interestingMethodPointcut(InterestingMethod interestingMethod) {
    }

    @Before("(interestingMethodPointcut(interestingMethod))")
    public void asd(JoinPoint joinPoint, InterestingMethod interestingMethod) throws AccessDeniedException {
        processArguments(joinPoint);
    }

    private void processArguments(JoinPoint joinPoint) throws AccessDeniedException {
        throw new AccessDeniedException("You don't have access to this endpoint.");
    }
}

这对我来说有点神奇,因为:

  1. 在 NotWorkingController 中,Aspect 代码抛出的异常未由自定义异常处理程序(位于 BaseController 中)处理。
  2. 我不得不将所有@RequestMappings 移动到接口 - 这对我来说有点烦人。如何预防?

所以,我应该看哪里,我应该检查什么?
提前感谢您的任何建议。

顺便说一句:完整的 maven 项目可用 here

嗯,我有答案了。

第一个问题(异常捕获): HandlerExceptionResolver 做了我需要的一切。 我已经从 BaseController 中的 handleException 方法中删除了 @ExceptionHandler 注释,HandlerExceptionResolver 的自定义实现捕获了我所有的异常)。

第二个问题: 我不得不从基于 JDK 的代理切换到基于 CGLIB 的代理。