最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

springboot打印接口調(diào)用日志的實例

 更新時間:2022年09月30日 08:35:04   作者:融極  
這篇文章主要介紹了springboot打印接口調(diào)用日志的實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

概述

請求日志幾乎是所有大型企業(yè)級項目的必要的模塊,請求日志對于我們來說后期在項目運行上線一段時間用于排除異常、請求分流處理、限制流量等。

請求日志一般都會記錄請求參數(shù)、請求地址、請求狀態(tài)(Status Code)、SessionId、請求方法方式(Method)、請求時間、客戶端IP地址、請求返回內(nèi)容、耗時等等。如果你得系統(tǒng)還有其他個性化的配置,也可以完成記錄。

記錄請求參數(shù)時,由于servlet.getInputStream的數(shù)據(jù)只能讀取一次,因此需要先把數(shù)據(jù)緩存下來,構造返回流,保證之后的Controller可以正常讀取到請求體的數(shù)據(jù)。

方案思路

  • 封裝HttpServletRequest請求類,改類在構造方法中將請求的輸入流中的數(shù)據(jù)緩存了起來,保證之后的處理可以重復讀取輸入流中的數(shù)據(jù)。
  • 實現(xiàn)過濾器,把上步封裝的請求類傳下去,保證Controller可以正常讀取輸入流中的數(shù)據(jù)。
  • 添加攔截器,讀取輸入流中的數(shù)據(jù)。
  • 讀取返回參數(shù)。

封裝HttpServletRequest請求

package com.example.demo.intercept;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
/**
?* @author?
?* @date 封裝HttpServletRequest請求
?*/
public class RequestWrapper extends HttpServletRequestWrapper {
? ? private final String body;
? ? public RequestWrapper(HttpServletRequest request) {
? ? ? ? super(request);
? ? ? ? StringBuilder stringBuilder = new StringBuilder();
? ? ? ? BufferedReader bufferedReader = null;
? ? ? ? InputStream inputStream = null;
? ? ? ? try {
? ? ? ? ? ? inputStream = request.getInputStream();
? ? ? ? ? ? if (inputStream != null) {
? ? ? ? ? ? ? ? bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
? ? ? ? ? ? ? ? char[] charBuffer = new char[128];
? ? ? ? ? ? ? ? int bytesBody = -1;
? ? ? ? ? ? ? ? while ((bytesBody = bufferedReader.read(charBuffer)) > 0) {
? ? ? ? ? ? ? ? ? ? stringBuilder.append(charBuffer, 0, bytesBody);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? stringBuilder.append("");
? ? ? ? ? ? }
? ? ? ? } catch (IOException e) {
? ? ? ? } finally {
? ? ? ? ? ? if (inputStream != null) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? inputStream.close();
? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? if (bufferedReader != null) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? bufferedReader.close();
? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? body = stringBuilder.toString();
? ? }
? ? @Override
? ? public ServletInputStream getInputStream() throws IOException {
? ? ? ? final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
? ? ? ? ServletInputStream servletInputStream = new ServletInputStream() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public boolean isFinished() {
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public boolean isReady() {
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public void setReadListener(ReadListener readListener) {
? ? ? ? ? ? }
? ? ? ? ? ? @Override
? ? ? ? ? ? public int read() throws IOException {
? ? ? ? ? ? ? ? return byteArrayInputStream.read();
? ? ? ? ? ? }
? ? ? ? };
? ? ? ? return servletInputStream;
? ? }
? ? @Override
? ? public BufferedReader getReader() throws IOException {
? ? ? ? return new BufferedReader(new InputStreamReader(this.getInputStream()));
? ? }
? ? public String getBody() {
? ? ? ? return this.body;
? ? }
}

把可重復讀請求體通過過濾器往下傳

防止請求流讀取一次后就沒有了,之后的不管是過濾器、攔截器、處理器都是讀的已經(jīng)緩存好的數(shù)據(jù),實現(xiàn)可重復讀。

package com.example.demo.intercept;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
?* @author?
?* @date 防止請求流讀取一次后就沒有了
?*/
@Component
@WebFilter(urlPatterns = "/**")
public class RecordChannelFilter implements Filter {
? ? @Override
? ? public void init(FilterConfig filterConfig) throws ServletException {
? ? }
? ? @Override
? ? public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
? ? ? ? ServletRequest request = null;
? ? ? ? if (servletRequest instanceof HttpServletRequest) {
? ? ? ? ? ? request = new RequestWrapper((HttpServletRequest) servletRequest);
? ? ? ? }
? ? ? ? if (request ==null){
? ? ? ? ? ? //防止流讀取一次就沒有了,將流傳遞下去
? ? ? ? ? ? filterChain.doFilter(servletRequest,servletResponse);
? ? ? ? }else {
? ? ? ? ? ? filterChain.doFilter(request,servletResponse);
? ? ? ? }
? ? }
? ? @Override
? ? public void destroy() {
? ? }
}

記錄入?yún)⑷罩?/h2>

實現(xiàn)入?yún)⒂涗洈r截器

