小程序统一服务消息实现

总体思路:运营后台处理某个任务时,推送相关消息到绑定了小程序的微信账户的服务通知里。需要用到用户的openid和用户在小程序中有交互动作产生的formId。

后台表结构设计:

 

小程序中的代码(taro-ui):

<View className="orderInfo">
          <View
            className="infoItem"
            onClick={this.navigateTo.bind(this, '/pages/order/unHandleOrder')}
          >
            <AtForm className="tb-submitForm"
              onSubmit={this.onSubmit.bind(this)}
              reportSubmit
            >
              <AtButton formType='submit'  className="num tb-submitBtn">{orderCount}</AtButton>
            </AtForm>
            <View className="infoTip">处理订单</View>
          </View>
          <View className="vLine" />
          <View className="infoItem" onClick={this.navigateTo.bind(this, '/pages/me/msgCenter')}>
            <AtForm className="tb-submitForm"
              onSubmit={this.onSubmit.bind(this)}
              reportSubmit
            >
              <AtButton formType='submit'  className="num tb-submitBtn">{msgCount}</AtButton>
            </AtForm>
            <View className="infoTip">未读消息</View>
          </View>
        </View>

 

  //表单提交事件,用于采集用户form_id
  onSubmit (event) {
    this.props.dispatch(action('app/updateUserFormId', event.detail.formId));
  }

app.js:

*updateUserFormId({ payload }, { select, call, put }) {
      try {
        const wechatId = yield select(state => state.app.openid);
        const formId = payload;

        console.log('updateUserFormId print formId : ' + formId);
        console.log('updateUserFormId print wechatId : ' + wechatId);
        const data = {
          urlParms: '/sys/api/v1/user/updateUserFormId',
          bodys: { wechatId, formId },
        };
        const res = yield call(request, data);
        if (res.code == 0) {
          // nothing to do
        } else {
          Taro.showToast({
            title: res.message,
            icon: 'none',
            duration: 2000,
          });
        }
      } catch (e) {
        console.log(e);
      }
    },

后台代码:

1)保存formId

/**
	 * 更新用户的formId
	 * @author xxx
	 * @date 2019-03-05 17:31:57
	 * @param formId
	 * @param wechatId
	 * @return
	 */
	@RequestMapping("/updateUserFormId")
	@ResponseBody
	@HttpSecurityAnnotation(typeValue = MethodType.USER_SERVICE,openLog=true)
	public String updateUserFormId(@NotBlank(message="formId不能为空") @Bodys(value="formId")String formId,
                @NotBlank(message="wechatId不能为空") @Bodys(value="wechatId")String wechatId){
		try{
			userService.updateUserFormId(wechatId,formId);
		}catch(Exception e){
			log.error("更新用户的formId失败!",e);
			return JSONUtil.wrapResponse(JSONUtil.ResponseCode.FAILURE,e.getMessage());
		}
		return JSONUtil.wrapResponse(JSONUtil.ResponseCode.SUCCESS,"更新用户的formId成功");
	}

1)发送模板消息:

if(addOperation){	//	新增对账单,发送消息到买方微信(拥有对账权限的买方账号)。
			String open = env.getProperty("wechat.uniformMessage.open","off");
			if("off".equals(open)){	//发送统一服务消息开关已关闭
				return;
			}
			//小程序跳转页面
			String page = env.getProperty("wechat.duizhangdan.page","pages/me/index");

			//7天 = 7 * 24 = 168小时,这里去掉1小时。
			//当前时间往前推167个小时,如果用户的的formId最后更新时间大于这个时间,则说明formId有效。
			//formId目前有效期微信给出的是7天。
			Date newDate = DateUtils.addHours(new Date(),-167);

			List<PersonVO> personList = this.userService.getMbrCellphones(ECAuthConstant.BLANACE_ACC, blanace.getBuyerId());
			if(!personList.isEmpty()){
				JSONObject data = new JSONObject();
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

				Map<String,Object> keyMap1 = new HashMap<String,Object>();
				keyMap1.put("value",blanace.getBuyerName());
				//添加客户名称
				data.put("keyword1",keyMap1);

				Map<String,Object> keyMap2 = new HashMap<String,Object>();
				keyMap2.put("value",blanace.getSellerName());
				//添加卖方名称
				data.put("keyword2",keyMap2);

				Map<String,Object> keyMap3 = new HashMap<String,Object>();
				keyMap3.put("value",blanace.getMonth());
				//添加对账月份
				data.put("keyword3",keyMap3);

				Map<String,Object> keyMap4 = new HashMap<String,Object>();
				keyMap4.put("value",sdf.format(blanace.getCreateTime()));
				//添加创建时间
				data.put("keyword4",keyMap4);

				for(PersonVO personVO : personList){
					if(StringUtils.isEmpty(personVO.getWechatFormId())){
                        logger.warn("用户的微信formId为空,不发送消息!用户名[" + personVO.getPersonName() + "]");
						continue;
                    }
                    if(personVO.getWechatFormIdModifyTime().before(newDate)){
                        //formId认为无效了,则不用发送了。
                        logger.warn("用户的微信formId时间已失效,不发送消息!用户名[" + personVO.getPersonName() + "]");
                        continue;
					}

					final UniformMsg uniformMsg = new UniformMsg();
					uniformMsg.setTouser(personVO.getWechatId());
					//uniformMsg.setTouser("oZaHr4iznKdHEjGremZZfvPS3X3k");
					uniformMsg.setForm_id(personVO.getWechatFormId());
					//uniformMsg.setForm_id("7821c2ceb9e848f1a95a2af8ce5f5a1c");
					uniformMsg.setTemplate_id(env.getProperty("wechat.duizhangdan.template_id"));
					uniformMsg.setPage(page); //小程序跳转页面
					uniformMsg.setData(data);
					this.taskExecutor.execute(new Runnable() {
						public void run() {
							wechatService.sendUniformMessage(uniformMsg);
						}
					});
				}
			}
		}

