spring aop 统一捕获异常

Aspect:

@Controller
@Aspect
public class WebExceptionAspect {

    //连接点是@RequestMapping注解的方法
    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    private void webPointcut() {}
    
    //切点在webpointCut()
    @AfterThrowing(pointcut = "webPointcut()", throwing = "e")
    //controller类抛出的异常在这边捕获
    public void handleThrowing(JoinPoint joinPoint, Exception e) {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        //开始打log
        System.out.println("异常:" + e.getMessage());
        System.out.println("异常所在类:" + className);
        System.out.println("异常所在方法:" + methodName);
        System.out.println("异常中的参数:");
        System.out.println(methodName);
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i].toString());
        }
    }

    @Before("execution(* com.xinjianqiao.mian.controller.*.*(..))")
    public void beforeProcess(JoinPoint joinPoint) {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        //在项目中最好记录当前操作的时间和用户
        System.out.println("操作所在类:" + className);
        System.out.println("操作所在方法:" + methodName);
        System.out.println("操作中的参数:");
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i].toString());
        }
    }

    @AfterReturning(value = "execution(* com.xinjianqiao.mian.controller.*.*(..)))", 
            returning = "returnVal")
    public void returnProcess(JoinPoint joinPoint, Object returnVal) {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        Class targetClass = null;
        String operationName = "";
        try {
            targetClass = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Method[] methods = targetClass.getMethods();
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs != null && clazzs.length == args.length&&
                        //这块是取出我们注解ArchiveLog中的值,一遍在日志时明确这个操作的名称
                        method.getAnnotation(ArchivesLog.class)!=null) {
                    operationName = method.getAnnotation(ArchivesLog.class).operationName();
                    break;
                }
            }
        }
        System.out.println("操作名称:" + operationName);
        System.out.println("方法正常返回的值:" + returnVal);
    }
}

ArchivesLog:

@Target({ElementType.PARAMETER, ElementType.METHOD})  //注解可以用于参数或者方法上
@Retention(RetentionPolicy.RUNTIME)  //保留至运行时
@Documented//被javadoc所记录
public @interface ArchivesLog {
    /**
     * 操作类型
     * @return
     */
    public String operationType() default "";

    /**
     * 操作名称
     * @return
     */
    public String operationName() default "";

}

Controller:

@Controller
@RequestMapping("/exception")
public class ExceptionController {

    @RequestMapping(value = "/test/{id}", method = RequestMethod.GET, 
            produces = "application/json;charset=UTF-8" )
    @ResponseBody
    @ArchivesLog(operationType = "测试", operationName = "测试异常或者测试返回")
    public JSONObject test(@PathVariable Integer id) throws Exception {
        JSONObject result = new JSONObject();
        try {//去掉注释可以测捕获的异常,不去掉注释可以测日志处理
            int i = 1;
            i=i/0;
        } catch (Exception ex) {
            throw new Exception("controller 层 异常");
        }
        return result;
    }
}

 

补充:

JoinPoint :封装了SpringAop中切面方法的信息,

public interface JoinPoint {

    /**
     * 连接点所在位置的相关信息
     * @return
     */
    String toString();

    /**
     * 连接点所在位置的简短相关信息
     * @return
     */
    String toShortString();

    /**
     * 连接点所在位置的全部相关信息
     * @return
     */
    String toLongString();

    /**
     * 返回AOP代理对象,也就是com.sun.proxy.$Proxy18
     * @return
     */
    Object getThis();

    /**
     * 返回目标对象,
     * 一般我们都需要它或者
     * (也就是定义方法的接口或类,为什么会是接口呢?
     * 这主要是在目标对象本身是动态代理的情况下,
     * 例如Mapper。所以返回的是定义方法的对象
     * 如aoptest.daoimpl.GoodDaoImpl
     * 或com.b.base.BaseMapper)
     * @return
     */
    Object getTarget();

    /**
     * 返回被通知方法参数列表
     * @return
     */
    Object[] getArgs();

    /**
     * 返回当前连接点签名
     * 其getName()方法返回方法的FQN,
     * 如void aoptest.dao.GoodDao.delete()
     * 或com.b.base.BaseMapper.insert(T)
     * (需要注意的是,很多时候我们定义了子类继承父类的时候,
     * 我们希望拿到基于子类的FQN,这直接可拿不到,
     * 要依赖于AopUtils.getTargetClass(point.getTarget())
     * 获取原始代理对象)
     * @return
     */
    Signature getSignature();

    /**
     * 返回连接点方法所在类文件中的位置
     * @return
     */
    SourceLocation getSourceLocation();

    /**
     * 连接点类型
     * @return
     */
    String getKind();

    /**
     * 返回连接点静态部分
     * @return
     */
    StaticPart getStaticPart();
}

 

JoinPoint.StaticPart:提供访问连接点的静态部分,如被通知方法签名、连接点类型等:

public interface StaticPart {  
   Signature getSignature();    //返回当前连接点签名  
   String getKind();          //连接点类型  
   int getId();               //唯一标识  
   String toString();         //连接点所在位置的相关信息  
   String toShortString();     //连接点所在位置的简短相关信息  
   String toLongString();     //连接点所在位置的全部相关信息  
}

 

你可能感兴趣的:(spring aop 统一捕获异常)