微信公众号Java开发记录(四)自定义菜单、识别图片消息文字

自定义菜单接口可实现多种类型按钮,如下:
click:点击推事件用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互;
view:跳转URL用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的网页URL,可与网页授权获取用户基本信息接口结合,获得用户基本信息。
scancode_push:扫码推事件用户点击按钮后,微信客户端将调起扫一扫工具,完成扫码操作后显示扫描结果(如果是URL,将进入URL),且会将扫码的结果传给开发者,开发者可以下发消息。
scancode_waitmsg:扫码推事件且弹出“消息接收中”提示框用户点击按钮后,微信客户端将调起扫一扫工具,完成扫码操作后,将扫码的结果传给开发者,同时收起扫一扫工具,然后弹出“消息接收中”提示框,随后可能会收到开发者下发的消息。
pic_sysphoto:弹出系统拍照发图用户点击按钮后,微信客户端将调起系统相机,完成拍照操作后,会将拍摄的相片发送给开发者,并推送事件给开发者,同时收起系统相机,随后可能会收到开发者下发的消息。
pic_photo_or_album:弹出拍照或者相册发图用户点击按钮后,微信客户端将弹出选择器供用户选择“拍照”或者“从手机相册选择”。用户选择后即走其他两种流程。
pic_weixin:弹出微信相册发图器用户点击按钮后,微信客户端将调起微信相册,完成选择操作后,将选择的相片发送给开发者的服务器,并推送事件给开发者,同时收起相册,随后可能会收到开发者下发的消息。
location_select:弹出地理位置选择器用户点击按钮后,微信客户端将调起地理位置选择工具,完成选择操作后,将选择的地理位置发送给开发者的服务器,同时收起位置选择工具,随后可能会收到开发者下发的消息。
media_id:下发消息(除文本消息)用户点击media_id类型按钮后,微信服务器会将开发者填写的永久素材id对应的素材下发给用户,永久素材类型可以是图片、音频、视频、图文消息。请注意:永久素材id必须是在“素材管理/新增永久素材”接口上传后获得的合法id。
view_limited:跳转图文消息URL用户点击view_limited类型按钮后,微信客户端将打开开发者在按钮中填写的永久素材id对应的图文消息URL,永久素材类型只支持图文消息。请注意:永久素材id必须是在“素材管理/新增永久素材”接口上传后获得的合法id。​

一、自定义菜单

接口调用请求说明

http请求方式:POST(请使用https协议) https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN

click和view的请求示例

{
“button”:[
{
“type”:“click”,
“name”:“今日歌曲”,
“key”:“V1001_TODAY_MUSIC”
},
{
“name”:“菜单”,
“sub_button”:[
{
“type”:“view”,
“name”:“搜索”,
“url”:“http://www.soso.com/”
},
{
“type”:“miniprogram”,
“name”:“wxa”,
“url”:“http://mp.weixin.qq.com”,
“appid”:“wx286b93c14bbf93aa”,
“pagepath”:“pages/lunar/index”
},
{
“type”:“click”,
“name”:“赞一下我们”,
“key”:“V1001_GOOD”
}]
}]
}

使用对象封装,通过JSONObject.fromObject(button)我们直接将对象转化成josn。

@Data
public class Button {
    
    
    private List<AbstractButton> button =  new ArrayList<>();

}

@Data
public class AbstractButton {
    
    
    private String name;

    public AbstractButton(String name){
    
    
        this.name = name;
    }
}

注意
使用JSONObject jsonObject = JSONObject.fromObject(button);方法需要导入依赖,并不是阿里巴巴的fastjson的方法。

  <!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.4</version>
            <classifier>jdk15</classifier>
        </dependency>

在这里插入图片描述
将AbstractButton类修改为抽象类,其他按钮继承它即可。

@Data
public abstract class AbstractButton {
    
    
    private String name;

    public AbstractButton(String name){
    
    
        this.name = name;
    }
}

新建按钮对象

@Data
public class ClickButten extends AbstractButton {
    
    
    private String type = "click";
    private String key;

    public ClickButten(String name,String key){
    
    
        super(name);
        this.key = key;

    }
}



@Data
public class ViewButton extends AbstractButton {
    
    
    private String type = "view";
    private String url;
    public ViewButton(String name,String url){
    
    
        super(name);
        this.url=url;
    }
}



package com.wx.model.button;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

