springboot+微信公众号发送模板消息+小程序发送订阅消息

测试号管理:https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

在开发之前需要做的事情:

1.申请一个公众号测试账号,一分钟就可以申请下来   

2.然后需要一个微信验证token的地址,这个大家可以网上找一下 比较简单。

验证token的代码贴一下

package com.cjkj.message.controller;

import com.cjkj.message.utils.SignUtil;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * @program: cjkj
 * @description:
 * @author: Mr.Wang
 * @create: 2020-03-25 17:11
 **/
@Controller
@RequestMapping("/wechat")
public class WechatController {

        private static Logger logger = Logger.getLogger(WechatController.class);

        @RequestMapping(value = "security", method = RequestMethod.GET)
        public void doGet(
                HttpServletRequest request,
                HttpServletResponse response,
                @RequestParam(value = "signature", required = true) String signature,
                @RequestParam(value = "timestamp", required = true) String timestamp,
                @RequestParam(value = "nonce", required = true) String nonce,
                @RequestParam(value = "echostr", required = true) String echostr) {
            try {
                if (SignUtil.checkSignature(signature, timestamp, nonce)) {
                    PrintWriter out = response.getWriter();
                    out.print(echostr);
                    out.close();
                } else {
                    logger.info("这里存在非法请求!");
                }
            } catch (Exception e) {
                logger.error(e, e);
            }
        }

        @RequestMapping(value = "security", method = RequestMethod.POST)
        // post方法用于接收微信服务端消息
        public void DoPost() {
            System.out.println("这是post方法!");
        }
    }

3.token验证成功后,用自己的微信扫描关注公众号。

4.创建一个自定义的模板。

我的模板事这个:

{{first.DATA}} 用户名:{{keyword1.DATA}} 订单号:{{keyword2.DATA}} 订单金额:{{keyword3.DATA}} 商品信息:{{keyword4.DATA}} {{remark.DATA}}

复制粘贴进去就可以了。

 

5.上边的话我们就可以看到appID,appsecret,关注用户的微信号,也就是openid。然后还有自己船舰的模板id(模板ID(用于接口调用))

接下来我们用代码就可以实现了。

我的代码中包含了一些业务代码,大家看的时候跳过。同时我们的appID,appsecret保存在数据库,当调用的时候 ,通过参数appkey去查询到这两个参数。

wechat:
  #获取token的地址
  getTokenUrl: https://api.weixin.qq.com/cgi-bin/token
  #发送公众号消息的地址
  sendMsgUrl: https://api.weixin.qq.com/cgi-bin/message/template/send
  #发送小程序的消息地址
  sendMiniPUrl: https://api.weixin.qq.com/cgi-bin/message/subscribe/send
@RestController
@RequestMapping("/wechat")
public class WechatMessageController {
    private static Logger logger = Logger.getLogger(WechatMessageController.class);
    @Autowired
    private WechatService wechatService;

    /**
     * 公众号发送模板消息
     * @return
     */
    @ApiOperation(value="公众号发送模板消息", notes="根据参数发送模板消息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "WechatTokenEntity", value = "公众号实体", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "data", value = "模板信息参数json结构的字符串", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "miniprogram", value = "小程序参数json结构字符串", required = true, paramType = "query", dataType = "String")
    })
    @RequestMapping(value="/sendMessage" ,method = {RequestMethod.POST})
    public com.cjwl.ResultData sendMessage(HttpServletRequest request, WechatOfficialEntity wechatOfficialEntity, @RequestParam String data, @RequestParam String miniProgram) {
        return wechatService.sendMsg(request, wechatOfficialEntity, data, miniProgram);
}

    /**
     * 小程序发送模板消息
     * @return
     */
    @ApiImplicitParams({
            @ApiImplicitParam(name = "MiniProgramEntity", value = "小程序实体", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "data", value = "发送信息参数json结构的字符串", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "miniprogram", value = "小程序参数json结构字符串", required = true, paramType = "query", dataType = "String")
    })
    @RequestMapping(value="/sendMiniProgramMessage", method = {RequestMethod.POST})
    public com.cjwl.ResultData miniPSendMessage(HttpServletRequest request, WechatMiniProgramEntity wechatMiniProgramEntity, @RequestParam String data) {
        return wechatService.sendMiniProgramMsg(request, wechatMiniProgramEntity, data);
    }

}
/**
 * @program: cjkj
 * @description:
 * @author: Mr.Wang
 * @create: 2020-03-31 00:10
 **/
