前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring AOP日志管理

spring AOP日志管理

作者头像
用户1212940
发布2018-01-23 11:09:40
1.6K0
发布2018-01-23 11:09:40
举报
文章被收录于专栏:LambdaLambda

Spring AOP 完成日志记录

SpringAOPAspectJsecurity日志记录

Spring AOP 完成日志记录

1、技术目标

  • 掌握Spring AOP基本用法
  • 使用Spring AOP完成日志记录功能

2、什么是AOP

AOP是Aspect Oriented Programming的缩写,意思是面向方面编程,AOP实际是GoF设计模式的延续

注意:关于AOP的详细介绍不是本文重点

3、关于Spring AOP的一些术语

  • 切面(Aspect):在Spring AOP中,切面可以使用通用类或者在普通类中以@Aspect 注解(@AspectJ风格)来实现
  • 连接点(Joinpoint):在Spring AOP中一个连接点代表一个方法的执行
  • 通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括"around"、"before”和"after"等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链
  • 切入点(Pointcut):定义出一个或一组方法,当执行这些方法时可产生通知,Spring缺省使用AspectJ切入点语法。

4、通知类型

  • 前置通知(@Before):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)
  • 返回后通知(@AfterReturning):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回
  • 抛出异常后通知(@AfterThrowing):方法抛出异常退出时执行的通知
  • 后通知(@After):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)
  • 环绕通知(@Around):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型,环绕通知可以在方法调用前后完成自定义的行为,它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行

5、@AspectJ风格的AOP配置

Spring AOP配置有两种风格:

  • XML风格 = 采用声明形式实现Spring AOP 
  • AspectJ风格 = 采用注解形式实现Spring AOP

注意:本文采用AspectJ风格

6、使用准备

闲话少说,下面开始日志记录的准备工作

6.1)创建日志记录表(MySQL),

Sql代码  