通過攔截器的方式實現(xiàn)用戶入?yún)⒂涗洝?/p>

package com.example.demo.intercept;
import com.alibaba.fastjson.JSONObject;
import org.bouncycastle.util.encoders.Base64;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import io.jsonwebtoken.Claims;
import javax.annotation.Resource;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
?* @author?
?* @date 記錄用戶操作記錄入?yún)?
?*/
@Component
public class OperationLogInterceptor implements HandlerInterceptor {
? ? /**
? ? ?* Jwt secert串,需要與加密token的秘鑰一致
? ? ?*/
? ? public static final String JWT_SECERT = "23142d7a9s7d66970ad07d8sa";
? ? /**
? ? ?* 需要記錄的接口URL
? ? ?*/
? ? private static List<String> pathList = new ArrayList<>();
? ? static {
? ? ? ? pathList.add("/mdms/model");
? ? }
? ? @Resource
? ? private FunctionDOMapper functionDOMapper;//菜單動能sql
? ? @Resource
? ? private UserOperationHistoryDOMapper historyDOMapper;//操作日志記錄表
? ? @Override
? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
? ? ? ? String servletPath = "" + request.getServletPath();
? ? ? ? String method = request.getMethod();
? ? ? ? pathList.forEach(path -> {
? ? ? ? ? ? if (servletPath.contains(path)){
? ? ? ? ? ? ? ? Cookie[] cookies = request.getCookies();
? ? ? ? ? ? ? ? if (cookies != null) {
? ? ? ? ? ? ? ? ? ? for (Cookie cookie : cookies) {
? ? ? ? ? ? ? ? ? ? ? ? //獲取token在請求中
? ? ? ? ? ? ? ? ? ? ? ? if (cookie.getName().equals("_qjt_ac_")) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? String token = cookie.getValue();
? ? ? ? ? ? ? ? ? ? ? ? ? ? /**解密token**/
? ? ? ? ? ? ? ? ? ? ? ? ? ? byte[] encodeKey = Base64.decode(JWT_SECERT);
? ? ? ? ? ? ? ? ? ? ? ? ? ? Claims claims = null;
? ? ? ? ? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? SecretKeySpec keySpec = new SecretKeySpec(encodeKey, 0, encodeKey.length, "AES");
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? claims = Jwts.parser().setSigningKey(keySpec).parseClaimsJws(token).getBody();
? ? ? ? ? ? ? ? ? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return;
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? //用戶賬號
? ? ? ? ? ? ? ? ? ? ? ? ? ? String account = claims.getSubject();
? ? ? ? ? ? ? ? ? ? ? ? ? ? //查詢URL在功能表中的功能
? ? ? ? ? ? ? ? ? ? ? ? ? ? functionDOMapper.selectOne(servletPath, method);
? ? ? ? ? ? ? ? ? ? ? ? ? ? //獲取入?yún)?
? ? ? ? ? ? ? ? ? ? ? ? ? ? RequestWrapper requestWrapper = null;
? ? ? ? ? ? ? ? ? ? ? ? ? ? if (request instanceof HttpServletRequest) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? requestWrapper = new RequestWrapper(request);
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? Map<String,Object> map = new HashMap<>();
? ? ? ? ? ? ? ? ? ? ? ? ? ? map.put("parameter", JSONObject.parse(requestWrapper.getBody()));
? ? ? ? ? ? ? ? ? ? ? ? ? ? historyDOMapper.insert(map);//將操作信息入庫
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }?
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? return true;
? ? }
}

注冊攔截器

package com.example.demo.config;
import com.example.demo.intercept.OperationLogInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
?* @author?
?* @date 注冊攔截器
?*/
public class WebConfig implements WebMvcConfigurer {
? ? @Bean
? ? public HandlerInterceptor getOperationLogInterceptor() {
? ? ? ? return new OperationLogInterceptor();
? ? }
? ? @Override
? ? public void addInterceptors(InterceptorRegistry registry){
? ? ? ? registry.addInterceptor(getOperationLogInterceptor()).addPathPatterns("/**").excludePathPatterns();
? ? }
}

記錄返參日志

package com.example.demo.intercept;
import com.alibaba.fastjson.JSONObject;
import org.bouncycastle.util.encoders.Base64;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import javax.annotation.Resource;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.xml.ws.Response;
import java.util.*;
/**
?* @author?
?* @date 記錄用戶操作日志返參
?*/
@ControllerAdvice(basePackages = "項目包")
public class GetResponseBody implements ResponseBodyAdvice<Object> {
? ? /**
? ? ?* Jwt secert串,需要與加密token的秘鑰一致
? ? ?*/
? ? public static final String JWT_SECERT = "23142d7a9s7d66970ad07d8sa";
? ? /**
? ? ?* 需要記錄的接口URL
? ? ?*/
? ? private static List<String> pathList = new ArrayList<>();
? ? static {
? ? ? ? pathList.add("/mdms/model");
? ? }
? ? @Resource
? ? private FunctionDOMapper functionDOMapper;//菜單動能sql
? ? @Resource
? ? private UserOperationHistoryDOMapper historyDOMapper;//操作日志記錄表
? ? @Override
? ? public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
? ? ? ? return false;
? ? }
? ? @Override
? ? public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
? ? ? ? String path = serverHttpRequest.getURI().getPath();
? ? ? ? String methodValue = serverHttpRequest.getMethodValue();
? ? ? ? pathList.forEach(serverPath -> {
? ? ? ? ? ? if (path.contains(serverPath)) {
? ? ? ? ? ? ? ? HashMap<String, String> cookieMap = new HashMap<>();
? ? ? ? ? ? ? ? HttpHeaders headers = serverHttpRequest.getHeaders();
? ? ? ? ? ? ? ? List<String> cookieList = headers.get("cookie");
? ? ? ? ? ? ? ? if (CollectionUtils.isEmpty(cookieList)) {
? ? ? ? ? ? ? ? ? ? return;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? String replaceAll = cookieList.get(0).replaceAll(";", "").replaceAll(";", "");
? ? ? ? ? ? ? ? String[] split = replaceAll.split(";");
? ? ? ? ? ? ? ? for (String cookie : split) {
? ? ? ? ? ? ? ? ? ? String[] param = cookie.split("=");
? ? ? ? ? ? ? ? ? ? cookieMap.put(param[0], param[1]);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? String token = cookieMap.get("_qjt_ac_");
? ? ? ? ? ? ? ? byte[] encodeKey = Base64.decode(JWT_SECERT);
? ? ? ? ? ? ? ? Claims claims = null;
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? SecretKeySpec keySpec = new SecretKeySpec(encodeKey, 0, encodeKey.length, "AES");
? ? ? ? ? ? ? ? ? ? claims = Jwts.parser().setSigningKey(keySpec).parseClaimsJws(token).getBody();
? ? ? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? ? ? return;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? //用戶賬號
? ? ? ? ? ? ? ? String account = claims.getSubject();
? ? ? ? ? ? ? ? //查詢URL在功能表中的功能
? ? ? ? ? ? ? ? functionDOMapper.selectOne(servletPath, method);
? ? ? ? ? ? ? ? //獲取返參
? ? ? ? ? ? ? ? List<Object> list = historyDOMapper.select("功能表參數(shù)", account);
? ? ? ? ? ? ? ? list.sort((Object1,Object2)->Object2.getTime().compareTo(Object1.getTime()));//將查詢到的操作記錄按時間降序排列
? ? ? ? ? ? ? ? Object history = list.get(0);
? ? ? ? ? ? ? ? if (body instanceof Response) {
? ? ? ? ? ? ? ? ? ? Response response = (Response) body;
? ? ? ? ? ? ? ? ? ? JSONObject jsonObject = JSONObject.parseObject(history.getParam());
? ? ? ? ? ? ? ? ? ? jsonObject.put("message",response.getMessage());
? ? ? ? ? ? ? ? ? ? jsonObject.put("body",response.getData());
? ? ? ? ? ? ? ? ? ? history.setParam(jsonObject.toString());
? ? ? ? ? ? ? ? ? ? history.setDes(response.getMessage());
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? historyDOMapper.updateByPrimaryKeySelective(history);//將操作信息更新
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? return body;
? ? }
}

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。 

相關文章

  • Java設計模式之訪問者模式使用場景及代碼示例

    Java設計模式之訪問者模式使用場景及代碼示例

    這篇文章主要介紹了Java設計模式之訪問者模式使用場景及代碼示例,小編覺得還是挺不錯的,這里分享給大家,供需要的朋友參考。
    2017-11-11
  • Springboot教程之如何設置springboot熱重啟

    Springboot教程之如何設置springboot熱重啟

    這篇文章主要介紹了Springboot教程之如何設置springboot熱重啟,本文通過實例圖文相結合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • Java設計模式之策略模式示例詳解

    Java設計模式之策略模式示例詳解

    這篇文章主要為大家詳細介紹了Java的策略模式,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • mybatis 如何判斷l(xiāng)ist集合是否包含指定數(shù)據(jù)

    mybatis 如何判斷l(xiāng)ist集合是否包含指定數(shù)據(jù)

    這篇文章主要介紹了mybatis 判斷l(xiāng)ist集合是否包含指定數(shù)據(jù)的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 純Java代碼實現(xiàn)流星劃過天空

    純Java代碼實現(xiàn)流星劃過天空

    本文給大家介紹純java代碼實現(xiàn)流星劃過天空,包括流星個數(shù),流星飛行的速度,色階,流星大小相關變量設置。對java流星劃過天空特效代碼感興趣的朋友可以參考下本文
    2015-10-10
  • SpringBoot?@InitBinder注解綁定請求參數(shù)的過程詳解

    SpringBoot?@InitBinder注解綁定請求參數(shù)的過程詳解

    這篇文章主要介紹了SpringBoot?@InitBinder注解綁定請求參數(shù),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • Kafka中使用Avro序列化和反序列化詳解

    Kafka中使用Avro序列化和反序列化詳解

    這篇文章主要介紹了Kafka中使用Avro序列化和反序列化詳解,由于Kafka中的數(shù)據(jù)都是字節(jié)數(shù)組,在將消息發(fā)送到Kafka之前需要先將數(shù)據(jù)序列化為字節(jié)數(shù)組, 序列化器的作用就是用于序列化要發(fā)送的消息的,需要的朋友可以參考下
    2023-12-12
  • 基于Springboot實現(xiàn)定時發(fā)送郵件功能

    基于Springboot實現(xiàn)定時發(fā)送郵件功能

    這篇文章主要為大家詳細介紹了基于Springboot實現(xiàn)定時發(fā)送郵件功能的相關知識,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-03-03
  • 基于java中子類的繼承性的應用介紹

    基于java中子類的繼承性的應用介紹

    本篇介紹了,基于java中子類的繼承性的應用。需要的朋友參考下
    2013-05-05
  • SpringBoot配置文件密碼加密與解密的操作代碼

    SpringBoot配置文件密碼加密與解密的操作代碼

    我們在SpringBoot項目當中,會把數(shù)據(jù)庫的用戶名密碼等配置直接放在yaml或者properties文件中,這樣維護數(shù)據(jù)庫的密碼等敏感信息顯然是有一定風險的,所以我們需要給密碼加解密,本文給大家介紹了SpringBoot配置文件密碼加密與解密的操作代碼,需要的朋友可以參考下
    2024-12-12

最新評論

布拖县| 海淀区| 勐海县| 石屏县| 祁阳县| 宁国市| 青阳县| 富锦市| 林州市| 瑞丽市| 沧源| 汤原县| 夏邑县| 桂平市| 宜良县| 额济纳旗| 平原县| 什邡市| 新兴县| 始兴县| 卫辉市| 临漳县| 合作市| 新化县| 宜丰县| 漳浦县| 赞皇县| 洛南县| 武冈市| 屏南县| 微博| 雷波县| 余姚市| 崇文区| 六安市| 阳泉市| 天等县| 依兰县| 仁寿县| 延长县| 临猗县|