公众号消息推送

master
ljw 2025-11-05 11:44:47 +08:00
parent b275a2c1fc
commit ea336aece1
8 changed files with 289 additions and 1 deletions

View File

@ -46,4 +46,9 @@ public class MyResult extends UserDetail {
*/
private String wechatOpenid;
/**
*
*/
private String wxAuthUrl;
}

View File

@ -15,11 +15,14 @@ import com.njzscloud.supervisory.sys.auth.pojo.result.MyResult;
import com.njzscloud.supervisory.sys.user.pojo.entity.UserEntity;
import com.njzscloud.supervisory.sys.user.pojo.param.UserRegisterParam;
import com.njzscloud.supervisory.sys.user.service.UserService;
import com.njzscloud.supervisory.wxPay.contant.WxApiConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Set;
@ -92,7 +95,27 @@ public class AuthService implements IUserService, IRoleService {
.setEndpoints(endpointResources)
.setCompany(company)
.setDriver(driver)
.setWechatOpenid(wechatOpenid != null ? wechatOpenid : "");
.setWechatOpenid(wechatOpenid != null ? wechatOpenid : "")
.setWxAuthUrl(wxAuthUrl());
}
public String wxAuthUrl() {
// 参数说明
// 对回调地址进行URL编码至关重要[citation:1]
String redirectUri = null;
try {
redirectUri = URLEncoder.encode(WxApiConfig.REDIRECT_URI, WxApiConfig.ENC);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 将authUrl返回给前端引导用户跳转
return "https://open.weixin.qq.com/connect/oauth2/authorize?" +
"appid=" + WxApiConfig.APP_ID +
"&redirect_uri=" + redirectUri +
"&response_type=code" +
"&scope=" + WxApiConfig.SCOPE +
"&state=STATE#wechat_redirect";
}
}

View File

@ -86,4 +86,9 @@ public class UserEntity {
@TableLogic
private Boolean deleted;
/**
* openid
*/
private String openid;
}

View File

@ -0,0 +1,23 @@
package com.njzscloud.supervisory.wxPay.contant;
public class WxApiConfig {
public static final String APP_ID = "wxcf5b818c19c51c07";
public static final String APP_SECRET = "35f72f3d49a9e24c618b82eb624538c8";
public static final String REDIRECT_URI = "https://supervisory.njzscloud.com/test/payment/wechat/callback";
public static final String SCOPE = "snsapi_base"; // 静默授权仅获取OpenID
// String scope = "snsapi_userinfo"; // 非静默授权,可获取用户昵称、头像等更多信息[citation:1]
public static final String ENC = "UTF-8";
public static final String OAUTH_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?";
public static final String GET_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=";
public static final String SEND_TEMPLATE_MSG_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";
}

View File

@ -0,0 +1,55 @@
package com.njzscloud.supervisory.wxPay.controller;
import com.njzscloud.common.core.utils.R;
import com.njzscloud.supervisory.wxPay.dto.TemplateData;
import com.njzscloud.supervisory.wxPay.service.WechatTemplateMessageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
/**
*
* 使SDK
*/
@Slf4j
@RestController
@RequestMapping("/wechatTemplateMessage")
@RequiredArgsConstructor
public class WechatTemplateMessageController {
private final WechatTemplateMessageService wechatTemplateMessageService;
/**
* openid
*/
@GetMapping("/bind")
public R<?> detail(@RequestParam String code) {
wechatTemplateMessageService.bind(code);
return R.success();
}
@PostMapping("/send-order-notice")
public String sendOrderNotice(@RequestParam String openId) {
try {
// 构建模板数据
Map<String, TemplateData> data = new HashMap<>();
data.put("first", new TemplateData("下单待审核通知"));
data.put("character_string6", new TemplateData("202312010001"));
data.put("thing4", new TemplateData("LuanMa"));
data.put("time5", new TemplateData("2023-12-01 10:30:00"));
data.put("remark", new TemplateData("感谢您的购买!"));
// 发送模板消息
String templateId = "HXr8xxYERp2TrkdfBgdRJGSJeMT_8mXF7Yjz6NDBUFw"; // 在公众号后台获取
return wechatTemplateMessageService.sendTemplateMessage(openId, templateId, data,
null, null);
} catch (Exception e) {
return "发送失败: " + e.getMessage();
}
}
}

View File

@ -0,0 +1,21 @@
package com.njzscloud.supervisory.wxPay.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
*
*/
@Data
@AllArgsConstructor
public class TemplateData {
private String value;
private String color;
public TemplateData(String value) {
this.value = value;
this.color = "#173177";
}
}

View File

