SpringBoot Starter 自定义配置类,实现日志记录
  2HyDHh3MOg71 2023年11月02日 29 0

1.什么是SpringBoot starter

Spring Boot Starter机制是Spring Boot框架提供的一种约定,用于简化依赖管理和配置的过程。它基于可插拔的自动配置原则,通过打包一组相关的依赖项和自动配置类,为特定的功能模块提供一键式集成和使用。

具体来说,Spring Boot Starter由以下几个关键组成部分组成

  1. Starter依赖:Starter依赖是一个聚合性的依赖,提供了一组相关的库和工具,以及必要的传递性依赖。它们通常以spring-boot-starter-*命名,如spring-boot-starter-web、spring-boot-starter-data-jpa等。引入这些Starter依赖,可以轻松地添加所需的功能模块到项目中。
  2. 自动配置:每个Starter依赖都包含一个或多个自动配置类。这些自动配置类会根据类路径上的条件(例如依赖的库是否存在)来检测需要自动配置的组件,并进行相应的配置。通过自动配置,开发者无需手动编写大量的配置代码,框架会自动完成许多常见的配置任务。
  3. 属性配置:Starter依赖通常还包含一些默认的属性配置,可以通过在应用程序的配置文件(如application.properties或application.yml)中进行覆盖。这些属性配置提供了对自动配置行为和功能的可定制性。

Spring Boot Starter机制的优点包括

  • 简化依赖管理:通过引入Starter依赖,开发者无需手动管理复杂的依赖关系,框架会自动处理依赖的版本和传递性依赖。
  • 快速集成和使用:通过引入特定的Starter依赖,开发者可以快速集成和使用各种功能模块。
  • 自动配置和约定优于配置:Spring Boot的自动配置机制可以根据类路径上的条件自动完成大部分配置工作,减少了繁琐的手动配置。
  • 可定制性:通过覆盖默认的属性配置,开发者可以根据项目需求进行个性化定制。 总而言之,Spring Boot Starter机制提供了一种方便、高效的方式来集成和使用各种功能模块,大大简化了Spring Boot应用程序的开发和配置过程。

2.AOP方式统一服务日志

原先实现统一日志都是放到每个工程中以AOP方式实现,现在有了starter方式,就可以将公司的日志规范集中到这里来统一管理。

2.1创建Log的Starter项目

项目名称zbblog-spring-boot-starter,结构如下:

SpringBoot Starter 自定义配置类,实现日志记录_spring

2.1.1在Pom.xml中添加依赖

<?xml versinotallow="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.14</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.zbbmeta</groupId>
    <artifactId>zbblog-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.35</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.20</version>
        </dependency>
    </dependencies>
</project>

2.1.2 添加自定义的Util类

  • 添加HttpUtil用于Http请求操作
package com.zbbmeta.util;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;


/**
 * @author maguobin
 * @description: http请求操作类
 * @link https://bbs.huaweicloud.com/blogs/104013
 */
@Slf4j
public class HttpUtil {

 /**
  * 发送GET请求
  *
  * @param requestUrl
  * @return
  */
 public static Object getRequest(String requestUrl, String charSetName) {
  String res = "";
  StringBuffer buffer = new StringBuffer();
  try {
   URL url = new URL(requestUrl);
   HttpURLConnection urlCon = (HttpURLConnection) url.openConnection();
   if (200 == urlCon.getResponseCode()) {
    InputStream is = urlCon.getInputStream();
    InputStreamReader isr = new InputStreamReader(is, charSetName);
    BufferedReader br = new BufferedReader(isr);
    String str = null;
    while ((str = br.readLine()) != null) {
     buffer.append(str);
    }
    br.close();
    isr.close();
    is.close();
    res = buffer.toString();
    return res;
   } else {
    throw new Exception("连接失败");
   }
  } catch (Exception e) {
   log.error(e.getMessage());
  }
  return null;
 }