代码语言:js
复制
 CREATE TABLE `t_log` (  
   `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,  
   `userid` bigint(20) unsigned NOT NULL,  
   `createdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建日期',  
   `content` varchar(8000) NOT NULL DEFAULT '' COMMENT '日志内容',  
   `operation` varchar(250) NOT NULL DEFAULT '' COMMENT '用户所做的操作',  
  PRIMARY KEY (`id`)  
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  

Sql代码  

代码语言:js
复制
 CREATE TABLE `t_log` (  
   `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,  
   `userid` bigint(20) unsigned NOT NULL,  
   `createdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建日期',  
   `content` varchar(8000) NOT NULL DEFAULT '' COMMENT '日志内容',  
   `operation` varchar(250) NOT NULL DEFAULT '' COMMENT '用户所做的操作',  
  PRIMARY KEY (`id`)  
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  

6.2)在经过了Spring Security的权限验证后,可以从Security中获取到

登录管理员的帐号,而日志记录表t_log中存储的是管理员id,所以需要通

过管理员的帐号查询出管理员id,创建管理员POJO、Mapper、Service,

代码及配置如下:

管理员POJO类:

Java代码  

代码语言:js
复制
 package com.xxx.pojo;  
 public class Admin extends BaseDomain {  
  
  private String nickname;//管理员帐号 
  private String passwd;//管理员密码 
  private String phoneno;//联系电话 
  
  public String getNickname() {  
  return nickname;  
     }  
  public void setNickname(String nickname) {  
  this.nickname = nickname;  
     }  
  public String getPasswd() {  
  return passwd;  
     }  
  public void setPasswd(String passwd) {  
  this.passwd = passwd;  
     }  
  public String getPhoneno() {  
  return phoneno;  
     }  
  public void setPhoneno(String phoneno) {  
  this.phoneno = phoneno;  
     }  
 }  

Java代码  

代码语言:js
复制
 package com.xxx.pojo;  
 public class Admin extends BaseDomain {  
  
  private String nickname;//管理员帐号 
  private String passwd;//管理员密码 
  private String phoneno;//联系电话 
  
  public String getNickname() {  
  return nickname;  
     }  
  public void setNickname(String nickname) {  
  this.nickname = nickname;  
     }  
  public String getPasswd() {  
  return passwd;  
     }  
  public void setPasswd(String passwd) {  
  this.passwd = passwd;  
     }  
  public String getPhoneno() {  
  return phoneno;  
     }  
  public void setPhoneno(String phoneno) {  
  this.phoneno = phoneno;  
     }  
 }  

管理员Mapper接口与XML配置文件:

Java代码  

代码语言:js
复制
 package com.xxx.dao;  
  
 import com.xxx.pojo.Admin;  
 /** 
  * 管理员Mapper接口 
  */ 
 public interface AdminMapper {  
  /** 
      * 获取指定帐号名的管理员 
      */ 
  public Admin findAdminByNickname(String userName);  
 }  

Java代码  

代码语言:js
复制
 package com.xxx.dao;  
  
 import com.xxx.pojo.Admin;  
 /** 
  * 管理员Mapper接口 
  */ 
 public interface AdminMapper {  
  /** 
      * 获取指定帐号名的管理员 
      */ 
  public Admin findAdminByNickname(String userName);  
 }  

Xml代码  

代码语言:js
复制
 <?xml version="1.0" encoding="UTF-8"?> 
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"   
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 
 <mapper namespace="com.xxx.dao.AdminMapper"> 
  <!-- 通过账号名称查询管理员 --> 
  <select id="findAdminByNickname" parameterType="string" resultType="Admin"> 
     select * from t_admin where nickname=#{userName}  
  </select> 
 </mapper> 

Xml代码  

代码语言:js
复制
 <?xml version="1.0" encoding="UTF-8"?> 
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"   
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 
 <mapper namespace="com.xxx.dao.AdminMapper"> 
  <!-- 通过账号名称查询管理员 --> 
  <select id="findAdminByNickname" parameterType="string" resultType="Admin"> 
     select * from t_admin where nickname=#{userName}  
  </select> 
 </mapper> 

管理员Service接口与实现类:

Java代码  

代码语言:js
复制
 package com.xxx.service;  
  
 import com.xxx.pojo.Admin;  
  
 /** 
  * 管理员信息业务逻辑接口 
  */ 
 public interface AdminService {  
  /** 
      * 获取指定帐号名的管理员 
      */ 
  public Admin findAdminByNickname(String userName);  
 }  

Java代码  

代码语言:js
复制
 package com.xxx.service;  
  
 import com.xxx.pojo.Admin;  
  
 /** 
  * 管理员信息业务逻辑接口 
  */ 
 public interface AdminService {  
  /** 
      * 获取指定帐号名的管理员 
      */ 
  public Admin findAdminByNickname(String userName);  
 }  

Java代码  

代码语言:js
复制
 package com.xxx.service;  
  
 import org.springframework.beans.factory.annotation.Autowired;  
 import com.xxx.dao.AdminMapper;  
 import com.xxx.pojo.Admin;  
  
 public class AdminServiceImpl implements AdminService {  
  @Autowired 
  private AdminMapper adminMapper;//Mapper接口 
  
  public Admin findAdminByNickname(String userName) {  
  return adminMapper.findAdminByNickname(userName);  
     }  
 }  

Java代码  

代码语言:js
复制
 package com.xxx.service;  
  
 import org.springframework.beans.factory.annotation.Autowired;  
 import com.xxx.dao.AdminMapper;  
 import com.xxx.pojo.Admin;  
  
 public class AdminServiceImpl implements AdminService {  
  @Autowired 
  private AdminMapper adminMapper;//Mapper接口 
  
  public Admin findAdminByNickname(String userName) {  
  return adminMapper.findAdminByNickname(userName);  
     }  
 }  

6.3)创建日志记录POJO、Mapper、Service,代码及配置如下:

日志记录POJO类:

Java代码  

代码语言:js
复制
 package com.xxx.pojo;  
  
 import java.io.Serializable;  
 import java.util.Date;  
  
 /** 
  * 日志记录POJO 
  */ 
 public class Log extends BaseDomain implements Serializable{  
  
  private static final long serialVersionUID = 1024792477652984770L;  
  
  private Long userid;//管理员id 
  private Date createdate;//日期 
  private String content;//日志内容 
  private String operation;//操作(主要是"添加"、"修改"、"删除") 
  
  //getter、setter,此处省略N字(你懂的) 
 }  

Java代码  

代码语言:js
复制
 package com.xxx.pojo;  
  
 import java.io.Serializable;  
 import java.util.Date;  
  
 /** 
  * 日志记录POJO 
  */ 
 public class Log extends BaseDomain implements Serializable{  
  
  private static final long serialVersionUID = 1024792477652984770L;  
  
  private Long userid;//管理员id 
  private Date createdate;//日期 
  private String content;//日志内容 
  private String operation;//操作(主要是"添加"、"修改"、"删除") 
  
  //getter、setter,此处省略N字(你懂的) 
 }  

