随着产品开发的深入,我们需要对用户的访问习惯进行分析,对各种异常情况都需要统一处理。为了避免代码的冗余以及模块的耦合,很自然想到了spring的切面原理。
切面,简而言之,就是将业务中相对独立的模块,例如日志、异常等作为一个处理点,统一管理并处理。这样做的好处是,以后的维护不需要大面积更改代码,提高模块之间的耦合度,代码会显得美观,可读性强,可移植性强。下面重点总结一下使用过程,具体如下:
1.首先应用spring切片,需要对应的jar包(org.aspectj)
可以直接应用jar包,也可以利用pom文件下载
2.配置注解扫描
<!-- 扫描注解,扫描controller -->
<context:component-scan base-package="zhitongits.controller,zhitongits.aop"/>
或者直接指定需要扫描的实体
- <aop:aspectj-autoproxy proxy-target-class="true"/>
- <bean class="com.yusj.interceptor.LogAspect" />
3.日志捕获和处理
通过注解标记切面,并通过@Before("execution(* com.yusj.controller..*.*(..))")、 @After("execution(* com.yusj.controller..*.*(..))")、@Around("execution(* com.yusj.controller..*.*(..))") 来处理日志,处理日志很容易想到,如何取获取请求内容和结果的问题,方法如下
//获取request对象
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
//获取request中的请求参数
Map<String, String[]> map = request.getParameterMap();
//获取请求结果
Object result = pjp.proceed();
这样,你就可以随心所欲地处理日志了,入库、利用log4j写日志等等
4.异常的统一处理
通过实现ThrowsAdvice捕获所有抛出的异常,这样,不需要在代码中写过多的try... catch代码
public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable
{
// 在后台中输出错误异常异常信息,通过log4j输出。
Logger log = Logger.getLogger(target.getClass());
System.out.println("Error happened in class: "+ target.getClass().getName() +";Error happened in method: " + method.getName());
System.out.println("异常详情:" + ex.getMessage());
ex.printStackTrace();
// 在这里判断异常,根据不同的异常返回错误。
if (ex.getClass().equals(DataAccessException.class))
{
ex.printStackTrace();
throw new BusinessException("数据库操作失败!");
} else if (ex.getClass().toString().equals( NullPointerException.class.toString()))
{
ex.printStackTrace();
throw new BusinessException("调用了未经初始化的对象或者是不存在的对象!");
} else if (ex.getClass().equals(IOException.class))
{
ex.printStackTrace();
throw new BusinessException("IO异常!");
} else if (ex.getClass().equals(ClassNotFoundException.class))
{
ex.printStackTrace();
throw new BusinessException("指定的类不存在!");
} else if (ex.getClass().equals(ArithmeticException.class))
{
ex.printStackTrace();
throw new BusinessException("数学运算异常!");
} else if (ex.getClass().equals(ArrayIndexOutOfBoundsException.class))
{
ex.printStackTrace();
throw new BusinessException("数组下标越界!");
} else if (ex.getClass().equals(IllegalArgumentException.class))
{
ex.printStackTrace();
throw new BusinessException("方法的参数错误!");
} else if (ex.getClass().equals(ClassCastException.class))
{
ex.printStackTrace();
throw new BusinessException("类型强制转换错误!");
} else if (ex.getClass().equals(SecurityException.class))
{
ex.printStackTrace();
throw new BusinessException("违背安全原则异常!");
} else if (ex.getClass().equals(SQLException.class))
{
ex.printStackTrace();
throw new BusinessException("操作数据库异常!");
} else if (ex.getClass().equals(NoSuchMethodError.class))
{
ex.printStackTrace();
throw new BusinessException("方法末找到异常!");
} else if (ex.getClass().equals(InternalError.class))
{
ex.printStackTrace();
throw new BusinessException("Java虚拟机发生了内部错误");
} else
{
ex.printStackTrace();
throw new BusinessException("程序内部错误,操作失败!" + ex.getMessage());
}
}
这样很容易记录下所有的异常信息,包括发生异常的class、method等,并返回准确的异常信息;特别的如果只需要监听部分类文件抛出的异常,也可以通过配置文件指定package或bean来实现