前言

@Builder 是什么?

它是 Lombok 提供的注解,编译时自动生成一个 Builder 内部类,让你用链式调用构建对象。

原理对比

没有 @Builder,你需要:

TemplateMessage msg = new TemplateMessage();
msg.setToUser("oXXXX");
msg.setTemplateId("abc123");
msg.setUrl("https://...");
// 字段多了很繁琐,而且构造函数参数顺序容易搞混

用了 @Builder,Lombok 在编译时自动生成等价代码:

TemplateMessage msg = TemplateMessage.builder()
        .toUser("oXXXX")
        .templateId("abc123")
        .url("https://...")
        .data(dataMap)
        .build();   // 最后调用 build() 才真正创建对象

为什么推荐用?

优势 说明
可读性好 链式调用,一眼看出每个字段赋了什么值
不怕顺序错 不依赖构造函数参数顺序
可选字段灵活 只设你需要的字段,其他保持 null
不可变对象 配合 @Builder + @AllArgsConstructor + 私有构造,可以做出不可变对象

本项目中的实际使用

WxPushService.java 里就是这样用的:

TemplateMessage message = TemplateMessage.builder()
        .toUser(openId)                          // 接收者
        .templateId(templateId)                  // 模板ID
        .url(url)                                // H5跳转
        .miniProgram(miniProgram)                // 小程序跳转
        .data(data)                              // 模板数据
        .build();                                // 构建对象

简单说:@Builder = Lombok 帮你自动写了一个链式构建器,你只管 .字段名(值) 链式调用,最后 .build() 拿到对象。

对比

Java (本项目) JavaScript
代码 JSON.toJSONString(message) JSON.stringify(message)
fastjson2 内置
作用 Java 对象 → JSON 字符串 JS 对象 → JSON 字符串

具体例子

Java 端(本项目):

TemplateMessage message = TemplateMessage.builder()
        .toUser("oXXXX")
        .templateId("abc123")
        .build();

String jsonBody = JSON.toJSONString(message);
// 结果: {"touser":"oXXXX","template_id":"abc123","data":null,...}

等价于 JavaScript 端:

const message = {
    touser: "oXXXX",
    template_id: "abc123",
    data: null
};

const jsonBody = JSON.stringify(message);
// 结果: {"touser":"oXXXX","template_id":"abc123","data":null}

为什么需要这一步?

微信 API 要求请求体是 JSON 字符串,而不是 Java 对象。所以必须把 Java 对象"序列化"成 JSON 字符串,才能通过 HTTP POST 发给微信服务器。

Java 对象  →  JSON.toJSONString()  →  JSON 字符串  →  POST 发给微信

一句话总结:JSON.toJSONString() 就是 Java 版的 JSON.stringify(),都是把对象转成 JSON 字符串。

区别

TemplateMessage.builder() new Request.Builder()
来源 Lombok @Builder 注解自动生成 OkHttp 库手写的 Builder 类
调用方式 类名.builder() new 类名.Builder()
原理 编译时 Lombok 自动生成代码 OkHttp 作者手动写的 Java 代码

为什么 OkHttp 的 Request 要用 Builder?

因为 Request 对象字段很多,而且有些是必填(URL),有些是可选(header、body、tag等)。用 Builder 模式可以灵活组合:

// GET 请求 — 简单
Request req1 = new Request.Builder()
        .url("https://api.weixin.qq.com/...")
        .get()
        .build();

// POST 请求 — 加 body
Request req2 = new Request.Builder()
        .url("https://api.weixin.qq.com/...")
        .post(requestBody)
        .addHeader("Authorization", "Bearer xxx")  // 可选加 header
        .build();

怎么区分?

看调用方式就行:

// Lombok 的 @Builder(没有 new)
TemplateMessage.builder().toUser("xxx").build();

// 库自己写的 Builder(有 new)
new Request.Builder().url("xxx").build();

new = 库/框架自己实现的 Builder 类
没有 new = Lombok @Builder 自动生成的静态方法

一句话总结:Builder 是一种通用的设计模式,Lombok 只是帮你自动生成,OkHttp 是作者手写的,效果一样,写法略有不同。

配置类–核心思路

package com.example.wxpush.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * 微信公众号配置属性
 */
@Data
@Component
@ConfigurationProperties(prefix = "wx.mp")
public class WxMpConfig {

    /** 公众号 AppID */
    private String appId;

    /** 公众号 AppSecret */
    private String appSecret;

    /** 模板消息模板ID */
    private String templateId;

    // ==================== 微信 API 地址常量 ====================

    /** 获取 access_token 接口 */
    public static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    /** 发送模板消息接口 */
    public static final String TEMPLATE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s";
}

把所有可变的、跟环境相关的值从代码中抽出来,集中管理。

硬编码(❌ 差)          配置类(✅ 好)
代码里写死 appid         配置文件里填,代码里读取
换个环境要改代码          换个环境只改配置文件

通用三步套路

第一步:application.yml 写配置值

wx:
  mp:
    app-id: wx123456
    app-secret: abcdef
    template-id: xyz789

第二步:Java 类用 @ConfigurationProperties 绑定

@Data
@Component
@ConfigurationProperties(prefix = "wx.mp")   // 对应 yml 中的 wx.mp
public class WxMpConfig {
    private String appId;        // 自动绑定 app-id(驼峰自动转换)
    private String appSecret;
    private String templateId;
}

第三步:哪里需要,就注入哪里

@Service
public class WxPushService {
    private final WxMpConfig wxMpConfig;    // 注入配置类

    public WxPushService(WxMpConfig wxMpConfig) {
        this.wxMpConfig = wxMpConfig;
    }

    public void doSomething() {
        String appId = wxMpConfig.getAppId();   // 直接用
    }
}

为什么这样做?

好处 说明
不改代码换配置 开发/测试/生产环境只需换 yml 文件
集中管理 所有配置值在一个类里,一目了然
类型安全 String、Integer、Boolean 自动转换,不会拼错
IDE 提示 配合插件,yml 里写错字段名会报错
方便复用 多个 Service 都注入同一个配置类

常见场景

几乎任何需要配置的东西都这么做:

# 数据库配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: 123456

# 阿里云 OSS 配置
aliyun:
  oss:
    endpoint: oss-cn-hangzhou.aliyuncs.com
    access-key-id: LTAI...
    bucket-name: my-bucket

# 支付配置
pay:
  alipay:
    app-id: 2021...
    private-key: MIIEv...

每个都对应一个 @ConfigurationProperties 配置类。

一句话总结

配置类的本质 = yml 文件和 Java 代码之间的桥梁,让代码不硬编码、配置集中管、环境切换零改动。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