首先我们需要订阅一个消息:
订阅教程本文章并未提起,感兴趣的同学自行百度。
我们可以看到订阅消息中【消息内容】有很多参数,我们在发送消息时就需要将这些参数进行填充,当然填充的时候要注意格式,如果格式不对还是会报错。
教程开始:
1、创建一个实体类,用来填充对应的数据
import lombok.Data;import java.util.Date;@Data
public class LeaveResultMsg {/*** 请假结果通知 -- 模板ID*/public static String RESULTID = "Qd0*************T8k";/*** 请假人OpenId*/private String openId;/*** 请假人名称*/private String name;/*** 请假开始时间*/private Date startTime;/*** 请假结束时间*/private Date endTime;/*** 审核人*/private String examine;/*** 请假结果(同意,不同意)*/private String status;/*** 请假类型*/private String type;}
2、实现类
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import org.dromara.common.api.service.ApiWeChatUtilsService;
import org.dromara.common.api.utils.DateUtil;
import org.dromara.school.domain.LeaveResultMsg;
import org.dromara.school.service.ISubscribeMsgService;
import org.dromara.system.service.ISysConfigService;
import org.springframework.stereotype.Service;import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;@Service
@RequiredArgsConstructor
public class SubscribeMsgService implements ISubscribeMsgService {private final static String SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=";// private final WeChatTokenUtil weChatTokenUtil;private final ISysConfigService configService;private final ApiWeChatUtilsService apiWeChatUtilsService;/*** 请假结果通知* @param msg* @throws Exception*/public void leaveResultW(LeaveResultMsg msg){try {System.out.println(msg.toString());Map<String, Object> params = baseParams(msg.getOpenId());params.put("template_id", LeaveResultMsg.RESULTID);Map<String, Object> data = new HashMap<String, Object>();// 传入转换后的 UTF-8 编码字节数组data.put("thing2", Collections.singletonMap("value", new String(msg.getName().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)));data.put("time3", Collections.singletonMap("value", DateUtil.getStringDateFormat(msg.getStartTime())));data.put("time4",Collections.singletonMap("value", DateUtil.getStringDateFormat(msg.getEndTime())));data.put("thing7", Collections.singletonMap("value",new String(msg.getExamine().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)));data.put("phrase1",Collections.singletonMap("value", new String(msg.getStatus().getBytes(StandardCharsets.UTF_8),StandardCharsets.UTF_8)));params.put("data", data);System.err.println(params);String post;try {post = HttpUtil.post(SEND_URL + apiWeChatUtilsService.getAccessTokenByRedis(0), JSONUtil.toJsonStr(params));}catch (Exception e) {post = HttpUtil.post(SEND_URL + apiWeChatUtilsService.getAccessTokenByRedis(1), JSONUtil.toJsonStr(params));}
// String post = HttpUtil.post(SEND_URL + weChatTokenUtil.getAccessToken(), JSONUtil.toJsonStr(params));System.err.println(post);}catch (Exception e){e.printStackTrace();}}
}
关联到的其他方法:
3、组装参数
@Service
@RequiredArgsConstructor
public class SubscribeMsgService implements ISubscribeMsgService {/*** 组装基础参数** @param openId* @return*/private Map<String, Object> baseParams(String openId) {Map<String, Object> map = new HashMap<String, Object>();String touser = openId;String page = "/pages/home/index";// 微信-小程序订阅跳转版本,developer:开发版,trial:体验版,formal:正式版String miniprogramState = configService.selectConfigByKey("***.version"); //小程序版本map.put("touser", touser);map.put("page", page);map.put("miniprogram_state", miniprogramState);return map;}
}
4、时间转换
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;public class DateUtil { /*** 获取当前时间,转换成String(yyyy-MM-dd HH:mm:ss)* @return yyyyMMddHHmmss*/public static String getStringDateFormat(Date date){//Thu May 11 11:08:15 GMT+08:00 2023//设置日期格式SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//获取String类型的时间String str = df.format(date);return str;}
}
5、获取token
package org.dromara.system.dubbo;import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.api.service.ApiWeChatUtilsService;
import org.dromara.common.api.utils.StringUtil;
import org.dromara.common.api.utils.https.HttpClientUtil;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.base.BaseException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;import java.time.Duration;
import java.util.HashMap;
import java.util.Map;/*** 字典 业务层处理** @author Lion Li*/
@RequiredArgsConstructor
@Service
@Slf4j
public class ApiWeChatUtilsServiceImpl implements ApiWeChatUtilsService {@AutowiredISysConfigService sysConfigService;/*** 0正常获取,1可能token失效了,重新获取(线上线下冲突)* @return*/@Overridepublic String getAccessTokenByRedis(int state) {String key = "wx.access_token";String accessToken;if (state==0){accessToken = RedisUtils.getCacheObject(key);if (StringUtil.isEmpty(accessToken)) {accessToken = getAccessTokenByAddress();if (!StringUtil.isEmpty(accessToken))RedisUtils.setCacheObject(key, accessToken, Duration.ofMinutes(120));}}else {accessToken = getAccessTokenByAddress();if (!StringUtil.isEmpty(accessToken))RedisUtils.setCacheObject(key, accessToken, Duration.ofMinutes(120));}return accessToken;}private String getAccessTokenByAddress() {String appid = sysConfigService.selectConfigByKey("***.appid");String secret =sysConfigService.selectConfigByKey("***.secret");String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;String result = HttpUtil.get(url);HashMap<String, String> resultMap = (HashMap<String, String>) JSONUtil.parse(result).toBean(HashMap.class);String accessToken = resultMap.get("access_token");if (StringUtil.isEmpty(accessToken))throw new BaseException(resultMap.get("errmsg"));return accessToken;}/*** 获取手机号* @param code* @return*/@Overridepublic String getPhoneByCode(String code) {String accessToken = getAccessTokenByRedis(0);String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;HttpHeaders headers = new HttpHeaders();RestTemplate restTemplate = new RestTemplate();HttpEntity<Map<String, String>> httpEntity;if (code.contains("code")) {httpEntity = new HttpEntity(code,headers);}else {Map<String, String> params = new HashMap<>();params.put("code", code);httpEntity = new HttpEntity(params,headers);}ResponseEntity<Object> response = restTemplate.postForEntity(url, httpEntity, Object.class, new Object[0]);HashMap<String, Object> resultMap = (HashMap<String, Object>) JSONUtil.parse(response.getBody()).toBean(HashMap.class);int errcode = ((Integer) resultMap.get("errcode")).intValue();if (errcode != 0) {if (errcode == 40001){//可能会出现多个服务器重复获取,导致accessToken失效的情况accessToken = getAccessTokenByRedis(1);url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;response = restTemplate.postForEntity(url, httpEntity, Object.class, new Object[0]);resultMap = (HashMap<String, Object>) JSONUtil.parse(response.getBody()).toBean(HashMap.class);errcode = ((Integer) resultMap.get("errcode")).intValue();if (errcode != 0){throw new ServiceException("获取手机号出错,报错类型------>{}",errcode);}}else {throw new ServiceException("获取手机号出错,报错类型------>{}",errcode);}}HashMap<String, Object> phoneInfo = (HashMap<String, Object>) JSONUtil.parse(resultMap.get("phone_info")).toBean(HashMap.class);String phone = (String) phoneInfo.get("purePhoneNumber");return phone;}/*** 获取手机号2* @param code* @return*/public String getPhoneByCode2(String code) {String accessToken = getAccessTokenByRedis(0);String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;
// String jsonStr = "{\"code\":\"" + code + "\"}";String httpOrgCreateTestRtn = HttpClientUtil.doPost(url, code, "utf-8");System.out.println("获取到的手机号----------->"+httpOrgCreateTestRtn);return httpOrgCreateTestRtn;}/*** 获取openid* @param code* @return*/@Overridepublic String getOpenidByCode(String code) {String appid = sysConfigService.selectConfigByKey("weChat.mini.appid");String secret =sysConfigService.selectConfigByKey("weChat.mini.secret");//https://api.weixin.qq.com/sns/jscode2sessionString url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret +"&js_code=" + code + "&grant_type=authorization_code";String result = HttpUtil.get(url);HashMap<String, String> resultMap = (HashMap<String, String>) JSONUtil.parse(result).toBean(HashMap.class);String openId = resultMap.get("openid");
// System.out.println("获取到的openId----------->"+openId);if (StringUtils.isNotEmpty(openId)) {return openId;} else {throw new ServiceException("用户信息获取错误,请稍候重试",Integer.valueOf(resultMap.get("errcode")) );}}}
以上用到的config类是配置类,配置的内容是由你申请小程序时候得到的数据。