前言
🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF
爬虫神器,无代码爬取,就来:bright.cn
Java基本知识:
1. 公众号配置
具体配置界面如下:
模版创建位置,如果找不到想要的,直接创建模版信息也可!
由于模版中没有我想要的,创建完成之后:
补充模版关键词参数类型:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html
相关的数据配置都在此处:
由于没有我想要的模版信息,后续想申请自身的模版(不过审核机制还是比较严格)
2. 源码解读
为便于讲解,会科普实战中用到的源码类:
WxMpTemplateData 这个类主要用于推送消息,key value对应的值,但是颜色值已经失效了,注意甄别
@Data
public class WxMpTemplateData implements Serializable {
private static final long serialVersionUID = 6301835292940277870L;
private String name;
private String value;
private String color;
public WxMpTemplateData() {
}
public WxMpTemplateData(String name, String value) {
this.name = name;
this.value = value;
}
public WxMpTemplateData(String name, String value, String color) {
this.name = name;
this.value = value;
this.color = color;
}
}
主要解读WxMpService 的基本知识
WxMpService 是 WeChat Java SDK(weixin-java-mp) 提供的 公众号核心服务接口
封装了微信的各种 API(如消息、用户、菜单、模板消息等),方便开发者调用
主要功能有如下:
-
获取 AccessToken(接口认证)
-
管理用户(获取用户信息、用户列表)
-
管理消息(发送模板消息、群发消息、客服消息)
-
管理菜单(自定义菜单、个性化菜单)
-
管理素材(图片、视频、文本)
-
管理 OAuth 授权(网页授权、扫码登录)
常用方法如下:
📌(1)获取 AccessToken
String accessToken = wxMpService.getAccessToken();
System.out.println("AccessToken: " + accessToken);
🔹 作用:获取调用微信 API 所需的 access_token,通常有效期为 2小时
📌(2)获取用户信息
WxMpUser user = wxMpService.getUserService().userInfo("用户OpenID");
System.out.println("用户昵称:" + user.getNickname());
🔹 作用:
通过 OpenID 查询用户信息
WxMpUser 包含用户的 昵称、头像、性别、城市、国家 等信息
📌(3)发送模板消息
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
.toUser("用户OpenID") // 接收者 OpenID
.templateId("模板ID") // 模板 ID
.url("https://你的跳转链接.com") // 点击详情跳转
.build();
// 添加数据
templateMessage.addData(new WxMpTemplateData("keyword1", "订单号:123456"));
templateMessage.addData(new WxMpTemplateData("keyword2", "状态:已支付"));
String msgId = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
System.out.println("消息发送成功,msgId:" + msgId);
🔹 作用:
发送 公众号模板消息
toUser() 设置 接收者 OpenID。
templateId() 绑定 微信模板 ID
url() 设置 点击跳转链接
📌(4)自定义菜单
WxMenu menu = new WxMenu();
WxMenuButton button1 = new WxMenuButton();
button1.setType("view");
button1.setName("官网");
button1.setUrl("https://yourwebsite.com");
menu.getButtons().add(button1);
wxMpService.getMenuService().menuCreate(menu);
System.out.println("菜单创建成功!");
🔹 作用:
WxMenu 定义自定义菜单
setType(“view”) 表示跳转网页
setUrl() 设置跳转链接
📌(5)OAuth 网页授权
String redirectUrl = "https://你的回调地址.com";
String authUrl = wxMpService.getOAuth2Service().buildAuthorizationUrl(redirectUrl, WxConsts.OAuth2Scope.SNSAPI_USERINFO, "state");
System.out.println("用户点击授权链接:" + authUrl);
🔹 作用:
生成网页授权链接,用户点击后跳转到 redirectUrl 获取 code
WxConsts.OAuth2Scope.SNSAPI_USERINFO 表示获取用户详细信息
📌(6)获取素材
WxMpMaterial material = wxMpService.getMaterialService().materialGet("素材ID");
System.out.println("素材名称:" + material.getName());
🔹 作用:
materialGet(“素材ID”) 获取 永久素材(图片、视频、文本等)
📌(7)发送客服消息
WxMpKefuMessage message = WxMpKefuMessage.TEXT().toUser("用户OpenID").content("你好,这是一条客服消息").build();
wxMpService.getKefuService().sendKefuMessage(message);
System.out.println("客服消息发送成功!");
🔹 作用:
TEXT() 表示文本消息(支持 图片、语音、视频)
toUser() 指定接收者 OpenID
sendKefuMessage() 发送 客服消息(用户 48小时内 互动可用)
- WxMpService 初始化
在 Spring Boot 项目中,通常通过 WxMpServiceImpl 实现 WxMpService 并初始化:
@Bean
public WxMpService wxMpService() {
WxMpService wxMpService = new WxMpServiceImpl();
WxMpConfigStorage configStorage = new WxMpDefaultConfigImpl();
configStorage.setAppId("你的公众号APPID");
configStorage.setSecret("你的公众号Secret");
configStorage.setToken("你的Token");
configStorage.setAesKey("你的AESKey");
wxMpService.setWxMpConfigStorage(configStorage);
return wxMpService;
}
🔹 作用:
初始化 WxMpServiceImpl,并配置公众号 APPID、Secret、Token
3. Demo(可执行)
这里是一个可直接运行的 Java Demo,不依赖 Spring Boot,只使用 WeChat SDK (weixin-java-mp) 来发送公众号模板消息
主要用于理解相关的框架 基本知识
注册微信公众平台并获取:
- appId(公众号唯一标识)
- secret(公众号密钥)
- 启用模板消息,并创建一个模板,记录模板 templateId
安装 WeChat Java SDK:
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.5.0</version>
</dependency>
截图如下:
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import java.util.HashMap;
import java.util.Map;
public class WeChatTemplateMessageDemo {
public static void main(String[] args) {
// 1. 初始化 WxMpService
WxMpService wxMpService = new WxMpServiceImpl();
WxMpConfigStorage config = new WxMpDefaultConfigImpl();
((WxMpDefaultConfigImpl) config).setAppId("你的公众号APPID");
((WxMpDefaultConfigImpl) config).setSecret("你的公众号SECRET");
((WxMpDefaultConfigImpl) config).setToken("你的TOKEN");
((WxMpDefaultConfigImpl) config).setAesKey("你的AES_KEY");
wxMpService.setWxMpConfigStorage(config);
// 2. 目标用户的 OpenID
String openId = "用户的OpenID";
try {
// 3. 检查用户是否关注公众号
WxMpUser user = wxMpService.getUserService().userInfo(openId);
if (user == null || !user.getSubscribe()) {
System.out.println("用户未关注公众号,跳过发送");
return;
}
// 4. 创建模板消息
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
.toUser(openId) // 接收者 OpenID
.templateId("你的模板ID") // 微信公众平台的模板 ID
.url("https://yourwebsite.com") // 点击跳转的 URL
.build();
// 5. 填充模板数据
Map<String, Object> values = new HashMap<>();
values.put("keyword1", "123456789"); // 订单号
values.put("keyword2", "支付成功"); // 状态
values.put("keyword3", "2024-03-31 10:30:00"); // 时间
for (String key : values.keySet()) {
templateMessage.addData(new WxMpTemplateData(key, values.get(key).toString()));
}
// 6. 发送消息
String result = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
System.out.println("消息发送成功,msgId:" + result);
} catch (WxErrorException e) {
System.err.println("微信推送失败:" + e.getError().getErrorMsg());
}
}
}
关键点解析
- 检查用户是否关注公众号
WxMpUser user = wxMpService.getUserService().userInfo(openId);
if (user == null || !user.getSubscribe()) {
System.out.println("用户未关注公众号,跳过发送");
return;
}
🔹 避免推送给未关注的用户
创建并填充模板消息
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
.toUser(openId)
.templateId("你的模板ID")
.url("https://yourwebsite.com")
.build();
🔹 这里的 templateId 必须是你在公众号后台配置的模板 ID
模板参数动态赋值
for (String key : values.keySet()) {
templateMessage.addData(new WxMpTemplateData(key, values.get(key).toString()));
}
🔹 这样可以动态填充模板参数
发送消息
String result = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
System.out.println("消息发送成功,msgId:" + result);
🔹 如果 msgId 返回 null,说明可能参数有误
注意事项
✅ 公众号必须认证:未认证的公众号无法使用 模板消息 API
✅ 用户必须关注公众号:否则消息无法送达
✅ 模板 ID 必须正确:后台 公众号管理平台 配置的 templateId 必须匹配
代码截图:
公众号内部的截图:
4. 实战配置
first 和 remark的字段已经取消掉了(2023年设定的新规),注意甄别使用模版信息
截图如下:
4.1 方案一
目前已经没有颜色区分了,所以直接使用Object格式
具体代码如下:
主体类:
import lombok.Data;
import java.util.Map;
@Data
public class MpTemplateSendReqDTO {
// 更改为OpenId,直接对接。原始是对接mp的user表再去找openId,但mp user表不是实时更新
private String openId;
private String templateId;
private String url;
private Map<String,Object> values;
}
发送类:
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.Map;
@Schema(description = "管理后台 - 公众号模版消息发送 Request VO")
@Data
public class MpTemplateSendReqVO {
@Schema(description = "openId", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxxx")
@NotNull(message = "openId不能为空")
private String openId;
@Schema(description = "公众号的模版id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "公众号的模版id不能为空")
private String templateId;
@Schema(description = "url", example = "1024")
private String url;
@Schema(description = "发送参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "发送参数不能为空")
private Map<String,Object> values;
}
业务逻辑类:
后续模板类核心代码如下:
String result = null;
// 指定三期公众号的appID,省的多次查表!
WxMpService mpService = mpServiceFactory.getRequiredMpService("xx");
// 先判断用户是否关注公众号
try {
WxMpUser user = mpService.getUserService().userInfo(templateSendReqVO.getOpenId());
if (user == null || !user.getSubscribe()) {
// log.warn("用户未关注公众号,跳过发送。openId = {}", templateSendReqVO.getOpenId());
return null; // 直接返回,不发送
}
} catch (WxErrorException e) {
// log.error("查询用户关注状态失败,openId = {}", templateSendReqVO.getOpenId(), e);
return null; // 查询失败也跳过,避免异常中断主流程
}
//创建模版类
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
.toUser(templateSendReqVO.getOpenId())
.templateId(templateSendReqVO.getTemplateId())
.url(templateSendReqVO.getUrl()).build();
Map<String,Object> map = templateSendReqVO.getValues();
for(String key: map.keySet()){
Object value = map.get(key);
templateMessage.addData(new WxMpTemplateData(key,value.toString()));
}
try{
result = mpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
}catch(WxErrorException e){
throw exception(MESSAGE_SEND_FAIL, e.getError().getErrorMsg());
}
特别说明:
时间戳 时间会这样显示:
要显示正确的时间,需要以特定的格式进行转化:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
coloredMap.put("keyword3", new WxMpTemplateData("keyword3", cabinetPickupDO.getCreateTime().format(formatter)));
结果如下:
4.2 方案二(已弃)
目前是没有颜色区分的,后续如果需要增加颜色区分:
(微信自 2021 年起已不再支持 WxMpTemplateData 的 color 参数,所有颜色属性会被微信自动忽略)
以下作为学习而已,最新版本的 weixin-java-mp SDK 已去除了 color 相关的 JSON 生成逻辑,即使手动添加 color,最终微信 API 仍然会忽略它
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.6.0</version>
<scope>compile</scope>
</dependency>
主体类如下:
import lombok.Data;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import java.util.Map;
@Data
public class MpTemplateSendReqDTO {
// 更改为OpenId,直接对接。原始是对接mp的user表再去找openId,但mp user表不是实时更新
private String openId;
private String templateId;
private String url;
private Map<String,WxMpTemplateData> values;
}
发送类:
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import javax.validation.constraints.NotNull;
import java.util.Map;
@Schema(description = "管理后台 - 公众号模版消息发送 Request VO")
@Data
public class MpTemplateSendReqVO {
@Schema(description = "openId", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxxx")
@NotNull(message = "openId不能为空")
private String openId;
@Schema(description = "公众号的模版id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "公众号的模版id不能为空")
private String templateId;
@Schema(description = "url", example = "1024")
private String url;
@Schema(description = "发送参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "发送参数不能为空")
private Map<String, WxMpTemplateData> values;
}
由于数据待有OpenID,对应发送到相关人员即可
// 微信通知
String openId = cabinetPickupDO.getOpenId();
if(openId != null){
// 定义格式化器
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
Map<String, WxMpTemplateData> coloredMap = new HashMap<>();
coloredMap.put("keyword1", new WxMpTemplateData("keyword1", cabinetPickupDO.getCntr()));
coloredMap.put("keyword2", new WxMpTemplateData("keyword2", isApproved ? "xx 【通过】" : "xx 【不通过】", isApproved ? "#173177" : "#ff0000"));
coloredMap.put("keyword3", new WxMpTemplateData("keyword3", cabinetPickupDO.getCreateTime().format(formatter)));
MpTemplateSendReqDTO mpTemplateSendReqDTO = new MpTemplateSendReqDTO();
mpTemplateSendReqDTO.setOpenId(openId)
.setTemplateId("xx")
.setUrl("xx")
.setValues(coloredMap);
mpTemplateApi.sendTemplateMessageAsync(mpTemplateSendReqDTO);
}
引入这个包:import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
截图如下:
模版类的核心如下:
String result = null;
// 指定xxx公众号的appID,省的多次查表!
WxMpService mpService = mpServiceFactory.getRequiredMpService("xxx");
// 先判断用户是否关注公众号
try {
WxMpUser user = mpService.getUserService().userInfo(templateSendReqVO.getOpenId());
if (user == null || !user.getSubscribe()) {
// log.warn("用户未关注公众号,跳过发送。openId = {}", templateSendReqVO.getOpenId());
return null; // 直接返回,不发送
}
} catch (WxErrorException e) {
// log.error("查询用户关注状态失败,openId = {}", templateSendReqVO.getOpenId(), e);
return null; // 查询失败也跳过,避免异常中断主流程
}
//创建模版类
WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
.toUser(templateSendReqVO.getOpenId())
.templateId(templateSendReqVO.getTemplateId())
.url(templateSendReqVO.getUrl()).build();
// 带颜色的通知
Map<String,WxMpTemplateData> coloredMap = templateSendReqVO.getValues();
for (WxMpTemplateData data : coloredMap.values()) {
templateMessage.addData(data);
}
try{
result = mpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
}catch(WxErrorException e){
throw exception(MESSAGE_SEND_FAIL, e.getError().getErrorMsg());
}