/**
 * @author :LiuShihao
 * @date :Created in 2020/10/10 10:52 上午
 * @desc :
 *  {
 *             "name": "发图",
 *             "sub_button": [
 *                 {
 *                     "type": "pic_sysphoto",
 *                     "name": "系统拍照发图",
 *                     "key": "rselfmenu_1_0",
 *                    "sub_button": [ ]
 *                  },
 *                 {
 *                     "type": "pic_photo_or_album",
 *                     "name": "拍照或者相册发图",
 *                     "key": "rselfmenu_1_1",
 *                     "sub_button": [ ]
 *                 },
 *                 {
 *                     "type": "pic_weixin",
 *                     "name": "微信相册发图",
 *                     "key": "rselfmenu_1_2",
 *                     "sub_button": [ ]
 *                 }
 *             ]
 *         }
 */
@Data
public class PhotoAlbumButton extends AbstractButton {
    
    
    private String type;
    private String key;
    private List<AbstractButton> sub_button = new ArrayList<>();

    public PhotoAlbumButton(String name,String type,String key){
    
    
        super(name);
        this.key = key;
        this.type = type;
    }


}



@Data
public class SubButton extends AbstractButton {
    
    
    private List<AbstractButton> sub_button = new ArrayList<>();

    public SubButton(String name ){
    
    
        super(name);
    }
}

将对象解析成Json

在这里插入图片描述


     @Test
    public void test2(){
    
    
        Button button = new Button();
        button.getButton().add(new ClickButten("一级菜单_点击","1"));
        button.getButton().add(new ViewButton("一级跳转","http://baidu.com"));
        SubButton subButton = new SubButton("子菜单");
        subButton.getSub_button().add(new PhotoAlbumButton("系统拍照发图","pic_sysphoto","rselfmenu_1_0"));
        subButton.getSub_button().add(new ClickButten("二级菜单_点击","2"));
        subButton.getSub_button().add(new ViewButton("二级跳转","http://news.163.com"));
        button.getButton().add(subButton);
        JSONObject jsonObject = JSONObject.fromObject(button);
        System.out.println(jsonObject);

    }


{
    
    "button":[{
    
    "key":"1","name":"一级菜单_点击","type":"click"},{
    
    "name":"一级跳转","type":"view","url":"http://baidu.com"},{
    
    "name":"子菜单","sub_button":[{
    
    "key":"rselfmenu_1_0","name":"系统拍照发图","sub_button":[],"type":"pic_sysphoto"},{
    
    "key":"2","name":"二级菜单_点击","type":"click"},{
    
    "name":"二级跳转","type":"view","url":"http://news.163.com"}]}]}



{
    
    
    "button":[
        {
    
    
            "key":"1",
            "name":"一级菜单_点击",
            "type":"click"
        },
        {
    
    
            "name":"一级跳转",
            "type":"view",
            "url":"http://baidu.com"
        },
        {
    
    
            "name":"子菜单",
            "sub_button":[
                {
    
    
                    "key":"rselfmenu_1_0",
                    "name":"系统拍照发图",
                    "sub_button":[

                    ],
                    "type":"pic_sysphoto"
                },
                {
    
    
                    "key":"2",
                    "name":"二级菜单_点击",
                    "type":"click"
                },
                {
    
    
                    "name":"二级跳转",
                    "type":"view",
                    "url":"http://news.163.com"
                }
            ]
        }
    ]
}

二、创建自定义菜单

package com.wx.util;

import com.wx.model.button.*;
import com.wx.service.Impl.WXServiceImpl;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author :LiuShihao
 * @date :Created in 2020/10/10 12:32 下午
 * @desc :
 */
public class CreateMenu {
    
    
    @Autowired
    WXServiceImpl wxService;
    public static void main(String[] args) {
    
    
        Button button = new Button();
        button.getButton().add(new ClickButten("一级菜单_点击","1"));
        button.getButton().add(new ViewButton("一级跳转","http://baidu.com"));
        SubButton subButton = new SubButton("子菜单");
        subButton.getSub_button().add(new PhotoAlbumButton("系统拍照发图","pic_sysphoto","rselfmenu_1_0"));
        subButton.getSub_button().add(new ClickButten("二级菜单_点击","2"));
        subButton.getSub_button().add(new ViewButton("二级跳转","http://news.163.com"));
        button.getButton().add(subButton);
        JSONObject jsonObject = JSONObject.fromObject(button);
        System.out.println(jsonObject);
        String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
        String token = WXServiceImpl.getToken();
        url = url.replace("ACCESS_TOKEN",token);
        com.alibaba.fastjson.JSONObject post = CommonUtil.httpsRequest(url, "POST", jsonObject.toString());
        System.out.println("post:"+post);
    }
}

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

