关于微信模板消息从申请到前后端代码全流程

98 阅读5分钟

医院的项目已经做好了,之前上级说最好要跟微信建联好,于是决定加入实时发送微信推送的功能,也就是发送微信模板信息的功能,感觉这个在以后也会经常用到这个功能,所以在这里写一下随笔,第一步,要先去微信开放平台把想要的模板信息挑选出来,这里我就不得不吐槽一句,找了半天没找到想要的,最好不得不挑了个沾得上边得的,好像是因为医院的随访,会诊这些功能国家都有规定,不能随便命名,所以微信模板消息也就比较少了。功能本身其实不复杂,但是我们的登录是只有医生在管理端添加进医院了,填写了准确的预留手机号,且分配了职位,才能够登录进小程序.而有一个功能板块是医生邀请其他医生进行会诊,亦或是患者邀请医生进行线下或者线上就诊,所以这不可避免地出现有可能有医生没有openId,发送不了模板信息。还有一个问题是,患者表和医生分别存储在client表与user表,所以前端在传的时候要定义好发送者与接收者的identity身份标识,加快查询效率。

image.png

第一步还是和以往一样,用serect与appid拿到该站点的token。

String wxAppId = "w*********************f";
String wxSecret = "8*********************a1";
String accessToken = getAccessToken(wxAppId, wxSecret);
private String getAccessToken(String appId, String appSecret) {
    com.alibaba.fastjson.JSONObject params = new com.alibaba.fastjson.JSONObject();
    params.put("grant_type", "client_credential");
    params.put("appid", appId);
    params.put("secret", appSecret);
    params.put("force_refresh", false);
    HttpResponse accessTokenResponse = HttpRequest.post("https://api.weixin.qq.com/cgi-bin/stable_token" ).body(params.toJSONString()).execute();
    com.alibaba.fastjson.JSONObject tokenJson = JSON.parseObject(accessTokenResponse.body());
    if(!tokenJson.containsKey("access_token")){
        throw new CommonException("******* 微信获取accessToken的错误返回结果 {}", accessTokenResponse.body());
    }
    String token = tokenJson.get("access_token").toString();
    int expiresIn = Integer.parseInt(tokenJson.get("expires_in").toString());
    return token;
}

判断用户的身份,查不到openId,就不查了,抛出异常。

List<ClientUser> clientUserList = new ArrayList<>();
List<BizUser> bizUserList = new ArrayList<>();
if (messageInfo.getReceptionIndentity().equals("0")) {
    QueryWrapper<ClientUser> queryWrapperUserList = new QueryWrapper<>();
    queryWrapperUserList.lambda().eq(ClientUser::getId, messageInfo.getUserId());
    clientUserList = clientUserService.list(queryWrapperUserList);
} else if (messageInfo.getReceptionIndentity().equals("1")) {
    QueryWrapper<BizUser> queryWrapperUserList = new QueryWrapper<>();
    queryWrapperUserList.lambda().eq(BizUser::getId, messageInfo.getUserId());
    bizUserList = bizUserService.list(queryWrapperUserList);
}
JSONArray userJsonArray = new JSONArray();
if (!clientUserList.isEmpty()) {
    for (ClientUser clientUser : clientUserList) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userId", clientUser.getId());
        jsonObject.put("userOpenId", clientUser.getOpenId());
        userJsonArray.put(jsonObject);
    }
} else if (!bizUserList.isEmpty()) {
    for (BizUser bizUser : bizUserList) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userId", bizUser.getId());
        jsonObject.put("userOpenId", bizUser.getOpenId());
        userJsonArray.put(jsonObject);
    }
} else {
    throw new CommonException("用户列表为空");
}

根据和前端协商好的,使用对应模板发送信息。

com.alibaba.fastjson.JSONObject data = new com.alibaba.fastjson.JSONObject();//模板数据data
//发送微信推送
//根据模板设置data数据
String templateId = "";
switch (messageInfo.getTemplatePurpose()) {
    case "INVITE":
        templateId = INVITE_TEMPLATE_ID;
        constructInviteData(messageInfo, templateId, data);
        break;
    case "INVITED":
        break;
    case "INVITERESULT":
        templateId = INVITE_TEMPLATE_RESULT_ID;

        constructInviteResultData(messageInfo, templateId, data);
        break;
    case "INVITEDOCTOR":
        templateId=INVITEDOCTOR;
        constructInviteDoctor(messageInfo, templateId, data);
    default:
        throw new CommonException("模版参数有误");
}

String finalTemplateId = templateId;
userJsonArray.forEach(thirdUser -> {
    this.sendTemplate(data, accessToken, finalTemplateId, ((cn.hutool.json.JSONObject) thirdUser).get("userOpenId").toString(), "/pages/mine/index");
});