@ -0,0 +1,18 @@
package com.njzscloud.supervisory.wxPay.service;
import com.njzscloud.supervisory.wxPay.dto.TemplateData;
import java.util.Map;
/**
*
*/
public interface WechatTemplateMessageService {
void bind(String code);
String sendTemplateMessage(String openId, String templateId,
Map<String, TemplateData> data,
String url, String miniProgram);
}

View File

@ -0,0 +1,138 @@
package com.njzscloud.supervisory.wxPay.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.common.security.util.SecurityUtil;
import com.njzscloud.supervisory.sys.user.pojo.entity.UserEntity;
import com.njzscloud.supervisory.sys.user.service.UserService;
import com.njzscloud.supervisory.wxPay.contant.WxApiConfig;
import com.njzscloud.supervisory.wxPay.dto.TemplateData;
import com.njzscloud.supervisory.wxPay.service.WechatTemplateMessageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
/**
*
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class WechatTemplateMessageServiceImpl implements WechatTemplateMessageService {
public final UserService userService;
@Override
public void bind(String code) {
// 使用Code换取Access Token和OpenID
String tokenUrl = WxApiConfig.OAUTH_URL + "appid=" + WxApiConfig.APP_ID + "&secret=" + WxApiConfig.APP_SECRET +
"&code=" + code + "&grant_type=authorization_code";
// 使用HTTP客户端发起请求
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(tokenUrl, String.class);
// 解析微信返回的JSON数据
JSONObject jsonObject = JSONObject.parseObject(response);
if (null == jsonObject) {
throw Exceptions.clierr("获取openid失败");
}
String openId = jsonObject.getString("openid");
// String accessToken = jsonObject.getString("access_token");
// 返回中通常还包含 expires_in, refresh_token等字段[citation:1]
if (openId == null || openId.isEmpty()) {
// 错误处理
String errCode = (String) jsonObject.get("errcode");
String errMsg = (String) jsonObject.get("errmsg");
log.info("获取OpenID失败: " + errCode + " - " + errMsg);
throw Exceptions.clierr("获取openid失败");
}
log.info("用户的OpenID是: " + openId);
// 将openId与你的系统用户关联
UserEntity userEntity = new UserEntity();
userEntity.setId(SecurityUtil.currentUserId());
userEntity.setOpenid(openId);
userService.updateById(userEntity);
}
/**
*
*/
@Override
public String sendTemplateMessage(String openId, String templateId,
Map<String, TemplateData> data,
String url, String miniProgram) {
// 1. 获取Access Token
String accessToken = getAccessToken();
// 2. 构建请求数据
JSONObject requestData = new JSONObject();
requestData.put("touser", openId);
requestData.put("template_id", templateId);
if (url != null) {
requestData.put("url", url); // 点击消息跳转的URL
}
if (miniProgram != null) {
JSONObject miniProgramObj = new JSONObject();
miniProgramObj.put("appid", miniProgram);
miniProgramObj.put("pagepath", "pages/index/index");
requestData.put("miniprogram", miniProgramObj);
}
// 3. 构建模板数据
JSONObject dataObj = new JSONObject();
for (Map.Entry<String, TemplateData> entry : data.entrySet()) {
JSONObject item = new JSONObject();
item.put("value", entry.getValue().getValue());
if (entry.getValue().getColor() != null) {
item.put("color", entry.getValue().getColor());
}
dataObj.put(entry.getKey(), item);
}
requestData.put("data", dataObj);
log.info(JSONObject.toJSONString(requestData));
// 4. 发送请求
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.postForObject(WxApiConfig.SEND_TEMPLATE_MSG_URL + accessToken, JSONObject.toJSONString(requestData), String.class);
// 5. 处理响应
JSONObject jsonResponse = JSONObject.parseObject(response);
if (null == jsonResponse) {
throw Exceptions.clierr("发送模板消息失败jsonResponse为null");
}
if (jsonResponse.getIntValue("errcode") == 0) {
return "发送成功";
} else {
throw Exceptions.clierr("发送模板消息失败: " + jsonResponse.getString("errmsg"));
}
}
/**
* Access Token
*/
private String getAccessToken() {
String tokenUrl = WxApiConfig.GET_TOKEN_URL + WxApiConfig.APP_ID + "&secret=" + WxApiConfig.APP_SECRET;
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(tokenUrl, String.class);
JSONObject jsonResponse = JSONObject.parseObject(response);
if (null == jsonResponse) {
throw Exceptions.clierr("获取Access Token失败");
}
if (jsonResponse.getIntValue("errcode") != 0) {
throw Exceptions.clierr("发送模板消息失败: " + jsonResponse.getString("errmsg"));
}
return jsonResponse.getString("access_token");
}
}