2019-05-23 16:52:00 weixin_30950237 阅读数 174
  • Web应用开发(上)

    准确掌握案例分析真题的重点、难点、能有效地做针对性复习 能快速将案例分析真题过一遍

    27824课时 0分钟 0人学习 黄星
    免费试看

个人微信开发api文档,个人微信开发sdk,个人微信开发协议接口
微信开发sdk服务端调用接口
1、基础消息类型
1、客户端发送的心跳包 HeartBeatReq = 1001;

2、消息接收确认回复(接收或拒绝接收) MsgReceivedAck = 1002;

3、错误单独提升为一种消息类型 Error = 1003;

2、设备客户端授权类消息

1、设备(手机客户端、客服客户端)获取通信token请求 DeviceAuthReq = 1010;

2、设备(手机客户端、客服客户端)获取通信token响应 DeviceAuthRsp = 1011;

3、设备授权后退出(仅用于服务端内部) DeviceExitNotice = 1012;

4、账号强制下线通知 AccountForceOfflineNotice = 1013;

个人微信开发api文档,个人微信开发sdk,个人微信开发协议接口
3、手机客户端上传的通知类消息

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文档,个人微信开发sdk,个人微信开发协议接口
4、服务端、客服客户端发给设备的指令类消息

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文档,个人微信开发sdk,个人微信开发协议接口
5、服务端通知执行的命令

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文档,个人微信开发sdk,个人微信开发协议接口
6、手机端主动发出的交互类消息

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;

个人微信开发api文档,个人微信开发sdk,个人微信开发协议接口
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;
}

个人微信开发api文档,个人微信开发sdk,个人微信开发协议接口,SDK的功能API列表

微信加好友功能API

1、导入手机通讯录

2、手机通讯录加好友

3、加指定微信群好友

4、自动通过微信好友请求

5、手机模拟定位

6、附近人加好友

7、各种账号加好友(QQ号、手机号、微信号)

8、陌陌自动回复引流加好友

9、探探自动回复引流加好友

10、摇一摇打招呼加好友

个人微信开发api文档,个人微信开发sdk,个人微信开发协议接口
微信群发功能API

1、微信群发好友(文字、图片、长短视频、链接、名片)

2、微信群发群(文字、图片、长短视频、链接、名片)

3、微信群发收藏(文字、图片、长短视频、链接、名片)

4、按标签群发、指定好友群发

个人微信开发api文档,个人微信开发sdk,个人微信开发协议接口
微信群管理功能API

1、入群欢迎语

2、指定群管理员

3、群管理统计(活跃度、发言数、总人数、邀请数、退出数等)

4、群管理员踢人、群消息警告

5、群关键词回复,群智能客服

6、建群、拉人功能接口

7、多群消息同步

8、群成员关系链

9、群二维码、群公告

10、群资料整理

个人微信开发api文档,个人微信开发sdk,个人微信开发协议接口
微信营销功能API

1、发朋友圈(图文、链接、长短视频)

2、发长视频到微信朋友圈

3、朋友圈点赞,按比例点赞,按数量点赞

4、发漂流瓶信息

5、智能自动回复

6、同步指定微信好友朋友圈

7、红包、转账

个人微信开发api文档,个人微信开发sdk,个人微信开发协议接口
微信聊天对话功能API

1、微信上线通知

2、微信下线通知

3、微信新增好友通知

4、微信删除好友通知

5、微信好友发来信息通知

6、回复微信好友聊天消息、聊天消息撤回

7、聊天执行结果通知

8、获取微信通讯录好友列表

9、获取群列表

10、好友请求添加好友的通知

11、获取手机客户端上微信的二维码

个人微信开发api文档,个人微信开发sdk,个人微信开发协议接口
微信营销辅助工具API

1、打开微信

2、定时执行任务

3、任务执行结果通知

4、清理僵尸粉

5、清理微信空间

6、智能随机养号

7、智能抢红包服务

8、微信运动智能点赞

9、提取指定朋友圈内容

10、关注指定公众号

个人微信开发api文档,个人微信开发sdk,个人微信开发协议接口
永久地址 https://www.wuliaokankan.cn/url301/138.html

转载于:https://www.cnblogs.com/wuliaokankan/p/10912926.html

2018-01-20 18:01:45 Cs_hnu_scw 阅读数 19097
  • Web应用开发(上)

    准确掌握案例分析真题的重点、难点、能有效地做针对性复习 能快速将案例分析真题过一遍

    27824课时 0分钟 0人学习 黄星
    免费试看

     最近的话,发现微信开发其实也有很多挺有意思的地方,比如最近很火的一款游戏“跳一跳”,也让我如此着迷。。但是,今天我所要讲的并不是对于小程序的开发,而是要说一下,关于微信开发的另外一个内容,那就是微信公众号。。

    关于,什么是微信公众号,微信公众号怎么申请,这个我就不多说,这些基本的概念不在这里进行讲解,自己可以直接百度就可以找到很多的资源。而我主要讲解一下关于微信公众号开发中,一些比较重要和常见的知识点,所以,这个也并不是基础篇的文章哦~!好歹也要对微信公众号有一点了解才行。~!

一:实现外网域名访问本地服务项目

描述:我们在刚开始接触微信公众号开发的时候,我想,一般情况下,很多人都是没有服务器的,简单点说,就是没有服务器IP,或者是公网访问的域名。然而,要想能够实现微信公众能能够与我们后台代码进行交互,那么肯定就需要有一个公网能够访问的地址,那么这怎么办好呢?

解法一:很简单呀,直接去新浪云,阿里云,华为云,买一个服务器呗,而且是学生的话,还有优惠,多好。。但是,这个又比较繁琐,里面又有配置内容啥的,一堆(比如,tomcat,mysql,jdk等等)。那么,看看第二种方法。。。。(但是,请记住,这个是想做服务端开发必须会的,如果你连部署项目都不会,你觉得公司对你的感觉如何?多一个技能就是一个优势)

解法二:反向代理。。如果,你是第一次听说这个名词,那么就赶紧恶补一下,这个名词的含义。我简单点说,就是通过反向代理的模式,来代理你本地的ip,以便能够在公网地址能够访问到本地的项目。。具体,请看下面,如何进行~!~!

步骤:(1)下载ogrok客户端---------也就是反向代理的客户端,当然还有很多类似的,我这里就使用这个而已。

这个可以通过该链接进行下载ogrok下载链接

(2)解压刚下载好的客户端文件到自己的一个目录下

(3)通过cmd命令,进入DOS,并且进入到刚刚解压的ogrok目录下

(4)执行 ngrok -config=ngrok.cfg -subdomain xxx 8080 //(xxx 是你自定义的域名前缀)