public interface WechatService {
    public ResultData sendMsg (HttpServletRequest request, WechatOfficialEntity wechatOfficialEntity, String data, String miniprogram);
    public ResultData sendMiniProgramMsg (HttpServletRequest request, WechatMiniProgramEntity wechatMiniProgramEntity, String data);
}

 

@Service
public class WechatServiceImpl implements WechatService {
    private static Logger logger = Logger.getLogger(WechatServiceImpl.class);

    @Autowired
    private ApikeyWechatDao apikeyWechatDao;
    @Value("${wechat.sendMiniPUrl}")
    private String sendMiniPUrl;
    @Value("${wechat.sendMsgUrl}")
    private String sendMsgUrl;
    @Value("${wechat.getTokenUrl}")
    private String getTokenUrl;

    @Override
    public ResultData sendMsg(HttpServletRequest request, WechatOfficialEntity wechatOfficialEntity, String data, String miniprogram) {
        //此处需要更换成appkey  替换appid和appsecret
        if (StringUtils.isNotBlank(wechatOfficialEntity.getApikey())) {
            if (stringRedisUtil.haskey(wechatOfficialEntity.getApikey())) {
                wechatOfficialEntity.setToken(stringRedisUtil.getStrValue(wechatOfficialEntity.getApikey()).toString());
            } else {
                List<ApikeyWechatEntity> apikeyRelationEntities = apikeyWechatDao.listWechatApikeyInfo(wechatOfficialEntity.getApikey(), wechatOfficialEntity.getIdentity());
                String wechatAppKey = apikeyRelationEntities.get(0).getWechatAppKey();
                String wechatSecret = apikeyRelationEntities.get(0).getWechatSecret();
                String token = WechatSendMsgUtil.getToken(wechatAppKey, wechatSecret, getTokenUrl);
                wechatOfficialEntity.setToken(token);
                stringRedisUtil.set(wechatOfficialEntity.getApikey(), token, 7000);//减少延迟带来的误差
            }
        }
        //发送消息
        String result = WechatSendMsgUtil.SendWeChatMsg(wechatOfficialEntity, sendMsgUrl, data, miniprogram);
        logger.info("公众号发送结果:" + result);
        JSONObject jsonResult = JSONObject.parseObject(result);
        String errCode = jsonResult.getString("errcode");
        String errMsg = jsonResult.getString("errmsg");
        try {
            
            final PushMessageEntity pushMessageEntity = getPushMessage(wechatOfficialEntity, data, miniprogram);
          
            
           
        } catch (Exception ex) {
            logger.error("解析IP地址失败!", ex);
            ResultData.build("500", "服务解析错误");
        }
        
        return ResultData.build(errCode, errMsg,null);
    }

