微信开发工具包WxJava之微信公众号开发的常用API使用篇

简介: 承接上文:微信开发工具包WxJava之微信公众号开发的入门使用篇,续写下文。

WxJava

承接上文:微信开发工具包WxJava之微信公众号开发的入门使用篇,续写下文。

微信开发工具包WxJava是一个基于Java语言的微信公众号和小程序开发工具包,提供了丰富的API接口,可以根据自己的需求选择相应的接口。

WxJava中常用API:

获取access_token:access_token是调用微信公众平台API的全局唯一凭证,通过获取access_token可以进行后续的API调用。

用户管理:包括用户信息的获取、设置备注名、拉黑用户等。

创建自定义菜单:创建自定义菜单,包括点击事件、跳转URL等。自定义菜单是指将公众号的功能以菜单形式展现给用户,方便用户快速访问公众号的各项功能。

模板消息:通过调用模板消息API可以向用户发送预设的模板消息,方便公众号进行消息推送,包含文字、链接、图片等。

素材管理:素材可以是图文消息、图片、语音、视频等多种类型,通过调用素材管理API可以实现对素材的上传、获取和删除等操作。

消息管理:通过客服接口发送文本、图片、语音、视频等消息给用户。同理,用户向公众号发送消息,公众号向用户回复的消息。

网页授权:网页授权是指允许公众号获取用户在微信内的基本信息,并在网页中进行相关操作的功能。

JS-SDK:JS-SDK可以帮助公众号在网页中调用微信提供的一些基础服务,如分享、支付等。

用户管理

用户管理提供了:更新用户备注名、获得用户信息、获得用户列表、查询用户标签列表、批量给用户添加标签、批量给用户移除标签等API

相关API

更新用户备注名

wxMpService.getUserService().userUpdateRemark(openid, "测试备注名");

获得用户信息

String lang = "zh_CN"; //语言
WxMpUser user = wxMpService.getUserService().userInfo(openid,lang);

获得用户列表

WxMpUserList wxUserList = wxMpService.getUserService().userList(next_openid);

查询用户标签列表

List<Long> tags = wxMpService.getUserTagService().userTagList(openid);

批量给用户添加标签

String[]openids,long tagid;
wxMpService.getUserTagService().batchTagging(tagid,openids);

批量给用户移除标签

wxMpService.getUserTagService().batchUntagging(tagid,openids);

使用示例

用户管理以使用获得用户列表API为例:

    @RequestMapping("/user")
    public String user() throws WxErrorException {
   
   
        // 可选,第一个拉取的OPENID,null为从头开始拉取
        String nextOpenid = null;
        // 获得用户列表,一次拉取调用最多拉取10000个关注者的OpenID
        WxMpUserList wxMpUserList = wxMpService.getUserService().userList(nextOpenid);
        log.info("wxMpUserList = {}", wxMpUserList);

        // 语言
        String lang = "zh_CN";
        List<String> openids = wxMpUserList.getOpenids();
        for (String openid : openids) {
   
   
            // 获得用户信息
            WxMpUser user = wxMpService.getUserService().userInfo(openid, lang);
            log.info("user = {}", user);

            // 更新用户备注名
            wxMpService.getUserService().userUpdateRemark(openid, "开发者");
        }

        return "OK";
    }
wxMpUserList = {
   
   "total":1,"count":1,"openids":["oqIoX6A_aW-_VxMbfV3vn3N2_adc"],"nextOpenid":"oqIoX6A_aW-_VxMbfV3vn3N2_adc"}

user = {
   
   "subscribe":true,"openId":"oqIoX6A_aW-_VxMbfV3vn3N2_adc","nickname":"","language":"zh_CN","headImgUrl":"","subscribeTime":1682671274,"remark":"","groupId":0,"tagIds":[],"subscribeScene":"ADD_SCENE_OTHERS","qrScene":"0","qrSceneStr":""}

二维码管理