处理图片信息(识别图片文字)调用百度AI开放平台的API

当用户发送一个图片时,会发送到微信服务器,我们服务器接收的微信服务器发送过来的xml数据包,进行解析

 /**
     * 处理消息和事件推送
     * @param request
     * @throws IOException
     */
    @PostMapping
    public String method2(HttpServletRequest request) throws IOException {
    
    

        Map<String,String> map = wxService.parseRequest(request.getInputStream());
        System.out.println("处理消息和事件推送:"+map);
        return wxService.getRespose(map);
    }

将xml数据包解析成map形式

    /**
     * 使用dom4j包     解析xml数据包  成Map形式
     * @param inputStream
     * @return
     */
    @Override
    public Map<String, String> parseRequest(ServletInputStream inputStream) {
    
    
        HashMap<String, String> hashMap = new HashMap<>();
        SAXReader reader = new SAXReader();
        try {
    
    
            //读取输入流 回去文档对象
            Document document = reader.read(inputStream);
            //根据文档对象 回去根节点
            Element rootElement = document.getRootElement();
            //根据根节点获取所有的子节点
            List<Element> elements = rootElement.elements();
            for (Element element : elements) {
    
    
                hashMap.put(element.getName(), element.getStringValue());
            }
        } catch (DocumentException e) {
    
    
            e.printStackTrace();
        }
        return hashMap;
    }

然后对不同的消息类型进行相应的处理:

/**
     * 用于处理所有的事件和消息de 回复
     * 将Map解析成xml数据包  回复消息
     * @param map
     * @return  返回的是xml数据包
     */
    @Override
    public String getRespose(Map<String, String> map) {
    
    
        String msgType = map.get("MsgType");
        BaseMessage msg = null;
        switch (msgType){
    
    
            case "text":
                msg = dealText(map);
                break;
            case "image":
                msg = dealImage(map);
                break;
            case "voice":
                msg = dealVoice(map);
                break;
            case "video":
                break;
            case "shortvideo":
                break;
            case "location":
                break;
            case "link":
                break;
            case "event":
                msg = dealEvent(map);
                break;
            default:
                break;
        }
        if (msg != null){
    
    
            String xml = beanToXml(msg);
            System.out.println(xml);
            log.info(xml);
            return xml;
        }else {
    
    
            return "success";
        }
    }

msgType类型如果为image,就调用百度API;

/**
     * 处理图片消息
     * @param map
     * @return
     */
    private BaseMessage dealImage(Map<String, String> map) {
    
    
        String url = map.get("PicUrl");
        String toText = bdUtil.imageToText(url);
        return new TextMessage(map,toText);
    }
package com.wx.util;

import com.baidu.aip.ocr.AipOcr;
import com.wx.model.weather.*;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.json.JSONException;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/**
 * @author :LiuShihao
 * @date :Created in 2020/10/10 3:24 下午
 * @desc :
 */
@Slf4j
@Component
public class BDUtil {
    
    
	//你的对应信息
    public static final String APP_ID = "228****23";
    public static final String API_KEY = "2D0gCVQP***********gGdjgUCs";
    public static final String SECRET_KEY = "UXL0pNYD***********ZO357kmXBa";
    public static AipOcr client;

    static {
    
    
        // 初始化一个AipOcr
         client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
    }

