微信相关开发

微信公众平台开发概述 | 微信开放文档

公众号:公众号通俗说的是服务号、订阅号

微信公众平台一共有4种类型账号接入类型:服务号、订阅号、小程序、企业微信四种类型

微信小程序:用户体验上,存在很大的差别。小程序更像App,,因为小程序,也是基于H5框架开发,所以很多接口都是可以通用的。但小程序在用户体验和使用效率上更高。小程序只能使用微信官方提供的工具进行开发

微信订阅号和服务号:其实就是移动端网站。但是两者可实现的功能,基本上差不多,而微信订阅号和服务号可以使用任何开发工具进行开发

服务号与订阅号的区别如下:

服务号,旨在为用户提供服务;订阅号,旨在为用户提供信息。

服务号1个月内仅可以发送4条群发消息;订阅号每天可以发送1条群发消息。

服务号发给粉丝的消息,会显示在对方的聊天列表中,相对应微信的首页;订阅号发给粉丝的消息,将会显示在对方的“订阅号”文件夹中,点击两次才可以打开。

服务号认证成功后可以建立微信商城,进行微信支付功能 ; 订阅号无论认证与否都不能进行微信支付。

服务号无论是否认证都会有自定义菜单功能 ; 订阅号完成认证才有自定义菜单功能。

服务号支持多个客服后台在线与粉丝们进行及时交流,适合粉丝关注较多的公众号; 订阅号不支持多客服服务,适合粉丝关注少的公众号。

一、微信服务号流程:

1:首先注册一个服务号,并设置密钥等,通过设置的token校验接口校验

2:注意点:

1:token获取需要配置当前电脑的公网的白名单,否则无法获取token

2:发送模板消息的格式需要注意

3:验签和接受消息是同一个接口,路径相同,只是请求类型不同!验签是get,接受消息是post

@CrossOrigin
@RestController
@RequestMapping("/wx")
@Slf4j
public class SubscribeNoticeController {
    @Autowired
    ISubscribeNoticeService subscribeNoticeService;

    /**
     * token 验签
     * @GetMapping 和 @PostMapping 路径名称是一样的,一个用来验证token、一个用来接收数据
     */
    @GetMapping("/notice")
    Long checkSignature(@RequestParam("signature") String signature,
                     @RequestParam("timestamp") String timestamp,
                     @RequestParam("nonce") String nonce,
                     @RequestParam("echostr") String echostr){

        return subscribeNoticeService.checkSignature(signature, timestamp, nonce, echostr);
    }

