微信公众号-根据openID给指定用户发送信息

微信公众号-给指定用户发送信息


前言

本篇主要讲解微信公众号中,根据openID向指定用户发送消息。
前置条件是:
①微信公众号已经被认证。
②微信公众号自定义菜单已设置。
③公众号设置->功能设置->JS接口安全域名、网页授权域名。
④已获取到AppId,AppSecret(开发->基本配置->公众号开发信息 中查看)。
⑤ip白名单已设置好(开发->基本配置->公众号开发信息->白名单 中设置)。
⑥服务器配置(开发/基本配置/ 填写服务器配置。本次章中未使用,因为功能简单,采用了链接的方式)
⑦至于根据code换token,加密签名这一些玩意就更多了,还有支付一些坑,mmp不说了

微信的这些东西,做了八百遍每次都有踩不完的坑,官方文档,emm,官方文档算了吧,mmp
鉴于找资料这么费劲, 准备写一下系列文章,从微信配置开始,包括以上全部前置条件、到使用,到服务器配置发布。 因懒取消原计划。
如果有需要的说一下,反正我也不一定写。


一、开通模板消息

看剑,不看箭头,点击开通
在这里插入图片描述

可以从模板库中选择合适的模板,也可以自己添加,我用【工单消息提醒】模板做例子。

{{first.DATA}}
工单编号:{{keyword1.DATA}}
工单标题:{{keyword2.DATA}}
时间:{{keyword3.DATA}}
{{remark.DATA}}
在发送时,需要将内容中的参数({{.DATA}}内为参数)赋值替换为需要的信息

二、项目使用步骤

1.引入库

  1. hutool工具包。
  2. lombok插件自己装。
  3. 阿里巴巴的fastjson。
    代码如下(示例):
<dependency>
   <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>4.5.1</version>
</dependency>

<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>fastjson</artifactId>
   <version>1.2.54</version>
</dependency>

2.直接上代码

controller

	@Autowired
	private WeChatMessageImpl weChatMessage;

	@RequestMapping("/sendMessage")
    public R sendMessage() {
        try {

           WeChatConfig weChatConfig = new WeChatConfig();

            TemplateConfig first =  new TemplateConfig();
            first.setValue("first");
            TemplateConfig k1 =  new TemplateConfig();
            k1.setValue("k1");
            TemplateConfig k2 =  new TemplateConfig();
            k2.setValue("k2");
            TemplateConfig k3 =  new TemplateConfig();
            k3.setValue("k3");
            k3.setColor("#ff3800");//颜色可以不设置,为默认
            TemplateConfig remark =  new TemplateConfig();
            remark.setValue("remarksadfasdf");
            remark.setColor("#ff3800");

            WeChatOrderNoticeVo data = new WeChatOrderNoticeVo();
            data.setFirst(first);
            data.setKeyword1(k1);
            data.setKeyword2(k2);
            data.setKeyword3(k3);
            data.setRemark(remark);


            MessageTemplate<WeChatOrderNoticeVo> template = new MessageTemplate<>();
            template.setTemplate_id("消息模板id");
            template.setTopcolor("#808080");
            template.setTouser("要发送对象的openID");
            template.setUrl("#");
            template.setData(data);

            return weChatMessage.sendMessage(weChatConfig,template);
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("发送失败");

        }
    }

service


import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;