日志记录Mapper接口与XML配置文件:

Java代码  

代码语言:js
复制
 package com.xxx.dao;  
  
 import com.xxx.pojo.Log;  
  
 /** 
  * 日志记录Mapper 
  */ 
 public interface LogMapper {  
  
  public void insert(Log log);//添加日志记录 
 }  

Java代码  

代码语言:js
复制
 package com.xxx.dao;  
  
 import com.xxx.pojo.Log;  
  
 /** 
  * 日志记录Mapper 
  */ 
 public interface LogMapper {  
  
  public void insert(Log log);//添加日志记录 
 }  

Xml代码  

代码语言:js
复制
 <?xml version="1.0" encoding="UTF-8"?> 
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"   
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 
 <mapper namespace="com.xxx.dao.LogMapper"> 
  <!-- 添加日志记录 --> 
  <insert id="insert" parameterType="Log"> 
         INSERT INTO t_log(userid,createdate,operation,content)  
         VALUES(#{userid},NOW(),#{operation},#{content});  
  </insert> 
 </mapper> 

Xml代码  

代码语言:js
复制
 <?xml version="1.0" encoding="UTF-8"?> 
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"   
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 
 <mapper namespace="com.xxx.dao.LogMapper"> 
  <!-- 添加日志记录 --> 
  <insert id="insert" parameterType="Log"> 
         INSERT INTO t_log(userid,createdate,operation,content)  
         VALUES(#{userid},NOW(),#{operation},#{content});  
  </insert> 
 </mapper> 

日志记录Service接口与实现类:

Java代码  

代码语言:js
复制
 package com.xxx.service;  
  
 import org.springframework.transaction.annotation.Transactional;  
 import com.xxx.pojo.Log;  
  
 /** 
  * 日志记录业务逻辑接口 
  */ 
 public interface LogService {  
  
  /** 
      * 日志记录 
      * @param log 
      */ 
  @Transactional 
  public void log(Log log);  
  
  /** 
      * 获取登录管理员ID 
      */ 
  public Long loginUserId();  
 }  

Java代码  

代码语言:js
复制
 package com.xxx.service;  
  
 import org.springframework.transaction.annotation.Transactional;  
 import com.xxx.pojo.Log;  
  
 /** 
  * 日志记录业务逻辑接口 
  */ 
 public interface LogService {  
  
  /** 
      * 日志记录 
      * @param log 
      */ 
  @Transactional 
  public void log(Log log);  
  
  /** 
      * 获取登录管理员ID 
      */ 
  public Long loginUserId();  
 } 

Java代码  

代码语言:js
复制
 package com.xxx.service;  
  
 import org.springframework.beans.factory.annotation.Autowired;  
 import org.springframework.security.core.context.SecurityContextHolder;  
 import org.springframework.security.core.userdetails.UserDetails;  
 import com.xxx.dao.LogMapper;  
 import com.xxx.pojo.Admin;  
 import com.xxx.pojo.Log;  
  
 /** 
  * 日志记录业务逻辑接口实现类 
  * @author HotStrong 
  */ 
 public class LogServiceImpl implements LogService{  
  
  @Autowired 
  private AdminService adminService;  
  
  @Autowired 
  private LogMapper logMapper;  
  
  public void log(Log log) {  
         logMapper.insert(log);  
     }  
  
  /** 
      * 获取登录管理员ID 
      *  
      * @return 
      */ 
  public Long loginUserId() {  
  
  if(SecurityContextHolder.getContext() == null){  
  return null;  
         }  
  
  if(SecurityContextHolder.getContext().getAuthentication() == null){  
  return null;  
         }  
  
         UserDetails userDetails = (UserDetails) SecurityContextHolder  
                 .getContext().getAuthentication().getPrincipal();  
  
  if(userDetails == null){  
  return null;  
         }  
  
  //获取登录管理员帐号名 
         String userName = userDetails.getUsername();  
  
  if(userName == null || userName.equals("")){  
  return null;  
         }  
  
  // 根据管理员帐号名获取帐号ID 
         Admin admin = this.adminService.findAdminByNickname(userName);  
  
  if(admin == null){  
  return null;  
         }  
  
  return admin.getId();  
     }  
 }  

Java代码  

代码语言:js
复制
 package com.xxx.service;  
  
 import org.springframework.beans.factory.annotation.Autowired;  
 import org.springframework.security.core.context.SecurityContextHolder;  
 import org.springframework.security.core.userdetails.UserDetails;  
 import com.xxx.dao.LogMapper;  
 import com.xxx.pojo.Admin;  
 import com.xxx.pojo.Log;  
  
 /** 
  * 日志记录业务逻辑接口实现类 
  * @author HotStrong 
  */ 
 public class LogServiceImpl implements LogService{  
  
  @Autowired 
  private AdminService adminService;  
  
  @Autowired 
  private LogMapper logMapper;  
  
  public void log(Log log) {  
         logMapper.insert(log);  
     }  
  
  /** 
      * 获取登录管理员ID 
      *  
      * @return 
      */ 
  public Long loginUserId() {  
  
  if(SecurityContextHolder.getContext() == null){  
  return null;  
         }  
  
  if(SecurityContextHolder.getContext().getAuthentication() == null){  
  return null;  
         }  
  
         UserDetails userDetails = (UserDetails) SecurityContextHolder  
                 .getContext().getAuthentication().getPrincipal();  
  
  if(userDetails == null){  
  return null;  
         }  
  
  //获取登录管理员帐号名 
         String userName = userDetails.getUsername();  
  
  if(userName == null || userName.equals("")){  
  return null;  
         }  
  
  // 根据管理员帐号名获取帐号ID 
         Admin admin = this.adminService.findAdminByNickname(userName);  
  
  if(admin == null){  
  return null;  
         }  
  
  return admin.getId();  
     }  
 }  

7、在MyBatis配置文件mybatis-config.xml中配置POJO,如下:

Xml代码  

代码语言:js
复制
 <?xml version="1.0" encoding="UTF-8"?> 
 <!DOCTYPE configuration  
     PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
     "http://mybatis.org/dtd/mybatis-3-config.dtd"> 
 <configuration> 
  <settings> 
  <!-- changes from the defaults --> 
  <setting name="lazyLoadingEnabled" value="false" /> 
  </settings> 
  <typeAliases> 
  <typeAlias alias="Film" type="com.xxx.pojo.Film"/> 
  <typeAlias alias="Admin" type="com.xxx.pojo.Admin"/> 
  <typeAlias alias="Log" type="com.xxx.pojo.Log"/> 
  </typeAliases> 
 </configuration> 

Xml代码  

代码语言:js
复制
 <?xml version="1.0" encoding="UTF-8"?> 
 <!DOCTYPE configuration  
     PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
     "http://mybatis.org/dtd/mybatis-3-config.dtd"> 
 <configuration> 
  <settings> 
  <!-- changes from the defaults --> 
  <setting name="lazyLoadingEnabled" value="false" /> 
  </settings> 
  <typeAliases> 
  <typeAlias alias="Film" type="com.xxx.pojo.Film"/> 
  <typeAlias alias="Admin" type="com.xxx.pojo.Admin"/> 
  <typeAlias alias="Log" type="com.xxx.pojo.Log"/> 
  </typeAliases> 
 </configuration> 

8、创建aop包,在aop包下创建切面类LogAspect

Java代码  

代码语言:js
复制
 package com.xxx.aop;  
  
 import java.lang.reflect.Method;  
 import java.util.Date;  
  
 import org.aspectj.lang.JoinPoint;  
 import org.aspectj.lang.ProceedingJoinPoint;  
 import org.aspectj.lang.annotation.AfterReturning;  
 import org.aspectj.lang.annotation.Around;  
 import org.aspectj.lang.annotation.Aspect;  
 import org.aspectj.lang.annotation.Pointcut;  
 import org.springframework.beans.factory.annotation.Autowired;  
  
 import com.xxx.pojo.Film;  
 import com.xxx.pojo.Log;  
 import com.xxx.service.FilmService;  
 import com.xxx.service.LogService;  
  
 /** 
  * 日志记录,添加、删除、修改方法AOP 
  * @author HotStrong 
  *  
  */ 
 @Aspect 
 public class LogAspect {  
  
  @Autowired 
  private LogService logService;//日志记录Service 
  
  @Autowired 
  private FilmService filmService;//影片Service 
  
  /** 
      * 添加业务逻辑方法切入点 
      */ 
  @Pointcut("execution(* com.xxx.service.*.insert*(..))")  
  public void insertServiceCall() { }  
  
  /** 
      * 修改业务逻辑方法切入点 
      */ 
  @Pointcut("execution(* com.xxx.service.*.update*(..))")  
  public void updateServiceCall() { }  
  
  /** 
      * 删除影片业务逻辑方法切入点 
      */ 
  @Pointcut("execution(* com.xxx.service.FilmService.deleteFilm(..))")  
  public void deleteFilmCall() { }  
  
  /** 
      * 管理员添加操作日志(后置通知) 
      * @param joinPoint 
      * @param rtv 
      * @throws Throwable 
      */ 
  @AfterReturning(value="insertServiceCall()", argNames="rtv", returning="rtv")  
  public void insertServiceCallCalls(JoinPoint joinPoint, Object rtv) throws Throwable{  
  
  //获取登录管理员id 
         Long adminUserId = logService.loginUserId();  
  
  if(adminUserId == null){//没有管理员登录 
  return;  
         }  
  
  //判断参数 
  if(joinPoint.getArgs() == null){//没有参数 
  return;  
         }  
  
  //获取方法名 
         String methodName = joinPoint.getSignature().getName();  
  
  //获取操作内容 
         String opContent = adminOptionContent(joinPoint.getArgs(), methodName);  
  
  //创建日志对象 
         Log log = new Log();  
         log.setUserid(logService.loginUserId());//设置管理员id 
         log.setCreatedate(new Date());//操作时间 
         log.setContent(opContent);//操作内容 
         log.setOperation("添加");//操作 
  
         logService.log(log);//添加日志 
     }  
  
  /** 
      * 管理员修改操作日志(后置通知) 
      * @param joinPoint 
      * @param rtv 
      * @throws Throwable 
      */ 
  @AfterReturning(value="updateServiceCall()", argNames="rtv", returning="rtv")  
  public void updateServiceCallCalls(JoinPoint joinPoint, Object rtv) throws Throwable{  
  
  //获取登录管理员id 
         Long adminUserId = logService.loginUserId();  
  
  if(adminUserId == null){//没有管理员登录 
  return;  
         }  
  
  //判断参数 
  if(joinPoint.getArgs() == null){//没有参数 
  return;  
         }  
  
  //获取方法名 
         String methodName = joinPoint.getSignature().getName();  
  
  //获取操作内容 
         String opContent = adminOptionContent(joinPoint.getArgs(), methodName);  
  
  //创建日志对象 
         Log log = new Log();  
         log.setUserid(logService.loginUserId());//设置管理员id 
         log.setCreatedate(new Date());//操作时间 
         log.setContent(opContent);//操作内容 
         log.setOperation("修改");//操作 
  
         logService.log(log);//添加日志 
     }  
  
  /** 
      * 管理员删除影片操作(环绕通知),使用环绕通知的目的是 
      * 在影片被删除前可以先查询出影片信息用于日志记录 
      * @param joinPoint 
      * @param rtv 
      * @throws Throwable 
      */ 
  @Around(value="deleteFilmCall()", argNames="rtv")  
  public Object deleteFilmCallCalls(ProceedingJoinPoint pjp) throws Throwable {  
  
         Object result = null;  
  //环绕通知处理方法 
  try {  
  
  //获取方法参数(被删除的影片id) 
             Integer id = (Integer)pjp.getArgs()[0];  
             Film obj = null;//影片对象 
  if(id != null){  
  //删除前先查询出影片对象 
                 obj = filmService.getFilmById(id);  
             }  
  
  //执行删除影片操作 
             result = pjp.proceed();  
  
  if(obj != null){  
  
  //创建日志对象 
                 Log log = new Log();  
                 log.setUserid(logService.loginUserId());//用户编号 
                 log.setCreatedate(new Date());//操作时间 
  
                 StringBuffer msg = new StringBuffer("影片名 : ");  
                 msg.append(obj.getFname());  
                 log.setContent(msg.toString());//操作内容 
  
                 log.setOperation("删除");//操作 
  
                 logService.log(log);//添加日志 
             }  
  
          }  
  catch(Exception ex) {  
             ex.printStackTrace();  
          }  
  
  return result;  
     }  
  
  /** 
      * 使用Java反射来获取被拦截方法(insert、update)的参数值, 
      * 将参数值拼接为操作内容 
      */ 
  public String adminOptionContent(Object[] args, String mName) throws Exception{  
  
  if (args == null) {  
  return null;  
         }  
  
         StringBuffer rs = new StringBuffer();  
         rs.append(mName);  
         String className = null;  
  int index = 1;  
  // 遍历参数对象 
  for (Object info : args) {  
  
  //获取对象类型 
             className = info.getClass().getName();  
             className = className.substring(className.lastIndexOf(".") + 1);  
             rs.append("[参数" + index + ",类型:" + className + ",值:");  
  
  // 获取对象的所有方法 
             Method[] methods = info.getClass().getDeclaredMethods();  
  
  // 遍历方法,判断get方法 
  for (Method method : methods) {  
  
                 String methodName = method.getName();  
  // 判断是不是get方法 
  if (methodName.indexOf("get") == -1) {// 不是get方法 
  continue;// 不处理 
                 }  
  
                 Object rsValue = null;  
  try {  
  
  // 调用get方法,获取返回值 
                     rsValue = method.invoke(info);  
  
  if (rsValue == null) {//没有返回值 
  continue;  
                     }  
  
                 } catch (Exception e) {  
  continue;  
                 }  
  
  //将值加入内容中 
                 rs.append("(" + methodName + " : " + rsValue + ")");  
             }  
  
             rs.append("]");  
  
             index++;  
         }  
  
  return rs.toString();  
     }  
  
 }  

Java代码  

代码语言:js
复制
 package com.xxx.aop;  
  
 import java.lang.reflect.Method;  
 import java.util.Date;  
  
 import org.aspectj.lang.JoinPoint;  
 import org.aspectj.lang.ProceedingJoinPoint;  
 import org.aspectj.lang.annotation.AfterReturning;  
 import org.aspectj.lang.annotation.Around;  
 import org.aspectj.lang.annotation.Aspect;  
 import org.aspectj.lang.annotation.Pointcut;  
 import org.springframework.beans.factory.annotation.Autowired;  
  
 import com.xxx.pojo.Film;  
 import com.xxx.pojo.Log;  
 import com.xxx.service.FilmService;  
 import com.xxx.service.LogService;  
  
 /** 
  * 日志记录,添加、删除、修改方法AOP 
  * @author HotStrong 
  *  
  */ 
 @Aspect 
 public class LogAspect {  
  
  @Autowired 
  private LogService logService;//日志记录Service 
  
  @Autowired 
  private FilmService filmService;//影片Service 
  
  /** 
      * 添加业务逻辑方法切入点 
      */ 
  @Pointcut("execution(* com.xxx.service.*.insert*(..))")  
  public void insertServiceCall() { }  
  
  /** 
      * 修改业务逻辑方法切入点 
      */ 
  @Pointcut("execution(* com.xxx.service.*.update*(..))")  
  public void updateServiceCall() { }  
  
  /** 
      * 删除影片业务逻辑方法切入点 
      */ 
  @Pointcut("execution(* com.xxx.service.FilmService.deleteFilm(..))")  
  public void deleteFilmCall() { }  
  
  /** 
      * 管理员添加操作日志(后置通知) 
      * @param joinPoint 
      * @param rtv 
      * @throws Throwable 
      */ 
  @AfterReturning(value="insertServiceCall()", argNames="rtv", returning="rtv")  
  public void insertServiceCallCalls(JoinPoint joinPoint, Object rtv) throws Throwable{  
  
  //获取登录管理员id 
         Long adminUserId = logService.loginUserId();  
  
  if(adminUserId == null){//没有管理员登录 
  return;  
         }  
  
  //判断参数 
  if(joinPoint.getArgs() == null){//没有参数 
  return;  
         }  
  
  //获取方法名 
         String methodName = joinPoint.getSignature().getName();  
  
  //获取操作内容 
         String opContent = adminOptionContent(joinPoint.getArgs(), methodName);  
  
  //创建日志对象 
         Log log = new Log();  
         log.setUserid(logService.loginUserId());//设置管理员id 
         log.setCreatedate(new Date());//操作时间 
         log.setContent(opContent);//操作内容 
         log.setOperation("添加");//操作 
  
         logService.log(log);//添加日志 
     }  
  
  /** 
      * 管理员修改操作日志(后置通知) 
      * @param joinPoint 
      * @param rtv 
      * @throws Throwable 
      */ 
  @AfterReturning(value="updateServiceCall()", argNames="rtv", returning="rtv")  
  public void updateServiceCallCalls(JoinPoint joinPoint, Object rtv) throws Throwable{  
  
  //获取登录管理员id 
         Long adminUserId = logService.loginUserId();  
  
  if(adminUserId == null){//没有管理员登录 
  return;  
         }  
  
  //判断参数 
  if(joinPoint.getArgs() == null){//没有参数 
  return;  
         }  
  
  //获取方法名 
         String methodName = joinPoint.getSignature().getName();  
  
  //获取操作内容 
         String opContent = adminOptionContent(joinPoint.getArgs(), methodName);  
  
  //创建日志对象 
         Log log = new Log();  
         log.setUserid(logService.loginUserId());//设置管理员id 
         log.setCreatedate(new Date());//操作时间 
         log.setContent(opContent);//操作内容 
         log.setOperation("修改");//操作 
  
         logService.log(log);//添加日志 
     }  
  
  /** 
      * 管理员删除影片操作(环绕通知),使用环绕通知的目的是 
      * 在影片被删除前可以先查询出影片信息用于日志记录 
      * @param joinPoint 
      * @param rtv 
      * @throws Throwable 
      */ 
  @Around(value="deleteFilmCall()", argNames="rtv")  
  public Object deleteFilmCallCalls(ProceedingJoinPoint pjp) throws Throwable {  
  
         Object result = null;  
  //环绕通知处理方法 
  try {  
  
  //获取方法参数(被删除的影片id) 
             Integer id = (Integer)pjp.getArgs()[0];  
             Film obj = null;//影片对象 
  if(id != null){  
  //删除前先查询出影片对象 
                 obj = filmService.getFilmById(id);  
             }  
  
  //执行删除影片操作 
             result = pjp.proceed();  
  
  if(obj != null){  
  
  //创建日志对象 
                 Log log = new Log();  
                 log.setUserid(logService.loginUserId());//用户编号 
                 log.setCreatedate(new Date());//操作时间 
  
                 StringBuffer msg = new StringBuffer("影片名 : ");  
                 msg.append(obj.getFname());  
                 log.setContent(msg.toString());//操作内容 
  
                 log.setOperation("删除");//操作 
  
                 logService.log(log);//添加日志 
             }  
  
          }  
  catch(Exception ex) {  
             ex.printStackTrace();  
          }  
  
  return result;  
     }  
  
  /** 
      * 使用Java反射来获取被拦截方法(insert、update)的参数值, 
      * 将参数值拼接为操作内容 
      */ 
  public String adminOptionContent(Object[] args, String mName) throws Exception{  
  
  if (args == null) {  
  return null;  
         }  
  
         StringBuffer rs = new StringBuffer();  
         rs.append(mName);  
         String className = null;  
  int index = 1;  
  // 遍历参数对象 
  for (Object info : args) {  
  
  //获取对象类型 
             className = info.getClass().getName();  
             className = className.substring(className.lastIndexOf(".") + 1);  
             rs.append("[参数" + index + ",类型:" + className + ",值:");  
  
  // 获取对象的所有方法 
             Method[] methods = info.getClass().getDeclaredMethods();  
  
  // 遍历方法,判断get方法 
  for (Method method : methods) {  
  
                 String methodName = method.getName();  
  // 判断是不是get方法 
  if (methodName.indexOf("get") == -1) {// 不是get方法 
  continue;// 不处理 
                 }  
  
                 Object rsValue = null;  
  try {  
  
  // 调用get方法,获取返回值 
                     rsValue = method.invoke(info);  
  
  if (rsValue == null) {//没有返回值 
  continue;  
                     }  
  
                 } catch (Exception e) {  
  continue;  
                 }  
  
  //将值加入内容中 
                 rs.append("(" + methodName + " : " + rsValue + ")");  
             }  
  
             rs.append("]");  
  
             index++;  
         }  
  
  return rs.toString();  
     }  
  
 }  

9、对管理员登录操作进行日志记录

还记得《使用Spring Security实现权限管理》一文中第7步提到的两个类吗?其中LoginSuccessHandler类中可以记录管理员的登录操作,代码如下:

Java代码  

代码语言:js
复制
 package com.xxx.security;  
  
 import java.io.IOException;  
 import java.util.Date;  
  
 import javax.servlet.ServletException;  
 import javax.servlet.http.HttpServletRequest;  
 import javax.servlet.http.HttpServletResponse;  
  
 import org.springframework.beans.factory.annotation.Autowired;  
 import org.springframework.security.core.Authentication;  
 import org.springframework.security.core.userdetails.UserDetails;  
 import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;  
  
 import com.xxx.pojo.Log;  
 import com.xxx.service.LogService;  
  
 /** 
  * 处理管理登录日志 
  * 
  */ 
 public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{  
  
  @Autowired 
  private LogService logService;//日志记录Service 
  
  @Override 
  public void onAuthenticationSuccess(HttpServletRequest request,  
             HttpServletResponse response, Authentication authentication) throws IOException,  
             ServletException {  
  
         UserDetails userDetails = (UserDetails)authentication.getPrincipal();  
  
  //创建日志对象 
         Log log = new Log();  
         log.setUserid(logService.loginUserId());//设置管理员id 
         log.setCreatedate(new Date());//操作时间 
         log.setContent("管理员 " + userDetails.getUsername());//操作内容 
         log.setOperation("登录");//操作 
  
         logService.log(log);//添加日志 
  
  super.onAuthenticationSuccess(request, response, authentication);  
     }  
  
 }  

Java代码  

代码语言:js
复制
 package com.xxx.security;  
  
 import java.io.IOException;  
 import java.util.Date;  
  
 import javax.servlet.ServletException;  
 import javax.servlet.http.HttpServletRequest;  
 import javax.servlet.http.HttpServletResponse;  
  
 import org.springframework.beans.factory.annotation.Autowired;  
 import org.springframework.security.core.Authentication;  
 import org.springframework.security.core.userdetails.UserDetails;  
 import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;  
  
 import com.xxx.pojo.Log;  
 import com.xxx.service.LogService;  
  
 /** 
  * 处理管理登录日志 
  * 
  */ 
 public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{  
  
  @Autowired 
  private LogService logService;//日志记录Service 
  
  @Override 
  public void onAuthenticationSuccess(HttpServletRequest request,  
             HttpServletResponse response, Authentication authentication) throws IOException,  
             ServletException {  
  
         UserDetails userDetails = (UserDetails)authentication.getPrincipal();  
  
  //创建日志对象 
         Log log = new Log();  
         log.setUserid(logService.loginUserId());//设置管理员id 
         log.setCreatedate(new Date());//操作时间 
         log.setContent("管理员 " + userDetails.getUsername());//操作内容 
         log.setOperation("登录");//操作 
  
         logService.log(log);//添加日志 
  
  super.onAuthenticationSuccess(request, response, authentication);  
     }  
  
 }  

10、在applicationContext-services.xml中加入新的配置

applicationContext-services.xml中加入了Aspectj配置以及新增的管理员Service、日志记录Service配置:

Xml代码  

代码语言:js
复制
 <?xml version="1.0" encoding="UTF-8"?> 
 <beans xmlns="http://www.springframework.org/schema/beans" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:aop="http://www.springframework.org/schema/aop" 
  xmlns:tx="http://www.springframework.org/schema/tx" 
  xsi:schemaLocation="  
             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
             http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 
  
  <!-- 加入Aspectj配置 --> 
  <aop:aspectj-autoproxy /> 
  <bean id="logAspect" class="com.xxx.aop.LogAspect" /> 
  
  <!-- 电影业务逻辑对象 --> 
  <bean id="filmService" class="com.xxx.service.FilmServiceImpl"></bean> 
  
  <!-- 管理员业务逻辑对象 --> 
  <bean id="adminService" class="com.xxx.service.AdminServiceImpl"></bean> 
  
  <!-- 日志记录业务逻辑对象 --> 
  <bean id="logService" class="com.xxx.service.LogServiceImpl"></bean> 
  
 </beans> 

Xml代码  

代码语言:js
复制
 <?xml version="1.0" encoding="UTF-8"?> 
 <beans xmlns="http://www.springframework.org/schema/beans" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:aop="http://www.springframework.org/schema/aop" 
  xmlns:tx="http://www.springframework.org/schema/tx" 
  xsi:schemaLocation="  
             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
             http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 
  
  <!-- 加入Aspectj配置 --> 
  <aop:aspectj-autoproxy /> 
  <bean id="logAspect" class="com.xxx.aop.LogAspect" /> 
  
  <!-- 电影业务逻辑对象 --> 
  <bean id="filmService" class="com.xxx.service.FilmServiceImpl"></bean> 
  
  <!-- 管理员业务逻辑对象 --> 
  <bean id="adminService" class="com.xxx.service.AdminServiceImpl"></bean> 
  
  <!-- 日志记录业务逻辑对象 --> 
  <bean id="logService" class="com.xxx.service.LogServiceImpl"></bean> 
  
 </beans> 

11、配置成功后分别进行登录、添加、修改、删除影片操作

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015-12-19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Spring AOP 完成日志记录
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档