版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第springboot打印接口调用日志的实例目录概述方案思路封装HttpServletRequest请求把可重复读请求体通过过滤器往下传记录入参日志实现入参记录拦截器注册拦截器记录返参日志
概述
请求日志几乎是所有大型企业级项目的必要的模块,请求日志对于我们来说后期在项目运行上线一段时间用于排除异常、请求分流处理、限制流量等。
请求日志一般都会记录请求参数、请求地址、请求状态(StatusCode)、SessionId、请求方法方式(Method)、请求时间、客户端IP地址、请求返回内容、耗时等等。如果你得系统还有其他个性化的配置,也可以完成记录。
记录请求参数时,由于servlet.getInputStream的数据只能读取一次,因此需要先把数据缓存下来,构造返回流,保证之后的Controller可以正常读取到请求体的数据。
方案思路
封装HttpServletRequest请求类,改类在构造方法中将请求的输入流中的数据缓存了起来,保证之后的处理可以重复读取输入流中的数据。实现过滤器,把上步封装的请求类传下去,保证Controller可以正常读取输入流中的数据。添加拦截器,读取输入流中的数据。读取返回参数。
封装HttpServletRequest请求
packageercept;
importjavax.servlet.ReadListener;
importjavax.servlet.ServletInputStream;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletRequestWrapper;
importjava.io.*;
*@author
*@date封装HttpServletRequest请求
publicclassRequestWrapperextendsHttpServletRequestWrapper{
privatefinalStringbody;
publicRequestWrapper(HttpServletRequestrequest){
super(request);
StringBuilderstringBuilder=newStringBuilder();
BufferedReaderbufferedReader=null;
InputStreaminputStream=null;
try{
inputStream=request.getInputStream();
if(inputStream!=null){
bufferedReader=newBufferedReader(newInputStreamReader(inputStream));
char[]charBuffer=newchar[128];
intbytesBody=-1;
while((bytesBody=bufferedReader.read(charBuffer))0){
stringBuilder.append(charBuffer,0,bytesBody);
}
}else{
stringBuilder.append("");
}
}catch(IOExceptione){
}finally{
if(inputStream!=null){
try{
inputStream.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
if(bufferedReader!=null){
try{
bufferedReader.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
body=stringBuilder.toString();
}
@Override
publicServletInputStreamgetInputStream()throwsIOException{
finalByteArrayInputStreambyteArrayInputStream=newByteArrayInputStream(body.getBytes());
ServletInputStreamservletInputStream=newServletInputStream(){
@Override
publicbooleanisFinished(){
returnfalse;
}
@Override
publicbooleanisReady(){
returnfalse;
}
@Override
publicvoidsetReadListener(ReadListenerreadListener){
}
@Override
publicintread()throwsIOException{
returnbyteArrayInputStream.read();
}
};
returnservletInputStream;
}
@Override
publicBufferedReadergetReader()throwsIOException{
returnnewBufferedReader(newInputStreamReader(this.getInputStream()));
}
publicStringgetBody(){
returnthis.body;
}
}
把可重复读请求体通过过滤器往下传
防止请求流读取一次后就没有了,之后的不管是过滤器、拦截器、处理器都是读的已经缓存好的数据,实现可重复读。
packageercept;
importorg.springframework.stereotype.Component;
importjavax.servlet.*;
importjavax.servlet.annotation.WebFilter;
importjavax.servlet.http.HttpServletRequest;
importjava.io.IOException;
*@author
*@date防止请求流读取一次后就没有了
@Component
@WebFilter(urlPatterns="/**")
publicclassRecordChannelFilterimplementsFilter{
@Override
publicvoidinit(FilterConfigfilterConfig)throwsServletException{
}
@Override
publicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainfilterChain)throwsIOException,ServletException{
ServletRequestrequest=null;
if(servletRequestinstanceofHttpServletRequest){
request=newRequestWrapper((HttpServletRequest)servletRequest);
}
if(request==null){
//防止流读取一次就没有了,将流传递下去
filterChain.doFilter(servletRequest,servletResponse);
}else{
filterChain.doFilter(request,servletResponse);
}
}
@Override
publicvoiddestroy(){
}
}
记录入参日志
实现入参记录拦截器
通过拦截器的方式实现用户入参记录。
packageercept;
importcom.alibaba.fastjson.JSONObject;
importorg.bouncycastle.util.encoders.Base64;
importorg.springframework.stereotype.Component;
importorg.springframework.web.servlet.HandlerInterceptor;
importio.jsonwebtoken.Claims;
importjavax.annotation.Resource;
importjavax.crypto.spec.SecretKeySpec;
importjavax.servlet.http.Cookie;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjava.util.ArrayList;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
*@author
*@date记录用户操作记录入参
@Component
publicclassOperationLogInterceptorimplementsHandlerInterceptor{
/**
*Jwtsecert串,需要与加密token的秘钥一致
*/
publicstaticfinalStringJWT_SECERT="23142d7a9s7d66970ad07d8sa";
/**
*需要记录的接口URL
*/
privatestaticListStringpathList=newArrayList();
static{
pathList.add("/mdms/model");
}
@Resource
privateFunctionDOMapperfunctionDOMapper;//菜单动能sql
@Resource
privateUserOperationHistoryDOMapperhistoryDOMapper;//操作日志记录表
@Override
publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler){
StringservletPath=""+request.getServletPath();
Stringmethod=request.getMethod();
pathList.forEach(path-{
if(servletPath.contains(path)){
Cookie[]cookies=request.getCookies();
if(cookies!=null){
for(Cookiecookie:cookies){
//获取token在请求中
if(cookie.getName().equals("_qjt_ac_")){
Stringtoken=cookie.getValue();
/**解密token**/
byte[]encodeKey=Base64.decode(JWT_SECERT);
Claimsclaims=null;
try{
SecretKeySpeckeySpec=newSecretKeySpec(encodeKey,0,encodeKey.length,"AES");
claims=Jwts.parser().setSigningKey(keySpec).parseClaimsJws(token).getBody();
}catch(Exceptione){
return;
}
//用户账号
Stringaccount=claims.getSubject();
//查询URL在功能表中的功能
functionDOMapper.selectOne(servletPath,method);
//获取入参
RequestWrapperrequestWrapper=null;
if(requestinstanceofHttpServletRequest){
requestWrapper=newRequestWrapper(request);
}
MapString,Objectmap=newHashMap();
map.put("parameter",JSONObject.parse(requestWrapper.getBody()));
historyDOMapper.insert(map);//将操作信息入库
}
}
}
}
});
returntrue;
}
}
注册拦截器
packagecom.example.demo.config;
importercept.OperationLogInterceptor;
importorg.springframework.context.annotation.Bean;
importorg.springframework.web.servlet.HandlerInterceptor;
importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;
importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;
*@author
*@date注册拦截器
publicclassWebConfigimplementsWebMvcConfigurer{
@Bean
publicHandlerInterceptorgetOperationLogInterceptor(){
returnnewOperationLogInterceptor();
}
@Override
publicvoidaddInterceptors(InterceptorRegistryregistry){
registry.addInterceptor(getOperationLogInterceptor()).addPathPatterns("/**").excludePathPatterns();
}
}
记录返参日志
packageercept;
importcom.alibaba.fastjson.JSONObject;
importorg.bouncycastle.util.encoders.Base64;
importorg.springframework.core.MethodParameter;
importorg.springframework.http.HttpHeaders;
importorg.springframework.http.MediaType;
importorg.springframework.http.converter.HttpMessageConverter;
importorg.springframework.http.server.ServerHttpRequest;
importorg.springframework.http.server.ServerHttpResponse;
importorg.springframework.util.CollectionUtils;
importorg.springframework.web.bind.annotation.ControllerAdvice;
importorg.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
importjavax.annotation.Resource;
importjavax.crypto.spec.SecretKeySpec;
importjavax.servlet.http.HttpServletRequest;
importjavax.xml.ws.Response;
importjava.util.*;
*@author
*@date记录用户操作日志返参
@ControllerAdvice(basePackages="项目包")
publicclassGetResponseBodyimplementsResponseBodyAdviceObject{
/**
*Jwtsecert串,需要与加密token的秘钥一致
*/
publicstaticfinalStringJWT_SECERT="23142d7a9s7d66970ad07d8sa";
/**
*需要记录的接口URL
*/
privatestaticListStringpathList=newArrayList();
static{
pathList.add("/mdms/model");
}
@Resource
privateFunctionDOMapperfunctionDOMapper;//菜单动能sql
@Resource
privateUserOperationHistoryDOMapperhistoryDOMapper;//操作日志记录表
@Override
publicbooleansupports(MethodParametermethodParameter,ClassextendsHttpMessageConverteraClass){
returnfalse;
}
@Override
publicObjectbeforeBodyWrite(Objectbody,MethodParametermethodParameter,MediaTypemediaType,ClassextendsHttpMessageConverteraClass,ServerHttpRequestserverHttpRequest,ServerHttpResponseserverHttpResponse){
Stringpath=serverHttpRequest.getURI().getPath();
StringmethodValue=serverHttpRequest.getMethodValue();
pathList.forEach(serverPath-{
if(path.contains(serverPath)){
HashMapString,StringcookieMap=newHashMap();
HttpHeadersheaders=serverHttpRequest.getHeaders();
ListStringcookieList=headers.get("cookie");
if(CollectionUtils.isEmpty(cookieList)){
return;
}
StringreplaceAll=cookieList.get(0).replaceAll(";","").replaceAll(";","");
String[]split=replaceAll.split(";");
for(Stringcookie:split){
String[]param=cookie.split("=");
cookieMap.put(param[0],param[1]);
}
Stringtoken=cookieMap.get("_qjt_ac_");
byte[]encodeKey=Base64.decode(JWT_SECERT);
Claimsclaims=null;
try{
SecretKeySpeckeySpec=newSecretKeySpec(encodeKey,0,encodeKey.length,"AES");
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 生产新员工上岗操作培训工作手册
- 2026北京顺义区教委所属事业单位第二次招聘教师189人备考题库附答案详解(综合卷)
- 2026浙江台州市椒江区三甲街道招聘4人备考题库含答案详解
- 城市夜游经济开发运营手册
- 2026中航贵州飞机有限责任公司重点人才蓄水池及成熟人才岗位招聘13人备考题库附答案详解(培优)
- 2026广东佛山市第二人民医院服务中心招聘18人备考题库含答案详解(巩固)
- 2026青海黄南州同德县紧密型县域医共体招聘2人备考题库含答案详解(基础题)
- 2026年安徽艺术学院专职思政课教师招聘1人备考题库及答案详解(基础+提升)
- 2026广东江门市新会古兜水电发展有限公司副经理选聘2人备考题库含答案详解(夺分金卷)
- 2026中山大学孙逸仙纪念医院心血管内科心电图室医教研岗位人员招聘1人备考题库附答案详解(典型题)
- 人工智能导论智慧树知到期末考试答案章节答案2024年哈尔滨工程大学
- 《公路桥涵养护规范》(JTG5120-2021)
- 饲料质量培训课件
- 用药交代题文档
- 我的家乡湖南长沙宣传简介
- 北师大版一年级数学下册《捉迷藏》说课稿课件
- 高考英语高频词组+短语+固定搭配
- 王慧文清华大学《互联网产品管理课》
- 3206回撤作业规程
- 循证医学课件:临床实践指南的评价与应用
- (4.3.1)-4.3平面问题三角形单元刚度矩阵
评论
0/150
提交评论