    /**
     * 接收推送的数据
     */
    @PostMapping("/notice")
    @ResponseBody
    public String acceptMessage(HttpServletRequest request) throws Exception {
        try {
            return subscribeNoticeService.acceptMessage(request);
        } catch (Exception e) {
            log.info(e.getMessage(),e);
            throw new RuntimeException(e);
        }
    }
    /**
     * 创建微信公众号菜单,只需要调用一次即可,多次也不会出问题
     */
    @PostMapping("/create/ws/menu")
    public Boolean createWSMenu() {
        return subscribeNoticeService.addMenu();
    }
    /**
    *@Description: 测试模板消息发送
    *@Author: yangfengfan
    *@Param:
    *@Return:
    *@Date: 2022/11/8 9:13
    **/
    @PostMapping("/message")
    public void message() {
        log.info("进入发送模板消息接口");
        subscribeNoticeService.cycleSendMessage();
    }
package com.haiyang.oceansite.mrv.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.haiyang.oceansite.mrv.api.RemoteWSService;
import com.haiyang.oceansite.mrv.entity.MrvConfig;
import com.haiyang.oceansite.mrv.entity.MrvNoonPaper;
import com.haiyang.oceansite.mrv.service.IMrvConfigService;
import com.haiyang.oceansite.mrv.service.IMrvNoonPaperService;
import com.haiyang.oceansite.mrv.service.ISubscribeNoticeService;
import com.haiyang.oceansite.mrv.vo.WSCustomMenu;
import com.haiyang.oceansite.mrv.vo.WSMenu;
import com.haiyang.oceansite.mrv.vo.WSTagInfo;
import com.haiyang.oceansite.mrv.vo.WSTags;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

@Service
@Slf4j
public class SubscribeNoticeServiceImpl implements ISubscribeNoticeService {
    //注意:标签name就是IMO!
    @Autowired
    RemoteWSService remoteWSService;
    @Autowired
    IMrvConfigService iMrvConfigService;
    @Autowired
    IMrvNoonPaperService iMrvNoonPaperService;
    /**
    *@Description: 验签token
    *@Author: yangfengfan
    *@Param:
    *@Return:
    *@Date: 2022/11/3 18:09
    **/
    @Override
    public Long checkSignature(String signature,String timestamp,String nonce,String echostr) {
        String token = "haiyang1304";
        String[] arr = {token, timestamp, nonce};
        Arrays.sort(arr);

        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        //sha1Hex 加密
        MessageDigest md = null;
        String temp = null;
        try {
            md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(content.toString().getBytes());
            temp = this.byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        if ((temp.toLowerCase()).equals(signature)){
            //重点:要把接收的这个随机码返回
            return Long.valueOf(echostr);
        }
        return null;
    }

    @Override
    public String acceptMessage(HttpServletRequest request) throws IOException {
        BufferedReader br = request.getReader();
        String str;
        String paramInfo = "";
        Map<String, Object> XMLmap = null;
        while ((str = br.readLine()) != null) {
            paramInfo += str;
        }
        if (StrUtil.isNotBlank(paramInfo)) {
            XMLmap = XmlUtil.xmlToMap(paramInfo);
        }
        log.info("微信公众号接收信息:{}", XMLmap);
        String userOpenId = (String) XMLmap.get("FromUserName");
        // 微信账号
        String userName = (String) XMLmap.get("ToUserName");
        // 事件
        String event = (String) XMLmap.get("Event");
        // 区分消息类型
        String msgType = (String) XMLmap.get("MsgType");
        // 判断消息体
        String msgInfo = (String) XMLmap.get("Content");
        // 点击的消息key
        String EventKey = (String) XMLmap.get("EventKey");
        // 模板消息发送后的状态
        String flag = (String) XMLmap.get("Status");
        // 微信返回消息xml中的content
        String content = null;
        //登录获取token
        String token = this.getToken();
        //输入文字触发
        if ("text".equals(msgType)) {
            //输入绑定的imo号
            if (this.checkIMO(msgInfo)) {
                //获取所有的标签列表,标签已存在就不创建,不存在就创建并指定
                String tagsStr = remoteWSService.getTags(token);
                WSTags wsTags = JSON.parseObject(tagsStr).toJavaObject(WSTags.class);
                List<WSTagInfo> tagsList = wsTags.getTags();
                StringBuilder imos = new StringBuilder("");
                String[] imoArray = msgInfo.trim().split(",");
                for (WSTagInfo wsTagInfo : tagsList) {
                    String imo = wsTagInfo.getName();
                    imos.append(imo).append(",");
                    for (String imoBanding : imoArray) {
                        if (imo.equals(imoBanding)){
                            //如果公众号中已有的标签和用户输入要绑定的标签有相同时,则不用创建标签,直接绑定即可
                            Integer id = wsTagInfo.getId();
                            HashMap<String, Object> stringObjectHashMap = new HashMap<>();
                            ArrayList<String> stringsList = new ArrayList<>();
                            stringsList.add(userOpenId);
                            stringObjectHashMap.put("openid_list",stringsList);
                            stringObjectHashMap.put("tagid",id);
                            remoteWSService.setUsersTag(token,stringObjectHashMap);
                        }
                    }
                }
                for (String imoBanding : imoArray){
                    //如果公众号中已存在的标签不包含用户输入的的标签时
                    if (!imos.toString().contains(imoBanding)){
                        HashMap<String, Object> data = new HashMap<>();
                        HashMap<String, String> stringStringHashMap = new HashMap<>();
                        stringStringHashMap.put("name",imoBanding);
                        data.put("tag",stringStringHashMap);
                        //创建标签,获取返回的标签id
                        String tagMap = remoteWSService.setUserTag(token, data);
                        JSONObject jsonObject = JSON.parseObject(tagMap);
                        Map map = jsonObject.toJavaObject(Map.class);
                        Map<String,Integer> tag = (Map<String, Integer>) map.get("tag");
                        Integer id = tag.get("id");
                        //绑定
                        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
                        ArrayList<String> stringsList = new ArrayList<>();
                        stringsList.add(userOpenId);
                        stringObjectHashMap.put("openid_list",stringsList);
                        stringObjectHashMap.put("tagid",id);
                        remoteWSService.setUsersTag(token,stringObjectHashMap);
                    }
                }
                return this.getMassage(userOpenId, userName,"您已成功绑定船舶IMO:"+msgInfo);
            }else {
                return this.getMassage(userOpenId, userName,"公众号正在学习您的指令,提示:绑定的IMO号是7位数,输入必须符合规范");
            }
        }

        //事件触发
        if ("event".equals(msgType)) {
            String message = null;
            if ("TEMPLATESENDJOBFINISH".equals(event)){
                if (flag.equals("success")){
                    log.info("模板消息发送成功");
                }else {
                    log.info("模板消息发送失败");
                }
                return null;
            }
            //点击午报触发
            if (EventKey.equals("noonPaper")) {
                ArrayList<String> imoNames = new ArrayList<>();
                //获取用户的标签列表
                List<Integer> tagidList = this.bandingIMO(token, userOpenId, userName);
                if (tagidList.size() == 0) {     //没有绑定IMO标签则不能获取午报
                    return this.getMassage(userOpenId, userName, "抱歉,未绑定IMO号不能获取午报,请先绑定IMO号");
                } else {
                    //获取公众号已创建的所有标签
                    String tagsStr = remoteWSService.getTags(token);
                    WSTags wsTags = JSON.parseObject(tagsStr).toJavaObject(WSTags.class);
                    List<WSTagInfo> tagsList = wsTags.getTags();
                    for (WSTagInfo wsTagInfo : tagsList) {
                        for (Integer tagid : tagidList) {
                            if (wsTagInfo.getId().equals(tagid)) {
                                String imoName = wsTagInfo.getName();
                                imoNames.add(imoName);
                            }
                        }
                    }
                    //发送午报
                    for (String imoName : imoNames) {
                        QueryWrapper<MrvConfig> qw = new QueryWrapper();
                        qw.eq("config_key", "wx");
                        MrvConfig mrvConfig = iMrvConfigService.getOne(qw);
                        if (ObjectUtil.isEmpty(mrvConfig)) {
                            content = "请先设置OCEANSITE系统的微信午报模板";
                        } else {
                            String jsonStr = mrvConfig.getConfigValue();
                            //查询imo并选择最近一条发送
                            QueryWrapper<MrvNoonPaper> queryWrapper = new QueryWrapper();
                            queryWrapper.eq("ship_imo", imoName);
                            queryWrapper.orderByDesc("create_time");
                            queryWrapper.last("limit 1");
                            MrvNoonPaper mrvNoonReport = iMrvNoonPaperService.getOne(queryWrapper);
                            if (ObjectUtil.isEmpty(mrvNoonReport)) {
                                content = "系统未找到午报信息,请先填写午报";
                            } else {
                                JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(mrvNoonReport));
                                Map map1 = JSON.toJavaObject(jsonObject, Map.class);
                                List<String> lisStr = JSONArray.parseArray(jsonStr, String.class);
                                for (String s : lisStr) {
                                    for (Object o : map1.keySet()) {
                                        if (StrUtil.contains(s, "$" + o + "$")) {
                                            s = StrUtil.replace(s, "$" + o + "$", map1.get(o) + "", true);
                                        }
                                    }
                                    content = StrUtil.concat(true, content, s, "&#x000A;");
                                }
                            }
                        }
                        return this.getMassage(userOpenId, userName,content);
                    }
                }
            }
            //点击绑定xxx触发
            if (EventKey.equals("binding")){
                message = "";
            }
            //点击联系我们
            if (EventKey.equals("contact")){
                message = "xxxx";
            }
            //订阅
            if ("subscribe".equals(event)) {
                message = "谢谢您的关注";
            }
            //取消订阅
            if ("unsubscribe".equals(event)) {
                message = "很遗憾,您已取消关注!";
            }
            return this.getMassage(userOpenId, userName,message);
        }
        return this.getMassage(userOpenId, userName,"公众号正在学习您的指令,抱歉");
    }


