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

springboot利用AOP完成日志統(tǒng)計(jì)的詳細(xì)步驟

 更新時(shí)間:2021年12月24日 11:49:29   作者:怪咖軟妹@  
項(xiàng)目用到了過(guò)濾器,可能有的人會(huì)不理解,之所以用過(guò)濾器是因?yàn)橄胍谌罩居涗沺ost請(qǐng)求的json數(shù)據(jù)。本文重點(diǎn)給大家介紹springboot利用AOP完成日志統(tǒng)計(jì)的詳細(xì)步驟,感興趣的朋友跟隨小編一起看看吧

步驟寫(xiě)的很詳細(xì),可以直接復(fù)制拿來(lái)用的,其中用到了過(guò)濾器、自定義注解以及AOP切面,來(lái)完成日志記錄統(tǒng)計(jì),感興趣的收藏起來(lái),以后遇到了可以直接用。

可能步驟會(huì)比較多,但是整體跟著思路下來(lái),應(yīng)該沒(méi)什么大問(wèn)題的。

項(xiàng)目用到了過(guò)濾器,可能有的人會(huì)不理解,之所以用過(guò)濾器是因?yàn)橄胍谌罩居涗沺ost請(qǐng)求的json數(shù)據(jù)。

請(qǐng)求的時(shí)候,是通過(guò)request的body來(lái)傳輸?shù)?。在AOP后置方法中獲取request里面的body,是取不到,直接為空。

原因很簡(jiǎn)單:因?yàn)槭橇?。想想看,java中的流也是只能讀一次,因?yàn)槲沂窃贏OP后置方法獲取的,控制器實(shí)際上已經(jīng)讀過(guò)了一次,后置方法再讀自然為空了。所以用過(guò)濾器來(lái)進(jìn)行解決了這個(gè)問(wèn)題。

1、創(chuàng)建日志表

這里我用的是mysql,假如您用的別的數(shù)據(jù)庫(kù),可以自行根據(jù)數(shù)據(jù)庫(kù)類(lèi)型進(jìn)行修改。

