2019-06-14 14:52:01 weixin_42152604 阅读数 720
  • 微信公众平台深度开发v2.0第2季——获取微信服务器IP...

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    27780 人正在学习 去看看 翟东平

1、接入图如下: 

Url是我们用来认证我们用来验证的接口

我们填写的url必须是在公网上的,我介绍一个免费的内网穿透工具给大家,在下方链接博客中

https://blog.csdn.net/weixin_42152604/article/details/88662706

 

Token和我们在我们自己的服务端配置的应该是一致的

至于下方的这个加密方式,我们没有设置,使用的是明文,因此无所谓

2、后台代码

(1)请求到的方法

/**
 * 作者:程序猿-南巷清风
 * 博客地址:https://blog.csdn.net/weixin_42152604(关注一下下^_^)
 * QQ:1821119445  java开发的朋友们可以加(非诚勿扰好吧!)
 */
@RestController
@RequestMapping("/weChat")
public class WeiXinController {
    @GetMapping("/signature")
    public String signature(String signature,String timestamp,String nonce,String echostr){
        if(SignUtil.checkSignature(signature, timestamp, nonce)){
            return echostr;
        }
        return null;
    }

}

 (2)工具类

/**
 * 类名: SignUtil </br>
 * 描述: 检验signature 工具类 </br>
 */
public class SignUtil {

    // 与接口配置信息中的Token要一致
    private static String token = "nxqfToken";

    /**
     * 方法名:checkSignature</br>
     * 详述:验证签名</br>
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     * @throws
     */
    public static boolean checkSignature(String signature, String timestamp,String nonce) {
        // 1.将token、timestamp、nonce三个参数进行字典序排序
        String[] arr = new String[] { token, timestamp, nonce };
        Arrays.sort(arr);

        // 2. 将三个参数字符串拼接成一个字符串进行sha1加密
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;
        try {
            md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        content = null;
        // 3.将sha1加密后的字符串可与signature对比,标识该请求来源于微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }

    /**
     * 方法名:byteToStr</br>
     * 详述:将字节数组转换为十六进制字符串</br>
     * @param byteArray
     * @return
     * @throws
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    /**
     * 方法名:byteToHexStr</br>
     * 详述:将字节转换为十六进制字符串</br>
     * @param mByte
     * @return
     * @throws
     */
    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A','B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];
        String s = new String(tempArr);
        return s;
    }
}

填写URL的时候,一定要看你本地映射的是什么端口,如果是80,那么就用http请求,如果是443,就用https请求,否则访问不到,会报错,系统错误

2015-08-28 15:42:14 u010773333 阅读数 5613
  • 微信公众平台深度开发v2.0第2季——获取微信服务器IP...

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    27780 人正在学习 去看看 翟东平

      上几篇文章基本是介绍有手机客户端触发的事件在先,这种有手机微信客户端触发的请求,咱们的服务器被动响应,这种模式我个人理解为被动发送信息。

但是除此之外我们有时间要让用户推送消息,比如向家长每天发送孩子的作业信息。这就要用到模板消息了

对于模板消息首先要添加

进入模板选择行业之后就要等两天才能用模板消息

能用模板消息之后 根据自己的情况,查看模板选择适用于自己的模板 如果没有可以自己定义 只要微信官方审核通过就可以用(我申请的好像说是7-15天,完成审计,但是好像30分钟就给我发通知说申请成功)

后两个都是我自己申请的模板。

给一个我调用模板的方法

 [WebMethod(Description = "测试优学酷能力报告")]
        public string TestEveryOneWeek(string featherOpenid)
        {
            string url = "http://......";
            string first = "亲爱的家长,您孩子能力报告出炉通知\n";
            var keyword1 = string.Format("英语");
            var keyword2 = "单词、语法很棒哦!听力、口语还不错!差一点就当学霸了,继续加油!\n";
            var remark = "点击“详情”查看";
            //得到所需要的模板数据
            var data = MessageTemplate.NoticeYouxuekuEvery(first, keyword1, keyword2, remark);
            //模板标号
            string templateid = "XakPchhUx1InpJX0pxDqmDKKQz6-ocrPTn682sV5VSw";
            featherOpenid = "............";  //我个人微信的openid
            bool sendsucess = SendTemplateMessageService.SendTemplateMessage(templateid, featherOpenid, url, data);
            if (sendsucess)
            {
                return "成功";
            }
            else
            {
                return "失败";
            }
        }

要给所谓的消息,制成固定格式如下 格式并添加颜色

      public static object NoticeYouxuekuEvery(string first, string keyword1, string keyword2,string remark)
        {
            var data = new
            {
                first = new TemplateDataItem(first, "#000000"),
                keyword1 = new TemplateDataItem(keyword1, "#000000"),
                keyword2 = new TemplateDataItem(keyword2, "#000000"),
                remark = new TemplateDataItem(remark, "#000000")
            };
            return data;
        }

里面的first,keyword1,keyword2,remark都是模板里面的参数。

调用发送消息方法如下

public static bool SendTemplateMessage(string templateId, string openId, string url, object data)
        {
            WeiXinService weixin = new WeiXinService();
            var accessToken = weixin.GetAccessToken();
            var getInfoUrl = string.Format(GetBaseUserInfoApi, accessToken, openId);
            WeiXinUserInfo userInfo = HttpClientHelper.GetResponse<WeiXinUserInfo>(getInfoUrl);
            string resultes=null;
            //判断用户是否关注公众号
            switch (userInfo.Subscribe)
            {
                case 0:
                    break;
                default:
                    var sendUrl = string.Format(SendMessageApi, accessToken);
                    var msg = new TemplateMessage
                    {
                        template_id = templateId,
                        touser = openId,
                        url = url,
                        data = data
                    };
                   //序列化实体为json
                   string json = JsonConvert.SerializeObject(msg, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
                   //调用消息发送接口
                   var result = HttpClientHelper.PostResponse<TemplateMessageResult>(string.Format(sendUrl, accessToken), json);
                   resultes = result.errmsg;
                    break;
            }
            if (resultes=="ok")
            {
                return true;
            }
            else
            {
                return false;
            }
        }

如果知道了用户的openid,这样就可以使用模板消息,主动向手机客户端发送消息了。



2019-04-02 23:06:02 weixin_38361347 阅读数 272
  • 微信公众平台深度开发v2.0第2季——获取微信服务器IP...

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    27780 人正在学习 去看看 翟东平

接收服务器推送普通消息

接收普通消息

当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。

服务器介入获取微信推送消息代码:

    /**
     * 此方法用于微信回复消息
     * @param request
     * @return
     */
    @PostMapping("getToken")
    @ResponseBody
    public String getUserMessage(HttpServletRequest request){
        String responseString = "";
        try {
            //处理消息与事件推送
            Map<String, String> xmlData = RequestParamType.getXmlData(request.getInputStream());
            logger.info(xmlData.toString());//接受到的消息
             responseString = RequestParamType.dealBean2Xml(xmlData);
             logger.info("消息回复ing..." + responseString);
             return responseString;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

解析xml工具类

    /**
     * 解析xml 获取key-value
     * @param inputStream
     * @return
     */
    public static Map<String,String> getXmlData(InputStream inputStream){
        Map<String,String> map =  new HashMap<>();
        //截取xml
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(inputStream);
            Element rootElement = document.getRootElement(); //获取根节点
            List<Element>  elements = rootElement.elements(); // h获取所有的节点
            for (Element e: elements) {
                map.put(e.getName(),e.getStringValue());
            }

        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return map;
    }

处理xml消息

    /**
     * 处理文本消息
     */
    public static String dealBean2Xml(Map<String,String> xmlData ){

        //获取 消息类型
        String msgType = xmlData.get("MsgType");
        BaseMsg baseMsg = null;
        switch (msgType){
            //普通文本消息
            case "text":
                baseMsg = dealText(xmlData);
                break;

            //图片消息
            case "image":
                break;

            //语音消息
            case "voice":
                break;

            //视频消息
            case "video":
                break;

            //小视频消息
            case "shortvideo":
                break;

            //地理位置消息
            case "location":
                break;
            //链接消息

            case "link":
                break;

            case "event":
                baseMsg = dealTicket(xmlData);
                break;

            default:
                break;
        }
        //把消息对象处理为xml数据包
        String xml = bean2Xml(baseMsg);
        if(xml!=null){
            return xml;
        }
        return null;
    }

处理文本工具类

    /**
     * 处理文本消息
     * @param xmlData
     * @return TextMsg
     */
    private static BaseMsg dealText(Map<String, String> xmlData) {
        //获取请求聊天信息
        String content = xmlData.get("Content");
        //回复文本消息
        BaseMsg bm = new TextMsg(xmlData,"欢迎访问公众号哟!");
        return bm;
    }

将对象转为xml

    /**
     *  javaBean 转xml
     * @param baseMsg
     * @return  xml
     */
    public static String bean2Xml(BaseMsg baseMsg){

        XStream xStream = new XStream();
        //若没有这句,xml中的根元素会是<包.类名>;或者说:注解根本就没生效,所以的元素名就是类的属性
        xStream.processAnnotations(BaseMsg.class);
        xStream.processAnnotations(ImageMsg.class);
        xStream.processAnnotations(LinkMsg.class);
        xStream.processAnnotations(LocationMsg.class);
        xStream.processAnnotations(SmalleVideoMsg.class);
        xStream.processAnnotations(TextMsg.class);
        xStream.processAnnotations(VideoMsg.class);
        xStream.processAnnotations(VoiceMsg.class);
        xStream.processAnnotations(ScanTicket.class);
        String xml = xStream.toXML(baseMsg);
        return xml;
    }

消息对象实体

消息实体基类

/**
 *  base模板实体类
 */
@XStreamAlias("xml") //设置根节点名
public class BaseMsg {

    //置顶别名首字母大写
    @XStreamAlias("ToUserName")
    private String toUserName;//开发者微信号
    private String FromUserName;//发送方帐号(一个OpenID)
    private String CreateTime;//消息创建时间 (整型)
    private String MsgType;//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;
    }

    public BaseMsg(){}
    public BaseMsg(Map<String,String> map){
        this.CreateTime=System.currentTimeMillis()/1000+"";
        this.FromUserName=map.get("ToUserName");
        this.toUserName=map.get("FromUserName");
    }

}

消息文本模板实体类

/**
 *  消息文本模板实体类
 */
@XStreamAlias("xml")
public class TextMsg extends BaseMsg {


    private String Content;//文本消息内容

    public String getContent() {
        return Content;
    }

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



    public TextMsg(Map<String,String> map, String Content){
        super(map);
        this.Content=Content;
        this.setMsgType("text");
    }

}

maven 依赖

        <!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.11.1</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.53</version>
        </dependency>
2015-08-28 10:40:11 u010773333 阅读数 2236
  • 微信公众平台深度开发v2.0第2季——获取微信服务器IP...

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    27780 人正在学习 去看看 翟东平

微信开发第二篇

上一篇讲述了公众号内部的程序员需要注意的一些内容。http://blog.csdn.net/u010773333/article/details/48047031

这里进行服务器被动交互的基础讲解,被动交互是由手机微信客户端发起的请求。开发公众微信号的准备一台外网服务器(80端口不能禁用或者被占用),申请一个自己网站的域名。

下面要编写代码,首先要知道自己的服务器,微信服务器,和手机微信客户端之间的运行原理


下面需要编写自己的代码,并且挂到自己的服务器了。我这个以C#语言进行讲解

首先要拿到微信公众号的AppID(应用ID) ,AppSecret(应用密钥),URL(服务器地址),Token(令牌),EncodingAESKey(消息加解密密钥)

先建一个项目(随便一个项目)设置一个首页,把这个项目用自己申请的域名挂到自己的服务器(一定要用80端口)并能实现简单的访问。

之后配置url和Token 主要是Token这个要参看微信官方文档。url就是自己服务器上的那个自己的项目首页就是交互时微信服务器首先访问的页面。一定要启用“服务器配置”如下图



对于微信服务器第一次请求咱们自己的服务器是发的是get请求,新的账号首先要微信接入测试。

在首页首先判断是不是第一次访问要是get请求说明是第一次要进行微信接入测试。测试成功之后就不在测试了,这段代码原则性只执行一遍。

代码如下:

if (Request.HttpMethod == "GET")
            {
                Auth(); //微信接入的测试
            }
            else
            {
                Stream s = System.Web.HttpContext.Current.Request.InputStream;
                byte[] b = new byte[s.Length];
                s.Read(b, 0, (int)s.Length);
                postStr = Encoding.UTF8.GetString(b);
                if (!string.IsNullOrEmpty(postStr)) //请求处理  
                {
                    weixinservice.Handle(postStr);
                }  
            }

 public void Auth()
        {
            string echoStr = System.Web.HttpContext.Current.Request.QueryString["echoStr"];
            if (CheckSignature())
            {
                if (!string.IsNullOrEmpty(echoStr))
                {
                    System.Web.HttpContext.Current.Response.Write(echoStr);
                    System.Web.HttpContext.Current.Response.End();
                }
            }
        }

并且需要知道微信服务器和咱们自己的服务器的交互是xml格式

          <xml>
                  <ToUserName><![CDATA[{0}]]></ToUserName>
                  <FromUserName><![CDATA[{1}]]></FromUserName>
                  <CreateTime>{2}</CreateTime>
                  <MsgType><![CDATA[event]]></MsgType>
                   <Event><![CDATA[{3}]]></Event>
                   <EventKey>{4}</EventKey>
                   </xml>

在WeixinService类中添加如下方法

      private string RequestXml { get; set; }

        public void Handle(string postStr)
        {
            //封装请求类  
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(postStr);
            XmlElement rootElement = doc.DocumentElement;
            //MsgType  
            XmlNode MsgType = rootElement.SelectSingleNode("MsgType");
            //接收的值--->接收消息类(也称为消息推送)  
            WeiXinModel requestXML = new WeiXinModel();
            requestXML.ToUserName = rootElement.SelectSingleNode("ToUserName").InnerText;
            requestXML.FromUserName = rootElement.SelectSingleNode("FromUserName").InnerText;
            requestXML.CreateTime = rootElement.SelectSingleNode("CreateTime").InnerText;
            requestXML.MsgType = MsgType.InnerText;
            string response = string.Empty;
            EventMessage em = EventMessage.LoadFromXml(RequestXml);
            IHandler handler = null;
            //根据不同的类型进行不同的处理
            switch (requestXML.MsgType)
            {
                case "text":
                    //requestXML.Content = rootElement.SelectSingleNode("Content").InnerText;
                    handler = new TextHandler(postStr);
                    response = handler.HandleRequest();
                    break;
                case "image": //图片  
                    requestXML.PicUrl = rootElement.SelectSingleNode("PicUrl").InnerText;
                    break;
                case "location": //位置  
                    requestXML.Location_X = rootElement.SelectSingleNode("Location_X").InnerText;
                    requestXML.Location_Y = rootElement.SelectSingleNode("Location_Y").InnerText;
                    requestXML.Scale = rootElement.SelectSingleNode("Scale").InnerText;
                    requestXML.Label = rootElement.SelectSingleNode("Label").InnerText;
                    break;
                case "link": //链接
                    //response = SubscribeEventHandler(em);
                    break;
                case "event": //事件推送 支持V4.5+  
                    handler = new Kingsun.WeiXin.Handlers.EventHandler(postStr);
                    response = handler.HandleRequest();
                    break;
            }
            //回复消息
            HttpContext.Current.Response.Clear();
            HttpContext.Current.Response.Charset = "UTF-8";
            HttpContext.Current.Response.Write(response);
            HttpContext.Current.Response.End();          
        }

其中requestXML.MsgType就是手机微信端出发的是什么事件的类型。咱们服务器通过手机端的不同类型可以做出不同相应,其中

可以接收用户手机微信客户端的一些信息如我新建了一个WeiXinModel类:发送方openid,接收方openid ,时间和类型。

           WeiXinModel requestXML = new WeiXinModel();
            requestXML.ToUserName = rootElement.SelectSingleNode("ToUserName").InnerText;
            requestXML.FromUserName = rootElement.SelectSingleNode("FromUserName").InnerText;
            requestXML.CreateTime = rootElement.SelectSingleNode("CreateTime").InnerText;
            requestXML.MsgType = MsgType.InnerText;

其中event事件比较特殊 event事件 subscribe(扫描二维码并且可以通过方法把手机微信openid存到自己的服务器上),scan(扫描带参数二维码,并直接关注事件),click(点击事件)这三种,具体看微信官方给的解释

我的代码如下:

EventMessage em = EventMessage.LoadFromXml(RequestXml);
            string content = "";
            if (em != null)
            {
                switch (em.Event.ToLower())
                {
                    case ("subscribe"):
                        //加载菜单
                        if (string.IsNullOrEmpty(em.EventKey))
                        {
                            //response = ResponseMessage.GetText(em.FromUserName, em.ToUserName, "关注成功");                 
                            response = SubscribeEventHandler(em);
                        }
                        else
                        {
                            content = em.EventKey.Replace("qrscene_", "");//二维码携带的信息
                            response = SubscribeEventHandler(em, content);//扫描带参数二维码先关注后推送事件
                        }
                        break;
                    case "scan":
                        response = ResponseMessage.ScanQrcode(em.FromUserName, em.ToUserName, em.EventKey);//扫描带参数二维码已关注 直接推送事件
                        break;
                    case "click":
                        response = ClickEventHandler(em);
                        break;
                }
            }
            return response;


其中给出一个点击事件:

        /// <summary>
        /// 关注
        /// </summary>
        /// <param name="em"></param>
        /// <returns></returns>
        private string SubscribeEventHandler(EventMessage em)
        {
            //回复欢迎消息
            TextMessage tm = new TextMessage();
            tm.ToUserName = em.FromUserName;
            tm.FromUserName = em.ToUserName;
            tm.CreateTime = Commons.GetNowTime();
            tm.Content = "亲,您已经学会了服务器被动交互";
            return tm.GenerateContent();
        }




2018-05-30 10:58:09 sinat_36265222 阅读数 1817
  • 微信公众平台深度开发v2.0第2季——获取微信服务器IP...

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    27780 人正在学习 去看看 翟东平

    1.微信公众平台->开发->基本配置->服务器配置


服务端使用java开发的,第一次服务器的验证代码如下:

 @GetMapping("/checkWechat")
	 public void wechatCallbackApi(@RequestParam("signature") String
	 signature,
	 @RequestParam("timestamp") String timestamp,
	 @RequestParam("nonce") String nonce,
	 @RequestParam("echostr") String echostr,HttpServletResponse response)
	 throws ServletException, IOException {
	 log.info("[服务器配置],进入是数据signature{},timestamp{},nonce{},echostr{}",signature,timestamp,nonce,echostr);
	
	 PrintWriter print;
	
	 // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
	 if (signature != null && CheckoutUtil.checkSignature(signature,
	 timestamp, nonce)) {
	
	 log.info("[服务器配置],验证通过","success");
	 try {
	 print = response.getWriter();
	 print.write(echostr);
	 print.flush();
	 } catch (IOException e) {
	 e.printStackTrace();
	 }
	
	 }
	 }

 注意CheckOutUtil验证工具类中的token要和上面微信公众号中填写的token一致。

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class CheckoutUtil {
	
	 // 与接口配置信息中的Token要一致
    private static String token = "XXXXXX";

    /**
     * 验证签名
     * 
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
        String[] arr = new String[] { token, timestamp, nonce };
        // 将token、timestamp、nonce三个参数进行字典序排序
        // Arrays.sort(arr);
        sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;

        try {
            md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        content = null;
        // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }

    /**
     * 将字节数组转换为十六进制字符串
     * 
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    /**
     * 将字节转换为十六进制字符串
     * 
     * @param mByte
     * @return
     */
    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];
        String s = new String(tempArr);
        return s;
    }
    public static void sort(String a[]) {
        for (int i = 0; i < a.length - 1; i++) {
            for (int j = i + 1; j < a.length; j++) {
                if (a[j].compareTo(a[i]) < 0) {
                    String temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
                }
            }
        }
    }

}

    编写好响应服务器配置的接口后,要确保可以在外网能够访问到。就可以在微信中点击确定,成功的话,微信会提示配置成功。

    服务器配置成功后我们就可以将上面的服务器响应接口改成一个接收消息处理的接口,如下,我们可以对不同的事件通知进行处理。

	@PostMapping("/checkWechat")
	public void wechatCallbackApi(@RequestBody String notifyData) throws ServletException, IOException {

		log.info("[服务器配置],进入审核事件通知{}", notifyData);

		PushMessage message = (PushMessage) XmlUtil.fromXML(notifyData, PushMessage.class);

//		String msgid = message.getFromUserName() + message.getCreateTime() + message.getEvent();

		Objects.requireNonNull(message, "[微信接收会员信息事件通知],返回为空!");

		log.info("[服务器配置],进入审核事件通知转对象信息结果{}", message);

		if ("submit_membercard_user_info".equals(message.getEvent())) {// 激活卡的通知
																		// 可以查询用户信息
			cardService.getOpenCardInfo(message);
		} else if ("update_member_card".equals(message.getEvent())) {// 修改会员卡信息
			log.info("[服务器配置],修改用户会员卡信息推送{}", message);
		} else if ("card_not_pass_check".equals(message.getEvent())) {// 会员卡审核不通
			MpMemberCard card = mpMemberCardRepository.findByCardId(message.getCardId());
			if(card!=null){
				card.setState(false);
				mpMemberCardRepository.save(card);
			}else{
				log.info("[服务器配置],会员卡审核不通过,未查询到该卡信息{}", message);
			}
			
		} else if ("card_pass_check".equals(message.getEvent())) {// 会员卡审核通过
			MpMemberCard card = mpMemberCardRepository.findByCardId(message.getCardId());
			if(card!=null){
				card.setState(true);
				mpMemberCardRepository.save(card);
			}else{
				log.info("[服务器配置],会员卡审核通过,未查询到该卡信息{}", message);
			}
			
		} else if ("card_sku_remind".equals(message.getEvent())) {// 库存报警给管理员发个通知吧
			Notice notice = new Notice();
			notice.setContent(message.getCardId() + "库存不过百");
			notice.setCreatetime(DateUtil.currentDate());
			notice.setCreater(1);
			noticeRepository.save(notice);
		} else {
			log.info("[服务器配置],会员卡信息推送{}", message);
		}

	}

 这里推荐可以使用simpleFrameWork解析xml。

1.我们可以将要解析的数据编成一个类如上面的PushMessage.class。

package com.ddzrh.wxcard.reponse;

import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;

import lombok.Data;

@Data
@Root(name = "xml", strict = false)
public class PushMessage {
	
	@Element(name = "ToUserName")
	private String ToUserName;
	
	@Element(name = "FromUserName")
	private String FromUserName;

	@Element(name = "CreateTime", required = false)
	private Long CreateTime;

	@Element(name = "Event", required = false)
	private String Event;
	
	@Element(name = "MsgType", required = false)
	private String MsgType;
	
	@Element(name = "CardId", required = false)
	private String CardId;
	
	@Element(name = "UserCardCode", required = false)
	private String UserCardCode;
	
	@Element(name = "ModifyBonus", required = false)
	private Integer ModifyBonus;

	@Override
	public String toString() {
		return "PushMessage [ToUserName=" + ToUserName + ", FromUserName=" + FromUserName + ", CreateTime=" + CreateTime
				+ ", Event=" + Event + ", MsgType=" + MsgType + ", CardId=" + CardId + ", UserCardCode=" + UserCardCode
				+ "]";
	}
	
	

}

2.编写一个XmlUtil工具类,这里的工具类是借用慕课网廖师兄的。

package com.lly835.bestpay.utils;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.naming.NoNameCoder;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;