IWechatService.java:

    @Autowired
    private Environment env;

    @Autowired
    private RedisTemplate redisTemplate;

    private volatile Boolean init = false;

    private String appid;
    private String secret;

    //获取微信accessToken接口地址
    private String accessTokenIp;

    //获取微信发送统一模板消息接口地址
    private String uniformMessageIp;


    private void init(){
        init = true;
        appid = env.getProperty("wechat.appid");
        secret = env.getProperty("wechat.secret");
        accessTokenIp = env.getProperty("wechat.accesstoken.ip");
        uniformMessageIp = env.getProperty("wechat.uniformMessage.ip");
    }


    @Override
    public String getAccessToken() throws Exception{
        if(!init){
            init();
        }

        NameValuePair[] nameValuePairs = new NameValuePair[3];

        NameValuePair nameValuePair = new NameValuePair();
        nameValuePair.setName("appid");
        nameValuePair.setValue(this.appid);

        NameValuePair nameValuePair2 = new NameValuePair();
        nameValuePair2.setName("secret");
        nameValuePair2.setValue(this.secret);

        NameValuePair nameValuePair3 = new NameValuePair();
        nameValuePair3.setName("grant_type");
        nameValuePair3.setValue("client_credential");

        nameValuePairs[0] = nameValuePair;
        nameValuePairs[1] = nameValuePair2;
        nameValuePairs[2] = nameValuePair3;

        HttpClient client = new HttpClient();
        GetMethod method = new GetMethod(this.accessTokenIp);
        method.addRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        method.setQueryString(nameValuePairs);

        client.executeMethod(method);
        String retValue = method.getResponseBodyAsString();
        method.releaseConnection();
        JSONObject jsonObject = JSONObject.parseObject(retValue);
        if(jsonObject.get("errcode") != null){
            logger.warn("微信小程序接口,获取accessToken失败,原因:{}",jsonObject.get("errmsg"));
            return null;
        }
        logger.info("打印accessToken jsonObject:{}",jsonObject.toJSONString());

        //将微信accessToken放入redis中
        redisTemplate.opsForValue().set("wechatAccessToken",jsonObject.get("access_token"));
        return (String)jsonObject.get("access_token");
    }



    @Override
    public void sendUniformMessage(UniformMsg uniformMsg) {
        if(StringUtils.isEmpty(uniformMessageIp)){
            init();
        }
        Double randomNum = Math.random();
        String redisAccesssToken = (String) redisTemplate.opsForValue().get("wechatAccessToken");
        if(StringUtils.isEmpty(redisAccesssToken)){
            try {
                this.getAccessToken();
            } catch (Exception e) {
                logger.error("发送统一模板消息,获取accessToken异常!",e);
                throw new RuntimeException("发送统一模板消息,获取accessToken异常!");
            }
        }
        redisAccesssToken = (String) redisTemplate.opsForValue().get("wechatAccessToken");

        uniformMsg.getWeapp_template_msg().put("template_id",uniformMsg.getTemplate_id());
        uniformMsg.getWeapp_template_msg().put("page",uniformMsg.getPage());
        uniformMsg.getWeapp_template_msg().put("form_id",uniformMsg.getForm_id());
        uniformMsg.getWeapp_template_msg().put("data",uniformMsg.getData());
        uniformMsg.getWeapp_template_msg().put("emphasis_keyword","");

        Map<String,Object> submitMap = Maps.newHashMap();
        submitMap.put("touser",uniformMsg.getTouser());
        submitMap.put("weapp_template_msg",uniformMsg.getWeapp_template_msg());
        //请求url
        String postUrl = this.uniformMessageIp + "?access_token=" + redisAccesssToken;
        //执行请求发送
        logger.info("[" + randomNum + "]submitMap:{}", JSON.toJSONString(submitMap));
        String retValue = "";
        try{
            retValue = this.httpsRequest(postUrl,"POST",JSON.toJSONString(submitMap));
        }catch(Exception e){
            logger.error(e.getMessage(),e);
            return;
        }
        logger.info("[" + randomNum + "]打印retValue:{}",retValue);
        logger.info("[" + randomNum + "]打印accessToken:{}",redisAccesssToken);
        //得到返回结果
        JSONObject jsonObject = JSONObject.parseObject(retValue);
        if(jsonObject.get("errcode") != null && (int)jsonObject.get("errcode") != 0){
            logger.warn("[" + randomNum + "]微信小程序接口,发送统一模板消息失败,原因:{}",jsonObject.get("errmsg"));
            if(DJECConstants.WechatUniformMsgErrcodeEnum.ACCESS_TOKEN_INVALID.getCode() == (int)jsonObject.get("errcode")){
                logger.info("[" + randomNum + "]accessToken失效,重新获取token,再调一次。");
                try {
                    redisAccesssToken = this.getAccessToken();
                } catch (Exception e) {
                    logger.error(e.getMessage(),e);
                    return;
                }
                postUrl = this.uniformMessageIp + "?access_token=" + redisAccesssToken;
                try{
                    //retValue = this.doPost(postUrl,JSON.toJSONString(submitMap));
                    retValue = this.httpsRequest(postUrl,"POST",JSON.toJSONString(submitMap));
                }catch(Exception e){
                    logger.error(e.getMessage(),e);
                    return;
                }
                logger.info("[" + randomNum + "]打印retValue(第二次):{}",retValue);
                //得到返回结果
                jsonObject = JSONObject.parseObject(retValue);
                if(jsonObject.get("errcode") != null && (int)jsonObject.get("errcode") !=0) {
                    logger.warn("[" + randomNum + "]微信小程序接口,发送统一模板消息(第二次)失败,原因:{}", jsonObject.get("errmsg"));
                    return;
                }
                logger.info("[" + randomNum + "]发送服务消息成功(第二次)。");
            }
            return;
        }
        logger.info("[" + randomNum + "]发送服务消息成功。");
    }

    //通用方法,执行请求连接。
    public String httpsRequest(String requestUrl, String requestMethod, String outputStr){
        try {
            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            conn.setRequestMethod(requestMethod);
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            // 当outputStr不为null时向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            conn.disconnect();
            return buffer.toString();
        } catch (ConnectException ce) {
            logger.error("连接超时:{}",ce);
        } catch (Exception e) {
            logger.error("https请求异常:{}",e);
        }
        return null;
    }