CREATE TABLE `log`  (
  `id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主鍵',
  `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '創(chuàng)建人',
  `create_time` datetime NULL DEFAULT NULL COMMENT '創(chuàng)建時(shí)間',
  `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '最近更新時(shí)間',
  `update_time` datetime NULL DEFAULT NULL COMMENT '最近更新人',
  `update_count` int(11) NULL DEFAULT NULL COMMENT '更新次數(shù)',
  `delete_flag` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '刪除標(biāo)志',
  `delete_time` datetime NULL DEFAULT NULL COMMENT '刪除日期',
  `delete_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '刪除人',
  `cost_time` int(11) NULL DEFAULT NULL COMMENT '花費(fèi)時(shí)間',
  `ip` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'ip',
  `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '日志描述',
  `request_param` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '請(qǐng)求參數(shù)',
  `request_json` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '請(qǐng)求json數(shù)據(jù)',
  `request_type` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '請(qǐng)求類(lèi)型',
  `request_url` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '請(qǐng)求路徑',
  `username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '請(qǐng)求用戶(hù)',
  `operation_type` int(3) NULL DEFAULT NULL COMMENT '操作類(lèi)型',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

2、創(chuàng)建實(shí)體類(lèi)

我的項(xiàng)目運(yùn)用到了mybatisplus、swagger、lombok,你們可以根據(jù)自己項(xiàng)目框架寫(xiě)對(duì)應(yīng)的實(shí)體類(lèi)。BaseModel 是我們封裝了一個(gè)基礎(chǔ)實(shí)體類(lèi),專(zhuān)門(mén)存放關(guān)于操作人的信息,然后實(shí)體類(lèi)直接繼承。

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import cn.org.xaas.mybatis.model.BaseModel;
import lombok.Data;
import lombok.ToString;

@TableName(value = "log")
@Data
@ToString(callSuper = true)
public class Log extends BaseModel {

    @ApiModelProperty(value = "花費(fèi)時(shí)間")
    @TableField(value = "cost_time")
    private Integer costTime;

    @ApiModelProperty(value = "ip")
    @TableField(value = "ip")
    private String ip;

    @ApiModelProperty(value = "日志描述")
    @TableField(value = "description")
    private String description;

    @ApiModelProperty(value = "請(qǐng)求參數(shù)")
    @TableField(value = "request_param")
    private String requestParam;

    @ApiModelProperty(value = "請(qǐng)求json數(shù)據(jù)")
    @TableField(value = "request_json")
    private String requestJson;

    @ApiModelProperty(value = "請(qǐng)求類(lèi)型")
    @TableField(value = "request_type")
    private String requestType;

    @ApiModelProperty(value = "請(qǐng)求路徑")
    @TableField(value = "request_url")
    private String requestUrl;

    @ApiModelProperty(value = "請(qǐng)求用戶(hù)")
    @TableField(value = "username")
    private String username;

    @ApiModelProperty(value = "操作類(lèi)型")
    @TableField(value = "operation_type")
    private Integer operationType;
}

3、創(chuàng)建枚舉類(lèi)

用來(lái)記錄日志操作類(lèi)型

public enum OperationType {
    /**
     * 操作類(lèi)型
     */
    UNKNOWN("unknown"),
    DELETE("delete"),
    SELECT("select"),
    UPDATE("update"),
    INSERT("insert");

    OperationType(String s) {
        this.value = s;
    }

    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

4、創(chuàng)建自定義注解

import java.lang.annotation.*;

@Target({ElementType.PARAMETER, ElementType.METHOD})//作用于參數(shù)或方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemLog {

    /**
     * 日志名稱(chēng)
     *
     * @return
     */
    String description() default "";

    /**
     * 操作類(lèi)型
     *
     * @return
     */
    OperationType type() default OperationType.UNKNOWN;
}

5、獲取ip的util

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
@Slf4j
@Component
public class IpInfoUtil {

    /**
     * 獲取客戶(hù)端IP地址
     *
     * @param request 請(qǐng)求
     * @return
     */
    public String getIpAddr(HttpServletRequest request) {

        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            if ("127.0.0.1".equals(ip)) {
                //根據(jù)網(wǎng)卡取本機(jī)配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ip = inet.getHostAddress();
            }
        }
        // 對(duì)于通過(guò)多個(gè)代理的情況,第一個(gè)IP為客戶(hù)端真實(shí)IP,多個(gè)IP按照','分割
        if (ip != null && ip.length() > 15) {
            if (ip.indexOf(",") > 0) {
                ip = ip.substring(0, ip.indexOf(","));
            }
        }
        if ("0:0:0:0:0:0:0:1".equals(ip)) {
            ip = "127.0.0.1";
        }
        return ip;
    }
}

6、線程池util

利用線程異步記錄日志。所以直接用了一個(gè)util維護(hù)線程池。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolUtil {

    /**
     * 線程緩沖隊(duì)列
     */
    private static BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(100);
    /**
     * 核心線程數(shù),會(huì)一直存活,即使沒(méi)有任務(wù),線程池也會(huì)維護(hù)線程的最少數(shù)量
     */
    private static final int SIZE_CORE_POOL = 5;
    /**
     * 線程池維護(hù)線程的最大數(shù)量
     */
    private static final int SIZE_MAX_POOL = 10;
    /**
     * 線程池維護(hù)線程所允許的空閑時(shí)間
     */
    private static final long ALIVE_TIME = 2000;

    private static ThreadPoolExecutor pool = new ThreadPoolExecutor(SIZE_CORE_POOL, SIZE_MAX_POOL, ALIVE_TIME, TimeUnit.MILLISECONDS, bqueue, new ThreadPoolExecutor.CallerRunsPolicy());

    static {

        pool.prestartAllCoreThreads();
    }

    public static ThreadPoolExecutor getPool() {
        return pool;
    }

    public static void main(String[] args) {
        System.out.println(pool.getPoolSize());
    }
}

