JAVA實(shí)現(xiàn)通用日志記錄方法
前言:
之前想在filter層直接過濾httpServerletRequest請(qǐng)求進(jìn)行日志處理,但是之后再getWriter()的 時(shí)候報(bào)already been call異常。查了下,才發(fā)現(xiàn)原來流形式的只能讀取一次。。就好像食物,吃了就沒了。。 所以在filter和inteceptor里面是沒法通過獲取request的流來進(jìn)行日志記錄的。
于是還是準(zhǔn)備用通用的方法:controller層aop進(jìn)行切面記錄日志。
使用Aop記錄操作日志
第一步:添加Aop
/** * 統(tǒng)一日志處理Handler * @author Mingchenchen * */ public class LogAopHandler { @Autowired private AuditLogDao auditLogDao; /** * controller層面記錄操作日志 * 注意此處是aop:around的 因?yàn)樾枰玫秸?qǐng)求前的參數(shù)以及請(qǐng)求后接口返回的結(jié)果 * @throws Throwable */ public Object doSaveLog(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature method = (MethodSignature) joinPoint.getSignature(); String methodName = method.getName(); Object[] objects = joinPoint.getArgs(); String requestBody = null; if (objects!=null && objects.length>0) { for (Object object : objects) { if (object == null) { requestBody = null;//POST接口參數(shù)為空 比如刪除XXX }else if (object instanceof String) { requestBody = (String) object;//有些接口直接把參數(shù)轉(zhuǎn)換成對(duì)象了 }else { requestBody = JSONObject.toJSONString(object); } } } //只記錄POST方法的日志 boolean isNeedSaveLog = false; //此處不能用getAnnotationByType 是JAVA8的特性,因?yàn)樽⒔饽軌蛑孛?所以得到的是數(shù)組 RequestMapping annotation = method.getMethod().getAnnotation(RequestMapping.class); for (RequestMethod requestMethod : annotation.method()) { if (requestMethod==RequestMethod.POST) { isNeedSaveLog = true; } } JSONObject requestBodyJson = null; try { requestBodyJson = JSONObject.parseObject(requestBody); } catch (Exception e) { //do nothing 即POST請(qǐng)求沒傳body } HttpServletRequest request = RequestContextUtil.getRequestByCurrentContext(); String userName = RequestContextUtil.getUserNameByCurrentContext(); if (StringUtil.isEmpty(userName)) { try { userName = DmsCache.get(requestBodyJson.getString("userName")).getName(); } catch (Exception e) { userName = RequestContextUtil.getAsynUserInfoByAutoDeploy().getName(); } } //得到request的參數(shù)后讓方法執(zhí)行它 //注意around的情況下需要返回result 否則將不會(huì)返回值給請(qǐng)求者 Object result = joinPoint.proceed(objects); try { JSONObject resultJson = JSONObject.parseObject(result.toString()); if (isNeedSaveLog) {//如果是POST請(qǐng)求 則記錄日志 LogTypeEnum logTypeEnum = LogTypeEnum.getDesByMethodName(methodName); if (logTypeEnum != null) { AuditLogEntity auditLogEntity = new AuditLogEntity(); auditLogEntity.setUuid(StringUtil.createRandomUuid()); auditLogEntity.setOperator(userName); auditLogEntity.setRequestIp(request.getRemoteAddr()); auditLogEntity.setRequestUrl(request.getRequestURI().replace("/cloud-master", "")); auditLogEntity.setEventType(logTypeEnum.getKey()); auditLogEntity.setEventDesc(logTypeEnum.getDescription()); auditLogEntity.setRequest(requestBody); int isSuccess = "200".equals(resultJson.getString("code")) ? 1 : 0; auditLogEntity.setSuccessFlag(isSuccess); auditLogEntity.setResponse(result.toString()); auditLogEntity.setCreateTime(new Date()); auditLogDao.insert(auditLogEntity); } } } catch (Exception e) { e.printStackTrace(); } return result; } }
第二步:在spring的xml中聲明
<!-- 記錄操作日志 --> <bean id="operationLogAop" class="com.ming.learn.core.aop.LogAopHandler"/> <aop:config> <aop:aspect id="logAOP" ref="operationLogAop"> <aop:pointcut id="target" expression="execution(* com.ming.learn..*Controller.*(..))"/> <aop:around method="doSaveLog" pointcut-ref="target"/> </aop:aspect> </aop:config>
如此一來,核心步驟就完成了,剩下的就是自己組裝需要記錄的東西了。
第三步:寫Dao、Entity、Mapper
import java.util.Date; import javax.persistence.Column; import javax.persistence.Id; import javax.persistence.Table; /** * 日志審計(jì) * @author Mingchenchen * */ @Table(name="audit_log") public class AuditLogEntity { @Id private String uuid; @Column(name="event_type") private String eventType;//事件類型 @Column(name="event_desc") private String eventDesc;//事件中文描述 @Column(name="operator") private String operator;//操作者 @Column(name="request_ip") private String requestIp;//客戶端地址 @Column(name="request_url") private String requestUrl;//請(qǐng)求地址 @Column(name="request") private String request;//請(qǐng)求body @Column(name="response") private String response;//請(qǐng)求返回值 @Column(name="create_time") private Date createTime; public String getUuid() { return uuid; } public void setUuid(String uuid) { this.uuid = uuid; } public String getEventType() { return eventType; } public void setEventType(String eventType) { this.eventType = eventType; } public String getEventDesc() { return eventDesc; } public void setEventDesc(String eventDesc) { this.eventDesc = eventDesc; } public String getOperator() { return operator; } public void setOperator(String operator) { this.operator = operator; } public String getRequestIp() { return requestIp; } public void setRequestIp(String requestIp) { this.requestIp = requestIp; } public String getRequestUrl() { return requestUrl; } public void setRequestUrl(String requestUrl) { this.requestUrl = requestUrl; } public String getRequest() { return request; } public void setRequest(String request) { this.request = request; } public String getResponse() { return response; } public void setResponse(String response) { this.response = response; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } }
第四步:根據(jù)Controller的方法名稱定制響應(yīng)的事件類型
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * 操作日志類型 * @author Mingchenchen * */ public enum LogTypeEnum { //用戶 COMMON_LOGIN("login","login","登錄"); //其他 private String methodName;//方法名稱與controller一致 private String key;//保存到數(shù)據(jù)庫(kù)的事件類型 private String description;//保存到數(shù)據(jù)庫(kù)的描述 private LogTypeEnum(String methodName,String key,String description){ this.methodName = methodName; this.key = key; this.description = description; } public String getMethodName() { return methodName; } public void setMethodName(String methodName) { this.methodName = methodName; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } /** * 根據(jù)方法名返回 * @param methodName * @return */ public static LogTypeEnum getDesByMethodName(String methodName){ return innerMap.map.get(methodName); } /** * 內(nèi)部類 用戶保存所有的enum 無須通過Enum.values()每次遍歷 * @author Mingchenchen * */ private static class innerMap{ private static Map<String, LogTypeEnum> map = new ConcurrentHashMap<>(128); static{ //初始化整個(gè)枚舉類到Map for (LogTypeEnum logTypeEnum : LogTypeEnum.values()) { map.put(logTypeEnum.getMethodName(), logTypeEnum); } } } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
基于Java注解(Annotation)的自定義注解入門介紹
要深入學(xué)習(xí)注解,我們就必須能定義自己的注解,并使用注解,在定義自己的注解之前,我們就必須要了解Java為我們提供的元注解和相關(guān)定義注解的語法2013-04-04詳解java如何實(shí)現(xiàn)帶RequestBody傳Json參數(shù)的GET請(qǐng)求
在調(diào)試Fate平臺(tái)時(shí),遇到了一個(gè)奇葩的接口類型,該接口為Get方式,入?yún)⑹且粋€(gè)json類型在body中傳遞,使用body中傳參的話為什么不用POST請(qǐng)求而使用了GET請(qǐng)求,下面我們就來深入研究一下2024-02-02