如何使用自定义处理程序处理方面抛出的异常
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.");
}
}
这对我来说有点神奇,因为:
- 在 NotWorkingController 中,Aspect 代码抛出的异常未由自定义异常处理程序(位于 BaseController 中)处理。
- 我不得不将所有@RequestMappings 移动到接口 - 这对我来说有点烦人。如何预防?
所以,我应该看哪里,我应该检查什么?
提前感谢您的任何建议。
顺便说一句:完整的 maven 项目可用 here。
嗯,我有答案了。
第一个问题(异常捕获):
HandlerExceptionResolver 做了我需要的一切。
我已经从 BaseController
中的 handleException
方法中删除了 @ExceptionHandler
注释,HandlerExceptionResolver
的自定义实现捕获了我所有的异常)。
第二个问题:
我不得不从基于 JDK 的代理切换到基于 CGLIB 的代理。
我正在与 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.");
}
}
这对我来说有点神奇,因为:
- 在 NotWorkingController 中,Aspect 代码抛出的异常未由自定义异常处理程序(位于 BaseController 中)处理。
- 我不得不将所有@RequestMappings 移动到接口 - 这对我来说有点烦人。如何预防?
所以,我应该看哪里,我应该检查什么?
提前感谢您的任何建议。
顺便说一句:完整的 maven 项目可用 here。
嗯,我有答案了。
第一个问题(异常捕获):
HandlerExceptionResolver 做了我需要的一切。
我已经从 BaseController
中的 handleException
方法中删除了 @ExceptionHandler
注释,HandlerExceptionResolver
的自定义实现捕获了我所有的异常)。
第二个问题: 我不得不从基于 JDK 的代理切换到基于 CGLIB 的代理。