完整实现

public void sendMessageToUser(List<MessageInfo> messageInfos) {
//
        String wxAppId = "w89888888888888*********f";
        String wxSecret = "8b5*****************************a1";
        String accessToken = getAccessToken(wxAppId, wxSecret);
        for (MessageInfo messageInfo : messageInfos) {
            //发送微信推送
            //判断接收者是患者还是医生
            List<ClientUser> clientUserList = new ArrayList<>();
            List<BizUser> bizUserList = new ArrayList<>();
            if (messageInfo.getReceptionIndentity().equals("0")) {
                QueryWrapper<ClientUser> queryWrapperUserList = new QueryWrapper<>();
                queryWrapperUserList.lambda().eq(ClientUser::getId, messageInfo.getUserId());
                clientUserList = clientUserService.list(queryWrapperUserList);
            } else if (messageInfo.getReceptionIndentity().equals("1")) {
                QueryWrapper<BizUser> queryWrapperUserList = new QueryWrapper<>();
                queryWrapperUserList.lambda().eq(BizUser::getId, messageInfo.getUserId());
                bizUserList = bizUserService.list(queryWrapperUserList);
            }
            JSONArray userJsonArray = new JSONArray();
            if (!clientUserList.isEmpty()) {
                for (ClientUser clientUser : clientUserList) {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("userId", clientUser.getId());
                    jsonObject.put("userOpenId", clientUser.getOpenId());
                    userJsonArray.put(jsonObject);
                }
            } else if (!bizUserList.isEmpty()) {
                for (BizUser bizUser : bizUserList) {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("userId", bizUser.getId());
                    jsonObject.put("userOpenId", bizUser.getOpenId());
                    userJsonArray.put(jsonObject);
                }
            } else {
                throw new CommonException("用户列表为空");
            }


            com.alibaba.fastjson.JSONObject data = new com.alibaba.fastjson.JSONObject();//模板数据data
            //发送微信推送
            //根据模板设置data数据
            String templateId = "";
            switch (messageInfo.getTemplatePurpose()) {
                case "INVITE":
                    templateId = INVITE_TEMPLATE_ID;
                    constructInviteData(messageInfo, templateId, data);
                    break;
                case "INVITED":
                    break;
                case "INVITERESULT":
                    templateId = INVITE_TEMPLATE_RESULT_ID;

                    constructInviteResultData(messageInfo, templateId, data);
                    break;
                case "INVITEDOCTOR":
                    templateId=INVITEDOCTOR;
                    constructInviteDoctor(messageInfo, templateId, data);
                default:
                    throw new CommonException("模版参数有误");
            }

            String finalTemplateId = templateId;
            userJsonArray.forEach(thirdUser -> {
                this.sendTemplate(data, accessToken, finalTemplateId, ((cn.hutool.json.JSONObject) thirdUser).get("userOpenId").toString(), "/pages/mine/index");
            });
        }
    }

相对应的三个模板信息

public void constructInviteDoctor(MessageInfo messageInfo, String templateId, com.alibaba.fastjson.JSONObject data){
    com.alibaba.fastjson.JSONObject thing1 = new com.alibaba.fastjson.JSONObject();
    thing1.put("value", messageInfo.getConsultationType());

    com.alibaba.fastjson.JSONObject thing9 = new com.alibaba.fastjson.JSONObject();
    thing9.put("value", messageInfo.getConsulationName());

    com.alibaba.fastjson.JSONObject time8 = new com.alibaba.fastjson.JSONObject();
    time8.put("value", messageInfo.getConsulationTime());

    com.alibaba.fastjson.JSONObject thing5 = new com.alibaba.fastjson.JSONObject();
    thing5.put("value", messageInfo.getConsulationLaunchName());

    com.alibaba.fastjson.JSONObject thing6 = new com.alibaba.fastjson.JSONObject();
    thing6.put("value", messageInfo.getConsulationRemark());

    data.put("thing1", thing1);
    data.put("thing9", thing9);
    data.put("time8", time8);
    data.put("thing5", thing5);
    data.put("thing6", thing6);

}

public void constructInviteResultData(MessageInfo messageInfo, String templateId, com.alibaba.fastjson.JSONObject data){
    com.alibaba.fastjson.JSONObject thing1 = new com.alibaba.fastjson.JSONObject();
    thing1.put("value", messageInfo.getBookingName());

    com.alibaba.fastjson.JSONObject thing2 = new com.alibaba.fastjson.JSONObject();
    thing2.put("value", messageInfo.getBookingStatus());

    com.alibaba.fastjson.JSONObject time3 = new com.alibaba.fastjson.JSONObject();
    time3.put("value", messageInfo.getBookingTime());

    com.alibaba.fastjson.JSONObject thing4 = new com.alibaba.fastjson.JSONObject();
    thing4.put("value",messageInfo.getBookingName()+ messageInfo.getBookingRemark());//萧医生 /接受/拒绝  了您的线下邀请

    data.put("thing1", thing1);
    data.put("thing2", thing2);
    data.put("time3", time3);
    data.put("thing4", thing4);

}