    /**
     * 识别 图片  文字
     * @param picUrl
     * @return
     * @throws JSONException
     */
    public String imageToText(String picUrl) throws JSONException {
    
    
        String totext = null;
        // 传入可选参数调用接口
        HashMap<String, String> options = new HashMap<String, String>();
        options.put("language_type", "CHN_ENG");
        options.put("detect_direction", "true");
        options.put("detect_language", "true");
        options.put("probability", "true");

//        // 参数为本地路径
//        String image = "test.jpg";
//        JSONObject res = client.basicGeneral(image, options);
//        System.out.println(res.toString(2));
//
//        // 参数为二进制数组
//        byte[] file = readFile("test.jpg");
//        res = client.basicGeneral(file, options);
//        System.out.println(res.toString(2));

        // 通用文字识别, 图片参数为远程url图片
        org.json.JSONObject res = client.basicGeneralUrl(picUrl, options);
        /**
         * 返回成功:
         * {
         *   "words_result": [{
         *     "probability": {
         *       "average": 0.950565,
         *       "min": 0.74773,
         *       "variance": 0.005733
         *     },
         *     "words": "该公众号提供的服务出现故障,请稍后再试"
         *   }],
         *   "log_id": 1314882863493021696,
         *   "words_result_num": 1,
         *   "language": 3,
         *   "direction": 0
         * }
         *
         * 返回失败:
         *
         */
        System.out.println(res.toString(2));
        String s = res.toString(2);
        //将 字符创 转化成 JSONObject   package net.sf.json;
        JSONObject jsonObject = JSONObject.fromObject(s);
        System.out.println("jsonObject:"+jsonObject);
        try{
    
    
            String error_code = jsonObject.getString("error_code");

            if(!StringUtils.isEmpty(error_code)){
    
    
                if ("216202".equals(error_code)){
    
    
                    totext = "上传的图片大小错误,现阶段我们支持的图片大小为:base64编码后小于4M,分辨率不高于4096*4096,请重新上传图片";
                }
                if ("216201".equals(error_code)){
    
    
                    totext = "上传的图片格式错误,现阶段我们支持的图片格式为:PNG、JPG、JPEG、BMP,请进行转码或更换图片";
                }
            }
        }catch (net.sf.json.JSONException e){
    
    
            e.printStackTrace();
            JSONArray words_result = jsonObject.getJSONArray("words_result");
            StringBuilder stringBuilder = new StringBuilder();
            Iterator it = words_result.iterator();
            while (it.hasNext()){
    
    
                JSONObject next = (JSONObject)it.next();
                stringBuilder.append(next.getString("words"));
            }
            log.info("imageToText:"+stringBuilder);
            totext= stringBuilder.toString();
        }
        return totext;
    }
}

打开百度AI开放平台网站,选择文字识别服务,如果没有应用,创建一个应用

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

删除菜单

使用接口创建自定义菜单后,开发者还可使用接口删除当前使用的自定义菜单。另请注意,在个性化菜单时,调用此接口会删除默认菜单及全部个性化菜单。

请求说明

http请求方式:GET https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN

返回说明

对应创建接口,正确的Json返回结果:

{“errcode”:0,“errmsg”:“ok”}

package com.wx.util;

import com.wx.model.button.*;
import com.wx.service.Impl.WXServiceImpl;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author :LiuShihao
 * @date :Created in 2020/10/10 12:32 下午
 * @desc :
 */
@Component
public class CreateMenu {
    
    
    @Autowired
    WXServiceImpl wxService;


    public static void main(String[] args) {
    
    

    }
    public void createMenu(){
    
    
        Button button = new Button();
        button.getButton().add(new ClickButten("一级菜单_点击","1"));
        button.getButton().add(new ViewButton("一级跳转","http://baidu.com"));
        SubButton subButton = new SubButton("子菜单");
        subButton.getSub_button().add(new PhotoAlbumButton("拍照或者相册发图","pic_photo_or_album","rselfmenu_1_0"));
        subButton.getSub_button().add(new ClickButten("二级菜单_点击","2"));
        subButton.getSub_button().add(new ViewButton("二级跳转","http://news.163.com"));
        subButton.getSub_button().add(new ViewButton("我的博客","http://116.62.13.104:8090/"));
        subButton.getSub_button().add(new ViewButton("我的网盘","http://116.62.13.104:8081/"));
        button.getButton().add(subButton);
        JSONObject jsonObject = JSONObject.fromObject(button);
        System.out.println(jsonObject);
        String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
        String token = WXServiceImpl.getToken();
        url = url.replace("ACCESS_TOKEN",token);
        com.alibaba.fastjson.JSONObject post = CommonUtil.httpsRequest(url, "POST", jsonObject.toString());
        System.out.println("post:"+post);
    }

    /**
     * http请求方式:GET https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
     */
    public void delMenu(){
    
    
        String url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";
        String token = wxService.getRedisToken();
        url = url.replace("ACCESS_TOKEN",token);
        com.alibaba.fastjson.JSONObject post = CommonUtil.httpsRequest(url, "GET", null);
        System.out.println("post:"+post);

    }

    /**
     * http请求方式: GET(请使用https协议)https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN
     */
    public void findMenu(){
    
    
        String url = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN";
        String token = wxService.getRedisToken();
        url = url.replace("ACCESS_TOKEN",token);
        com.alibaba.fastjson.JSONObject post = CommonUtil.httpsRequest(url, "GET", null);
        System.out.println("post:"+post);

    }
}



 @Test
    public void test3(){
    
    
//        menu.delMenu();
        menu.createMenu();
        menu.findMenu();
    }

猜你喜欢

转载自blog.csdn.net/DreamsArchitects/article/details/108991417