2017-06-30 01:44:24 phil_jing 阅读数 4530
  • 微信公众平台深度开发v2.0第1季——微信公众号基础...

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

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

官方文档

准备工作:已通过微信认证的公众号,域名可以不通过ICP备案
借鉴了很多大神的文章,在此先谢过了
大体过程:根据固定金额和商品的ID先生成订单,再生成二维码,客户扫一扫付款
模式二支付的流程如下图,可以说是最简单的支付方式了

原生支付模式二时序图

业务流程说明:

(1)商户后台系统根据用户选购的商品生成订单。
(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;
(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。
(4)商户后台系统根据返回的code_url生成二维码。
(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。
(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。
(8)微信支付系统根据用户授权完成支付交易。
(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。
(12)商户确认订单已支付后给用户发货。

一、生成微信支付二维码

订单可以在订单表中新建一条数据,然后用id作为product_id

 /**
     * 扫码模式二
     *
     * @param params
     * @throws Exception
     */
    @RequestMapping("M2")
    public Map<String, Object> paytwo(HttpServletRequest request, UnifiedOrderParams params) throws Exception {
        Map<String, Object> data = new HashMap<>();
        // 商户后台系统根据用户选购的商品生成订单。
        String out_trade_no = PayHelper.createNonceStr();
        String product_id = DateUtils.getCurrentTime();// 根据自己的逻辑生成
        // int total_fee = 1; // 1分作测试
        // String attach = "支付测试";
        // String body = "微信支付-支付测试";
        String nonce_str = PayHelper.createNonceStr();
        String spbill_create_ip = HttpUtil.getRemortIP(request); // 获取IP
        UnifiedOrderParams unifiedOrderParams = new UnifiedOrderParams();
        unifiedOrderParams.setAppid(wechatAccountConfig.getAppid());// 必须
        unifiedOrderParams.setMch_id(PayConstant.MCH_ID);// 必须
        unifiedOrderParams.setOut_trade_no(out_trade_no);
        unifiedOrderParams.setBody(params.getBody());
        unifiedOrderParams.setAttach(params.getAttach());
        unifiedOrderParams.setProduct_id(product_id);// 必须
        unifiedOrderParams.setTotal_fee(params.getTotal_fee());// 必须
        unifiedOrderParams.setNonce_str(nonce_str); // 必须
        unifiedOrderParams.setSpbill_create_ip(spbill_create_ip); // 必须
        unifiedOrderParams.setTrade_type("NATIVE");// 必须
        unifiedOrderParams.setNotify_url(wechatPayConfig.getNotifyUrl()); // 异步通知URL
        // 统一下单 请求的Xml(除detail外不需要<![CDATA[product_001]]>格式)
        String unifiedXmL = PayHelper.toPayXml(unifiedOrderParams); // 签名并入util
        // log.debug("统一下单 请求的Xml"+unifiedXmL);
        // 统一下单 返回的xml(<![CDATA[product_001]]>格式)
        String unifiedResultXmL = HttpUtil.doPost(
                wechatPayConfig.getUnifiedOrderUrl(), null, unifiedXmL);
        // log.debug("统一下单 返回的xml("+unifiedResultXmL);
        // 统一下单返回 验证签名
        if (SignatureUtil.checkValidPaySign(unifiedResultXmL, null)) {
            UnifiedOrderResult unifiedOrderResult = XmlUtil.fromXml(unifiedResultXmL,
                    UnifiedOrderResult.class);
            if (Objects.equals("SUCCESS", unifiedOrderResult.getReturn_code())
                    && Objects.equals("SUCCESS", unifiedOrderResult.getResult_code())) {
                /**** 根据unifiedOrderResult.getCode_url()生成有效期为2小时的二维码 ****/


                /**** 根据product_id再次支付方法自己写 ****/
            }
        } else {
            log.debug("签名验证错误");
        }
        return data;
    }

 

二、完成支付并通知支付结果

package com.phil.wechat.pay.controller;

import com.phil.modules.result.ResultState;
import com.phil.modules.util.SignatureUtil;
import com.phil.modules.util.XmlUtil;
import com.phil.wechat.pay.model.response.PayNotifyResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.util.Objects;

/**
 * 微信支付结果通知(统一下单参数的notify_url)
 *
 * @author phil
 * @date 2017年6月27日
 */
@RestController
@RequestMapping("api/wxpay")
@Slf4j
public class WechatPayNotifyController {

    @RequestMapping("notify")
    public ResultState notice(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ResultState resultState = new ResultState();
        log.debug("开始处理支付返回的请求");
        String resXml = ""; // 反馈给微信服务器
        String notifyXml = IOUtils.toString(request.getInputStream());// 微信支付系统发送的数据(<![CDATA[product_001]]>格式)
        log.debug("微信支付系统发送的数据" + notifyXml);
        // 验证签名
        if (SignatureUtil.checkValidPaySign(notifyXml, null)) {
            PayNotifyResult notify = XmlUtil.fromXml(notifyXml, PayNotifyResult.class);
            log.debug("支付结果 {}", notify.toString());
            if (Objects.equals("SUCCESS", notify.getResult_code())) {
                resultState.setErrcode(0);// 表示成功
                resultState.setErrmsg(notify.getResult_code());
                /**** 业务逻辑 保存openid之类的 ****/
                // 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            } else {
                resultState.setErrcode(-1);// 支付失败
                resultState.setErrmsg(notify.getErr_code_des());
                log.debug("支付失败,错误信息:" + notify.getErr_code_des());
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA["
                        + notify.getErr_code_des() + "]]></return_msg>" + "</xml> ";
            }
        } else {
            resultState.setErrcode(-1);// 支付失败
            resultState.setErrmsg("签名验证错误");
            log.debug("签名验证错误");
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[签名验证错误]]></return_msg>" + "</xml> ";
        }
        try (BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream())) {
            out.write(resXml.getBytes());out.flush();
        } catch (Exception e) {

            log.error(e.getMessage());
        }
        return resultState;
    }
}

可以说这是最简单的支付方式了

具体源码:https://github.com/philjing/my_wechat/tree/master/src/main/java/com/phil/wechat/pay

扫一扫加群

 

2015-12-31 16:45:45 u012178818 阅读数 234
  • 微信公众平台深度开发v2.0第1季——微信公众号基础...

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

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

       

         完成了基础配置之后,我们就可以进行微信开发啦。首先要讲的就是微信的消息接收与返回,我们在公众号中向微信发送的消息都会通过我们上次配置的接口传给微信,微信会将数据格式化成固定的xml格式。

<xml>

 <ToUserName><![CDATA[gh_680bdefc8c5d]]></ToUserName>  公众帐号

 <FromUserName><![CDATA[oIDrpjqASyTPnxRmpS9O_ruZGsfk]]></FromUserName> 发送方帐号(open_id)

 <CreateTime>1359028446</CreateTime>

 <MsgType><![CDATA[text]]></MsgType>  消息<span style="font-family:Microsoft YaHei;">类型</span>

 <Content><![CDATA[测试文字]]></Content>   用户发送的数据

 <MsgId>5836982729904121631</MsgId>

</xml>
 

       我们服务器所要做的就是解析这xml数据,根据用户发送的内容及内容格式,返回给用户指定消息。

        接下来,我们就进行实战,写个简单的例子。

    第一步:将我们上次的方法再加个写一个post类型的方法。

@RequestMapping(value = "/checkSignature", method = RequestMethod.POST)
	public String checkSignature2(HttpServletRequest request, HttpServletResponse response

	) throws IOException {
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");
		String respMessage = CoreService.processRequest(request);

		response.getWriter().write(respMessage);
		return null;
	}

   第二部:在CoreService中解析微信发过来的数据,根据用户的内容及格式返回指定值。


        

  Map<String, String> requestMap = MessageUtil.parseXml(request);
	  
			// 发送方帐号(open_id)
			String fromUserName = requestMap.get("FromUserName");
			// 公众帐号
			String toUserName = requestMap.get("ToUserName");
			// 消息类型
			String msgType = requestMap.get("MsgType");
<span style="white-space:pre">	</span>              if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
<span style="white-space:pre">				</span>String Content = requestMap.get("Content");
<span style="white-space:pre">				</span>// 创建图文消息
<span style="white-space:pre">				</span>NewsMessage newsMessage = new NewsMessage();
<span style="white-space:pre">				</span>newsMessage.setToUserName(fromUserName);
<span style="white-space:pre">				</span>newsMessage.setFromUserName(toUserName);
<span style="white-space:pre">				</span>newsMessage.setCreateTime(new Date().getTime());
<span style="white-space:pre">				</span>newsMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_NEWS);
<span style="white-space:pre">				</span>newsMessage.setFuncFlag(0);
                               
<span style="white-space:pre">				</span>
<span style="white-space:pre">				</span>if(Content.equals("1")){  //判断文本消息为1时发送返回消息欢迎您
<span style="white-space:pre">					</span>respContent = "欢迎您";
<span style="white-space:pre">					</span>textMessage.setContent(respContent);
 <span style="white-space:pre">				</span>   respMessage = MessageUtil.textMessageToXml(textMessage);
<span style="white-space:pre">				</span>}

   

MessageUtil.java

public class MessageUtil {
	/**
	 * 返回消息类型:文本
	 */
	public static final String RESP_MESSAGE_TYPE_TEXT = "text";

	/**
	 * 返回消息类型:音乐
	 */
	public static final String RESP_MESSAGE_TYPE_MUSIC = "music";

	/**
	 * 返回消息类型:图文
	 */
	public static final String RESP_MESSAGE_TYPE_NEWS = "news";

	/**
	 * 请求消息类型:文本
	 */
	public static final String REQ_MESSAGE_TYPE_TEXT = "text";

	/**
	 * 请求消息类型:图片
	 */
	public static final String REQ_MESSAGE_TYPE_IMAGE = "image";

	/**
	 * 请求消息类型:链接
	 */
	public static final String REQ_MESSAGE_TYPE_LINK = "link";

	/**
	 * 请求消息类型:地理位置
	 */
	public static final String REQ_MESSAGE_TYPE_LOCATION = "location";

	/**
	 * 请求消息类型:音频
	 */
	public static final String REQ_MESSAGE_TYPE_VOICE = "voice";

	/**
	 * 请求消息类型:推送
	 */
	public static final String REQ_MESSAGE_TYPE_EVENT = "event";

	/**
	 * 事件类型:subscribe(订阅)
	 */
	public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";

	/**
	 * 事件类型:unsubscribe(取消订阅)
	 */
	public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";

	/**
	 * 事件类型:CLICK(自定义菜单点击事件)
	 */
	public static final String EVENT_TYPE_CLICK = "CLICK";

	/**
	 * 解析微信发来的请求(XML)
	 */
	public static Map<String, String> parseXml(HttpServletRequest request)
			throws Exception {
		// 将解析结果存储在HashMap中
		Map<String, String> map = new HashMap<String, String>();

		// 从request中取得输入流
		InputStream inputStream = request.getInputStream();
		// 读取输入流
		SAXReader reader = new SAXReader();
		Document document = reader.read(inputStream);
		// 得到xml根元素
		Element root = document.getRootElement();
		// 得到根元素的所有子节点
		List<Element> elementList = root.elements();

		// 遍历所有子节点
		for (Element e : elementList)
			map.put(e.getName(), e.getText());

		// 释放资源
		inputStream.close();
		inputStream = null;

		return map;
	}

	/**
	 * 文本消息对象转换成xml
	 */

	public static String textMessageToXml(TextMessage textMessage) {
		xstream.alias("xml", textMessage.getClass());
		return xstream.toXML(textMessage);
	}

	/**
	 * 音乐消息对象转换成xml
	 */
	public static String musicMessageToXml(MusicMessage musicMessage) {
		xstream.alias("xml", musicMessage.getClass());
		return xstream.toXML(musicMessage);
	}

	/**
	 * 图文消息对象转换成xml
	 */
	public static String newsMessageToXml(NewsMessage newsMessage) {

		xstream.alias("xml", newsMessage.getClass());
		xstream.alias("item", new Article().getClass());
		return xstream.toXML(newsMessage);
	}

	/**
	 * xstream拓展
	 */
	private static XStream xstream = new XStream(new XppDriver() {
		public HierarchicalStreamWriter createWriter(Writer out) {
			return new PrettyPrintWriter(out) {
				// 对所有xml节点的转换都增加CDATA标记
				boolean cdata = true;

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

				protected void writeText(QuickWriter writer, String text) {
					if (cdata) {
						writer.write("<![CDATA[");
						writer.write(text);
						writer.write("]]>");
					} else {
						writer.write(text);
					}
				}
			};
		}
	});
}



       最后一步当然就是检验我们的结果啦,打开微信,搜索微信公众号‘苏州创游’


       

   消息类是有很多种类的,大家可以在了解最简单的文本消息后,试试其他的消息。


2017-05-31 15:15:37 csdn_Info 阅读数 3698
  • 微信公众平台深度开发v2.0第1季——微信公众号基础...

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

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

微信支付文档

1、生成二维码
2、二维码回调
3、支付成功回调
4、监听是否成功
4、错误解决方案

官方上说的这里就不提了。
官方文档地址

简单理解的流程
1、开发者设置微信参数生成二维码
2、微信公众平台设置 支付回调URL (eg:http://xxx.com/wxpay/return_url.aspx
i.必须外网能够访问,并且有域名和后缀 .xxx,并且回调页面只能直接继承

System.Web.UI.Page

不能间接继承:eg: child:parent,System.Web.UI.Page

3、用户扫描二维码后,微信会请求设置的支付回调地址并传回一个XML文件流数据,其中数据包含了生成二维码时传的参数
4、在支付回调地址中获取微信传回的XML 文件流,并调用微信的 统一下单接口,设置统一下单接口需要的参数,发送给微信服务器。
i.统一下单接口为:https://api.mch.weixin.qq.com/pay/unifiedorder
5、微信服务器进行处理,生成预支付交易,并返回XML文件流,其中包含交易会话标识(prepay_id)
6、开发者获取到XML 后,将此XML 发送到微信服务器()
7、微信支付系统根据交易会话标识,发起用户端授权支付流程
8、用户在微信客户端输入密码,确认支付后,微信客户端提交支付授权
9、微信支付系统验证后扣款,完成支付交易
10、微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
11、微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况
i.异步回调地址notify_url

ASP.NET 扫码支付模式一,代码
1、生成二维码
a)使用 ThoughtWorks.QRCode 程序集

// 微信提供的类
WxPayData data = new WxPayData();
data.SetValue("appid", WxPayConfig.APPID);//公众帐号id
data.SetValue("mch_id", WxPayConfig.MCHID);//商户号
data.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//随机字符串
data.SetValue("product_id", tempPrId.ToString());//商品ID
data.SetValue("time_stamp", WxPayApi.GenerateTimeStamp());//时间戳
data.SetValue("sign", data.MakeSign());//签名
string str = ToUrlParams(data.GetValues());//转换为URL串
string url = "weixin://wxpay/bizpayurl?" + str;// url
//日志
Log.Info(this.GetType().ToString(), "Get native pay mode 1 url : " + url);
// 生成二维码
CreateQrcode(url);
**// 生成二维码函数**
private void CreateQrcode(string nr)
{
        Bitmap bt;
        string enCodeString = nr;
        QRCodeEncoder qrCodeEncoder = new QRCodeEncoder();
        qrCodeEncoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;
        qrCodeEncoder.QRCodeScale = 4;
        qrCodeEncoder.QRCodeVersion = 0;// 超出索引,修改为0
        qrCodeEncoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M;
        bt = qrCodeEncoder.Encode(enCodeString);
        Random dom = new Random();
        int randomnum = dom.Next(0, 999);
        string filename = DateTime.Now.ToString("yyyymmddhhmmssfff") + randomnum;
        string path = Server.MapPath("~/Images/wxpaycode/") + filename + ".jpg";
        // 此处是在服务器上部署时出现 GDI+ XXX的错误而添加的,本地没错误。(效果嘛....呵呵。可以考虑注释掉此段代码)
        Bitmap bmp = new Bitmap(bt);
        bt.Dispose();// 
        bmp.Save(path);
        this.ImageCode.ImageUrl = "~/Images/wxpaycode/" + filename + ".jpg";
}

2、支付回调地址(用户扫码后的回调地址操作)

// 微信返回的是xml 格式的数据,eg:

<xml>
<appid><![CDATA[wx5e9360a3f46f64cd]]></appid>
<openid><![CDATA[o_pncsidC-pRRfCP4zj98h6slREw]]></openid>
<mch_id><![CDATA[1322117501]]></mch_id>
<is_subscribe><![CDATA[Y]]></is_subscribe>
<nonce_str><![CDATA[y4dGR6JxuybgUWUo]]></nonce_str>
<product_id><![CDATA[001]]></product_id>
<sign><![CDATA[89951BAE8796DE7D32E9741E42C35FB4]]></sign>
</xml>

// 2.1获取用户扫描二维码后,微信返回的信息

//接收并读取POST过来的XML文件流
StreamReader reader = new StreamReader(Request.InputStream);
String xmlData = reader.ReadToEnd();
WxPayData obj = new WxPayData();
SortedDictionary<string, object> dic = obj.FromXml(xmlData);
//此处获取产品id
int rankid = Convert.ToInt32(dic["product_id"].ToString());
Rank rankobj = new Rank();
RankEntity entity = rankobj.Select(rankid);
if (entity != null)
{
    //dic["openid"]
    //统一下单接口
    WxPayData wxdata = new WxPayData();// 微信提供的类
    wxdata.SetValue("appid", WxPayConfig.APPID);//公众帐号id
    wxdata.SetValue("mch_id", WxPayConfig.MCHID);//商户号
    wxdata.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//随机字符串
    wxdata.SetValue("product_id", dic["product_id"]);//商品ID
    wxdata.SetValue("time_stamp", WxPayApi.GenerateTimeStamp());//时间戳
    wxdata.SetValue("body", "测试");// 商品描述
    wxdata.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());//订单号
    wxdata.SetValue("total_fee", entity.Price * 100);//金额*100为真正金额,测试使用 1 为 1 分钱
    wxdata.SetValue("spbill_create_ip", ValidateHelper.GetHostAddress());//终端IP
    wxdata.SetValue("notify_url", WxPayConfig.NOTIFY_URL);//支付回调地址
    wxdata.SetValue("trade_type", "NATIVE");//交易类型(--原生扫码支付)
    wxdata.SetValue("openid", dic["openid"]);// 用户标识,当(trade_type=JSAPI)时,为必填参数
    // 附加数据(订单号,金额,rank id(级别ID)),类似于支付宝的公共回传参数
    wxdata.SetValue("attach", wxdata.GetValue("out_trade_no") + "_" + wxdata.GetValue("total_fee") + "_" + rankid);
    Log.Info(this.GetType().ToString(), "wxdata:wxdata=true");
    WxPayData returnData = WxPayApi.UnifiedOrder(wxdata);// 请求微信微信服务器统一下单接口,生成预处理订单(微信demo 类方法)
    Response.Write(returnData.ToXml());// 回发给微信
    Response.End();
}

3、支付成功异步回调(用户支付成功后的回调地址操作)

//接收并读取POST过来的XML文件流
StreamReader reader = new StreamReader(Request.InputStream);
String xmlData = reader.ReadToEnd();
WxPayData obj = new WxPayData();
SortedDictionary<string, object> dic = obj.FromXml(xmlData);
Log.Info(this.GetType().ToString(), "return_code:back=" + dic["return_code"]);//日志
Log.Info(this.GetType().ToString(), "公共回传参数:attach=" + dic["attach"]);

if (Equals(dic["return_code"].ToString(), "SUCCESS") && Equals(dic["result_code"].ToString(), "SUCCESS"))
{
    // 判断SUCCESS 后,可以修改数据信息
    string[] parmaArr = dic["attach"].ToString().Split('_');
    int uid = ValidateHelper.GetNullableInt(Session["uid"] ?? "0");
    // 支付记录
    PayRecord pr = new PayRecord();
    PayRecordEntity pre = new PayRecordEntity();
    pre.UserId = uid;
    pre.PayOrder = parmaArr[0];// 订单号
    pre.RankId = Convert.ToInt32(parmaArr[2]);
    pre.PayType = 2;// 微信
    pre.PayDate = DateTime.Now;
    pre.PayAmount = Convert.ToDecimal(parmaArr[1]);
    int res = pr.Save(pre);
    if (res > 0)
    {
        // 用户信息更改
        User user = new User();
        UserEntity ue = user.Select(uid);
        ue.RankId = ue.RankId > pre.RankId ? ue.RankId : pre.RankId;
        int ures = user.Save(ue);
        if (ures > 0)
        {
            Response.Redirect("../index.aspx");
        }
    }
}

4、二维码页面监听是否完成(根据需求)
利用 jquery 定时请求一个地址,这个地址内查询数据库的订单状态。
如果订单状态更改为成功,则二维码页面提示支付成功并跳转。

    <script type="text/javascript">
        setInterval("CheckStatus()", 3000);
        function CheckStatus() {
            $.post("../Handler/GetDataHandler.ashx", { status: $("#HiddenField1").val(), flag: 19 }, function (data) {
                if (data) {
                    var json = JSON.parse(data);
                    layer.msg(json.result, {
                        icon: 1,
                        time: 2000
                    }, function () {
                        window.location.href = json.url;
                    });
                }
            });
        }
    </script>

// 出现的错误和解决方案
1、原生支付URL参数错误
解决方案:检查生成二维码的参数,校验签名是否正确(微信提供的sign签名算法生成的签名不正确(我是测试了不正确,然后我自己写的MD5加密的sign))
微信提供的签名校验工具地址:

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=20_1

2、获取商户订单信息超时或者商户返回的httpcode非200
在用户扫码二维码后,在二维码回调页面获取微信数据的同时也需要将数据再重新回发给微信(见:2.1)

2016-12-27 16:31:38 getluo 阅读数 1358
  • 微信公众平台深度开发v2.0第1季——微信公众号基础...

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

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

首先需要公众号有模板消息的权限,这里不多说明了。


要实现的功能就是在第三方网站通过调用接口在对给用户发消息,当然也可以给用户标签组群发消息。


获取access_token代码:

$weixin_appid = "";
$weixin_secret = "";
$weixin_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$weixin_appid."&secret=".$weixin_secret;
$weixin_return = get_url_contents ( $weixin_url );
$weixin = json_decode ( $weixin_return );
$access_token = $weixin->access_token;
//模板ID
$template_id = "";

发送消息代码:

				$dataarray = array(
						"touser"=>$openid,//用户的openid
						"template_id"=>$template_id,//消息模板id
						"url"=>$_POST['yanbao_url'],
						"data"=>array(
						    "first"=>array(
				                       "value"=>$_POST['yanbao_title'],
				                       "color"=>"#173177"
				                    ),
				                    "keyword1"=>array(
				                       "value"=>$_POST['yanbao_name'],
				                       "color"=>"#173177"
				                    ),
				                    "keyword2"=>array(
				                       "value"=>$_POST['yanbao_desc'],
				                       "color"=>"#173177"
				                    ),
				                    "remark"=>array(
				                       "value"=>$_POST['yanbao_more'],
				                       "color"=>"#173177"
				                    )
								)
				            );
				$data = json_encode($dataarray);
				$output = json_decode(do_post($url,$data));//do_post是模拟post的函数,请自行定义
				if($output->errcode == '0'){
					echo '<div class="updated"><p>发送成功!</p></div>';
				}else{
					echo '<div class="error"><p>发送失败!错误码:'.$output->errcode.'</p></div>';
				}

获取用户标签代码:

				<tr valign="top">
					<th scope="row"><label>用户标签</label></th>
					<td>
						<select name="yanbao_user_tag" id="yanbao_user_tag" style="min-width: 150px">
							<option value="">请选择</option>
							<option value="all">所有用户</option>
							<?php 
								$yanbao_user_tag_url = "https://api.weixin.qq.com/cgi-bin/tags/get?access_token=".$access_token;
								$yanbao_user_tag_return = get_url_contents ( $yanbao_user_tag_url );
								$yanbao_user_tag = json_decode ( $yanbao_user_tag_return );
								$tags = $yanbao_user_tag->tags;
								foreach ($tags as $tag) {
									echo '<option value="'.$tag->id.'">'.$tag->name.'('.$tag->count.')</option>';
								}
							?>		
						</select>
						<span class="description">(选择了用户标签就是<strong>群发</strong>给该标签下的用户)</span>
					</td>
				</tr>

获取用户代码:

<tr valign="top">
					<th scope="row"><label>用户</label></th>
					<td>
						<select name="yanbao_user" id="yanbao_user">
							<option selected="selected" value="">请选择</option>
							<?php 
								/*
								$yanbao_user_url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=".$access_token."&next_openid=";
								$yanbao_user_return = get_url_contents ( $yanbao_user_url );
								$yanbao_user = json_decode ( $yanbao_user_return );
								$openids = $yanbao_user->data->openid;
								foreach ($openids as $openid) {
									$added_user = Moge_check_weixin_user_added($openid);
									if($added_user){
										echo '<option value="'.$openid.'">'.$added_user->nickname.'</option>';
									}else{
										$user = Moge_weixin_get_user_info($access_token,$openid);
										$wpdb->query("insert into ".$wpdb->prefix."erphp_weixin_users (openid,nickname) values('".$openid."','".$user->nickname."')");
										echo '<option value="'.$openid.'">'.$user->nickname.'</option>';
									}
								}*/
								
								$weixin_users = Moge_get_weixin_users();//获取本地数据库里的微信用户函数
								if($weixin_users){
									foreach ($weixin_users as $user) {
										echo '<option value="'.$user->openid.'">'.$user->nickname.'</option>';
									}
								}
								
							?>
						</select>
						<span class="description">(若已选择了用户标签,此项选择就无效了。)</span>
					</td>
				</tr>


这里主要遇到一个问题就是如果高效快速的获取用户列表的昵称(nickname),通过以下的接口

https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID

只能获取用户的openid,我尝试过针对每个用户获取其详细资料,结果页面直接卡死了(用户数量太多)。虽然看到有批量获取资料,但是不适合用,最后没办法,只能先循环获取然后存在本地数据库,定期获取更新下数据库了,有个弊端就是取消关注的人还是会在本地数据库里。

2020-01-09 16:53:06 u011400521 阅读数 10
  • 微信公众平台深度开发v2.0第1季——微信公众号基础...

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

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

在使用企业微信中,如果需要接收到企业微信用户发送的消息或者监测通讯录是否发生改动时,就需要用到企业微信的回调模式。

回调模式接口地址:https://work.weixin.qq.com/api/doc/90000/90135/90930

调用回调模式需要事先准备一台有固定公网IP或者域名指向的服务器,这台服务器用于后面接收企业微信下发的各种数据。

第一步 创建应用

 

第二步 设置API配置

这边的参数说明:

URL为回调的服务器地址可以使用公网IP或者域名,要加上项目名称

Token用于计算签名可以自己设定也可以随机生成

EncodingAESKey用于消息内容加密同样可以自己设定或随机生成

将三个参数设置好,先不要点击保存,点击保存时企业微信就会下发验证消息,验证不成功会提示失败。

 

第三步 编写服务器端代码

企业微信提供了用于url验证的加解密库

大家可以根据自己的语言选择对应库,我这边使用的是Java

将加解密库文件放到自己项目里

回调模式首先会验证url有效性,这边企业微信会向之前填写的url发送一条xml信息,里面包含四个参数

验证步骤一共四步

解密验证的代码:

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import bean.Token;
import common.xml.XMLDeal;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import wwapi.WXDoMessage;
import wxutil.AesException;
import wxutil.WXBizMsgCrypt;

/**
 * Servlet implementation class GetMassage
 */
@WebServlet("/GetUrlVerify")
public class GetUrlVerify extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public GetUrlVerify() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String msg_signature = request.getParameter("msg_signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");
		System.out.println("msg_signature:" + msg_signature);
		System.out.println("timestamp:" + timestamp);
		System.out.println("nonce:" + nonce);
		System.out.println("echostr:" + echostr);
		WXBizMsgCrypt wxmc;
		try {
			//解密
            //corpid:wwcb74a7*******,Token:5N****,EncodingAESKey:48wJVcsQlHedUeiESoJMpWy*****************
			wxmc = new WXBizMsgCrypt("5N****", "48wJVcsQlHedUeiESoJMpWy*****************", "wwcb74a7*******");
			String newechostr = wxmc.VerifyURL(msg_signature, timestamp, nonce, echostr);
			System.out.println(newechostr);
			//返回明文
			PrintWriter writer = response.getWriter();
			writer.println(newechostr);
		} catch (AesException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
	}

}

将项目放到服务器上运行,再配置页面点击保存

验证成功后,回调模式就可以开始使用了

 

更多腾讯接口开发可以关注本人微信公众号查看

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