    /**
     * 小程序发送消息
     *
     * @param wechatMiniProgramEntity
     * @param data
     * @return
     */
    @Override
    public ResultData sendMiniProgramMsg(HttpServletRequest request, WechatMiniProgramEntity wechatMiniProgramEntity, String data) {
        if (StringUtils.isNotBlank(wechatMiniProgramEntity.getApikey())) {
            if (stringRedisUtil.haskey(wechatMiniProgramEntity.getApikey())) {
                wechatMiniProgramEntity.setToken(stringRedisUtil.getStrValue(wechatMiniProgramEntity.getApikey()).toString());
            } else {
                List<ApikeyWechatEntity> apikeyRelationEntities = apikeyWechatDao.listWechatApikeyInfo(wechatMiniProgramEntity.getApikey(), wechatMiniProgramEntity.getIdentity());
                String wechatAppKey = apikeyRelationEntities.get(0).getWechatAppKey();
                String wechatSecret = apikeyRelationEntities.get(0).getWechatSecret();
                String token = WechatSendMsgUtil.getToken(wechatAppKey, wechatSecret, getTokenUrl);
                wechatMiniProgramEntity.setToken(token);
                stringRedisUtil.set(wechatMiniProgramEntity.getApikey(), token, 7000);
            }
        }
        //发送小程序消息
        String result = WechatSendMsgUtil.sendMiniProgramMsg(wechatMiniProgramEntity, sendMiniPUrl, data);
        logger.info("小程序发送结果:" + result);
        JSONObject jsonResult = JSONObject.parseObject(result);
        String errCode = jsonResult.getString("errcode");
        String errMsg = jsonResult.getString("errmsg");
        try {
            
            PushMessageEntity miniProgramMsg = miniProgramMsg(wechatMiniProgramEntity, data);
            
    

        } catch (Exception ex) {
            logger.error("解析IP地址失败!", ex);
            ResultData.build("500", "服务解析错误");
        }
        
        return ResultData.build(errCode, errMsg,null);
    }

 

/**
 * @program: cjkj
 * @description: 微信公众号发送消息工具类
 * @author: Mr.Wang
 * @create: 2020-03-31 00:40
 **/
public class WechatSendMsgUtil {
    /**
     * 获取token
     *
     * @return token
     */
    public static String getToken(String appid, String secret, String getTokenApi) {
        //授予形式
        String grant_type = "client_credential";
        //接口地址拼接参数
        getTokenApi = getTokenApi + "?grant_type=" + grant_type + "&appid=" + appid + "&secret=" + secret;
        String tokenJsonStr = doGetPost(getTokenApi, "GET", null);
        JSONObject tokenJson = JSONObject.parseObject(tokenJsonStr);
        String token = tokenJson.get("access_token").toString();
        System.out.println("获取到的TOKEN : " + token);
        return token;
    }


    /***
     * 发送公众号消息
     * @param wechatOfficialEntity
     */
    public static String SendWeChatMsg(WechatOfficialEntity wechatOfficialEntity, String sendMsgApi, String data, String miniprogram) {
        //接口地址
        sendMsgApi = sendMsgApi + "?access_token=" + wechatOfficialEntity.getToken();
        //openId
        String toUser = wechatOfficialEntity.getToUser();
        //消息模板ID
        String template_id = wechatOfficialEntity.getTemplateId();
        String toUrl = wechatOfficialEntity.getToUrl();
        //整体参数map
        Map<String, Object> paramMap = new HashMap<String, Object>();
        JSONObject dataJson = JSONObject.parseObject(data);
        Map<String, Object> datamap = dataJson;

        paramMap.put("touser", toUser);
        paramMap.put("template_id", template_id);
        paramMap.put("url", toUrl);
        paramMap.put("miniprogram", miniprogram);
        paramMap.put("data", datamap);
        String result = doGetPost(sendMsgApi, "POST", paramMap);
        return result;
    }

    /**
     * 发送小程序消息
     */

    public static String sendMiniProgramMsg(WechatMiniProgramEntity wechatMiniProgramEntity, String sendUrl, String data) {
        //接口地址
        sendUrl = sendUrl + "?access_token=" + wechatMiniProgramEntity.getToken();
        //openId
        String toUser = wechatMiniProgramEntity.getToUser();
        //消息模板ID
        String template_id = wechatMiniProgramEntity.getTemplateId();
        String page = wechatMiniProgramEntity.getPage();
        String miniprogramState = wechatMiniProgramEntity.getMiniProgramState();
        String lang = wechatMiniProgramEntity.getLang();
        //整体参数map
        Map<String, Object> paramMap = new HashMap<String, Object>();
        JSONObject dataJson = JSONObject.parseObject(data);
        Map<String, Object> datamap = dataJson;

        paramMap.put("touser", toUser);
        paramMap.put("template_id", template_id);
        paramMap.put("page", page);
        paramMap.put("page", page);
        paramMap.put("miniprogram_state", miniprogramState);
        paramMap.put("lang", lang);
        paramMap.put("data", datamap);
        String result = doGetPost(sendUrl, "POST", paramMap);
        return result;
    }

