基于SSM框架通过Spring AOP实现Controller、Service日志管理

基于SSM框架通过Spring AOP实现Controller、Service日志管理
1.项目背景
需要在Web管理平台添加用户操作日志,采用Spring AOP的方式完成该功能
2.编写测试代码:
(1)数据库

 CREATE TABLE `syslog` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `operName` varchar(200) DEFAULT NULL,
  `operResult` varchar(200) DEFAULT NULL,
  `operDate` varchar(200) DEFAULT NULL,
  `operExceptionDesc` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;

(2)日志管理实体类

package com.ssm.entity;

public class SysLog {

    private String operName;
    private String operResult;
    private String operDate;
    private String operExceptionDesc;

    public String getOperExceptionDesc() {
        return operExceptionDesc;
    }

    public void setOperExceptionDesc(String operExceptionDesc) {
        this.operExceptionDesc = operExceptionDesc;
    }

    public String getOperName() {
        return operName;
    }

    public void setOperName(String operName) {
        this.operName = operName;
    }

    public String getOperResult() {
        return operResult;
    }

    public String getOperDate() {
        return operDate;
    }

    public void setOperDate(String operDate) {
        this.operDate = operDate;
    }

    public void setOperResult(String operResult) {
        this.operResult = operResult;
    }
    @Override
    public String toString() {
        return "SysLog{" +
                "operName='" + operName + '\'' +
                ", operResult='" + operResult + '\'' +
                ", operDate='" + operDate + '\'' +
                ", operExceptionDesc='" + operExceptionDesc + '\'' +
                '}';
    }
}

(3)通过自定义注解实现

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SysLog {
    String operName() default "";
    String operResult() default "";
}

(4)定义切面类,

@Aspect
@Service
public class SysLogAspect {

    @Autowired
   private SysLogService sysLogService;
    
    @Pointcut("@annotation(com.ssm.service.SysLog)")
    public void getSysLog(){

    }

    @AfterReturning("getSysLog()")
    public void afterReturning(JoinPoint joinPoint){
        handlerSysLog(joinPoint,null);
    }

    @AfterThrowing(value = "getSysLog()",throwing = "e")
    public void afterReturning(JoinPoint joinPoint,Exception e){
        handlerSysLog(joinPoint,e);
    }

    public void handlerSysLog(JoinPoint joinPoint,Exception e){

        //整体思路:通过反射获取到目标方法对象,通过方法对象拿到注解,,再通过注解拿到注解属性值

        SysLog sysLog = null;
        String operName = "";
        String operResult = "";
        String operDate = "";
        String operExceptionDesc = "";

        try {
            //获取目标方法所在类的全称
            String targetName = joinPoint.getTarget().getClass().getName();
            //获取目标方法的名称
            String methodName = joinPoint.getSignature().getName();
            //获取目标方法的参数
            Object[] arguments = joinPoint.getArgs();
            //获取目标方法做在的类对象,后期通过反射获取方法和属性
            Class targetClass = Class.forName(targetName);
            //获取目标方法所在类的所有方法
            Method[] methods = targetClass.getMethods();

            for(Method method:methods){
                if(method.getName().equals(methodName)){
                    Class[] classes = method.getParameterTypes();
                    if(arguments.length == classes.length){
                        sysLog = method.getAnnotation(SysLog.class);
                    }
                }
            }

        }catch (Exception ex){
            ex.printStackTrace();
        }

        operName = sysLog.operName();
        operDate = dateString(new Date());
        if(e != null){
            operResult = "异常";
            operExceptionDesc = e.toString();
        }else if(e == null){
            operResult = "正常";
        }




        com.ssm.entity.SysLog entity = new com.ssm.entity.SysLog();
        entity.setOperDate(operDate);
        entity.setOperName(operName);
        entity.setOperResult(operResult);
        entity.setOperExceptionDesc(operExceptionDesc);

        sysLogService.saveSysLog(entity);

    }


    public String dateString(Date date){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        return simpleDateFormat.format(date);
    }


}

@AfterReturning:后置通知,方法正常执行结束后执行该方法
@AfterThrowing:后置异常通知:方法发生异常后执行该方法
本测试案例中,后置通知和后置异常通知调用的同一个方法,在方法内通过判断是否有异常来区分方法是正常执行结束还是发生了异常。

(4)日志操作mapper.xml

<mapper namespace="com.ssm.mapper.SysLogMapper" >
    <insert id="saveSysLog" parameterType="sysLog">
         insert into sysLog(operName,operResult,operDate,operExceptionDesc) values(#{operName},#{operResult},#{operDate},#{operExceptionDesc})
    </insert>
</mapper>

(5)日志操作mapper.java

public interface SysLogMapper {
    public void saveSysLog(SysLog sysLog);
}

(6)日志操作业务层接口

public interface SysLogService {
    public void saveSysLog(SysLog sysLog);
}

业务层实现类

@Service
public class SysLogImpl implements SysLogService {

    @Autowired
    private SysLogMapper sysLogMapper;

    @Override
    public void saveSysLog(SysLog sysLog) {
        sysLogMapper.saveSysLog(sysLog);
    }
}

(7)
       Spring AOP的动态代理是通过JDK实现的,基于JDK实现的动态代理,被代理的类需要实现接口,在测试代码中,业务层实现了接口,可以直接使用@SysLog完成日志管理,业务层配置文件applicationContext_service.xml不需要做任何配置;
       控制层没有实现接口,默认通过Cglib实现动态代理,需要在springmvc.xml配置文件中,让Spring AOP强制使用cglib代理,这样才能在控制层使用@SysLog
添加的配置如下:

  <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

(8)
控制层代码:

@SysLog(operName = "查看自身贷款及应还款查询")
	@RequestMapping("queryLoanInfoByIdCard.action")
	public ModelAndView queryLoanInfoByIdCard(HttpServletRequest request){
		ModelAndView modelAndView = new ModelAndView();
		String idCard = ((User)request.getSession().getAttribute("user")).getIdCard();
		List<LoanInfo> infos = userService.queryLoanInfoByIdCard(idCard);
		modelAndView.addObject("infos", infos);
		modelAndView.setViewName("personalAllLoanInfo");
		String a = null;
		System.out.println(a.length());
		return modelAndView;
	}

业务层代码

SysLog(operName = "业务层")
	@Override
	public List<LoanInfo> queryLoanInfoByIdCard(String idCard) {
        List<LoanInfo> list = userMapper.queryLoanInfoByIdCard(idCard);
        logger.info("根据身份证号查询到的已贷款信息:"+list);
		return list;
	}

(9)代码执行后,数据库数据如下:
在这里插入图片描述
在后置通知和后置异常通知中,主要思路是:通过反射拿到类对象,通过类对象拿到所有方法,获取有指定注解的方法,再获取注解属性值,这样就可以在数据库中记录用户操作了哪些方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值