    /**
     * 添加菜单
     */
    @Override
    public boolean addMenu(){
        String access_token = this.getToken();
        log.info("token:" + access_token);
        //新增2个菜单按钮
        WSMenu wsMenu = new WSMenu();
        WSCustomMenu customMenu1 = new WSCustomMenu();
        customMenu1.setKey("binding");
        customMenu1.setName("绑定IMO");
        customMenu1.setType("click");
        WSCustomMenu customMenu2 = new WSCustomMenu();
        customMenu2.setKey("noonPaper");
        customMenu2.setName("午报");
        customMenu2.setType("click");
        WSCustomMenu customMenu3 = new WSCustomMenu();
        customMenu3.setKey("contact");
        customMenu3.setName("联系我们");
        customMenu3.setType("click");
        ArrayList<WSCustomMenu> WSCustomMenus = new ArrayList<>();
        WSCustomMenus.add(customMenu1);
        WSCustomMenus.add(customMenu2);
        WSCustomMenus.add(customMenu3);
        wsMenu.setButton(WSCustomMenus);
        log.info(JSON.toJSONString(wsMenu));
        remoteWSService.createMenu(access_token,wsMenu);
        return true;
    }

    public String getToken(){
        //获取微信的access_token
        String accessToken = remoteWSService.getAccessToken("client_credential", "wxa0031d230d26e2e0", "3343ac9a40cf2e285fff4d3dda2c7671");
        JSONObject jsonObject = JSON.parseObject(accessToken);
        Map<String,String> map = jsonObject.toJavaObject(Map.class);
        return map.get("access_token");
    }

