springAOP实现操作日志记录,并记录请求参数与编辑前后字段的具体改变

时间:2019-03-21 21:19:20   收藏:0   阅读:938

 

本文为博主原创,未经允许不得转载:

 

 1 import java.lang.annotation.Documented;
 2 import java.lang.annotation.Retention;
 3 import java.lang.annotation.Target;
 4 
 5 import java.lang.annotation.ElementType;
 6 import java.lang.annotation.RetentionPolicy;
 7 
 8 @Target({ElementType.PARAMETER, ElementType.METHOD})  
 9 @Retention(RetentionPolicy.RUNTIME)  
10 @Documented 
11 public @interface SystemControllerLog {
12         
13          /**查询模块*/
14          String module()  default ""; 
15          
16          /**查询模块名称*/
17         String methods()  default ""; 
18          
19         /**查询的bean名称*/
20         String serviceClass() default "";
21         
22         /**查询单个详情的bean的方法*/
23         String queryMethod() default "";
24         
25         /**查询详情的参数类型*/
26         String parameterType() default "";
27         
28         /**从页面参数中解析出要查询的id,
29          * 如域名修改中要从参数中获取customerDomainId的值进行查询
30          */
31         String parameterKey() default "";
32         
33         /**是否为批量类型操作*/
34         boolean paramIsArray() default false;
35         
36     }

 

  1 package com.suning.fucdn.impl.service.log;
  2 
  3 import java.lang.reflect.Method;
  4 import java.text.SimpleDateFormat;
  5 import java.util.Date;
  6 
  7 import javax.servlet.http.HttpServletRequest;
  8 import javax.servlet.http.HttpSession;
  9 
 10 import org.apache.commons.lang3.StringUtils;
 11 import org.aspectj.lang.ProceedingJoinPoint;
 12 import org.aspectj.lang.Signature;
 13 import org.aspectj.lang.annotation.Around;
 14 import org.aspectj.lang.annotation.Aspect;
 15 import org.aspectj.lang.annotation.Pointcut;
 16 import org.aspectj.lang.reflect.MethodSignature;
 17 import org.slf4j.Logger;
 18 import org.slf4j.LoggerFactory;
 19 import org.springframework.beans.factory.annotation.Autowired;
 20 import org.springframework.stereotype.Component;
 21 import org.springframework.util.ReflectionUtils;
 22 import org.springframework.web.context.request.RequestContextHolder;
 23 import org.springframework.web.context.request.ServletRequestAttributes;
 24 
 25 import com.alibaba.fastjson.JSON;
 26 import com.alibaba.fastjson.JSONArray;
 27 import com.alibaba.fastjson.JSONObject;
 28 import com.suning.fucdn.common.RequestResult;
 29 import com.suning.fucdn.common.enums.FucdnStrConstant;
 30 import com.suning.fucdn.entity.log.SystemControllerLogInfo;
 31 import com.suning.fucdn.impl.service.log.LogServiceImpl;
 32 import com.suning.fucdn.vo.AdminUserVO;
 33 
 34 /**
 35  * 
 36  * 〈一句话功能简述:操作日志切面记录操作〉<br> 
 37  * 〈功能详细描述〉
 38  *
 39  * @author xiang
 40  * @see [相关类/方法](可选)
 41  * @since [产品/模块版本] (可选)
 42  */
 43 @Component
 44 @Aspect
 45 public class ControllerLogAopAspect {
 46     
 47     private static final Logger LOGGER = LoggerFactory.getLogger(ControllerLogAopAspect.class);
 48     
 49     //注入service,用来将日志信息保存在数据库
 50     @Autowired
 51     private LogServiceImpl logservice;
 52     
 53      //配置接入点,如果不知道怎么配置,可以百度一下规则
 54      @Pointcut("execution(* com.suning.fucdn.controller..*.*(..))")  
 55      private void controllerAspect(){
 56          System.out.println("point cut start");
 57      }//定义一个切入点
 58  
 59      @SuppressWarnings({ "rawtypes", "unused" })
 60      @Around("controllerAspect()")
 61      public Object around(ProceedingJoinPoint pjp) throws Throwable {
 62          //常见日志实体对象
 63          SystemControllerLogInfo log = new SystemControllerLogInfo(); 
 64          //获取登录用户账户
 65          HttpServletRequest httpRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
 66         
 67          //方法通知前获取时间,为什么要记录这个时间呢?当然是用来计算模块执行时间的
 68          //获取系统时间
 69          String time = new SimpleDateFormat(FucdnStrConstant.YEAR_MONTH_DAY_HOUR_MINUTE_SECOND.getConstant()).format(new Date());
 70          log.setStartTime(time);
 71          
 72          //获取系统ip,这里用的是我自己的工具类,可自行网上查询获取ip方法
 73          //String ip = GetLocalIp.localIp();
 74          //log.setIP(ip);
 75          
 76         // 拦截的实体类,就是当前正在执行的controller
 77         Object target = pjp.getTarget();
 78         // 拦截的方法名称。当前正在执行的方法
 79         String methodName = pjp.getSignature().getName();
 80         // 拦截的方法参数
 81         Object[] args = pjp.getArgs();
 82         //String params = Arrays.toString(pjp.getArgs());
 83         JSONArray operateParamArray = new JSONArray();
 84         for (int i = 0; i < args.length; i++) {
 85             Object paramsObj = args[i];
 86             if(paramsObj instanceof String || paramsObj instanceof JSONObject ){
 87                 String str = (String) paramsObj;
 88                 //将其转为jsonobject
 89                 JSONObject dataJson = JSONObject.parseObject(str);
 90                 if(dataJson == null || dataJson.isEmpty() || "null".equals(dataJson)){
 91                     break;
 92                 }else{
 93                     operateParamArray.add(dataJson);
 94                 }
 95             }
 96         }
 97         //设置请求参数
 98         log.setOperateParams(operateParamArray.toJSONString());
 99         // 拦截的放参数类型
100         Signature sig = pjp.getSignature();
101         MethodSignature msig = null;
102         if (!(sig instanceof MethodSignature)) {
103             throw new IllegalArgumentException("该注解只能用于方法");
104         }
105         msig = (MethodSignature) sig;
106         
107         Class[] parameterTypes = msig.getMethod().getParameterTypes();
108         Object object = null;
109         // 获得被拦截的方法
110         Method method = null;
111         try {
112             method = target.getClass().getMethod(methodName, parameterTypes);
113         } catch (NoSuchMethodException e1) {
114             LOGGER.error("ControllerLogAopAspect around error",e1);
115         } catch (SecurityException e1) {
116             LOGGER.error("ControllerLogAopAspect around error",e1);
117         }
118         if (null != method) {
119             // 判断是否包含自定义的注解,说明一下这里的SystemLog就是我自己自定义的注解
120             if (method.isAnnotationPresent(SystemControllerLog.class)) {
121                 
122                 //此处需要对用户进行区分:1为admin user 2为customer user
123                 // get session
124                 HttpSession httpSession = httpRequest.getSession(true);
125                 // 从session获取登录用户
126                 AdminUserVO adminUserVO = (AdminUserVO) httpSession
127                         .getAttribute(FucdnStrConstant.SESSION_KEY_ADMIN.getConstant());
128                 long adminUserId = adminUserVO.getAdminUserId();
129                 log.setUserId(String.valueOf(adminUserId));
130                 
131                 SystemControllerLog systemlog = method.getAnnotation(SystemControllerLog.class);
132                 
133                 log.setModule(systemlog.module());
134                 log.setMethod(systemlog.methods());
135                 //请求查询操作前数据的spring bean
136                 String serviceClass = systemlog.serviceClass();
137                 //请求查询数据的方法
138                 String queryMethod = systemlog.queryMethod();
139                 //判断是否需要进行操作前的对象参数查询
140                 if(StringUtils.isNotBlank(systemlog.parameterKey())
141                     &&StringUtils.isNotBlank(systemlog.parameterType())
142                     &&StringUtils.isNotBlank(systemlog.queryMethod())
143                     &&StringUtils.isNotBlank(systemlog.serviceClass())){
144                     boolean isArrayResult = systemlog.paramIsArray();
145                      //参数类型
146                     String paramType = systemlog.parameterType();
147                     String key = systemlog.parameterKey();
148                     
149                     if(isArrayResult){//批量操作
150                         //JSONArray jsonarray = (JSONArray) object.get(key);
151                         //从请求的参数中解析出查询key对应的value值
152                         String value = "";
153                         JSONArray beforeParamArray = new JSONArray();
154                         for (int i = 0; i < operateParamArray.size(); i++) {
155                             JSONObject params =  operateParamArray.getJSONObject(i);
156                             JSONArray paramArray = (JSONArray) params.get(key);
157                             if (paramArray != null) {
158                                 for (int j = 0; j < paramArray.size(); j++) {
159                                     String paramId =  paramArray.getString(j);
160                                     //在此处判断spring bean查询的方法参数类型
161                                     Object data = getOperateBeforeData(paramType, serviceClass, queryMethod, paramId);
162                                     JSONObject json = (JSONObject) JSON.toJSON(data);
163                                     beforeParamArray.add(json);
164                                 }
165                             }
166                         }
167                         log.setBeforeParams(beforeParamArray.toJSONString());
168                         
169                     }else{//单量操作
170                         
171                         //从请求的参数中解析出查询key对应的value值
172                         String value = "";
173                         for (int i = 0; i < operateParamArray.size(); i++) {
174                             JSONObject params =  operateParamArray.getJSONObject(i);
175                             value = params.getString(key);
176                             if(StringUtils.isNotBlank(value)){
177                                 break;
178                             }
179                         }
180                         //在此处获取操作前的spring bean的查询方法
181                         Object data = getOperateBeforeData(paramType, serviceClass, queryMethod, value);
182                         JSONObject beforeParam = (JSONObject) JSON.toJSON(data);
183                         log.setBeforeParams(beforeParam.toJSONString());
184                     }
185                 }
186                 
187                 try {
188                     //执行页面请求模块方法,并返回
189                     object = pjp.proceed();
190                     //获取系统时间
191                     String endTime = new SimpleDateFormat(FucdnStrConstant.YEAR_MONTH_DAY_HOUR_MINUTE_SECOND.getConstant()).format(new Date());
192                     log.setEndTime(endTime);
193                     //将object 转化为controller封装返回的实体类:RequestResult
194                     RequestResult requestResult = (RequestResult) object;
195                     if(requestResult.isResult()){
196                         //操作流程成功
197                         if(StringUtils.isNotBlank(requestResult.getErrMsg())){
198                             log.setResultMsg(requestResult.getErrMsg());
199                         }else if(requestResult.getData() instanceof String){
200                             log.setResultMsg((String) requestResult.getData());
201                         }else{
202                             log.setResultMsg("执行成功");
203                         }
204                     }else{
205                         log.setResultMsg("失败");
206                     }
207                     //保存进数据库
208                     logservice.saveLog(log);
209                 } catch (Throwable e) {
210                     String endTime = new SimpleDateFormat(FucdnStrConstant.YEAR_MONTH_DAY_HOUR_MINUTE_SECOND.getConstant()).format(new Date());
211                     log.setEndTime(endTime);
212                     
213                     log.setResultMsg(e.getMessage());
214                     logservice.saveLog(log);
215                 }
216             } else {
217                 //没有包含注解
218                 object = pjp.proceed();
219             }
220         } else { 
221             //不需要拦截直接执行
222             object = pjp.proceed();
223         }
224         return object;
225      }
226      
227      /**
228       * 
229       * 功能描述: <br>
230       * 〈功能详细描述〉
231       *
232       * @param paramType:参数类型
233       * @param serviceClass:bean名称
234       * @param queryMethod:查询method
235       * @param value:查询id的value
236       * @return
237       * @see [相关类/方法](可选)
238       * @since [产品/模块版本](可选)
239       */
240      public Object getOperateBeforeData(String paramType,String serviceClass,String queryMethod,String value){
241         Object obj = new Object();
242          //在此处解析请求的参数类型,根据id查询数据,id类型有四种:int,Integer,long,Long
243          if(paramType.equals("int")){
244              int id = Integer.parseInt(value);
245              Method  mh = ReflectionUtils.findMethod(SpringContextUtil.getBean(serviceClass).getClass(), queryMethod,Long.class );
246             //用spring bean获取操作前的参数,此处需要注意:传入的id类型与bean里面的参数类型需要保持一致
247             obj = ReflectionUtils.invokeMethod(mh,  SpringContextUtil.getBean(serviceClass),id);
248              
249          }else if(paramType.equals("Integer")){
250              Integer id = Integer.valueOf(value);
251              Method  mh = ReflectionUtils.findMethod(SpringContextUtil.getBean(serviceClass).getClass(), queryMethod,Long.class );
252             //用spring bean获取操作前的参数,此处需要注意:传入的id类型与bean里面的参数类型需要保持一致
253             obj = ReflectionUtils.invokeMethod(mh,  SpringContextUtil.getBean(serviceClass),id);
254              
255          }else if(paramType.equals("long")){
256              long id = Long.parseLong(value);
257              Method  mh = ReflectionUtils.findMethod(SpringContextUtil.getBean(serviceClass).getClass(), queryMethod,Long.class );
258             //用spring bean获取操作前的参数,此处需要注意:传入的id类型与bean里面的参数类型需要保持一致
259             obj = ReflectionUtils.invokeMethod(mh,  SpringContextUtil.getBean(serviceClass),id);
260              
261          }else if(paramType.equals("Long")){
262              Long id = Long.valueOf(value);
263              Method  mh = ReflectionUtils.findMethod(SpringContextUtil.getBean(serviceClass).getClass(), queryMethod,Long.class );
264             //用spring bean获取操作前的参数,此处需要注意:传入的id类型与bean里面的参数类型需要保持一致
265             obj = ReflectionUtils.invokeMethod(mh,  SpringContextUtil.getBean(serviceClass),id);
266          }
267          return obj;
268      }
269 }

 

 

 1 import org.springframework.beans.BeansException;
 2 import org.springframework.context.ApplicationContext;
 3 import org.springframework.context.ApplicationContextAware;
 4 import org.springframework.stereotype.Component;
 5 
 6 
 7 /**
 8  * 获取spring容器,以访问容器中定义的其他bean
 9  *  xiang
10  *  MOSTsView 3.0 2009-11-16
11  */
12 @Component
13 public class SpringContextUtil implements ApplicationContextAware{
14      
15     private static ApplicationContext   applicationContext;
16  
17     /**
18      * 实现ApplicationContextAware接口的回调方法,设置上下文环境
19      */
20     public void setApplicationContext(ApplicationContext applicationContext){
21         SpringContextUtil.applicationContext = applicationContext;
22     }
23  
24     public static ApplicationContext getApplicationContext(){
25         return applicationContext;
26     }
27  
28     /**
29      * 获取对象
30      * @return  Object 一个以所给名字注册的bean的实例 (service注解方式,自动生成以首字母小写的类名为bean name)
31      */
32     public static Object getBean(String name) throws BeansException{
33         return applicationContext.getBean(name);
34     }
35 }

 

 

 

 

 1 public class SystemControllerLogInfo{
 2     
 3     private long id;
 4 
 5     /**用户id*/
 6     private String userId;
 7     
 8     /**用户类型*/
 9     private int userType;
10     
11     /**操作模块*/
12     private String module;
13     
14     /**操作类型*/
15     private String method;
16     
17     /**操作前参数*/
18     private String beforeParams;
19 
20     /**操作时请求参数*/
21     private String operateParams;
22 
23     /**开始时间*/
24     private String startTime;
25 
26     /**结束时间*/
27     private String endTime;
28     
29     /**操作状态描述*/
30     private int resultStatus;
31     
32     /**操作结果描述*/
33     private String resultMsg;

 

 

 1 @ResponseBody
 2     @RequestMapping(value = "/delete", method = { RequestMethod.POST })
 3     @SystemControllerLog(module="域名管理",methods="域名删除",serviceClass="domainConfService",queryMethod="queryDomain",parameterType="Long",parameterKey="customerDomainId")
 4     public RequestResult delete(@RequestBody String param) {
 5         // 定义请求数据
 6         RequestResult result = new RequestResult();
 7         // 接收数据
 8         CustomerDomain customerDomain = JSONObject.parseObject(param, CustomerDomain.class);
 9         // 更新客户域名
10         try {
11             String data = domainConfService.deleteDomain(customerDomain.getId());
12             // 设置true
13             if (StringUtils.isBlank(data)) {
14                 result.setData("删除成功");
15             } else {
16                 result.setData(data);
17             }
18             result.setResult(true);
19         } catch (Exception e) {
20             // 记录错误信息,并返回
21             LOGGER.error("delete failed", e);
22             result.setErrMsg(e.getMessage());
23         }
24         // 返回
25         return result;
26     }

 

 

技术分享图片

 

原文:https://www.cnblogs.com/zjdxr-up/p/10573936.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!