比如,我这里就是xxx就是用myjavttest

结果:

(5)这样的话,我们就可以通过上面的地址进行访问本地的项目了。(原来都是用的localhost:8080/login.jsp或者127.0.0.1:8080/login.jsp),当然,前提是本地有一个开启的项目,这样才可以,别本地都没有项目开启,就用公网去访问,你觉得,它能够访问么?所以,请别忘记这一点。

(二)微信公众号客户端与后台进行验证身份

首先,我们通过第一步,我们就能够得到一个以公网地址访问的一个IP(域名),那么既然要使得微信公众号能够与后台进行关联,那么肯定需要配置微信公众号的具体对应的服务器地址了。

步骤:(1)首先,进入微信公众号开发官网,并且进行登陆

(2)

(3)

(4)

OK,配置到这个的话,就简单的,将基本的配置进行设置好了。。那么,下面才是关键,进入真正的开发阶段。。

如果微信端,要与后台进行关联,那么当用户进行与后台交互的时候,后台就需要采取,身份验证,而这个是通过GET方式的请求,而只有通过的才可以进行后续的处理。所以,如何进行,那么就看下面的代码:这里讲解两种形式~~~~

第一种:(采取Servlet)

@WebServlet(name = "ConnectWeChatServlet")
public class ConnectWeChatServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }

    /**
     * 进行验证是否身份匹配
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        System.out.println(""+signature +"@"+timestamp +"$"+nonce +"^"+echostr);
        PrintWriter out = response.getWriter();
        if(CheckConnectUtils.checkConncetWithWeChat(signature,timestamp,nonce)){
            out.print(echostr);
        }
    }

验证的代码:

package com.hnu.scw.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
 * @author scw
 * @create 2018-01-17 9:28
 * @desc 检查微信和服务器是否链接成功
 **/