二维码管理介绍

可以生成带参数的二维码,应用于为了满足用户渠道推广分析和用户帐号绑定等场景

用户扫描带场景值二维码时,可以推送以下两种事件:

如果用户未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。

如果用户已关注公众号,在用户扫描后会自动进入会话,微信也会将带场景值扫描事件推送给开发者。

二维码管理中有2种类型的二维码:

1、临时二维码

临时二维码是有过期时间的,最长可以设置为在二维码生成后的30天(即2592000秒)后过期,但能够生成较多数量。临时二维码主要用于帐号绑定等不要求二维码永久保存的业务场景

2、永久二维码

永久二维码是无过期时间的,但数量较少(目前为最多10万个)。永久二维码主要用于适用于帐号绑定、用户来源统计等场景。

创建二维码ticket

每次创建二维码ticket需要提供一个开发者自行设定的参数scene_id

// 临时ticket
WxMpQrCodeTicket ticket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(scene, expire_seconds);

// 永久ticket
WxMpQrCodeTicket ticket = wxMpService.getQrcodeService().qrCodeCreateLastTicket(scene);

通过ticket换取二维码

获取二维码ticket后,开发者可用ticket换取二维码图片。请注意,本接口无须登录态即可调用。

// 创建二维码ticket
WxMpQrCodeTicket ticket = wxMpService.getQrcodeService().qrCodeCreate*();

// 获得在系统临时目录下的文件,需要自己保存使用,注意:临时文件夹下存放的文件不可靠,不要直接使用
File file = wxMpService.getQrcodeService().qrCodePicture(ticket);
    @RequestMapping("/user")
    public String user() throws WxErrorException {
   
   
        WxMpQrCodeTicket ticket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket("scene_id", 2592000);
        File file = wxMpService.getQrcodeService().qrCodePicture(ticket);
        log.info("file = {}", file);
        return file.getPath();
    }
 ticket = {
   
   "ticket":"gQHz7zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAySjhRY0VsRWFjbkUxaFN0UGhBY24AAgR2kEtkAwQAjScA","expireSeconds":2592000,"url":"http://weixin.qq.com/q/02J8QcElEacnE1hStPhAcn"}
 file = C:\Users\Admin\AppData\Local\Temp\wxjava-temp4795776614163231975\4063eff3-53d5-4227-9ee4-eff1be9201fa1918629243212569901.jpg

获取二维码ticket后,开发者可用ticket换取二维码图片。请注意,本接口无须登录态即可调用

https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET

接收消息

接收事件推送

实现一个接收关注、取消关注事件推送的处理。

@Component
public class SubscribeHandler implements WxMpMessageHandler {
   
   
    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService, WxSessionManager sessionManager) throws WxErrorException {
   
   
        return WxMpXmlOutMessage.TEXT().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
                .content("欢迎关注XX公众号").build();
    }
}
@Component
@Slf4j
public class UnSubscribeHandler implements WxMpMessageHandler {
   
   
    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService, WxSessionManager sessionManager) throws WxErrorException {
   
   
        return WxMpXmlOutMessage.TEXT().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
                .content("注意:已经取消关注,即使回复消息也不会收到").build();
    }
}
@Configuration
public class MessageRouterConfig {
   
   
    @Autowired
    private WxMpService wxMpService;

    @Autowired
    private SubscribeHandler subscribeHandler;

    @Autowired
    private UnSubscribeHandler unSubscribeHandler;