    public String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        System.err.println("strDigest : "+strDigest);
        return strDigest;
    }
    private String byteToHexStr(byte mByte) {
        char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A','B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4)& 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];
        String s = new String(tempArr);
        return s;
    }

    // 校验imo号,7位数
    public boolean checkIMO (String msgInfo){
        String[] split = msgInfo.split(",");
        for (String s : split) {
            boolean b = s.length() == 7;
            if (!b) {
                return false;
            }
        }
        return true;
    }
    //获取符合格式的消息
    public String getMassage(String userOpenId,String userName,String data){
        //返回的xml消息格式
        String str = "<xml>\n" +
                "  <ToUserName><![CDATA[" + userOpenId + "]]></ToUserName>\n" +
                "  <FromUserName><![CDATA[" + userName + "]]></FromUserName>\n" +
                "  <CreateTime>" + System.currentTimeMillis() + "</CreateTime>\n" +
                "  <MsgType><![CDATA[text]]></MsgType>\n" +
                "  <Content>" + data + "</Content>\n" +
                "</xml>\n";
        log.info("发送的消息格式:" + str);
        return str;
    }

    //每天中午定时发送最新的午报
    //@Scheduled(cron = "30 * * * * ?")  30s触发一次
    //@Scheduled(cron = "0 0 12 * * ?")  每天中午12点触发
    public void cycleSendMessage(){
        String token = this.getToken();
        //获取所有的标签列表
        String tagsStr = remoteWSService.getTags(token);
        WSTags wsTags = JSON.parseObject(tagsStr).toJavaObject(WSTags.class);
        List<WSTagInfo> tagsList = wsTags.getTags();
        for (WSTagInfo wsTagInfo : tagsList) {
            String imo =wsTagInfo.getName();
            //--根据tagId即imo号,查询获取最新午报信息
            QueryWrapper<MrvNoonPaper> queryWrapper = new QueryWrapper();
            queryWrapper.eq("ship_imo", imo);
            queryWrapper.orderByDesc("create_time");
            queryWrapper.last("limit 1");
            MrvNoonPaper mrvNoonReport = iMrvNoonPaperService.getOne(queryWrapper);
            if (ObjectUtil.isEmpty(mrvNoonReport)) {
                //系统没有午报
                log.info("oceansite系统没有该IMO船舶的午报数据,IMO:"+imo);
                continue;
            }
            //--获取该标签下的粉丝,入参标签id
            List<String> openidList = this.getTagUsers(wsTagInfo.getId(), token);
            log.info("获取该标签下的粉丝:"+openidList.toString());

            //--获取模板id(也可以自行进行公众号后台获取模板id)
            //HashMap<String, String> stringObjectHashMap = new HashMap<>();
            //stringObjectHashMap.put("template_id_short", "TM00201");
            //String templateId = remoteWSService.getTemplateId(token, stringObjectHashMap);
            //Map map = JSON.parseObject(templateId).toJavaObject(Map.class);
            //String template_id = (String) map.get("template_id");
            //log.info("模板id:"+template_id);

            //--根据模板发送对应的午报给对应粉丝
            for (String openid : openidList) {
                HashMap<String, Object> templateMessageMap = new HashMap<>();
                templateMessageMap.put("touser",openid);
                templateMessageMap.put("template_id","iyCm1ygyWPEafxY4yHgOHWqwhc5u21z-Qv8OtZ6Iqes"); //模板id
                //templateMessageMap.put("client_msg_id",StrUtil.uuid());防重入id。对于同一个openid + client_msg_id, 只发送一条消息,10分钟有效,超过10分钟不保证效果。若无防重入需求,可不填


                HashMap<String, Object> dataInfoMap = new HashMap<>();
                HashMap<String, String> data1 = new HashMap<>();
                data1.put("value","详细午报数据请进入OceanSite系统查看");
                data1.put("color","#173177");
                dataInfoMap.put("first",data1);
                HashMap<String, String> data2 = new HashMap<>();
                data2.put("value","下一个港口名称:"+mrvNoonReport.getNextPortName()+",当前航次:"+mrvNoonReport.getVoyageNumber());
                data2.put("color","#173177");
                dataInfoMap.put("reason",data2);
                HashMap<String, String> data3 = new HashMap<>();
                data3.put("value", DateUtil.today());
                data3.put("color","#173177");
                dataInfoMap.put("time",data3);
                HashMap<String, String> data4 = new HashMap<>();
                data4.put("value", "感谢您关注");
                data4.put("color","#173177");
                dataInfoMap.put("remark",data4);
                templateMessageMap.put("data",dataInfoMap);
                String s = remoteWSService.sendTemplateMessage(token, templateMessageMap);
                log.info(s);
            }
        }
    }

    //没有绑定IMO不能获取午报,返回用户身上的标签列表
    public List<Integer> bandingIMO(String access_token, String userOpenId, String userName){
        HashMap<String, Object> stringStringHashMap = new HashMap<>();
        stringStringHashMap.put("openid",userOpenId);
        //获取用户身上的标签列表
        String userTagList = remoteWSService.getUserTagList(access_token, stringStringHashMap);
        Map<String,Object> map = JSON.parseObject(userTagList).toJavaObject(Map.class);
        List<Integer> tagid_list = (List<Integer>) map.get("tagid_list");
        return tagid_list;
    }

    public List<String> getTagUsers(Integer tagid,String token){
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        stringObjectHashMap.put("tagid",tagid);
        stringObjectHashMap.put("next_openid","");
        String tagUsers = remoteWSService.getTagUsers(token, stringObjectHashMap);
        Map map = JSON.parseObject(tagUsers).toJavaObject(Map.class);
        Map<String,Object> data = (Map<String,Object>)map.get("data");
        List<String> openidArrayList = (List<String>) data.get("openid");
        return openidArrayList;
    }
}

二、企业微信应用免登录集成流程:

注意:

1、后端构造网页授权链接

2、前端拿到code后,调用后端接口获取token和用户信息(后端调用企业微信获取userid,然后创建token等)

3、前端重定向到新的页面(也可以是构造网页授权链接时的重定向页面)

开始开发 - 接口文档 - 企业微信开发者中心(官网)

企业微信集成应用程序、服务最详细教程_企业微信工作台集成自己web应用-CSDN博客

三、企业微信web登陆集成:

开始开发 - 接口文档 - 企业微信开发者中心(官网)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值