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)