背景
前端时间负责小程序后端的老哥离职,所以由本人负责与前端对接开发 - 小程序消息推送,简单封装了个工具类,在此记录一下。
前提
服务通知推送需要申请小程序模板,具体申请细节可百度了解,登录地址:微信公众平台
对接文档地址:微信官方文档
获取用户登录唯一code:唯一code,使用 code 换取 openid、unionid、session_key 等信息
代码实现
public class WxProperties {
public static String appid = "登录小程序官网账户获取";
public static String appsecret = "登录小程序官网账户获取";
public static String accessTokenUrl ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";;
public static String templateId = "前面申请的模板id";
public static String sendMessageUrl = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN";
public static String openIdUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=APPSECRET&js_code=JSCODE&grant_type=authorization_code";
public static Boolean sendMessageFlag = true;
}
public class WxSendMessageParam {
@JsonProperty("access_token")
private String accessToken;
private String touser;
private HashMap data;
@JsonProperty("template_id")
private String templateId;
private String page;
@JsonProperty("miniprogram_state")
private String miniprogramState;
}
public class AccessTokenUtil {
private String token;
private int expiresIn;
public static AccessTokenUtil getAccessToken() {
AccessTokenUtil token = new AccessTokenUtil();
String url = WxProperties.accessTokenUrl.replace(WxCommonConstants.APPID, WxProperties.appid).replace(WxCommonConstants.APPSECRET, WxProperties.appsecret);
try {
log.info("appid :" + WxProperties.appid);
log.info("appsecret :" + WxProperties.appsecret);
log.info("accessTokenUrl :" + WxProperties.accessTokenUrl);
log.info("调用微信获取凭证url :" + url);
String resp = HttpUtil.get(url);
log.info("调用微信获取凭证接口返回 :" + resp);
HashMap resMap = JSONUtil.toBean(resp, HashMap.class);
if (MapUtil.isNotEmpty(resMap)) {
token.setToken(MapUtil.getStr(resMap, WxCommonConstants.ACCESS_TOKEN));
token.setExpiresIn(MapUtil.getInt(resMap, WxCommonConstants.EXPIRES_IN));
}
log.info("token :" + token.getToken());
return token;
} catch (Exception e) {
log.error("获取access_token失败:" + ExceptionUtil.stacktraceToString(e));
return token;
}
}
}
@Component
public class WxSendUtil {
private static final Integer COUNT = 3;
@Autowired
RedisService redisService;
private static WxSendUtil sendUtil;
@PostConstruct
public void init() {
sendUtil = this;
}
public static R sendAndHandle(WxSendMessageParam param, String accessToken, Integer count) {
if (++count >= COUNT) {
log.info("已请求2次 向用户推送消息失败");
return R.FAIL("向用户推送消息失败");
}
log.info("进入sendAndHandle:{}",count);
Map<String, Object> map = reqWxSendAPI(param, accessToken);
String errCode = MapUtil.getStr(map, WxCommonConstants.ERRCODE);
if (WxCommonConstants.SUCCESS.equals(errCode)) {
log.info(StrUtil.format("第{}次 向用户推送消息成功",count));
return new R<>("向用户推送消息成功");
} else {
log.info(StrUtil.format("第{}次 错误 errorCode:" + errCode + ",错误errormsg:" + MapUtil.getStr(map, WxCommonConstants.ERRMSG)),count);
if (!WxCommonConstants.ERROR_CODE_40001.equals(errCode)) {
log.info(StrUtil.format("第{}次 向用户推送消息失败"),count);
return R.FAIL("向用户推送消息失败");
}else{
return sendAndHandle(param, StrUtil.EMPTY, count);
}
}
}
private static Map<String, Object> reqWxSendAPI(WxSendMessageParam param, String accessToken) {
param.setAccessToken(StrUtil.isBlank(accessToken) ? getAndRefreshToken() : accessToken);
String url = WxProperties.sendMessageUrl + param.getAccessToken();
log.info("发送订阅消息请求 :" + url + "&" + JsonUtil.toJson(param));
String resp = HttpUtil.post(url, JsonUtil.toJson(param));
log.info("发送订阅消息请求响应 :" + resp);
Map<String, Object> map = JSONUtil.toBean(resp, HashMap.class);
if (MapUtil.isEmpty(map)) {
log.info("请求微信推送接口时,发生了未知的情况,响应为空");
throw new ServiceException(WxCodeMsg.REQ_API_EXCEPTION.fillArgs("未知的响应结果"));
}
return map;
}
private static String getAndRefreshToken() {
AccessTokenUtil token = AccessTokenUtil.getAccessToken();
log.info("获取到的token:" + JSONUtil.toJsonStr(token));
String accessToken = token.getToken();
sendUtil.redisService.set(WxCommonConstants.ACCESS_TOKEN_REDIS_PREFIX, accessToken, token.getExpiresIn());
return accessToken;
}
}
- 业务层组装WxSendMessageParam 并远程调用工具
@Slf4j
@Component
public class HkWxSendUtil {
@Autowired
RemoteWxSendMessageService remoteWxSendMessageService;
private static HkWxSendUtil sendUtil;
@PostConstruct
public void init() {
sendUtil = this;
}
public static void sendMessage(HashMap<String, Object> sourceMap,String openId,String pageUrl,String templateId) {
WxSendMessageParam messageParam = new WxSendMessageParam();
messageParam.setTouser(openId);
messageParam.setData(sourceMap);
messageParam.setTemplateId(templateId);
messageParam.setPage(pageUrl);
log.info("微信订阅消息参数 :" + JSONUtil.toJsonStr(messageParam));
R r = sendUtil.remoteWxSendMessageService.newSendWxMessage(messageParam, SecurityConstants.FROM_IN);
log.info("微信订阅消息返回 :" + JSONUtil.toJsonStr(r));
}
public static void putWxParamMap(HashMap<String, Object> source, String keyword, Object value) {
HashMap<String, Object> paramMap = new HashMap<>(2);
paramMap.put("value",value);
source.put(keyword,paramMap);
}
}
main:
log.info("进入小程序推送方法");
HashMap<String,Object> sourceMap = new HashMap<>(8);
HkWxSendUtil.putWxParamMap(sourceMap,"模板key1","key1对应的值");
HkWxSendUtil.putWxParamMap(sourceMap,"模板key2","key2对应的值");
HkWxSendUtil.putWxParamMap(sourceMap,"模板key3","key3对应的值");
HkWxSendUtil.putWxParamMap(sourceMap,"模板key4","key4对应的值");
HkWxSendUtil.putWxParamMap(sourceMap,"模板key5","key5对应的值");
HkWxSendUtil.sendMessage(sourceMap,openId, pageUrl,templateId);
推送成功效果
|