    /**
     * 调用接口 post
     *
     * @param apiPath
     */
    public static String doGetPost(String apiPath, String type, Map<String, Object> paramMap) {

        OutputStreamWriter out = null;
        InputStream is = null;
        String result = null;
        try {
            URL url = new URL(apiPath);// 创建连接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestMethod(type); // 设置请求方式
            connection.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式
            connection.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的格式
            connection.connect();

            if (type.equals("POST")) {
                out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); // utf-8编码
                out.append(JSON.toJSONString(paramMap));
                out.flush();
                out.close();
            }


            // 读取响应
            is = connection.getInputStream();
            int length = (int) connection.getContentLength();// 获取长度
            if (length != -1) {
                byte[] data = new byte[length];
                byte[] temp = new byte[512];
                int readLen = 0;
                int destPos = 0;
                while ((readLen = is.read(temp)) > 0) {
                    System.arraycopy(temp, 0, data, destPos, readLen);
                    destPos += readLen;
                }
                result = new String(data, "UTF-8"); // utf-8编码

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
}

 

/**
 * @program: cjkj
 * @description: 微信公众号实体类
 * @author: Mr.Wang
 * @create: 2020-03-30 16:11
 **/
@Data
public class WechatOfficialEntity implements Serializable {
    /**
     * 服务注册标识
     */
    private String apikey;
    /**
     * 账号唯一标识
     */
    private String identity;
    /**
     * 微信返回的ACCESS_TOKEN
     */
    private String token;
    /**
     * 发送到用户的openid
     */
    private String toUser;
    /**
     * 消息模板id
     */
    private String templateId;
    /**
     * 点击跳转的url
     */
    private String toUrl;
}

 

/**
 * @program: cjkj
 * @description: 小程序实体类
 * @author: Mr.zhang
 * @create: 2020-04-02 15:45
 **/
@Data
public class WechatMiniProgramEntity {
    /**
     * 系统唯一标识
     */
    private String apikey;
    /**
     * 账号唯一标识
     */
    private String identity;

    private String token;
    /**
     * 接收者(用户)的 openid
     */
    private String toUser;
    /**
     * 所需下发的模板消息的id
     */
    private String templateId;
    /**
     * 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。
     * 该字段不填则模板无跳转。
     */
    private String page;
    /**
     * 表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id
     */
    private String formId;
    /**
     * 模板需要放大的关键词
     * 不填则默认无放大
     */
    private String emphasisKeyword;

    /**
     * 进入小程序查看”的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为zh_CN
     */
    private String lang;
    /**
     * 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
     */
    private String miniProgramState;
}

 

公众号调用方式:

地址:/api-message/wechat/sendMessage

参数

含义

数据类型

是否必填

说明

apikey

注册分配的code

String

 

identity

账号唯一标识

String

 

toUser

发送用户的openid

String

 

templateId

模板编号

String

 

url

点击跳转地址

String

 

miniProgram

跳小程序所需数据,不需跳小程序可不用传该数据

String

格式:{"appid":"http://www.baidu.com","pagepath":"231"}

data

模板数据

String

 

 

其中data的数据是json格式的字符串。案例如下:

{
                   "first": {
                       "value":"恭喜你购买成功!"
                   },
                   "keyword1":{
                       "value":"巧克力"
                   },
                   "keyword2": {
                       "value":"39.8"
                   },
                   "keyword3": {
                       "value":"2014922"
                   },
                   "remark":{
                       "value":"欢迎再次购买!",
                    "color":"#173177"                 
}       
}

小程序的调用方式:

地址:/api-message/wechat/sendMiniProgramMessage

参数

含义

数据类型

是否必填

说明

apikey

注册分配的code

String

 

identity

账号唯一标识

String

 

toUser

发送用户的openid

String

 

templateId

模板编号

String

 

page

点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。

String

 

miniProgram

跳小程序所需数据,不需跳小程序可不用传该数据

String

 

data

模板数据

String

模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } }

lang

进入小程序查看”的语言类型

string

 

支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为zh_CN

postman、测试发送公众号 

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值