    @Bean
    public WxMpMessageRouter messageRouter() {
   
   
        // 创建消息路由
        final WxMpMessageRouter router = new WxMpMessageRouter(wxMpService);
        // 订阅事件
        router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.EventType.SUBSCRIBE).handler(subscribeHandler).end();
        // 取消订阅事件
        router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).event(WxConsts.EventType.UNSUBSCRIBE).handler(unSubscribeHandler).end();
        return router;
    }
}
    @RequestMapping("send")
    public String configAccess(@RequestBody String requestBody, @RequestParam("signature") String signature, @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce) {
   
   
        if (!wxMpService.checkSignature(timestamp, nonce, signature)) {
   
   
            log.error("签名校验 ===》 非法请求");
            return null;
        }
        WxMpXmlMessage xmlMessage = WxMpXmlMessage.fromXml(requestBody);
        WxMpXmlOutMessage outMessage = null;
        try {
   
   
            outMessage = wxMpMessageRouter.route(xmlMessage);
        } catch (Exception e) {
   
   
            log.error("消息路由异常", e);
        }
        return outMessage == null ? null : outMessage.toXml();
    }

image.png

群发接口

文本消息

    @RequestMapping("send")
    public String send() throws WxErrorException {
   
   
        WxMpMassOpenIdsMessage massMessage = new WxMpMassOpenIdsMessage();
        massMessage.setMsgType(WxConsts.MassMsgType.TEXT);
        massMessage.setContent("文本消息内容文本消息内容文本消息内容文本消息内容文本消息内容文本消息内容");
        // 用户openid 扫描`测试号二维码`可以得到
        massMessage.getToUsers().add("oqIoX6A_aW-_VxMbfV3vn3N2_adc");
        // 针对异常:errcode: 40130,具体异常请参考文末异常项
        massMessage.getToUsers().add("");

        WxMpMassSendResult massResult = wxMpService.getMassMessageService().massOpenIdsMessageSend(massMessage);
        return "OK";
    }

image.png

图片消息

    @RequestMapping("send")
    public String send() throws WxErrorException {
   
   
        File file = new File("D://test.png");

        WxMediaUploadResult uploadMediaRes = null;
        try (
                FileInputStream fileInputStream = new FileInputStream(file);
        ) {
   
   
            uploadMediaRes = wxMpService.getMaterialService().mediaUpload(WxConsts.MediaFileType.IMAGE, "jpg", fileInputStream);
        } catch (Exception e) {
   
   
            e.printStackTrace();
            return "Fail";
        }


        WxMpMassOpenIdsMessage massMessage = new WxMpMassOpenIdsMessage();
        massMessage.setMsgType(WxConsts.MassMsgType.IMAGE);
        massMessage.setMediaId(uploadMediaRes.getMediaId());
        // 用户openid 扫描`测试号二维码`可以得到
        massMessage.getToUsers().add("oqIoX6A_aW-_VxMbfV3vn3N2_adc");
        // errcode: 40130
        massMessage.getToUsers().add("");

        WxMpMassSendResult massResult = wxMpService.getMassMessageService().massOpenIdsMessageSend(massMessage);
        log.info("massResult ===》 {}", massResult);
        return "OK";
    }

image.png

异常

在测试群发接口时,出现以下异常:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is me.chanjar.weixin.common.error.WxRuntimeException: javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty] with root cause


java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
  at java.security.cert.PKIXParameters.setTrustAnchors(PKIXParameters.java:200) ~[na:1.8.0_41]
  at java.security.cert.PKIXParameters.<init>(PKIXParameters.java:120) ~[na:1.8.0_41]
  at java.security.cert.PKIXBuilderParameters.<init>(PKIXBuilderParameters.java:104) ~[na:1.8.0_41]

因为群发的用户数用户有两个或两个以上,由于本公众号只有一个关注用户,所以报错。

me.chanjar.weixin.common.error.WxErrorException: 错误代码:40130, 错误信息:invalid openid list size, at least two openid rid: 644a404f-092ae85f-012852f0,微信原始报文:{
   
   "errcode":40130,"errmsg":"invalid openid list size, at least two openid rid: 644a404f-092ae85f-012852f0"}
me.chanjar.weixin.common.error.WxErrorException: 错误代码:40017, 错误信息:不合法的按钮类型,微信原始报文:{
   
   "errcode":40017,"errmsg":"invalid button type rid: 644b41e9-28e5a17e-0983ff62"}

