微信支付公的众号支付和扫码支付

公众号支付是手机端的微信公众号H5页面支付,这种支付方式必须是在微信内置浏览器发起。

扫码支付分为模式一和模式二,模式一主要为线下服务,该模式是先扫码,再生成订单,商户先为自己的商品生成二维码连接,然后用户扫码之后决定是否购买,二维码无过期时间,比如自动售卖机大多采用这种模式;模式二主要为线上电商服务,用户选择商品后生成订单,根据订单生成二维码,然后支付,该二维码为临时二维码。

开发流程

一、授权目录

官方文档说必须是精确目录,其实是二级或三级目录就可以了,太精确的可能还会出现不识别的情况。如果是扫码支付模式一还需要设置扫码支付回调URL

二.统一下单

注意传入参数不要为null,尽量不要是空字符串,如果在没有抛出Exception的情况下支付失败,十有八九是参数导致的签名有问题,微信支付的签名规定的特别严格,必须按照微信给的规则来,建议第一次先用demo提供的签名方法,以后可以再修改。这里的appid就是支付所在的公众号的appid,openId是用户对应当前公众号的openId。

1、扫码支付模式二

扫码支付比较简单,可以直接通过url发起,传入统一下单参数,生成扫码支付的url。扫码支付的trade_type为NATIVE。

public void getCodeUrl(@PathVariable(value="tradeNo")String tradeNo, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		//根据订单号获取订单详情
		OrderProduceBean order = reservationCarService.getTradebyNo(tradeNo);

		// 附加数据 原样返回
		String attach = "attach";
		// 总金额以分为单位,不带小数点
		String totalFee = TenpayUtil.getMoney(order.getTotalFee().toString());
		// 订单生成的机器 IP
		String spbill_create_ip = IpUtil.getIpAddr(request);
		// 这里notify_url是 支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等。
		String notify_url = TenPayConfig.notifyUrl;
		String trade_type = "NATIVE";
		// 商户号
		String mch_id = TenPayConfig.partner;
		// 随机字符串
		String nonce_str = TenpayUtil.getNonceStr();
		// 商品描述根据情况修改
		String body = order.getBody();
		// 商户订单号
		String out_trade_no = order.getOutTradeNo();

		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		packageParams.put("appid", TenPayConfig.appid);
		packageParams.put("mch_id", mch_id);
		packageParams.put("nonce_str", nonce_str);
		packageParams.put("body", body);
		packageParams.put("attach", attach);
		packageParams.put("out_trade_no", out_trade_no);

		packageParams.put("total_fee", totalFee);
		packageParams.put("spbill_create_ip", spbill_create_ip);
		packageParams.put("notify_url", notify_url);

		packageParams.put("trade_type", trade_type);

		RequestHandler reqHandler = new RequestHandler(null, null);
		reqHandler.init(TenPayConfig.appid, TenPayConfig.appsecret,
				TenPayConfig.partnerkey);

		String sign = reqHandler.createSign(packageParams);
		String xml = "<xml>" + "<appid>" + TenPayConfig.appid + "</appid>"
				+ "<mch_id>" + mch_id + "</mch_id>" + "<nonce_str>" + nonce_str
				+ "</nonce_str>" + "<sign>" + sign + "</sign>"
				+ "<body><![CDATA[" + body + "]]></body>" + "<out_trade_no>"
				+ out_trade_no + "</out_trade_no>" + "<attach>" + attach
				+ "</attach>" + "<total_fee>" + totalFee + "</total_fee>"
				+ "<spbill_create_ip>" + spbill_create_ip
				+ "</spbill_create_ip>" + "<notify_url>" + notify_url
				+ "</notify_url>" + "<trade_type>" + trade_type
				+ "</trade_type>" + "</xml>";
		System.out.println(xml);
		String code_url = "";
		String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

		code_url = new TenPayCore().getCodeUrl(createOrderURL, xml);//调用统一下单接口
		if (code_url == null || code_url.equalsIgnoreCase("")) {
			logger.debug("****************************trade has closed or no this trade in tencentPay");
			response.sendError(404);
			return;
		}

		GenerateQrCodeUtil.encodeQrcode(code_url, response);
	}

2.公众号支付