7、HttpServletRequest實(shí)現(xiàn)類(lèi)

這個(gè)就是重寫(xiě)的一個(gè)HttpServletRequest類(lèi)。

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

public class BodyReaderRequestWrapper extends HttpServletRequestWrapper {

    private final String body;

    /**
     * @param request
     */
    public BodyReaderRequestWrapper(HttpServletRequest request) {
        super(request);
        StringBuilder sb = new StringBuilder();
        InputStream ins = null;
        BufferedReader isr = null;
        try {
            ins = request.getInputStream();
            if (ins != null) {
                isr = new BufferedReader(new InputStreamReader(ins));
                char[] charBuffer = new char[128];
                int readCount = 0;
                while ((readCount = isr.read(charBuffer)) != -1) {
                    sb.append(charBuffer, 0, readCount);
                }
            } else {
                sb.append("");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (isr != null) {
                    isr.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (ins != null) {
                    ins.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        body = sb.toString();
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body.getBytes());
        ServletInputStream servletIns = 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 byteArrayIns.read();
            }
        };
        return servletIns;
    }
}

8、添加過(guò)濾器

這個(gè)過(guò)濾器我添加了一個(gè)路徑,就是代表需要json日志的接口,可以在list當(dāng)中添加路徑,不需要取request當(dāng)中json數(shù)據(jù)的可以不配置。

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public class BodyReaderRequestFilter implements Filter {

    private static final Pattern SHOULD_NOT_FILTER_URL_PATTERN;

    static {
        List<String> urlList = new ArrayList<>();
        // 想要通過(guò)aop記錄request當(dāng)中body數(shù)據(jù)的,就需要進(jìn)行配置路徑
        urlList.add("(socket/.*)");
        urlList.add("(test/test1)");
        urlList.add("(test/test2)");
        StringBuilder sb = new StringBuilder();
        for (String url : urlList) {
            sb.append(url);
            sb.append("|");
        }
        sb.setLength(sb.length() - 1);
        SHOULD_NOT_FILTER_URL_PATTERN = Pattern.compile(sb.toString());
    }

    @Override
    public void init(FilterConfig filterConfig) {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        // 獲取訪問(wèn)的url
        String servletPath = request.getServletPath();
        if (SHOULD_NOT_FILTER_URL_PATTERN.matcher(servletPath).find()) {
            BodyReaderRequestWrapper requestWrapper = new BodyReaderRequestWrapper(request);
            if (requestWrapper == null) {
                filterChain.doFilter(request, response);
            } else {
                filterChain.doFilter(requestWrapper, response);
            }
        }else {
            filterChain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {

    }
}

想要讓過(guò)濾器生效需要注入到容器當(dāng)中。

import cn.org.bjca.szyx.xaas.equipment.filter.BodyReaderRequestFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyServerConfig {

    @Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new BodyReaderRequestFilter());
        return registrationBean;
    }
}

9、添加AOP核心類(lèi)

對(duì)于切面,我們可以通過(guò)指定包名,進(jìn)行日志統(tǒng)計(jì),也可以選擇根據(jù)自定義的注解在方法上添加,然后進(jìn)行統(tǒng)計(jì),根據(jù)自己的實(shí)際情況,在切點(diǎn)進(jìn)行配置即可。

LogDao我是沒(méi)有提供的,每個(gè)項(xiàng)目框架不一樣,自行根據(jù)情況進(jìn)行編寫(xiě),就是保存數(shù)據(jù)庫(kù)就可以了。

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import cn.org.xaas.core.util.HeaderSecurityUtils;
import cn.org.xaas.equipment.annotation.SystemLog;
import cn.org.xaas.equipment.dao.LogDao;
import cn.org.xaas.equipment.model.base.Log;
import cn.org.xaas.equipment.utils.IpInfoUtil;
import cn.org.xaas.equipment.utils.ThreadPoolUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
@Slf4j
public class SystemLogAspect {

