在spring mvc项目中,使用@Aspect截取所有contoller中的exception,并且通过HttpServletResponse输出的一些问题
2016-12-10 03:25
405 查看
需求业务场景:
在spring 4.3 的mvc项目中,需要把所有controller层中的exception全部捕获,把错误信息进行处理后,通过HttpServletResponse 输出到浏览器出现的问题:
2个项目都需要完成这个场景,但是一个项目实现了。另外一个项目通过同样的配置,却无法实现。表现在aop虽然截获了所有的controller中的exception,通过aop中的@autowired注入的HttpServletResponse却无法替换controller中的输出。浏览器界面依然显示的是标准的web 500 出错界面。解决过程:
通过2个项目比对,发现实现这个功能需要注意以下几点:1. 对controller中所有的方法进行切面的定义后,如果只是用@AfterThrowing 来通知处理出错内容,并且需要用HttpServletResponse来代替controller输出到浏览器,需要对同样的切面,进行@Around通知处理。
2. @Around 通知,必须优先于 @AfterThrowing通知.
3. 在同一个@Aspect类中,无法做到第二点,所以需要拆分成2个@Aspect类,并且通过@Order来指定顺序。
相关文档可以查看:
http://sishuok.com/forum/blogPost/list/0/2474.html
4. 另外一个项目碰巧可以实现这个功能,是因为@Around通知所在的aop类的包名排名在@AfterThrowing通知所在的aop类的签名。应该是优先载入了,所以在没有显式指定的时候,恰好就完成了这个功能,并且没有错误。
5. 相关AOP代码如下代码:2个代码都是定义同样的切面(切入所有的controller中的方法)
a. 处理@Around 的AOP类代码
/** * @Title: SystemLogAspect.java * @Package com.ninelephas.meerkat.aspect * @Description: 系统日志的AOP类 * Copyright: Copyright (c) 2016 * Company:九象网络科技(上海)有限公司 * * @author "徐泽宇" * @date 2016年8月1日 下午5:25:15 * @version V1.0.0 */ package com.ninelephas.terrier.aspect.controller; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.ResponseBody; /** * * @ClassName: ArroundControllerAspect * @Description: 处理所有controller类中方法的环绕通知,什么事情都不做,就是执行方法,为了和CatchControllerExceptionAspect配合 * 切面定义和 CatchControllerExceptionAspect 一致,并且优先级要高于CatchControllerExceptionAspect * @author 徐泽宇 * @date 2016年12月10日 上午3:11:39 * */ @Aspect @Order(1) @Component("com.ninelephas.terrier.aspect.controller.ArroundControllerAspect") public class ArroundControllerAspect { private static final Logger logger = LogManager.getLogger(ArroundControllerAspect.class); /** * * runControllerMethod * * @Auther 徐泽宇 * @Date 2016年12月10日 上午3:15:59 * @Title: logTheController * @Description: 定义一个切面,指向所有的controller类中的所有方法 */ @Pointcut("execution(* com.ninelephas.terrier.controller..*.*(..)) ") public void runControllerMethod() { // Nothing to clean up } /** * * runControllerMethod * * @Auther 徐泽宇 * @Date 2016年12月10日 上午3:17:12 * @Title: runControllerMethod * @Description: 什么都不处理,仅仅是增加一个环绕通知. * 这里必须返回一个object,把处理过程交回给controller。否则controller中的@ResponseBody不会起作用了 * @param joinPoint */ @Around("runControllerMethod()") private Object runControllerMethod(ProceedingJoinPoint joinPoint) { if (logger.isDebugEnabled()) { logger.debug("runControllerMethod(ProceedingJoinPoint joinPoint={}) - start", joinPoint); //$NON-NLS-1$ } Object rtnObject = null; try { rtnObject = joinPoint.proceed(); } catch (Throwable e) { logger.error(e); } if (logger.isDebugEnabled()) { logger.debug("runControllerMethod(ProceedingJoinPoint joinPoint={}) - end", joinPoint); //$NON-NLS-1$ } return rtnObject; } }
b. 处理@AfterThrowing的AOP类代码(核心功能),处理controller中的exception,并且用HttpServletResponse 输出
package com.ninelephas.terrier.aspect.catchcontroller; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * @ClassName: CatchControllerExceptionAspect * @Description: 捕获所有Controller中的方法的Exception * 通过HttpServletResponse输出到浏览器 * @author 徐泽宇 * @date 2016年11月1日 下午10:05:29 * */ @Aspect @Order(2) @Component("com.ninelephas.terrier.aspect.catchcontroller.CatchControllerExceptionAspect") public class CatchControllerExceptionAspect { /** * Logger for this class */ private static final Logger logger = LogManager.getLogger(CatchControllerExceptionAspect.class.getName()); @Autowired private HttpServletResponse response; /** * catchController * * @Auther 徐泽宇 * @Date 2016年11月1日 下午10:08:50 * @Title: catchControllerMethod * @Description: 切入所有controller中方法的切面 */ @Pointcut("execution(* com.ninelephas.terrier.controller..*.*(..)) ") public void catchControllerMethod() { // Nothing to clean up } /** * writeToHttpResponse * * @throws IOException * * @throws ServletException * * @Auther 徐泽宇 * @Date 2016年11月1日 下午10:11:24 * @Title: writeToHttpResponse * @Description: 捕捉到切面产生的Exception后,写入HttpServletResponse */ @AfterThrowing(throwing = "ex", pointcut = "catchControllerMethod()") private void writeToHttpResponse(Throwable ex) throws IOException { response.setStatus(500); response.getWriter().write(ex.getMessage()); logger.debug("浏览器输出完成!"); logger.error(ex, ex.fillInStackTrace()); } }
相关文章推荐
- 第十二周 项目4 利用遍历思想求解图问题(输出通过一个节点的所有简单回路 )
- 第十二周项目四----利用遍历思想求解图问题之输出通过一个节点的所有简单回路
- “超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。”问题的解决方法
- Android使用NDK开发项目时的一些问题
- Android使用NDK开发项目时的一些问题
- 解决HttpServletResponse输出的中文乱码问题
- 高效的使用 Response.Redirect解决一些不必要的问题
- [项目过程中所遇到的各种问题记录]ORM篇——使用NHibernate配置对象实体的一些小问题
- <车载物联网项目,视频采集传输部分,第二天> 使用ffserver输出视频文件流,并且使用使用命令行终端播放视频文件
- 在使用VS创建 cocos2d-x 项目时遇到的一些问题
- SpringMVC使用@ResponseBody输出字符串时遇到的乱码问题及解决办法
- 通过反射读取HttpServletResponse输出至客户端的流
- SpringMVC使用@ResponseBody输出字符串时遇到的乱码问题及解决办法
- Spring MVC 使用@responseBody IE下出现下载的问题
- 使用Aspect中的annotation标签的方法来截获所有的Exception,进行控制台打印
- word通配符的使用,以及去掉项目符号,以及函数指针,中断向量的一些杂问题
- SpringMVC使用@ResponseBody输出字符串时遇到的乱码问题及解决办法
- Android 使用JNI的项目通过Proguard混淆后程序异常的问题
- [转] 解决HttpServletResponse输出的中文乱码问题
- 通过response的write留输出数据的问题