微信api_微信api接口 - CSDN
精华内容
参与话题
  •   从今天开始,开始打造一个个人版的微信小程序,尽早上线,方便大家使用以及技术讨论。这套小程序包括前台、后台、数据库等部分,估计需要花些时间了。   小程序开发在入门阶段直接参照官方的帮助文档即可,...

    如果觉得这篇文章对您有所启发,欢迎关注我的公众号,我会尽可能积极和大家交流,谢谢。
    这里写图片描述

      从今天开始,开始打造一个个人版的微信小程序,尽早上线,方便大家使用以及技术讨论。这套小程序包括前台、后台、数据库等部分,估计需要花些时间了。
      小程序开发在入门阶段直接参照官方的帮助文档即可,包括基本语法(和Vue.js大同小异)、开发工具(腾讯提供了一个小的开发工具)等,官方文档:微信小程序开发。
      小程序开发自然而然分为前台后台,前台程序的入门参照官方文档,后台程序则需要自己搭建了。主要问题是微信小程序要求内部调用的API接口必须都是https的,并且最好是带域名,因此需要在搭建后台的时候费点功夫,整体后台基本流程如下:
    这里写图片描述

    • 1 选用API接口。想让产品能够吸引用户来用,首先得要求其有一些实实在在的功能,这就需要对应业务的API接口了。
    • 2 Springboot统一后台。整合用到的api业务接口,同时支撑一些自定义功能(如登录注册等)
    • 3 云服务器、域名、SSL证书:后台部署的媒介,同时负责将http接口转换为https接口
    • 4 Nginx反向代理:将域名和IP绑定,以https的形式提供给前端程序调用
    • 5 微信小程序:前端

    1 API市场

    1.1 API市场

      有多少程序员在入门的时候都写过天气预报的demo?这就是一个最简单的数据API。目前在市面上有很多API接口可供大家调用,有付费的也有免费的,这里举两个例子:聚合数据阿里云API市场。这两个市场的优缺点我并没有仔细研究。
      这里以阿里云API市场中的天气预报API接口为例来做:天气预报API接口

    1.2 购买API

      首先,需要先购买该API接口之后才能调用,即使是表明免费的接口也需要进行购买操作,否则无法进行调用。这里有很多便宜且实用的接口,如天气预报、快递查询、驾照查分、身份证识别等等,具体如何组合使用还是取决于我们对产品发展的设想:
    这里写图片描述
      以天气预报查询为例,我们在登录阿里云账号(支付宝可以直接登录)并购买对应API接口之后,在对应的控制台中可以查看到该接口的AppCode、AppKey、AppSecret,这些都是我们对该接口的调用凭证,在调用时是需要放到header中上传的:
    这里写图片描述

    1.3 测试API

      在API购买完成之后,我们需要测试一下这个接口的可用性,我这里使用postman来测试一下,对应的调用方式在文档中已经都明确说明过了:天气预报API接口
      调用地址见文档,调用方式为get请求,请求头中写入AppCode做身份认证,添加城市名称作为请求参数,测试如下:
    这里写图片描述
    具体身份认证方式见文档:Appcode简单认证

    2 搭建Springboot

    2.1 IDE

      这里选用IntelliJ IDEA,IntelliJ IDEA是付费最好的java编辑器,eclipse是免费最好的java编辑器。为了方便springboot项目的新建和编写,这里推荐下载两个插件,即GsonFormat和Spring Assistant:
    这里写图片描述
    这里写图片描述

    2.2 新建springboot项目

      Spring Assistant能够方便快速的新建一个springboot项目:“file”->“new”->“project”->“Spring Assistant”,按照提示一步步创建SpringBoot项目即可。有一点需要说明的就是,这里默认通过maven来构建项目以及依赖包的管理,IDEA默认是国外的maven仓库地址,第一次构建下载相应的jar包时会相当慢,需要转换到国内镜像来下载,具体如下:maven国内镜像地址
      在新建Springboot项目时,记得选中web的依赖,后续在使用网络请求的时候会用到这个依赖:
    这里写图片描述
      数据库的依赖这里先不要选,等用到的时候再添加即可,不然程序启动不起来。程序新建完成之后,找到对应的Application入口,右键debug它:
    这里写图片描述
      也可以通过“shift+alt+F9”快捷键来实现debug,控制台输出一下内容,说明程序启动正常:
    这里写图片描述

    2.3 集成swagger接口文档

      Swagger是一种Rest API的 简单但强大的表示方式,这里应用知乎上的一篇文章作为介绍:swagger简介。接下来,我们要在新建的springboot项目中将swagger集成进来。
      1、在项目的pom.xml文件中添加swagger相关依赖:

            <!-- Swagger -->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>2.6.1</version>
            </dependency>
    
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>2.6.1</version>
            </dependency>

    每次修改pom文件时,系统在右下角有所提示,点击“import change”即可完成相关依赖包的添加。
      2、在和Application同级的目录中,新建名为“Swagger2”的类:
    这里写图片描述
    swagger2文件中的代码如下:

    @Configuration
    @EnableSwagger2
    public class Swagger2 {
        private String BASE_PACKAGE = Swagger2.class.getPackage().getName();
    
        @Bean
        public Docket createRestApi() {
            return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
                    .apis(RequestHandlerSelectors.basePackage(BASE_PACKAGE)).paths(PathSelectors.any()).build();
        }
    
        private ApiInfo apiInfo() {
            return new ApiInfoBuilder().title("WechatApplet")
                    .description("微信小程序后台支持")
                    .termsOfServiceUrl("http://www.neuqosft.com")
                    .version("0.0.1")
                    .build();
        }
    
    }

      “ctrl+F5”重启项目,启动成功之后在浏览器中输入:http://localhost:8080/swagger-ui.html,显示swagger页面,配置完成。
    这里写图片描述

    3 调用阿里云api市场中的天气预报接口

      springboot的项目建完之后,需要在其中调用我们之前购买的API接口。

    3.1 新建package

      新建api、weather两个包,同时在weather新建dto、service两个包:
    这里写图片描述

    • api:放置SpringMVC中的controller,直接接受前台的请求,并返回数据结果
    • weather:放置有关天气相关的service层、dto层、entity层代码
    • service:负责相关业务调用和逻辑处理
    • dto:构造bean,负责将API返回的json串解析成对应的类

    3.2 新建dto

      在dto包下新建WeatherInfoDto的java class,dto生成可以使用插件gsonformat。首先,在postman中复制接口返回的所有字符串数据:
    这里写图片描述
    在WeatherInfoDto的类内部(大括号包裹的区域),点击右键->“Generate”->“GsonFormat”,然后将接口中返回的json字符串完整的复制到弹出的输入框中:
    这里写图片描述
    点击“OK”->“OK”,对应的javabean会根据接口返回的字符串来自动生成:
    这里写图片描述

    3.3 新建Service

      Service层主要是负责业务逻辑的处理,同时将处理结果返回给Controller层。这里在Service层中完成接口的网络请求,这里的网络请求选用RestTemplate。在使用RestTemplate之前,需要先在pom文件中添加“spring-boot-starter-web”依赖,这个我们在新建项目的过程中已经完成。在service包下新建名为“WeatherService”的java class文件,具体如下:

    @Service
    public class WeatherService {
    
        public WeatherInfoDto queryBasicInfo(String strCityName){
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders requestHeaders = new HttpHeaders();
            Map<String,String> parmaters = new HashMap<String,String>();
    
            requestHeaders.set("Authorization","APPCODE ae35098dabb84cd883c047c80672cb2b");
            parmaters.put("city",strCityName);
    
            HttpEntity requestEntity = new HttpEntity(requestHeaders);
            ResponseEntity<WeatherInfoDto> response = restTemplate.exchange("http://chkj02.market.alicloudapi.com/qgtq?city={city}",HttpMethod.GET, requestEntity, WeatherInfoDto.class, parmaters);
            return response.getBody();
        }
    }
    

    有如下几个问题需要强调:

    • 1 RestTemplate官方文档:1RestTemplate
    • 2 需要在header中加入参数“Authorization”,其中的值包含申请到的Appcode;请求参数(parmaters)包含”city”,具体指由controller层传入
    • 3 RestTemplate中get请求的URL为“http://chkj02.market.alicloudapi.com/qgtq?city={city}”,注意需要将参数拼接到后边,否则无法正常进行传参
    • 4 service层,需要加“@Service”注解

    3.4 新建Controller

      Service中完成之后,可以开始编写Controller层中的代码了。Controller层主要职责是接受前台的网络请求,调用对应的service层代码,并将service层的处理结果返回给调用者。在api中新建名为“WeatherController”的java class文件,代码如下:

    @Api(description = "天气信息查询")
    @RestController
    @RequestMapping("/weather")
    public class WeatherController {
    
        @Autowired
        private WeatherService weatherService;
    
        @ApiOperation(value = "天气基本信息查询")
        @ApiImplicitParam(name = "strCityName", value = "城市名称", required = true, paramType = "query")
        @GetMapping("/jbxx")
        public WeatherInfoDto queryBasicInfo(@RequestParam String strCityName) {
            return weatherService.queryBasicInfo(strCityName);
        }
    }
    

    这些都是基本的Springboot、swagger注解,这里就不在一一解释。

    3.5 运行

      至此,Springboot中API调用代码已经完成,ctrl+F5重启一下程序,输入swagger地址:http://localhost:8080/swagger-ui.html
    这里写图片描述
    点击“try it out”按钮,正常返回信息,程序运行正常:
    这里写图片描述
      OK,这篇博客先到此为止,在下一篇博客中我们重点解释如何将这个简单的springboot程序部署到腾讯云上,并且通过“域名+https”的形式代理出来,供前台接口进行调用,谢谢。

    欢迎打赏,谢谢:
    这里写图片描述

    展开全文
  • 个人微信开发API

    2019-11-25 15:16:28
    个人微信开发API微信个人号二次开发,个人微信开发API好友管理:消息管理:群管理:朋友圈:各种知名SCRM系统、客服平台都是根据此API二次开发的。 文档地址:wkteam.gitbook.io 微信个人号二次开发,个人微信开发...

    文档地址:wkteam.gitbook.io

    微信个人号二次开发,个人微信开发API

    好友管理:

    • 添加好友、
    • 删除好友、
    • 修改备注、
    • 创建标签、
    • 获取好友列表、
    • 检测僵尸粉

    消息管理:

    • 发文本消息、
    • 图片消息、
    • 名片消息、
    • 动图表情、
    • 小程序、
    • 发文件、
    • 发送视频、
    • 发送URL链接
    • 入群消息

    群管理:

    • 自动创群、
    • 修改群名称、
    • 邀请新成员、
    • 踢群成员、
    • 获取群列表、
    • 发送邀请链接、
    • 获取群聊。

    朋友圈:

    • 发送朋友圈、
    • 朋友圈点赞、
    • 获取朋友圈列表、
    • 转发朋友圈、
    • 同步朋友圈,
    • 批量发送朋友圈
    • 在这里插入图片描述
    • 在这里插入图片描述

    各种知名SCRM系统、客服平台都是根据此API二次开发的。

    文档地址:wkteam.gitbook.io

    展开全文
  • 微信API接口文档

    万次阅读 2019-05-24 01:03:22
    微信API接口文档 微信API接口文档,微信API接口,个人微信聊天接口api 微信手机客户端上传的通知类消息 1、手机客户端微信上线通知 WeChatOnlineNotice = 1020; 2、手机客户端微信下线通知 ...

    微信API接口文档

    微信API接口文档,微信API接口,个人微信聊天接口api
    微信手机客户端上传的通知类消息

    1、手机客户端微信上线通知 WeChatOnlineNotice = 1020;

    2、手机客户端微信下线通知 WeChatOfflineNotice = 1021;

    3、微信个人号新增好友通知 FriendAddNotice = 1022;

    4、微信个人号移除好友通知 FriendDelNotice = 1023;

    5、微信好友发来聊天消息 FriendTalkNotice = 1024;

    6、任务执行结果通知 TaskResultNotice = 1025;

    7、手机上回复好友的聊天消息 WeChatTalkToFriendNotice = 1026;

    8、有好友请求添加好友的通知 FriendAddReqeustNotice = 1027;

    9、手机端向服务端通知聊天执行结果 TalkToFriendTaskResultNotice = 1028;

    10、图片或视频消息的详细内容结果 RequestTalkDetailTaskResultNotice = 1029;

    11、上传手机客户端上微信的二维码 PullWeChatQrCodeTaskResultNotice = 1030;

    12、手机上发送了朋友圈通知 CircleNewPublishNotice = 1031;

    13、手机上删除朋友圈通知 CircleDelNotice = 1032;

    14、手机检测到有人点赞/取消点赞通知 CircleLikeNotice = 1033;

    15、手机检测到有人评论/删除朋友圈通知 CircleCommentNotice = 1034;

    16、消息标记为已读 PostMessageReadNotice = 1035;

    17、联系人信息上传 ContactsInfoNotice = 1036;

    18、群聊新增通知 ChatRoomAddNotice = 1037;

    19、联系人标签新增,修改通知 ContactLabelAddNotice = 1038;

    20、收钱任务执行结果通知 TakeMoneyTaskResultNotice = 1039;

    21、朋友圈图片上传 CircleDetailNotice = 1040;

    22、群聊删除通知 ChatRoomDelNotice = 1041;

    23、群聊信息变更通知 ChatRoomChangedNotice = 1042;

    24、群二维码 PullChatRoomQrCodeTaskResultNotice = 1043;

    微信API接口文档,微信API接口,个人微信聊天接口api
    服务端、客服客户端发给设备的指令类消息

    1、给好友发消息任务 TalkToFriendTask = 1070;

    2、发送朋友圈任务 PostSNSNewsTask = 1071;

    3、主动添加好友任务 AddFriendsTask = 1072;

    4、发送朋友圈任务后数据回传 PostSNSNewsTaskResultNotice = 1073;

    5、删除朋友圈 DeleteSNSNewsTask = 1074;

    6、客户端或者服务端接受好友请求通知 AcceptFriendAddRequestTask = 1075;

    7、群发消息任务 WeChatGroupSendTask = 1076;

    8、执行养号动作命令 WeChatMaintenanceTask = 1077;

    9、请求图片或视频消息的详细内容 RequestTalkDetailTask = 1078;

    10、服务端主动要求手机上传当前登录的微信二维码 PullWeChatQrCodeTask = 1079;

    11、触发手机推送好友列表任务 TriggerFriendPushTask = 1080;

    12、触发手机推送朋友圈列表任务 TriggerCirclePushTask = 1081;

    13、朋友圈评论删除任务 CircleCommentDeleteTask = 1082;

    14、朋友圈评论删除任务反馈 CircleCommentDeleteTaskResultNotice = 1083;

    15、朋友圈评论回复任务 CircleCommentReplyTask = 1084;

    16、朋友圈评论回复反馈 CircleCommentReplyTaskResultNotice = 1085;

    17、通知手机将某个聊天窗口置为已读 TriggerMessageReadTask = 1086;

    18、消息撤回 RevokeMessageTask = 1087;

    19、转发消息 ForwardMessageTask = 1088;

    20、通知手机推送聊天记录 TriggerHistoryMsgPushTask = 1089;

    21、获取群聊二维码 PullChatRoomQrCodeTask = 1090;

    微信API接口文档,微信API接口,个人微信聊天接口api
    服务端通知执行的命令

    1、服务端通知pc客户版本升级 UpgradeAppNotice = 1093;

    2、通知手机客户端软件升级 UpgradeDeviceAppNotice = 1094;

    3、清粉任务 PostFriendDetectTask = 1095;

    4、终止清粉任务 PostStopFriendDetectTask = 1096;

    5、删除设备通知 PostDeleteDeviceNotice = 1097;

    6、朋友圈点赞任务 PostMomentsPraiseTask = 1098;

    7、停止朋友圈点赞任务 PostStopMomentsPraiseTask = 1099;

    8、养号任务停止 PostStopWeChatMaintenanceTask = 1100;

    9、修改备注任务 ModifyFriendMemoTask = 1101;

    10、领取红包或转账 TakeLuckyMoneyTask = 1200;

    11、获取指定好友朋友圈 PullFriendCircleTask = 1201;

    12、获取朋友圈图片 PullCircleDetailTask = 1202;

    13、单条朋友圈点赞任务 CircleLikeTask = 1203;

    14、触发手机推送群聊列表 TriggerChatroomPushTask = 1210;

    15、请求具体群聊的详细信息 RequestChatRoomInfoTask = 1211;

    16、获取联系人详细信息(不一定是好友,如群聊成员) RequestContactsInfoTask = 1212;

    17、群聊管理 ChatRoomActionTask = 1213;

    18、群内加好友 AddFriendInChatRoomTask = 1214;

    19、通讯录加好友 AddFriendFromPhonebookTask = 1215;

    20、删除好友 DeleteFriendTask = 1216;

    21、发红包 SendLuckyMoneyTask = 1217;

    22、获取聊天消息的原始内容(主要是xml内容) RequestTalkContentTask = 1218;

    23、返回聊天消息的原始内容 RequestTalkContentTaskResultNotice = 1219;

    24、转发消息内容 ForwardMessageByContentTask = 1220;

    微信API接口文档,微信API接口,个人微信聊天接口api
    手机端主动发出的交互类消息

    1、手机端推送好友列表 FriendPushNotice = 2026;

    2、手机端推送当前安装版本 PostDeviceInfoNotice = 2027;

    3、手机端回传检测清粉好友数 PostFriendDetectCountNotice = 2028;

    4、手机回传朋友圈数据 CirclePushNotice = 2029;

    5、手机回传朋友圈点赞数量 PostMomentsPraiseCountNotice = 2030;

    9、手机端推送群聊列表 ChatroomPushNotice = 2031;

    7、手机端推送标签列表 ContactLabelInfoNotice = 2032;

    8、推送历史消息 HistoryMsgPushNotice = 2033;

    9、群成员(陌生人)信息 ChatRoomMembersNotice = 2034;

    case HeartBeatReq: {// 客户端发送的心跳包
    heartBeatReqHandler.handleMsg(ctx, msgVo);
    break;
    }
    case DeviceAuthReq: {// 设备客户端授权 设备(手机客户端、客服客户端)获取通信token请求
    deviceAuthReqHandler.handleMsg(ctx, msgVo);
    break;
    }
    case AccountForceOfflineNotice: {// 设备账号强制下线通知
    accountForceOfflineNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    / 手机客户端通知类消息 start///
    case WeChatOnlineNotice: {// 手机客户端微信上线通知
    weChatOnlineNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case WeChatOfflineNotice: {// 手机客户端微信下线通知
    weChatOfflineNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case FriendAddNotice: {// 微信个人号新增好友通知
    friendAddNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case FriendDelNotice: {// 微信个人号移除好友通知
    friendDelNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case FriendTalkNotice: {// 微信好友发来聊天消息
    friendTalkNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case TaskResultNotice: {// 任务执行结果通知
    taskResultNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case WeChatTalkToFriendNotice: {// 手机上回复好友的聊天消息
    weChatTalkToFriendNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case FriendAddReqeustNotice: {// 有好友请求添加好友的通知
    friendAddReqeustNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case TalkToFriendTaskResultNotice: {// 手机端向服务端通知聊天执行结果
    talkToFriendTaskResultNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case RequestTalkDetailTaskResultNotice: {// 图片或视频消息的详细内容结果
    requestTalkDetailTaskResultNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case PullWeChatQrCodeTaskResultNotice: {// 上传手机客户端上微信的二维码
    pullWeChatQrCodeTaskResultNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case CircleNewPublishNotice: {// 手机上发送了朋友圈通知
    circleNewPublishNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case CircleDelNotice: {// 手机上删除朋友圈通知
    circleDelNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case CircleLikeNotice: {// 手机检测到有人点赞/取消点赞通知
    circleLikeNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case CircleCommentNotice: {// 手机检测到有人评论/删除朋友圈通知
    circleCommentNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case CircleCommentReplyTaskResultNotice: {// 朋友圈评论回复反馈
    circleCommentReplyTaskResultNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case CircleCommentDeleteTaskResultNotice: {// 朋友圈评论删除任务反馈
    circleCommentDeleteTaskResultNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case PostFriendDetectCountNotice: {// 手机端回传检测清粉好友数
    postFriendDetectCountNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case CirclePushNotice: {// 手机回传朋友圈数据
    circlePushNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case PostMomentsPraiseCountNotice: {// 手机回传朋友圈点赞数
    postMomentsPraiseCountNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case PostMessageReadNotice: {// 手机端微信 消息标记为已读
    postMessageReadNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    / 手机客户端通知类消息 end
    //客服pc客户端发给设备的指令类消息 start//
    case TalkToFriendTask: {// 给好友发消息任务
    talkToFriendTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case PostSNSNewsTask: {// 发送朋友圈任务
    postSNSNewsTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case AddFriendsTask: {// 主动添加好友任务
    addFriendsTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case PostSNSNewsTaskResultNotice: {// 发送朋友圈任务后数据回传
    postSNSNewsTaskResultNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case DeleteSNSNewsTask: {// 删除朋友圈
    deleteSNSNewsTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case AcceptFriendAddRequestTask: {// 客户端或者服务端接受好友请求通知
    acceptFriendAddRequestTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case WeChatGroupSendTask: {// 群发消息任务
    weChatGroupSendTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case WeChatMaintenanceTask: {// 执行养号动作命令
    weChatMaintenanceTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case PostStopWeChatMaintenanceTask: {// 养号任务停止
    postStopWeChatMaintenanceTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case RequestTalkDetailTask: {// 请求图片或视频消息的详细内容
    requestTalkDetailTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case PullWeChatQrCodeTask: {// 服务端主动要求手机上传当前登录的微信二维码
    pullWeChatQrCodeTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case TriggerFriendPushTask: {// 触发手机推送好友列表任务
    triggerFriendPushTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case FriendPushNotice: {// 手机端推送好友列表
    friendPushNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case TriggerCirclePushTask: {// 触发手机推送朋友圈列表任务
    triggerCirclePushTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case CircleCommentDeleteTask: {// 朋友圈评论删除任务
    circleCommentDeleteTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case CircleCommentReplyTask: {// 朋友圈评论回复任务
    circleCommentReplyTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case PostFriendDetectTask: {// 清粉任务
    postFriendDetectTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case PostStopFriendDetectTask: {// 终止清粉任务
    postStopFriendDetectTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case PostMomentsPraiseTask: {// 朋友圈点赞任务
    postMomentsPraiseTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case PostStopMomentsPraiseTask: {// 停止朋友圈点赞任务
    postStopMomentsPraiseTaskHandler.handleMsg(ctx, msgVo);
    break;
    }
    case GetWeChatsReq: {// 拉取当前微信个人号列表请求
    getWeChatsReqHandler.handleMsg(ctx, msgVo);
    break;
    }
    case SyncFriendMessageAsyncReq: {// 同步好友消息数据请求
    syncFriendMessageAsyncReqHandler.handleMsg(ctx, msgVo);
    break;
    }
    case AccountLogoutNotice: {//pc客户端退出通知
    accountLogoutNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case WeChatLoginNotice: {//pc客户端选择微信号登陆/登出通知
    weChatLoginNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    case ReadChatMessageNotice: {//pc客户端 标记消息已读
    readChatMessageNoticeHandler.handleMsg(ctx, msgVo);
    break;
    }
    /客服客户端发给设备的指令类消息 end//
    //其他公共消息处理start//
    case MsgReceivedAck: {//消息接收确认回复(接收或拒绝接收)
    msgReceivedAckHandler.handleMsg(ctx, msgVo);
    break;
    }
    永久地址:https://www.wuliaokankan.cn/url301/138.html

    posted @ 2019-05-23 16:45 微信客服scrm研究中心 阅读(...) 评论(...) 编辑 收藏
    展开全文
  • 微信 API 接口

    2020-07-29 14:20:10
    网页版微信API,包含终端版微信及微信机器人 ,微信接口
  • 调用微信api时出现的问题

    千次阅读 2014-09-26 16:57:24
    微信提供的api是https而非http,https协议是基于ssl的,在调用过程中会出现抛异常的情况(估计是客户端验证服务器端不通过)。 网上有不少方法,比如忽略客户端的验证:
    微信提供的api是https而非http,https协议是基于ssl的,在调用过程中会出现抛异常的情况(估计是客户端验证服务器端不通过)。

    网上有不少方法,比如忽略客户端的验证:

    ============================================转载资料==========================================================================

    微信5.0发布

    2013年8月5日,伴随着微信5.0 iPhone版的发布,公众平台也进行了重要的更新,主要包括:

    1)运营主体为组织,可选择成为服务号或者订阅号;

    2)服务号可以申请自定义菜单;

    3)使用QQ登录的公众号,可以升级为邮箱登录;

    4)使用邮箱登录的公众号,可以修改登录邮箱;

    5)编辑图文消息可选填作者;

    6)群发消息可以同步到腾讯微博。

    其中,大家议论最多的当属前两条,就是关于帐号类型和自定义菜单的更新,我这里做几点补充说明:

    1)目前公众号类型分为两种:服务号和订阅号,8月5日平台更新后所有的帐号默认为订阅号,有一次转换成服务号的机会;

    2)服务号主要面向企业、政府和其他组织,而订阅号主要面向媒体和个人;

    3)只有服务号可以申请自定义菜单,订阅号不能申请;

    4)服务号每月只能群发一条消息,而订阅号每天能群发一条消息。

    平台更新后,让很多人纠结的是自定义菜单和每天群发一条消息不可兼得,对此,我不想过多评论。

     

    引言及内容概要

    在微信5.0以前,自定义菜单是作为一种内测资格使用的,只有少数公众帐号拥有菜单,因此出现很多企业为了弄到菜单不惜重金求购。现如今,一大批帐号从订阅号转为服务号,很多都是奔着自定义菜单去的。而且,经测试发现,微信最近的审核放松很多,只要申请服务号、自定义菜单的基本都成功了,根本不管填写的资料真伪。不知道以后微信会不会翻脸,要求补全企业资料,那将会是一种给小孩一颗糖吃再把他打哭的感觉。。。

    自定义菜单是申请到了,到底该怎么创建、怎么使用呢?最近几天不管是微信官方交流群,还是在我博客留言里,都能够看到不少开发者都在为这个发愁。本篇文章就为大家解决这个难题。

     

    自定义菜单的创建步骤

    1、找到AppId和AppSecret。自定义菜单申请成功后,在“高级功能”-“开发模式”-“接口配置信息”的最后两项就是;

    2、根据AppId和AppSecret,以https get方式获取访问特殊接口所必须的凭证access_token;

    3、根据access_token,将json格式的菜单数据通过https post方式提交。

     

    分析创建菜单的难点

    原来创建菜单这么简单,三步就能搞定?跟把大象放冰箱差不多。呵呵,当然没有这么简单,那我们一步步来看,到底难在哪里?

    首先,第1步肯定都没有问题,只要成功申请了自定义菜单,一定能拿到AppId和AppSecret这两个值。

    再来看第2步,由于是get方式获取access_token,很多人直接把拼好的url放在浏览器里执行,access_token就拿到了。抛开是不是用编程方式实现的来说,这真是个好办法,显然大家在第二步上也没有问题。

    最后再看第3步,拼装json格式的菜单数据,虽然繁锁一点,但基本上也都没有什么问题的,因为官方给了个例子,照猫画虎就行了。那问题一定就出现在https post提交上了。

    结论:不知道如何创建自定义菜单的朋友,大都可以归为以下三种情况:

    1)根本不看或者没看懂公众平台API文档中关于“通用接口”、“自定义菜单接口”和“使用限制”部分的说明;

    2)不知道如何发起HTTPS请求(平时的http请求,直接使用HttpUrlConnection就可以轻松搞定,但https请求要复杂一点);

    3)不知道如何通过POST方式提交json格式的菜单数据。

    正在看文章的你,不知道是属于哪一种,或者几种情况都有,不妨留言说出来,也可以做个调查。不管属于哪一种情况,既然看到了这篇文章,相信一定会让你弄明白的。

     

    解读通用接口文档---凭证的获取

    我们先来看通用接口文档的简介部分,如下图所示。

    通俗点讲,这段简介可以这么理解:公众平台还有很多特殊的接口,像自定义菜单的创建、语音文件的获取、主动发送消息等,如果开发者想通过HTTP请求访问这些特殊接口,就必须要有访问凭证,也就是access_token。

    那么,又该如何获取接口访问凭证access_token呢?让我们继续往下看。

    图中已经表达的很清楚了,获取access_token是通过GET方式访问如下链接:

    1. https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET  

    链接中有三个参数,分别是grant_type、appid和secret。根据图中的参数说明,grant_type传固定值client_credential,而appid和secret就是申请完自定义菜单后微信分配给我们的。

    请求发送成功后,微信服务器会返回一个json串,包含access_token和expires_in两个元素。其中,access_token就是我们最终需要的凭证,而expires_in是凭证的有效期,单位是秒,7200秒也就是2个小时。这就意味着,不是每次访问特殊接口,都需要重新获取一次access_token,只要access_token还在有效期内,就一直可以使用。

     

    解读自定义菜单接口文档

    还是一样,先来看看自定义菜单接口的简介部分,如下图所示。

    从图中我们能够获取到以下信息:

    1)拿到凭证access_token后,我们能对菜单执行三种操作:创建、查询和删除;

    2)自定义菜单目前只支持click一种事件,即用户点击后回复某种类型的消息;不能够实现点击菜单项直接打开页面(type=view未开放,目前只是微生活有);

    3)由于微信客户端缓存的原因,菜单创建后并不会立即在微信上显示出来,需要过24小时。在测试菜单创建时,可以通过取消关注后,再关注的方式达到立即看菜单的目的。

     

    继续往下看,就是关于菜单怎么创建的介绍了,如下图所示。

    其实就是向地址https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN以POST方式提交一个JSON格式的菜单字符串。

    后面,关于参数说明的部分我就不一一贴图说明了,把重点说一下:

    1)自定义菜单是一个3x5结构的,即菜单最多只能有二级,一级菜单最多只能有3个,每个一级菜单下最多可以有5个二级菜单项;

    2)菜单项都有一个key值。当用户点击某个菜单项时,微信会将该菜单项的key值以事件推送的方式发送给我们的后台处理程序。

    关于菜单的查询、创建我就不提了,这两个接口使用的频率非常小,一般都用不上。如果需要,再按照我上面提供的思路也不难理解。

     

    解读API文档之使用限制

    很多小伙伴看到这张图就开始疑惑了:怎么菜单还限制使用次数,用户量越来越大的时候,根本不够用啊。看清楚,这个限制是针对接口调用的,也就是针对开发者的,和用户数、使用次数半点关系也没有。

    就先拿获取凭证接口来说吧,限制一天只能调用200次。还记得前面提到过access_token是有有效期的,并且有效期为两小时,也就是获取一次access_token后的两小时内,都可以继续使用,那么理想情况一天24小时内,是不是只需要获取12次就够了?难道200次还不够用?

    再来看下菜单创建接口限制一天只能调用100次。我就这么解释吧,菜单创建一次后,只要你不切换模式(指的是在编辑模式和开发模式间切换)、不调用删除接口,这个菜单会永远存在的。谁没事干,一天要创建100次菜单,就算是测试,测个10次8次足够了吧?

    菜单的查询和删除接口的限制我就不解释了,至今为止这二个接口我都没使用过一次。就算有这样的使用需求,一天这么多次的调用,完全足够了。

     

    封装通用的请求方法

    读到这里,就默认大家已经掌握了上面讲到的所有关于自定义菜单的理论知识,下面就进入代码实战讲解的部分。

    先前我们了解到,创建菜单需要调用二个接口,并且都是https请求,而非http。如果要封装一个通用的请求方法,该方法至少需要具备以下能力:

    1)支持HTTPS请求;

    2)支持GET、POST两种方式;

    3)支持参数提交,也支持无参数的情况;

    对于https请求,我们需要一个证书信任管理器,这个管理器类需要自己定义,但需要实现X509TrustManager接口,代码如下:

    1. package org.liufeng.weixin.util;  
    2.   
    3. import java.security.cert.CertificateException;  
    4. import java.security.cert.X509Certificate;  
    5.   
    6. import javax.net.ssl.X509TrustManager;  
    7.   
    8. /** 
    9.  * 证书信任管理器(用于https请求) 
    10.  *  
    11.  * @author liufeng 
    12.  * @date 2013-08-08 
    13.  */  
    14. public class MyX509TrustManager implements X509TrustManager {  
    15.   
    16.     public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {  
    17.     }  
    18.   
    19.     public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {  
    20.     }  
    21.   
    22.     public X509Certificate[] getAcceptedIssuers() {  
    23.         return null;  
    24.     }  
    25. }  

    这个证书管理器的作用就是让它信任我们指定的证书,上面的代码意味着信任所有证书,不管是否权威机构颁发。

    证书有了,通用的https请求方法就不难实现了,实现代码如下:

    1. package org.liufeng.weixin.util;  
    2.   
    3. import java.io.BufferedReader;  
    4. import java.io.InputStream;  
    5. import java.io.InputStreamReader;  
    6. import java.io.OutputStream;  
    7. import java.net.ConnectException;  
    8. import java.net.URL;  
    9.   
    10. import javax.net.ssl.HttpsURLConnection;  
    11. import javax.net.ssl.SSLContext;  
    12. import javax.net.ssl.SSLSocketFactory;  
    13. import javax.net.ssl.TrustManager;  
    14.   
    15. import net.sf.json.JSONObject;  
    16.   
    17. import org.slf4j.Logger;  
    18. import org.slf4j.LoggerFactory;  
    19.   
    20. /** 
    21.  * 公众平台通用接口工具类 
    22.  *  
    23.  * @author liuyq 
    24.  * @date 2013-08-09 
    25.  */  
    26. public class WeixinUtil {  
    27.     private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);  
    28.   
    29.     /** 
    30.      * 发起https请求并获取结果 
    31.      *  
    32.      * @param requestUrl 请求地址 
    33.      * @param requestMethod 请求方式(GET、POST) 
    34.      * @param outputStr 提交的数据 
    35.      * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) 
    36.      */  
    37.     public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {  
    38.         JSONObject jsonObject = null;  
    39.         StringBuffer buffer = new StringBuffer();  
    40.         try {  
    41.             // 创建SSLContext对象,并使用我们指定的信任管理器初始化  
    42.             TrustManager[] tm = { new MyX509TrustManager() };  
    43.             SSLContext sslContext = SSLContext.getInstance("SSL""SunJSSE");  
    44.             sslContext.init(null, tm, new java.security.SecureRandom());  
    45.             // 从上述SSLContext对象中得到SSLSocketFactory对象  
    46.             SSLSocketFactory ssf = sslContext.getSocketFactory();  
    47.   
    48.             URL url = new URL(requestUrl);  
    49.             HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();  
    50.             httpUrlConn.setSSLSocketFactory(ssf);  
    51.   
    52.             httpUrlConn.setDoOutput(true);  
    53.             httpUrlConn.setDoInput(true);  
    54.             httpUrlConn.setUseCaches(false);  
    55.             // 设置请求方式(GET/POST)  
    56.             httpUrlConn.setRequestMethod(requestMethod);  
    57.   
    58.             if ("GET".equalsIgnoreCase(requestMethod))  
    59.                 httpUrlConn.connect();  
    60.   
    61.             // 当有数据需要提交时  
    62.             if (null != outputStr) {  
    63.                 OutputStream outputStream = httpUrlConn.getOutputStream();  
    64.                 // 注意编码格式,防止中文乱码  
    65.                 outputStream.write(outputStr.getBytes("UTF-8"));  
    66.                 outputStream.close();  
    67.             }  
    68.   
    69.             // 将返回的输入流转换成字符串  
    70.             InputStream inputStream = httpUrlConn.getInputStream();  
    71.             InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");  
    72.             BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  
    73.   
    74.             String str = null;  
    75.             while ((str = bufferedReader.readLine()) != null) {  
    76.                 buffer.append(str);  
    77.             }  
    78.             bufferedReader.close();  
    79.             inputStreamReader.close();  
    80.             // 释放资源  
    81.             inputStream.close();  
    82.             inputStream = null;  
    83.             httpUrlConn.disconnect();  
    84.             jsonObject = JSONObject.fromObject(buffer.toString());  
    85.         } catch (ConnectException ce) {  
    86.             log.error("Weixin server connection timed out.");  
    87.         } catch (Exception e) {  
    88.             log.error("https request error:{}", e);  
    89.         }  
    90.         return jsonObject;  
    91.     }  
    92. }  

     代码说明:

    1)41~50行:解决https请求的问题,很多人问题就出在这里;

    2)55~59行:兼容GET、POST两种方式;

    3)61~67行:兼容有数据提交、无数据提交两种情况,也有相当一部分人不知道如何POST提交数据;

     

    Pojo类的封装

    在获取凭证创建菜单前,我们还需要封装一些pojo,这会让我们的代码更美观,有条理。

    首先是调用获取凭证接口后,微信服务器会返回json格式的数据:{"access_token":"ACCESS_TOKEN","expires_in":7200},我们将其封装为一个AccessToken对象,对象有二个属性:token和expiresIn,代码如下:

    1. package org.liufeng.weixin.pojo;  
    2.   
    3. /** 
    4.  * 微信通用接口凭证 
    5.  *  
    6.  * @author liufeng 
    7.  * @date 2013-08-08 
    8.  */  
    9. public class AccessToken {  
    10.     // 获取到的凭证  
    11.     private String token;  
    12.     // 凭证有效时间,单位:秒  
    13.     private int expiresIn;  
    14.   
    15.     public String getToken() {  
    16.         return token;  
    17.     }  
    18.   
    19.     public void setToken(String token) {  
    20.         this.token = token;  
    21.     }  
    22.   
    23.     public int getExpiresIn() {  
    24.         return expiresIn;  
    25.     }  
    26.   
    27.     public void setExpiresIn(int expiresIn) {  
    28.         this.expiresIn = expiresIn;  
    29.     }  
    30. }  

    接下来是对菜单结构的封装。因为我们是采用面向对象的编程方式,最终提交的json格式菜单数据就应该是由对象直接转换得到,而不是在程序代码中拼一大堆json数据。菜单结构封装的依据是公众平台API文档中给出的那一段json格式的菜单结构,如下所示:

    1. {  
    2.     "button":[  
    3.     {     
    4.          "type":"click",  
    5.          "name":"今日歌曲",  
    6.          "key":"V1001_TODAY_MUSIC"  
    7.      },  
    8.      {  
    9.           "type":"click",  
    10.           "name":"歌手简介",  
    11.           "key":"V1001_TODAY_SINGER"  
    12.      },  
    13.      {  
    14.           "name":"菜单",  
    15.           "sub_button":[  
    16.            {  
    17.               "type":"click",  
    18.               "name":"hello word",  
    19.               "key":"V1001_HELLO_WORLD"  
    20.            },  
    21.            {  
    22.               "type":"click",  
    23.               "name":"赞一下我们",  
    24.               "key":"V1001_GOOD"  
    25.            }]  
    26.       }]  
    27. }  

    首先是菜单项的基类,所有一级菜单、二级菜单都共有一个相同的属性,那就是name。菜单项基类的封装代码如下:

    1. package org.liufeng.weixin.pojo;  
    2.   
    3. /** 
    4.  * 按钮的基类 
    5.  *  
    6.  * @author liufeng 
    7.  * @date 2013-08-08 
    8.  */  
    9. public class Button {  
    10.     private String name;  
    11.   
    12.     public String getName() {  
    13.         return name;  
    14.     }  
    15.   
    16.     public void setName(String name) {  
    17.         this.name = name;  
    18.     }  
    19. }  

    接着是子菜单项的封装。这里对子菜单是这样定义的:没有子菜单的菜单项,有可能是二级菜单项,也有可能是不含二级菜单的一级菜单。这类子菜单项一定会包含三个属性:type、name和key,封装的代码如下:

    1. package org.liufeng.weixin.pojo;  
    2.   
    3. /** 
    4.  * 普通按钮(子按钮) 
    5.  *  
    6.  * @author liufeng 
    7.  * @date 2013-08-08 
    8.  */  
    9. public class CommonButton extends Button {  
    10.     private String type;  
    11.     private String key;  
    12.   
    13.     public String getType() {  
    14.         return type;  
    15.     }  
    16.   
    17.     public void setType(String type) {  
    18.         this.type = type;  
    19.     }  
    20.   
    21.     public String getKey() {  
    22.         return key;  
    23.     }  
    24.   
    25.     public void setKey(String key) {  
    26.         this.key = key;  
    27.     }  
    28. }  

    再往下是父菜单项的封装。对父菜单项的定义:包含有二级菜单项的一级菜单。这类菜单项包含有二个属性:name和sub_button,而sub_button以是一个子菜单项数组。父菜单项的封装代码如下:

    1. package org.liufeng.weixin.pojo;  
    2.   
    3. /** 
    4.  * 复杂按钮(父按钮) 
    5.  *  
    6.  * @author liufeng 
    7.  * @date 2013-08-08 
    8.  */  
    9. public class ComplexButton extends Button {  
    10.     private Button[] sub_button;  
    11.   
    12.     public Button[] getSub_button() {  
    13.         return sub_button;  
    14.     }  
    15.   
    16.     public void setSub_button(Button[] sub_button) {  
    17.         this.sub_button = sub_button;  
    18.     }  
    19. }  

    最后是整个菜单对象的封装,菜单对象包含多个菜单项(最多只能有3个),这些菜单项即可以是子菜单项(不含二级菜单的一级菜单),也可以是父菜单项(包含二级菜单的菜单项),如果能明白上面所讲的,再来看封装后的代码就很容易理解了:

    1. package org.liufeng.weixin.pojo;  
    2.   
    3. /** 
    4.  * 菜单 
    5.  *  
    6.  * @author liufeng 
    7.  * @date 2013-08-08 
    8.  */  
    9. public class Menu {  
    10.     private Button[] button;  
    11.   
    12.     public Button[] getButton() {  
    13.         return button;  
    14.     }  
    15.   
    16.     public void setButton(Button[] button) {  
    17.         this.button = button;  
    18.     }  
    19. }  

    关于POJO类的封装就介绍完了。

     

    凭证access_token的获取方法

    继续在先前通用请求方法的类WeixinUtil.java中加入以下代码,用于获取接口访问凭证:

    1. // 获取access_token的接口地址(GET) 限200(次/天)  
    2. public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";  
    3.   
    4. /** 
    5.  * 获取access_token 
    6.  *  
    7.  * @param appid 凭证 
    8.  * @param appsecret 密钥 
    9.  * @return 
    10.  */  
    11. public static AccessToken getAccessToken(String appid, String appsecret) {  
    12.     AccessToken accessToken = null;  
    13.   
    14.     String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret);  
    15.     JSONObject jsonObject = httpRequest(requestUrl, "GET"null);  
    16.     // 如果请求成功  
    17.     if (null != jsonObject) {  
    18.         try {  
    19.             accessToken = new AccessToken();  
    20.             accessToken.setToken(jsonObject.getString("access_token"));  
    21.             accessToken.setExpiresIn(jsonObject.getInt("expires_in"));  
    22.         } catch (JSONException e) {  
    23.             accessToken = null;  
    24.             // 获取token失败  
    25.             log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));  
    26.         }  
    27.     }  
    28.     return accessToken;  
    29. }  


    自定义菜单的创建方法

    继续在先前通用请求方法的类WeixinUtil.java中加入以下代码,用于创建自定义菜单:

    1. // 菜单创建(POST) 限100(次/天)  
    2. public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";  
    3.   
    4. /** 
    5.  * 创建菜单 
    6.  *  
    7.  * @param menu 菜单实例 
    8.  * @param accessToken 有效的access_token 
    9.  * @return 0表示成功,其他值表示失败 
    10.  */  
    11. public static int createMenu(Menu menu, String accessToken) {  
    12.     int result = 0;  
    13.   
    14.     // 拼装创建菜单的url  
    15.     String url = menu_create_url.replace("ACCESS_TOKEN", accessToken);  
    16.     // 将菜单对象转换成json字符串  
    17.     String jsonMenu = JSONObject.fromObject(menu).toString();  
    18.     // 调用接口创建菜单  
    19.     JSONObject jsonObject = httpRequest(url, "POST", jsonMenu);  
    20.   
    21.     if (null != jsonObject) {  
    22.         if (0 != jsonObject.getInt("errcode")) {  
    23.             result = jsonObject.getInt("errcode");  
    24.             log.error("创建菜单失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));  
    25.         }  
    26.     }  
    27.   
    28.     return result;  
    29. }  

     

    调用封装的方法创建自定义菜单

    1. package org.liufeng.weixin.main;  
    2.   
    3. import org.liufeng.weixin.pojo.AccessToken;  
    4. import org.liufeng.weixin.pojo.Button;  
    5. import org.liufeng.weixin.pojo.CommonButton;  
    6. import org.liufeng.weixin.pojo.ComplexButton;  
    7. import org.liufeng.weixin.pojo.Menu;  
    8. import org.liufeng.weixin.util.WeixinUtil;  
    9. import org.slf4j.Logger;  
    10. import org.slf4j.LoggerFactory;  
    11.   
    12. /** 
    13.  * 菜单管理器类 
    14.  *  
    15.  * @author liufeng 
    16.  * @date 2013-08-08 
    17.  */  
    18. public class MenuManager {  
    19.     private static Logger log = LoggerFactory.getLogger(MenuManager.class);  
    20.   
    21.     public static void main(String[] args) {  
    22.         // 第三方用户唯一凭证  
    23.         String appId = "000000000000000000";  
    24.         // 第三方用户唯一凭证密钥  
    25.         String appSecret = "00000000000000000000000000000000";  
    26.   
    27.         // 调用接口获取access_token  
    28.         AccessToken at = WeixinUtil.getAccessToken(appId, appSecret);  
    29.   
    30.         if (null != at) {  
    31.             // 调用接口创建菜单  
    32.             int result = WeixinUtil.createMenu(getMenu(), at.getToken());  
    33.   
    34.             // 判断菜单创建结果  
    35.             if (0 == result)  
    36.                 log.info("菜单创建成功!");  
    37.             else  
    38.                 log.info("菜单创建失败,错误码:" + result);  
    39.         }  
    40.     }  
    41.   
    42.     /** 
    43.      * 组装菜单数据 
    44.      *  
    45.      * @return 
    46.      */  
    47.     private static Menu getMenu() {  
    48.         CommonButton btn11 = new CommonButton();  
    49.         btn11.setName("天气预报");  
    50.         btn11.setType("click");  
    51.         btn11.setKey("11");  
    52.   
    53.         CommonButton btn12 = new CommonButton();  
    54.         btn12.setName("公交查询");  
    55.         btn12.setType("click");  
    56.         btn12.setKey("12");  
    57.   
    58.         CommonButton btn13 = new CommonButton();  
    59.         btn13.setName("周边搜索");  
    60.         btn13.setType("click");  
    61.         btn13.setKey("13");  
    62.   
    63.         CommonButton btn14 = new CommonButton();  
    64.         btn14.setName("历史上的今天");  
    65.         btn14.setType("click");  
    66.         btn14.setKey("14");  
    67.   
    68.         CommonButton btn21 = new CommonButton();  
    69.         btn21.setName("歌曲点播");  
    70.         btn21.setType("click");  
    71.         btn21.setKey("21");  
    72.   
    73.         CommonButton btn22 = new CommonButton();  
    74.         btn22.setName("经典游戏");  
    75.         btn22.setType("click");  
    76.         btn22.setKey("22");  
    77.   
    78.         CommonButton btn23 = new CommonButton();  
    79.         btn23.setName("美女电台");  
    80.         btn23.setType("click");  
    81.         btn23.setKey("23");  
    82.   
    83.         CommonButton btn24 = new CommonButton();  
    84.         btn24.setName("人脸识别");  
    85.         btn24.setType("click");  
    86.         btn24.setKey("24");  
    87.   
    88.         CommonButton btn25 = new CommonButton();  
    89.         btn25.setName("聊天唠嗑");  
    90.         btn25.setType("click");  
    91.         btn25.setKey("25");  
    92.   
    93.         CommonButton btn31 = new CommonButton();  
    94.         btn31.setName("Q友圈");  
    95.         btn31.setType("click");  
    96.         btn31.setKey("31");  
    97.   
    98.         CommonButton btn32 = new CommonButton();  
    99.         btn32.setName("电影排行榜");  
    100.         btn32.setType("click");  
    101.         btn32.setKey("32");  
    102.   
    103.         CommonButton btn33 = new CommonButton();  
    104.         btn33.setName("幽默笑话");  
    105.         btn33.setType("click");  
    106.         btn33.setKey("33");  
    107.   
    108.         ComplexButton mainBtn1 = new ComplexButton();  
    109.         mainBtn1.setName("生活助手");  
    110.         mainBtn1.setSub_button(new CommonButton[] { btn11, btn12, btn13, btn14 });  
    111.   
    112.         ComplexButton mainBtn2 = new ComplexButton();  
    113.         mainBtn2.setName("休闲驿站");  
    114.         mainBtn2.setSub_button(new CommonButton[] { btn21, btn22, btn23, btn24, btn25 });  
    115.   
    116.         ComplexButton mainBtn3 = new ComplexButton();  
    117.         mainBtn3.setName("更多体验");  
    118.         mainBtn3.setSub_button(new CommonButton[] { btn31, btn32, btn33 });  
    119.   
    120.         /** 
    121.          * 这是公众号xiaoqrobot目前的菜单结构,每个一级菜单都有二级菜单项<br> 
    122.          *  
    123.          * 在某个一级菜单下没有二级菜单的情况,menu该如何定义呢?<br> 
    124.          * 比如,第三个一级菜单项不是“更多体验”,而直接是“幽默笑话”,那么menu应该这样定义:<br> 
    125.          * menu.setButton(new Button[] { mainBtn1, mainBtn2, btn33 }); 
    126.          */  
    127.         Menu menu = new Menu();  
    128.         menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 });  
    129.   
    130.         return menu;  
    131.     }  
    132. }  

    注意:在运行以上代码时,需要将appId和appSecret换成你自己公众号的。

     

    整个工程的结构

    为了保证文章的完整独立性和可读性,我是新建了一个Java Project(Java web工程也可以,没有太大关系),没有在前几篇文章所讲到的weixinCourse工程中添加代码。如果需要,读者可以自己实现将菜单创建的代码移到自己已有的工程中去。

    图中所有Java文件的源代码都在文章中贴出并进行了说明,图中使用到的jar也是Java开发中通用的jar包,很容易在网上下载到。

    工程中引入的jar包主要分为两类:

    1)第一类是json开发工具包,用于Java对象和Json字符串之间的转换;json开发工具包一共有3个jar:ezmorph-1.0.6.jar,json-lib-2.2.3-jdk13.jar和morph-1.1.1.jar。

    2)第二类是slf4j日志工具包,用于记录系统运行所产生的日志,日志可以输出到控制台或文件中。

    整个工程中,唯一没有讲到的是src下的log4j.properties的配置,也把它贴出来,方便大家参考,这样才是一个完整的工程源码。log4j.properties文件的内容如下:

    1. log4j.rootLogger=info,console,file  
    2.   
    3. log4j.appender.console=org.apache.log4j.ConsoleAppender  
    4. log4j.appender.console.layout=org.apache.log4j.PatternLayout  
    5. log4j.appender.console.layout.ConversionPattern=[%-5p] %m%n  
    6.   
    7. log4j.appender.file=org.apache.log4j.DailyRollingFileAppender  
    8. log4j.appender.file.DatePattern='-'yyyy-MM-dd  
    9. log4j.appender.file.File=./logs/weixinmpmenu.log  
    10. log4j.appender.file.Append=true  
    11. log4j.appender.file.layout=org.apache.log4j.PatternLayout  
    12. log4j.appender.file.layout.ConversionPattern=[%-5p] %d %37c %3x - %m%n  

     

    如何响应菜单点击事件
    自定义菜单的创建工作已经完成,那么该如何接收和响应菜单的点击事件呢,也就是说在公众帐号后台处理程序中,如何识别用户点击的是哪个菜单,以及做出响应。这部分内容其实在教程的第5篇各种消息的接收与响应中已经讲解清楚了。

    来看一下第一篇教程weixinCourse项目中的CoreService类要怎么改写,才能接收响应菜单点击事件,该类修改后的完整代码如下:

    1. package org.liufeng.course.service;  
    2.   
    3. import java.util.Date;  
    4. import java.util.Map;  
    5.   
    6. import javax.servlet.http.HttpServletRequest;  
    7.   
    8. import org.liufeng.course.message.resp.TextMessage;  
    9. import org.liufeng.course.util.MessageUtil;  
    10.   
    11. /** 
    12.  * 核心服务类 
    13.  *  
    14.  * @author liufeng 
    15.  * @date 2013-05-20 
    16.  */  
    17. public class CoreService {  
    18.     /** 
    19.      * 处理微信发来的请求 
    20.      *  
    21.      * @param request 
    22.      * @return 
    23.      */  
    24.     public static String processRequest(HttpServletRequest request) {  
    25.         String respMessage = null;  
    26.         try {  
    27.             // 默认返回的文本消息内容  
    28.             String respContent = "请求处理异常,请稍候尝试!";  
    29.   
    30.             // xml请求解析  
    31.             Map<String, String> requestMap = MessageUtil.parseXml(request);  
    32.   
    33.             // 发送方帐号(open_id)  
    34.             String fromUserName = requestMap.get("FromUserName");  
    35.             // 公众帐号  
    36.             String toUserName = requestMap.get("ToUserName");  
    37.             // 消息类型  
    38.             String msgType = requestMap.get("MsgType");  
    39.   
    40.             // 回复文本消息  
    41.             TextMessage textMessage = new TextMessage();  
    42.             textMessage.setToUserName(fromUserName);  
    43.             textMessage.setFromUserName(toUserName);  
    44.             textMessage.setCreateTime(new Date().getTime());  
    45.             textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);  
    46.             textMessage.setFuncFlag(0);  
    47.   
    48.             // 文本消息  
    49.             if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {  
    50.                 respContent = "您发送的是文本消息!";  
    51.             }  
    52.             // 图片消息  
    53.             else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {  
    54.                 respContent = "您发送的是图片消息!";  
    55.             }  
    56.             // 地理位置消息  
    57.             else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {  
    58.                 respContent = "您发送的是地理位置消息!";  
    59.             }  
    60.             // 链接消息  
    61.             else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {  
    62.                 respContent = "您发送的是链接消息!";  
    63.             }  
    64.             // 音频消息  
    65.             else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {  
    66.                 respContent = "您发送的是音频消息!";  
    67.             }  
    68.             // 事件推送  
    69.             else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {  
    70.                 // 事件类型  
    71.                 String eventType = requestMap.get("Event");  
    72.                 // 订阅  
    73.                 if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {  
    74.                     respContent = "谢谢您的关注!";  
    75.                 }  
    76.                 // 取消订阅  
    77.                 else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {  
    78.                     // TODO 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息  
    79.                 }  
    80.                 // 自定义菜单点击事件  
    81.                 else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {  
    82.                     // 事件KEY值,与创建自定义菜单时指定的KEY值对应  
    83.                     String eventKey = requestMap.get("EventKey");  
    84.   
    85.                     if (eventKey.equals("11")) {  
    86.                         respContent = "天气预报菜单项被点击!";  
    87.                     } else if (eventKey.equals("12")) {  
    88.                         respContent = "公交查询菜单项被点击!";  
    89.                     } else if (eventKey.equals("13")) {  
    90.                         respContent = "周边搜索菜单项被点击!";  
    91.                     } else if (eventKey.equals("14")) {  
    92.                         respContent = "历史上的今天菜单项被点击!";  
    93.                     } else if (eventKey.equals("21")) {  
    94.                         respContent = "歌曲点播菜单项被点击!";  
    95.                     } else if (eventKey.equals("22")) {  
    96.                         respContent = "经典游戏菜单项被点击!";  
    97.                     } else if (eventKey.equals("23")) {  
    98.                         respContent = "美女电台菜单项被点击!";  
    99.                     } else if (eventKey.equals("24")) {  
    100.                         respContent = "人脸识别菜单项被点击!";  
    101.                     } else if (eventKey.equals("25")) {  
    102.                         respContent = "聊天唠嗑菜单项被点击!";  
    103.                     } else if (eventKey.equals("31")) {  
    104.                         respContent = "Q友圈菜单项被点击!";  
    105.                     } else if (eventKey.equals("32")) {  
    106.                         respContent = "电影排行榜菜单项被点击!";  
    107.                     } else if (eventKey.equals("33")) {  
    108.                         respContent = "幽默笑话菜单项被点击!";  
    109.                     }  
    110.                 }  
    111.             }  
    112.   
    113.             textMessage.setContent(respContent);  
    114.             respMessage = MessageUtil.textMessageToXml(textMessage);  
    115.         } catch (Exception e) {  
    116.             e.printStackTrace();  
    117.         }  
    118.   
    119.         return respMessage;  
    120.     }  
    121. }  

    代码说明:

    1)第69行、第81行这两行代码说明了如何判断菜单的点击事件。当消息类型MsgType=event,并且Event=CLICK时,就表示是自定义菜单点击事件;

    2)第83行是判断具体点击的是哪个菜单项,根据菜单的key值来判断;

    3)第85~109行表示当用户点击某个菜单项后,具体返回什么消息,我只是做个简单示例,统一返回文本消息,读者可以根据实际需要来灵活处理。

     

    总结

    到这里关于自定义菜单的创建、菜单事件的判断和处理响应就全部介绍完了。我只希望看过文章的人不要只是拷贝代码,如果是这样,我完全不用花这么多的时间来写这篇文章,直接把工程放在下载区多简单。另外,网上是有很多工具,让你填入appid,appsecret和菜单结构,提交就能创建菜单,请慎用!因为appid和appsecret一旦告诉别人,你的公众号的菜单控制权就在别人手上了,总会有别有用心的人出来搞点事的。

     

    如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号xiaoqrobot支持柳峰!

    转帖请注明本文出自柳峰的博客(http://blog.csdn.net/lyq8479),请尊重他人的辛勤劳动成果,谢谢!

    ================================================================================================================

    另外一种方法:


    ====================================转载资料=====================================

    SSL自签名的实现类org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory

    分类: JAVA实用笔记 1043人阅读 评论(1) 收藏 举报
    如果是编写的一个通用的客户端,可以用于支持访问所有的HTTP及HTTPS协议请求,这个时候SSL自签名就非常管用了,如soupUI,它是一款用于WEBSERVICE的性能及压力测试工具,可以访问所有的HTTPS请求,并且不需要我们指定trustStore。通过查看其源代码,原来它使用的就是SSL自签名的实现类org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory,有了它,在访问任何HTTPS的时候都不需要指定trustStore了。

    当然这个是有安全问题的,这个自签名的API中也有明确的提示,尽量不要用于生产环境,用于平时的测试过程中是可以的。使用是非常简单的,只需要在发起请求前将SSL自签名API注册到Protocol中即可:

    1. EasySSLProtocolSocketFactory easySSL = null;  
    2. try {  
    3.     easySSL = new EasySSLProtocolSocketFactory();  
    4. catch (Exception e) {  
    5.     // TODO Auto-generated catch block  
    6.     e.printStackTrace();  
    7. }  
    8. Protocol easyhttps = new Protocol( "https", ( ProtocolSocketFactory )easySSL, 443 );  
    9. Protocol.registerProtocol( "https", easyhttps );  

    如果你使用HttpClient,那么这个时候只需要在使用HttpClient发起请求之前执行这段注册代码即可。

    通常的trustStore的注册方式,可以查看这篇文章 http://blog.csdn.net/fenglibing/article/details/16842543

    =========================================================================


    展开全文
  • 您对这个post请求做了应答(格式为文本),则该应答会通过微信平台投递到您粉丝的微信应用上。 微信开发者中心的文档将这种行为称为“被动回复用户消息”: 回复消息报文的格式在开发者文档里也有清晰的定义,是...
  • 微信API整理(1)——微信常用API

    千次阅读 2018-08-02 11:55:19
    整理一下微信API文档,以备未来开发,本文API内容为常用的微信开发API整理,内容有待完善...... package cn.vision.weixindemo.utils.base.API; public class WeiXin_API { // 授权类 /** * 获取授权Token *...
  • 微信API接口整理

    2017-06-09 11:26:10
    总结的一些微信API接口,包括微信支付、微信红包、微信卡券、微信小店等。 微信入口绑定,微信事件处理,微信API全部操作包含在这些文件中。 微信支付、微信红包、微信卡券、微信小店。 [代码]index.php  include...
  • 微信API证书过期,获取API证书

    万次阅读 2019-04-29 19:45:29
    在做微信如:(退款、企业红包、企业付款)提现这些操作的时候,微信返回(具体哪个字段我忘记了)的信息是:证书过期,那么就需要重新获取证书,证书的获取前提条件: 1:你需要有微信商户平台的商户号(类似电话号码的数字)...
  • vue调用微信API

    千次阅读 2018-06-21 10:05:36
    cnpm install weixin-js-sdk2,在vue的main中引入并将其挂在到vue实例上 import wx from 'weixin-js-sdk' Vue.prototype.wx = wx3,各个组件中如果需要使用的话 输出一下this.wx就可以知道是否能掉到wx的API了...
  • 企业微信API接口

    千次阅读 2019-12-20 15:22:01
    对于众多企业来说企业微信是一个新的机遇,企业微信API接口功能也让众多企业备受关注。 企业微信服务端API: 企业微信服务端开放了丰富的API,企业的开发者能够凭借接口,实现企业特有的服务和与企业微信的集成。...
  • 简单封装一个调用企业微信API程序发送文本,图片,及文件消息。
  • Python学习-Itchat微信API

    万次阅读 2017-03-10 13:09:54
    Itchat-微信API接口for python说明 Itchat是用python对微信API的封装 支持发送消息、图片、视频、地图、名片、文件等 支持热登陆,不用每次登陆都要扫描二维码 支持上传中文文件 简单示例1:自动回复 code#coding=...
  • 前阵子部署zabbix监控系统,做了个微信报警,下面分享下微信API发消息的脚本。要用微信发消息,自己首先要有微信企业号,如果没有申请也容易 准备工作:1.申请微信企业号2.在企业号后台创建应用3.关注微信企业号 ...
  • 微信api接入验证的坑!!!

    千次阅读 2019-01-17 23:19:35
    一、这是官方文档的接入讲解 ...这儿第二步就是微信接口验证了,看官方文档说的那几个发来的参数的确是get过来的啊 但是我这样写 //1.得到微信发过来的timestamp,nonce,token,signature变量 $timestam...
  • 微信API给指定的用户发送消息

    千次阅读 2019-08-14 10:36:04
    API:https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=23_4ql1vcosifp2Px1ivVWrMXJE1OupGuu5H-B36jrZ4bQgzLhk2xeSvXlD 参数: 执行结果: 要获取更多Jerry的原创文章,请关注公众号"汪子熙...
  • 大家可能经常看到一些微信公众号具有功能强大的自定义菜单,点击之后可以访问很...那么用什么API创建这些自定义菜单呢?微信公众号平台技术文档中,点击”自定义菜单”: 文档里给了创建自定义菜单需要维护参数的H...
  • http://blog.csdn.net/u012591761/article/details/42263009 现在我们给应用添加一个功能,能在应用内将消息分享给微信好友,或者分享到朋友圈中。 我们首先来到微信开放平台官网,跟着组织走,官网指南: ...
  • 想想将个人微信变为一个机器人也是很好玩的,这个项目就教你如何把自己的微信变为一个聊天机器人,嗯~对的,和小冰差不多的感觉吧(哈哈哈~)。 最终效果图: 效果图 原理: 通过微信的Python接口itchat获取...
  • 使用微信API实现H5页面播放音频文件

    千次阅读 2019-06-03 09:50:24
    之前在处理H5页面播放音频文件的时候,总是需要搞一个https才能正常播放,一次无意浏览到了一个自动播放音频的页面,发现了使用微信Api可以不使用https也能播放音频文件。作为记录,简单页面实现如下: <!...
1 2 3 4 5 ... 20
收藏数 167,701
精华内容 67,080
关键字:

微信api