公众号支付首先通过H5调起支付api,微信生成订单,然后开发者获取预支付id,最后由用户确认支付。

①H5调起JSAPI。

调起有两种方式,一种是WeixinJSBridge.invoke(),另一种是最新的微信JSAPI,两种方式均可,官方文档用的第一种,使用第一种方式首先要引入http://res.wx.qq.com/open/js/jweixin-1.0.0.js。

function toPay(){
	$.ajax({
		url : URL,
		type : "GET",
		dataType : 'json',
		success : function(data) {
			WeixinJSBridge.invoke('getBrandWCPayRequest', {
				"appId" : data.appId, //公众号名称,由商户传入
				"timeStamp" : data.timeStamp, //时间戳,自1970年以来的秒数
				"nonceStr" : data.nonceStr, //随机串
				"package" : data.package,
				"signType" : data.signType, //微信签名方式:
				"paySign" : data.paySign
			//微信签名
			}, function(res) {
				if (res.err_msg == "get_brand_wcpay_request:ok") {
				} // 使用以上方式判断前端返回:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。
				else{
					//res.err_msg;
				}
			});
		}
	});
}	

②获取预支付id

这个api和扫码支付的api差不多,就是trade为JSAPI不一样。

public void  TencentPayController(@RequestParam("orderno")String orderno,HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		//根据订单号查询订单
		OrderProduceBean order=reservationCarService.getTradebyNo(orderno);

		String appid = TenPayConfig.appid;
		String openId =order.getOpenId();
		// 订单号
		String orderId = order.getOutTradeNo();
		// 附加数据 原样返回
		String attach = "attach";
		// 总金额以分为单位,不带小数点
		String totalFee = TenpayUtil.getMoney(order.getTotalFee().toString());

		// 订单生成的机器 IP
		String spbill_create_ip = IpUtil.getIpAddr(request);;
		// 这里notify_url是 支付完成后微信发给该链接信息,可以判断会员是否支付成功,改变订单状态等。
		String notify_url = TenPayConfig.notifyUrl;
		String trade_type = "JSAPI";

		// ---必须参数
		// 商户号
		String mch_id = TenPayConfig.partner;
		// 随机字符串
		String nonce_str = TenpayUtil.getNonceStr();

		// 商品描述根据情况修改
		String body = order.getBody();

		// 商户订单号
		String out_trade_no = orderId;

		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		packageParams.put("appid", appid);
		packageParams.put("mch_id", mch_id);
		packageParams.put("nonce_str", nonce_str);
		packageParams.put("body", body);
		packageParams.put("attach", attach);
		packageParams.put("out_trade_no", out_trade_no);

		packageParams.put("total_fee", totalFee);
		packageParams.put("spbill_create_ip", spbill_create_ip);
		packageParams.put("notify_url", notify_url);

		packageParams.put("trade_type", trade_type);
		packageParams.put("openid", openId);

		RequestHandler reqHandler = new RequestHandler(null, null);
		reqHandler.init(appid, TenPayConfig.appsecret,TenPayConfig.partnerkey);

		String sign = reqHandler.createSign(packageParams);
		String xml = "<xml>" + "<appid>" + appid + "</appid>" + "<mch_id>"
				+ mch_id + "</mch_id>" + "<nonce_str>" + nonce_str
				+ "</nonce_str>" + "<sign>" + sign + "</sign>"
				+ "<body><![CDATA[" + body + "]]></body>"
				+ "<out_trade_no>" + out_trade_no
				+ "</out_trade_no>" + "<attach>" + attach + "</attach>"
				+ "<total_fee>" + totalFee + "</total_fee>"
				+ "<spbill_create_ip>" + spbill_create_ip
				+ "</spbill_create_ip>" + "<notify_url>" + notify_url
				+ "</notify_url>" + "<trade_type>" + trade_type
				+ "</trade_type>" + "<openid>" + openId + "</openid>"
				+ "</xml>";
		String prepay_id = "";
		String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

		prepay_id = new TenPayCore().getPayNo(createOrderURL, xml);
		logger.debug("********************************************");
		logger.debug("prepay_id :" + prepay_id);

		//获取prepay_id后,拼接最后请求支付所需要的package
		SortedMap<String, String> finalpackage = new TreeMap<String, String>();
		String timestamp = Sha1Util.getTimeStamp();
		String packages = "prepay_id="+prepay_id;
		finalpackage.put("appId", appid);
		finalpackage.put("timeStamp", timestamp);
		finalpackage.put("nonceStr", nonce_str);
		finalpackage.put("package", packages);
		finalpackage.put("signType", "MD5");
		//要签名
		String finalsign = reqHandler.createSign(finalpackage);
		finalpackage.put("paySign", finalsign);

		String finaPackage = "\"appId\":\"" + appid + "\",\"timeStamp\":\"" + timestamp
		+ "\",\"nonceStr\":\"" + nonce_str + "\",\"package\":\""
		+ packages + "\",\"signType\" : \"MD5" + "\",\"paySign\":\""
		+ finalsign + "\"";

		logger.debug("********************************************");
		logger.debug("V3 jsApi package:" + finaPackage);

		if(prepay_id.length()>0){
			this.callBack(response, request,this.gson.toJson(finalpackage));
			return;
		}else{
			this.callBack(response, request,"{\"error\":\"prepay_id is null\"}");
			return;
		}		

	}