    private static final ThreadLocal<Date> beginTimeThreadLocal = new NamedThreadLocal<Date>("ThreadLocal beginTime");

    @Autowired
    private LogDao logDao;

    @Autowired
    private IpInfoUtil ipInfoUtil;

    @Autowired(required = false)
    private HttpServletRequest request;

    /**
     * Controller層切點(diǎn),注解方式
     */
    //@Pointcut("execution(* *..controller..*Controller*.*(..))")
    @Pointcut("@annotation(cn.org.xaas.equipment.annotation.SystemLog)")
    public void controllerAspect() {

    }

    /**
     * 前置通知 (在方法執(zhí)行之前返回)用于攔截Controller層記錄用戶(hù)的操作的開(kāi)始時(shí)間
     *
     * @param joinPoint 切點(diǎn)
     * @throws InterruptedException
     */
    @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint) throws InterruptedException {

        //線程綁定變量(該數(shù)據(jù)只有當(dāng)前請(qǐng)求的線程可見(jiàn))
        Date beginTime = new Date();
        beginTimeThreadLocal.set(beginTime);
    }

    /**
     * 后置通知(在方法執(zhí)行之后并返回?cái)?shù)據(jù)) 用于攔截Controller層無(wú)異常的操作
     *
     * @param joinPoint 切點(diǎn)
     */
    @AfterReturning("controllerAspect()")
    public void after(JoinPoint joinPoint) {
        try {
        	// 獲取操作人,每個(gè)系統(tǒng)不一樣,一般存儲(chǔ)與session,此處就不展示了
            String username = HeaderSecurityUtils.getUserName();

            // 讀取json數(shù)據(jù)
            String openApiRequestData = getJSON(request);
            Map<String, String[]> requestParams = request.getParameterMap();

            Log log = new Log();
            if (openApiRequestData != null) {
                log.setRequestJson(JSONUtil.toJsonStr(openApiRequestData));
            }
            log.setId(IdUtil.simpleUUID());
            log.setUsername(username);
            //日志標(biāo)題
            String description = getControllerMethodInfo(joinPoint).get("description").toString();
            log.setDescription(description);
            //日志類(lèi)型
            log.setOperationType((int) getControllerMethodInfo(joinPoint).get("type"));
            //日志請(qǐng)求url
            log.setRequestUrl(request.getRequestURI());
            //請(qǐng)求方式
            log.setRequestType(request.getMethod());
            //請(qǐng)求參數(shù)
            log.setRequestParam(JSONUtil.toJsonStr(requestParams));

            //其他屬性
            log.setIp(ipInfoUtil.getIpAddr(request));
            log.setCreateBy(username);
            log.setUpdateBy(username);
            log.setCreateTime(new Date());
            log.setUpdateTime(new Date());
            log.setDeleteFlag("0");

            //請(qǐng)求開(kāi)始時(shí)間
            long beginTime = beginTimeThreadLocal.get().getTime();
            long endTime = System.currentTimeMillis();
            //請(qǐng)求耗時(shí)
            Long logElapsedTime = endTime - beginTime;
            log.setCostTime(logElapsedTime.intValue());

            //持久化(存儲(chǔ)到數(shù)據(jù)或者ES,可以考慮用線程池)
            ThreadPoolUtil.getPool().execute(new SaveSystemLogThread(log, logDao));

        } catch (Exception e) {
            log.error("AOP后置通知異常", e);
        }
    }

