最近项目中要上线支付功能、前段时间刚开发完微信的扫码支付、不得不说微信开发团队的文档真是一个烂。但总算是对照着API把功能交付上线了。
前几天公司申请下来了企业支付宝,得空所以也把支付宝的扫码支付给集成进去。这里又不得不说,是支付宝的文档写的不咋地还是自己没有仔细阅读,总之翻遍了API最终在沙箱里面运行成功(切记、认真读文档,不然各种BUG等着你)
扫码支付,指用户打开支付宝钱包中的“扫一扫”功能,扫描商家展示在某收银场景下的二维码并进行支付的模式。该模式适用于线下实体店支付、面对面支付等场景。
业务流程:
使用步骤:
用户登陆支付宝钱包,点击首页“付款-扫码付”,进入扫一扫界面;
收银员在商家收银系统操作生成支付宝订单,用户确认支付金额,并生成二维码;
用户使用钱包的“扫码付”,扫收银员提供的二维码,确认支付;
用户付款后商家收银系统会拿到支付成功或者失败的结果。
前面的大家可以大体了解一下
开放平台服务端SDK下载地址(这里选择JAVA版本)、点击下载、里面有详细的API测试方法。
下载DEMO解压、仔细阅读里面的readme.txt文件、里面有详细的项目结构。
# 支付宝网关名、partnerId和appId
#open_api_domain = https://openapi.alipay.com/gateway.do
#支付宝沙箱环境
open_api_domain = https://openapi.alipaydev.com/gateway.do
mcloud_api_domain = http://mcloudmonitor.com/gateway.do
pid = 此处请填写你的PID
appid = 此处请填写你当面付的APPID
# RSA私钥、公钥和支付宝公钥
private_key = 此处请填写你的商户私钥且转PKCS8格式
public_key = 此处请填写你的商户公钥
alipay_public_key = MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDI6d306Q8fIfCOaTXyiUeJHkrIvYISRcc73s3vF1ZT7XN8RNPwJxo8pWaJMmvyTn9N4HQ632qJBVHf8sxHi/fEsraprwCtzvzQETrNRwVxLO5jVmRGi60j8Ue1efIlzPXV9je9mkjzOmdssymZkh2QhUrCmZYI/FCEa3/cNMW0QIDAQAB
# 当面付最大查询次数和查询间隔(毫秒)
max_query_retry = 5
query_duration = 5000
# 当面付最大撤销次数和撤销间隔(毫秒)
max_cancel_retry = 3
cancel_duration = 2000
# 交易保障线程第一次调度延迟和调度间隔(秒)
heartbeat_delay = 5
heartbeat_duration = 900
RSA私钥、公钥和支付宝公钥 获取方法。
生成与配置密钥
这里我选择的是方式一,使用支付宝提供的一键生成工具(内附使用说明)。
如果是JAVA程序public_key参数对应rsa_private_key_pkcs8.pem文件里面的内容,
public_key参数对用rsa_public_key.pem文件里面的内容。然后把公钥复制到沙箱中的RSA(SHA1)密钥中生成支付宝公钥、对应的是alipay_public_key参数。
然后你就可以运行Main.java 中的额main方法进行测试了,运行结果如下:
[acts_pay]|2016-11-04 15:23:35:530|Configs{支付宝openapi网关: https://openapi.alipaydev.com/gateway.do
, 支付宝mcloudapi网关域名: http://mcloudmonitor.com/gateway.do
, pid: 2088102169116018
, appid: 2016073000123724
, 商户RSA私钥: MIICdw******rLZis=
, 商户RSA公钥: MIGfMA******IDAQAB
, 支付宝RSA公钥: MIGfMA******IDAQAB
, 查询重试次数: 5
, 查询间隔(毫秒): 5000
, 撤销尝试次数: 3
, 撤销重试间隔(毫秒): 2000
, 交易保障调度延迟(秒): 5
, 交易保障调度间隔(秒): 900
}
[acts_pay]|2016-11-04 15:23:35:719|trade.precreate bizContent:{"out_trade_no":"tradeprecreate14782442155652020005","seller_id":"","total_amount":"0.01","undiscountable_amount":"0","subject":"xxx品牌xxx门店当面付扫码消费","body":"购买商品3件共20.00元","goods_detail":[{"goods_id":"goods_id001","goods_name":"xxx小面包","quantity":1,"price":"10"},{"goods_id":"goods_id002","goods_name":"xxx牙刷","quantity":2,"price":"5"}],"operator_id":"test_operator_id","store_id":"test_store_id","extend_params":{"sys_service_provider_id":"2088100200300400500"}}
[acts_pay]|2016-11-04 15:23:37:875|{"alipay_trade_precreate_response":{"code":"10000","msg":"Success","out_trade_no":"tradeprecreate14782442155652020005","qr_code":"https:\/\/qr.alipay.com\/bax03938xgzra2b5pijd00d2"},"sign":"LA2d5txq43c3t12sCsNEEGvu3plXUrqrd/uyzOy4HIMM5eRkWXaFkL+wqVNcYX/Jfn6no72yqiAUvYAivaWZkXZA3UxTRYlW+0EwZ96HrpnjFCK+QGOSDZuoiA2AyQlFgM/cQwdgTFGI+R2X9QZWxft1z3zYVG1uRGEZXed5RPQ="}
[acts_pay]|2016-11-04 15:23:37:878|支付宝预下单成功: )
[acts_pay]|2016-11-04 15:23:37:878|code:10000, msg:Success
[acts_pay]|2016-11-04 15:23:37:878|body:{"alipay_trade_precreate_response":{"code":"10000","msg":"Success","out_trade_no":"tradeprecreate14782442155652020005","qr_code":"https:\/\/qr.alipay.com\/bax03938xgzra2b5pijd00d2"},"sign":"LA2d5txq43c3t12sCsNEEGvu3plXUrqrd/uyzOy4HIMM5eRkWXaFkL+wqVNcYX/Jfn6no72yqiAUvYAivaWZkXZA3UxTRYlW+0EwZ96HrpnjFCK+QGOSDZuoiA2AyQlFgM/cQwdgTFGI+R2X9QZWxft1z3zYVG1uRGEZXed5RPQ="}
[acts_pay]|2016-11-04 15:23:37:878|filePath:D:\qr.png
最后下载沙箱钱包就可以完成手机支付了。
用户会用手机扫码给支付宝付款,然后支付宝收到之后会发送一条支付成功的消息给我们设置的notify_url
import java.io.BufferedOutputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.acts.web.acc.service.IWeixinPayService;
import com.acts.web.common.utils.LogUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.demo.trade.config.Configs;
@Controller
@RequestMapping(value = "alipay")
public class AliPayController {
//初始化参数 不然signVerified会验证失败
static {
Configs.init("zfbinfo.properties");
}
/**
* 支付宝支付回调
* @Author 小柒
* @param request
* @param response
* @throws Exception
* void
* @Date 2016年10月31日 更新日志 2016年10月31日 小柒 首次创建
*
*/
@SuppressWarnings("unchecked")
@RequestMapping(value = "pay",method = RequestMethod.POST)
public void alipay_notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
LogUtil.info("支付宝付款异步通知!");
String message = "success";
Map<String, String> params = new HashMap<String, String>();
// 取出所有参数是为了验证签名
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
String parameterName = parameterNames.nextElement();
params.put(parameterName, request.getParameter(parameterName));
}
//验证签名
boolean signVerified = false;
try {
signVerified = AlipaySignature.rsaCheckV1(params, Configs.getAlipayPublicKey(), "UTF-8");
} catch (AlipayApiException e) {
e.printStackTrace();
message = "failed";
}
if (signVerified) {
LogUtil.info("验证签名成功!");
// 若参数中的appid和填入的appid不相同,则为异常通知
if (!Configs.getAppid().equals(params.get("app_id"))) {
LogUtil.info("与付款时的appid不同,此为异常通知,应忽略!");
message = "failed";
}else{
String outtradeno = params.get("out_trade_no");
LogUtil.info(outtradeno + "号订单回调通知。");
//在数据库中查找订单号对应的订单,并将其金额与数据库中的金额对比,若对不上,也为异常通知
String status = params.get("trade_status");
if (status.equals("WAIT_BUYER_PAY")) {
// 如果状态是正在等待用户付款
} else if (status.equals("TRADE_CLOSED")) {
// 如果状态是未付款交易超时关闭,或支付完成后全额退款
} else if (status.equals("TRADE_SUCCESS") || status.equals("TRADE_FINISHED")) {
// 如果状态是已经支付成功
//成功 更新状态
} else {
weixinpayBack.updateAccOrder(outtradeno);
}
LogUtil.info(outtradeno + "订单的状态已经修改为" + status);
}
} else {
// 如果验证签名没有通过
message = "failed";
LogUtil.info("验证签名失败!");
}
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(message.getBytes());
out.flush();
out.close();
}
}
前言最近研究二级指针,发现了二级指针配合realloc函数其实可以用来实现动态数组这篇博文我只实现动态数组的push_back操作,就是在数组的末端增加一个元素修正一个思想c语言的函数参数,是不能在函数内部被修改的!!!因为传进来的参数,是拷贝构造我们平时说"传指针就可以在函数内修改参数",实际上是误导学生的说法,因为这个时候,函数的参数是指针,而这时候你会发现,你函数返回以后,这个指针变量没有被..._c 语言 push
广告关闭2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品。未来,我们一起乘风破浪,创造无限可能。例如:想了解python做数据可视化的工作。 我们可以从互联网找一些python做数据可视化的代码进行阅读,调试和迁移。 这样做的好处,突出实用性。 同时,我们在结合联想的学习方法,对所用到的可视化函数,做个更深入地了解和使用。 我借用《数据科学和人工智能》这个公众号,分享一..._python代码大全
关于AJAX所谓Ajax,全名Asynchronous JavaScript and XML。(也就异步的JS和XML)简单点来讲就是不刷新页面来发送和获取数据,然后更新页面。Ajax的优势•无需插件支持•优秀的用户体验•提高web程序的性能•减轻服务器和带宽的负担Ajax的不足•浏览器兼容不足•破坏浏览器前进和后退按钮的正常功能•对搜索引擎的支持不足•开发和调试工具的 缺乏好吧,这些都是几年前的...
python中BSON模块使用详解_python bson
这篇文章主要介绍了Python生成随机数的方法,有需要的朋友可以参考一下如果你对在Python生成随机数与random模块中最常用的几个函数的关系与不懂之处,下面的文章就是对Python生成随机数与random模块中最常用的几个函数的关系,希望你会有所收获,以下就是这篇文章的介绍。random.random()用于生成用于生成一个指定范围内的随机符点数,两个参数其中一个是上限,一个是下限。如果a ..._python随机生成偶数
#include<stdio.h>char *getstr1(){ char s[]="str1"; return s;}char *getstr2(){ char *s="str2"; return s;}void getstr3(char *s){ s="str3"; return;}int main(){ char *s1,*s2,*s3; s1=getstr1(); s2=getstr2(); getstr3(s3); printf("st_address of a local variable is returned through global variable
题目:农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数L个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是L 的总和。但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将..._huffman分木头
早上有个朋友发邮件给遇到一个SSIS连接Oracle的问题,具体的错误信息如下: Test connection failed because of an error in initializing provider. Oracle client and networking components were not found. These components are supplied by O..._sql 連oracletest connection failed bec
汇编源代码demo.asm.globl funfun: movl $0, %eax jmp .L2.L3: addq (%rdi), %rax movq 8(%rdi),%rdi.L2: testq %rdi, %rdi jne .L3 rep; retmain.asm.LC0: .string "%ld\n" .globl mainmain:.LFB0: pushq %rbp movq %rsp, %rbp subq $80, %rsp_"asm(\" .globl"
Oracle最最基本的概念: 实例和数据库实例就是oracle进程和一块共享内存,数据库就是静态的文件,如datafile, log file, redo logfile, control file, spfile等下面通过一些实验看看这些进程和文件1. 刚启动你的linux server的时候,还没有打开任何oracle 进程或服务, 查看进程: ps -aef ...
转载于:https://www.cnblogs.com/redips-l/p/11398580.html_android studio 编写c++ 没有提示iostream
当你的项目要求你的程序对高达几万条的数据在集中的时间内执行固定序列的操作,且不能完全使用存储过程时而需要使用程序来执行时。会需要这些优化。 我们知道,SQL服务器对一条语句的执行,需要分析、编译、执行这些步骤,通过参数化我们可以对一种命令只分析和编译一次,而执行多次,从而提高效率。在执行时,如果每次提交语句,可以完成多条SQL语句,则可以减少通讯时间,也可以提高效率。 通过 S