java支付宝支付文档(含代码)
java后台实现支付宝对账功能的示例代码

java后台实现⽀付宝对账功能的⽰例代码完成⽀付宝⽀付、查询的接⼝之后,我们应该还需要定时与⽀付宝进⾏对账,以确保商户系统的订单信息是正确的,想知道⽀付宝⽀付、查询接⼝实现过程的亲们,可移步到有详细过程。
现在我们来讲⼀下⽀付宝对账的功能,关于与⽀付宝交互的关键代码,其实⽀付宝的API已经讲得很清楚,如果亲们想直接看⽀付宝API,点击,当然我在⽂章也会进⾏说明解释。
实现⽀付宝⾃动对账功能先看⼀下商户系统和⽀付宝的⼤概交互过程:所谓对账,其实就是调⽤⽀付宝查询接⼝,跟上⼀篇的查询接⼝不同的是,上⼀篇的查询接⼝是针对特定的⼀个订单,通过订单号或者⽀付宝交易号去查询这⼀笔订单的信息,⽽对账,我们需要获取⼀个时间段的所有订单信息,因此,我们⾃然⽽已的去看⽀付宝提供的SDK是否有提供该接⼝给我们,经过查看⽀付宝API,我们发现确实我们所需要的接⼝:alipay.data.dataservice.bill.downloadurl.query。
废话不多说,先上我实现的代码1.先是调⽤⽀付宝的对账查询接⼝,获取账单⽂件下载地址URL,关于⼀些⽀付宝的公共参数,在上⼀篇我已经封装好,下⾯代码是针对对账的实现过程,传⼊关键的2个业务参数.公共参数⽀付宝SDK 已经封装好。
第⼀个参数,账单类型(字符串类型,trade或者signcustomer,具体含义见⽀付宝API)第⼆个参数,获取时间段(字符串类型,(2018-03-15)需要下载的账单⽇期,最晚是当期⽇期的前⼀天)/*** 实现⽀付宝对账* @param request* @return response*/@Overridepublic void alipayBill() {("==================向⽀付宝发起对账请求");// 获取⽀付宝⽀付的配置信息ValueOperations<String, Object> valueOps = redisTemplate.opsForValue();Payment alipayment = (Payment) valueOps.get("alipayment");if (alipayment == null) {alipayment = alipayMentOrderRepository.getPayment(1, 1);}try {//实例化客户端(参数:⽹关地址、商户appid、商户私钥、格式、编码、⽀付宝公钥、加密类型)AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, alipayment.getAppid(),AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET,AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);AlipayDataDataserviceBillDownloadurlQueryRequest request = new AlipayDataDataserviceBillDownloadurlQueryRequest();//创建API对应的request类request.setBizContent("{" +"\"bill_type\":\"trade\"," +"\"bill_date\":\"2018-03-14\"}"); //设置业务参数AlipayDataDataserviceBillDownloadurlQueryResponse response = alipayClient.execute(request);String billDownloadUrl=response.getBillDownloadUrl();("==================⽀付宝返回⽂件下载地址:"+billDownloadUrl);this.downBill(billDownloadUrl); //调⽤下载⽂件⽅法} catch (AlipayApiException e) {// TODO Auto-generated catch blocke.printStackTrace();}//通过alipayClient调⽤API,获得对应的response类//根据response中的结果继续业务逻辑处理}2.获取到⽀付宝返回的订单⽂件下载地址之后,我们直接把它下载到本地,下载的代码如下:/*** 下载账单⽂件:* @param request* @return response*/public String downBill(String billDownloadUrl){long filename=new Date().getTime();//指定希望保存的⽂件路径String filePath = "G:/alipay/billfile/fund_bill_"+filename+".zip";URL url = null;HttpURLConnection httpUrlConnection = null;InputStream fis = null;FileOutputStream fos = null;try {url = new URL(billDownloadUrl);httpUrlConnection = (HttpURLConnection) url.openConnection();httpUrlConnection.setConnectTimeout(5 * 1000);httpUrlConnection.setDoInput(true);httpUrlConnection.setDoOutput(true);httpUrlConnection.setUseCaches(false);httpUrlConnection.setRequestMethod("GET");httpUrlConnection.setRequestProperty("Charsert", "UTF-8");httpUrlConnection.connect();fis = httpUrlConnection.getInputStream();byte[] temp = new byte[1024];int b;fos = new FileOutputStream(new File(filePath));while ((b = fis.read(temp)) != -1) {fos.write(temp, 0, b);fos.flush();}} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if(fis!=null) fis.close();if(fos!=null) fos.close();if(httpUrlConnection!=null) httpUrlConnection.disconnect();} catch (IOException e) {e.printStackTrace();}}return null;}以上就是与⽀付宝交互的过程,⽀付宝API上也能找到这些代码,完成以上2步之后,我们就可以下载每⽇账单⽂件了我下载下来是这样的,上个图:解压之后:打开excel(汇总)是这样的:⾄此,我们已经拿到了⽀付宝提供的每⽇账单⽂件,接下来才是重头戏,⽬前还没有确定选择哪种⽅案进⾏⾃动对账确定之后,会把过程也补上。
34-支付宝支付

34-⽀付宝⽀付⽀付宝⽀付⼀、快速连接通道1. ⽀付宝<1>. ⽀付宝API:六⼤接⼝<2>. ⽀付宝⼯作流程<3>. ⽀付宝8次异步通知机制(⽀付宝对我们的服务器发送POST请求,索要success7个字符)2. 沙箱环境<1>. 在沙箱环境下实名认证<2>. 电脑⽹站⽀付API<3>. 完成RSA秘钥⽣成<4>. 在开发中⼼的沙箱应⽤下设置应⽤公钥填⼊⽣成的公钥⽂件中的内容<5>. Python⽀付宝开源框架pip install python-alipay-sdk --upgrade<6>. 公钥私钥设置"""# alipay_public_key.pem-----BEGIN PUBLIC KEY-----⽀付宝公钥-----END PUBLIC KEY-----# app_private_key.pem-----BEGIN RSA PRIVATE KEY-----⽤户私钥-----END RSA PRIVATE KEY-----"""<7>. ⽀付宝回调连接⼆、⽀付流程图三、⽀付宝介⼊⼊门1. 流程'''# ⽀付宝开放平台1. 服务范围(⾃研开发服务) -> 实名认证2. 控制台 -> 我的应⽤ -> 创建应⽤ -> ⽹页&移动应⽤ -> ⽀付接⼊ -> 应⽤名称 -> 应⽤图标 ->1) 移动应⽤ -> 应⽤平台 -> Bundle ID ...2) ⽹页应⽤ (不成功. 需要使⽤营业执照) -> ⽹址url -> 简介注意: 先选择功能再审核能⼒列表:添加能⼒ -> ⽀付能⼒ -> 电脑⽹站⽀付 开发设置:加签管理 -> 公钥 -⽀付宝⽹关应⽤⽹关授权回调地址3. ⽂档 -> ⽹页 & 移动应⽤接⼝⽂档能⼒列表1) 开放能⼒:⽀付能⼒ -> 电脑⽹站⽀付2) 产品介绍:注意: 会跳到⽀付宝的页⾯, ⽀付宝会有⼀个get页⾯回调, post数据返回后端回调费率: 0.6%3) 快速接⼊:SDK快速接⼊: python没有, 只能使⽤API开发⽀付流程: 下单 -> 商户系统 -> ⽀付宝 -> 回调(get显⽰订单结果, post修改订单状态)4) ⽀付API:公共请求参数请求参数订单号 out_trade_no总⾦额 total_amount订单标题 subjet公共响应参数⽀付宝交易号 trade_no我们的订单号 out_trade_no5) GitHub开源SDKpip install python-alipay-sdk# ⽀付宝沙箱环境1. 沙箱环境地址: https:///platform/appDaily.htm2. 沙箱应⽤:APPID⽀付宝⽹关: 地址中带dev表⽰沙箱环境, 不带表⽰正式环境加密⽅式: 使⽤⽀付宝提供的密钥⽣成(⽀付宝开放平台组助⼿).之前是xx.jar包, 现在变成xx.exe软件. 需要⽣成公钥和私钥将⾃⼰的公钥配置在⽀付宝中, ⽀付宝会⽣成⼀个⽀付宝的公钥.3. 项⽬中使⽤:注释 .read这⾥是操作⽂件的app_private_key_string 配置⾃⼰的私钥alipay_public_key_string 配置⽀付宝的公钥注意: 不能有空格AliPay类中的参数配置:APPID配置沙箱环境的APPIDsign_type 配置⾃⼰的 RSA2debug=False测试环境, True正式环境alipay.api_alipay_trade_page_pay中的参数配置:return_url 回调地址 (注意: 需要使⽤公⽹地址)notify_url 回调地址⽀付宝⽹关 + order_string => ⽣成连接地址提⽰: ⽣成连接地址打开会出现钓鱼⽹站异常4. 解决提⽰钓鱼问题: 浏览器⾥⾯有多个窗⼝沙箱环境存在的问题, 如果出现问题, 开⽆痕窗⼝即可, 付完之后会回调到之前配置的return_url中配置的⽹页⽀付宝沙箱环境充值:控制台 -> 沙箱账号 -> 账户余额# ⽀付宝公私密钥⽣成, sdk使⽤⽀付宝开放平台组助⼿使⽤: ⽣成公私钥⽀付宝开放平台下载:https:///ide/getPluginUrl.htm?clientType=assistant&platform=win&channelType=WEB密钥长度: RSA2密钥格式: PKCS1⽣成即可GitHub开源SDK:⽀付宝开源框架地址: https:///fzlee/alipaypip install python-alipay-sdk# 拓展:xx.apk 如果apk使⽤QQ 或者微信传送, 它会改名, 再后⾯加个.1 -> xx.apk.1. ⽬的就是防⽌恶意软件.如果你需要安装, 只需要将后缀名修改过来即可'''2. 测试⽬录结构3. t_alipay.pyfrom alipay import AliPayapp_private_key_string = """-----BEGIN rsa2 PRIVATE KEY-----MIIEowIBAAKCAQEAr6my/KRUtoPcQzuBt8TZtxLvLtwI8Rf/ETubH6dfi143yuiHd0SnfTctD+ZTmGyRHxuqNwwTNV4CN0d58wuI2F3hky4Tm8ocp8n0tzjlYxDvoh1b4d4ksxXCM0yhSzywdIK+K+Y9VP74uU4mlT47oBFUs6TBK9AAlMfZfoPTUAUjSDF -----END rsa2 PRIVATE KEY-----"""alipay_public_key_string = """-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCqAQEAgvXw19HTUH0t1thzkoq8KBhDBwFCoDqRJyBYnpN/KOTxTuSoUR0+pLK3vJbeQ0w5GJ/tiHpLh38hc88LNSR5nk26IBXX8WuNmxxC56d/A4/AaqiO3xgs9jKZjvYs0xuaFkwLswMuD8vm3 -----END PUBLIC KEY-----"""alipay = AliPay(appid="2021000117620642",app_notify_url=None, # 默认回调urlapp_private_key_string=app_private_key_string,# ⽀付宝的公钥,验证⽀付宝回传消息使⽤,不是你⾃⼰的公钥,alipay_public_key_string=alipay_public_key_string,sign_type="RSA2", # rsa2 或者 RSA2debug=False # 默认False)# 如果你是 Python 3的⽤户,使⽤默认的字符串即可subject = "测试订单"# 电脑⽹站⽀付,需要跳转到https:///gateway.do? + order_stringalipay_url = 'https:///gateway.do?'order_string = alipay.api_alipay_trade_page_pay(out_trade_no="20161112", # 订单号, 必须唯⼀total_amount=10, # 总⾦额subject=subject, # 订单标题return_url="http://139.196.184.91/", # 同步回调(⽀付成功)notify_url="http://139.196.184.91/" # 异步回调(订单状态) 可选, 不填则使⽤默认notify url)print(alipay_url + order_string)4. 注意事项from alipay import AliPayapp_private_key_string = """-----BEGIN rsa2 PRIVATE KEY-----MIIEowIBAAKCAQEAr6my/KRUtoPcQzuBt8TZtxLvLtwI8Rf/ETubH6dfi143yuiHd0SnfTctD+ZTmGyRHxuqNwwTNV4CN0d58wuI2F3hky4Tm8ocp8n0tzjlYxDvoh1b4d4ksxXCM0yhSzywdIK+K+Y9VP74uU4mlT47oBFUs6TBK9AAlMfZfoPTUAUjSDF -----END rsa2 PRIVATE KEY-----"""alipay_public_key_string = """-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgvXw19HTUH0t1thzkoq8KBhDBwFCoDqRJyBYnpN/KOTxTuSoUR0+pLK3vJbeQ0w5GJ/tiHpLh38hc88LNSR5nk26IBXX8WuNmxxC56d/A4/AaqiO3xgs9jKZjvYs0xuaFkwLswMuD8vm3x -----END PUBLIC KEY-----"""alipay = AliPay(appid="2021000117620642",app_notify_url=None, # 默认回调urlapp_private_key_string=app_private_key_string,# ⽀付宝的公钥,验证⽀付宝回传消息使⽤,不是你⾃⼰的公钥,alipay_public_key_string=alipay_public_key_string,sign_type="RSA2", # rsa2 或者 RSA2debug=False # 默认False)# 如果你是 Python 3的⽤户,使⽤默认的字符串即可subject = "测试订单"# 电脑⽹站⽀付,需要跳转到https:///gateway.do? + order_stringalipay_url = 'https:///gateway.do?'order_string = alipay.api_alipay_trade_page_pay(out_trade_no="20161112", # 订单号, 必须唯⼀total_amount=10, # 总⾦额subject=subject, # 订单标题return_url="http://139.196.184.91/", # 同步回调(⽀付成功)notify_url="http://139.196.184.91/" # 异步回调(订单状态) 可选, 不填则使⽤默认notify url)print(alipay_url + order_string)四、⽀付宝⼆次封装1. GitHub开源框架参考https:///fzlee/alipay2. 调⽤⽀付宝⽀付SDKpip install python-alipay-sdk --upgrade3. 流程'''1. libs中新建⽂件, ⽂件中新建__init__.py, 新建.py⽂件2. 将之前写死的 app...string 等, 修改成从⽂件中读取 open().read()3. 新建⽂件夹存放⽀付宝公钥和⾃⼰的私钥⽤于被第⼆步读取公钥私钥存放的⽂件格式是:-----xxx-----公钥或者私钥-----xxx-----4. 新建settings.py⽂件存放⼀些常量5. debug 配置成和 setting.py中的debug⼀直性6. 使⽤三元运算配置⽀付宝的⽀付⽹关7. 使⽤__init__.py优化导⼊的层级注意: ⽹站⽀付alipay.api_alipay_trade_page_pay放到外⾯书写和订单⼀起.'''4. ⽬录结构libs├── al_alipay # aliapy⼆次封装包│├── __init__.py # 包⽂件│├── pem # 公钥私钥⽂件夹││├── alipay_public_key.pem # ⽀付宝公钥⽂件││├── app_private_key.pem # 应⽤私钥⽂件│├── pay.py # ⽀付⽂件└──└── settings.py # 应⽤配置5. pem/alipay_public_key.pem-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt99Bp0XLP1Zu2WdRu74CMB/tVx1/2thIo8t3oAo8eD8smku1e76PfeOw4iqYMHU32Vq1Fg7BLa9oPMw7Ro+kNjX4jTDz4wC3LA6dUI5OeGxYd9+tkpsBwyg+buVNhhogppQn5rcCzkRFTx0D -----END PUBLIC KEY-----6. pem/app_private_key.pem-----BEGIN RSA PRIVATE KEY-----MIIEowIBAAKCAQEAj91mUtyrPlFFkfoLB+66lYcwexzXzEt6SlJuxsj3lW6+8pqla4YKqiUf98DeuBpX+USFm+baYFPqP5FWKyAUmGSDU8T4xD9BwLc+gm7rjeEjE5LzdyMInoEjW0QKXnn6S5y4gGPwI2WjOhg9vfr2R0GTDMTqn4i7zDB/u+wTksX5e -----END RSA PRIVATE KEY-----7. __init__.pyfrom .alipay_task import alipay, alipay_gateway8. pay.pyfrom alipay import AliPayfrom . import settingsalipay = AliPay(appid=settings.APPID,app_notify_url=None,app_private_key_string=settings.APP_PRIVATE_KEY_SIRING,alipay_public_key_string=settings.ALIPAY_PUBLIC_KEY_SIRING,sign_type=settings.SIGN_TYPE,debug=settings.DEBUG,)gateway = settings.GATEWAY9. settings.pyimport osAPPID = '2021000117613064'# 默认回调APP_NOTIFY_URL = None# ⾃⼰私钥APP_PRIVATE_KEY_SIRING = open(os.path.join(os.path.dirname(__file__), 'pem', 'app_private_kay.pem')).read()# 阿⾥公钥ALIPAY_PUBLIC_KEY_SIRING = open(os.path.join(os.path.dirname(__file__), 'pem', 'alipay_public_key.pem')).read()# 标签加密类型SIGN_TYPE = 'RSA2'# True表⽰测试沙箱环境DEBUG = True# 阿⾥⽹关GATEWAY = 'https:///gateway.do?' if DEBUG else 'https:///gateway.do?'10. 配置⽂件中配置⽀付宝替换接⼝:settings.py|开发⼈员# 后台基URLBASE_URL = 'http://139.196.184.91:8000' # 注意: 这⾥的8000上线以后指定的nginx的8000端⼝, 由nginx的8000端⼝发送到nginx配置内部的uwsgi的端⼝中# 前台基URLLUFFY_URL = 'http://139.196.184.91' # 注意: 这⾥没有写端⼝默认就是80端⼝.# ⽀付宝同步异步回调接⼝配置# 后台: ⽀付宝异步回调的接⼝NOTIFY_URL = BASE_URL + "/order/success/"# 前台: ⽀付宝同步回调接⼝,没有 / 结尾RETURN_URL = LUFFY_URL + "/pay/success"五、后台-⽀付接⼝1. 订单模块表<1>. 流程'''1. 新建订单app, 注册, ⼦路由urls, 总路由分发,2. 表分析订单表:订单标题, 总价格, 订单id(⾃⼰的), 流⽔号(⽀付宝), 订单状态, ⽀付⽅式, ⽀付时间, 订单⽤户(注意: 导⼊⽤户表路径尽量⼩), 创建时间, 更新时间订单⼀对多外键, 课程⼀对多外键(级联删除改为Set_NULL, null=True), 原价格, 实价str的健壮性校验订单和订单详情表关系分析: ⼀对多订单详情是多的⼀⽅⼀个订单可以有多个订单详情, ⼀个订单详情不可以同时属于多个订单.订单表和课程表关系分析: 多对多⼀个订单可以包含多个课程, ⼀个课程可以属于多个订单重点: 但是我们这⾥不着不过对订单表与课程表建⽴多对多的关系,⽽是通过订单详情表与课程表建⽴关系.订单详情表和课程表关系分析: ⼀对多订单详情是多的⼀⽅订单详情多的⼀⽅⼀个订单详情不可以属于多个课程, ⽽⼀个课程可以属于多个订单详情订单表和⽤户表关系分析: ⼀对多订单是多的⼀⽅⼀个⽤户可以下多个订单, ⼀个订单不能属于多个⽤户on_delete -> DO_NOTHINGdb_constraint=False提⽰: 不继承BaseModel表. is_show, orders没有必要存在3. 数据迁移'''<2>. order/models.py"""class Order(models.Model):# 主键、总⾦额、订单名、订单号、订单状态、创建时间、⽀付时间、流⽔号、⽀付⽅式、⽀付⼈(外键) - 优惠劵(外键,可为空)passclass OrderDetail(models.Model):# 订单号(外键)、商品(外键)、实价、成交价 - 商品数量pass"""from django.db import modelsfrom user.models import Userfrom course.models import Courseimport utilsclass Order(models.Model):"""订单模型"""status_choices = ((0, '未⽀付'),(1, '已⽀付'),(2, '已取消'),(3, '超时取消'),)pay_choices = ((1, '⽀付宝'),(2, '微信⽀付'),)subject = models.CharField(max_length=150, verbose_name="订单标题")total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="订单总价", default=0)out_trade_no = models.CharField(max_length=64, verbose_name="订单号", unique=True)trade_no = models.CharField(max_length=64, null=True, verbose_name="流⽔号")order_status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="订单状态")pay_type = models.SmallIntegerField(choices=pay_choices, default=1, verbose_name="⽀付⽅式")pay_time = models.DateTimeField(null=True, verbose_name="⽀付时间")created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')updated_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')# 订单表和⽤户表关系分析: ⼀对多订单是多的⼀⽅⼀个⽤户可以下多个订单, ⼀个订单不能属于多个⽤户user = models.ForeignKey(User, related_name='order_user', on_delete=models.DO_NOTHING, db_constraint=False,verbose_name="下单⽤户")class Meta:db_table = "luffy_order"verbose_name = "订单记录"verbose_name_plural = "订单记录"def __str__(self):return "%s - ¥%s" % (self.subject, self.total_amount)@propertydef courses(self):data_list = []for item in self.order_courses.all():data_list.append({"id": item.id,"course_name": ,"real_price": item.real_price,})return data_listclass OrderDetail(models.Model):"""订单详情"""price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="课程原价")real_price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="课程实价")# 订单和订单详情表关系分析: ⼀对多订单详情是多的⼀⽅⼀个订单可以有多个订单详情, ⼀个订单详情不可以同时属于多个订单.order = models.ForeignKey(Order, related_name='order_courses', on_delete=models.CASCADE, db_constraint=False,verbose_name="订单")# 订单详情表和课程表关系分析: ⼀对多订单详情是多的⼀⽅订单详情多的⼀⽅⼀个订单详情不可以属于多个课程, ⽽⼀个课程可以属于多个订单详情 '''订单表和课程表关系分析: 多对多⼀个订单可以包含多个课程, ⼀个课程可以属于多个订单重点: 但是我们这⾥不着不过对订单表与课程表建⽴多对多的关系,⽽是通过订单详情表与课程表建⽴关系.'''course = models.ForeignKey(Course, related_name='course_orders', on_delete=models.SET_NULL, null=True,db_constraint=False,verbose_name="课程")class Meta:db_table = "luffy_order_detail"verbose_name = "订单详情"verbose_name_plural = "订单详情"def __str__(self):"""str的健壮性校验"""try:return "%s的订单:%s" % (, self.order.out_trade_no)except Exception as e:utils.log.error(str(e))return super().__str__()2. 订单模块接⼝之⽀付接⼝<1>. 流程'''1. ⽀付接⼝: ⽣成订单, ⽣成⽀付连接, 返回⽀付连接1) 新建路由pay, payView2) 新建视图payVieworder表和orderdetail表插⼊数据, 重写create⽅法.⽣成订单号 uuid登录后才能⽀付 jwt认证当前登录⽤户就是下单⽤户, 存到order表中订单价格校验. 如: 下了三个课程, 总价格100, 前端提交的价格是99# 实现继承 C, G新建序列化类 OrderModelSeriailzer注意: 这是⼀个反序列化的表# 传输的数据格式{course: [1, 2, 3], total_amount: 100, subject: 商品名, pay_type: 1}# 控制字段fields=['total_amount', 'subject', 'pay_type', 'course_list']# 可以再局部钩⼦中把course=[1, 2, 3]⽣成course=[obj1, obj2, obj3] 或者使⽤ PrimayKeyRElatedFieldcourse=serialisers.CharField()# 校验1. 校验订单总价格: 获取总价格, 获取课程对象列表从总价格列表中获取每个价格叠加与总价格对⽐ (注意: 需要返回总价格)2. ⽣成订单号: str(uuid).replace('-', '')3. 获取⽀付⽤户: 视图中重写create⽅法借助self.context传将request对象传给序列化类4. ⽣成⽀付连接: 导⼊alipay, alipay_gateway. 拷贝, 将post, get2个回调的地址存放到配置⽂件中(配置到django的配置⽂件中), 拼接地址返回即可!5. ⼊库(订单, 订单详情): 将user对象存⼊attrs中, 把订单号存⼊attrs中, 将pay_url存⼊self.context中6. create⽅法. 先pop出课程列表对象, 存order表. for循环存⼊课程详情视图中: Response返回给前端的, 前端只需要⼀个连接, 那么序列化校验的第五步, 在self.context中将它存⼊, 将它返回给前端3) 配置jwt认证对PayView类进⾏限制. 使⽤内置限制(认证 + 权限)内置认证类: JSONWebTokenAUthentication内置权限类: isAuthenticated4) 序列化中让所有的fields中的字段必填. 有默认值的字段, 就不是必填的. required=True5) 出现错误: ⽀付宝⽀付的时候pay_total_amount是⼀个decimal类型, 需要转换成float类型. (提⽰: decimal累加可以)提⽰: ⽀付⽅式⽬前只写了⽀付宝的⽀付⽅式因此pay_type=1, 3个课程⼀起买⼀共1382. ⽀付宝异步回调的post接⼝: 验签, 修改订单状态3. 当⽀付宝get回调前端, vue组件⼀创建, ⽴马向后端你发⼀个get请求.(⽐较绕)'''<2>. order/views.pyfrom rest_framework.viewsets import GenericViewSetfrom rest_framework.mixins import CreateModelMixinfrom rest_framework import statusfrom rest_framework_jwt.authentication import JSONWebTokenAuthenticationfrom rest_framework.permissions import IsAuthenticatedimport utilsfrom . import modelsfrom . import serializerclass PayView(CreateModelMixin, GenericViewSet):# 对PayView类进⾏限制. 使⽤内置限制(认证 + 权限)authentication_classes = [JSONWebTokenAuthentication]permission_classes = [IsAuthenticated]queryset = models.Order.objects.all()serializer_class = serializer.OrderModelSeriailzerdef create(self, request, *args, **kwargs):# 视图中重写create⽅法借助self.context传将request对象传给序列化类serializer = self.get_serializer(data=request.data, context={'request': request})serializer.is_valid(raise_exception=True)self.perform_create(serializer)headers = self.get_success_headers(serializer.data)# 视图中: Response返回给前端的, 前端只需要⼀个连接, 那么序列化校验的第五步, 在self.context中将它存⼊, 将它返回给前端return utils.APIResponse(serializer.context['pay_link'], status=status.HTTP_201_CREATED, headers=headers)<3>. order/serializer.pyimport uuidfrom rest_framework import serializersfrom rest_framework.exceptions import ValidationErrorfrom django.conf import settingsfrom . import modelsfrom libs.alipay_sdk import alipay, alipay_gatewayclass OrderModelSeriailzer(serializers.ModelSerializer):# 可以再局部钩⼦中把course_list=[1, 2, 3]⽣成course_list=[obj1, obj2, obj3] 或者使⽤ PrimayKeyRElatedFieldcourse_list = serializers.PrimaryKeyRelatedField(write_only=True, many=True, queryset=models.Course.objects.all())class Meta:model = models.Orderfields = ['subject', 'total_amount', 'pay_type', 'course_list']extra_kwargs = {# 序列化中让所有的fields中的字段必填. 有默认值的字段, 就不是必填的. required=True'total_amount': {'required': True},'pay_type': {'required': True},}@staticmethoddef _verify_amount(attrs):total_amount = attrs.get('total_amount')course_list = attrs.get('course_list')course_amount = 0for course in course_list:course_amount += course.priceif course_amount == total_amount:return total_amountraise ValidationError("订单总价错误!")@staticmethoddef _order_number():return str(uuid.uuid1()).replace('-', '')def _pay_user(self):return self.context['request'].userdef _pay_link(self, out_trade_no, total_amount, subject):# print('total_amount:', total_amount, type(total_amount)) # total_amount: 138.00 <class 'decimal.Decimal'>order_string = alipay.api_alipay_trade_page_pay(out_trade_no=out_trade_no, # 订单号, 必须唯⼀# ⽀付宝⽀付的时候pay_total_amount是⼀个decimal类型, 需要转换成float类型. (提⽰: decimal累加可以)total_amount=float(total_amount), # 总⾦额subject=subject, # 订单标题return_url=settings.RETURN_URL, # 同步回调(⽀付成功)notify_url=settings.NOTIFY_URL # 异步回调(订单状态) 可选, 不填则使⽤默认notify url)return alipay_gateway + order_stringdef _before_create(self, attrs, out_trade_no, user, pay_link):attrs['out_trade_no'] = out_trade_noattrs['user'] = userself.context['pay_link'] = pay_linkdef validate(self, attrs):"""1. 校验订单总价格: 获取总价格, 获取课程对象列表从总价格列表中获取每个价格叠加与总价格对⽐ (注意: 需要返回总价格)2. ⽣成订单号: str(uuid).replace('-', '')3. 获取⽀付⽤户: 视图中重写create⽅法借助self.context传将request对象传给序列化类4. ⽣成⽀付连接: 导⼊alipay, alipay_gateway. 拷贝, 将post, get2个回调的地址存放到配置⽂件中(配置到django的配置⽂件中), 拼接地址返回即可!5. ⼊库(订单, 订单详情): 将user对象存⼊attrs中, 将pay_link存⼊self.context中"""# 1. 校验订单总价格total_amount = self._verify_amount(attrs)# 2. ⽣成订单号order_number = self._order_number()# 3. 获取⽀付⽤户user = self._pay_user()# 4. ⽣成⽀付连接pay_link = self._pay_link(out_trade_no=order_number, total_amount=total_amount, subject=attrs.get('subject'))# 5. ⼊库(订单, 订单详情)self._before_create(attrs=attrs, out_trade_no=order_number, user=user, pay_link=pay_link)return attrsdef create(self, validated_data):course_list = validated_data.pop('course_list')order = models.Order.objects.create(**validated_data)for course in course_list:models.OrderDetail.objects.create(course=course, price=course.price, real_price=course.price, order=order)return order<4>. settings/dev.py# 后台基URLBASE_URL = 'http://139.196.184.91'# 前台基URLLUFFY_URL = 'http://139.196.184.91'# ⽀付宝同步异步回调接⼝配置# 后台异步回调接⼝NOTIFY_URL = BASE_URL + "/order/success/"# 前台同步回调接⼝,没有 / 结尾RETURN_URL = LUFFY_URL + "/pay/success"<5>. luffyapi/urls.pypath('order/',include('order.urls')),<6>. order/urls.py⼦路由from django.urls import path, re_path, includefrom . import viewsfrom rest_framework.routers import SimpleRouterrouter = SimpleRouter()router.register('pay', views.PayView, 'pay')urlpatterns = [path('', include(router.urls)),]六、前台-⽀付⽣成页⾯1. 前端跳转到⽀付宝⽀付<1>. 流程'''提⽰: ⼀共三个地⽅都有⽴即购买操作1. FreeCourse.vue1) 定义buy_now()点击触发事件的⽅法从this.$cookies中获取token判断如果没有token那么触发this.$message发送ajax的post请求, this.$settings.base_url + /order/pay/, headers需要携带认证 Authorization, data需要携带对着数据. 使⽤另⼀种⽤法{}获取到pay_link, 前端发送get请求window.open(pay_link, '_self')2) 付款成功以后需要跳转到/order/success页⾯, 前端需要success组件. 后端需要success接⼝'''<2>. FreeCoourse.vue# template<span class="buy-now" @click="buy_now(course)">⽴即购买</span># scriptmethods: {buy_now(course) {// 获取token, 校验⽤户是否登录let token = this.$cookies.get('token');if (!token) {this.$message({message: "请先登录!",type: 'warning',});return false;}// 发送axiosthis.$axios({method: 'post',url: `${this.$settings.base_url}/order/pay/`,data: {"subject": ,// "total_amount": 11,"total_amount": course.price,"pay_type": 1,"course_list": [course.id,},headers: {Authorization: `jwt ${this.$cookies.get('token')}`},}).then(response => {console.log(response.data);if (response.data.code) {open(response.data.data, '_self');} else {this.$message({message: '订单处理失败!',type: 'warning',})}}).catch(error => {this.$message({message: "未知错误!",type: 'warning',})})},...}2. ⽀付成功前端页⾯<1>. 流程'''1. 新建PaySuccess.vue组件2. 配置路由 path: '/pay/success'注意: 回调以后会在你的url地址中, 携带者很多东西3. 拷贝PaySuccess页⾯提⽰: 页⾯只有⽀付宝回调回来才有数据, 直接查看是没有的4. create⾥⾯有⼀种特殊⽤法5. 同步回调参数trade_no ⽀付宝的流⽔号auth_app_id 商家流⽔号app_id 我们的id号页⾯需要的参数: 订单号, 交易号, 付款时间'''<2>. routere/index.jsimport PaySuccess from '../views/PaySuccess.vue'const routes = [...{path: '/pay/success',name: 'PaySuccess',component: PaySuccess},];<3>. ⽀付宝返回参数charset=utf-8&out_trade_no=7f7c7d12d57d45b693e1b49a6b01e1dd& # ⾃⼰的订单号method=alipay.trade.page.pay.return&total_amount=39.00&sign=FUmceqiNMWvxcD%2BUPCHiOTaEwlJ%2FXIXL5UwZWOSI1TwRjPIZVzjRLB4j2G5CQpn472JO8X%2BwMx04dHqjLxqLcY3TRu0XurQ%2FwKTNpyfDrtNuNv0rfGPuVHw52y3blbS7%2FKFVsWryw4%2BBuF2fCrJ4qWH8Zg14Rct7qoMbu73N trade_no=2020030722001464020500585462& # ⽀付宝的流⽔号auth_app_id=2016093000631831&version=1.0&app_id=2016093000631831&sign_type=RSA2&seller_id=2088102177958114×tamp=2020-03-07%2014%3A47%3A48 # 付款时间`// 同步回调没与订单状态<4>. views/PaySuccess.vue<template><div class="pay-success"><!--如果是单独的页⾯,就没必要展⽰导航栏(带有登录的⽤户)--><Header/><div class="main"><div class="title"><div class="success-tips"><p class="tips">您已成功购买 1 门课程!</p></div></div><div class="order-info"><p class="info"><b>订单号:</b><span>{{ result.out_trade_no }}</span></p><p class="info"><b>交易号:</b><span>{{ result.trade_no }}</span></p><p class="info"><b>付款时间:</b><span><span>{{ result.timestamp }}</span></span></p></div><div class="study"><span>⽴即学习</span></div></div></div></template><script>import Header from "@/components/Header"export default {name: "Success",data() {return {result: {},};},// console.log(location.search);// 解析⽀付宝回调的url参数let params = location.search.substring(1); // 去除? => a=1&b=2 let items = params.length ? params.split('&') : []; // ['a=1', 'b=2']//逐个将每⼀项添加到args对象中for (let i = 0; i < items.length; i++) { // 第⼀次循环a=1,第⼆次b=2 let k_v = items[i].split('='); // ['a', '1']//解码操作,因为查询字符串经过编码的if (k_v.length >= 2) {// url编码反解let k = decodeURIComponent(k_v[0]);this.result[k] = decodeURIComponent(k_v[1]);// 没有url编码反解// this.result[k_v[0]] = k_v[1];}}// 解析后的结果// console.log(this.result);// 把地址栏上⾯的⽀付结果,再get请求转发给后端this.$axios({url: this.$settings.base_url + '/order/success/' + location.search, method: 'get',}).then(response => {console.log(response.data);}).catch(() => {console.log('⽀付结果同步失败');})},components: {Header,}}</script><style scoped>.main {padding: 60px 0;margin: 0 auto;width: 1200px;background: #fff;}.main .title {display: flex;-ms-flex-align: center;align-items: center;padding: 25px 40px;border-bottom: 1px solid #f2f2f2;}.main .title .success-tips {box-sizing: border-box;}.title img {vertical-align: middle;width: 60px;height: 60px;margin-right: 40px;}.title .success-tips {box-sizing: border-box;}.title .tips {font-size: 26px;color: #000;}.info span {color: #ec6730;}.order-info {padding: 25px 48px;padding-bottom: 15px;border-bottom: 1px solid #f2f2f2;}.order-info p {display: -ms-flexbox;display: flex;margin-bottom: 10px;font-size: 16px;}.order-info p b {font-weight: 400;color: #9d9d9d;white-space: nowrap;}.study {padding: 25px 40px;}.study span {display: block;width: 140px;height: 42px;text-align: center;line-height: 42px;cursor: pointer;background: #ffc210;border-radius: 6px;font-size: 16px;color: #fff;}</style>七、后台-⽀付成功的备选接⼝1. 流程优化: 后端序列化中判断⽤户⽀付⾦额是否是0, 是0那么就直接修改订单状态, 也不⽤发送pay_link了# 前端: created分析1. localtion.search就可以获取⽀付好?号后⾯的参数获取到(包括问号), 使⽤.substring(1), 取出左边的?号2. 使⽤三元表达式, 对params进⾏split. 以及后⾯将这种参数进⾏处理3. decodeURICompontent,4. 把地址栏上⾯的⽀付结果, 再get请求发给后端this.$settings.base_url + '/order/success/' + localtion.search# 后端1. 路由: success/ SuccessView2. 视图: 继承APIView 因为不和序列化类有关系, 和数据库有点关系# get:获取前端传递过来的 out_trade_no, 去数据库中查取, 判断订单 order_status 的订单状态是否成功.最后返回响应中通过code=0或者code=1返回给前端即可# post: ⽀付宝回调回调地址: https:///fzlee/alipay/blob/master/README.zh-hans.md#alipay.fund.trans.toaccount.transfer回调参数: https:///open/270/105902/注意: 必须data内容返回 successrequest.data可能有2种情况. 如果是json格式是字典, 如果是QuseryDict需要注意失败了之后需要记录⽇志成功了之后需要记录⽇志, 并且修改订单状态, 使⽤ out_trade_no 作为过来标志, order_status 修改为1, 交易⽀付时间pay_time=gmt_payment'''2. 同步理论参数charset=utf-8&out_trade_no=7f7c7d12d57d45b693e1b49a6b01e1dd&method=alipay.trade.page.pay.return&total_amount=39.00&sign=FUmceqiNMWvxcD%2BUPCHiOTaEwlJ%2FXIXL5UwZWOSI1TwRjPIZVzjRLB4j2G5CQpn472JO8X%2BwMx04dHqjLxqLcY3TRu0XurQ%2FwKTNpyfDrtNuNv0rfGPuVHw52y3blbS7%2FKFVsWryw4%2BBuF2fCrJ4qWH8Zg14Rct7qoMbu73N trade_no=2020030722001464020500585462&auth_app_id=2016093000631831&version=1.0&app_id=2016093000631831&sign_type=RSA2&seller_id=2088102177958114×tamp=2020-03-07%2014%3A47%3A48`// 同步回调没与订单状态3. order/urls.pypath('success/',views.successView.as_view()),4. order/views.pyfrom rest_framework.views import APIViewfrom libs.alipay_sdk import alipayclass SuccessView(APIView):def get(self, request, *args, **kwargs):"""获取前端传递过来的 out_trade_no, 去数据库中查取, 判断订单 order_status 的订单状态是否成功.最后返回响应中通过code=0或者code=1返回给前端即可"""out_trade_no = request.query_params.get('out_trade_no')order = models.Order.objects.filter(out_trade_no=out_trade_no).first()# order.order_status值为1表⽰订单成功if order.order_status == 1:return utils.APIResponse()return utils.APIResponse(code=0, msg='失败')def post(self, request, *args, **kwargs):"""回调地址: https:///fzlee/alipay/blob/master/README.zh-hans.md#alipay.fund.trans.toaccount.transfer回调参数: https:///open/270/105902/注意: 必须data内容返回 successrequest.data可能有2种情况. 如果是json格式是字典, 如果是QuseryDict需要注意失败了之后需要记录⽇志成功了之后需要记录⽇志, 并且修改订单状态, 使⽤ out_trade_no 作为过来标志, order_status修改为1, 交易⽀付时间pay_time=gmt_payment"""# request.data类型判断data = request.data.dict()utils.log(f'data: {data}')signature = data.pop("sign")out_trade_no = data.get('out_trade_no')gmt_payment = data.get('gmt_payment')# 校验success = alipay.verify(data, signature)if success and data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):# 修改订单状态models.Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1, pay_time=gmt_payment)(f'{out_trade_no}订单⽀付成功!')# 注意: 服务器异步通知页⾯特性'''当商户收到服务器异步通知并打印出 success 时,服务器异步通知参数 notify_id 才会失效。
java支付宝第三方即时到账支付接口

java⽀付宝第三⽅即时到账⽀付接⼝alipay 的⼏个内核功能⽂件:====================================================================================================== AlipayFunction.java1. package com.test.util.alipay;2.3.4. import java.io.FileWriter;5. import java.io.IOException;6. import .MalformedURLException;7. import .URL;8. import java.util.ArrayList;9. import java.util.Collections;10. import java.util.HashMap;11. import java.util.List;12. import java.util.Map;13.14. import org.dom4j.Document;15. import org.dom4j.DocumentException;16. import org.dom4j.Node;17. import org.dom4j.io.SAXReader;18.19.20.21.22. public class AlipayFunction {23. /**24. * 功能:⽣成签名结果25. * @param sArray 要签名的数组26. * @param key 安全校验码27. * @return 签名结果字符串28. */29. public static String BuildMysign(Map sArray, String key) {30. String prestr = CreateLinkString(sArray); //把数组所有元素,按照“参数=参数值”的模式⽤“&”字符拼接成字符串31. prestr = prestr + key; //把拼接后的字符串再与安全校验码直接连接起来32. String mysign = Md5Encrypt.md5(prestr);33. return mysign;34. }35.36. /**37. * 功能:除去数组中的空值和签名参数38. * @param sArray 签名参数组39. * @return 去掉空值与签名参数后的新签名参数组40. */41. public static Map ParaFilter(Map sArray){42. List keys = new ArrayList(sArray.keySet());43. Map sArrayNew = new HashMap();44.45. for(int i = 0; i < keys.size(); i++){46. String key = (String) keys.get(i);47. String value = (String) sArray.get(key);48.49. if( value == null || value.equals("") ||50. key.equalsIgnoreCase("sign") || key.equalsIgnoreCase("sign_type")){51. continue;52. }53.54. sArrayNew.put(key, value);55. }56.57. return sArrayNew;58. }59.60. /**61. * 功能:把数组所有元素排序,并按照“参数=参数值”的模式⽤“&”字符拼接成字符串62. * @param params 需要排序并参与字符拼接的参数组63. * @return 拼接后字符串64. */65. public static String CreateLinkString(Map params){66. List keys = new ArrayList(params.keySet());67. Collections.sort(keys);68.69. String prestr = "";70.71. for (int i = 0; i < keys.size(); i++) {72. String key = (String) keys.get(i);73. String value = (String) params.get(key);74.75. if (i == keys.size() - 1) {//拼接时,不包括最后⼀个&字符76. prestr = prestr + key + "=" + value;77. } else {78. prestr = prestr + key + "=" + value + "&";79. }80. }81.82. return prestr;83. }84.85. /**86. * 功能:写⽇志,⽅便测试(看⽹站需求,也可以改成把记录存⼊数据库)87. * @param sWord 要写⼊⽇志⾥的⽂本内容88. */89. public static void LogResult(String sWord){90. // 该⽂件存在于和应⽤服务器启动⽂件同⼀⽬录下,⽂件名是alipay log加服务器时间91. try {92. FileWriter writer = new FileWriter("D:\\alipay_log" + System.currentTimeMillis() + ".txt");93. writer.write(sWord);94. writer.close();95. } catch (Exception e) {96. e.printStackTrace();97. }98. }99.100. /**101. * 功能:⽤于防钓鱼,调⽤接⼝query_timestamp来获取时间戳的处理函数102. * 注意:远程解析XML出错,与服务器是否⽀持SSL等配置有关103. * @param partner 合作⾝份者ID104. * @return 时间戳字符串105. * @throws IOException106. * @throws DocumentException107. * @throws MalformedURLException108. */109.110. public static String query_timestamp(String partner)111. throws MalformedURLException, DocumentException, IOException {112. String strUrl = "https:///gateway.do?service=query_timestamp&partner="+partner; 113. StringBuffer buf1 = new StringBuffer();114. SAXReader reader = new SAXReader();115. Document doc = reader.read(new URL(strUrl).openStream());116.117. List<Node> nodeList = doc.selectNodes("//alipay/*");118.119. for (Node node : nodeList) {120. // 截取部分不需要解析的信息121. if (node.getName().equals("is_success")122. && node.getText().equals("T")) {123. // 判断是否有成功标⽰124. List<Node> nodeList1 = doc.selectNodes("//response/timestamp/*");125. for (Node node1 : nodeList1) {126. buf1.append(node1.getText());127. }128. }129. }130.131. return buf1.toString();132. }133. }====================================================================================================== AlipayNotify.java1. package com.test.util.alipay;2.3. import java.io.BufferedReader;4. import java.io.InputStreamReader;5. import .HttpURLConnection;6. import .URL;7. import java.util.Map;8.9. import com.test.constants.AlipayConfig;10.11.12. public class AlipayNotify {13. /**14. * *功能:根据反馈回来的信息,⽣成签名结果15. * @param Params 通知返回来的参数数组16. * @param key 安全校验码17. * @return ⽣成的签名结果18. */19. public static String GetMysign(Map Params, String key){20. Map sParaNew = AlipayFunction.ParaFilter(Params);//过滤空值、sign与sign_type参数21. String mysign = AlipayFunction.BuildMysign(sParaNew, key);//获得签名结果22.23. return mysign;24. }25.26. /**27. * *功能:获取远程服务器ATN结果,验证返回URL28. * @param notify_id 通知校验ID29. * @return 服务器ATN结果30. * 验证结果集:31. * invalid命令参数不对出现这个错误,请检测返回处理中partner和key是否为空32. * true 返回正确信息33. * false 请检查防⽕墙或者是服务器阻⽌端⼝问题以及验证时间是否超过⼀分钟34. */35. public static String Verify(String notify_id){36. //获取远程服务器ATN结果,验证是否是⽀付宝服务器发来的请求37. String transport = AlipayConfig.transport;38. String partner = AlipayConfig.partner;39. String veryfy_url = "";40. if(transport.equalsIgnoreCase("https")){41. veryfy_url = "https:///cooperate/gateway.do?service=notify_verify";42. } else{43. veryfy_url = "/trade/notify_query.do?";44. }45. veryfy_url = veryfy_url + "&partner=" + partner + "¬ify_id=" + notify_id;46.47. String responseTxt = CheckUrl(veryfy_url);48.49. return responseTxt;50. }51.52. /**53. * *功能:获取远程服务器ATN结果54. * @param urlvalue 指定URL路径地址55. * @return 服务器ATN结果56. * 验证结果集:57. * invalid命令参数不对出现这个错误,请检测返回处理中partner和key是否为空58. * true 返回正确信息59. * false 请检查防⽕墙或者是服务器阻⽌端⼝问题以及验证时间是否超过⼀分钟60. */61. public static String CheckUrl(String urlvalue){62. String inputLine = "";63.64. try {65. URL url = new URL(urlvalue);66. HttpURLConnection urlConnection = (HttpURLConnection) url67. .openConnection();68. BufferedReader in = new BufferedReader(new InputStreamReader(69. urlConnection.getInputStream()));70. inputLine = in.readLine().toString();71. } catch (Exception e) {72. e.printStackTrace();73. }74.75. return inputLine;76. }77. }====================================================================================================== AlipayService.java1. package com.test.util.alipay;2.3. import java.util.ArrayList;4. import java.util.HashMap;5. import java.util.List;6. import java.util.Map;7.8.9. public class AlipayService {10. /**11. * 功能:构造表单提交HTML12. * @param partner 合作⾝份者ID13. * @param seller_email 签约⽀付宝账号或卖家⽀付宝帐户14. * @param return_url 付完款后跳转的页⾯要⽤以http开头格式的完整路径,不允许加?id=123这类⾃定义参数15. * @param notify_url 交易过程中服务器通知的页⾯要⽤以http开格式的完整路径,不允许加?id=123这类⾃定义参数16. * @param show_url ⽹站商品的展⽰地址,不允许加?id=123这类⾃定义参数17. * @param out_trade_no 请与贵⽹站订单系统中的唯⼀订单号匹配18. * @param subject 订单名称,显⽰在⽀付宝收银台⾥的“商品名称”⾥,显⽰在⽀付宝的交易管理的“商品名称”的列表⾥。
支付宝开发规范

范简化版潘燕目录一. 操作规范 (4)1. 模板及格式化 (4)2. 代码提交 (4)3. 垃圾清理 (5)二. 日志规范 (5)4. 日志输出 (5)5. 错误日志 (5)三. 注释规范 (6)6. 基本原则 (6)四. 安全规范 (6)7. 敏感信息的保护 (6)8. WEB安全 (6)五. 通用规范 (7)9. 金额的使用 (7)10. 枚举的使用 (7)11. URL使用 (7)12. 配置信息的使用 (7)13. 异常处理 (8)14. 资源的使用 (8)15. 本地事务操作 (8)16. 线程安全处理 (9)支付宝代码规范(简化版)一.操作规范1.模板及格式化支付宝的开发人员必须保证代码格式化的一致性,否则可能会导致代码冲突,轻微的耗费人力合并代码;严重时可能导致代码丢失,引起bug或者故障。
●开发人员必须配置ALIPAY的codetemplates.xml代码模板文件。
●开发人员必须配置ALIPAY的AlipayFormatter.xml代码格式化文件。
●每次提交代码之前,必须对java代码format。
最新模板文件的下载地址:Eclipse中配置的位置:2.代码提交●为防止冲突,任何时候,代码(及配置文件)提交前,先从CC或者SVN中更新代码和配置文件,以及早发现不兼容的代码变更和冲突。
●提交代码(及配置文件)时,如果发生冲突时,先看历史说明,再找相关人员确认,坚决不允许强制覆盖。
●每次提交代码之前,必须检查是否有eclipse warning,并FIX所有的warning(由dalgen等自动生成、不允许人工修改的代码例外)。
●开发过程定期使用FindBugs扫描代码,合并代码时不允许出现高等级问题。
3.垃圾清理●对于从来没有用到的或者被注释的方法,变量,类,配置文件,动态配置属性等要坚决从系统中清理出去,避免造成过多垃圾。
二.日志规范4.日志输出●生产代码禁止以System及Throwable.printStackTrace的方式输出日志信息,必须用Logger替代。
java对接支付宝支付接口开发详细步骤

java对接⽀付宝⽀付接⼝开发详细步骤⽬录第⼀步第⼆步第三步第四步对接⽀付宝⽀付接⼝,官⽅⽂档已经写的很清楚了,但是也有很多像我⼀样的⼩⽩,第⼀次对接⽀付宝⽀付接⼝,会有些迷茫,所以我在此写下这篇⽂章,给我和我⼀样的同学,⼀点思路吧。
第⼀步(先要在⽀付宝进⾏操做,拿到我们需要开发的信息后在动代码)进⼊蚂蚁⾦服,我们先要创建应⽤看到图下的应⽤按钮了吗?点击应⽤(如下图)创建应⽤(创建应⽤需要审核)提供资料审核吧,这个时候我们就不⽤管他了。
审核通过就可以⽤了。
但是他审核我们也不能闲着着,我们先弄个测试把代码写出来,等审核沟通过后我们这边在替换审核后的信息即可。
第⼆步(使⽤沙箱环境进⾏开发)看到APPID了吗这个很重要,我们⽀付的时候需要⽤到它,当前审核的后的信息⾥也会有,这个沙箱就是给我们测试⽤的,和正式⼏乎是⼀致的,只是切换不同的APPID和⽀付宝⽹关。
(这⾥我要吐槽⼀下微信⽀付,微信⽀付说真的⽂档太烂,坑太多,后续我也会把微信⽀付对接弄上来。
)⽀付宝还有⼀个好的地⽅就是旁边的机器⼈了,这个很到位,有不会的呼叫⼀下即可(⼩技巧:使⽤机器⼈,问题多打⼏次,⼈⼯就出来了,要不⼈⼯出不来呢。
)在这个界⾯需要设定应⽤公钥点击打开设置应⽤公钥(其他不⽤设定)点击设置应⽤公钥ok ,这⾥是输⼊公钥的地⽅,如何⽣成钥匙,请点击查看⽣成秘钥⽅法(下图,下载钥匙⽣成⼯具)下载后按照说明打开(切记安照说明进⾏打开)点击⽣成秘钥(这⾥注意:不要去验签你⽣成的秘钥,因为你验签会失败)我们直接拷贝⽣成的公钥放⼊即可。
这⾥也不需要验证公钥的准确性直接点击保存即可。
第三步导⼊alipay的jar包(jar包在)第四步编写代码创建⼀个AppPayConfig 类如下图放⼊对应的值即可编写action 类ok 到此⽀付宝就对接完毕了,当然上⾯有个异步回调地址,这个接⼝也是需要些的,我这了就不贴出来了。
不知道⼤家能不能看明⽩,如果还有模糊,可以呼叫我吧。
支付宝开发样例

out.println("<input type='hidden' name='subject' value='" + hm.get("subject") + "'>");
out.println("<input type='hidden' name='body' value='" + hm.get("body") + "'>");
Collections.sort(keys);//支付宝要求参数必须按字母排序
StringBuffer content = new StringBuffer();
for (int i = 0; i < keys.size(); i++) {
ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
String alipayNotifyURL = "https:///cooperate/gateway.do?service=notify_verify";
hm.put("show_url", "http://127.0.0.1:8888/mypenguin/books.do?method=list&kindId=1");//展示地址,即在支付页面时,商品名称旁边的“详情”的链接地址。
Java利用沙箱支付实现电脑扫码支付教程

Java利⽤沙箱⽀付实现电脑扫码⽀付教程⽬录⼀、准备⼯作⼆、效果展⽰三、实现代码3.1 后台代码3.2 前台代码⼀、准备⼯作1、注册⽀付宝开放平台账号,成为开发者。
2、进⼊沙箱,进⾏配置。
3.我们可以看到这个界⾯4.后⾯需要使⽤的参数APPID商户私钥(使⽤系统默认密钥的公钥模式,点击查看获取)⽀付宝公钥⽀付宝⽹关5、⼿机上下载沙箱⽀付宝(到时候⽀付⽤这个⽀付宝⽀付)6、下载好⽀付宝沙箱版后,登录⽀付宝提供的账号⼆、效果展⽰1、随⼿写的⼀个前台vue界⾯2、进⼊确定订单界⾯,可以添加商品描述3、跳转⽀付界⾯,利⽤沙箱⽀付宝完成⽀付4、完成⽀付5、跳回⾃⼰设置的界⾯三、实现代码3.1 后台代码(我这⾥利⽤的是SpringBoot集成的SSM,当然不使⽤SpringBoot也可以)3.1.1 pom.xml⽂件不⽤全部的,重点是:⽀付宝sdk包、fastjson<?xml version="1.0" encoding="UTF-8"?><project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0 https:///xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.zking</groupId><artifactId>springboot02</artifactId><version>0.0.1-SNAPSHOT</version><name>springboot02</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.1.18.RELEASE</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.44</version><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>RELEASE</version><scope>test</scope></dependency><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.6.2</version></dependency><!-- ⽀付宝sdk包 --><dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>3.1.0</version></dependency><!-- fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.48</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- https:///artifact/com.alibaba/druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.6</version></dependency><!-- https:///artifact/log4j/log4j --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><!-- mvn mybatis-generator:generate --><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.2</version><configuration><verbose>true</verbose><overwrite>true</overwrite><!--配置⽂件的位置--><configurationFile>src/main/resources/generatorConfig.xml</configurationFile> </configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.1.18.RELEASE</version><configuration><mainClass>com.zking.springboot02.Springboot02Application</mainClass> </configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build></project>3.1.2 model包package com.zking.springboot02.model;import lombok.Data;/*** ⽀付实体对象* 根据⽀付宝接⼝协议,其中的属性名,必须使⽤下划线,不能修改** @author 借我丹青妙笔*/@Datapublic class AlipayBean {private static final long serialVersionUID = 1L;/*** 商户订单号,必填**/private String out_trade_no;/*** 订单名称,必填*/private String subject;/*** 付款⾦额,必填* 根据⽀付宝接⼝协议,必须使⽤下划线*/private String total_amount;/*** 商品描述,可空*/private String body;/*** 超时时间参数*/private String timeout_express= "10m";/*** 产品编号*/private String product_code= "FAST_INSTANT_TRADE_PAY";public String getOut_trade_no() {return out_trade_no;}public void setOut_trade_no(String out_trade_no) {this.out_trade_no = out_trade_no;}public String getSubject() {return subject;}public void setSubject(String subject) {this.subject = subject;}public String getTotal_amount() {return total_amount;}public void setTotal_amount(String total_amount) {this.total_amount = total_amount;}public String getBody() {return body;}public void setBody(String body) {this.body = body;}}3.1.3 utils包AlipayConfig类(请配置好该类,防⽌报错)1. appId:APPID,沙箱应⽤提供的2. privateKey: 商户私钥,点击公钥证书查看3. returnUrl : ⽀付完成后跳转的页⾯,例如我填的是:http://localhost:8088/package com.zking.springboot02.utils;import lombok.Data;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;import ponent;/*** 配置⽂件读取**/@Configuration@Data@Componentpublic class AlipayConfig {/*** 应⽤ID,您的APPID,收款账号既是您的APPID对应⽀付宝账号*/private String appId = "";/*** 商户私钥,您的PKCS8格式RSA2私钥*/private String privateKey = "";/*** ⽀付宝公钥,*/private String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyqAN9WzWigim0/3fBK97RFZ7Juu31+DfXMVHTHSTP+4WPvr80zTiIQmT9xTFVGBgD8BBX0XELxqLQxsYQm/MgEgccHTnCKPP7Ci979YuwZyjOysdTc6BNO/6RqPZruih /*** 服务器异步通知页⾯路径需http://格式的完整路径,不能加?id=123这类⾃定义参数*/private String notifyUrl = "https://www.duan33f.top";/*** 页⾯跳转同步通知页⾯路径需http://格式的完整路径.* ⽀付完成后返回的地址*/private String returnUrl = "";/*** 签名⽅式*/private String signType = "RSA2";/*** 字符编码格式*/private String charset = "utf-8";/*** ⽀付宝⽹关*/private String gatewayUrl = "https:///gateway.do";/*** ⽀付宝⽹关*/private String logPath = "C:\\";}Alipay类package com.zking.springboot02.utils;import com.alibaba.fastjson.JSON;import com.alipay.api.AlipayApiException;import com.alipay.api.AlipayClient;import com.alipay.api.DefaultAlipayClient;import com.alipay.api.request.AlipayTradePagePayRequest;import com.zking.springboot02.model.AlipayBean;import org.springframework.beans.factory.annotation.Autowired;import ponent;import javax.annotation.Resource;/*** ⽀付宝⽀付接⼝* @author 借我丹青妙笔*/@Componentpublic class Alipay {@Autowiredprivate AlipayConfig alipayConfig;/*** ⽀付接⼝* @param alipayBean* @return* @throws AlipayApiException*/public String pay(AlipayBean alipayBean) throws AlipayApiException {// 1、获得初始化的AlipayClientString serverUrl = alipayConfig.getGatewayUrl();String appId = alipayConfig.getAppId();String privateKey = alipayConfig.getPrivateKey();String format = "json";String charset = alipayConfig.getCharset();String alipayPublicKey = alipayConfig.getPublicKey();String signType = alipayConfig.getSignType();String returnUrl = alipayConfig.getReturnUrl();String notifyUrl = alipayConfig.getNotifyUrl();//System.out.println(appId);AlipayClient alipayClient = new DefaultAlipayClient(serverUrl, appId, privateKey, format, charset, alipayPublicKey, signType); // 2、设置请求参数AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();// 页⾯跳转同步通知页⾯路径alipayRequest.setReturnUrl(returnUrl);// 服务器异步通知页⾯路径alipayRequest.setNotifyUrl(notifyUrl);// 封装参数alipayRequest.setBizContent(JSON.toJSONString(alipayBean));// 3、请求⽀付宝进⾏付款,并获取⽀付结果String result = alipayClient.pageExecute(alipayRequest).getBody();// 返回付款信息return result;}}3.1.4 Service包PayService接⼝package com.zking.springboot02.service;import com.alipay.api.AlipayApiException;import com.zking.springboot02.model.AlipayBean;/*** ⽀付服务* @author 借我丹青妙笔* @date Dec 12, 2018*/public interface PayService {/*** ⽀付宝⽀付接⼝* @param alipayBean* @return* @throws AlipayApiException*/String aliPay(AlipayBean alipayBean) throws AlipayApiException;}PayServiceImpl类package com.zking.springboot02.service.impl;import com.alipay.api.AlipayApiException;import com.zking.springboot02.model.AlipayBean;import com.zking.springboot02.service.PayService;import com.zking.springboot02.utils.Alipay;import org.springframework.stereotype.Service;import javax.annotation.Resource;@Servicepublic class PayServiceImpl implements PayService {@Resourceprivate Alipay alipay;@Overridepublic String aliPay(AlipayBean alipayBean) throws AlipayApiException {return alipay.pay(alipayBean);}}3.1.5 contorller包payController类package com.zking.springboot02.contorller;import com.alipay.api.AlipayApiException;import com.zking.springboot02.model.AlipayBean;import com.zking.springboot02.service.PayService;import org.springframework.web.bind.annotation.CrossOrigin;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;import java.util.HashMap;import java.util.Map;@RestController@RequestMapping("/pay")@CrossOriginpublic class PayController {@Resourceprivate PayService payService;/*** 阿⾥⽀付* @param alipayBean* @return* @throws AlipayApiException*/@PostMapping("/alipay")public Map alipay(AlipayBean alipayBean) throws AlipayApiException {System.out.println(alipayBean);Map<String,Object> map = new HashMap<String,Object>();String str = payService.aliPay(alipayBean);System.out.println(str);map.put("msg",str);map.put("code",0);//return map;}}3.1.6 application.yml⽂件server:port: 8080 #端⼝号servlet:context-path: /s02 #项⽬名3.2 前台代码(前台是利⽤脚⼿架搭建的Vue项⽬)3.2.1 src下api包下action.js⽂件/*** 对后台请求的地址的封装,URL格式如下:* 模块名_实体名_操作*/export default {//服务器'SERVER': 'http://localhost:8080/s02','alipay' : 'http://localhost:8080/s02/pay/alipay',//获得请求的完整地址,⽤于mockjs测试时使⽤'getFullPath': k => {return this.SERVER + this[k];}}3.2.2 src下api包下http.js⽂件/*** vue项⽬对axios的全局配置*/import axios from 'axios'import qs from 'qs'//引⼊action模块,并添加⾄axios的类属性urls上import action from '@/api/action'axios.urls = action// axios默认配置axios.defaults.timeout = 10000; // 超时时间// axios.defaults.baseURL = 'http://localhost:8080/crm'; // 默认地址axios.defaults.baseURL = action.SERVER;//整理数据// 只适⽤于 POST,PUT,PATCH,transformRequest` 允许在向服务器发送前,修改请求数据axios.defaults.transformRequest = function(data) {data = qs.stringify(data);return data;};// 请求拦截器e(function(config) {// let jwt = sessionStorage.getItem('jwt');// if (jwt) {// config.headers['jwt'] = jwt;// }return config;}, function(error) {return Promise.reject(error);});// 响应拦截器e(function(response) {return response;}, function(error) {return Promise.reject(error);});export default axios;3.2.3 src下router下index.js⽂件import Vue from 'vue'import Router from 'vue-router'import Shop from '@/views/Shop'import buy from '@/views/buy'e(Router)export default new Router({routes: [{path: '/',name: 'Shop',component: Shop},{path: '/buy',name: 'buy',component: buy}]})3.2.4 src下views下Shop.vue⽂件<template><el-table :data="tableData" style="width: 100%"><el-table-column prop="out_trade_no" label="编号"></el-table-column><el-table-column prop="subject" label="订单名称" ></el-table-column><el-table-column prop="total_amount" label="付款⾦额"></el-table-column><el-table-column label="操作"><template slot-scope="scope"><el-button @click="toBuy(scope.row)" type="text" size="small">去⽀付</el-button> </template></el-table-column></el-table></template><script>export default {name: "Shop",data: function() {return {tableData: [{out_trade_no: '101',subject: 'Java从⼊门到⼊⼟',total_amount: 33}, {out_trade_no: '202',subject: 'Mysql删库跑路指南',total_amount: 44}, {out_trade_no: '303',subject: 'Java编程思想',total_amount: 89}, {out_trade_no: '404',subject: 'Java设计模式',total_amount: 56}]};},methods: {toBuy(row){console.log(row);//利⽤$router.push进⾏跳转this.$router.push({//path后⾯跟跳转的路由地址path: '/buy',//name后⾯跟跳转的路由名字(必须有亲测,不使⽤命名路由会传参失败)name: 'buy',params: {//imgsListsUrl2是⾃⼰定义的名字,this.imgsListsUrl是要被传递的值payInfo: row}})}},created: function() {}}</script><style></style>3.2.5 src下views下buy.vue⽂件<template><div class="main"><center><div class="box"><h2>确定订单</h2><el-form :model="payInfo" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"><el-form-item label="订单号" prop="out_trade_no"><el-input v-model="payInfo.out_trade_no" readonly="true"></el-input></el-form-item><el-form-item label="商品名称" prop="subject"><el-input v-model="payInfo.subject" readonly="true"></el-input></el-form-item><el-form-item label="商品价格" prop="total_amount"><el-input v-model="payInfo.total_amount" readonly="true"></el-input></el-form-item><el-form-item label="商品描述" prop="body"><el-input v-model="payInfo.body"></el-input></el-form-item><el-button type="primary" plain @click="submit" style="width: 100%;" round>付款</el-button></el-form></div></center></div></template><script>//import axios from 'axios'export default {name: "buy",data() {return {payInfo: {out_trade_no: '',subject: '',total_amount: null,body: ''}}},mounted() {//this.$route.params.imgsListsUrl2是传过来的参数var time = new Date();this.payInfo = this.$route.params.payInfothis.payInfo.out_trade_no = time.getTime();},methods: {submit() {var url = this.axios.urls.alipay;//得到api下action.js中的alipaythis.axios.post(url, this.payInfo).then(resp => {//调⽤后台⽅法console.log(resp);const divForm = document.getElementsByTagName('div')if (divForm.length) {document.body.removeChild(divForm[0])}const div = document.createElement('div')div.innerHTML = resp.data.msg // data就是接⼝返回的form 表单字符串document.body.appendChild(div)document.forms[0].setAttribute('target', '_blank') // 新开窗⼝跳转document.forms[0].submit()}).catch(resp => {console.log(resp);});}}}</script><style scoped>.box {width: 800px;}.left {width: 85px;padding-top: 5px;font-size: 15px;}.right {width: 400px;}</style>3.2.6 src下main.js⽂件import Vue from 'vue'import ElementUI from 'element-ui' //新添加1import 'element-ui/lib/theme-chalk/index.css' //新添加2,避免后期打包样式不同,要放在import App from './App';之前import axios from '@/api/http' //vue项⽬对axios的全局配置import App from './App'import router from './router'import VueAxios from 'vue-axios'e(VueAxios,axios)e(ElementUI) //新添加3Vue.config.productionTip = false/* eslint-disable no-new */new Vue({el: '#app',router,components: { App },template: '<App/>'})OK,重要的代码已经完全提供了。
H5集成支付宝App支付客户端+服务端(java)

H5集成⽀付宝App⽀付客户端+服务端(java)由于最近项⽬需要接⼊第三⽅开发,⽀付宝⽀付,微信⽀付,OSS图⽚上传以及短信服务。
为避免第⼀次开发⽀付宝再次花时间查看⽂档,今天总结⼀下接⼊⽀付宝的过程,以及接⼊过程中遇到的问题。
2.在已申请应⽤中查看签约状态,若状态为已⽣效才可以继续开发,签约状态查看如下所⽰,注意:未完成签约的应⽤是⽆法接⼊成功的。
3.配置密钥4.客户端开发客户端开发相对简单,可根据需要⾃⾏添加业务。
1var channel=null;2// 1. 获取⽀付通道3 plus.payment.getChannels(function(channels){4 channel=channels[0];5 },function(e){6 alert("获取⽀付通道失败:"+e.message);7 });8var ALIPAYSERVER=AppDataURL + '/weixinpay.do?price=1';9// 2. 发起⽀付请求10function pay(id){11var PAYSERVER='';12if(id=='alipay'){13 PAYSERVER=ALIPAYSERVER;14 }else if(id=='wxpay'){15 PAYSERVER=WXPAYSERVER;16 }else{17 plus.nativeUI.alert("不⽀持此⽀付通道!",null,"");18return;19 }20var xhr=new XMLHttpRequest();21 xhr.onreadystatechange=function(){22switch(xhr.readyState){23case 4:24 mui.toast("xhr.status:"+xhr.status);25if(xhr.status==200){26 plus.payment.request(channel,xhr.responseText,function(result){27 plus.nativeUI.alert("⽀付成功!",function(){28 back();29 });30 },function(error){31 plus.nativeUI.alert("⽀付失败:" + error.code+error.message);32 });33 }else{34 alert("获取订单信息失败!");35 }36break;37default:38break;39 }40 }41 xhr.open('GET',PAYSERVER);42 xhr.send();5.服务端开发以下代码只需配置好正确参数即可使⽤。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Java版支付宝支付功能整理文档 (2)一、引用文件 (2)1、基础配置类:AlipayConfig.java (2)2、支付宝MD5签名处理核心文件:MD5.java (4)3、支付宝接口公用函数类:AlipayCore.java (5)4、支付宝通知处理类:AlipayNotify.java (9)5、支付宝各接口请求提交类:AlipaySubmit.java (12)6.自定义订单类:UtilDate.java (16)7.HttpClient方式访问:HttpProtocolHandler.java (17)8、Http请求对象的封装:HttpRequest.java (23)9、Http返回对象的封装:HttpResponse.java (27)10、表示Http返回的结果字符方式:HttpResultType.java (29)二、Controller处理方法 (30)1、支付宝PC端支付(即时到账) (30)(1、)支付方法 (30)(2、)支付成功后的同步调用 (31)(4、)支付成功后的异步调用 (33)2、支付宝手机网页支付 (35)(1、)支付方法 (35)(2、)支付成功后的同步调用 (37)(4、) 支付成功后的异步调用 (37)三、页面代码 (37)1、跳转页面:alipay.jsp和alipaywap.jsp (37)2、同步调用页面:return_url.jsp (38)3、异步调用页面:notify_url.jsp (38)Java版支付宝支付功能整理文档作者:Lock-玄清时间:2017-03-15注:此文档只支持付款,没有退款的功能一、引用文件1、基础配置类:AlipayConfig.javapackage com.alipay.config;/* **类名:AlipayConfig*功能:基础配置类*详细:设置帐户有关信息及返回路径*版本:3.4*修改日期:2016-03-08*说明:*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
*该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*/public class AlipayConfig {//↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓// 合作身份者ID,签约账号,以2088开头由16位纯数字组成的字符串,查看地址:https:///order/pidAndKey.htmpublic static String partner = "";// 收款支付宝账号,以2088开头由16位纯数字组成的字符串,一般情况下收款账号就是签约账号public static String seller_id = partner;// MD5密钥,安全检验码,由数字和字母组成的32位字符串,查看地址:https:///order/pidAndKey.htmpublic static String key = "";//----------------pc端支付宝返回路径---------------------// 服务器异步通知页面路径需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问public static String notify_url = "";// 页面跳转同步通知页面路径需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问public static String return_url = "";// 签名方式public static String sign_type = "MD5";// 调试用,创建TXT日志文件夹路径,见AlipayCore.java类中的logResult(String sWord)打印方法。
public static String log_path = "C:\\";// 字符编码格式目前支持 gbk 或 utf-8public static String input_charset = "utf-8";// 支付类型,无需修改public static String payment_type = "1";//----------------pc端支付宝调用接口--------------------- // 调用的接口名,无需修改public static String service = "create_direct_pay_by_user";//----------------手机端支付宝调用接口--------------------- public static String wap_service ="er";//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑//↓↓↓↓↓↓↓↓↓↓请在这里配置防钓鱼信息,如果没开通防钓鱼功能,为空即可↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓// 防钓鱼时间戳若要使用请调用类文件submit中的query_timestamp 函数public static String anti_phishing_key = "";// 客户端的IP地址非局域网的外网IP地址,如:221.0.0.1public static String exter_invoke_ip = "";//↑↑↑↑↑↑↑↑↑↑请在这里配置防钓鱼信息,如果没开通防钓鱼功能,为空即可↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑}2、支付宝MD5签名处理核心文件:MD5.javapackage com.alipay.sign;import java.io.UnsupportedEncodingException;import java.security.SignatureException;import mons.codec.digest.DigestUtils;/*** 功能:支付宝MD5签名处理核心文件,不需要修改* 版本:3.3* 修改日期:2012-08-17* 说明:* 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
* 该代码仅供学习和研究支付宝接口使用,只是提供一个* */public class MD5 {/*** 签名字符串* @param text 需要签名的字符串* @param key 密钥* @param input_charset 编码格式* @return签名结果*/public static String sign(String text, String key, String input_charset) {text = text + key;return DigestUtils.md5Hex(getContentBytes(text,input_charset));}/*** 签名字符串* @param text 需要签名的字符串* @param sign 签名结果* @param key 密钥* @param input_charset 编码格式* @return签名结果*/public static boolean verify(String text, String sign, String key, String input_charset) {text = text + key;String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));if(mysign.equals(sign)) {return true;}else {return false;}}/*** @param content* @param charset* @return* @throws SignatureException* @throws UnsupportedEncodingException*/private static byte[] getContentBytes(String content, String charset) {if (charset == null || "".equals(charset)) {return content.getBytes();}try {return content.getBytes(charset);} catch (UnsupportedEncodingException e) {throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);}}}3、支付宝接口公用函数类:AlipayCore.javapackage com.alipay.util;import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.util.ArrayList;import java.util.Collections;import java.util.HashMap;import java.util.List;import java.util.Map;import mons.codec.digest.DigestUtils;importmons.httpclient.methods.multipart.FilePartSource ;importmons.httpclient.methods.multipart.PartSource; import com.alipay.config.AlipayConfig;/* **类名:AlipayFunction*功能:支付宝接口公用函数类*详细:该类是请求、通知返回两个文件所调用的公用函数核心处理文件,不需要修改*版本:3.3*日期:2012-08-14*说明:*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
*该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
*/public class AlipayCore {/*** 除去数组中的空值和签名参数* @param sArray 签名参数组* @return去掉空值与签名参数后的新签名参数组*/public static Map<String, String> paraFilter(Map<String, String> sArray) {Map<String, String> result = new HashMap<String, String>();if (sArray == null || sArray.size() <= 0) {return result;}for (String key : sArray.keySet()) {String value = sArray.get(key);if (value == null || value.equals("") ||key.equalsIgnoreCase("sign")|| key.equalsIgnoreCase("sign_type")) {continue;}result.put(key, value);}return result;}/*** 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串* @param params 需要排序并参与字符拼接的参数组* @return拼接后字符串*/public static String createLinkString(Map<String, String> params) {List<String> keys = newArrayList<String>(params.keySet());Collections.sort(keys);String prestr = "";for (int i = 0; i < keys.size(); i++) {String key = keys.get(i);String value = params.get(key);if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符prestr = prestr + key + "=" + value;} else {prestr = prestr + key + "=" + value + "&";}}return prestr;}/*** 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)* @param sWord 要写入日志里的文本内容*/public static void logResult(String sWord) {FileWriter writer = null;try {writer = new FileWriter(AlipayConfig.log_path + "alipay_log_" + System.currentTimeMillis()+".txt");writer.write(sWord);} catch (Exception e) {e.printStackTrace();} finally {if (writer != null) {try {writer.close();} catch (IOException e) {e.printStackTrace();}}}}/*** 生成文件摘要* @param strFilePath 文件路径* @param file_digest_type 摘要算法* @return文件摘要结果*/public static String getAbstract(String strFilePath, String file_digest_type) throws IOException {PartSource file = new FilePartSource(newFile(strFilePath));if(file_digest_type.equals("MD5")){return DigestUtils.md5Hex(file.createInputStream());}else if(file_digest_type.equals("SHA")) {returnDigestUtils.sha256Hex(file.createInputStream());}else {return"";}}}4、支付宝通知处理类:AlipayNotify.javapackage com.alipay.util;import java.io.BufferedReader;import java.io.InputStreamReader;import .HttpURLConnection;import .URL;import java.util.Map;import com.alipay.config.AlipayConfig;import com.alipay.sign.MD5;/* **类名:AlipayNotify*功能:支付宝通知处理类*详细:处理支付宝各接口通知返回*版本:3.3*日期:2012-08-17*说明:*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。