 /**
  * 发送POST请求
  *
  * @param path
  * @param post
  * @return
  */
 public static Object postRequest(String path, String post) {
  URL url = null;
  try {
   url = new URL(path);
   HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
   // 提交模式
   httpURLConnection.setRequestMethod("POST");
   //连接超时 单位毫秒
   httpURLConnection.setConnectTimeout(10000);
   //读取超时 单位毫秒
   httpURLConnection.setReadTimeout(2000);
   // 发送POST请求必须设置如下两行
   httpURLConnection.setDoOutput(true);
   httpURLConnection.setDoInput(true);
   // 获取URLConnection对象对应的输出流
   PrintWriter printWriter = new PrintWriter(httpURLConnection.getOutputStream());
   // 发送请求参数
   //post的参数 xx=xx&yy=yy
   printWriter.write(post);
   // flush输出流的缓冲
   printWriter.flush();
   //开始获取数据
   BufferedInputStream bis = new BufferedInputStream(httpURLConnection.getInputStream());
   ByteArrayOutputStream bos = new ByteArrayOutputStream();
   int len;
   byte[] arr = new byte[1024];
   while ((len = bis.read(arr)) != -1) {
    bos.write(arr, 0, len);
    bos.flush();
   }
   bos.close();

   return bos.toString("utf-8");
  } catch (Exception e) {
   log.error(e.getMessage());
  }
  return null;
 }
}
  • 添加IP工具类
package com.zbbmeta.util;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;


/**
 * @author maguobin
 * @description: IP工具类
 */
@Slf4j
public class IPUtil {

 private final static boolean ipLocal = false;

 /**
  * 根据ip获取详细地址
  */
 public static String getCityInfo(String ip) {
  if (ipLocal) {
   //待开发
   return null;
  } else {
   return getHttpCityInfo(ip);
  }
 }

 /**
  * 根据ip获取详细地址
  * 临时使用,待调整
  */
 public static String getHttpCityInfo(String ip) {
  String api = String.format("http://whois.pconline.com.cn/ipJson.jsp?ip=%s&jsnotallow=true", ip);
  JSONObject object = JSON.parseObject((String) HttpUtil.getRequest(api, "gbk"));
  return object.getString("addr");
 }

 public static void main(String[] args) {
  System.err.println(getCityInfo("220.248.12.158"));
 }
}
  • 添加获取获取HttpServletRequest类
package com.zbbmeta.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * @author maguobin
 * @description: 获取HttpServletRequest类
 */
@Slf4j
public class RequestHolder {

    private static final String UNKNOWN = "unknown";

    /**
     * 获取HttpServletRequest请求
     *
     * @return HttpServletRequest
     */
    public static HttpServletRequest getHttpServletRequest() {
        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
    }

    /**
     * 获取请求IP
     *
     * @return String IP
     */
    public static String getHttpServletRequestIpAddress() {
        HttpServletRequest request = getHttpServletRequest();
        return getHttpServletRequestIpAddress(request);
    }

