• 【公众号开发】图像文字识别 · 模板消息推送 · 素材管理 · 带参数二维码的生成与事件的处理


    公众号开发】(4)

    在这里插入图片描述

    【公众号开发】(4)

    1. 图像文字识别功能

    我们的需求就是

    实现读取图片文本信息

    在这里插入图片描述

    实现原理:

    在这里插入图片描述

    发送图片给公众号,开发者服务器会收到这个消息:

    A

    包含图片url:

    1.1 百度AI图像文字识别接口申请

    我们当然很难自己去实现一个图片识别功能,我们要借助强大的已有接口:

    在这里插入图片描述

    我们现在要实现的功能是图片的文字识别功能,首先我们在百度搜索一下“百度AI”:

    在这里插入图片描述

    百度AI开放平台给我们提供了很多人工智能相关的接口让我们去直接使用

    在这里插入图片描述

    登录一下(顺便实名认证):

    在这里插入图片描述

    找到满足我们需求,我们要用到的接口:

    在这里插入图片描述

    在这里插入图片描述

    点击技术文档可以进行学习:文字识别OCR (baidu.com)

    点击立即使用/在控制台前往文字识别:

    在这里插入图片描述

    创建一个应用:

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    我们不经常使用,所以就开通一下,来练习一下,按量计费,购买的话可以访问很久很多次,但是我觉得没啥必要

    在这里插入图片描述

    在列表中查看信息,这些信息等一下我们的程序里是要用到的,有了这些信息,百度才允许你访问接口

    在这里插入图片描述

    1.2 查看文档学习如何调用百度AI

    进入文档:

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    快速入门:

    在里面我们可以查看如何实现这个功能

    1.3 程序开发

    1.3.1 导入依赖:

    Maven Central: Search (sonatype.com)

    在这里插入图片描述

    <dependency>
        <groupId>com.baidu.aipgroupId>
        <artifactId>java-sdkartifactId>
        <version>4.16.16version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    tips:版本冲突运行不了的话,可以这样排除

    在这里插入图片描述

    <exclusions>
       <exclusion>
          <groupId>org.slf4jgroupId>
          <artifactId>slf4j-apiartifactId>
       exclusion>
       <exclusion>
          <groupId>org.slf4jgroupId>
          <artifactId>slf4j-simpleartifactId>
       exclusion>
    exclusions>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1.3.2 公众号发来post请求格式

    基础消息能力 / 接收普通消息 (qq.com)

    在这里插入图片描述

    在这里插入图片描述

    1.3.3 对image类型的消息做好分支处理

    在这里插入图片描述

    1.3.4 访问百度AI的必要参数配置

    在这里插入图片描述

    public class ImageUtils {
        //设置APPID/AK/SK
        public static final String APP_ID = "你的 App ID";
        public static final String API_KEY = "你的 Api Key";
        public static final String SECRET_KEY = "你的 Secret Key";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1.3.5 访问百度AI(根据文档写就完事了)

    在这里插入图片描述

    响应json的格式:

    在这里插入图片描述

    把word_result读出来就行了(其他两个一个记录id,一个结果数)

    public static String getImageText(String picUrl) {
        // 初始化一个AipOcr
        AipOcr client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
        System.out.println(picUrl);
        // 调用接口
        JSONObject jsonObject = client.webImageUrl(picUrl, new HashMap<String, String>());
        // 解析json字符串
        Map<String, Object> map = JsonUtils.jsonToMap(jsonObject.toString());
        // 获取单词集
        List<Map<String, Object>> wordsResult = (List<Map<String, Object>>) map.get("words_result");
        if(wordsResult == null || wordsResult.size() == 0) {
            return "";
        }
        List<String> words = new ArrayList<>();
        for(Map<String, Object> m : wordsResult) {
            words.add((String) m.get("words"));
        }
        System.out.println(words);
        // 返回识别结果
        return words.toString();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    1.3.6 封装回复消息
    private String handleImage(Map<String, Object> map) {
        String picUrl = (String) map.get("PicUrl");
        String content = ImageUtils.getImageText(picUrl);
        map.put("Content", content);
        TextMessage textMessage = TextMessage.getReplyTextMessage(map);
        String message = XmlUtils.objectToXml(textMessage);
        return message;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1.3.7 测试

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    成功啦😊~

    补充,之前我们做的上拉菜单,点击里面的发送图片按钮,发送的并不是事件类型的消息:

    1. 点击它弹出子菜单:选择拍照或者相册选择
    2. 反正选择图片确认后,都相当于发送了图片类型的消息

    这个只是示例,其他的自行研究,举一反三~

    试玩了之后,把那个服务终止了,少花点钱🤭

    2. 模板消息

    在我们可以获得Access Token后就可以使用模板消息了

    文档:基础消息能力 / 模板消息接口 (qq.com)

    这个是公众号主动的向用户发送重要的消息

    例如这种,就是模板消息

    在这里插入图片描述

    使用规则也要注意:

    在这里插入图片描述

    2.1 设置所属的行业

    我们要想实现这个模板消息的发送的话,就要先设置所属的行业

    在这里插入图片描述

    参数:

    • id1与id2,可以理解为主业和副业

    在这里插入图片描述

    行业编码可以在文档里查找:

    在这里插入图片描述

    public class TextModelMessage {
    
        public static void setTradeInfo() {
            String url = "https://api.weixin.qq.com/cgi-bin/template/api_set_industry" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
                this.put("access_token", TokenUtils.getToken());
            }});
            Map<String, Object> param = new HashMap<String, Object>() {{
                this.put("industry_id1", "1");
                this.put("industry_id2", "2");
            }};
            System.out.println(HttpUtils.doPost(url, JsonUtils.objectToJson(param)));
        }
    
    
        public static void main(String[] args) {
            setTradeInfo();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    结果:

    在这里插入图片描述

    🆗啦😊~

    2.2 获取设置的行业消息

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    公众号开发这么久了,套路都差不多~

    public static String getTradeInfo() {
        String url = "https://api.weixin.qq.com/cgi-bin/template/get_industry" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
            this.put("access_token", TokenUtils.getToken());
        }});
        return HttpUtils.doGet(url, null);
    }
    
    
    public static void main(String[] args) {
        //setTradeInfo();
        System.out.println(getTradeInfo());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    信息获取正确:

    在这里插入图片描述

    2.3 发送模板消息

    2.3.1 获得模板id

    首先我们要先获取模板id

    在我们的测试公众平台界面,有这个模板消息接口:

    在这里插入图片描述

    新增测试模板:

    在这里插入图片描述

    模板消息运营规范:

    基础消息能力 / 模板消息运营规范 (qq.com)

    目前允许发的模板消息示例:

    模板

    以一个很常见的为例子:

    在这里插入图片描述

    填入模板信息:

    在这里插入图片描述

    复制模板ID

    在这里插入图片描述

    这里测试公众号阶段,直接这样获取模板id(此模板也只在此阶段能用),之后需要通过请求的方式获取,再回头来学!

    包括获取模板列表,删除模板,等等这些动作感兴趣的同学可以去研究一下,之后需要用到回头再学!

    2.3.2 访问接口发送模板消息

    在这里插入图片描述

    data属性的值对象的各个 属性就是刚才的模板内容中的xxx.DATA

    在这里插入图片描述

    更详细的json字符串示例:

    在这里插入图片描述

    可见,first和remark也在其中,并且属性值不仅有value(String)这个属性,还有color(String),也就是表现颜色(#六位十六进制的格式)

    json字符串各个参数的介绍:

    在这里插入图片描述

    openid就是微信用户的id,这个用户肯定做了些事情我们才发模板消息给他,我们肯定有记录他的标识,也就是openid~

    在这里插入图片描述

    • 也就是这里的“微信号”
    • 之后我们可以从数据库或者其他手段,也能获取到openid的,那个时候再说

    小程序相关的和防止重入的这里不考虑(小程序不填了的话,其appid虽然必填,也因为miniprogram不填而不需要填写,pagepath也不需要)

    返回码,简单了解即可

    在这里插入图片描述

    public static void sendModelMessage() {
        String url = "https://api.weixin.qq.com/cgi-bin/message/template/send" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
            this.put("access_token", TokenUtils.getToken());
        }});
    
        String data =
            "{" +
            "    \"first\":{\n" +
            "         \"value\":\"你好,你申请参加活动报名成功。\",\n" +
            "         \"color\":\"#101010\"" +
            "     },\n" +
            "     \"keyword1\":{\n" +
            "         \"value\":\"张三\",\n" +
            "         \"color\":\"#101010\"" +
            "     },\n" +
            "     \"keyword2\":{\n" +
            "         \"value\":\"13333333333\"\n" +
            "     },\n" +
            "     \"keyword3\": {\n" +
            "         \"value\":\"2023-10-21 17:43\"\n" +
            "     },\n" +
            "     \"keyword4\": {\n" +
            "         \"value\":\"你选择的是足球队员\"\n" +
            "     },\n" +
            "     \"remark\": {\n" +
            "         \"value\":\"感谢您 的使用,祝你生活愉快!\",\n" +
            "         \"color\":\"#FF0000\"" +
            "     }" +
            "}";
        Map<String, Object> param = new HashMap<String, Object>() {{
            this.put("touser", "otfI46nw4BoHVoOjivoWmEamB494");
            this.put("template_id", "jDrr4sGQBOgI7uTliXajxbaTTXMxhf2RzTXlwq3DBWY");
            this.put("url", "https://blog.csdn.net/Carefree_State?type=blog");
            this.put("data", JsonUtils.jsonToMap(data));
        }};
        // 发送请求
        System.out.println(HttpUtils.doPost(url, JsonUtils.objectToJson(param)));
    }
    
    
    public static void main(String[] args) {
        //setTradeInfo();
        //System.out.println(getTradeInfo());
        sendModelMessage();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    效果:

    在这里插入图片描述

    为什么不显示首行内容、尾部/备注内容、颜色?

    在这里插入图片描述

    可能是很多违规案例的出现导致的(诈骗、营销、骚扰用户等等不良行为)

    点此查看违规案例

    这里的data,我直接偷懒给个写死了的~

    • 之后我们只需要自己将我们的模板,封装成对象,再动态地获取和设置数据进去就行了

    3. 素材管理

    素材管理 / 新增临时素材 (qq.com)

    有时候,我们需要将一些素材上传到公众号内进行缓存,所以我们需要学习一些素材管理的内容

    在这里插入图片描述

    差不多就这样吧,之后就是向公众号服务器发送请求

    3.1 上传文件资源方法

    这个方法比较万能,可以解决上传资源的各个文件问题,但是文件要满足限制!

    //httpClient发送携带⽂件的post请求
    public static String doPostByFile(String url, Map<String,
            Object> map, String localFile, String fileParamName) {
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 把⽂件转换成流对象FileBody
            FileBody bin = new FileBody(new File(localFile));
            MultipartEntityBuilder builder =
                    MultipartEntityBuilder.create();
            builder.addPart(fileParamName, bin);
            if (map != null) {
                for (String key : map.keySet()) {
                    builder.addPart(key,
                            new StringBody((String) map.get(key),
                                    ContentType.create("text/plain", Consts.UTF_8)));
                }
            }
            HttpEntity reqEntity = builder.build();
            httpPost.setEntity(reqEntity);
            // 发起请求 并返回请求的响应
            response = httpClient.execute(httpPost, HttpClientContext.create());
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null)
                    response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
            return resultString;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    需要的依赖:

    
    <dependency>
        <groupId>org.apache.httpcomponentsgroupId>
        <artifactId>httpclientartifactId>
        <version>4.5.2version>
    dependency>
    
    <dependency>
        <groupId>org.apache.httpcomponentsgroupId>
        <artifactId>httpclient-cacheartifactId>
        <version>4.5version>
    dependency>
    
    <dependency>
        <groupId>org.apache.httpcomponentsgroupId>
        <artifactId>httpmimeartifactId>
        <version>4.3.2version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    3.2 发送临时素材

    这里以发送图片为例,其他参考文档!

    在这里插入图片描述

    在这里插入图片描述

    public static String sendImage() {
    
        // 构造url
        String url = "https://api.weixin.qq.com/cgi-bin/media/upload" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
            this.put("access_token", TokenUtils.getToken());
            this.put("type", "image");
        }});
        // 发起请求
        String response = HttpUtils.doPostByFile(url, null, "D:/马图/瞪眼.jpg", "");
        System.out.println(response);
        return (String) JsonUtils.jsonToMap(response).get("media_id");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    测试:

    public static void main(String[] args) {
        System.out.println(sendImage());
    }
    
    • 1
    • 2
    • 3

    成功了😊:

    在这里插入图片描述

    • 这个就是临时的media_id(所有资源统一的字段)

    3.3 获得临时素材

    这里以发送图片为例,其他参考文档!

    在这里插入图片描述

    通过身份标识和media_id确认对于的临时资源

    在这里插入图片描述
    在这里插入图片描述

    对于非视频消息素材,返回的就是素材的二进制序列!

    • 在浏览器访问的话,会触发文件下载
    public static String getImage(String mediaId) {
        // 构造url
        String url = "https://api.weixin.qq.com/cgi-bin/media/get" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
            this.put("access_token", TokenUtils.getToken());
            this.put("media_id", mediaId);
        }});
        System.out.println(url);
        return HttpUtils.doGet(url, null);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    测试:

    public static void main(String[] args) {
        String ret = getImage(sendImage());
    }
    
    • 1
    • 2
    • 3

    成功啦😊:

    在这里插入图片描述

    访问一下这个链接:

    • 触发下载了

    在这里插入图片描述

    打开后,就是刚才我们发的文件:

    在这里插入图片描述

    4. 二维码的生成与获取信息

    账号管理 / 生成带参数的二维码 (qq.com)

    这里生成带参数的二维码,扫二维码后是跳转到公众号,是公众号的宣传手段之一

    带的参数有这些:

    在这里插入图片描述

    二维码分为四类:

    1. QR_SCENE为 临时的整型参数值
    2. QR_STR_SCENE为 临时的字符串参数值
    3. QR_LIMIT_SCENE为 永久的整型参数值
    4. QR_LIMIT_STR_SCENE为 永久的字符串参数值

    在这里插入图片描述

    4.1 生成带参数二维码

    在这里插入图片描述

    在这里插入图片描述

    反正就字面意思,我这里就不封装对象,直接写死一个data:

        public static String createTicket() {
            String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
                this.put("access_token", TokenUtils.getToken());
            }});
            //生成临时二维码的数据
    //        Map param = new HashMap(){{
    //
    //        }};
            String data = "{\"expire_seconds\": 3600, \"action_name\": \"QR_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": \"test\"}}";
            // 发送请求
            String ret = HttpUtils.doPost(url, data);
            System.out.println(ret);
            return (String) JsonUtils.jsonToMap(ret).get("ticket");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    测试:

    public static void main(String[] args) {
        System.out.println(createTicket());
    }
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    4.2 获取二维码

    这里就不需要access_token了,毕竟这个二维码要拿去宣传的

    public static String getTicket() {
        String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
            this.put("ticket", createTicket());
        }});
        //System.out.println(HttpUtils.doGet(url, null));
        return url;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试:

    public static void main(String[] args) {
        System.out.println(getTicket());
    }
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    在这里插入图片描述

    访问成功!

    4.3 分支处理扫描二维码触发的事件

    在这里插入图片描述

    基础消息能力 / 接收事件推送 (qq.com)

    如果未关注,扫码后进入公众号简介界面(可选择关注),关注后触发的事件类型为:

    在这里插入图片描述

    如果已关注,扫码后就直接触发的事件类型为:

    在这里插入图片描述

    对于EventKey,就是二维码所带参数相关,可进一步做分支,这里不做演示!

    编写代码处理事件:

    在这里插入图片描述

    private String handleEvent(Map<String, Object> map) {
        String message = "";
        // 获取event值
        String event = (String) map.get("Event");
        // 事件分支
        switch (event) {
            case "CLICK":
                message = EventUtils.handleClick(map);
                break;
            case "VIEW":
                System.out.println("view");
                break;
            case "SCAN":
                message = EventUtils.handleScan(map);
                break;
            case "subscribe":
                message = EventUtils.handleSubscribe(map);
                break;
            default:
                break;
        }
        return message;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    handleScan方法:

    public static String handleScan(Map<String, Object> map) {
        map.put("Content", "欢迎光临! " + map.get("FromUserName"));
        TextMessage textMessage = TextMessage.getReplyTextMessage(map);
        return XmlUtils.objectToXml(textMessage);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    handleSubscribe方法:

    public static String handleSubscribe(Map<String, Object> map) {
        map.put("Content", "感谢关注!  " + map.get("FromUserName"));
        TextMessage textMessage = TextMessage.getReplyTextMessage(map);
        return XmlUtils.objectToXml(textMessage);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    测试:

    关注状态下扫码:

    在这里插入图片描述

    非关注状态下扫码:

    在这里插入图片描述


    文章到此结束!谢谢观看
    可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆

    代码:wx-demo · 游离态/马拉圈2023年10月 - 码云 - 开源中国 (gitee.com)


  • 相关阅读:
    【AGC】调测应用内消息服务的收不到弹窗的问题
    LeetCode 131 Java 实现
    安全事件报告和处置制度
    WEB 渗透之CSRF
    [区块链go]windows系统中安装Go与环境变量配置
    安卓app源码和设计报告——简易记账本
    第十一周周报
    Qt-FFmpeg开发-视频播放(4)
    【面试精讲】Java:String、StringBuffer、StringBuilder有什么区别?
    kubernetes(5)Controller的一些核心概念
  • 原文地址:https://blog.csdn.net/Carefree_State/article/details/133967182