3.支付回调

该回调方法的路径就是获取预支付id中的参数notify_url,用来处理支付完成后的业务逻辑,注意一定要检查return_code和result_code是否都为success,另外一定要给微信返回success信息.

public void notifyPay(HttpServletRequest request,
		HttpServletResponse response) throws IOException {
	// 示例报文
	String inputLine;
	String notityXml = "";
	String resXml = "";
	try {
		while ((inputLine = request.getReader().readLine()) != null) {
			notityXml += inputLine;
		}
		request.getReader().close();
	} catch (Exception e) {
		e.printStackTrace();
	}

	Map<String, String> m = TenpayUtil.parseXmlToList(notityXml);
	OrderTenPayBean orderTen = new OrderTenPayBean();
	orderTen.setAppid(m.get("appid").toString());
	orderTen.setBankType(m.get("bank_type").toString());
	orderTen.setCashFee(m.get("cash_fee").toString());
	orderTen.setFeeType(m.get("fee_type").toString());
	orderTen.setIsSubscribe(m.get("is_subscribe").toString());
	orderTen.setMchId(m.get("mch_id").toString());
	orderTen.setNonceStr(m.get("nonce_str").toString());
	orderTen.setOpenid(m.get("openid").toString());
	orderTen.setOutTradeNo(m.get("out_trade_no").toString());
	orderTen.setResultCode(m.get("result_code").toString());
	orderTen.setReturnCode(m.get("return_code").toString());
	orderTen.setSign(m.get("sign").toString());
	orderTen.setTimeEnd(m.get("time_end").toString());
	orderTen.setTotalFee(m.get("total_fee").toString());
	orderTen.setTradeType(m.get("trade_type").toString());
	orderTen.setTransactionId(m.get("transaction_id").toString());

	if ("SUCCESS".equals(orderTen.getResultCode()) && "SUCCESS".equals(orderTen.getReturnCode())<span style="font-family: Arial, Helvetica, sans-serif;">) { //必须判断</span>
		//TODO   信息入库,修改订单状态

		// 支付成功,必须给微信返回此信息,否则微信会一直调用此回调方法
		resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
				+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
	} else {
		resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
				+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
	}
	this.callBack(response, request, resXml);
}

4.退款

退款需要把商户证书apiclient_cert.p12放到指定目录下,因为有证书的情况下退款不需要密码,一定要注意业务请求的权限问题