    /**
     * 獲取request的body
     *
     * @param request
     * @return
     */
    public String getJSON(HttpServletRequest request) {
        ServletInputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader streamReader = null;
        StringBuilder responseStrBuilder = new StringBuilder();
        try {
            inputStream = request.getInputStream();
            inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
            streamReader = new BufferedReader(inputStreamReader);
            String inputStr;
            while ((inputStr = streamReader.readLine()) != null) {
                responseStrBuilder.append(inputStr);
            }
        } catch (IOException ioException) {
            ioException.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (inputStreamReader != null) {
                    inputStreamReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (streamReader != null) {
                    streamReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return responseStrBuilder.toString();
    }

    /**
     * 保存日志至數(shù)據(jù)庫(kù)
     */
    private static class SaveSystemLogThread implements Runnable {

        private Log log;
        private LogDao logDao;

        public SaveSystemLogThread(Log esLog, LogDao logDao) {
            this.log = esLog;
            this.logDao = logDao;
        }

        @Override
        public void run() {
            logDao.insert(log);
        }
    }

    /**
     * 獲取注解中對(duì)方法的描述信息 用于Controller層注解
     *
     * @param joinPoint 切點(diǎn)
     * @return 方法描述
     * @throws Exception
     */
    public static Map<String, Object> getControllerMethodInfo(JoinPoint joinPoint) throws Exception {

        Map<String, Object> map = new HashMap<String, Object>(16);
        //獲取目標(biāo)類(lèi)名
        String targetName = joinPoint.getTarget().getClass().getName();
        //獲取方法名
        String methodName = joinPoint.getSignature().getName();
        //獲取相關(guān)參數(shù)
        Object[] arguments = joinPoint.getArgs();
        //生成類(lèi)對(duì)象
        Class targetClass = Class.forName(targetName);
        //獲取該類(lèi)中的方法
        Method[] methods = targetClass.getMethods();

        String description = "";
        Integer type = null;

        for (Method method : methods) {
            if (!method.getName().equals(methodName)) {
                continue;
            }
            Class[] clazzs = method.getParameterTypes();
            if (clazzs.length != arguments.length) {
                //比較方法中參數(shù)個(gè)數(shù)與從切點(diǎn)中獲取的參數(shù)個(gè)數(shù)是否相同,原因是方法可以重載哦
                continue;
            }
            description = method.getAnnotation(SystemLog.class).description();
            type = method.getAnnotation(SystemLog.class).type().ordinal();
            map.put("description", description);
            map.put("type", type);
        }
        return map;
    }

}

10、接口測(cè)試

import cn.org.xaas.equipment.annotation.SystemLog;
import cn.org.xaas.equipment.constant.OperationType;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/test")
public class TestController {

    @PostMapping("/test1")
    @SystemLog(description = "根據(jù)id查詢(xún)某某數(shù)據(jù)",type = OperationType.SELECT)
    public void test1(@RequestParam("id")String id){
        System.out.println(id);
    }


    @PostMapping("/test2")
    @SystemLog(description = "根據(jù)id查詢(xún)某某數(shù)據(jù),傳json",type = OperationType.SELECT)
    public void test2(@RequestBody String id){
        System.out.println(id);
    }
}

調(diào)用第一個(gè)測(cè)試接口:

在這里插入圖片描述
在這里插入圖片描述

調(diào)用第二個(gè)測(cè)試接口:

在這里插入圖片描述
在這里插入圖片描述

到此這篇關(guān)于springboot利用AOP完成日志統(tǒng)計(jì)的文章就介紹到這了,更多相關(guān)springboot日志統(tǒng)計(jì)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot?調(diào)用外部接口的三種實(shí)現(xiàn)方法

    SpringBoot?調(diào)用外部接口的三種實(shí)現(xiàn)方法

    Spring Boot調(diào)用外部接口的方式有多種,常見(jiàn)的有以下三種方式:RestTemplate、Feign 和 WebClient,本文就詳細(xì)介紹一下,感興趣的可以了解一下
    2023-08-08
  • Spring Boot整合Swagger測(cè)試api構(gòu)建全紀(jì)錄

    Spring Boot整合Swagger測(cè)試api構(gòu)建全紀(jì)錄

    這篇文章主要給大家介紹了關(guān)于Spring Boot整合Swagger測(cè)試api構(gòu)建的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01
  • 詳細(xì)聊聊Spring MVC重定向與轉(zhuǎn)發(fā)

    詳細(xì)聊聊Spring MVC重定向與轉(zhuǎn)發(fā)

    大家應(yīng)該都知道請(qǐng)求重定向和請(qǐng)求轉(zhuǎn)發(fā)都是web開(kāi)發(fā)中資源跳轉(zhuǎn)的方式,這篇文章主要給大家介紹了關(guān)于Spring MVC重定向與轉(zhuǎn)發(fā)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-09-09
  • Springboot整合Gson報(bào)錯(cuò)問(wèn)題解決過(guò)程

    Springboot整合Gson報(bào)錯(cuò)問(wèn)題解決過(guò)程

    這篇文章主要介紹了Springboot整合Gson報(bào)錯(cuò)問(wèn)題解決過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Java 深入淺出分析Synchronized原理與Callable接口

    Java 深入淺出分析Synchronized原理與Callable接口

    Synchronized關(guān)鍵字解決的是多個(gè)線程之間訪問(wèn)資源的同步性,synchronized關(guān)鍵字可以保證被它修飾的方法或者代碼塊在任意時(shí)刻只能有一個(gè)線程執(zhí)行,Runnable是執(zhí)行工作的獨(dú)立任務(wù),但是不返回任何值。如果我們希望任務(wù)完成之后有返回值,可以實(shí)現(xiàn)Callable接口
    2022-03-03
  • 通過(guò)實(shí)例分析java多態(tài)

    通過(guò)實(shí)例分析java多態(tài)

    這篇文章主要介紹了通過(guò)實(shí)例分析java多態(tài),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • 使用logstash同步mysql數(shù)據(jù)到elasticsearch實(shí)現(xiàn)

    使用logstash同步mysql數(shù)據(jù)到elasticsearch實(shí)現(xiàn)

    這篇文章主要為大家介紹了使用logstash同步mysql數(shù)據(jù)到elasticsearch實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Java中的this和super實(shí)例淺析

    Java中的this和super實(shí)例淺析

    要說(shuō)this和super就不得不說(shuō)Java的封裝和繼承了。這篇文章主要介紹了Java中的this和super實(shí)例淺析,需要的朋友可以參考下
    2017-03-03
  • 從SpringMVC遷移到Springboot的方法步驟

    從SpringMVC遷移到Springboot的方法步驟

    本篇文章主要介紹了從SpringMVC遷移到Springboot的方法步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • Java中Cglib代理和JDK代理的區(qū)別詳解

    Java中Cglib代理和JDK代理的區(qū)別詳解

    這篇文章主要介紹了Java中Cglib代理和JDK代理的區(qū)別詳解,Cglib代理功能更強(qiáng),無(wú)論目標(biāo)類(lèi)是否實(shí)現(xiàn)了接口都可以代理,他是基于繼承的方式來(lái)代理目標(biāo)類(lèi),如果目標(biāo)類(lèi)也實(shí)現(xiàn)了接口,代理類(lèi)也會(huì)實(shí)現(xiàn)一次,需要的朋友可以參考下
    2023-09-09

最新評(píng)論

辽中县| 呼伦贝尔市| 白玉县| 宁都县| 陕西省| 屯昌县| 德保县| 鄱阳县| 福贡县| 霍林郭勒市| 西畴县| 永平县| 安乡县| 科尔| 措勤县| 商丘市| 龙陵县| 翁牛特旗| 元谋县| 灯塔市| 西青区| 浦东新区| 宁晋县| 黄大仙区| 崇义县| 镇安县| 大方县| 海宁市| 和田市| 军事| 大渡口区| 丰顺县| 龙井市| 门源| 河源市| 贡嘎县| 凉山| 乃东县| 印江| 庐江县| 高邑县|