網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
文章目錄
- 一、需求
- 二、定義訪問(wèn)日志內(nèi)容記錄實(shí)體類(lèi)
- 三、自定義日志攔截器
- 四、攔截器注冊(cè)
- 五、獲取ip訪問(wèn)地址的工具類(lèi)
- 六、"ACCESS-LOG"的日志Logger定義
一、需求
我們本節(jié)要實(shí)現(xiàn)的需求
- 針對(duì)當(dāng)前系統(tǒng)的每一次接口訪問(wèn),要記錄是什么人訪問(wèn)的(用戶名)、什么時(shí)間訪問(wèn)的、訪問(wèn)耗時(shí)多長(zhǎng)時(shí)間、使用什么HTTP method方法訪問(wèn)的、訪問(wèn)結(jié)果如何等。可以稱(chēng)為審計(jì)日志。
- 將訪問(wèn)記錄審計(jì)日志,輸出到一個(gè)單獨(dú)的日志文件access.log
二、定義訪問(wèn)日志內(nèi)容記錄實(shí)體類(lèi)
@Data
public class AccessLog {
//訪問(wèn)者用戶名
private String username;
//請(qǐng)求路徑
private String url;
//請(qǐng)求消耗時(shí)長(zhǎng)
private Integer duration;
//http 方法:GET、POST等
private String httpMethod;
//http 請(qǐng)求響應(yīng)狀態(tài)碼
private Integer httpStatus;
//訪問(wèn)者ip
private String ip;
//此條記錄的創(chuàng)建時(shí)間
private Date createTime;
}
三、自定義日志攔截器
通過(guò)自定義攔截器的方式,記錄審計(jì)日志。
- 攔截器的preHandle方法,可以用于攔截請(qǐng)求處理開(kāi)始。用于記錄請(qǐng)求開(kāi)始時(shí)間等信息保存到Http Request,用于后續(xù)計(jì)算請(qǐng)求時(shí)長(zhǎng)。
- 攔截器的postHandle方法,可以用于攔截請(qǐng)求處理完成。可以從Request對(duì)象獲取開(kāi)始時(shí)間,計(jì)算本次請(qǐng)求總的處理時(shí)長(zhǎng)等信息。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
public class AccessLogInterceptor implements HandlerInterceptor {
//請(qǐng)求開(kāi)始時(shí)間標(biāo)識(shí)
private static final String LOGGER_SEND_TIME = "SEND_TIME";
//請(qǐng)求日志實(shí)體標(biāo)識(shí)
private static final String LOGGER_ACCESSLOG = "ACCESSLOG_ENTITY";
private static final Logger logger = LoggerFactory.getLogger("ACCESS-LOG");
/**
* 進(jìn)入SpringMVC的Controller之前開(kāi)始記錄日志實(shí)體
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
//創(chuàng)建日志實(shí)體
AccessLog accessLog = new AccessLog();
// 設(shè)置IP地址
accessLog.setIp(AdrressIpUtils.getIpAdrress(request));
//設(shè)置請(qǐng)求方法,GET,POST...
accessLog.setHttpMethod(request.getMethod());
//設(shè)置請(qǐng)求路徑
accessLog.setUrl(request.getRequestURI());
//設(shè)置請(qǐng)求開(kāi)始時(shí)間
request.setAttribute(LOGGER_SEND_TIME,System.currentTimeMillis());
//設(shè)置請(qǐng)求實(shí)體到request內(nèi),方便afterCompletion方法調(diào)用
request.setAttribute(LOGGER_ACCESSLOG,accessLog);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) throws Exception {
//獲取本次請(qǐng)求日志實(shí)體
AccessLog accessLog = (AccessLog) request.getAttribute(LOGGER_ACCESSLOG);
//獲取請(qǐng)求錯(cuò)誤碼,根據(jù)需求存入數(shù)據(jù)庫(kù),這里不保存
int status = response.getStatus();
accessLog.setHttpStatus(status);
//設(shè)置訪問(wèn)者(這里暫時(shí)寫(xiě)死)
// 因?yàn)椴煌膽?yīng)用可能將訪問(wèn)者信息放在session里面,有的通過(guò)request傳遞,
// 總之可以獲取到,但獲取的方法不同
accessLog.setUsername("admin");
//當(dāng)前時(shí)間
long currentTime = System.currentTimeMillis();
//請(qǐng)求開(kāi)始時(shí)間
long snedTime = Long.valueOf(request.getAttribute(LOGGER_SEND_TIME).toString());
//設(shè)置請(qǐng)求時(shí)間差
accessLog.setDuration(Integer.valueOf((currentTime - snedTime)+""));
accessLog.setCreateTime(new Date());
//將sysLog對(duì)象持久化保存
logger.info(accessLog.toString());
}
}
上文中LoggerFactory.getLogger("ACCESS-LOG")
獲取一個(gè)日志配置中的Logger的名字,用于打印日志輸出,持久化到日志文件里面。"ACCESS-LOG"的日志Logger定義我們下文中介紹。
四、攔截器注冊(cè)
攔截器注冊(cè)就不細(xì)講了,前面的章節(jié)已經(jīng)介紹過(guò),回看。
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
//設(shè)置排除路徑,spring boot 2.*,注意排除掉靜態(tài)資源的路徑,不然靜態(tài)資源無(wú)法訪問(wèn)
private final String[] excludePath = {"/static"};
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AccessLogInterceptor()).addPathPatterns("/**").excludePathPatterns(excludePath);
}
}
五、獲取ip訪問(wèn)地址的工具類(lèi)
上面的代碼中涉及到一個(gè)工具類(lèi),用于獲取請(qǐng)求客戶端的ip。代碼如下:
public class AdrressIpUtils {
/**
* 獲取Ip地址
* @param request HttpServletRequest
* @return ip
*/
public static String getIpAdrress(HttpServletRequest request) {
String Xip = request.getHeader("X-Real-IP");
String XFor = request.getHeader("X-Forwarded-For");
if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
//多次反向代理后會(huì)有多個(gè)ip值,第一個(gè)ip才是真實(shí)ip
int index = XFor.indexOf(",");
if(index != -1){
return XFor.substring(0,index);
}else{
return XFor;
}
}
XFor = Xip;
if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
return XFor;
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getRemoteAddr();
}
return XFor;
}
}
六、"ACCESS-LOG"的日志Logger定義
下文中的配置參考以Log4J2配置為例(參考上一節(jié)的內(nèi)容進(jìn)行學(xué)習(xí))
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-y0r1Nn7P-1644633419822)(images/screenshot_1598061650386.png)]
-
LoggerFactory.getLogger("ACCESS-LOG")
代碼去配置文件里面找一個(gè)name為ACCESS-LOG的Logger配置。 - 該Logger是一個(gè)AsyncLogger,指向的輸出目標(biāo)是ACCESS-APPENDER
- ACCESS-APPENDER是一個(gè)日志文件輸出配置,日志文件是access-log.log
<configuration>
<properties>
<property name="LOG_HOME">D:/logsproperty>
properties>
<Appenders>
<RollingFile name="ACCESS-APPENDER"
fileName="${LOG_HOME}/access.log"
filePattern="${LOG_HOME}/access-%d{yyyy-MM-dd}-%i.log">
<PatternLayout>
<pattern>[%d][%p][%t][%C] %m%npattern>
PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="100MB"/>
<TimeBasedTriggeringPolicy/>
Policies>
<DefaultRolloverStrategy max="20"/>
RollingFile>
Appenders>
<Loggers>
<AsyncLogger name="ACCESS-LOG" level="debug" additivity="false">
<AppenderRef ref="ACCESS-APPENDER" level="info"/>
AsyncLogger>
Loggers>
configuration>
原文鏈接:https://blog.csdn.net/hanxiaotongtong/article/details/122893220
相關(guān)推薦
- 2022-07-19 iptables限制docker端口禁止對(duì)某臺(tái)主機(jī)進(jìn)行提供服務(wù)
- 2022-09-09 python處理xml文件操作詳解_python
- 2022-11-19 C++如何去除cpp文件的注釋詳解_C 語(yǔ)言
- 2022-06-21 Android實(shí)現(xiàn)登錄界面的注冊(cè)功能_Android
- 2022-08-15 Python包裝異常處理方法_python
- 2023-05-20 命令行傳遞參數(shù)argparse.ArgumentParser的使用解析_python
- 2022-07-04 C#實(shí)現(xiàn)進(jìn)制轉(zhuǎn)換_C#教程
- 2022-01-06 springmvc中的model和HttpServletRequest的區(qū)別詳細(xì)分析
- 欄目分類(lèi)
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支