public class CheckConnectUtils {
    private static final String token = "wechat"; //这个就是微信公众号之前配置的token,必须保持一致
    /**
     * 判断是否链接匹配
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkConncetWithWeChat(String signature,String timestamp,String nonce){
        String[] arr = new String[]{token,timestamp,nonce};
        //排序
        Arrays.sort(arr);
        //生成字符串
        StringBuilder stringBuilder = new StringBuilder();
        for (String str:arr) {
            stringBuilder.append(str);
        }
        //进行SHA1加密
        String encodeString = passSha1Encode(stringBuilder.toString());
        if(signature.equals(encodeString)){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 字符串进行SHA1加密
     * @param str
     * @return
     */
    public static String passSha1Encode(String str){
        if(str == null || str.length() == 0){
            return null;
        }
        char hexDigits[] = {'0','1','2','3','4','5','6','7','8','9'
        ,'a','b','c','d','e','f'};
        try{
            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
            mdTemp.update(str.getBytes());
            byte[] md = mdTemp.digest();
            int j = md.length;
            char[] buf = new char[j*2];
            int k = 0;
            for(int i=0 ; i <j ; i++){
                byte byte0 = md[i];
                buf[k++] = hexDigits[byte0 >>>4 & 0xf];
                buf[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(buf);
        } catch (NoSuchAlgorithmException e) {
           return null;
        }
    }
}

第二种:(采取框架,比如SpringMVC+Spring+Hibernate)

/**
 * @author scw
 * @create 2018-01-18 11:38
 * @desc 微信前端连接的主要控制类
 **/
@Controller
public class WeChatDogPrimaryController {
    /**
     * 进行微信用户验证,只能是Get方法
     * @param request
     * @param response
     */
    @RequestMapping(value = "/wechat" ,method = RequestMethod.GET)
    public void connectValidate(HttpServletRequest request , HttpServletResponse response) throws IOException {
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        System.out.println(""+signature +"@"+timestamp +"$"+nonce +"^"+echostr);
        PrintWriter out = response.getWriter();
        if(CheckConnectUtils.checkConncetWithWeChat(signature,timestamp,nonce)){
            out.print(echostr);
        }
    }


    /**
     * 客户端进行的消息处理
     * @param request
     * @param response
     */
    @RequestMapping(value = "/wechat" ,method = RequestMethod.POST)
    public void disposeClientMessage(HttpServletRequest request , HttpServletResponse response ) throws IOException {
      
    }

(三)微信客户端与后台进行消息交互(比如,文本,图片,视频,音频)

消息的实体类:

package com.hnu.scw.model;

/**
 * @author scw
 * @create 2018-01-17 13:37
 * @desc 对于所有消息的基本父类
 **/
public class BaseMessage {
    private String ToUserName;
    private String FromUserName;
    private String CreateTime;
    private String MsgType;

    public String getToUserName() {
        return ToUserName;
    }

    public void setToUserName(String toUserName) {
        ToUserName = toUserName;
    }

    public String getFromUserName() {
        return FromUserName;
    }

    public void setFromUserName(String fromUserName) {
        FromUserName = fromUserName;
    }

    public String getCreateTime() {
        return CreateTime;
    }

    public void setCreateTime(String createTime) {
        CreateTime = createTime;
    }

    public String getMsgType() {
        return MsgType;
    }

    public void setMsgType(String msgType) {
        MsgType = msgType;
    }
}
package com.hnu.scw.model;

/**
 * @author SCW
 * @create 2018-01-17 15:08
 * @desc 图片的基本类
 **/
public class ImageBase {
    private String MediaId;

    public String getMediaId() {
        return MediaId;
    }

    public void setMediaId(String mediaId) {
        MediaId = mediaId;
    }
}
package com.hnu.scw.model;

/**
 * @author scw
 * @create 2018-01-17 15:09
 * @desc 图片消息
 **/
public class ImageMessage extends BaseMessage {
    private ImageBase Image ;

    public ImageBase getImageBase() {
        return Image;
    }

    public void setImageBase(ImageBase Image) {
        this.Image = Image;
    }
}
package com.hnu.scw.model;

/**
 * @author Administrator
 * @create 2018-01-17 16:45
 * @desc 音乐类型的基本类
 **/
public class MusicBase {
    private String Title;
    private String Description;
    private String MusicUrl;
    private String HQMusicUrl;
    private String ThumbMediaId;

    public String getTitle() {
        return Title;
    }

    public void setTitle(String title) {
        Title = title;
    }

    public String getDescription() {
        return Description;
    }

    public void setDescription(String description) {
        Description = description;
    }

    public String getMusicUrl() {
        return MusicUrl;
    }

    public void setMusicUrl(String musicUrl) {
        MusicUrl = musicUrl;
    }

    public String getHQMusicUrl() {
        return HQMusicUrl;
    }

    public void setHQMusicUrl(String HQMusicUrl) {
        this.HQMusicUrl = HQMusicUrl;
    }

    public String getThumbMediaId() {
        return ThumbMediaId;
    }

    public void setThumbMediaId(String thumbMediaId) {
        ThumbMediaId = thumbMediaId;
    }
}
package com.hnu.scw.model;

/**
 * @author Administrator
 * @create 2018-01-17 16:46
 * @desc 用于包装音乐的实体
 **/
public class MusicMessage extends BaseMessage {
    private MusicBase Music;

    public MusicBase getMusic() {
        return Music;
    }

    public void setMusic(MusicBase music) {
        Music = music;
    }
}
package com.hnu.scw.model;

/**
 * @author scw
 * @create 2018-01-17 10:03
 * @desc 文本消息的内容
 **/
public class MyTestMessage  extends BaseMessage{
    private String Content;
    private String  MsgId;

    public String getContent() {
        return Content;
    }

    public void setContent(String content) {
        Content = content;
    }

    public String getMsgId() {
        return MsgId;
    }

    public void setMsgId(String msgId) {
        MsgId = msgId;
    }
}
package com.hnu.scw.model;

/**
 * @author scw
 * @create 2018-01-17 13:38
 * @desc 对于图文消息最内层结构的实体类
 **/
public class NewsBase {
    private String Title;
    private String Description;
    private String PicUrl;
    private String Url;

    public String getTitle() {
        return Title;
    }

    public void setTitle(String title) {
        Title = title;
    }

    public String getDescription() {
        return Description;
    }

    public void setDescription(String description) {
        Description = description;
    }

    public String getPicUrl() {
        return PicUrl;
    }

    public void setPicUrl(String picUrl) {
        PicUrl = picUrl;
    }

    public String getUrl() {
        return Url;
    }

    public void setUrl(String url) {
        Url = url;
    }
}
package com.hnu.scw.model;

import java.util.List;

/**
 * @author scw
 * @create 2018-01-17 13:35
 * @desc 对于图文消息的实体类
 **/
public class NewsMessage extends BaseMessage{
    private int ArticleCount;
    private List<NewsBase> Articles;

    public int getArticleCount() {
        return ArticleCount;
    }

    public void setArticleCount(int articleCount) {
        ArticleCount = articleCount;
    }

    public List<NewsBase> getArticles() {
        return Articles;
    }

    public void setArticles(List<NewsBase> articles) {
        Articles = articles;
    }
}

消息封装工具类:

package com.hnu.scw.utils;
import com.hnu.scw.model.*;
import com.thoughtworks.xstream.XStream;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author scw
 * @create 2018-01-17 9:52
 * @desc 用户转换消息的格式
 **/
public class MessageUtils {
    /**
     * 定义多种消息类型
     */
    public static final String MESSAGE_TEXT = "text";
    public static final String MESSAGE_IMAGE = "image";
    public static final String MESSAGE_VOICE = "voice";
    public static final String MESSAGE_MUSIC = "music";
    public static final String MESSAGE_VIDEO = "video";
    public static final String MESSAGE_LINK = "link";
    public static final String MESSAGE_LOCATION = "location";
    public static final String MESSAGE_EVENT = "event";
    public static final String MESSAGE_SUBSCRIBE = "subscribe";
    public static final String MESSAGE_UNSUBSCRIBE = "unsubscribe";
    public static final String MESSAGE_CLICK = "CLICK";
    public static final String MESSAGE_VIEW = "VIEW";
    //扫码事件
    public static final String MESSAGE_SCANCODE = "scancode_push";

    /**
     * XML格式转为map格式
     * @param request
     * @return
     */
    public static Map<String , String> xmlToMap(HttpServletRequest request){
        Map<String ,String> map = new HashMap<String , String>();
        try {
            InputStream inputStream =null;
            inputStream = request.getInputStream();
            SAXReader reader = new SAXReader();
            Document doc = reader.read(inputStream);
            Element rootElement = doc.getRootElement();
            List<Element> elements = rootElement.elements();
            for (Element el:elements) {
                map.put(el.getName() , el.getText());
            }
            inputStream.close();
            return map ;
        } catch (Exception e) {
            e.printStackTrace();
            return null ;
        }
    }
    /**
     * 文本消息对象转为xml格式
     * @param myTestMessage
     * @return
     */
    public static String textMessage2Xml(MyTestMessage myTestMessage){
        XStream xStream = new XStream();
        xStream.alias("xml" , myTestMessage.getClass());
        return xStream.toXML(myTestMessage);
    }
    /**
     * 将图文消息对象转化为图文格式的XML
     * @return
     */
    public static String newsMessage2XML(NewsMessage newsMessage){
        XStream xStream = new XStream();
        //将需要修改的一些标签进行替换
        xStream.alias("xml" , newsMessage.getClass());
        xStream.alias("item" , new NewsBase().getClass());
        return xStream.toXML(newsMessage);
    }
    /**
     * 设置需要返回的图文信息
     * @param fromUserName
     * @param toUserName
     * @return
     */
    public static String initNewSMessage(String fromUserName , String toUserName ){
        String message = null;
        List<NewsBase> newList = new ArrayList<NewsBase>();
        NewsMessage newsMessage = new NewsMessage();
        NewsBase  newsBase = new NewsBase();
        newsBase.setTitle("我是图文消息");
        newsBase.setDescription("测试测试测试测试测试测试测试测试测试");
    newsBase.setPicUrl("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=677717294,4155848424&fm=27&gp=0.jpg")
        newsBase.setUrl("www.baidu.com");
        //添加图文消息的内容
        newList.add(newsBase);

        //注意接受消息和发送消息的顺序要反过来,因为现在是从服务器进行发送了,而客户端是接收端了
        newsMessage.setFromUserName(toUserName);
        newsMessage.setToUserName(fromUserName);
        newsMessage.setCreateTime(String.valueOf(System.currentTimeMillis()));
        newsMessage.setMsgType("news");
        newsMessage.setArticleCount(newList.size());
        newsMessage.setArticles(newList);
        //调用转为图文的XML
        return MessageUtils.newsMessage2XML(newsMessage);
    }
    /**
     * 设置需要返回的文本信息
     * @param fromUserName
     * @param toUserName
     * @param content
     * @return
     */
    public static String initText(String fromUserName , String toUserName , String content){
        MyTestMessage text = new MyTestMessage();
        //注意接受消息和发送消息的顺序要烦过来
        text.setFromUserName(toUserName);
        text.setToUserName(fromUserName);
        text.setMsgType(MessageUtils.MESSAGE_TEXT);
        long time = System.currentTimeMillis();
        text.setCreateTime(String.valueOf(time));
        text.setContent(content);
        return MessageUtils.textMessage2Xml(text);
    }
    /**
     * 设置订阅时,返回菜单的内容
     * @return
     */
    public static String menuText(){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("菜单1:回复数字1,有惊喜\n");
        stringBuilder.append("菜单2:回复数字2,有惊喜\n");
        stringBuilder.append("菜单3:回复数字3,有惊喜\n");
        stringBuilder.append("菜单4:回复数字3,有惊喜\n");
        stringBuilder.append("菜单5:回复数字3,有惊喜\n");
        stringBuilder.append("菜单6:回复数字未知的东东,也还有有惊喜哦\n");
        return stringBuilder.toString();
    }
    /**
     * 回复关键字"1"的时候的内容
     * @return
     */
    public static String inputNumber1(){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("我是惊喜111,哈哈,惊喜不惊喜!");
        return stringBuilder.toString();
    }
    /**
     * 回复关键字"2"的时候的内容
     * @return
     */
    public static String inputNumber2(){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("我是惊喜2222,哈哈,惊喜不惊喜!");
        return stringBuilder.toString();
    }
    /**
     * 返回图片消息(对于视频和音频都是一样的方式,只需要更改类型即可,即将Image修改为video,voice)
     * @param fromUserName
     * @param toUserName
     * @return
     */
    public static String initImageMessage(String fromUserName , String toUserName ){
        ImageBase imageBase = new ImageBase();
        //这个media_Id是在之前执行过上传图片返回得到的信息
        imageBase.setMediaId("HK17wQmCupESK4B9u14PqI4w3gtteXhUtGgriJW6G5c8O-Y0OsjGbYfQYhGDbYDx");
        ImageMessage imageMessage = new ImageMessage();
        imageMessage.setFromUserName(toUserName);
        imageMessage.setToUserName(fromUserName);
        imageMessage.setMsgType(MessageUtils.MESSAGE_IMAGE);
        long time = System.currentTimeMillis();
        imageMessage.setCreateTime(String.valueOf(time));
        imageMessage.setImageBase(imageBase);
        return imageMessage2XML(imageMessage);
    }
    /**
     * 将图片消息对象转化为图片格式的XML
     * @return
     */
    public static String imageMessage2XML(ImageMessage imageMessage){
        XStream xStream = new XStream();
        //将需要修改的一些标签进行替换
        xStream.alias("xml" , imageMessage.getClass());
        xStream.alias("Image" , new ImageBase().getClass());
        return xStream.toXML(imageMessage);
    }
    /**
     * 将音乐消息对象转化为图片格式的XML
     * @return
     */
    public static String musicMessage2XML(MusicMessage musicMessage){
        XStream xStream = new XStream();
        //将需要修改的一些标签进行替换
        xStream.alias("xml" , musicMessage.getClass());
        xStream.alias("Music" , new MusicBase().getClass());
        return xStream.toXML(musicMessage);
    }
    /**
     * 返回音乐消息
     * @param fromUserName
     * @param toUserName
     * @return
     */
    public static String initMusicMessage(String fromUserName , String toUserName ){
        MusicBase musicBase = new MusicBase();
        //这个ThumbMediaId是在之前执行过上传缩略图返回得到的信息(这个和上传图片的方法是一样的,都是调用pictureUtils中的上传方法)
        musicBase.setThumbMediaId("vJOi5E4_U91onQnsayPdkzxted6ZctEAEzcoLd3BJ8a00gJLuhEmTckF6S2XkS5R");
        musicBase.setTitle("来一首音乐");
        musicBase.setDescription("静静的听首歌吧!");
        //设置高质量音质的歌曲路径,可以和一般音质音乐的路径一样
        musicBase.setHQMusicUrl("http://myjava.ngrok.xiaomiqiu.cn/resource/mymusic.mp3");
        //设置音乐的路径
        musicBase.setMusicUrl("http://myjava.ngrok.xiaomiqiu.cn/resource/mymusic.mp3");
        MusicMessage musicMessage = new MusicMessage();
        musicMessage.setFromUserName(toUserName);
        musicMessage.setToUserName(fromUserName);
        //设置类型为音乐
        musicMessage.setMsgType(MessageUtils.MESSAGE_MUSIC);
        long time = System.currentTimeMillis();
        musicMessage.setCreateTime(String.valueOf(time));
        musicMessage.setMusic(musicBase);
        return musicMessage2XML(musicMessage);
    }
}

交互主类:

package com.hnu.scw.controller;
import com.hnu.scw.utils.CheckConnectUtils;
import com.hnu.scw.utils.MessageUtils;
import com.hnu.scw.utils.WeiXinUserInfoUtiols;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
/**
 * @author scw
 * @create 2018-01-18 11:38
 * @desc 微信前端连接的主要控制类
 **/
@Controller
public class WeChatDogPrimaryController {
    /**
     * 进行微信用户验证,只能是Get方法
     * @param request
     * @param response
     */
    @RequestMapping(value = "/wechat" ,method = RequestMethod.GET)
    public void connectValidate(HttpServletRequest request , HttpServletResponse response) throws IOException {
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        System.out.println(""+signature +"@"+timestamp +"$"+nonce +"^"+echostr);
        PrintWriter out = response.getWriter();
        if(CheckConnectUtils.checkConncetWithWeChat(signature,timestamp,nonce)){
            out.print(echostr);
        }
    }
    /**
     * 客户端进行的消息处理
     * @param request
     * @param response
     */
    @RequestMapping(value = "/wechat" ,method = RequestMethod.POST)
    public void disposeClientMessage(HttpServletRequest request , HttpServletResponse response ) throws IOException {
        backTestFunction(request , response );
    }
    /**
     * 文字回复功能开发
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    public void backTestFunction(HttpServletRequest request , HttpServletResponse response ) throws IOException {
        //防止进行post提交和响应的消息乱码
        request.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "text/html;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        try{
            //将发送过来的消息XML形式转为map内容
            Map<String , String> map = MessageUtils.xmlToMap(request);
            String fromUserName = map.get("FromUserName");
            String toUserName = map.get("ToUserName");
            String msgType = map.get("MsgType");
            String content = map.get("Content");
            String message = null ;
            if(MessageUtils.MESSAGE_TEXT.equals(msgType)){
                //进行关键字回复功能
                if("1".equals(content)){
                    message = MessageUtils.initText(fromUserName,toUserName,MessageUtils.inputNumber1());
                }else if("2".equals(content)){
                    message = MessageUtils.initText(fromUserName,toUserName,MessageUtils.inputNumber2());
                }
                else if("3".equals(content)){
                    //客户端输入“3”,返回一条图文消息
                    message = MessageUtils.initNewSMessage(fromUserName,toUserName);
                }else if("4".equals(content)){
                    //客户端输入“4”,返回一条图片消息
                    message = MessageUtils.initImageMessage(fromUserName,toUserName);
                }else if("5".equals(content)){
                    //客户端输入“5”,返回一首音乐消息
                    message = MessageUtils.initMusicMessage(fromUserName,toUserName);
                }else if("6".equals(content)){
                    //测试是否能够获取用户的信息
                    message = MessageUtils.initText(fromUserName,toUserName, WeiXinUserInfoUtiols.getUserInfo(fromUserName));
                }else if(content.startsWith("翻译")){
                    //客户端输入“以翻译开头”,返回对应的翻译信息
                    /*String translateResult = TranslationUtils.translate(content.substring(2,content.length()));
                    message = MessageUtils.initText(fromUserName,toUserName , translateResult);*/
                }else {
                    message = MessageUtils.initText(fromUserName,toUserName,"你发送的消息是:" + content);
                }
            }else if(MessageUtils.MESSAGE_EVENT.equals(msgType)){
                String eventType = map.get("Event");
                //完成订阅时候返回的内容
                if(MessageUtils.MESSAGE_SUBSCRIBE .equals(eventType)){
                    message = MessageUtils.initText(fromUserName,toUserName , MessageUtils.menuText());
                }else if(MessageUtils.MESSAGE_CLICK .equals(eventType)){
                    //进行的是click按钮的点击事件(这里就推送一下主菜单内容)
                    message = MessageUtils.initText(fromUserName,toUserName , MessageUtils.menuText());
                }else if(MessageUtils.MESSAGE_VIEW .equals(eventType)){
                    //进行的是view按钮的点击事件(这里就推送一下主菜单内容)
                    String viewUrl = map.get("EventKey");
                    message = MessageUtils.initText(fromUserName,toUserName , viewUrl);
                }else if(MessageUtils.MESSAGE_SCANCODE .equals(eventType)) {
                    //进行的是扫码事件
                    String key = map.get("EventKey");
                    message = MessageUtils.initText(fromUserName,toUserName , key);
                }
            }else if(MessageUtils.MESSAGE_LOCATION .equals(msgType)) {
                //进行的是地理位置信息
                String label = map.get("Label");
                message = MessageUtils.initText(fromUserName,toUserName , label);
            }
            //打印输出的xml格式内容,方便进行调试
            System.out.println(message);
            out.print(message);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            out.close();
        }
    }
}