模板消息、业务通知

通过调用模板消息API可以向用户发送预设的模板消息,方便公众号进行消息推送等。

配置消息模板

创建微信模板

模板标题:系统异常通知

模板内容:

服务名称:   {
   
   {
   
   keyword1.DATA}} 
IP和端口:   {
   
   {
   
   keyword2.DATA}}
异常内容:   {
   
   {
   
   keyword3.DATA}} 
异常时间:   {
   
   {
   
   keyword4.DATA}} 

系统异常,请及时处理。

image.png

业务通知实现

    @RequestMapping("send")
    public String send() {
   
   
        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                // 用户openid 扫描`测试号二维码`可以得到
                .toUser("oqIoX6A_aW-_VxMbfV3vn3N2_adc")
                // 模板id
                .templateId(templateId)
                //点击消息要访问的网址
                .url("https://baidu.com/")
                .build();

        templateMessage.addData(new WxMpTemplateData("keyword1", "user服务", "#000000"))
                .addData(new WxMpTemplateData("keyword2", "192.168.30.30:8080"))
                .addData(new WxMpTemplateData("keyword3", "获取数据失败"))
                .addData(new WxMpTemplateData("keyword4", LocalDateTime.now()+""));
        try {
   
   
            // 发送模板消息
            wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
        } catch (WxErrorException e) {
   
   
            e.printStackTrace();
        }
        return "OK";
    }

image.png

自定义菜单管理

创建自定义菜单,包括点击事件、跳转URL等。自定义菜单是指将公众号的功能以菜单形式展现给用户,方便用户快速访问公众号的各项功能。

AIP介绍

自定义菜单使用2个核心对象:

WxMenu:菜单对象

WxMenuButton:按钮对象

创建自定义菜单

包括新增和修改,修改相当于覆盖之前的菜单。

WxMenu wxMenu = new WxMenu();

设置菜单

wxMpService.getMenuService().menuCreate(wxMenu);

删除自定义菜单

wxMpService.getMenuService().menuDelete();

获得自定义菜单

WxMenu wxMenu = wxMpService.getMenuService().menuGet();

传递JSON参数

    @GetMapping("createMenu")
    public String createMenu() throws WxErrorException {
   
   
        String json="{\"button\": [{\"name\": \"点击\",\"type\": \"click\",\"key\": \"1\"},{\"name\": \"跳转\",\"type\": \"view\",\"url\": \"http://www.baidu.com\"}]}";
        // 创建按钮
        wxMpService.getMenuService().menuCreate(json);

        // 获取菜单信息
        WxMpGetSelfMenuInfoResult selfMenuInfo = wxMpService.getMenuService().getSelfMenuInfo();
        log.info("selfMenuInfo : {}", selfMenuInfo);

        return "OK";
    }

image.png

传递对象参数

    @GetMapping("createMenu")
    public String createMenu() throws WxErrorException {
   
   
        // 创建菜单对象
        WxMenu menu = new WxMenu();

        // 创建按钮A
        WxMenuButton button_a = new WxMenuButton();
        button_a.setType(WxConsts.MenuButtonType.CLICK);
        button_a.setName("按钮A");
        button_a.setKey("BUTTON_A");

        // 创建按钮A的子按钮1
        WxMenuButton button_a_1 = new WxMenuButton();
        button_a_1.setType(WxConsts.MenuButtonType.VIEW);
        button_a_1.setName("子按钮1");
        button_a_1.setUrl("https://www.baidu.com");
        // 将子按钮添加到按钮A
        button_a.getSubButtons().add(button_a_1);

        // 创建按钮A的子按钮2
        WxMenuButton button_a_2 = new WxMenuButton();
        button_a_2.setType(WxConsts.MenuButtonType.CLICK);
        button_a_2.setName("子按钮2");
        button_a_2.setKey("BUTTON_A_2");
        button_a.getSubButtons().add(button_a_2);

        // 创建按钮B
        WxMenuButton button_b = new WxMenuButton();
        button_b .setType(WxConsts.MenuButtonType.CLICK);
        button_b.setName("按钮B");
        button_b.setKey("BUTTON_B");

        // 将按钮A和按钮B添加到菜单
        menu.getButtons().add(button_a);
        menu.getButtons().add(button_b);

        // 创建按钮
        wxMpService.getMenuService().menuCreate(menu);

        // 获取菜单信息
        WxMpGetSelfMenuInfoResult selfMenuInfo = wxMpService.getMenuService().getSelfMenuInfo();
        log.info("selfMenuInfo : {}", selfMenuInfo);

        return "OK";
    }