@Service
public class WeChatMessageImpl {
    private static Logger log = LoggerFactory.getLogger(WeChatMessageImpl.class);
    /**
     *  * 发送模板消息
     *  * weChatConfig 微信配置
     *  * MessageTemplate 消息模板
     * @return
     */
    public R sendMessage(WeChatConfig weChatConfig, MessageTemplate<WeChatOrderNoticeVo> wechatOrderNoticeTemplate ) {
        Token token = WeChatUtils.getToken(weChatConfig.getAppId(), weChatConfig.getAppSecret());
        if(null == token || StrUtil.isBlank(token.getAccessToken())){
            return R.fail("获取token失败");
        }
        String access_token = token.getAccessToken();
        String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + access_token;

        String jsonString = JSONObject.toJSONString(wechatOrderNoticeTemplate).replace("day", "Day");
        log.info(jsonString);

        JSONObject jsonObject = WeChatUtils.httpsRequest(url, "POST", jsonString);

        System.out.println(jsonObject);

        if (null != jsonObject) {
            if (StrUtil.isBlank(jsonObject.getString("errcode"))
                    || !StrUtil.equals(jsonObject.getString("errcode"),"0")){
                log.error("错误 errcode:{} errmsg:{}", jsonObject.getInteger("errcode"), jsonObject.getString("errmsg"));
                return R.fail(jsonObject.toString());
            }
        }
        return R.ok(jsonObject);
    }
}

其他一些封装的类

BaseTemplateField
import lombok.Data;

/**
 * @author :socilents
 * @date :Created in 2020/11/4 16:41
 * @description:微信模板基础字段(必填项),这些字段变量的名字不可改变,变了微信接口不认
 */
@Data
public class BaseTemplateField {
    //用户OpenID
    private String touser;
    //模板消息ID
    private String template_id;
    //点击详情后要进入的页面,可为空
    private String url;
    //标题颜色,根据官方文档写的,好像没啥卵用
    private String topcolor;
}
MessageTemplate
import lombok.Data;

/**
 * @author :socilents
 * @date :Created in 2020/11/4 16:39
 * @description:微信发送消息模板封装,
 * 同BaseTemplateField中的字段名称一样,不可以更改字段名称,否则不认
 */
@Data
public class MessageTemplate<T> extends BaseTemplateField {

    private T data;

}
MyX509TrustManager
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * 信任管理器
 *
 */
public class MyX509TrustManager implements X509TrustManager {

    @Override
    public void checkClientTrusted(X509Certificate[] arg0, String arg1)
            throws CertificateException {

    }

    @Override
    public void checkServerTrusted(X509Certificate[] arg0, String arg1)
            throws CertificateException {

    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }

}

TemplateConfig
import lombok.Data;

/**
 * @author :magangming
 * @date :Created in 2020/11/4 16:40
 * @description:微信模板字段设置
 */
@Data
public class TemplateConfig {
    //字段值
    private String value;
    //字体颜色
    private String color;
}

WeChatConfig
import lombok.Data;

/**
 * @author :magangming
 * @date :Created in 2020/11/4 17:07
 * @description:微信公众号的基本配置
 * 根据实际情况使用,这么写是为了方便展示
 */
@Data
public class WeChatConfig {
    private String appId="你的APPID";
    private String appSecret="你的appsecret";

    //为了方便展示写在这里,根据实际情况使用
    private String openId;
    private String templeId;
}

WeChatOrderNoticeVo

import lombok.Data;

/**
 * @author :socilents
 * @date :Created in 2020/11/4 16:51
 * @description:发送消息的封装类,
 * 工单模板内容 微信公众号通知模板
 * 这里我引用了工单消息提醒的模板,记得要在消息模板中添加
 */
@Data
public class WeChatOrderNoticeVo {

    private TemplateConfig first;

    private TemplateConfig keyword1;

    private TemplateConfig keyword2;

    private TemplateConfig keyword3;

    private TemplateConfig remark;
}
WeChatUtils

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.kalvin.kvf.modules.web.entity.Token;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;

/**
 * @author :socilents
 * @date :2020/11/2 17:20
 * @description: 微信公众号指定openID发送消息工具类
 */
public class WeChatUtils {

    private static Logger log = LoggerFactory.getLogger(WeChatUtils.class);

    // 凭证获取(GET)
    public final static String token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

