懒羊羊
2024-01-31 e57a8990ae56f657a59c435a0613c5f7a8728003
提交 | 用户 | 时间
e57a89 1 package com.jcdm.framework.aspectj;
2
3 import java.util.Collection;
4 import java.util.Map;
5 import javax.servlet.http.HttpServletRequest;
6 import javax.servlet.http.HttpServletResponse;
7 import org.apache.commons.lang3.ArrayUtils;
8 import org.aspectj.lang.JoinPoint;
9 import org.aspectj.lang.annotation.AfterReturning;
10 import org.aspectj.lang.annotation.AfterThrowing;
11 import org.aspectj.lang.annotation.Aspect;
12 import org.aspectj.lang.annotation.Before;
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15 import org.springframework.core.NamedThreadLocal;
16 import org.springframework.stereotype.Component;
17 import org.springframework.validation.BindingResult;
18 import org.springframework.web.multipart.MultipartFile;
19 import com.alibaba.fastjson2.JSON;
20 import com.jcdm.common.annotation.Log;
21 import com.jcdm.common.core.domain.model.LoginUser;
22 import com.jcdm.common.enums.BusinessStatus;
23 import com.jcdm.common.enums.HttpMethod;
24 import com.jcdm.common.filter.PropertyPreExcludeFilter;
25 import com.jcdm.common.utils.SecurityUtils;
26 import com.jcdm.common.utils.ServletUtils;
27 import com.jcdm.common.utils.StringUtils;
28 import com.jcdm.common.utils.ip.IpUtils;
29 import com.jcdm.framework.manager.AsyncManager;
30 import com.jcdm.framework.manager.factory.AsyncFactory;
31 import com.jcdm.system.domain.SysOperLog;
32
33 /**
34  * 操作日志记录处理
35  * 
36  * @author jc
37  */
38 @Aspect
39 @Component
40 public class LogAspect
41 {
42     private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
43
44     /** 排除敏感属性字段 */
45     public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
46
47     /** 计算操作消耗时间 */
48     private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");
49
50     /**
51      * 处理请求前执行
52      */
53     @Before(value = "@annotation(controllerLog)")
54     public void boBefore(JoinPoint joinPoint, Log controllerLog)
55     {
56         TIME_THREADLOCAL.set(System.currentTimeMillis());
57     }
58
59     /**
60      * 处理完请求后执行
61      *
62      * @param joinPoint 切点
63      */
64     @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
65     public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)
66     {
67         handleLog(joinPoint, controllerLog, null, jsonResult);
68     }
69
70     /**
71      * 拦截异常操作
72      * 
73      * @param joinPoint 切点
74      * @param e 异常
75      */
76     @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
77     public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)
78     {
79         handleLog(joinPoint, controllerLog, e, null);
80     }
81
82     protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult)
83     {
84         try
85         {
86             // 获取当前的用户
87             LoginUser loginUser = SecurityUtils.getLoginUser();
88
89             // *========数据库日志=========*//
90             SysOperLog operLog = new SysOperLog();
91             operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
92             // 请求的地址
93             String ip = IpUtils.getIpAddr();
94             operLog.setOperIp(ip);
95             operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
96             if (loginUser != null)
97             {
98                 operLog.setOperName(loginUser.getUsername());
99             }
100
101             if (e != null)
102             {
103                 operLog.setStatus(BusinessStatus.FAIL.ordinal());
104                 operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
105             }
106             // 设置方法名称
107             String className = joinPoint.getTarget().getClass().getName();
108             String methodName = joinPoint.getSignature().getName();
109             operLog.setMethod(className + "." + methodName + "()");
110             // 设置请求方式
111             operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
112             // 处理设置注解上的参数
113             getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
114             // 设置消耗时间
115             operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
116             // 保存数据库
117             AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
118         }
119         catch (Exception exp)
120         {
121             // 记录本地异常日志
122             log.error("异常信息:{}", exp.getMessage());
123             exp.printStackTrace();
124         }
125         finally
126         {
127             TIME_THREADLOCAL.remove();
128         }
129     }
130
131     /**
132      * 获取注解中对方法的描述信息 用于Controller层注解
133      * 
134      * @param log 日志
135      * @param operLog 操作日志
136      * @throws Exception
137      */
138     public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception
139     {
140         // 设置action动作
141         operLog.setBusinessType(log.businessType().ordinal());
142         // 设置标题
143         operLog.setTitle(log.title());
144         // 设置操作人类别
145         operLog.setOperatorType(log.operatorType().ordinal());
146         // 是否需要保存request,参数和值
147         if (log.isSaveRequestData())
148         {
149             // 获取参数的信息,传入到数据库中。
150             setRequestValue(joinPoint, operLog, log.excludeParamNames());
151         }
152         // 是否需要保存response,参数和值
153         if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
154         {
155             operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
156         }
157     }
158
159     /**
160      * 获取请求的参数,放到log中
161      * 
162      * @param operLog 操作日志
163      * @throws Exception 异常
164      */
165     private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception
166     {
167         Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
168         String requestMethod = operLog.getRequestMethod();
169         if (StringUtils.isEmpty(paramsMap)
170                 && (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)))
171         {
172             String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
173             operLog.setOperParam(StringUtils.substring(params, 0, 2000));
174         }
175         else
176         {
177             operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000));
178         }
179     }
180
181     /**
182      * 参数拼装
183      */
184     private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames)
185     {
186         String params = "";
187         if (paramsArray != null && paramsArray.length > 0)
188         {
189             for (Object o : paramsArray)
190             {
191                 if (StringUtils.isNotNull(o) && !isFilterObject(o))
192                 {
193                     try
194                     {
195                         String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
196                         params += jsonObj.toString() + " ";
197                     }
198                     catch (Exception e)
199                     {
200                     }
201                 }
202             }
203         }
204         return params.trim();
205     }
206
207     /**
208      * 忽略敏感属性
209      */
210     public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames)
211     {
212         return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));
213     }
214
215     /**
216      * 判断是否需要过滤的对象。
217      * 
218      * @param o 对象信息。
219      * @return 如果是需要过滤的对象,则返回true;否则返回false。
220      */
221     @SuppressWarnings("rawtypes")
222     public boolean isFilterObject(final Object o)
223     {
224         Class<?> clazz = o.getClass();
225         if (clazz.isArray())
226         {
227             return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
228         }
229         else if (Collection.class.isAssignableFrom(clazz))
230         {
231             Collection collection = (Collection) o;
232             for (Object value : collection)
233             {
234                 return value instanceof MultipartFile;
235             }
236         }
237         else if (Map.class.isAssignableFrom(clazz))
238         {
239             Map map = (Map) o;
240             for (Object value : map.entrySet())
241             {
242                 Map.Entry entry = (Map.Entry) value;
243                 return entry.getValue() instanceof MultipartFile;
244             }
245         }
246         return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
247                 || o instanceof BindingResult;
248     }
249 }