【JavaEE进阶】Spring Boot 日志:从 System.out 到 @Slf4j,6 个级别 + 4 类配置一篇讲透

  • 🏠博客主页:小谢同学的小破站
  • ✍️本文由 小谢同学的小破站 原创,首发于 CSDN 💻
  • ☕JavaSE专栏:JavaSE
  • 📗JavaEE初阶专栏:JavaEE初阶
  • 📘JavaEE进阶专栏:JavaEE进阶
  • 🧩数据结构专栏:数据结构
  • ⚙️算法专栏:算法
  • 📚MySQL初阶专栏:MySQL初阶
  • 🔐MySQL进阶专栏:MySQL进阶
  • 🌐计算机网络专栏:计算机网络
  • 💻C语言专栏:C语言
  • 👍欢迎点赞👍 收藏⭐ 留言📝,发现错误欢迎指正!
  • ✨脚踏实地,持续深耕,奔赴自己的目标✨
    ----- 📌分割线 📌-------

JavaEE进阶Spring Boot日志

  • [1. 日志到底解决什么问题](#1. 日志到底解决什么问题)
    • [1.1 System.out.print 的四个"原罪"](#1.1 System.out.print 的四个"原罪")
    • [1.2 日志的三份正经工作](#1.2 日志的三份正经工作)
  • [2. 在 Spring Boot 里打印第一条日志](#2. 在 Spring Boot 里打印第一条日志)
    • [2.1 先拿到日志对象](#2.1 先拿到日志对象)
    • [2.2 用日志对象输出的效果](#2.2 用日志对象输出的效果)
    • [2.3 一条日志长什么样(六件套)](#2.3 一条日志长什么样(六件套))
  • [3. 日志级别:给消息分级上报](#3. 日志级别:给消息分级上报)
    • [3.1 六个级别](#3.1 六个级别)
    • [3.2 默认只打印 info 及以上](#3.2 默认只打印 info 及以上)
  • [4. 日志框架与门面模式](#4. 日志框架与门面模式)
    • [4.1 SLF4J 是什么](#4.1 SLF4J 是什么)
    • [4.2 门面模式:一家奶茶店就讲明白了](#4.2 门面模式:一家奶茶店就讲明白了)
    • [4.3 没有门面的日子有多惨](#4.3 没有门面的日子有多惨)
  • [5. 日志配置:级别、持久化、分割、格式](#5. 日志配置:级别、持久化、分割、格式)
    • [5.1 改日志级别](#5.1 改日志级别)
    • [5.2 日志持久化](#5.2 日志持久化)
    • [5.3 日志文件分割](#5.3 日志文件分割)
    • [5.4 自定义日志格式](#5.4 自定义日志格式)
  • [6. 更省事的写法:@Slf4j](#6. 更省事的写法:@Slf4j)
  • [7. 总结与速查表](#7. 总结与速查表)

前言:

  这里是小谢同学的 Spring Boot 日志学习记录,整理日志的基本用法、级别、门面模式、配置与持久化。笔记用于自我复盘巩固,有错误欢迎大家指出,专栏还有 Java、网络、C 语言等系列笔记欢迎翻阅。同时也希望这篇文章能够帮助到你~

1. 日志到底解决什么问题

1.1 System.out.print 的四个"原罪"

 日志其实我们一点都并不陌生,从 JavaSE 开始我们就在用 System.out.print 打印东西了,就好比我们在写算法题目的时候,有时候我们并不好观察,我们就可以使用IDEA的sout进行打印出来看看对不对?是不是符合我们的预期?

 但是如果项目开始复杂起来了呢?

 System.out.print 就明显不够用了。举个一个例子,之前我写一个简单的借书接口,所有信息全靠 println,在测试的时候出现了问题,控制台里密密麻麻的文字,我根本分不清哪一行是几点几秒打印的、是哪个类的、是哪一次请求的。

 就像我们使用Spring Boot框架一样,Spring Boot 本身给我们设置好了一些日志的功能,我们在启动的时候能够观察到时间,位置,进程ID,等等信息:

 四条硬伤总结一下:

对比项 System.out.print 专业日志框架
时间信息 没有,只能靠自己手写 默认带精确到毫秒的时间
日志级别 没有,所有输出一样重 有 ERROR/WARN/INFO/DEBUG 等级别
来源信息 没有,不知道哪个类打的 自动带类名、线程名、进程号
开关控制 只能删代码,改一行重新打包 改个配置项就能压掉某些日志
持久化 只能重定向,格式乱七八糟 一行配置写文件,还能自动切分
性能 同步阻塞,量大时拖慢接口 支持异步,量大了也不至于卡死

所以说白了,"专业的人干专业的事情",此时我们就需要一个专门的日志框架;
[↩ 返回目录](#↩ 返回目录)


1.2 日志的三份正经工作

 除了最常见的"排查 bug",日志其实还在干三件大事:

① 系统监控

 一个成熟的系统基本上都离不开监控;把每一个接口的响应时间,返回状态记录到日志中,然后根据统计分析设计阈值,当超过了阈值就会报警;比如统计日志中"库存不足"这个关键字出现了多少次,一分钟超过 100 次就发告警,这就是很常见的需求。

 也可以换一个说法: 一天晚上,公司的服务器出现异常,假设出现的问题只有以下这几种;

  1. 第一种:可能出现的情况: P3(低优先级、日志统计、非核心小报错)

通知:纯邮箱、日报汇总

  • 不弹任何强提醒,定期复盘
  1. 第二种:P2(预警、慢查询、磁盘慢慢要满、证书快到期)

通知:群消息 + 邮箱

  • 不用半夜打扰,上班之后排查就行
  1. 第三种:P1(高危但业务没全崩:错误率飙升、内存打满、单实例宕机)

通知:短信 + 钉钉 / 企微机器人

  • 不用电话吵醒,看到消息尽快处理,适合晚上非致命故障
  1. 第四种:P0(核心炸了,最高级:支付、下单、首页挂了,大量用户受影响)

通知:电话(值班 on-call 工程师)+ 短信 + 群告警

  • 先打值班开发 / 运维,不是直接打领导;工程师处理超时没确认,才升级给组长、领导打电话
  • 目标:立刻接电话,5~10 分钟响应止损

② 数据采集

 采集来的数据能用在很多地方:

  • 数据统计:页面的浏览量(PV)、访客量(UV)、点击量,用来看运营效果;
  • 推荐排序:把用户浏览过什么、停留多久记进日志,算法同学拿去训练模型做推荐。购物、广告、新闻这些领域基本都在这么干。

③ 日志审计

 这个在正经公司里特别重要。运营在后台删了一条数据、改了一条数据,如果没有操作日志,你根本不知道是谁干的;记了日志,一查就清楚。还有些内部违规、信息泄漏的情况(比如客户信息被偷偷导出去卖),没有日志留存,事后根本没法追查。所以很多公司连"频繁查询客户信息"都会记录并报警。

 就好比生活中的例子:

别人污蔑你进去他房间偷东西,但是没有摄像头,刚好你又进去过,东西又丢失了,没有任何的证明来证明自己没有偷

 就像数据库设计中,一般使用的都是逻辑删除,而不是正真意义上的删除,目的就是不要去麻烦人家,欠别人的人情,即使自己不小心删错了,也能进行找回来,不会造成很大的损失
 一句话:日志不只是给开发看的,它还是运维的眼睛、算法的粮食、合规的证据。
[↩ 返回目录](#↩ 返回目录)


2. 在 Spring Boot 里打印第一条日志

2.1 先拿到日志对象

 Spring Boot 项目一启动,控制台就自带一堆日志,这些可不是 System.out 打的,是内置的日志框架干的活。Spring Boot 内置的是 SLF4J + Logback,我们直接调 SLF4J 就能输出日志。

打印日志就两步:拿到日志对象 → 用它输出内容。

 拿对象要用日志工厂 LoggerFactory(注意是工厂,不是直接 new):

java 复制代码
private static final Logger logger = LoggerFactory.getLogger(TestController.class);

 getLogger 要传一个参数,用来标记这个日志是谁打的。一般就传当前类的 class,这样出问题时看日志里的类名就能直接定位到代码,非常直观。

 ⚠️ 踩坑提醒:Logger 有几个同名类,一定要导 org.slf4j.Logger,别导成 org.apache.logging.log4j.Logger 或者 java.util.logging.Logger,不然要么编译报错,要么日志打不出来。
[↩ 返回目录](#↩ 返回目录)


2.2 用日志对象输出的效果

 我简单写一个借阅的接口,例如:

java 复制代码
@RestController
public class TestController {
    private static final Logger logger = LoggerFactory.getLogger(TestController.class);

    @RequestMapping("/borrow")
    public String borrow() {
        logger.info("用户借阅《Java 编程思想》,编号 B1024");
        System.out.println("用户借阅《Java 编程思想》,编号 B1024");
        return "借阅成功";
    }
}

 我们可以简单来看看日志情况:

 访使用postman或者浏览器访问一下 http://localhost:8080/book/borrow,控制台输出的长这样:

 对比一下 System.out 打出来的那行干巴巴的文字,信息量差得不是一点半点。
[↩ 返回目录](#↩ 返回目录)


2.3 一条日志长什么样(六件套)

 上面那行其实是六块内容拼起来的,从左往右看:

序号 元素 示例 说明
1 时间日期 2026-10-21T17:28:08.040+08:00 精确到毫秒,排查偶发问题时很关键
2 日志级别 INFO ERROR、WARN、INFO、DEBUG、TRACE
3 进程 ID 18632 多实例部署时用来区分是哪个进程
4 线程名 [nio-8080-exec-1] 能看出是哪个线程处理的,并发问题全靠它
5 Logger 名 c.e.b.c.BookController 通常就是类名(超长会缩写)
6 日志内容 用户借阅... 我们自己写的那句话

 看到第 5 项没?这就是为什么 getLogger 里要传当前类的 class,否则这里只会显示一个你自己起的名字,定位起来全靠猜。
[↩ 返回目录](#↩ 返回目录)


3. 日志级别:给消息分级上报

 打个比方。假设你是一家两万人公司的老板,如果每个员工的鸡毛蒜皮都直接汇报给你,你早就干不下去了。于是有了组织架构:组员报组长,组长报研发一组,研发一组报 Java 研发......层层上报,重要的才往上走。

 日志级别就是这个道理。给消息分好级,出问题时只看 ERROR,日常看 INFO,就不用在一堆输出里翻半天了。

3.1 六个级别

 日志从高到低分一共6个日志等级(Spring Boot 用的 Logback 里没有 FATAL,它被并到了 ERROR):

级别 含义 借书场景里的例子
FATAL 致命,系统级错误,必须立刻处理 数据库连不上了,整个服务不可用
ERROR 错误,但仍不影响系统继续运行 扣库存失败,这一单借阅失败返回 500
WARN 警告,不影响使用,但值得注意 用户积分不够,跳过积分抵扣
INFO 普通信息,记录正常运行轨迹 借阅成功、项目启动完成
DEBUG 调试信息,开发期用 进入 borrow 方法,bookId=1024
TRACE 追踪,比 DEBUG 更细 循环里每一轮迭代的中间值

注意: Bug 级别没有半毛钱关系

 我们需要知道的是,日志级别是自己开发设置的,给开发人员自己看的;Bug 级别是测试根据现象和影响范围定的。

 还有个口诀:级别越高,能收到的消息越少。
[↩ 返回目录](#↩ 返回目录)


3.2 默认只打印 info 及以上

 Logger 对每个级别都有对应的方法,我一次性全打一遍:

java 复制代码
    @RequestMapping("/levels")
    public String levels() {
        logger.trace("========== trace ==========");
        logger.debug("========== debug ==========");
        logger.info("========== info ==========");
        logger.warn("========== warn ==========");
        logger.error("========== error ==========");
        return "打印不同级别的日志";
    }

使用postman访问: http://127.0.0.1:8080/levels

 结果只出来三行:

 这下面两行根本就没有打印出来:

java 复制代码
        logger.trace("========== trace ==========");
        logger.debug("========== debug ==========");

 踩坑记录:第一次见这个现象我还以为是 trace 和 debug 方法没生效。其实 Spring Boot 默认日志级别就是 info,只有大于等于 当前级别的日志才会输出,所以 info、warn、error 出来了,debug 和 trace 被过滤掉了。想让它们出现,改配置就行(下一节说: [5.1 改日志级别](#5.1 改日志级别))。

 💡 再补一个小技巧:SLF4J 支持 {} 占位符,不用自己拼字符串,性能也更好:

java 复制代码
logger.info("用户 {} 借阅了《{}》,编号 {}", userId, bookName, bookNo);

[↩ 返回目录](#↩ 返回目录)


4. 日志框架与门面模式

4.1 SLF4J 是什么

 市面上日志框架一大堆:Log4j、Logback、Log4j2、JUL......那为什么我们代码里只导 org.slf4j 的包?

 因为 SLF4J 本身不是 一个具体的日志实现,它只是一层抽象:一套规范、一套接口。它不能单独干活,必须搭配 Logback 这类真正的实现来用。

 这就引出它背后的设计思想------门面模式。
[↩ 返回目录](#↩ 返回目录)


4.2 门面模式:一家奶茶店就讲明白了

 门面模式(Facade Pattern,也叫外观模式)的定义是:为子系统中的一组接口提供一个统一的入口,让子系统更容易使用。

 生活中的例子也比较多,例如去医院挂号,门诊,化验,取药,等流程比较繁琐,患者需要自己跑一圈,这可比较累了;但是如果有一个导诊台帮你把这些事情穿起来,你只需要跟导诊台打交道就行;

 我用奶茶店来写这段代码------顾客只跟收银台说话,后面的泡茶、加料、封口各干各的:

java 复制代码
public class FacadeDemo {
    public static void main(String[] args) {
        MilkTeaShop shop = new MilkTeaShop();
        shop.order("珍珠奶茶");
    }
}

/**
 * 奶茶店门店:门面角色,对外的统一入口
 */
class MilkTeaShop {
    private TeaMaker teaMaker = new TeaMaker();
    private ToppingAdder toppingAdder = new ToppingAdder();
    private CupSealer cupSealer = new CupSealer();

    public void order(String name) {
        System.out.println("收到订单:" + name);
        teaMaker.brew();
        toppingAdder.add();
        cupSealer.seal();
        System.out.println("出餐,请取餐~");
    }
}

class TeaMaker {
    public void brew() {
        System.out.println("① 泡茶底,焖 8 分钟");
    }
}

class ToppingAdder {
    public void add() {
        System.out.println("② 加珍珠,两勺");
    }
}

class CupSealer {
    public void seal() {
        System.out.println("③ 封口,贴标");
    }
}

 顾客(客户端)压根不知道后面有几个工位、谁先谁后,他只知道"点单"这一个动作。这就是门面的价值:

优点 说明
降低耦合 客户端只依赖门面,子系统内部怎么改都不影响调用方
使用更简单 客户端不用关心执行顺序和内部细节
安全性更好 门面里不开放的方法,外面就调不到

 对于顾客来说: 我不关心你后面有几道工序,我只关系我需要一杯奶茶~

 门面模式里面之一两个角色: 外观角色 (Facade,对外的统一接口,上面的 MilkTeaShop)和子系统角色(SubSystem,可以有很多个,而且子系统本身并不知道门面的存在,对它来说门面也只是个普通调用方)。
用我们现在的话来说就是: 我要去买奶茶,我付钱,你给我奶茶~
[↩ 返回目录](#↩ 返回目录)


4.3 没有门面的日子有多惨

 把奶茶换成日志框架就懂了。假设你的项目用的是 Log4j,结果依赖的一个第三方组件(比如某个消息中间件)用的是 Logback,那你就得把 Logback 也引进来。麻烦随之而来:

  1. 两套框架的 API 和配置文件都不一样,你得维护两份配置;
  2. 哪天想换框架,业务代码里的日志调用全得改,改的过程还容易冲突;
  3. 依赖一多,可能同时存在三四套日志,配置越堆越乱。

 引入门面模式之后就清爽了: 应用程序只需要面向SLF4J这一套的接口代码,地城换成Logback,Log4j2都行.,业务层代码一行都不需要动,同理配置文件也只有一份;

 所以那句话说得挺对:SLF4J 让你的代码独立于任何特定的日志 API。
[↩ 返回目录](#↩ 返回目录)


5. 日志配置:级别、持久化、分割、格式

 Spring Boot 的日志配置全写在 application.properties 或 application.yml 里,两个文件配一个就行 。两者可以互换,规律很简单:properties 里的点 .,在 yml 里就是换行。

5.1 改日志级别

 修改日志的级别,我们只需要配置相关内容: logging.level:

 例如:

properties 复制代码
logging.level.root=trace

 或者

yaml 复制代码
logging:
  level:
    root: trace

 root 表示根 logger,也就是全局生效。改完重启,刚才那五条日志就全出来了------debug 和 trace 都在。实际开发里一般不用全局开 debug,日志会爆炸,通常是给某个包单独开,比如只盯自己写的 Controller:

 但是当你修改完默认的日志级别之后,你去启动项目,你会发现,下面的日志滚动的非常快~
[↩ 返回目录](#↩ 返回目录)


5.2 日志持久化

 控制台日志一关窗口就没了,线上出了问题想回溯根本没戏。把日志存到文件里,就叫持久化 。有两种配法。

方式一:指定文件名

properties 复制代码
logging.file.name=log/book.log

 或者:

yaml 复制代码
logging:
  file:
    name: log/book.log

 路径可以写相对路径,也可以写绝对路径(比如 D:/logs/book.log)。配完跑一下,项目根目录下就多出 log/book.log,内容就是控制台打印的那些。

方式二:只指定目录

properties 复制代码
logging.file.path=D:/logs

 或者:

yaml 复制代码
logging:
  file:
    path: D:/logs

 这种方式只能指定目录,文件名是固定的 spring.log,不能自己起名。

⚠️ 踩坑记录:两个都配了会怎样?只生效一个,以 logging.file.name 为准。我第一次配的时候两个都写了,还纳闷为什么文件名不是我想要的那个,后来才发现是优先级问题。所以别贪心,选一个用。
[↩ 返回目录](#↩ 返回目录)


5.3 日志文件分割

 所有日志都堆在一个文件里,跑上几天就是几个 G,打开都能卡死编辑器的。日志框架其实早就想到了,默认超过 10MB 就自动切分。

 想自己定规则,配这两个项:

配置项 说明 默认值
logging.logback.rollingpolicy.file-name-pattern 分割后的文件名格式 ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz
logging.logback.rollingpolicy.max-file-size 单个文件超过多大就切 10MB

 为了看得清楚,我把阈值调成 1KB 做个演示:

properties 复制代码
logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}.%d{yyyy-MM-dd}.%i
logging.logback.rollingpolicy.max-file-size=1KB

 或者:

yaml 复制代码
logging:
  logback:
    rollingpolicy:
      max-file-size: 1KB
      file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i

 多点几次接口多打些日志,目录里就出现了一堆文件:

 命名规律就是"日志名.日期.索引"。1KB 只是为了演示,企业里一般设 200MB 或 500MB,这个没有硬性标准,看磁盘和日志量自己定。
[↩ 返回目录](#↩ 返回目录)


5.4 自定义日志格式

 默认格式看习惯了其实挺好,但有时候需要精简,或者想把自己的方法名、行号加上去。控制台和文件可以分开配:

配置项 作用
logging.pattern.console 控制台日志格式
logging.pattern.file 日志文件格式

 常用占位符先收好:

占位符 含义
%d{yyyy-MM-dd HH:mm:ss.SSS} 日期时间,精确到毫秒
%5p 日志级别,不足 5 位右边补空格
%t / %thread 线程名
%c 类的全限定名
%M 方法名
%L 行号
%m / %msg 日志内容
%n 换行
%clr(表达式){颜色} 给日志上色,支持 blue、cyan、faint、green、magenta、red、yellow

 举个精简版配置:时间 + 类名 + 方法 + 行号 + 线程 + 内容:

properties 复制代码
logging.pattern.console='%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'

 或者:

yaml 复制代码
logging:
  pattern:
    console: '%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'
    file: '%d{yyyy-MM-dd HH:mm:ss.SSS} %c %M %L [%thread] %m%n'

 这样看起来就清爽多了:

 格式里那几个数字规则也顺手记一下:%5 是不够 5 位时右边补空格,%-5 是左边补空格,%.15 是超过 15 位就截断,%15.15 是两个都干。

⚠️ 踩坑记录:想用 %clr 上色,结果控制台一点颜色都没有?不是配置写错了,是 IDEA 默认不给控制台 ANSI 颜色。要在启动配置的 VM options 里加一句:

text 复制代码
-Dspring.output.ansi.enabled=ALWAYS

 重启就有了。不过说实话,实际开发里默认格式就够用,除非有特殊要求,不太建议折腾。

 只不过我这是专业版,自动给日志渲染上了颜色~
[↩ 返回目录](#↩ 返回目录)


6. 更省事的写法:@Slf4j

 每个类都写一遍 LoggerFactory.getLogger(xxx.class),说实话挺烦的,尤其是 Controller 一多,粘贴都粘到手软。Lombok 给了个偷懒方案。

 第一步,加依赖(Spring Boot 项目一般创建时就自带了):

xml 复制代码
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

 第二步,类上打 @Slf4j,然后直接用 log:

java 复制代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/book")
public class LogController {

    public void log() {
        log.info("用户借阅《Java 编程思想》,编号 B1024");
    }
}

 就这么简单,log 这个对象是注解帮我们生成的,不用自己声明。

 ⚠️ 踩坑提醒:如果 IDEA 里 log 报红,基本都是 Lombok 没配好------要么没开注解处理器(Enable annotation processing),要么插件没装。不是代码写错了。

 再给大叫推荐几个工具:

 这几个工具还是非常的好用的,具体用法这里就不过多解释了;

 我们就能打开对一些配置文件进行快速添加:


[↩ 返回目录](#↩ 返回目录)


7. 总结与速查表

 这一节内容不多,但都是天天要用的东西。三句话概括:

  1. 日志是项目的基础设施,能帮我们发现问题、分析问题、定位问题,还能做监控、数据采集和审计;Spring Boot 内置 SLF4J + Logback,默认以 info 级别输出到控制台,用 @Slf4j + log 就能快速打日志。
  2. 日志有 6 个级别(FATAL/ERROR/WARN/INFO/DEBUG/TRACE),级别越高收到的消息越少;通过配置文件名或目录可以把日志持久化到磁盘。
  3. 想改行为就改配置:级别、存哪儿、怎么切、长什么样,四个维度全都能配。

其实一些配置文件我们不需去记: 我们可以提前存储起来,需要使用的时候能想起来,直接使用复制粘贴的方式~

配置速查表

需求 配置项 备注
改全局日志级别 logging.level.root=debug 也可给指定包单独设
指定日志文件名 logging.file.name=log/book.log 支持绝对/相对路径
只指定日志目录 logging.file.path=D:/logs 文件名固定为 spring.log
两者同时配 --- 以 logging.file.name 为准
切分阈值 logging.logback.rollingpolicy.max-file-size 默认 10MB
切分文件名 logging.logback.rollingpolicy.file-name-pattern 默认含日期和索引
控制台格式 logging.pattern.console 占位符见上表
文件格式 logging.pattern.file 与控制台可分开配
控制台颜色 VM options 加 -Dspring.output.ansi.enabled=ALWAYS IDEA 需要

易错点速记

坑 正解
Logger 导错包 必须是 org.slf4j.Logger
debug 日志不打印 默认级别是 info,配置里放开
两个持久化配置都写了 只有 logging.file.name 生效
只配 path 想改文件名 不行,是固定的 spring.log
颜色配置不生效 IDEA 要开 ANSI 输出
用字符串拼接打日志 改用 {} 占位符

 好了,日志这块就先整理到这里。下一篇继续 Spring Boot 的其他内容,感兴趣的可以蹲一下~

 如果这篇笔记对你有帮助,欢迎点赞 👍 收藏 ⭐ 留言 📝,有写错的地方也请帮忙指正,一起进步!
[↩ 返回目录](#↩ 返回目录)


相关推荐
IT_Octopus2 小时前
Apollo 配置中心入门:一所“小学校“读懂 Portal、Meta Server、Config Service
java·后端·spring
cfm_29142 小时前
偏向锁的Epoch优化机制
java
CRMEB系统商城2 小时前
家电零售的供应商协同与物流提效
java·开发语言·人工智能·小程序·1024程序员节
jason.zeng@15022072 小时前
Nginx 配置详解(静态 HTML、下载目录、API 反向代理三套场景)
java·vue.js·1024程序员节
鬼手点金2 小时前
从 API 消息到模型 Token:Chat Template
java·前端·javascript·数据库·人工智能·深度学习·1024程序员节
Shadow(⊙o⊙)2 小时前
LangChain 自定义工具全解析:从 @tool 到 bind_tools 的完整调用链路
java·服务器·前端·1024程序员节
王大师王文峰2 小时前
Java+AI 面试题(二):业务场景设计 10 例【客服机器人、合同审查、Text2SQL、告警降噪、成本优化】场景题答法与追问链路
java·开发语言·人工智能
弦儿3 小时前
后端 Web 实战:员工管理(新增员工 + 事务管理 + 文件上传)
java·后端
Mr-Wanter3 小时前
Spring Boot 接口签名实践
java·spring boot