public void refusePay(HttpServletResponse response,HttpServletRequest request,@PathVariable(value="outTradeNo")String outTradeNo) throws Exception {

	OrderProduceBean tradebyNo = reservationCarService.getTradebyNo(outTradeNo);

	SortedMap<String, String> parameters = new TreeMap<String, String>();
	parameters.put("appid", TenPayConfig.appid);
	parameters.put("mch_id", TenPayConfig.partner);
	parameters.put("nonce_str", TenpayUtil.getNonceStr());
	parameters.put("out_trade_no", tradebyNo.getOutTradeNo());
	parameters.put("out_refund_no", tradebyNo.getOutTradeNo()); // 我们自己设定的退款申请号,约束为UK
	parameters.put("total_fee", TenpayUtil.getMoney(tradebyNo.getTotalFee().toString())); // 单位为分
	parameters.put("refund_fee", TenpayUtil.getMoney(tradebyNo.getTotalFee().toString())); // 单位为分
	parameters.put("op_user_id", TenPayConfig.partner);

	RequestHandler reqHandler = new RequestHandler(null, null);
	reqHandler.init(TenPayConfig.appid, TenPayConfig.appsecret,
			TenPayConfig.partnerkey);

	String sign = reqHandler.createSign(parameters);
	parameters.put("sign", sign);

	String reuqestXml = TenpayUtil.getRequestXml(parameters);

	KeyStore keyStore  = KeyStore.getInstance("PKCS12");
	FileInputStream instream = new FileInputStream(new File(Resources.getString("cert_url")));
	try {
		keyStore.load(instream, TenPayConfig.partner.toCharArray());
	} finally {
		instream.close();
	}

	// Trust own CA and all self-signed certs
	SSLContext sslcontext = SSLContexts.custom()
			.loadKeyMaterial(keyStore, TenPayConfig.partner.toCharArray())
			.build();
	// Allow TLSv1 protocol only
	SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
			sslcontext,
			new String[] { "TLSv1" },
			null,
			SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
	CloseableHttpClient httpclient = HttpClients.custom()
			.setSSLSocketFactory(sslsf)
			.build();
	try {
		HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
		System.out.println("executing request" + httpPost.getRequestLine());
		StringEntity reqEntity = new StringEntity(reuqestXml);
		// 设置类型
		reqEntity.setContentType("application/x-www-form-urlencoded");
		httpPost.setEntity(reqEntity);
		CloseableHttpResponse reqs = httpclient.execute(httpPost);
		try {
			HttpEntity entity = reqs.getEntity();
			if (entity != null) {
				System.out.println("Response content length: " + entity.getContentLength());
				BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
				String returnXml = "";
				String text;
				while ((text = bufferedReader.readLine()) != null) {
					returnXml += text;
				}
				//微信退款返回的参数转换为Map
				Map<String, String> resultMaP = TenpayUtil.parseXmlToList(returnXml);
				this.callBack(response, request, resultMaP.toString());
				//TODO   信息入库			

			}
			EntityUtils.consume(entity);
		} finally {
			reqs.close();
		}
	} finally {
		httpclient.close();
	}

}

PS:代码仅供参考!

时间: 2024-11-09 04:04:57

微信支付公的众号支付和扫码支付的相关文章

聚合支付入驻墨西哥,全国即将统一扫码支付

亚马逊虽然是全世界规模最大的网络零售商,但是在聚合支付领域,亚马逊并未获得主导优势.不过亚马逊聚合支付迎来了一个重要推动,据外媒最新消息,墨西哥央行正与亚马逊公司进行谈判,以推出一种新的政府支持的聚合支付系统,该系统将允许消费者使用二维码支付在线购物费用. 据报道,这将是这家全球最大的在线零售商首次在墨西哥提供这样的扫码技术,并最终可能在这个半数以上人口没有银行账户的国家获得新的购物客户群.这一名为"CoDi"的支付系统是由墨西哥央行(Banxico)建设的.该系统将允许客户使用二维码

微信支付—— 扫码支付

个人认为扫码支付比Jsapi支付从开发和使用上要顺心的多.扫码支付不用担心是PC端还是移动浏览器还是微信客户端访问的问题,生成一个二维码,扫描支付即可. 一些配置和代码SDK以及SDK存在的错误可以参考上一篇 微信支付的文章 http://blog.csdn.net/m0sh1/article/details/45199711 友情提示以下内容实在简陋 - -# 如果你跑通了 Jsapi支付,那么扫码支付其实没什么太特别的. 扫码支付发起支付的文件在 example SDK 中的 native.

怎么对接个人收款支付接口(扫码支付)