(四)获取Access_Token

Access_Token是一个全局的票据,调用任何的高级接口,都需要这个,所以这个非常非常的重要

具体代码:

package com.hnu.scw.utils;
import com.hnu.scw.menu.BaseButton;
import com.hnu.scw.menu.ClickButton;
import com.hnu.scw.menu.CustomeMenu;
import com.hnu.scw.menu.ViewButton;
import com.hnu.scw.model.AccessToken;
import com.hnu.scw.projectconst.ProjectConst;
import net.sf.json.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;

import javax.servlet.ServletContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

/**
 * @author scw
 * @create 2018-01-17 14:13
 * @desc 用户获取access_token,众号调用各接口时都需使用access_token
 **/
public class WeiXinUtils {
    /**
     * 微信公众号的APPID和Appsecret,这个是每个微信公众号都唯一的,以后配置不同的公众号配置这里即可
     */
    private static final String APPID = "自己公众号对应的内容";
    private static final String APPSECRET = "自己公众号对应的内容";
    //获取access_token的URL
    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

    //进行创建菜单的接口URL
    private static final String CREATE_MENU_URL ="https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";

    //菜单查询的接口URL
    private static final String QUERY_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN";

    //菜单删除的接口URL
    private static final String DELETE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";

    /**
     * Get请求,方便到一个url接口来获取结果
     * @param url
     * @return
     */
    public static JSONObject doGetStr(String url){
        DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(url);
        JSONObject jsonObject = null;
        try{
            HttpResponse response = defaultHttpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if(entity != null){
                String result = EntityUtils.toString(entity, "UTF-8");
                jsonObject = JSONObject.fromObject(result);
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * 带参数的post请求,方便到一个url接口来获取结果
     * @param url
     * @param outStr
     * @return
     */
    public static JSONObject doPostStr(String url , String outStr)  {
        DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        JSONObject jsonObject = null;
        try {
            httpPost.setEntity(new StringEntity(outStr , "UTF-8"));
            HttpResponse response = defaultHttpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            if(entity != null){
                String result = EntityUtils.toString(entity, "UTF-8");
                jsonObject = JSONObject.fromObject(result);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * 获取access_token
     * @return
     */
    public static AccessToken getAccessToken(){
        AccessToken accessToken = new AccessToken();
        String url = ACCESS_TOKEN_URL.replace("APPID" ,APPID).replace("APPSECRET",APPSECRET);
        JSONObject jsonObject = doGetStr(url);
        if(jsonObject !=null){
            accessToken.setToken(jsonObject.getString("access_token"));
            accessToken.setExpireIn(jsonObject.getLong("expires_in"));
        }
        return accessToken;
    }

测试是否成功获取:

package com.hnu.scw.test;
import com.hnu.scw.model.AccessToken;
import com.hnu.scw.utils.WeiXinAccessTokenKeepAlive;
import com.hnu.scw.utils.WeiXinUtils;
import org.junit.Test;
/**
 * @author scw
 * @create 2018-01-18 15:21
 * @desc 用于对Access_token内容相关的测试
 **/
public class AccessTokenTest {
    /**
     * 获取到Access_Token,这个对于要想使用其他的微信接口,就必须要有这个进行验证
     */
    @Test
    public void getAccssTokenTest(){
        AccessToken accessToken = WeiXinUtils.getAccessToken();
        System.out.println("token:" +accessToken.getToken());
        System.out.println("有效时间:" +accessToken.getExpireIn());
    }
}

(五)自定义菜单

下面的代码,就接着(四)中的类写就可以了,因为都属于微信开发的工具类

步骤:

(1)创建菜单按钮的实体对象类

BaseButton:

package com.hnu.scw.menu;
/**
 * @author scw
 * @create 2018-01-17 17:20
 * @desc 最基础的Button
 **/
public class BaseButton {
    private String type;
    private String name;
    //子按钮(也可以理解为二级菜单)
    private BaseButton[] sub_button;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BaseButton[] getSub_button() {
        return sub_button;
    }

    public void setSub_button(BaseButton[] sub_button) {
        this.sub_button = sub_button;
    }
}

clickButton:

package com.hnu.scw.menu;
/**
 * @author Administrator
 * @create 2018-01-17 17:21
 * @desc Click类型的Button实体
 **/
public class ClickButton extends BaseButton {
    private String key;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }
}

viewButton:

package com.hnu.scw.menu;
/**
 * @author scw
 * @create 2018-01-17 17:22
 * @desc 类型是View的按钮实体
 **/
public class ViewButton extends BaseButton{
    private String url;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

CustomerMenu菜单定义:

package com.hnu.scw.menu;
/**
 * @author scw
 * @create 2018-01-17 17:23
 * @desc 自定义菜单的实体
 **/
public class CustomeMenu {
    //对菜单按钮进行封装
    private BaseButton[] button;

    public BaseButton[] getButton() {
        return button;
    }

    public void setButton(BaseButton[] button) {
        this.button = button;
    }
}

(2)调用接口,进行菜单的创建

 /**
     * 设置菜单的形式
     * @return
     */
    public static CustomeMenu initMenu(){
        CustomeMenu customeMenu = new CustomeMenu();
        ClickButton clickButton = new ClickButton();
        clickButton.setName("click菜单");
        clickButton.setType("click");
        clickButton.setKey("01");

        ViewButton viewButton = new ViewButton();
        viewButton.setName("view菜单");
        viewButton.setType("view");
        viewButton.setUrl("需要访问的地址");

        ClickButton clickButton2 = new ClickButton();
        clickButton2.setName("扫码事件的click菜单");
        clickButton2.setType("scancode_push");
        clickButton2.setKey("02");

        ClickButton clickButton3 = new ClickButton();
        clickButton3.setName("地理位置的click菜单");
        clickButton3.setType("location_select");
        clickButton3.setKey("03");

        BaseButton baseButton = new BaseButton();
        baseButton.setName("菜单");
        //将clickButton2,clickButton3作为一个子菜单中的按钮
        baseButton.setSub_button(new BaseButton[]{clickButton2,clickButton3});
        //把按钮分别放入到菜单中
        customeMenu.setButton(new BaseButton[]{clickButton,viewButton,baseButton});

        return customeMenu;
    }

    /**
     * 创建自定义菜单
     * @param token
     * @param menu
     * @return
     */
    public static int createMenu(String token , String menu){
        int result = 0;
        String url = CREATE_MENU_URL.replace("ACCESS_TOKEN" ,token);
        JSONObject jsonObject = doPostStr(url, menu);
        if(jsonObject != null){
            //接受返回回来的参数,如果是0,就是创建成功
            result = jsonObject.getInt("errcode");
        }
        return result;
    }

    /**
     * 对菜单进行查询
     * @param token
     * @return
     */
    public static JSONObject queryMenu(String token){
        String url = QUERY_MENU_URL.replace("ACCESS_TOKEN" ,token);
        JSONObject jsonObject = doGetStr(url);
        return jsonObject;
    }

    /**
     * 对菜单进行删除
     * @param token
     * @return
     */
    public static JSONObject deleteMenu(String token){
        String url = DELETE_MENU_URL.replace("ACCESS_TOKEN" ,token);
        JSONObject jsonObject = doGetStr(url);
        return jsonObject;
    }

(3)生成菜单

package com.hnu.scw.test;
import com.hnu.scw.model.AccessToken;
import com.hnu.scw.utils.WeiXinUtils;
import net.sf.json.JSONObject;
import org.junit.Test;
/**
 * @author scw
 * @create 2018-01-18 15:21
 * @desc 菜单相关的测试
 **/
public class MenuTest {
    /**
     * 创建菜单
     */
    @Test
    public void creatMenuTest(){
        //获取到access_token
        AccessToken accessToken = WeiXinUtils.getAccessToken();
        //获取到自定义菜单的格式(JSONObject将对象转为json,然后再需要转为字符串型)
        String menu = JSONObject.fromObject(WeiXinUtils.initMenu()).toString();
        //调用创建菜单
        int result = WeiXinUtils.createMenu(accessToken.getToken(), menu);
        if(result == 0){
            //如果调用方法之后,返回的是0,那么就表示创建成功。
            System.out.println("创建成功");
        }else{
            System.out.println("创建失败");
        }
    }
    /**
     * 查询菜单
     */
    @Test
    public void queryMenuTest(){
        //获取到access_token
        AccessToken accessToken = WeiXinUtils.getAccessToken();
        //调用菜单查询的方法,返回是的一个Json格式
        JSONObject jsonObject = WeiXinUtils.queryMenu(accessToken.getToken());
        System.out.println(jsonObject);
    }
    /**
     * 删除菜单
     */
    @Test
    public void deleteMenuTest(){
        //获取到access_token
        AccessToken accessToken = WeiXinUtils.getAccessToken();
        //调用菜单查询的方法,返回是的一个Json格式
        JSONObject jsonObject = WeiXinUtils.deleteMenu(accessToken.getToken());
        if(jsonObject.getInt("errcode") == 0){
            //返回0,表示的是删除成功
            System.out.println("删除成功");
        }else{
            System.out.println("删除失败");
        }

    }
}

       上面就是一些基本的微信公众号的交互了,刚刚接触可能不是很熟,慢慢的就了解了之后,其实也很简单的,当然,对于其中的一些高级接口的使用,可以看看我其他的文章,都有提到。。如果有问题,不明白的地方,欢迎进行交流和留言~!另外,推荐了比较好的学习资源,就是慕课网,这里面对于比较基础的微信公众号开发还是讲解的比较好,再结合我的文章,肯定是没有任何问题的。。。。

Github的地址:

https:https://github.com/qq496616246/WeChatCode.git

git地址:git@github.com:qq496616246/WeChatCode.git

2018-12-21 15:26:07 wang178yang 阅读数 4091
  • Web应用开发(上)

    准确掌握案例分析真题的重点、难点、能有效地做针对性复习 能快速将案例分析真题过一遍

    27824课时 0分钟 0人学习 黄星
    免费试看

我们在关注微信公众号点击菜单回复关键词或者执行程序中的某些事件(比如,订单提交成功等。)的时候,可以看到,有些公众号同时给我们回复了两条或两条以上的消息内容。

内容形式不限于文字,可能是这些消息类型:文本为text,图片为image,语音为voice,视频消息为video,音乐消息为music,图文消息(点击跳转到外链)为news,图文消息(点击跳转到图文消息页面)为mpnews,卡券为wxcard,小程序为miniprogrampage

如果给用户发送的是图片/语音/视频等媒体文件时,需要通过素材上传接口,先上传媒体文件,获取media_id

先看看效果:

下面以ecshop的微信通为例来进行讲解(其它程序也类似):
这里以$keyword == 'debug' 即回复关键字”debug“为例(如果需要在用户关注公众号时回复多条,可以在 $keyword == 'subscribe' 条件中处理),来回复用户 文本+ 图片+ 文本

打开站点根目录下的wechat/callback-ent.php文件,搜索if ($keyword == 'debug')(如果该条件下有内容,先删除),因为需要回复的消息中有一条是图片,这里我们先通过素材上传接口上传需要的图片到微信公众号的素材库中(假设服务器根目录下images/qrcode/shop.png图片已经存在):

上传图片到微信公众号的素材管理库并回复用户该图片:

//从数据库 获取access_token
$ret = $db->getRow("SELECT `access_token` FROM ". $GLOBALS['ecs']->table('weixin_config'));
$access_token = $ret['access_token'];


//通过 上传素材接口 获取media_id(如果已经上传并知道media_id,这段不需要,直接在下面需要media_id的地方写上值即可)
$file_path = dirname(dirname(__FILE__))."/images/qrcode/shop.png";//图片在本地服务器上的路径
$file_data = array('media'  => '@'.$file_path);
if(strlen($access_token) >= 64)
{
    $imgurl = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=".$access_token."&type=image";
    $imgres_json =$this -> https_request($imgurl, $file_data);
    $imgjson = json_decode($imgres_json);
}
$media_id = $imgjson->media_id;


//回复用户图片
$imgmsgType = "image";
$imgresultStr = sprintf($imageTpl, $fromUsername, $toUsername, $time, $imgmsgType, $media_id);
echo $imgresultStr;
exit;

//回复用户文本消息示例
/*$msgType = "text";
$contentStr = $media_id."——".$access_token."——".$fromUsername;
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
echo $resultStr;
exit;*/


上面的代码主要演示通过素材上传接口上传图片并获取其media_id,然后回复用户该图片,为了实现回复用户两条或两条以上的消息,下面我们使用客服接口:

为了讲解方便,我们还在if ($keyword == 'debug')条件中写,记下上面得到的media_id值(可以通过回复文本的形式输出查看media_id的值),然后把上面的代码换成下面这样:

//从数据库 获取access_token
$ret = $db->getRow("SELECT `access_token` FROM ". $GLOBALS['ecs']->table('weixin_config'));
$access_token = $ret['access_token'];


//回复第一条 文本
$content1="点击菜单微商城或扫描下方二维码,即可进入商城随心购,更有惊喜等您发现!";
$this->replymsg($fromUsername,$access_token,$content1);

//回复第二条 图片
$mediaid = "Wa1Zo-yWRj-uGKRm-leGMVuYn3Sh3EcNehZPgJPcTR0";
$this->replyimg($fromUsername,$access_token,$mediaid);

//回复第三条 文本
$content2="很高兴能收到您的消息,想了解更多资讯或如需帮助,请添加客服微信";
$this->replymsg($fromUsername,$access_token,$content2);

exit;

在wechat/callback-ent.php文件中添加replymsg、replyimg、https_post函数:

private function replymsg($fromUsername,$access_token,$content){

    $data = '{
        "touser":"'.$fromUsername.'",
        "msgtype":"text",
        "text":
        {
             "content":"'.$content.'"
        }
    }';

    $url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=".$access_token;

    $result = $this->https_post($url,$data);
    $final = json_decode($result);
    return $final;
}

private function replyimg($fromUsername,$access_token,$media_id){

    $data = '{
        "touser":"'.$fromUsername.'",
        "msgtype":"image",
        "image":
        {
             "media_id":"'.$media_id.'"
        }
    }';

    $url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=".$access_token;

    $result = $this->https_post($url,$data);
    $final = json_decode($result);
    return $final;
}

private function https_post($url,$data)
{
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($curl, CURLOPT_POST, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    $result = curl_exec($curl);
    if (curl_errno($curl)) {
       return 'Errno'.curl_error($curl);
    }
    curl_close($curl);
    return $result;
}

2016-12-30 16:18:00 myuantao3286286 阅读数 11876
  • Web应用开发(上)

    准确掌握案例分析真题的重点、难点、能有效地做针对性复习 能快速将案例分析真题过一遍

    27824课时 0分钟 0人学习 黄星
    免费试看

相信对于大多数的微信公众号开发的初学者来说,由于微信提供的文档过于简洁,所以这无疑是对我们的巨大考验。

但是,苦心人,天不负。在强烈的“我能行”这一自我暗示下,经过在各大网站上的查询、电子书籍类的读阅,经过无数次的尝试,终于能够实现一次事件同时回复用户多条信息的功能了。额,不说废话了,下面展示我的最终成果。 

(公众号是接管过来自己开发的)

首先,创建公众号子菜单的点击事件

const APPID = '你的微信appid';
	const SECRET = '你的secret';
	const ACCESS_TOKEN_URL = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=';
	const GET_MENU_URL = 'https://api.weixin.qq.com/cgi-bin/menu/get?access_token=';
	const CREATE_MENU_URL = 'https://api.weixin.qq.com/cgi-bin/menu/create?access_token=';


/** 
	* createmenu 
	* 创建菜单 
	* @access public 
	* @param void
	* @since 1.0 
	* @return array 
	*/ 
	public function actioncreatemenu()
	{
		$access_token_url = self::ACCESS_TOKEN_URL.self::APPID.'&secret='.self::SECRET;
		$wdata =json_decode($this->curl_get($access_token_url),true);
		$create_menu_url = self::CREATE_MENU_URL.$wdata['access_token'];
		$menu = json_encode($this->getMenuConfig(),JSON_UNESCAPED_UNICODE);
		$data = $this->curl_post($create_menu_url,$menu);
		echo $data;exit;
	}
private function getMenuConfig()
	{
		$data = array();
		$data = Array(

				'button' => Array(
						 Array(
							'name' => '你关心的',
							'sub_button' => Array(
										Array(
											'type' => 'click',
											'name' => '邀友有礼',
											'key' => 'V1001_INVITE_GIFT'
											)
														
										)
							)
)
}

public function curl_post($url, $data)
	{
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
		curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		$output = curl_exec($ch);
		if (curl_errno($ch)) {
		return curl_error($ch);
		}

		curl_close($ch);
		return $output;

	}


然后在网页运行 createmenu方法,微信公众号菜单就创建好了。

这些都是前期的准备。

下面是点击事件的处理

$this->sendIMG($media_id , $open_id , $token);
这行代码中的 media_id ,是通过微信接口上传媒体素材返回的微信独有的标识,上传素材的代码在最后面展示

	libxml_disable_entity_loader(true);
        $postObj = simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
        $fromUsername = $postObj->FromUserName;
        $toUsername = $postObj->ToUserName;
        $event = $postObj->Event;
        $time = $postObj->CreateTime;
	$open_id = trim($fromUsername);
	$MsgType = $postObj->MsgType;
	file_put_contents('/tmp/test.log', $MsgType, FILE_APPEND);
switch ($event) {
case 'CLICK':
			$token = $this->token();
			$this->sendText($open_id , $token);
				
			$resultIMG = '图片相对于服务器下的路径';
			$media_id = $this->add_m($resultIMG);
			$this->sendIMG($media_id , $open_id , $token);
			/*	
			$returnTpl = "<xml>
					<ToUserName><![CDATA[%s]]></ToUserName>
					<FromUserName><![CDATA[%s]]></FromUserName>
					<CreateTime>%s</CreateTime>
					<MsgType><![CDATA[%s]]></MsgType>
					<Image>
						<MediaId><![CDATA[%s]]></MediaId>
					</Image>
				</xml>";
			$resultStr = sprintf($returnTpl,$fromUsername , $toUsername , time(), 'image'  ,$media_id);
			echo $resultStr;	*/			
		break;
}

function sendText($open_id , $token) {
		$data = '{ "touser" : "'.$open_id.'",
						"msgtype" : "text",
						"text" : {
							"content" : "敬请期待" 
						}
					}';
		$url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=".$token;
		$result = $this->https_request($url , $data);
		var_dump($result);
	}
	
	function sendIMG($media_id , $open_id , $token) {
		$data = '{ "touser" : "'.$open_id.'",
						"msgtype" : "image",
						"image" : {
							"media_id" : "'.$media_id.'" 
						}
					}';
		$url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=".$token;
		$result = $this->https_request($url , $data);
		var_dump($result);
	}

上传媒体素材,这里上传的是图片,所以传的参数则是一张图片的路径

function add_m($img) {
		
		$path = '这里填写图片上传的相对路径'.$img ;  
		//$img = 'web/image/qrcode/20161229/10.jpg';
		if (class_exists ( '\CURLFile' )) {//关键是判断curlfile,官网推荐php5.5或更高的版本使用curlfile来实例文件  
			$filedata = array (  
				'fieldname' => new \CURLFile ( realpath ( $path ), 'image/jpeg' )   
			);  
		} else {  
			$filedata = array (  
				'fieldname' => '@' . realpath ( $path )   
			);  
		}  
		$url = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=".$this->token()."&type=image";
        $result = $this->https_request($url , $filedata);
		$data = json_decode($result);
       return $data->media_id;
}
(通过 path ,必须能够在服务器下访问到图片)


最后,说明一下,我的图片是能都通过网络访问到的,比如(http://www.image.****.com)

但是,当我将这个图片的地址添加到上传媒体素材进行上传的时候,结果是上传失败,也就没有了本来应该返回的 media_id,所以采用了获取路径上传的方法

在这里如果有更好的方法,欢迎留言艾特我,大家相互交流,共同进步!!!

2018-08-12 20:12:21 i042416 阅读数 2580
  • Web应用开发(上)

    准确掌握案例分析真题的重点、难点、能有效地做针对性复习 能快速将案例分析真题过一遍

    27824课时 0分钟 0人学习 黄星
    免费试看

我之前的文章 微信程序开发系列教程(一)开发环境搭建 介绍了微信开发环境的搭建,这篇文章我们就来一步步开发一些具体的功能。

功能需求:当有微信用户关注了您的公众号之后,您用JavaScript发送一个欢迎消息给这个粉丝。

具体实现

我们登陆微信公众号的控制台后,点开发-> 基本配置:

能看到我们配置的微信消息服务器的地址。在我第一篇教程里讲到,我们在本地用nodejs开发一个Web服务器,然后部署到您喜欢的云平台,比如腾讯云,阿里云,百度云等等(我选的是云平台Heroku),然后把部署后应用的url维护到微信公众号控制台的服务器配置,如下图所示。维护好之后,微信用户关注该公众号或者给该公众号发送的消息,就会通过微信平台投递到您的nodejs应用,我们在里面就可以编程实现一些需求了。下文将该nodejs应用称为“消息服务器”。

我们首先用nodejs的express module获得一个app对象:

var express = require('express');

var app = express();

当有微信用户关注您的公众号时,微信平台会发送一个HTTP post请求到您的消息服务器。您需要编程响应这个post请求。

app.route('/').post(function(req,res){
    var content;
    // 把微信平台发送的HTTP post的内容存储到变量content里
    req.on("data",function(data){
        content = data.toString("utf-8");
    }
    );
    req.on("end",function(){
        console.log("new http post: " + content );
        // 打印HTTP post请求,做调试用

// 从微信平台发送的HTTP请求里解析出事件对象。如果是粉丝点关注,事件类型为subscribe。

var msgType = formattedValue(getXMLNodeValue('MsgType', content));
// 有粉丝点了关注按钮啦
if( event === "subscribe"){
    // 回复一条欢迎消息给粉丝
    var replyxml = replyMessage(content, "欢迎欢迎,终于等到您了!");
    res.send(replyxml);
     }
}

上述代码逻辑很清晰,看注释都易懂。关键就是如何把欢迎消息回复给点了关注按钮的粉丝。

核心逻辑在replyMessage函数里,这个函数的任务是将粉丝的openID从微信平台发给消息服务器的HTTP post内容中解析出来。代码如下:

输入参数1: 微信平台发给消息服务器的HTTP post全部内容

输入参数2:准备给粉丝推送的欢迎消息

输出参数:准备通过HTTP返回给粉丝的欢迎消息的微信报文,需符合微信定义的消息规范,具体规范如下代码所示。

module.exports = function(originalBody, contentToReply){
    // 从原始报文里提取出消息的接收方
    var ToUserName = getXMLNodeValue('ToUserName', originalBody);
    // 从原始报文里提取出消息的发送方
    var FromUserName = getXMLNodeValue('FromUserName',originalBody);
    var CreateTime = getXMLNodeValue('CreateTime',originalBody);
    // 告诉微信平台这条消息的类型是文本消息
    var MsgType = "<![CDATA[text]]>";
    // 准备将欢迎消息的文字内容加入消息报文
    var Content = contentToReply;
    // 开始拼装准备发送给微信粉丝的消息报文
    var xml = '<xml><ToUserName>'+FromUserName+'</ToUserName><FromUserName>'+ToUserName+'</FromUserName><CreateTime>'+CreateTime+'</CreateTime><MsgType>'
    + MsgType + '</MsgType><Content>'+Content+'</Content></xml>';
    console.log("xml to be sent: " + xml);
    // 打印消息报文
    return xml;
    // 返回消息报文
}
;

要获取更多Jerry的原创技术文章,请关注公众号”汪子熙”或者扫描下面二维码:

C#微信开发

阅读数 5312

微信开发sdk

阅读数 558