Spring 自定义注解和AOP结合实现方法操作日志管理

该功能是参照https://www.cnblogs.com/jianjianyang/p/4910851.html一文实现的。

以UAP项目为例:Spring版本3.1,JDK版本1.8,TOMCAT版本8.5,数据库技术为myBatis

1、在spring-service.xml中添加以下代码,启动对@AspectJ注解的支持:

  <aop:aspectj-autoproxy/>

     在其他相关博客中看到使用该标签时将其属性proxy-target-class设为了true,代表强制使用cglib代理(该属性默认是false,如果你的类实现了接口就走JDK代理,如果没有,走cglib代理),但在我的项目里如果设为了true,会在项目启动时报错,具体报错原因尚未深究,留待后面处理。

    (注:对于单利模式建议使用cglib代理,虽然JDK动态代理比cglib代理速度快,但性能不如cglib ----> 具体说明可看:http://blog.csdn.net/kingson_wu/article/details/50864637

2、创建日志实体对象:

  1 package com.bw.scpw.model;
  2 
  3 import java.util.Date;
  4 
  5 import com.bw.core.model.BaseModel;
  6 import com.bw.core.model.IBaseModel;
  7 
  8 public class SystemLog extends BaseModel implements IBaseModel
  9 {
 10     /** id */
 11     private String id;
 12     /** 模块名 */
 13     private String model;
 14     /** 方法名 */
 15     private String method;
 16     /** 请求ip地址 */
 17     private String requestIp;
 18     /** 方法参数 */
 19     private String params;
 20     /** 操作人 */
 21     private String creator;
 22     /** 操作人id */
 23     private String creatorId;
 24     /** 操作时间 */
 25     private Date createDate;
 26     /** 操作时间 开始时间 */
 27     private String createDateBegin;
 28     /** 操作时间 结束时间 */
 29     private String createDateEnd;
 30 
 31     /**
 32      * id
 33      * @return
 34      */
 35     public String getId()
 36     {
 37         return id;
 38     }
 39 
 40     /**
 41      * id
 42      * @param id
 43      */
 44     public void setId(String id)
 45     {
 46         this.id = id;
 47     }
 48 
 49     /**
 50      * 模块名
 51      * @return
 52      */
 53     public String getModel()
 54     {
 55         return model;
 56     }
 57 
 58     /**
 59      * 模块名
 60      * @param model
 61      */
 62     public void setModel(String model)
 63     {
 64         this.model = model;
 65     }
 66 
 67     /**
 68      * 方法名
 69      * @return
 70      */
 71     public String getMethod()
 72     {
 73         return method;
 74     }
 75 
 76     /**
 77      * 方法名
 78      * @param method
 79      */
 80     public void setMethod(String method)
 81     {
 82         this.method = method;
 83     }
 84 
 85     /**
 86      * 请求ip
 87      * @return
 88      */
 89     public String getRequestIp()
 90     {
 91         return requestIp;
 92     }
 93 
 94     /**
 95      * 请求ip
 96      * @param requestIp
 97      */
 98     public void setRequestIp(String requestIp)
 99     {
100         this.requestIp = requestIp;
101     }
102 
103     /**
104      * 请求参数
105      * @return
106      */
107     public String getParams()
108     {
109         return params;
110     }
111 
112     /**
113      * 请求参数
114      * @param params
115      */
116     public void setParams(String params)
117     {
118         this.params = params;
119     }
120 
121     /**
122      * 操作人
123      * @return
124      */
125     public String getCreator()
126     {
127         return creator;
128     }
129 
130     /**
131      * 操作人
132      * @param creator
133      */
134     public void setCreator(String creator)
135     {
136         this.creator = creator;
137     }
138 
139     /**
140      * 操作人id
141      * @return
142      */
143     public String getCreatorId()
144     {
145         return creatorId;
146     }
147 
148     /**
149      * 操作人id
150      * @param creatorId
151      */
152     public void setCreatorId(String creatorId)
153     {
154         this.creatorId = creatorId;
155     }
156 
157     /**
158      * 操作时间
159      * @return
160      */
161     public Date getCreateDate()
162     {
163         return createDate;
164     }
165 
166     /**
167      * 操作时间
168      * @param createDate
169      */
170     public void setCreateDate(Date createDate)
171     {
172         this.createDate = createDate;
173     }
174 
175     /**
176      * 操作时间 开始时间
177      * @param createDateBegin
178      */
179     public void setCreateDateBegin(String createDateBegin)
180     {
181         this.createDateBegin = createDateBegin;
182     }
183 
184     /**
185      * 操作时间 开始时间
186      * @return
187      */
188     public String getCreateDateBegin()
189     {
190         return createDateBegin;
191     }
192 
193     /**
194      * 操作时间 结束时间
195      * @param CreateDateEnd
196      */
197     public void setCreateDateEnd(String createDateEnd)
198     {
199         this.createDateEnd = createDateEnd;
200     }
201 
202     /**
203      * 操作时间 结束时间
204      * @return
205      */
206     public String getCreateDateEnd()
207     {
208         return createDateEnd;
209     }
210 
211 }
View Code

3、编写dao层、service层的接口和实现类(因为该项目已有dao层、service层的底层实现,直接继承父类即可,所以此处无具体代码):

 1 package com.bw.scpw.dao.impl;
 2 
 3 import com.bw.core.dao.impl.IBaseDaoImpl;
 4 import com.bw.scpw.model.SystemLog;
 5 
 6 /**
 7  * 系统操作日志DAO层
 8  * @author liying 2019年7月2日
 9  */
10 public class SystemLogDao extends IBaseDaoImpl<SystemLog>
11 {
12 
13 }
View Code
 1 package com.bw.scpw.service;
 2 
 3 import com.bw.core.service.IBaseService;
 4 import com.bw.scpw.model.SystemLog;
 5 
 6 /**
 7  * 系统操作日志service层
 8  * @author liying 2019年7月2日
 9  */
10 public interface SystemLogService extends IBaseService<SystemLog>
11 {
12 
13 }
View Code
 1 package com.bw.scpw.service.impl;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.stereotype.Service;
 5 
 6 import com.bw.core.dao.IBaseDao;
 7 import com.bw.core.service.impl.BaseServiceImpl;
 8 import com.bw.scpw.dao.impl.SystemLogDao;
 9 import com.bw.scpw.model.SystemLog;
10 import com.bw.scpw.service.SystemLogService;
11 
12 /**
13  * 系统操作日志service层实现类
14  * @author liying 2019年7月2日
15  */
16 @Service("systemLogService")
17 public class SystemLogServiceImpl extends BaseServiceImpl<SystemLog> implements SystemLogService
18 {
19 
20     @Autowired
21     private SystemLogDao systemLogDao;
22 
23     @Override
24     protected IBaseDao<SystemLog> getBaseDao()
25     {
26         return systemLogDao;
27     }
28 
29 }
View Code

    注:service层的实现类中对dao层实现类的引用是通过@Autowired注解的,因此dao层类需在项目启动时就注册好,否则会报因找不到对象而自动注入失败的错。注册方式(选其一即可):

  (1)在spring-dao.xml中添加以下代码:<bean id="systemLogDao" class="com.bw.scpw.dao.impl.SystemLogDao" parent="bizBaseDAO" />;

  (2)在dao层实现类名上添加@Service注解:@Service("systemLogDao")。

4、自定义注解:

 1 package com.bw.scpw.annotation;
 2 
 3 import java.lang.annotation.Documented;
 4 import java.lang.annotation.ElementType;
 5 import java.lang.annotation.Retention;
 6 import java.lang.annotation.RetentionPolicy;
 7 import java.lang.annotation.Target;
 8 
 9 /**
10  * 保存method操作日志
11  * @author liying 2019年7月3日
12  */
13 @Target(ElementType.METHOD)
14 @Retention(RetentionPolicy.RUNTIME)
15 @Documented
16 public @interface Log
17 {
18 
19 }
View Code

    注:后续添加注解说明。

5、编写AOP切面代码

  1 package com.bw.scpw.annotation;
  2 
  3 import java.util.Date;
  4 
  5 import javax.annotation.Resource;
  6 import javax.servlet.ServletRequest;
  7 import javax.servlet.ServletResponse;
  8 import javax.servlet.http.HttpServletRequest;
  9 
 10 import org.apache.commons.lang.StringUtils;
 11 import org.aspectj.lang.JoinPoint;
 12 import org.aspectj.lang.annotation.After;
 13 import org.aspectj.lang.annotation.Aspect;
 14 import org.aspectj.lang.annotation.Pointcut;
 15 import org.slf4j.Logger;
 16 import org.slf4j.LoggerFactory;
 17 import org.springframework.stereotype.Component;
 18 import org.springframework.web.context.request.RequestContextHolder;
 19 import org.springframework.web.context.request.ServletRequestAttributes;
 20 
 21 import com.bw.scpw.isc.help.SysUser;
 22 import com.bw.scpw.isc.help.SysUserUtil;
 23 import com.bw.scpw.model.SystemLog;
 24 import com.bw.scpw.service.SystemLogService;
 25 
 26 import net.sf.json.JSONArray;
 27 
 28 /**
 29  * 操作日志保存
 30  * @author liying 2019年7月3日
 31  */
 32 @Aspect
 33 @Component
 34 public class SystemLogAspect
 35 {
 36     private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);
 37 
 38     @Resource
 39     private SystemLogService systemLogService;
 40 
 41     // 切点
 42     @Pointcut("@annotation(com.bw.scpw.annotation.Log)")
 43     public void methodLogAspect()
 44     {
 45     }
 46 
 47     /**
 48      * 后置通知 用于拦截Controller层记录用户的操作
 49      * @param joinPoint 切点
 50      */
 51     @After("methodLogAspect()")
 52     public void after(JoinPoint joinPoint)
 53     {
 54         try
 55         {
 56             SysUser user = SysUserUtil.getUser();
 57             HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
 58             // *========控制台输出=========*//
 59             System.out.println("=====methodLog后置通知开始=====");
 60             System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
 61             System.out.println("请求人:" + user.getUserName());
 62             System.out.println("请求IP:" + getCliectIp(request));
 63             // *========数据库日志=========*//
 64             SystemLog log = new SystemLog();
 65             log.setModel(joinPoint.getTarget().getClass().getName());
 66             log.setMethod(joinPoint.getSignature().getName());
 67             log.setRequestIp(getCliectIp(request));
 68             log.setParams(getParams(joinPoint));
 69             log.setCreator(user.getUserName());
 70             log.setCreatorId(user.getUserId());
 71             log.setCreateDate(new Date());
 72             systemLogService.add(log);
 73 
 74             System.out.println("=====methodLog后置通知结束=====");
 75         }
 76         catch (Exception e)
 77         {
 78             // 记录本地异常日志
 79             logger.error("==后置通知异常==");
 80             logger.error("异常信息:{}", e.getMessage());
 81             e.printStackTrace();
 82         }
 83     }
 84 
 85     /**
 86      * 获取方法参数
 87      * @param joinPoint
 88      * @return
 89      */
 90     private String getParams(JoinPoint joinPoint)
 91     {
 92         Object[] arguments = joinPoint.getArgs();
 93         JSONArray jsonArr = new JSONArray();
 94         if (null != arguments && arguments.length > 0)
 95         {
 96             for (Object arg : arguments)
 97             {
 98                 if (arg instanceof ServletRequest || arg instanceof ServletResponse)
 99                 {
100                     continue;
101                 }
102                 jsonArr.add(arg);
103             }
104         }
105         return jsonArr.toString();
106     }
107 
108     /**
109      * 获取客户端ip地址
110      * @param request
111      * @return
112      */
113     private String getCliectIp(HttpServletRequest request)
114     {
115         String ip = request.getHeader("x-forwarded-for");
116         if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip))
117         {
118             return ip.split(",")[0];
119         }
120         ip = request.getHeader("X-Real-IP");
121         if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip))
122         {
123             return ip;
124         }
125         return request.getRemoteAddr();
126     }
127 }
View Code

    注:我的切面代码中只用到了后置通知,其实还有很多,留待以后研究。

6、在controller层的方法中添加注解:

/**
 * 加载枚举下拉项
* @return
*/
@RequestMapping("/wrapDictList")
@Log
public @ItemResponseBody List<DicItems> wrapDictList()
{
    return scpwythJhxmglPcglAppService.wrapDictList();
}
         
View Code

以上就是操作日志管理功能实现的全部步骤。下面是后台运行数据和入库数据:

 

转载于:https://www.cnblogs.com/leeplums/p/11157985.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值