公众号消息推送
parent
b275a2c1fc
commit
ea336aece1
|
|
@ -46,4 +46,9 @@ public class MyResult extends UserDetail {
|
|||
*/
|
||||
private String wechatOpenid;
|
||||
|
||||
/**
|
||||
* 微信授权地址
|
||||
*/
|
||||
private String wxAuthUrl;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,4 +86,9 @@ public class UserEntity {
|
|||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 微信 公众号openid
|
||||
*/
|
||||
private String openid;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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=";
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue