支付宝沙箱环境对接(当面付)
支付宝沙箱环境对接(当面付)
第一步:
好好阅读以下的文档:
沙箱登录:https://openhome.alipay.com/platform/appDaily.htm
沙箱环境使用说明:https://doc.open.alipay.com/doc2/detail.htm?treeId=200&articleId=105311&docType=1
如何使用沙箱环境:https://support.open.alipay.com/support/hotProblemDetail.htm?spm=a219a.7386793.0.0.uS5uZ6&id=251932&tagId=100248
当面付产品介绍:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.hV5Clx&treeId=193&articleId=105072&docType=1
扫码支付接入指引:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.Ia6Wqy&treeId=193&articleId=106078&docType=1
当面付快速接入:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.bROnXf&treeId=193&articleId=105170&docType=1
当面付接入必读:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.hV5Clx&treeId=193&articleId=105322&docType=1
当面付进阶功能:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.YFmkxI&treeId=193&articleId=105190&docType=1
当面付异步通知-仅用于扫码支付:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.BykVSR&treeId=193&articleId=103296&docType=1
当面付SDK&DEMO:https://support.open.alipay.com/docs/doc.htm?spm=a219a.7386797.0.0.k0rwWc&treeId=193&articleId=105201&docType=1
服务端SDK:https://doc.open.alipay.com/doc2/detail?treeId=54&articleId=103419&docType=1
生成RSA密钥:https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=105971&docType=1
线上创建应用说明:https://doc.open.alipay.com/doc2/detail.htm?treeId=200&articleId=105310&docType=1#s0
第二步:
下载好支付宝提供的当面付demo,将支付宝沙箱环境的应用网关、UID、APPID、私钥、公钥以及对应的支付宝秘钥输到zfbinfo.properties文件中,把demo调通。
第三步:
沙箱环境进行测试,支付宝会回调数据回来,所以需要将本机地址与外网进行连接,需要用到内网穿透,可以用natapp工具。
第四步:
集成到项目中,controller里主要有三个action,alipay()、alipay_callback、query_order_pay_status,alipay_callback是支付宝回调调用的,alipay是支付生成二维码等、query_order_pay_status是查询订单状态,判断是否支付,然后让前端作出反应用的:
代码:
private static final Logger logger = LoggerFactory.getLogger(OrderController.class);
@Autowired
private OrderService orderService;
/***
* 支付
* @param session
* @param orderNo
* @param request
* @return
*/
@RequestMapping("alipay")
@ResponseBody
public ServerData alipay(HttpSession session,Long orderNo,HttpServletRequest request){
User user =(User) session.getAttribute("user");
System.out.println("==========================="+user);
//通过request拿到上下门对象,取到upload文件夹,将生成的二维码放到upload里
//取到upload路径
String path = request.getSession().getServletContext().getRealPath("upload");
return orderService.pay(orderNo, path, user.getId());
}
/***
* 支付宝回调(由支付宝来调的)
* @param request
* @return
*/
@RequestMapping("alipay_callback")
@ResponseBody
public Object alipay_callback(HttpServletRequest request){
Map<String,String> params = new HashMap<String,String>();
//支付宝返回的数据都是放在getParameterMap()里
Map requestParams = request.getParameterMap();
//通过迭代器的方法将key和vaule取出来
for(Iterator iter=requestParams.keySet().iterator();iter.hasNext();){
String name = (String)iter.next();
String[] values =(String[]) requestParams.get(name);
String valueStr = "";
for(int i = 0; i <values.length;i++){
valueStr =(i == values.length-1)? valueStr+values[i]:valueStr+values[i]+",";
}
params.put(name, valueStr);
}
//打印一下日志
logger.info("支付宝回调,sign:{},trade_statu:{},参数:{}",params.get("sign"),params.get("trade_status"),params.toString());
//验证回调的正确性,是不是支付宝发过来的,还要避免重复通知
params.remove("sign_type");
try {
boolean alipayRSACheckedV2 = AlipaySignature.rsaCheckV2(params, Configs.getAlipayPublicKey(), "utf-8", Configs.getSignType());
if(!alipayRSACheckedV2){
return ServerData.createByErrorMsg("非法请求");
}
} catch (AlipayApiException e) {
logger.error("支付宝回调异常!",e);
}
//todo,根据支付宝文档要求,需要验证各种数据
ServerData response = orderService.alicallback(params);
if(response.isSuccess()){
return Const.AlipayCallback.RESPONSE_SUCCESS;//支付宝规定要返回 success或者failed
}
return Const.AlipayCallback.RESPONSE_FAILED;
}
/***
* 查询订单支付状态
* @param session
* @param orderNo
* @return
*/
@RequestMapping("query_order_pay_status")
@ResponseBody
public ServerData queryOrderPayStatus(HttpSession session,Long orderNo){
User user =(User) session.getAttribute("user");
if(user == null){
return ServerData.createByErrorMsg("请登录");
}
ServerData response = orderService.queryOrderPayStatus(orderNo, user.getId());
if(response.isSuccess()){
return ServerData.createBySuccessData(true);
}
//不需要报错,直接返回false
return ServerData.createBySuccessData(false);
}
实现类的代码:
private static Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderItemMapper orderItemMapper;
@Autowired
private PayInfoMapper payInfoMapper;
// 支付宝当面付2.0服务
private static AlipayTradeService tradeService;
static{
/** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
* Configs会读取classpath下的zfbinfo.properties文件配置信息,如果找不到该文件则确认该文件是否在classpath目录
*/
Configs.init("zfbinfo.properties");
/** 使用Configs提供的默认参数
* AlipayTradeService可以使用单例或者为静态成员对象,不需要反复new
*/
}
// 支付宝简单打印应答
private void dumpResponse(AlipayResponse response) {
if (response != null) {
logger.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
if (StringUtils.isNotEmpty(response.getSubCode())) {
logger.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
response.getSubMsg()));
}
logger.info("body:" + response.getBody());
}
}
/**
* 通过orderNo和userId拿到orderItem,将orderItem里面的属性写到支付宝提供的接口里面,生成二维码,再将二维码上传到FTP服务器,且返回给前端,供用户扫码付款
*/
public ServerData pay(Long orderNo,String path,Integer userId){
Map<String,String> resultMap = new HashMap<String,String>();
//校验通过orderNo和userId的订单存不存在
Order order = orderMapper.selectOrderByOrderNoUserId(orderNo, userId);
if(order == null){
return ServerData.createByErrorMsg("没有该订单");
}
resultMap.put("orderNo", order.getOrderNo().toString());
/**进行支付宝对接*/
// (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、数字、下划线,
// 需保证商户系统端不能重复,建议通过数据库sequence生成,
/*String outTradeNo = "tradeprecreate" + System.currentTimeMillis()
+ (long) (Math.random() * 10000000L);*/
String outTradeNo = order.getOrderNo().toString();
// (必填) 订单标题,粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费”
//StringBuilder()返回的是一个Object类型的
String subject = new StringBuilder().append("loveshop扫码支付,订单号:").append(outTradeNo).toString();
// (必填) 订单总金额,单位为元,不能超过1亿元
// 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
String totalAmount = order.getPayment().toString();
// (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段
// 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
String undiscountableAmount = "0";
// 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号)
// 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID
String sellerId = "";
// 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元"
String body = new StringBuilder().append("订单:").append(outTradeNo).append(" 购买金额为:").append(totalAmount).toString();
// 商户操作员编号,添加此参数可以为商户操作员做销售统计
String operatorId = "test_operator_id";
// (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持
String storeId = "test_store_id";
// 业务扩展参数,目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法),详情请咨询支付宝技术支持
ExtendParams extendParams = new ExtendParams();
extendParams.setSysServiceProviderId("2088100200300400500");
// 支付超时,定义为120分钟
String timeoutExpress = "120m";
// 商品明细列表,需填写购买商品详细信息,
List<GoodsDetail> goodsDetailList = new ArrayList<GoodsDetail>();
//同个用户同个订单下,可以有多个明细
List<OrderItem> orderItemList = orderItemMapper.selectOrderItemByOrderNoUserId(orderNo, userId);
for(OrderItem orderItem: orderItemList){
// 创建一个商品信息,参数含义分别为商品id(使用国标)、名称、单价(单位为分)、数量,如果需要添加商品类别,详见GoodsDetail
GoodsDetail goods1 = GoodsDetail.newInstance(orderItem.getProductId().toString(),
orderItem.getProductName(),
BigDecimalUtil.mul(orderItem.getCurrentUnitPrice().doubleValue(), new Double(100).doubleValue()).longValue(),
orderItem.getQuantity());
goodsDetailList.add(goods1);
}
/*// 创建一个商品信息,参数含义分别为商品id(使用国标)、名称、单价(单位为分)、数量,如果需要添加商品类别,详见GoodsDetail
GoodsDetail goods1 = GoodsDetail.newInstance("goods_id001", "xxx小面包", 1000, 1);
// 创建好一个商品后添加至商品明细列表
goodsDetailList.add(goods1);
// 继续创建并添加第一条商品信息,用户购买的产品为“黑人牙刷”,单价为5.00元,购买了两件
GoodsDetail goods2 = GoodsDetail.newInstance("goods_id002", "xxx牙刷", 500, 2);
goodsDetailList.add(goods2);*/
// 创建扫码支付请求builder,设置请求参数
AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
.setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo)
.setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
.setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams)
.setTimeoutExpress(timeoutExpress)
.setNotifyUrl(PropertiesUtil.getPropertyMethod("alipay.callback.url"))//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
.setGoodsDetailList(goodsDetailList);
tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();
AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
switch (result.getTradeStatus()) {
case SUCCESS:
logger.info("支付宝预下单成功: )");
AlipayTradePrecreateResponse response = result.getResponse();
dumpResponse(response);
//创建目录(),如果目录不存在,则创建并赋予写的权限;如果目录存在,就不用创建
File folder = new File(path);
if(!folder.exists()){
//赋予目录写的权限
folder.setWritable(true);
folder.mkdirs();
}
//下单成功之后,生成二维码,将二维码上传到FTP服务器上,再把二维码返回给前端
// 需要修改为运行机器上的路径
String qrPath = String.format(path+"/qr-%s.png",response.getOutTradeNo());
logger.info("qrPath:" + qrPath);
//获取到二维码文件名
String qrFileName = String.format("qr-%s.png",response.getOutTradeNo());
ZxingUtils.getQRCodeImge(response.getQrCode(), 256, qrPath);
//这里不太懂
File targetFile = new File(path,qrFileName);
FTPUtil.uploadFile(Lists.newArrayList(targetFile));
String qrUrl = PropertiesUtil.getPropertyMethod("ftp.server.http.prefix")+targetFile.getName();
resultMap.put("qrUrl", qrUrl);
return ServerData.createBySuccessData(resultMap);
case FAILED:
logger.error("支付宝预下单失败!!!");
return ServerData.createByErrorMsg("支付宝预下单失败!!!");
case UNKNOWN:
logger.error("系统异常,预下单状态未知!!!");
return ServerData.createByErrorMsg("系统异常,预下单状态未知!!!");
default:
logger.error("不支持的交易状态,交易返回异常!!!");
return ServerData.createByErrorMsg("不支持的交易状态,交易返回异常!!!");
}
}
public ServerData alicallback(Map<String, String> params){
//这是从支付宝回调回来的数据(request.getParameterMap())
//params.get("out_trade_no")返回的外部订单号就是我们的内部订单号
Long orderNo = Long.parseLong(params.get("out_trade_no"));
String tradeNo = params.get("trade_no");
String tradeStatu = params.get("trade_status");
Order order = orderMapper.selectOrderByOrderNo(orderNo);
if(order == null){
return ServerData.createByErrorMsg("非loveshop网站的订单,回调忽略");
}
/*CANCELED(0,"已取消"),
NO_PAY(10,"未支付"),
PAID(20,"已支付"),
SHIPPED(40,"已发货"),
ORDER_SUCCESS(50,"订单完成"),
ORDER_CLOSE(60,"订单关闭");*/
if(order.getStatus() >= Const.OrderStatuEnum.PAID.getCode()){
//说明这个订单在之前已经付款了,支付宝重复调用
return ServerData.createBySuccessMsg("支付宝重复调用");
}
if(Const.AlipayCallback.TRADE_STATU_TRADE_SUCCESS.equals(tradeStatu)){
order.setStatus(Const.OrderStatuEnum.PAID.getCode());
order.setPaymentTime(DateTimeUtil.strToDate(params.get("gmt_payment")));
orderMapper.updateByPrimaryKeySelective(order);
}
//填充支付信息表
PayInfo payInfo = new PayInfo();
payInfo.setUserId(order.getUserId());
payInfo.setOrderNo(order.getOrderNo());
payInfo.setPayPlatform(Const.PayPlatform.ALIPAY.getCode());
payInfo.setPlatformNumber(tradeNo);//支付宝支付流水号
payInfo.setPlatformStatus(tradeStatu);
payInfoMapper.insert(payInfo);
return ServerData.createBySuccess();
}
public ServerData queryOrderPayStatus(Long orderNo,Integer userId){
Order order = orderMapper.selectOrderByOrderNoUserId(orderNo, userId);
if(order == null){
return ServerData.createByErrorMsg("非loveshop网站的订单,回调忽略");
}
if(order.getStatus() >= Const.OrderStatuEnum.PAID.getCode()){
//支付成功
return ServerData.createBySuccess();
}
//支付失败
return ServerData.createByError();
}
支付宝沙箱环境对接(当面付)相关推荐
- 支付宝沙箱环境对接流程
前者注:使用前导入支付宝SDK到项目中,对接使用java版本SDK. 对接步骤: 1.进入支付宝开发者中心(https://openhome.alipay.com/platform/appDaily. ...
- Vue对接支付宝沙箱环境
文章目录 前言 一.支付宝沙箱环境是什么? 二.安装所需要的环境 1.引入环境以及工具 2.安装Express框架 3.对接支付宝沙箱环境 总结 前言 此文章仅供学习参考,这里我们对接的环境是Vue. ...
- 支付宝沙箱环境+SpringBoot+内网穿透整合开发
目录 1.查看沙箱账号 2.内网穿透 3.沙箱环境整合SpringBoot开发 下面我将以实际案例详细介绍如何使用沙箱环境进行支付宝支付对接的开发 1.查看沙箱账号 首先什么是沙箱账号? 沙箱账号是指 ...
- python如何接入支付宝沙箱环境
最近的项目需要对接支付宝,因为之前没有接触过支付宝支付的功能,折腾了好久才把问题测地解决了,现在把详细的过程贴出来让广大同学少走弯路. 目前,支付宝有两种状态,一种是用于支付的正式环境,也就是平时我们 ...
- android 支付宝沙箱测试环境,Android支付宝沙箱环境使用教程
Android支付宝沙箱环境使用教程 网上好多支付宝教程,但是好像没看到支付宝沙箱环境的使用教程,尤其是在做Android支付宝测试的时候,沙箱拿来测试挺好的,正式使用的时候更换里面的个别数据就可以了 ...
- 支付宝沙箱环境接口使用详解
最近在做一个模拟支付宝的支付功能,用到了支付宝沙箱模拟环境,具体使用步骤如下,仅供参考: 一.注册支付宝沙箱环境账号 1.既然使用人家提供的东西,必须要注册一个他家的账号,使用万能的百度找到支付宝沙箱 ...
- 支付宝沙箱环境 电脑支付
项目场景: java语言,jdk1.8也可以使用 .支付宝沙箱环境电脑支付. 电脑端生成二维码,手机端扫描支付 AlipayConfig: APP 中接收数据代码: package com.hc;/* ...
- 支付宝沙箱环境的使用----详细教程
支付宝沙箱环境的使用----详细教程 支付宝的沙箱环境不需要商家认证,相对于微信沙箱门槛比较低,开发的时候方便我们在本地测试 这个教程带大家完成客户端支付 手机准备环境 客户端调试----支付宝沙箱环 ...
- 支付宝沙箱环境的H5收不到手机验证码
支付宝沙箱环境的H5收不到手机验证码? 解决方法: 我使用支付宝沙箱环境的H5老是收不到手机验证码,http://www.yayihouse.com/yayishuwu/chapter/1457
最新文章
- 用navicate 连接本地数据库提示用户名/口令无效
- 文本挖掘技术在CIC的应用--转载
- 【SDL】 如何在RedHat6.5中搭建SDL开发环境
- Eclipse里Java项目设置Java编辑器版本的位置
- Sublime Text如何安装和卸载插件
- 火狐 和 IE 透明度的设置。
- 阿里云上Kubernetes集群联邦
- MethodInvokingJobDetailFactoryBean的并发问题
- 基于界面自动化测试框架的发展
- vue中 点击事件的写法_vue基础之事件v-onclick=函数用法示例
- 金属零件图像数据集_如何使用包装零件来开发易于维护的数据仓库解决方案
- 人工智能时代!Python跃升编程语言第一名!
- APP 设计原则(界面设计原则) / 设计模式(界面设计模式、 程序架构模式、程序方法模式) 简述
- Python3学习笔记_INDEX(汇总)
- 修改thinkpad 小红点(TrackPoint速度)
- 作业6 陪集 拉格朗日定理
- Matlab GUI的数据传递——运用GUI本身的varargin和varargout传递参数
- 霹雳猿教程网站正式上线
- 批量图片重命名(excel、代码实现)
- 嵌入式设备的启动过程
热门文章
- 英语与计算机整合课,浅谈计算机与英语教学的有效整合
- WSL2的文件 I/O 效率低下问题
- “东数西算”工程带动各方面投资超1900亿元
- 使用Arduino开发ESP32(11):IO口与相关外设说明与记录
- 更快更稳更优质:华为云CDN下载加速解决方案测评
- 华为鸿蒙怎样报名,华为鸿蒙os2.0官网报名入口
- 洞悉规模化敏捷框架S@S、LeSS、SAFe(下篇)
- 一、新民主主义革命理论的实践基础。
- 超详细!ActionBar 使用·详解 .
- 计算机cpu哪种性价比高,2019年最佳电脑处理器,这5款性价比CPU不能错过