2017-03-11 12:27:39 zyw_java 阅读数 4360
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27840 人正在学习 去看看 秦子恒

微信开发交流群:148540125

系列文章参考地址 极速开发微信公众号

欢迎留言、转发
项目源码参考地址 点我点我–欢迎Start

前几篇文章已讲完如何导入项目,如何启动配置项目,如何成为开发者(如果前三项不会的看这里 极速开发微信公众号。这篇文章就来讲讲如果实现消息交互

总所周知Jfinal 开发中配置非常简单只要在web.xml中添加如下代码就可以将所有的请求交由Jfianl处理

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <filter>
    <filter-name>jfinal</filter-name>
    <filter-class>com.jfinal.core.JFinalFilter</filter-class>
    <async-supported>true</async-supported>
    <init-param>
      <param-name>configClass</param-name>
      <param-value>com.javen.common.APPConfig</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>jfinal</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

可以看到com.javen.common.APPConfig 是项目的核心配置文件,他是继承自JFinalConfig 实现了如下方法

消息交互-配置详解.png

以上配置 详细介绍参考官方文档
成为开发者模式这篇文章中讲到过消息交互都是由WeixinMsgController接管的,

消息到底是如何交互的在此做详细的讲解

上面有讲到消息交互都是由WeixinMsgController接管的,她是继承自MsgControllerAdapter 又继承自 MsgController 里面有个index 方法其中上面的拦截器MsgInterceptor是进行加密验证的(成为开发者模式),验证没有问题就执行index方法,如下图

消息交互-接收消息.png

可以看出接收消息并返回一个InMsg,之后根据信息类型调用对应的抽象方法交给实现方式实现消息的处理。

那么问题来了:
1、如何接收微信交互的xml
2、如何处理微信的各种消息
3、如何响应微信的各种消息

接收微信交互的xml

成功开发者(get请求)之后,所有的消息接收处理都交由开发者url处理(post请求)所以就有一下方法获取xml

 @Before({NotAction.class})
    public String getInMsgXml() {
        if(this.inMsgXml == null) {
            this.inMsgXml = HttpKit.readData(this.getRequest());
            if(ApiConfigKit.getApiConfig().isEncryptMessage()) {
                this.inMsgXml = MsgEncryptKit.decrypt(this.inMsgXml, this.getPara("timestamp"), this.getPara("nonce"), this.getPara("msg_signature"));
            }
        }

        if(StrKit.isBlank(this.inMsgXml)) {
            throw new RuntimeException("请不要在浏览器中请求该连接,调试请查看WIKI:http://git.oschina.net/jfinal/jfinal-weixin/wikis/JFinal-weixin-demo%E5%92%8C%E8%B0%83%E8%AF%95");
        } else {
            return this.inMsgXml;
        }
    }

解析微信的各种消息

@Before({NotAction.class})
    public InMsg getInMsg() {
        if(this.inMsg == null) {
            this.inMsg = InMsgParser.parse(this.getInMsgXml());
        }

        return this.inMsg;
    }

可以看到this.inMsg 为null时会解析InMsgParser.parse(this.getInMsgXml());获取到的xml

public static InMsg parse(String xml) {
        XmlHelper xmlHelper = XmlHelper.of(xml);
        return doParse(xmlHelper);
    }

静态方法 通过xml 实例化一个XmlHelper(主要提供一些常用类型数据的获取方法) 再交给doParse方法处理 text消息 image消息 voice消息 vide消息 shortvideo消息 location消息 link消息 eveen消息

private static InMsg doParse(XmlHelper xmlHelper) {
        String toUserName = xmlHelper.getString("//ToUserName");
        String fromUserName = xmlHelper.getString("//FromUserName");
        Integer createTime = Integer.valueOf(xmlHelper.getNumber("//CreateTime").intValue());
        String msgType = xmlHelper.getString("//MsgType");
        if("text".equals(msgType)) {
            return parseInTextMsg(xmlHelper, toUserName, fromUserName, createTime, msgType);
        } else if("image".equals(msgType)) {
            return parseInImageMsg(xmlHelper, toUserName, fromUserName, createTime, msgType);
        } else if("voice".equals(msgType)) {
            return parseInVoiceMsgAndInSpeechRecognitionResults(xmlHelper, toUserName, fromUserName, createTime, msgType);
        } else if("video".equals(msgType)) {
            return parseInVideoMsg(xmlHelper, toUserName, fromUserName, createTime, msgType);
        } else if("shortvideo".equals(msgType)) {
            return parseInShortVideoMsg(xmlHelper, toUserName, fromUserName, createTime, msgType);
        } else if("location".equals(msgType)) {
            return parseInLocationMsg(xmlHelper, toUserName, fromUserName, createTime, msgType);
        } else if("link".equals(msgType)) {
            return parseInLinkMsg(xmlHelper, toUserName, fromUserName, createTime, msgType);
        } else if("event".equals(msgType)) {
            return parseInEvent(xmlHelper, toUserName, fromUserName, createTime, msgType);
        } else {
            LogKit.error("无法识别的消息类型 " + msgType + ",请查阅微信公众平台开发文档");
            return parseInNotDefinedMsg(toUserName, fromUserName, createTime, msgType);
        }
    }

解析出来消息类型之后就调用对应的解析方法并返回InMsg

消息类型很多避免重复造轮子,所以就诞生了消息的封装这个东西。

查看所有普通消息的xml格式找规律进行封装 官方文档 可以发现都包含有ToUserName FromUserName CreateTime MsgId 不同的是 MsgType 以及 各个类型对应的消息内容。

这里是接收消息以及响应消息的截图
消息交互-消息封装.png

以解析 text消息 为栗子讲解

接收到的xml 如下

<xml>
 <ToUserName><![CDATA[toUser]]></ToUserName>
 <FromUserName><![CDATA[fromUser]]></FromUserName> 
 <CreateTime>1348831860</CreateTime>
 <MsgType><![CDATA[text]]></MsgType>
 <Content><![CDATA[this is a test]]></Content>
 <MsgId>1234567890123456</MsgId>
 </xml>

解析text消息

private static InMsg parseInTextMsg(XmlHelper xmlHelper, String toUserName, String fromUserName, Integer createTime, String msgType) {
        InTextMsg msg = new InTextMsg(toUserName, fromUserName, createTime, msgType);
        msg.setContent(xmlHelper.getString("//Content"));
        msg.setMsgId(xmlHelper.getString("//MsgId"));
        return msg;
    }

封装text消息

public class InTextMsg extends InMsg {
    private String content;
    private String msgId;

    public InTextMsg(String toUserName, String fromUserName, Integer createTime, String msgType) {
        super(toUserName, fromUserName, createTime, msgType);
    }

    public String getContent() {
        return this.content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getMsgId() {
        return this.msgId;
    }

    public void setMsgId(String msgId) {
        this.msgId = msgId;
    }
}

接收消息的公用部分

public abstract class InMsg {
    protected String toUserName;
    protected String fromUserName;
    protected Integer createTime;
    protected String msgType;

    public InMsg(String toUserName, String fromUserName, Integer createTime, String msgType) {
        this.toUserName = toUserName;
        this.fromUserName = fromUserName;
        this.createTime = createTime;
        this.msgType = msgType;
    }

    public String getToUserName() {
        return this.toUserName;
    }

    public void setToUserName(String toUserName) {
        this.toUserName = toUserName;
    }

    public String getFromUserName() {
        return this.fromUserName;
    }

    public void setFromUserName(String fromUserName) {
        this.fromUserName = fromUserName;
    }

    public Integer getCreateTime() {
        return this.createTime;
    }

    public void setCreateTime(Integer createTime) {
        this.createTime = createTime;
    }

    public String getMsgType() {
        return this.msgType;
    }

    public void setMsgType(String msgType) {
        this.msgType = msgType;
    }
}

响应微信的各种消息

由上分析可以知道,消息处理完成后都是交由抽象方法的实现方法处理消息。MsgControllerAdapter 主要是适配各种消息的抽象类。

下面 text消息为例子说明

接收到text消息之后会调用 WeixinMsgController中的protected void processInTextMsg(InTextMsg inTextMsg) 方法,可以通过InTextMsg对象获取text消息

protected void processInTextMsg(InTextMsg inTextMsg)
  {
    String msgContent = inTextMsg.getContent().trim();
    // 帮助提示
    if ("help".equalsIgnoreCase(msgContent) || "帮助".equals(msgContent)) {
      OutTextMsg outMsg = new OutTextMsg(inTextMsg);
      outMsg.setContent(helpStr);
      render(outMsg);
    }else {
      renderOutTextMsg("你发的内容为:"+msgContent);
      //转发给多客服PC客户端
//      OutCustomMsg outCustomMsg = new OutCustomMsg(inTextMsg);
//      render(outCustomMsg);
    }

}

以上可以看到响应消息有两种实现方式

第一种render一个消息对象

OutTextMsg outMsg = new OutTextMsg(inTextMsg); 
outMsg.setContent(helpStr); 
render(outMsg);

第二种直接传一个String

renderOutTextMsg("你发的内容为:"+msgContent);

以下是具体的实现:
1、将对象转化为xml outMsg.toXml()
2、如果是开发模式输出调试的xml
3、如果是加密模式,就将消息加密
4、通过Jfinal 的renderText()方法应用xml

public void render(OutMsg outMsg) {
        String outMsgXml = outMsg.toXml();
        if(ApiConfigKit.isDevMode()) {
            System.out.println("发送消息:");
            System.out.println(outMsgXml);
            System.out.println("--------------------------------------------------------------------------------\n");
        }

        if(ApiConfigKit.getApiConfig().isEncryptMessage()) {
            outMsgXml = MsgEncryptKit.encrypt(outMsgXml, this.getPara("timestamp"), this.getPara("nonce"));
        }

        this.renderText(outMsgXml, "text/xml");
    }

renderOutTextMsg(String content)方法就是调用的render(outMsg)方法

public void renderOutTextMsg(String content) {
        OutTextMsg outMsg = new OutTextMsg(this.getInMsg());
        outMsg.setContent(content);
        this.render(outMsg);
    }

欢迎留言、转发
项目源码参考地址 点我点我–欢迎Start

2014-08-23 10:37:27 GoodShot 阅读数 14820
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27840 人正在学习 去看看 秦子恒

公众平台开发模式的数据交互方式

1.2 公众平台开发模式的数据交互方式

公众平台消息接口为开发者提供了与用户进行消息交互的能力。对于成功接入消息接口的公众账号,当用户发消息给公众账号时,微信公众平台服务器会使 用 HTTP 请求对接入的网址进行消息推送,第三方服务器可通过响应包返回个性的回复,从而达到回复消息的目的。简单地说,就是公众账号可以使用自己的程序来和用户对话。

这个模式和多年前的手机订阅很像。在21世纪初,互联网在泡沫之后迎来了一种非常厉害的盈利模式——SP/CP 模式,拯救了水深火热的互联网。当然,现在这种模式已经过时了,大家可以在网上了解一下那段互联网的历史。不过现实中还是存在真实的例子,如果你的手机号是中国移动的,可以参看 10086 的短信功能;如果你的手机号是中国电信的,可以参看 10000 的短信功能。笔者的手机号是中国电信的,当笔者想查询自己的套餐使用情况时,即可发送 702 到 10001,10001 会立即返回笔者的套餐详细使用情况。大家肯定猜到这条短信不是人工发过来的,而是由后台程序接到 702 之后查询中国电信自己的用户数据库后发过来的。同样的,中国移动的用户发送“YE”到 10086 查询余额的功能也是一样的。

使用了开发模式的微信公众账号就会成为一个配备了一些指令规则的账号。在用户关注公众账号,发送对应的指令给公众账号之后可以获得相应的结果。而这些规则的逻辑需要公众账号的开发者根据公众平台的开发规则在后台实现。用户、微信后台和我们需要开发的公众账号后台的服务器三者之间的交互关系如图1-1所示。

图1-1 用户、微信后台和公众账号服务器间的交互图

图1-1 所示的具体交互过程的描述如下:
1)用户在微信的手机客户端里向公众账号发送一条消息,这条消息会通过网络到达微信的后台;
2)后台收到这条消息之后,把消息转发给公众账号的后台,也就是公众账号的服务器;
3)公众账号服务器收到请求后,解析消息格式,根据用户内容和自己的服务器逻辑,计算出需要返回给用户的消息,然后封装消息,返回给微信后台;
4)微信后台把公众账号服务发来的消息转发给用户的微信手机客户端,这样用户在手机客户端上就可以看到公众账号发来的微信消息了。

通过这个过程可以看到公众账号服务器要做的事情有三件:
❑ 获取微信后台发过来的消息;
❑ 实现自己的业务逻辑;
❑ 发送返回消息给微信后台。

因为微信服务器请求公众账号服务使用的是 HTTP 协议,所以在公众账号服务器上必须要运行一个 HTTP 服务,并打开一个端口。本书的案例为了开发时的 方便,使用 Windows 上的 AppServ 作为开发和调试环境,使用 zendstudio 作为 PHP 语言的 IDE,使用 Windows 版本的 MySQL 作为数据存储;在部署应用时使 用 Nginx、PHP-FPM 和 Linux 版本的 MySQL 作为生产环境。

接下来介绍一下开发环境的准备工作及生产环境的部署,如果读者已经知道如何使用 AppServ 可以跳过这些内容。

2018-03-21 22:49:11 u014740338 阅读数 2443
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27840 人正在学习 去看看 秦子恒

最近在搞微信的开发者模式,对于第一次接触这东西的人来说还真是没有头绪,因为需要跟微信进行交互,难免会碰到一些问题,不像我们在本机开发那样,很快就能把逻辑代码写完。今天主要是让测试耽误了时间,由于微信只能绑定域名,不能使用ip地址,但是在公司中域名直接解析到线上服务器,但是线上服务器该域名下已经有服务在运行,所以不能使用线上服务器直接进行开发测试,也不能把已有的服务号打开开发者模式,因为打开开发者模式之后好多已有的自动回复就不能使用了,总之遇到了各种问题,记录下开发过程。


申请测试账号

进入申请地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

点击登录按钮,会弹出一个二维码,使用手机微信扫描即可

登录成功之后会出现下面的界面


appID和appsecret在调用微信接口的时候会用到,这里是微信自动给我们生成好的,直接使用就可以。

URL:是我们自己服务器的URL,用户微信推送用户消息和事件用的。这里只能配置域名,不能使用IP。这个URL是用来接收微信的token认证和消息事件用的,我们自己的服务器要能对这个url的请求进行处理并相应,所以要求该域名必须是外网可以访问的,否则在点“提交”按钮的时候会报token异常。

Token:是验证签名用的,此处填写的要与代码中的Token保持一致否则验证不过。

URL和Token都填好之后点击提交按钮,若验证通过,会返回配置成功,否则返回配置失败。

配置失败的原因可能有几个:

1、URL地址不能访问

2、Token填写错误

注意:在点击提交按钮之前一定要先把服务端的代码写好,否则会返回配置失败,具体实现代码在后面演示。

到此为止,我们的接口配置信息就算完成了。

扫描测试号二维码就可以来测试我们的功能了


Token认证

我配置的URL是,http://www.xxx.com/XX/wxProcess/service,所以微信会把所有的请求都发到我的/service路径上,包括Token认证和事件处理,我使用两个方法来处理的,但是请求类型不同,Token认证是用的GET请求,事件处理使用的是POST请求。演示代码如下:

/**
     * 打开开发者模式签名认证
     * @param signature
     * @param timestamp
     * @param nonce
     * @param echostr
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/service", method = RequestMethod.GET)
    public Object defaultView(String signature, String timestamp, String nonce, String echostr) {
        if (echostr == null || echostr.isEmpty()) {
            return nonce;
        }
        if (SignUtil.checkSignature(signature, timestamp, nonce)) {
            return echostr;
        }
        return nonce;
    }

    /**
     * 事件处理
     * @param signature
     * @param timestamp
     * @param nonce
     * @param message
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/service", method = RequestMethod.POST, consumes = "text/xml", produces = "text/xml;charset=UTF-8")
    public String defaultViewHandler(String signature, String timestamp, String nonce, @RequestBody String message) {
        String result = "";
        if (SignUtil.checkSignature(signature, timestamp, nonce)) {
            result = coreService.processRequest(message);
        }
        return result;
    }

做签名认证的时候会调用我的defaultView方法,其他的事件都走defaultViewHandler方法。

coreService.processRequest(): 是对所有的请求事件进行处理

CoreService.java主要代码实现如下:

@Override
    public String processRequest(String msg) {
        String respMessage = null;
        try {
            // 默认返回的文本消息内容
            String respContent = "";

            // xml请求解析
            Map<String, String> requestMap = MessageUtil.parseXml(msg);

            // 发送方帐号(open_id)
            String fromUserName = requestMap.get("FromUserName");
            // 公众帐号
            String toUserName = requestMap.get("ToUserName");
            // 消息类型
            String msgType = requestMap.get("MsgType");
            String eventType = requestMap.get("Event");

            // 存在事件类型且类型有效 或者 消息类型可以处理,才需要进行身份处理,防止没有意义的事件引起发送大量绑定消息
            if ((!StringUtils.isEmpty(eventType) && !eventArrays.contains(eventType)) || !msgArrays.contains(msgType)) {
                return "";
            }

            respMessage = handleWxMessage(requestMap);
        } catch (Exception e) {
            LOGGER.error("error", e);
            e.printStackTrace();
        }
        return respMessage;
    }

    @Override
    public String handleWxMessage(Map<String, String> requestMap) {
        // 发送方帐号(open_id)
        String fromUserName = requestMap.get("FromUserName");
        // 公众帐号
        String toUserName = requestMap.get("ToUserName");
        // 消息类型
        String msgType = requestMap.get("MsgType");
        // 回复文本消息
        String respContent = "";
        BaseMessage textMessage = new TextMessage();
        textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
        switch (msgType) {
            case MessageUtil.REQ_MESSAGE_TYPE_TEXT:
                // 文本类型消息,暂时设置成用户发什么就回复什么
                String content = requestMap.get("Content");
                respContent = "";
                break;
            case MessageUtil.REQ_MESSAGE_TYPE_VOICE:
                // 使用语音识别功能需要开启微信公众号相关权限
                // 语音识别结果
                String recognizeText = requestMap.get("Recognition");
                respContent = "";
                break;
            case MessageUtil.REQ_MESSAGE_TYPE_EVENT:
                // 事件类型
                String eventType = requestMap.get("Event");
                // 事件KEY值,qrscene_为前缀,后面为二维码的参数值
                String eventKey = requestMap.get("EventKey");
                // 自定义事件
                switch (eventType) {
                    // 用户未关注时,进行关注后的事件推送
                    case MessageUtil.EVENT_TYPE_SUBSCRIBE:
                        if (isUserBuyLastActivity(fromUserName)) {
                            textMessage = getAddClassTextMessage(fromUserName);
                        } else {
                            textMessage = getDefaultTextMessage(fromUserName);
                        }
                        Integer eventKeyValue = 1;// 带参数的情景值
                        if (!StringUtils.isEmpty(eventKey) && eventKey.contains("qrscene_")) {
                            eventKey = eventKey.replace("qrscene_", "");
                            // 渠道ID
                            eventKeyValue = Integer.parseInt(eventKey);
                        }
                        subscribeAction(fromUserName, eventKeyValue);
                        break;
                    // 取消关注
                    case MessageUtil.EVENT_TYPE_UNSUBSCRIBE:
                        unSubscribeAction(fromUserName);
                        break;
                    // 用户已关注时的事件推送
                    case MessageUtil.EVENT_TYPE_SCAN:
                        textMessage = getDefaultTextMessage(fromUserName);
                        break;
                    default:
                        respContent = "";
                        break;
                }
                break;
            default:
                respContent = "";
                break;
        }

        if (textMessage instanceof TextMessage) {
            // 文本内容为空且是文本消息返回空字符串,防止微信发送异常消息
            String content = ((TextMessage) textMessage).getContent();
            if (StringUtils.isEmpty(respContent) && StringUtils.isEmpty(content)) {
                return "";
            }
            if (org.apache.commons.lang.StringUtils.isBlank(content)) {
                ((TextMessage) textMessage).setContent(respContent);
            }
        }
        textMessage.setToUserName(fromUserName);
        textMessage.setFromUserName(toUserName);
        textMessage.setCreateTime(new Date().getTime());
        String xmlString = MessageUtil.messageToXml(textMessage);
        return xmlString;
    }

上面只是展示了部分核心代码,具体代码可以去我的GitHub下载,地址:https://github.com/liuyanmin/wxDemo

下面是微信开发相关的链接:

申请个人测试账号:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

微信被动回复消息开发文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140543

微信错误码文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140543


2018-02-01 13:53:12 zyy_hbcz 阅读数 349
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27840 人正在学习 去看看 秦子恒

1    技术概述

微信公众平台是腾讯为了让用户申请和管理微信公众账号推出的一个web平台。微信公众账号的种类可以分为3种,并且一旦选定不可更改。按照功能的限制从小到大依次为:订阅号、服务号、企业号。个人只能注册订阅号

2    微信公众号的数据交互原理

3  入门前了解

3.1 要明白开发者模式是什么?

开发者模式,简单的说,就是先验证我们自己的服务器地址,验证完成之后,用户一旦给微信公众号发消息,微信的就会把微信用户的消息转发到这个地址上。

我们自己的服务器接到数据后,然后我们自己设计一套程序,输出一个结果,再由微信服务器返回给用户。而我们开发者能做的:就是在自己的服务器上,设计出各种功能的逻辑实现。


3.2 开发者模式能实现什么功能

 无论你会不会技术,首先要做的一件事就是:仔细阅读开发者文档、仔细阅读开发者文档、仔细阅读开发者文档(重要的事情说三遍)

  要明白一些基本的东西

   要明白openid是一个加密的串,每个用户对一个某个公众号的openid是唯一的。

  根据openid获取用户的头像,性别、昵称、所在地区等微信公开的信息,不过用户的微信号获取不到。

3.3 微信公众平台的开发者模式能实现的功能

首先要知道开发者模式的接口有哪些,所有的功能,都是基于这些接口的。

打开微信公众平台后台,点击开发者中心下面的接口权限。





2015-04-14 21:13:42 growing_IT_bird 阅读数 439
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27840 人正在学习 去看看 秦子恒
用Java实现成为微信开发者


1、微信开发的数据交互方式
公众平台消息接口为开发者提供了与用户进行消息交互的能力。对于成功接入消息接口的公众账号,当用户发消息给公众账号时,微信公众平台服务器会使用HTTP请求对接入的网址进行消息推送,第三方服务器可通过响应包返回个性的回复,从而达到回复消息的目的。简单地说,就是公众账号可以使用自己的程序来和用户对话。(摘自http://book.2cto.com/201309/33610.html)


2、微信开发者的服务支持
由以上数据交互方式开出看出,必须有  微信公众平台、第三方服务器

3、成为微信开发者
成为微信开发者要通过修改配置,即填写URL、token、和生成EncodingAESKey
认证有servlet完成,代码要有一下代码文件


//weixinServlet.java第三方服务器的入口
public class weixinServlet extends HttpServlet{
private static final long serialVersionUID = 4440739483644821986L;


/**
* 确认请求来自微信服务器
  */


public 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");
PrintWriter out = response.getWriter();
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
out.print(echostr);
}
out.close();
out = null;
}
}




//SignUtil.java签名校验文件在servlet文件中调用












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


/**
* 验证签名
* @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);
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];  // 取一个字节的高4位,然后获得其对应的十六进制字符
tempArr[1] = Digit[mByte & 0X0F];//  取一个字节的低4位,然后获得其对应的十六进制字符  
String s = new String(tempArr);
return s;
}
}




//配置web.xml文件的servlet




<servlet>
  <servlet-name>weixinServlet</servlet-name>
  <servlet-class>com.yc.servlets.weixinServlet</servlet-class>
 </servlet>
 <servlet-mapping>
  <servlet-name>weixinServlet</servlet-name>
  <url-pattern>/weixinServlet</url-pattern>
 </servlet-mapping>










做到这里,准备工作已经完成以下的步奏我只是提示一下




1、在新浪云上发布你的项目
2、将token、URL填写,生成EncodingAESKey
3、选择明文模式
4、提交




注意:URL是项目的URL+/weixinServlet

微信开发

阅读数 90

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