image.png

OAuth2网页授权

流程时序图

微信网页授权流程时序图如下:
image.png

相关API说明

构造网页授权url

wxMpService.getOAuth2Service().buildAuthorizationUrl(url, WxConsts.OAuth2Scope.SNSAPI_USERINFO, null)

获得access token

WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);

获得用户基本信息

WxOAuth2UserInfo wxMpUser = wxMpService.getOAuth2Service().getUserInfo(wxMpOAuth2AccessToken, null);

刷新access token

WxOAuth2AccessToken = wxMpService.getOAuth2Service().refreshAccessToken(wxOAuth2AccessToken.getRefreshToken());

验证access token

boolean valid = wxMpService.getOAuth2Service().validateAccessToken(wxOAuth2AccessToken);

构造网页授权url

首先构造网页授权url,然后构成超链接让用户点击:

  /**
     * 构造网页授权url
     *
     * @return
     */
    @GetMapping("authPage")
    public String authPage() {
   
   
        WxOAuth2Service oAuth2Service = wxMpService.getOAuth2Service();
        String callbackUrl = "https://*.zicp.fun/callback";
        // 构建授权url
        String url = oAuth2Service.buildAuthorizationUrl(callbackUrl, WxConsts.OAuth2Scope.SNSAPI_USERINFO, null);
        return url;
    }

获得access token

当用户同意授权后,会回调所设置的url并把authorization code传过来,然后用这个code获得access token,其中也包含用户的openid等信息

    /**
     * 用户确认授权后的回调处理
     */
    @GetMapping("callback")
    public WxOAuth2UserInfo callback(String code) throws WxErrorException {
   
   
        WxOAuth2Service oAuth2Service = wxMpService.getOAuth2Service();
        // 利用code获取accessToken
        WxOAuth2AccessToken accessToken = oAuth2Service.getAccessToken(code);
        // 利用accessToken获取用户信息
        WxOAuth2UserInfo userInfo = oAuth2Service.getUserInfo(accessToken, null);
        return userInfo;
    }
    @GetMapping("createMenu")
    public String createMenu() throws WxErrorException {
   
   
        // 创建菜单对象
        WxMenu menu = new WxMenu();

        // 创建按钮A
        WxMenuButton button_a = new WxMenuButton();
        button_a.setType(WxConsts.MenuButtonType.VIEW);
        button_a.setName("授权登录");
        button_a.setUrl("https://*.zicp.fun/authPage");

        // 创建按钮B
        WxMenuButton button_b = new WxMenuButton();
        button_b .setType(WxConsts.MenuButtonType.CLICK);
        button_b.setName("按钮B");
        button_b.setKey("BUTTON_B");

        // 将按钮A和按钮B添加到菜单
        menu.getButtons().add(button_a);
        menu.getButtons().add(button_b);

        // 创建按钮
        wxMpService.getMenuService().menuCreate(menu);

        return "OK";
    }

image.png

执行测试

在进行OAuth2网页授权测试过程中,获取构造网页授权url,遇到如下异常:
image.png

需要再公众号开发平台设置网页回调域名地址

image.png

image.png