怎么对接个人收款支付接口(扫码支付) 实现个人收款是一件很麻烦的事,可以通过PAYJX 支付平台 注册个人收款接口,帮助签约个人支付宝,微信支付接口(不需要营业执照),几分钟就可以开通,申请开通后,获取商户号和通信密钥,然后开始对接,上一章讲了收银台模式支付,本章主要说一下扫码支付 扫码支付请求步骤: 构建请求参数 POST 参数到请求地址 根据返回内容展示二维码 用户支付成功后接收异步通知 扫码对接 php代码如下: <?php $order = [ 'mchid' => 'xxxxxxxx

支付宝支付-支付宝PC端扫码支付

前言 支付宝支付—沙箱环境使用支付宝支付-支付宝PC端扫码支付「本文」支付宝支付-手机浏览器H5支付「待写」 PC端扫码支付,其实就是就是 电脑网站支付,本文基于支付宝沙箱环境,不了解的可以看一下上边的链接. 废话不多说,直接进入主题. 下载运行测试Demo 官方Demo下载链接:电脑网站支付(Java) 下载后导入 IDEA 中运行如下图所示: 如果在导入运行过程遇到错误,请参考这篇文章:IDEA中导入支付宝电脑网站支付测试Demo遇到的错误 进行支付测试,注意付款要用沙箱环境提供的支付宝AP

微信公众号 扫码支付 模式二 demo

扫码支付 本文附有代码,在下方,如果不熟悉场景的可以看看下面的场景介绍 场景介绍 官网介绍地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1 用户扫描商户展示在各种场景的二维码进行支付. 步骤1:商户根据微信支付的规则,为不同商品生成不同的二维码(如图6.1),展示在各种场景,用于用户扫描购买. 步骤2:用户使用微信"扫一扫"(如图6.2)扫描二维码后,获取商品支付信息,引导用户完成支付(如图6.3). 图6

8. PHP接入微信的三种支付:APP支付、公众号支付、扫码支付

微信的支付逻辑与支付宝的支付有一些差别.为了让客户端忽略这些差别,统一调用.本sdk做了对应处理. # SDK调用 微信支付不同接口需要的参数会有差别.请大家在使用接口时,仔细查看文档. use Payment\ChargeContext; use Payment\Config; use Payment\Common\PayException; // 微信支付,必须设置时区,否则发生错误 date_default_timezone_set('Asia/Shanghai'); // 生成订单号 便

asp.net core 微信支付工具类(H5支付,扫码支付,公众号支付,app支付)之2-H5支付

上一篇说到微信扫码支付,今天来分享下微信H5支付,适用场景为手机端非微信浏览器调用微信H5支付惊醒网站支付业务处理.申请开通微信H5支付工作不多做介绍,直接上代码. 首先是微信支付业务类(WxPayService)中的方法,传上必要的参数,该方法将会构造请求XML字符串到微信api接口,H5支付用到的是返回XML参数的mweb_url的值,控制器中的Aciton方法调用该业务层方法得到mweb_url的值,此时,前端ajax调用控制器返回mweb_url值,直接将window.localtion

微信支付之扫码支付、公众号支付、H5支付、小程序支付相关业务流程分析总结

前言 很久以来,一直想写一篇微信支付有关的总结文档:一方面是总结自己的一些心得,另一方面也可以帮助别人,但是因种种原因未能完全理解透彻微信支付的几大支付方式,今天有幸做一些总结上的文章,也趁此机会,将一年多以来的相关经验分享一下. 概述 1. 扫码支付 商户在pc端展示一个支付二维码,用户使用微信扫一扫功能,扫码后实现付款的支付方式. 2. 公众号支付 商户在微信APP内(微信浏览器)打开H5网页,通过微信支付实现付款的支付方式. 3. H5支付 商户在微信浏览器以外的手机浏览器打开H5网页,通

微信:微信扫码支付、调用统一下单接口、网站支付 + springmvc

一.场景:公司需要在网站上进行微信支付. 二.API:使用微信开放平台的接入微信支付 -扫码支付.微信支付开发者平台链接 三.分析: 接入扫码支付(包含PC网站支付)包含三个阶段,问这里只讲使用,也就是第2阶段的<启动设计和开发>. 点击查看开发者文档(扫码支付)后,这里感觉微信的文档没有支付宝好理解(稍微吐槽下~~~),不过我们忽略一切,直接进入模式二:模式二最简单直接,不需要在商户后台进行配置,推荐大家使用,微信也说流程更为简单,我这里也讲的是模式二,模式一大家有兴趣可以自行研究下. 如上