spring aop的案例(一)日志拦截

来源:互联网 发布:d3.js官网下载 编辑:程序博客网 时间:2024/04/30 08:34

日志拦截,一般主要在service和action进行日志拦截。这里我们直接讲用法,至于原理就不做具体讲解。
我们使用spring+spring mvc架构项目

aplicationContext-common.xml:

<context:component-scan base-package="com.tonghui.thcws">        <!--删除controller注解扫描-->        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /></context:component-scan>   <!-- 启动对@AspectJ注解的支持 -->  <aop:aspectj-autoproxy/> <!--事务注解--><tx:annotation-driven  transaction-manager="transactionManager" proxy-target-class="true" />

applicationContext-mvc.xml:

<context:component-scan base-package="com.tonghui.thcws.web.controller">    <!--只扫描controller注解-->        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>

Log注解声明:SystemLogAspect.java

import java.lang.reflect.Method;import java.util.Date;import javax.servlet.http.HttpServletRequest;import org.apache.shiro.SecurityUtils;import org.apache.shiro.subject.Subject;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import com.tonghui.cws.vo.Principal;import com.tonghui.thcws.model.SysLog;import com.tonghui.thcws.service.SysLogService;/** * 切点类 *  * @author 崔金睿 * @since 2015年6月24日 10:17:51 * @version 1.0 */@Aspect@Componentpublic class SystemLogAspect {    // 注入Service用于把日志保存数据库    @Autowired    private SysLogService logService;    // 本地异常日志记录对象    private static final Logger logger = LoggerFactory            .getLogger(SystemLogAspect.class);    // Service层切点    @Pointcut("@annotation(SystemServiceLog)")    public void serviceAspect() {    }    // Controller层切点    @Pointcut("@annotation(SystemControllerLog)")    public void controllerAspect() {    }    private String getUser() {        Subject subject = SecurityUtils.getSubject();        Principal principal=    (Principal) subject.getPrincipal();        return principal==null?"未登录用户":principal.getUsername();    }    /**     * 前置通知 用于拦截Controller层记录用户的操作     *      * @param joinPoint     *            切点     */    @After("controllerAspect()")    public void doAfter(JoinPoint joinPoint) {        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder                .getRequestAttributes()).getRequest();        // 请求的IP        String ip = request.getRemoteAddr();        // 获取用户请求方法的参数并序列化为JSON格式字符串                StringBuffer params = new StringBuffer();                if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {                    params.append("[");                    for (int i = 0; i < joinPoint.getArgs().length; i++) {                        params.append(joinPoint.getArgs()[i]);                        params.append(",");                    }                    params.deleteCharAt(params.length()-1);                    params.append("]");                }        try {            // *========数据库日志=========*//            SysLog log = new SysLog();            log.setType("0");// 0录用户的操作日志 1为异常日志            log.setCreateBy(getUser());            log.setCreateDate(new Date());            log.setRemoteAddr(ip);            log.setUserAgent(request.getHeader("User-Agent"));            log.setRequestUri(request.getRequestURI());            log.setMethod((joinPoint.getTarget().getClass().getName() + "."                    + joinPoint.getSignature().getName() + "()"));            log.setDescription(getControllerMethodDescription(joinPoint));            // 参数            log.setParams(params.toString());            log.setExceptionCode(null);            log.setExceptionDetail(null);            // 保存数据库            logService.addLog(log);        } catch (Exception e) {            // 记录本地异常日志            logger.error("==前置通知异常==");            logger.error("异常信息:{}", e.getMessage());        }    }    /**     * 异常通知 用于拦截serviceAspect层记录异常日志     *      * @param joinPoint     * @param e     */    @AfterThrowing(pointcut = "serviceAspect()", throwing = "e")    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder                .getRequestAttributes()).getRequest();        // 获取请求ip        String ip = request.getRemoteAddr();        // 获取用户请求方法的参数并序列化为JSON格式字符串        StringBuffer params = new StringBuffer();        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {            params.append("[");            for (int i = 0; i < joinPoint.getArgs().length; i++) {                params.append(joinPoint.getArgs()[i]);                params.append(",");            }            params.deleteCharAt(params.length()-1);            params.append("]");        }        try {            // *========数据库日志=========*//            SysLog log = new SysLog();            log.setType("1");// 0录用户的操作日志 1为异常日志            log.setCreateBy(getUser());            log.setCreateDate(new Date());            log.setRemoteAddr(ip);            log.setUserAgent(request.getHeader("User-Agent"));            log.setRequestUri(request.getRequestURI());            log.setMethod((joinPoint.getTarget().getClass().getName() + "."                    + joinPoint.getSignature().getName() + "()"));            log.setDescription(getControllerMethodDescription(joinPoint));            // 参数            log.setParams(params.toString());            log.setExceptionCode(e.getClass().getName());            log.setExceptionDetail(e.getMessage());            // 保存数据库            logService.addLog(log);        } catch (Exception ex) {            // 记录本地异常日志            logger.error("==异常通知异常==");            logger.error("异常信息:{}", ex.getMessage());        }        /* ==========记录本地异常日志========== */        logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget()                .getClass().getName()                + joinPoint.getSignature().getName(), e.getClass().getName(),                e.getMessage(), params);    }    /**     * 获取注解中对方法的描述信息 用于service层注解     *      * @param joinPoint     *            切点     * @return 方法描述     * @throws Exception     */    @Deprecated    public static String getServiceMthodDescription(JoinPoint joinPoint)            throws Exception {        String targetName = joinPoint.getTarget().getClass().getName();        String methodName = joinPoint.getSignature().getName();        Object[] arguments = joinPoint.getArgs();        Class targetClass = Class.forName(targetName);        Method[] methods = targetClass.getMethods();        String description = "";        for (Method method : methods) {            if (method.getName().equals(methodName)) {                Class[] clazzs = method.getParameterTypes();                if (clazzs.length == arguments.length) {                    description = method.getAnnotation(SystemServiceLog.class)                            .description();                    break;                }            }        }        return description;    }    /**     * 获取注解中对方法的描述信息 用于Controller层注解     *      * @param joinPoint     *            切点     * @return 方法描述     * @throws Exception     */    public static String getControllerMethodDescription(JoinPoint joinPoint)            throws Exception {        String targetName = joinPoint.getTarget().getClass().getName();        String methodName = joinPoint.getSignature().getName();        Object[] arguments = joinPoint.getArgs();        Class targetClass = Class.forName(targetName);        Method[] methods = targetClass.getMethods();        String description = "";        for (Method method : methods) {            if (method.getName().equals(methodName)) {                Class[] clazzs = method.getParameterTypes();                if (clazzs.length == arguments.length) {                    description = method.getAnnotation(                            SystemControllerLog.class).description();                    break;                }            }        }        return description;    }}

Controller日志拦截注解类:SystemControllerLog.java

import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/**  *自定义注解 拦截Controller  */ @Target({ElementType.PARAMETER, ElementType.METHOD})  @Retention(RetentionPolicy.RUNTIME)  @Documentedpublic @interface SystemControllerLog {    String description()  default "";}

Service异常日志拦截注解类:SystemServiceLog.java

import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/**  *自定义注解 拦截Service */ @Target({ElementType.PARAMETER, ElementType.METHOD})  @Retention(RetentionPolicy.RUNTIME)  @Documentedpublic @interface SystemServiceLog {    String description()  default "";}

如何使用?

Controller:

@SystemControllerLog(description ="账户启用账户")@RequestMapping(value ="/accountStart",method=RequestMethod.POST)@ResponseBodypublic JsonVO accountStart(Long id){    JsonVO j = new JsonVO();    try {        accountService.accountEnable(id);        j.setStatus(CwsConstants.STATUS_SUCCESS);        j.setMessage("启停成功!");    } catch (Exception e) {        j.setMessage("账户启用失败!");        j.setStatus(CwsConstants.STATUS_ERROR);        logger.error("账户启用失败",e.getMessage());    }    return j;}

Service:

@SystemServiceLog(description="保存账户发生异常")@Transactionalpublic void save(CwsAccount entity) throws Exception{    try {        sqlSession.insert(DOMAIN_NAME+".insertSelective",entity);    } catch (Exception e) {        e.printStackTrace();        throw e;    }}

使用的过程中会发现,service捕捉异常的时候会出现事务回滚的现象,为什么?如何解决?

原因是因为aop的先后顺序导致,刚刚写入数据库就被事务拦截后并发生异常则回滚操作了。

<!--事务注解--><tx:annotation-driven  transaction-manager="transactionManager" proxy-target-class="true" order="2" />

这样就实现了我们自己写的aop在事务介入之前就执行了!

1 0
原创粉丝点击