方法httpsRequest参考了:https://blog.csdn.net/wave_zf/article/details/82463715

UniformMsg.java:

import com.alibaba.fastjson.JSONObject;

/**
 * 微信小程序统一发送模板消息对象
 * @author XXXX
 * @date 2019年3月1日 18:14:15
 */
public class UniformMsg {

    /**
     * 微信小程序模板ID
     */
    private String template_id;

    /**
     * 微信用户绑定的小程序openid
     */
    private String touser;

    /**
     * 跳转至小程序的页面路径
     */
    private String page;

    /**
     * 表单提交场景下,为 submit 事件带上的 formId
     */
    private String form_id;

    /**
     * 模板需要放大的关键词,不填则默认无放大
     */
    private String emphasis_keyword;

    private JSONObject weapp_template_msg = new JSONObject();

    private JSONObject data = new JSONObject();

    public String getTemplate_id() {
        return template_id;
    }

    public void setTemplate_id(String template_id) {
        this.template_id = template_id;
    }

    public String getTouser() {
        return touser;
    }

    public void setTouser(String touser) {
        this.touser = touser;
    }

    public String getPage() {
        return page;
    }

    public void setPage(String page) {
        this.page = page;
    }

    public String getForm_id() {
        return form_id;
    }

    public void setForm_id(String form_id) {
        this.form_id = form_id;
    }

    public String getEmphasis_keyword() {
        return emphasis_keyword;
    }

    public void setEmphasis_keyword(String emphasis_keyword) {
        this.emphasis_keyword = emphasis_keyword;
    }

    public JSONObject getData() {
        return data;
    }

    public void setData(JSONObject data) {
        this.data = data;
    }

    public JSONObject getWeapp_template_msg() {
        return weapp_template_msg;
    }

    public void setWeapp_template_msg(JSONObject weapp_template_msg) {
        this.weapp_template_msg = weapp_template_msg;
    }
}

restful工具测试:

 

request body json结构:

{
    "touser" : "oZaHr4iznKdHEjGremZZfvPS3X3k",
    "weapp_template_msg" : {
        "data":{
            "keyword1":{
                "value":"娄底建材工程有限公司"
            },
            "keyword2":{
                "value":"2019-02"
            }
        },
        "template_id":"mfFyTYNfYJhEOKxbW5hPSYOvlhcztM3qoclq6SHJ04s",
        "form_id" : "70aff62c35a64ece84a281797cad095f",
        "page" : "pages/order/statementAccount"
    }
}

 

微信接收效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值