当填写网页回调授权域名地址后,再次获取构造网页授权url,结果如下:
image.png

将得到的构造网页授权url发送到公众号,然后点击该链接,进入到用户授权详情页,用户同意后则将获得access token
image.png

利用accessToken获取用户信息,具体用户信息格式如下

image.png

相关文章
|
2月前
|
缓存 API 网络架构
Nuxt Kit API :路径解析工具
【9月更文挑战第20天】在 Nuxt Kit API 中,路径解析工具如 `resolvePath()`、`joinPaths()` 和 `relativePath()` 帮助开发者高效处理应用路径,确保资源准确加载,并支持动态路由与组件导入。这些工具提升了应用的灵活性和可扩展性,同时需注意路径准确性、跨平台兼容性和性能优化,以提升用户体验。
36 12
|
1月前
|
监控 API 数据安全/隐私保护
2024年开源API工具盘点,覆盖API全生命周期
2024年经济持续低迷,本文整理一些免费的开源工具,旨在帮助企业组织降低工具的支出成本,能用免费的何必用付费的呢(狗头)?
68 0
|
2月前
|
JSON 安全 API
淘宝 API 接口:解锁商品详情的强大工具
淘宝API接口在电商领域扮演着关键角色,为商家和开发者提供强大的数据支持和服务能力。它不仅帮助商家获取商品信息、管理订单和物流,还支持数据分析、价格调整等功能,助力商家在竞争激烈的市场中取得成功。此外,通过注册认证、搭建开发环境等步骤,开发者可快速上手并利用丰富的技术文档和社区支持进行高效开发。
|
2月前
|
小程序 前端开发 API
微信小程序 - 调用微信 API 回调函数内拿不到 this 问题(解决方案)
本文讨论了在微信小程序中调用API回调函数时无法获取到`this`上下文的问题,并提供了解决方案。在回调函数中,使用一个变量(如`that`)来保存当前的`this`引用,然后在回调内部使用这个变量来访问当前页面的数据和方法。
|
3月前
|
小程序 开发者
第一个微信小程序的初始化过程、小程序微信开发平台的下载、如何注册一个微信小程序的账号
这篇文章介绍了微信小程序的初始化过程,包括如何注册微信小程序账号、下载微信小程序开发者平台,并指导了新建小程序的详细步骤。
第一个微信小程序的初始化过程、小程序微信开发平台的下载、如何注册一个微信小程序的账号
|
4月前
|
文字识别 小程序 安全
印刷文字识别操作报错合集之微信小程序调用API时路径总是返回不对,该如何处理
在使用印刷文字识别(OCR)服务时,可能会遇到各种错误。例如:1.Java异常、2.配置文件错误、3.服务未开通、4.HTTP错误码、5.权限问题(403 Forbidden)、6.调用拒绝(Refused)、7.智能纠错问题、8.图片质量或格式问题,以下是一些常见错误及其可能的原因和解决方案的合集。
|
3月前
|
前端开发 JavaScript API
微信公众号项目,实现微信支付(具体流程和参数)
微信公众号项目,实现微信支付(具体流程和参数)
|
3月前
|
缓存 JavaScript 前端开发
微信 JS-SDK Demo “分享信息设置” API 及数字签名生成方法(NodeJS版本)
微信 JS-SDK Demo “分享信息设置” API 及数字签名生成方法(NodeJS版本)更新时间(2020-10-29)
|
3月前
|
开发框架 前端开发 API
使用代码生成工具快速开发应用-结合后端Web API提供接口和前端页面快速生成,实现通用的业务编码规则管理
使用代码生成工具快速开发应用-结合后端Web API提供接口和前端页面快速生成,实现通用的业务编码规则管理
|
4月前
|
小程序 API
微信小程序getLocation报错 getLocation:fail the api need to be declared in the requiredPrivateInfos field in
微信小程序getLocation报错 getLocation:fail the api need to be declared in the requiredPrivateInfos field in
382 1