public void constructInviteData(MessageInfo messageInfo, String templateId, com.alibaba.fastjson.JSONObject data) {
    com.alibaba.fastjson.JSONObject thing1 = new com.alibaba.fastjson.JSONObject();
    thing1.put("value", messageInfo.getBookingTitle());

    com.alibaba.fastjson.JSONObject thing2 = new com.alibaba.fastjson.JSONObject();
    thing2.put("value", "请及时应邀");

    com.alibaba.fastjson.JSONObject thing3 = new com.alibaba.fastjson.JSONObject();
    thing3.put("value", messageInfo.getBookingName());

    com.alibaba.fastjson.JSONObject time5 = new com.alibaba.fastjson.JSONObject();
    time5.put("value", messageInfo.getBookingTime());

    com.alibaba.fastjson.JSONObject phone_number4 = new com.alibaba.fastjson.JSONObject();
    phone_number4.put("value", messageInfo.getBookingPhone());

    data.put("thing1", thing1);
    data.put("thing2", thing2);
    data.put("thing3", thing3);
    data.put("time5", time5);
    data.put("phone_number4", phone_number4);
}

最后的发送信息

private void sendTemplate(com.alibaba.fastjson.JSONObject data, String accessToken, String templateId, String toUser, String page) {
    com.alibaba.fastjson.JSONObject params = new com.alibaba.fastjson.JSONObject();
    params.put("template_id", templateId);
    params.put("touser", toUser);
    params.put("data", data);
    params.put("page", page);   //"/pages/mine/index"
    params.put("miniprogram_state", "formal");
    params.put("lang", "zh_CN");
    String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken;
    String response = HttpUtil.post(url, params.toJSONString());
    com.alibaba.fastjson.JSONObject res = JSON.parseObject(response);
    log.warn("*** 微信发送消息返回结果:"+ response);
}

接下来是前端,微信每点击一次授权就可以多一次弹窗,次数可以累加,但是如果用户不点击接受,没有次数,就不会给用户发送模板信息,所以需要找地方将授权的弹窗放置,且必须是用户主动点击。所以可以找那种页面点击跳转的按钮进行微信模板信息的授权,调用wx.requestSubscribeMessage这个api,往tmplIds,push进ID就可以了。

handleToOnlineVisit(){		
	const param = encodeURIComponent(JSON.stringify(this.doctorDetailInfo));
	const templateInviteId='JEY2J41VcFP_dqDwPyYKD_0jSRWxfjwrIwwq93aKkR8'
	const templateInvitedId='BtzZZ7j-5j6na-6IwoM8i8EK1UH6VrHNycM0Ntbr45M'
	const templateInviteResult='JRCTpv43CSdn7g7I_GU5aMepOxDj-6WtroPIYFAMNfo'
	const templIdsArray=[]
	if(templateInviteId) templIdsArray.push(templateInviteId)
	if(templateInvitedId) templIdsArray.push(templateInvitedId)
	if(templateInviteResult) templIdsArray.push(templateInviteResult)
	if(templIdsArray.length>0){
		wx.requestSubscribeMessage({
		tmplIds:[...templIdsArray],						
		success(res){
			uni.navigateTo({
				url: '/pages/mine/onlineVisit/index?param=' + param
			})
			}})}else{
			uni.navigateTo({
				url: '/pages/mine/onlineVisit/index?param=' + param
			})
		}
				
	}

授权完毕接下来就是发送了,在封装接口的时候param特意将其不封装为param对象,而是list数组,原因就是方便如果得给多个人发送消息,就不用调多次接口,而是服务端循环list数组就可以了。

	const inviteDoctorArray = [];
	const nowTime = getDate(0);
	const launchDoctorName = getUserInfo().name;
	       currentDoctorIdArray.forEach((record, index) => {
		let param = {
			 userId: record,
			 receptionIndentity: '1',
			 templatePurpose: 'INVITEDOCTOR',
			 consulationName: this.consultationName,
			 consultationType: '新的会诊',
			 consulationTime: nowTime,
			 consulationRemark: '您有新的会诊,请及时应邀',
			 consulationLaunchName: launchDoctorName
			};
			inviteDoctorArray.push(param);
		});
	     await sendTemplateMessageToUser(currentDoctorIdArray);
                

最后收到消息的感觉别提多开心

image.png