JAVA實(shí)現(xiàn)通用日志記錄方法
前言:
之前想在filter層直接過(guò)濾httpServerletRequest請(qǐng)求進(jìn)行日志處理,但是之后再getWriter()的 時(shí)候報(bào)already been call異常。查了下,才發(fā)現(xiàn)原來(lái)流形式的只能讀取一次。。就好像食物,吃了就沒(méi)了。。 所以在filter和inteceptor里面是沒(méi)法通過(guò)獲取request的流來(lái)進(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)求沒(méi)傳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>
如此一來(lái),核心步驟就完成了,剩下的就是自己組裝需要記錄的東西了。
第三步:寫(xiě)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;//事件類(lèi)型
@Column(name="event_desc")
private String eventDesc;//事件中文描述
@Column(name="operator")
private String operator;//操作者
@Column(name="request_ip")
private String requestIp;//客戶(hù)端地址
@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的方法名稱(chēng)定制響應(yīng)的事件類(lèi)型
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 操作日志類(lèi)型
* @author Mingchenchen
*
*/
public enum LogTypeEnum {
//用戶(hù)
COMMON_LOGIN("login","login","登錄");
//其他
private String methodName;//方法名稱(chēng)與controller一致
private String key;//保存到數(shù)據(jù)庫(kù)的事件類(lèi)型
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)部類(lèi) 用戶(hù)保存所有的enum 無(wú)須通過(guò)Enum.values()每次遍歷
* @author Mingchenchen
*
*/
private static class innerMap{
private static Map<String, LogTypeEnum> map = new ConcurrentHashMap<>(128);
static{
//初始化整個(gè)枚舉類(lèi)到Map
for (LogTypeEnum logTypeEnum : LogTypeEnum.values()) {
map.put(logTypeEnum.getMethodName(), logTypeEnum);
}
}
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
基于Java注解(Annotation)的自定義注解入門(mén)介紹
要深入學(xué)習(xí)注解,我們就必須能定義自己的注解,并使用注解,在定義自己的注解之前,我們就必須要了解Java為我們提供的元注解和相關(guān)定義注解的語(yǔ)法2013-04-04
一文詳解Spring是怎樣處理循環(huán)依賴(lài)的
循環(huán)依賴(lài)簡(jiǎn)單理解就是A,B 兩個(gè)bean相互依賴(lài),A依賴(lài)B,B依賴(lài)A,A->B、B->A大概就是這樣,這篇文章主要介紹了Spring是怎樣處理循環(huán)依賴(lài)的,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2024-01-01
深入了解Java設(shè)計(jì)模式之UML類(lèi)圖
UML?即?Unified?Modeling?Language?統(tǒng)一建模語(yǔ)言,是用來(lái)設(shè)計(jì)軟件的可視化建模語(yǔ)言。本文就帶大家了解一下UML中類(lèi)圖的定義與使用,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-11-11
Java如何重寫(xiě)object類(lèi)的equals方法詳解
這篇文章主要給大家介紹了關(guān)于Java如何重寫(xiě)object類(lèi)的equals方法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
詳解java如何實(shí)現(xiàn)帶RequestBody傳Json參數(shù)的GET請(qǐng)求
在調(diào)試Fate平臺(tái)時(shí),遇到了一個(gè)奇葩的接口類(lèi)型,該接口為Get方式,入?yún)⑹且粋€(gè)json類(lèi)型在body中傳遞,使用body中傳參的話為什么不用POST請(qǐng)求而使用了GET請(qǐng)求,下面我們就來(lái)深入研究一下2024-02-02

