工具类: 小程序消息推送

背景


前端时间负责小程序后端的老哥离职,所以由本人负责与前端对接开发 - 小程序消息推送,简单封装了个工具类,在此记录一下。

前提


服务通知推送需要申请小程序模板,具体申请细节可百度了解,登录地址:微信公众平台

对接文档地址:微信官方文档

获取用户登录唯一code:唯一code,使用 code 换取 openid、unionid、session_key 等信息
在这里插入图片描述

代码实现


  • 配置类
public class WxProperties {
    /**
     * 小程序appid
     */
    public static String appid = "登录小程序官网账户获取";
    /**
     * 小程序应用密钥
     */
    public static String appsecret = "登录小程序官网账户获取";
    /**
     * 小程序获取token的地址  APPID 和 APPSECRET 记得替换为真实 appId和密钥
     */
    public static String accessTokenUrl ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";;
    /**
     * 小程序消息推送模板id
     */
    public static String templateId = "前面申请的模板id";
    /**
     * 小程序消息推送地址 ACCESS_TOKEN 记得替换为真实 access_token
     */
    public static String sendMessageUrl = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN";
    /**
     * 小程序获取openid地址 APPID 和 APPSECRET 和 JSCODE(通过 wx.login 接口获得临时登录凭证 code,微信前端唯一标识) 需替换
     */
    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;
    /**
     * 接收者(用户)的 openid
     */
    private String touser;
    /**
     * 模板内容
     */
    private HashMap data;
    /**
     * 订阅模板id
     */
    @JsonProperty("template_id")
    private String templateId;
    /**
     * 点击模板卡片后的跳转页面
     */
    private String page;
    /**
     * 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
     */
    @JsonProperty("miniprogram_state")
    private String miniprogramState;

}
  • 获取access_token 工具
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 {

    /**
     * 数值3,用于请求次数的判断
     */
    private static final Integer COUNT = 3;

    @Autowired
    RedisService redisService;

    private static WxSendUtil sendUtil;

    @PostConstruct
    public void init() {
        sendUtil = this;
    }

    /**
     * 请求推送接口,并处理响应
     *
     * @param param 微信小程序订阅消息参数类
     * @param accessToken 接口调用凭证 (传空时会重新获取)
     * @param count 用于次数统计,初始传0
     * @return
     * @author  wrx
     * @date  2021/11/3 21:45
     */
    public static R sendAndHandle(WxSendMessageParam param, String accessToken, Integer count) {
        // 重发推送请求前,判断是否已请求2次,是则结束程序
        if (++count >= COUNT) {
            log.info("已请求2次 向用户推送消息失败");
            return R.FAIL("向用户推送消息失败");
        }
        log.info("进入sendAndHandle:{}",count);
        // 请求推送接口,获取响应map
        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 {
            // ①走到此说明推送失败了
            // ②如果不是因为token过期导致请求失败,直接结束程序
            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{
                //③走到此说明说明是token过期导致失败则重新获取token,再次发起推送请求
                return sendAndHandle(param, StrUtil.EMPTY, count);
            }
        }
    }

    /**
     * 请求微信推送api接口
     *
     * @param param 微信小程序订阅消息参数类
     * @param accessToken 接口调用凭证 (传空时会重新获取)
     * @return
     * @author  wrx
     * @date  2021/11/3 19:56
     */
    private static Map<String, Object> reqWxSendAPI(WxSendMessageParam param, String accessToken)  {
        // ①如果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;
    }

    /**
     * 获取并刷新缓存中的access_token
     *
     * @return  token
     * @author  wrx
     * @date  2021/11/3 17:02
     */
    private static String getAndRefreshToken() {
        AccessTokenUtil token = AccessTokenUtil.getAccessToken();
        log.info("获取到的token:" + JSONUtil.toJsonStr(token));
        String accessToken = token.getToken();
        //更新redis中的微信凭证和过期时间
        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;
    }

    /**
     * 发送小程序推送消息
     *
     * @param  createrId 单证创建人id
     * @param  sourceMap 存储模板内容的源map
     * @param  pageUrl 点击推送详情要跳转的页面
     * @param  templateId 模板id
     * @return
     * @author  wrx
     * @date  2021/11/3 16:22
     */
    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));
    }

    /**
     * 添加模板内容
     *
     * @param  source 存储模板内容的源map
     * @param  keyword key
     * @param  value value
     * @return
     * @author  wrx
     * @date  2021/11/3 14:26
     */
    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);

推送成功效果


在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值