    public static String getHttpServletRequestIpAddress(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 (ip.contains(",")) {
            ip = ip.split(",")[0];
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

    public static String getServerHttpRequestIpAddress(ServerHttpRequest request) {
        HttpHeaders headers = request.getHeaders();
        String ip = headers.getFirst("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !UNKNOWN.equalsIgnoreCase(ip)) {
            if (ip.contains(StringPool.COMMA)) {
                ip = ip.split(StringPool.COMMA)[0];
            }
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = headers.getFirst("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = headers.getFirst("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = headers.getFirst("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = Objects.requireNonNull(request.getRemoteAddress()).getAddress().getHostAddress();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }
}
  • 字符串操作
package com.zbbmeta.util;

/**
 * @author maguobin
 * @description: https://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.10.5
 */

public interface StringPool {

    String AMPERSAND = "&";
    String AND = "and";
    String AT = "@";
    String ASTERISK = "*";
    String STAR = ASTERISK;
    String BACK_SLASH = "\\";
    String COLON = ":";
    String COMMA = ",";
    String DASH = "-";
    String DOLLAR = "$";
    String DOT = ".";
    String DOTDOT = "..";
    String DOT_CLASS = ".class";
    String DOT_JAVA = ".java";
    String DOT_XML = ".xml";
    String EMPTY = "";
    String EQUALS = "=";
    String FALSE = "false";
    String SLASH = "/";
    String HASH = "#";
    String HAT = "^";
    String LEFT_BRACE = "{";
    String LEFT_BRACKET = "(";
    String LEFT_CHEV = "<";
    String DOT_NEWLINE = ",\n";
    String NEWLINE = "\n";
    String N = "n";
    String NO = "no";
    String NULL = "null";
    String OFF = "off";
    String ON = "on";
    String PERCENT = "%";
    String PIPE = "|";
    String PLUS = "+";
    String QUESTION_MARK = "?";
    String EXCLAMATION_MARK = "!";
    String QUOTE = "\"";
    String RETURN = "\r";
    String TAB = "\t";
    String RIGHT_BRACE = "}";
    String RIGHT_BRACKET = ")";
    String RIGHT_CHEV = ">";
    String SEMICOLON = ";";
    String SINGLE_QUOTE = "'";
    String BACKTICK = "`";
    String SPACE = " ";
    String TILDA = "~";
    String LEFT_SQ_BRACKET = "[";
    String RIGHT_SQ_BRACKET = "]";
    String TRUE = "true";
    String UNDERSCORE = "_";
    String UTF_8 = "UTF-8";
    String US_ASCII = "US-ASCII";
    String ISO_8859_1 = "ISO-8859-1";
    String Y = "y";
    String YES = "yes";
    String ONE = "1";
    String ZERO = "0";
    String DOLLAR_LEFT_BRACE = "${";
    String HASH_LEFT_BRACE = "#{";
    String CRLF = "\r\n";

    String HTML_NBSP = " ";
    String HTML_AMP = "&";
    String HTML_QUOTE = """;
    String HTML_LT = "<";
    String HTML_GT = ">";

    // ---------------------------------------------------------------- array

    String[] EMPTY_ARRAY = new String[0];

    byte[] BYTES_NEW_LINE = StringPool.NEWLINE.getBytes();
}

2.1.3 添加日志对象类CommonLog

package com.zbbmeta.dto;

import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * @author maguobin
 * @description: 日志对象
 */
@Data
@Accessors(chain = true)
public class CommonLog implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 日志类型
     */
    private String type;
    /**
     * 跟踪ID
     */
    private String traceId;
    /**
     * 日志标题
     */
    private String title;
    /**
     * 操作内容
     */
    private String operation;
    /**
     * 执行方法
     */

    private String method;

    /**
     * 请求路径
     */
    private String url;
    /**
     * 参数
     */
    private String params;
    /**
     * ip地址
     */
    private String ip;
    /**
     * 耗时
     */
    private Long executeTime;
    /**
     * 地区
     */
    private String location;
    /**
     * 创建人
     */
    private String createBy;
    /**
     * 更新人
     */
    private String updateBy;
    /**
     * 创建时间
     */
    private LocalDateTime createTime;
    /**
     * 更新时间
     */
    private LocalDateTime updateTime;
    /**
     * 删除标识
     */
    private String isDeleted;
    /**
     * 租户ID
     */

    private Integer tenantId;
    /**
     * 异常信息
     */

    private String exception;
}

2.2 编写相关属性类LogProperties

/**
 * @author maguobin
 * @description: TODO
 */
@ConfigurationProperties("zbbmeta.log")
@Data
public class LogProperties implements Serializable {
    
    private Boolean enabled;
}

2.3 使用AOP功能编写Starter业务

package com.zbbmeta.aspect;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.zbbmeta.dto.CommonLog;
import com.zbbmeta.util.IPUtil;
import com.zbbmeta.util.RequestHolder;
import com.zbbmeta.util.StringPool;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * @author maguobin
 * @description: 日志拦截器
 */

@Slf4j
@Aspect
public class LogAspect {


//    @Pointcut("@annotation(com.zbbmeta.annotation.Log)")
    @Pointcut("execution(* *..*Controller.*(..))")
    public void pointcut() {
    }

    /**
     * 环绕通知,使用Pointcut()上注册的切入点
     * @param point
     * @return
     */
    @Around("pointcut()")
    public Object recordLog(ProceedingJoinPoint point) throws Throwable {
        Object result = new Object();

        // 获取request
        HttpServletRequest request = RequestHolder.getHttpServletRequest();


        // 判断为空则直接跳过执行
        if (ObjectUtils.isEmpty(request)){
            return point.proceed();
        }
        // 获取注解里的value值
        Method targetMethod = resolveMethod(point);
//        Log logAnn = targetMethod.getAnnotation(Log.class);
        // 打印执行时间
        long startTime = System.nanoTime();
        // 请求方法
        String method = request.getMethod();
        String url = request.getRequestURI();

        // 获取IP和地区
        String ip = RequestHolder.getHttpServletRequestIpAddress();
        String region = IPUtil.getCityInfo(ip);

        //获取请求参数
        //Map<String, Object> paramMap = logIngArgs(point);
        // 参数
        Object[] args = point.getArgs();
        String requestParam = getArgs(args, request);

        // 计算耗时
        long tookTime = 0L;
        try {
            result = point.proceed();
        } finally {
            tookTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime);
        }
        // 如果是登录请求,则不获取用户信息
        String userName = "springboot葵花宝典";

        // 封装SysLog
        CommonLog commonLog = new CommonLog();
        commonLog.setIp(ip)
                .setCreateBy(userName)
                .setMethod(method)
                .setUrl(url)
                .setOperation(String.valueOf(result))
                .setLocation(StringUtils.isEmpty(region) ? "本地" : region)
                .setExecuteTime(tookTime)
//                .setTitle(logAnn.value())
                .setParams(JSON.toJSONString(requestParam));
        log.info("Http Request: {}", JSONObject.toJSONString(commonLog));


        return result;
    }

    /**
     * 配置异常通知
     *
     * @param point join point for advice
     * @param e exception
     */
    @AfterThrowing(pointcut = "pointcut()", throwing = "e")
    public void logAfterThrowing(JoinPoint point, Throwable e) {
        // 打印执行时间
        long startTime = System.nanoTime();

        CommonLog commonLog = new CommonLog();

        // 获取IP和地区
        String ip = RequestHolder.getHttpServletRequestIpAddress();
        String region = IPUtil.getCityInfo(ip);


        // 获取request
        HttpServletRequest request = RequestHolder.getHttpServletRequest();

        // 请求方法
        String method = request.getMethod();
        String url = request.getRequestURI();

        // 获取注解里的value值
        Method targetMethod = resolveMethod((ProceedingJoinPoint) point);
//        Log logAnn = targetMethod.getAnnotation(Log.class);

        commonLog.setExecuteTime(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime))
                .setIp(ip)
                .setLocation(region)
                .setMethod(method)
                .setUrl(url)
                .setType("2")
//                .setTitle(logAnn.value())
                .setException(getStackTrace(e));
        // 发布事件
        log.info("Error Result: {}", commonLog);
    }

    private Method resolveMethod(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Class<?> targetClass = point.getTarget().getClass();

        Method method = getDeclaredMethod(targetClass, signature.getName(),
                signature.getMethod().getParameterTypes());
        if (method == null) {
            throw new IllegalStateException("无法解析目标方法: " + signature.getMethod().getName());
        }
        return method;
    }

    /**
     * 获取堆栈信息
     */
    public static String getStackTrace(Throwable throwable) {
        StringWriter sw = new StringWriter();
        try (PrintWriter pw = new PrintWriter(sw)) {
            throwable.printStackTrace(pw);
            return sw.toString();
        }
    }

    private Method getDeclaredMethod(Class<?> clazz, String name, Class<?>... parameterTypes) {
        try {
            return clazz.getDeclaredMethod(name, parameterTypes);
        } catch (NoSuchMethodException e) {
            Class<?> superClass = clazz.getSuperclass();
            if (superClass != null) {
                return getDeclaredMethod(superClass, name, parameterTypes);
            }
        }
        return null;
    }

    /**
     * 获取请求参数
     * @param args
     * @param request
     * @return
     */
    private String getArgs(Object[] args, HttpServletRequest request) {
        String strArgs = StringPool.EMPTY;

        try {
            if (!request.getContentType().contains("multipart/form-data")) {
                strArgs = JSONObject.toJSONString(args);
            }
        } catch (Exception e) {
            try {
                strArgs = Arrays.toString(args);
            } catch (Exception ex) {
                log.warn("解析参数异常", ex);
            }
        }
        return strArgs;
    }
}

2.4.编写自动配置类AutoConfig

@ConditionalOnProperty(prefix = "zbbmeta.log" ,value = "enabled" ,matchIfMissing = true): matchIfMissing属性:默认情况下matchIfMissing为false,也就是说如果未进行属性配置,则自动配置不生效。如果matchIfMissing为true,则表示如果没有对应的属性配置,则自动配置默认生效

/**
 * @author maguobin
 * @description: TODO
 */
@Configuration
@EnableConfigurationProperties({LogProperties.class})
@ConditionalOnProperty(prefix = "zbbmeta.log" ,value = "enabled" ,matchIfMissing = true)
public class LogAutoConfig {

    @Bean
    public LogAspect logAspect(){
        return new LogAspect();
    }
}

2.5 编写自动配置类

resources目录下创建MERA-INF.spring文件夹并创建文件org.springframework.boot.autoconfigure.AutoConfiguration.imports,进行配置

注意创建文件的时候是META-INF/spring

com.zbbmeta.config.LogAutoConfig

SpringBoot Starter 自定义配置类,实现日志记录_java_02

3 创建SpringBoot项目进行测试

创建名称为day25-sprongboot-starter-test项目进行测试自定义日志Satrter

SpringBoot Starter 自定义配置类,实现日志记录_日志记录 spring boot_03

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

    <dependency>
        <groupId>com.zbbmeta</groupId>
        <artifactId>zbblog-spring-boot-starter</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
</dependencies>

3.1在application.yml中进行配置

zbbmeta:
  log:
    enabled: true # 表示开启自定义日志starter

3.2 创建Controller

/**
 * @author maguobin
 * @description: TODO
 */
@RestController
@RequestMapping("/students")
public class StudentController {
    
    @GetMapping
    public String  getAll(){
        return "student log test";
    }
}

启动测试

访问http://localhost:8080/students显示结果如下:

[nio-8080-exec-1] com.zbbmeta.aspect.LogAspect             : Http Request: {"createBy":"maguobin","executeTime":657,"ip":"127.0.0.1","location":" 本机地址","method":"GET","operation":"student log test","params":"\"[]\"","url":"/students"}
  • 关闭日志starter
zbbmeta:
  log:
    enabled: false # 表示关闭自定义日志starter

重新启动项目,访问发现控制台就没有我们自定义的日志了。

SpringBoot Starter 自定义配置类,实现日志记录_日志记录 spring boot_04


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  2Vtxr3XfwhHq   2024年05月17日   53   0   0 Java
  Tnh5bgG19sRf   2024年05月20日   109   0   0 Java
  8s1LUHPryisj   2024年05月17日   46   0   0 Java
  aRSRdgycpgWt   2024年05月17日   47   0   0 Java
2HyDHh3MOg71