import java.io.Writer;

/**
 * Created by 廖师兄
 * 2017-07-02 15:30
 */
public class XmlUtil {

    private static XStream xStream = new XStream(new XppDriver(new NoNameCoder()) {

        @Override
        public HierarchicalStreamWriter createWriter(Writer out) {
            return new PrettyPrintWriter(out) {
                // 对所有xml节点的转换都增加CDATA标记
                boolean cdata = true;

                @Override
                @SuppressWarnings("rawtypes")
                public void startNode(String name, Class clazz) {
                    super.startNode(name, clazz);
                }

                ////当对象属性带下划线时,XStream会转换成双下划线,
                // 重写这个方法,不再像XppDriver那样调用nameCoder来进行编译,而是直接返回节点名称,避免双下划线出现
                @Override
                public String encodeNode(String name) {
                    return name;
                }


                @Override
                protected void writeText(QuickWriter writer, String text) {
                    if (cdata) {
                        writer.write("<![CDATA[");
                        writer.write(text);
                        writer.write("]]>");
                    } else {
                        writer.write(text);
                    }
                }
            };
        }
    });
    /**
     * 对象转xml
     * @param obj
     * @return
     */
    public static String toXMl(Object obj) {
        //使用注解设置别名必须在使用之前加上注解类才有作用
        xStream.processAnnotations(obj.getClass());
        return xStream.toXML(obj);
    }

    public static Object fromXML(String xml, Class objClass) {
        Serializer serializer = new Persister();
        try {
            return serializer.read(objClass, xml);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

.NET微信开发,服务器配置响应微信验

博文 来自: xz1414682954

微信开发的原理

阅读数 20

没有更多推荐了,返回首页