    /**
     * @param requestUrl    请求地址
     * @param requestMethod 请求方式(GET、POST)
     * @param outputStr     提交的数据
     * @return JSONObject(通过 JSONObject.get(key) 的方式获取 JSON 对象的属性值)
     * @description: 发送 https 请求,方法有多种
     */
    public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {

        JSONObject jsonObject = null;

        try {
            // 创建 SSLContext 对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = {new MyX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述 SSLContext 对象中得到 SSLSocketFactory 对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);

            // 设置请求方式(GET/POST)
            conn.setRequestMethod(requestMethod);

            // 当 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();
            inputStream = null;
            conn.disconnect();
            jsonObject = JSONObject.parseObject(buffer.toString());
        } catch (ConnectException ce) {
            log.error(" 连接超时:{}", ce);
        } catch (Exception e) {
            log.error("https 请求异常:{}", e);
        }

        return jsonObject;
    }

    /**
     * @author :socilents
     * @date :2020/11/5 7:59
     * @param appId 凭证
     * @param secret 密钥
     * @description: 获取接口访问凭证
     */
    public static Token getToken(String appId, String secret) {
        Token token = null;
        String requestUrl = token_url.replace("APPID", appId).replace("APPSECRET", secret);
        // 发起GET请求获取凭证
        JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);

        if (null != jsonObject) {
            if (StrUtil.isBlank(jsonObject.getString("errcode"))) {
                try {
                    token = new Token();
                    token.setAccessToken(jsonObject.getString("access_token"));
                    token.setExpiresIn(jsonObject.getInteger("expires_in"));
                    log.info(jsonObject.getString("access_token"));
                } catch (JSONException e) {
                    token = null;
                    // 获取token失败
                    log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInteger("errcode"), jsonObject.getString("errmsg"));
                }
            }else {
                log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInteger("errcode"), jsonObject.getString("errmsg"));
                token = null;
            }

        }
        return token;
    }

}
返回结果R的封装

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import ****************************************.Constants;

import java.io.Serializable;

/**
 * 返回前端 数据封闭类
 */
public class R implements Serializable {

    private static final long serialVersionUID = 1L;

    private Integer code;
    private String msg;
    private Object data;
    private Long total; // 分页信息:总条数

    public R() { }

    private R(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        if (data instanceof Page<?>) {
            Page<?> page = (Page<?>) data;
            this.total = page.getTotal();
            this.data = page.getRecords();
        } else {
            this.data = data;
        }
    }

    public static R ok() {
        return new R(Constants.OK_CODE, Constants.OK_MSG, null);
    }

    public static R ok(Object data) {
        return new R(Constants.OK_CODE, Constants.OK_MSG, data);
    }

    public static R ok(String msg, Object data) {
        return new R(Constants.OK_CODE, msg, data);
    }

    public static R fail(String msg) {
        return new R(Constants.FAIL_CODE, msg, null);
    }

    public static R invalidToken(String msg) {
        return new R(Constants.INVALID_TOKEN_CODE, msg, null);
    }

    public static R fail(int errorCode, String msg) {
        return new R(errorCode, msg, null);
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public Object getData() {
        return data;
    }

    public Long getTotal() {
        return total;
    }

    public R setTotal(Long total) {
        this.total = total;
        return this;
    }
}


Constants
/**
 * 常量类
 */
public class Constants {

    public final static int OK_CODE = 200;
    public final static int FAIL_CODE = 400;
    public final static int OTHER_FAIL_CODE = 333;    // 其它错误
    public final static int INVALID_TOKEN_CODE = 10000;    // 其它错误
    public final static String OK_MSG = "请求成功";
    public final static String FAIL_MSG = "请求失败";
    public final static int STATUS_0 = 0;   // 可用状态
    public final static int STATUS_1 = 1;   // 禁用状态
}

发送成功之后的展示:
在这里插入图片描述

微信官方文档:
https://mp.weixin.qq.com/advanced/tmplmsg?action=faq&token=505847577&lang=zh_CN


总结

wxsb。

  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值