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.服务端开发以下代码只需配置好正确参数即可使⽤。
Java支付宝PC网站支付功能开发(详细教程)
Java⽀付宝PC⽹站⽀付功能开发(详细教程)⼀、前⾔本案例使⽤的是Java实现的。
使⽤⽀付宝的沙盒环境⽰例。
发布需要换成正式环境。
这⾥就不作详细说明了本代码适合⽤来做参考,不要直接复制去使⽤。
没有账号的需要去平台注册⼀个:找到开发服务中的沙箱点击查看沙箱开发的流程进⼊到沙箱环境中配置相应的信息点击左边的⽣成密钥,密钥长度选择 RSA2 密钥格式选择PKCS8 因为我们使⽤的是Java开发然后点击⽣成密钥然后复制应⽤公钥上传到沙盒环境中应⽤私钥需要⾃⼰保存下来,后⾯有⽤到噢;⽀付宝的东西已经准备好了现在我们开始写代码⼆、Java代码实现本案例使⽤的是Maven项⽬⾸先我们导⼊⽀付宝的 alipay-sdk-java<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>3.0.0</version></dependency>(1)编写⽀付宝配置⽂件package cn.xtyos.project.system.czzx.config;/*** TODO ⽀付宝配置⽂件** @author James* @date 2020/2/9 20:15*/public class AliPayConfig {//应⽤ID,您的APPID,收款账号既是您的APPID对应⽀付宝账号public static String APP_ID="2018121562XXXXX";//商户私钥,您的PKCS8格式RSA2私钥public static String MERCHANT_PRIVATE_KEY="MIIEvQIBADANxxxxxxxxxxxxx";//⽀付宝公钥,查看地址:https:///platform/keyManage.htm 对应APPID下的⽀付宝公钥。
微信、支付宝二码合一扫码支付实现思路(java)
微信、⽀付宝⼆码合⼀扫码⽀付实现思路(java)⼀、⽀付⼆维码(预订单)根据需要购买的信息创建预订单,将订单信息保存到Redis中,并设置有效期,注意⽣产⼆维码的链接后的参数可以关联到Redis中的key;QRCode 为servlet扫码请求的URL;UUIDUtils.getUUID() 为预订单单号,在servlet请求中截取,然后在Redis中查找对应的Key的数据;⼆、创建⼆维码扫码请求地址servlet:QRCodeServlet;微信⽀付重定向请求servlet:WechatPayServlet;⽀付宝重定向请求servlet:AliPayServlet;QRCodeServlet ⽤于⽤户使⽤微信或者⽀付宝扫码⼆维码进⾏客户端识别及重定向到对应的业务处理;package com.platform.cloudlottery.servlet;import java.io.IOException;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.context.support.SpringBeanAutowiringSupport;import monConfig;import mon.alipay.config.MyAliPayConfig;import mon.wechat.config.WXPublicConfig;import mon.wechat.util.HttpUtil;import com.platform.cloudlottery.model.SysPayChannel;import com.platform.cloudlottery.service.Impl.SysPayChannelServiceImpl;import com.platform.cloudlottery.web.StatusContant.PayTypeConstant;/*** @ClassName: QRCodeServlet* @Description: TODO(根据请求的后缀获取该数据编码对应的数据,并重定向到页⾯)* @author chenkun* @date 2018年12⽉29⽇**/public class QRCodeServlet extends HttpServlet {private static final long serialVersionUID = -8457626626670970403L;protected Logger logger = LoggerFactory.getLogger(getClass());private static final String UrlStr = "QRCode/";private static final String wechatPay = "wechatPay/";private static final String aliPay = "aliPay/";@Autowiredprivate SysPayChannelServiceImpl payChannelService;public void init(ServletConfig servletConfig) throws ServletException {super.init(servletConfig);SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, servletConfig.getServletContext());}public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {("####################请求开始####################");String userAgent = request.getHeader("user-agent");String RequestURL = request.getRequestURL().toString();("URL : " + RequestURL);String ReqInfo = RequestURL.substring(RequestURL.indexOf(UrlStr)+UrlStr.length());("URL : " + ReqInfo);CommonConfig commonConfig = new CommonConfig();if (userAgent != null && userAgent.contains("AlipayClient")) {("来⾃⽀付宝");String redirecturi = HttpUtil.urlEnCode(commonConfig.getDomain() + aliPay + ReqInfo);("REDIRECT_URI="+redirecturi);SysPayChannel channel = payChannelService.selectByChannelType(PayTypeConstant.Alipay);MyAliPayConfig aliPayConfig = new MyAliPayConfig();aliPayConfig.setAppId(channel.getAppid());// 授权页⾯地址String requestUrl = aliPayConfig.getAuthgateway();requestUrl = requestUrl.replace("APPID", aliPayConfig.getAppId()).replace("SCOPE", aliPayConfig.getScope()).replace("REDIRECT_URI", redirecturi);// 重定向到授权页⾯response.sendRedirect(requestUrl);} else if (userAgent != null && userAgent.contains("MicroMessenger")) {("来⾃微信");String redirecturi = HttpUtil.urlEnCode(commonConfig.getDomain() + wechatPay + ReqInfo);("REDIRECT_URI="+redirecturi);SysPayChannel channel = payChannelService.selectByChannelType(PayTypeConstant.Wechat);WXPublicConfig publicConfig = new WXPublicConfig();publicConfig.setAppId(channel.getAppid());publicConfig.setOriginId(channel.getOriginid());publicConfig.setAppSecret(channel.getAppsecret());publicConfig.setEncodingAESKey(channel.getEncodingaeskey());// 授权页⾯地址String requestUrl = publicConfig.getAuthorizeinterface();requestUrl = requestUrl.replace("APPID", publicConfig.getAppId()).replace("REDIRECT_URI", redirecturi).replace("SCOPE", publicConfig.getScope()).replace("STATE", publicConfig.getState()); // 重定向到授权页⾯response.sendRedirect(requestUrl);} else {("未知来源");}("####################请求结束####################");}public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}}WechatPayServlet 在获取到Redis中预订单数据后,创建真实订单并调⽤微信“统⼀下单接⼝”;package com.platform.cloudlottery.servlet;import com.alibaba.fastjson.JSONObject;import com.github.wxpay.sdk.WXPayUtil;import monConfig;import mon.jedis.JedisUtil;import ng.StringUtils;import mon.utils.BusinessCodeUtils;import mon.wechat.bean.WeiXinOAuth2Token;import mon.wechat.bean.WeiXinUserInfo;import mon.wechat.config.WXPayConfig;import mon.wechat.config.WXPublicConfig;import mon.wechat.util.WeiXinOAuth2Util;import mon.wechat.util.WeiXinPayUtils;import com.platform.cloudlottery.model.SysPayChannel;import com.platform.cloudlottery.service.Impl.LotteryOrderServiceImpl;import com.platform.cloudlottery.service.Impl.SysPayChannelServiceImpl;import erMemberServiceImpl;import com.platform.cloudlottery.service.OrderServcie;import erInfoService;import com.platform.cloudlottery.web.ResultContant;import com.platform.cloudlottery.web.StatusContant.PayTypeConstant;import com.platform.cloudlottery.web.SysKey;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.context.support.SpringBeanAutowiringSupport;import redis.clients.jedis.Jedis;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.math.BigDecimal;import java.util.Date;import java.util.LinkedHashMap;import java.util.Map;/*** @ClassName: WechatPayServlet* @Description: TODO(这⾥⽤⼀句话描述这个类的作⽤)* @author chenkun* @date 2019年1⽉5⽇**/public class WechatPayServlet extends HttpServlet {private static final long serialVersionUID = -8457626626670970403L;protected Logger logger = LoggerFactory.getLogger(getClass());private static Jedis redis = JedisUtil.getJedis();@Value("${config.domain}")private String domain;@Value("${config.isProduction}")private boolean isProduction;// 请求路径包含的字符串private static final String UrlStr = "wechatPay/";@Autowiredprivate SysPayChannelServiceImpl payChannelService;@Autowiredprivate UserMemberServiceImpl memberService;@Autowiredprivate LotteryOrderServiceImpl lotteryOrderService;public void init(ServletConfig servletConfig) throws ServletException {super.init(servletConfig);SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, servletConfig.getServletContext());}public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {logger.debug("####################请求开始####################");request.setCharacterEncoding("utf-8");response.setCharacterEncoding("utf-8");try {// ⽤户同意授权后,能获取到codeString code = request.getParameter("code");// ⽤户同意授权if (!"authdeny".equals(code)) {CommonConfig commonConfig = new CommonConfig();String RequestURL = request.getRequestURL().toString();logger.debug("URL : " + RequestURL);String QRCodeUrl = RequestURL.substring(RequestURL.indexOf(UrlStr) + UrlStr.length());String QRCodeReqInfo = QRCodeUrl.split("&")[0];String operatorId = QRCodeUrl.split("&")[1];logger.debug("QRCodeReqInfo : " + QRCodeReqInfo +";operatorId : " + operatorId);String advancekey = commonConfig.getLotteryorder() + QRCodeReqInfo;SysPayChannel channel = payChannelService.selectByChannelType(PayTypeConstant.Wechat);WXPublicConfig publicConfig = new WXPublicConfig();publicConfig.setAppId(channel.getAppid());publicConfig.setOriginId(channel.getOriginid());publicConfig.setAppSecret(channel.getAppsecret());publicConfig.setEncodingAESKey(channel.getEncodingaeskey());WXPayConfig payConfig = new WXPayConfig();payConfig.setMchId(channel.getMchid());payConfig.setAppId(channel.getAppid());payConfig.setKey(channel.getWxkey());payConfig.setApicertPath(channel.getPayCertUrl());payConfig.setSpbillCreateIp(channel.getSpbillcreateip());// 获取⽹页授权access_tokenWeiXinOAuth2Token weixinOauth2Token = WeiXinOAuth2Util.getOAuth2AccessToken(publicConfig,code);// ⽹页授权接⼝访问凭证String accessToken = weixinOauth2Token.getAccessToken();logger.debug("accessToken=" + accessToken);// ⽤户标识String openId = weixinOauth2Token.getOpenId();logger.debug("openId="+openId);// 获取⽤户信息WeiXinUserInfo userInfo = WeiXinOAuth2Util.getOAuth2UserInfo(publicConfig, accessToken, openId);logger.debug(userInfo.getNickName()+"=====微信⽀付====="+userInfo.getOpenId());//添加或更新⽤户信息String userid = UserInfoService.CreateUserMember(userInfo,memberService);if (!redis.exists(advancekey)) {// 判断key是否存在logger.debug("⼆维码失效");request.setAttribute("code", ResultContant.notuserdqrcode);request.setAttribute("message", "⼆维码失效");request.getRequestDispatcher("../wechat/WechatPay.jsp").forward(request, response);logger.debug("####################请求结束####################");return;}if (StringUtils.trimToEmpty(redis.get(advancekey)).equals("")) {logger.debug("⼆维码失效");request.setAttribute("code", ResultContant.notuserdqrcode);request.setAttribute("message", "⼆维码失效");request.getRequestDispatcher("../wechat/WechatPay.jsp").forward(request, response);logger.debug("####################请求结束####################");return;}JSONObject jsonObject = JSONObject.parseObject(redis.get(advancekey));if (null == jsonObject) {logger.debug("⼆维码失效");request.setAttribute("code", ResultContant.notuserdqrcode);request.setAttribute("message", "⼆维码失效");request.getRequestDispatcher("../wechat/WechatPay.jsp").forward(request, response);logger.debug("####################请求结束####################");return;}if (redis.get(advancekey + "_lock") != null && !redis.get(advancekey + "_lock").equals("")){logger.debug("⼆维码失效");request.setAttribute("code", ResultContant.notuserdqrcode);request.setAttribute("message", "⼆维码失效");request.getRequestDispatcher("../wechat/WechatPay.jsp").forward(request, response);logger.debug("####################请求结束####################");return;}redis.setex(advancekey + "_lock", 1, "lock");String orderid = BusinessCodeUtils.getOrderNo(jsonObject.getString(SysKey.deviceSn));int money = jsonObject.getIntValue(SysKey.money);int lotterytype = jsonObject.getIntValue(SysKey.lotteryType);if (!orderid.equals("") && money!=0) {//创建订单boolean bool = OrderServcie.createorder(QRCodeReqInfo, PayTypeConstant.Wechat, payConfig.getAppID(), userid, openId, orderid, jsonObject, lotteryOrderService); if (bool) {//删除预订单信息redis.del(advancekey);//⼀个预订单只能创建⼀个订单String paymoney = String.valueOf(money);if (!isProduction) {//测试环境paymoney = BigDecimal.valueOf(Long.valueOf(paymoney)).divide(new BigDecimal(100)).toString();//真实⾦额除100}logger.debug("是否⽣产环境:"+isProduction+";订单⾦额为:"+String.valueOf(money)+";实际⽀付⾦额为:"+paymoney);//创建微信订单Map<String, String> map = WeiXinPayUtils.createOrderJsapi(domain, payConfig, orderid, paymoney, lotterytype==0?"即开票":"电脑票", openId);logger.debug("创建微信⽀付预订单返回数据:"+JSONObject.toJSONString(map));if (map != null) {if (map.get("return_code").equals("SUCCESS")) {if (map.get("result_code").equals("SUCCESS")) {logger.debug("创建微信⽀付预订单成功");Map<String, String> data = new LinkedHashMap<String, String>();data.put("appId", payConfig.getAppID());data.put("timeStamp", String.valueOf(new Date().getTime()/1000));data.put("nonceStr", WXPayUtil.generateNonceStr());data.put("package", "prepay_id="+map.get("prepay_id"));data.put("signType", "MD5");data.put("paySign", WXPayUtil.generateSignature(data, payConfig.getKey()));logger.debug("返回到客户端的数据:"+JSONObject.toJSONString(data));request.setAttribute("appId", data.get("appId"));request.setAttribute("timeStamp", data.get("timeStamp"));request.setAttribute("nonceStr", data.get("nonceStr"));request.setAttribute("package", data.get("package"));request.setAttribute("signType", data.get("signType"));request.setAttribute("paySign", data.get("paySign"));request.setAttribute("code", ResultContant.sucess);request.setAttribute("message", "成功");request.getRequestDispatcher("../wechat/WechatPay.jsp").forward(request, response);}else{logger.debug("创建订单失败:创建⽀付预订单失败");request.setAttribute("code", ResultContant.createordererror);request.setAttribute("message", "创建订单失败");request.getRequestDispatcher("../wechat/WechatPay.jsp").forward(request, response);}} else {logger.debug("创建订单失败:创建⽀付预订单失败");request.setAttribute("code", ResultContant.createordererror);request.setAttribute("message", "创建订单失败");request.getRequestDispatcher("../wechat/WechatPay.jsp").forward(request, response);}} else {logger.debug("创建订单失败:创建⽀付预订单失败");request.setAttribute("code", ResultContant.createordererror);request.setAttribute("message", "创建订单失败");request.getRequestDispatcher("../wechat/WechatPay.jsp").forward(request, response);}} else {logger.debug("创建订单失败:创建⽀付预订单失败");request.setAttribute("code", ResultContant.createordererror);request.setAttribute("message", "创建订单失败");request.getRequestDispatcher("../wechat/WechatPay.jsp").forward(request, response);}} else {logger.debug("创建订单失败;订单⾦额或者订单号数据有误");request.setAttribute("code", ResultContant.createordererror);request.setAttribute("message", "创建订单失败");request.getRequestDispatcher("../wechat/WechatPay.jsp").forward(request, response);}}} catch (Exception e) {e.printStackTrace();logger.debug("系统异常");request.setAttribute("code", ResultContant.notuserdqrcode);request.setAttribute("message", "⼆维码失效");request.getRequestDispatcher("../wechat/WechatPay.jsp").forward(request, response);}logger.debug("####################请求结束####################");}public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response);}}AliPayServlet 在获取到Redis中预订单数据后,创建真实订单并调⽤⽀付宝“⼿机⽹站⽀付接⼝”;package com.platform.cloudlottery.servlet;import com.alibaba.fastjson.JSONObject;import monConfig;import mon.alipay.bean.AliPayOAuth2Token;import mon.alipay.bean.AliPayUserInfo;import mon.alipay.config.MyAliPayConfig;import mon.alipay.uitl.AliPayOAuth2Util;import mon.alipay.uitl.AlipayPayUtils;import mon.jedis.JedisUtil;import ng.StringUtils;import mon.properties.PropertiesUtils;import mon.utils.BusinessCodeUtils;import com.platform.cloudlottery.model.SysPayChannel;import com.platform.cloudlottery.service.Impl.LotteryOrderServiceImpl;import com.platform.cloudlottery.service.Impl.SysPayChannelServiceImpl;import erMemberServiceImpl;import com.platform.cloudlottery.service.OrderServcie;import erInfoService;import com.platform.cloudlottery.web.ResultContant;import com.platform.cloudlottery.web.StatusContant.PayTypeConstant;import com.platform.cloudlottery.web.SysKey;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.context.support.SpringBeanAutowiringSupport;import redis.clients.jedis.Jedis;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.math.BigDecimal;import java.util.Properties;/*** @ClassName: AliPayServlet* @Description: TODO(这⾥⽤⼀句话描述这个类的作⽤)* @author chenkun* @date 2019年1⽉5⽇**/public class AliPayServlet extends HttpServlet {private static final long serialVersionUID = -8457626626670970403L;protected Logger logger = LoggerFactory.getLogger(getClass());private static Jedis redis = JedisUtil.getJedis();@Value("${config.domain}")private String domain;@Value("${config.isProduction}")private boolean isProduction;// 请求路径包含的字符串private static final String UrlStr = "aliPay/";@Autowiredprivate SysPayChannelServiceImpl payChannelService;@Autowiredprivate UserMemberServiceImpl memberService;@Autowiredprivate LotteryOrderServiceImpl lotteryOrderService;public void init(ServletConfig servletConfig) throws ServletException {super.init(servletConfig);SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, servletConfig.getServletContext());}public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { logger.debug("####################请求开始####################");request.setCharacterEncoding("utf-8");response.setCharacterEncoding("utf-8");try {//⽤户同意授权后,能获取到codeString code = request.getParameter("auth_code");//⽤户同意授权if (!code.equals("")) {CommonConfig commonConfig = new CommonConfig();//具体业务String RequestURL = request.getRequestURL().toString();logger.debug("URL : " + RequestURL);String QRCodeUrl = RequestURL.substring(RequestURL.indexOf(UrlStr) + UrlStr.length());String QRCodeReqInfo = QRCodeUrl.split("&")[0];String operatorId = QRCodeUrl.split("&")[1];logger.debug("QRCodeReqInfo : " + QRCodeReqInfo +";operatorId : " + operatorId);String advancekey = commonConfig.getLotteryorder() + QRCodeReqInfo;SysPayChannel channel = payChannelService.selectByChannelType(PayTypeConstant.Alipay);MyAliPayConfig aliPayConfig = new MyAliPayConfig();aliPayConfig.setAppId(channel.getAppid());String certsrc = channel.getPayCertUrl();Properties propertiesFile = PropertiesUtils.getPropertiesFile(certsrc);if (propertiesFile != null) {aliPayConfig.setPayeeAccount(propertiesFile.getProperty("ALI_PAYEE_ACCOUNT"));aliPayConfig.setAppId(propertiesFile.getProperty("ALI_APP_ID"));aliPayConfig.setAliPayPublicKey(propertiesFile.getProperty("ALI_ALIPAY_PUBLIC_KEY"));aliPayConfig.setAppPayPublicKey(propertiesFile.getProperty("ALI_APP_PAY_PUBLIC_KEY"));aliPayConfig.setAppPrivateKey(propertiesFile.getProperty("ALI_APP_PRIVATE_KEY"));}//获取⽹页授权access_tokenAliPayOAuth2Token aliPayOAuth2Token = AliPayOAuth2Util.getOAuth2AccessToken(aliPayConfig,code);//⽹页授权接⼝访问凭证String accessToken = aliPayOAuth2Token.getAccessToken();logger.debug("accessToken=" + accessToken);//⽤户标识String aliuserid = aliPayOAuth2Token.getUserid();logger.debug("aliuserid="+aliuserid);//获取⽤户信息AliPayUserInfo userInfo = AliPayOAuth2Util.getOAuth2UserInfo(aliPayConfig,accessToken,aliuserid);logger.debug(userInfo.getNickName()+"=====⽀付宝⽀付====="+userInfo.getUserId());//添加或更新⽤户信息String userid = UserInfoService.CreateUserMember(userInfo,memberService);if (!redis.exists(advancekey)) {// 判断key是否存在logger.debug("⼆维码失效");request.setAttribute("code", ResultContant.notuserdqrcode);request.setAttribute("message", "⼆维码失效");request.getRequestDispatcher("../alipay/AliPay.jsp").forward(request, response);logger.debug("####################请求结束####################");return;}if (StringUtils.trimToEmpty(redis.get(advancekey)).equals("")) {logger.debug("⼆维码失效");request.setAttribute("code", ResultContant.notuserdqrcode);request.setAttribute("message", "⼆维码失效");request.getRequestDispatcher("../alipay/AliPay.jsp").forward(request, response);logger.debug("####################请求结束####################");return;}JSONObject jsonObject = JSONObject.parseObject(redis.get(advancekey));if (null == jsonObject) {logger.debug("⼆维码失效");request.setAttribute("code", ResultContant.notuserdqrcode);request.setAttribute("message", "⼆维码失效");request.getRequestDispatcher("../alipay/AliPay.jsp").forward(request, response);logger.debug("####################请求结束####################");return;}if (redis.get(advancekey + "_lock") != null && !redis.get(advancekey + "_lock").equals("")){logger.debug("⼆维码失效");request.setAttribute("code", ResultContant.notuserdqrcode);request.setAttribute("message", "⼆维码失效");request.getRequestDispatcher("../alipay/AliPay.jsp").forward(request, response);logger.debug("####################请求结束####################");return;}redis.setex(advancekey + "_lock", 1, "lock");String orderid = BusinessCodeUtils.getOrderNo(jsonObject.getString(SysKey.deviceSn));int money = jsonObject.getIntValue(SysKey.money);int lotterytype = jsonObject.getIntValue(SysKey.lotteryType);if (!orderid.equals("") && money != 0) {//创建订单boolean bool = OrderServcie.createorder(QRCodeReqInfo, PayTypeConstant.Alipay, aliPayConfig.getAppId(), userid, aliuserid, orderid, jsonObject, lotteryOrderService);if (bool) {//删除预订单信息redis.del(advancekey);//⼀个预订单只能创建⼀个订单String paymoney = BigDecimal.valueOf(Long.valueOf(money)).divide(new BigDecimal(100)).toString();if (!isProduction) {//测试环境paymoney = BigDecimal.valueOf(Long.valueOf(paymoney)).divide(new BigDecimal(100)).toString();//真实⾦额除100}logger.debug("是否⽣产环境:"+isProduction+";订单⾦额为:"+BigDecimal.valueOf(Long.valueOf(money)).divide(new BigDecimal(100)).toString()+";实际⽀付⾦额为:"+paymoney); //创建⽀付宝订单String responsestr = AlipayPayUtils.createOrderWapPay(domain, aliPayConfig, orderid, lotterytype==0?"即开票":"电脑票", paymoney, "");logger.debug("创建⽀付宝⽀付预订单返回数据:"+responsestr);if (!responsestr.equals("")) {response.setContentType("text/html;charset=UTF-8");response.getWriter().write(responsestr);//直接将完整的表单html输出到页⾯response.getWriter().flush();response.getWriter().close();response.getWriter().append("Served at: ").append(request.getContextPath());} else {logger.debug("创建订单失败:创建⽀付预订单失败");request.setAttribute("code", ResultContant.createordererror);request.setAttribute("message", "创建订单失败");request.getRequestDispatcher("../alipay/AliPay.jsp").forward(request, response);}} else {logger.debug("创建订单失败:创建⽀付预订单失败");request.setAttribute("code", ResultContant.createordererror);request.setAttribute("message", "创建订单失败");request.getRequestDispatcher("../alipay/AliPay.jsp").forward(request, response);}} else {logger.debug("创建订单失败;订单⾦额或者订单号数据有误");request.setAttribute("code", ResultContant.createordererror);request.setAttribute("message", "创建订单失败");request.getRequestDispatcher("../alipay/AliPay.jsp").forward(request, response);}}} catch (Exception e) {e.printStackTrace();logger.debug("系统异常");request.setAttribute("code", "⼆维码失效");request.setAttribute("message", "⼆维码失效");request.getRequestDispatcher("../alipay/AliPay.jsp").forward(request, response);}logger.debug("####################请求结束####################");}public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}}三、创建微信⽀付结果回调接⼝和⽀付宝⽀付接⼝回调接⼝,⽤于接收微信或者⽀付宝的⽀付结果通知;aliPayNotify ⽀付宝⽀付成功回调接⼝/*** @Title: aliPayNotify* @Description: TODO(⽀付宝⽀付成功过回调)* @author chenkun* @return 参数* @return String 返回类型* @throws*/@RequestMapping(value = "/aliPayNotify", method = RequestMethod.POST)public String aliPayNotify() {ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();Map<String, String> params = convertRequestParamsToMap(request); // 将异步通知中收到的待验证所有参数都存放到map中String paramsJson = JSON.toJSONString(params);("⽀付宝⽀付回调,{" + paramsJson + "}");try {SysPayChannel channel = payChannelService.selectByChannelType(PayTypeConstant.Alipay);MyAliPayConfig aliPayConfig = new MyAliPayConfig();aliPayConfig.setAppId(channel.getAppid());String certsrc = channel.getPayCertUrl();Properties propertiesFile = PropertiesUtils.getPropertiesFile(certsrc);if (propertiesFile != null) {aliPayConfig.setPayeeAccount(propertiesFile.getProperty("ALI_PAYEE_ACCOUNT"));aliPayConfig.setAppId(propertiesFile.getProperty("ALI_APP_ID"));aliPayConfig.setAliPayPublicKey(propertiesFile.getProperty("ALI_ALIPAY_PUBLIC_KEY"));aliPayConfig.setAppPayPublicKey(propertiesFile.getProperty("ALI_APP_PAY_PUBLIC_KEY"));aliPayConfig.setAppPrivateKey(propertiesFile.getProperty("ALI_APP_PRIVATE_KEY"));}// 调⽤SDK验证签名boolean signVerified = AlipaySignature.rsaCheckV1(params, aliPayConfig.getAliPayPublicKey(),aliPayConfig.getCharset(), aliPayConfig.getSigntype());if (signVerified) {("⽀付宝回调签名认证成功");// 按照⽀付结果异步通知中的描述,对⽀付结果中的业务内容进⾏1\2\3\4⼆次校验,校验成功后在response中返回success,校验失败返回failure this.check(params);// 另起线程处理业务executorService.execute(new AliPayNotifyTask(params,payCallBackService));// 如果签名验证正确,⽴即返回success,后续业务另起线程单独处理// 业务处理失败,可查看⽇志进⾏补偿,跟⽀付宝已经没多⼤关系。
luffy-支付宝支付
luffy-⽀付宝⽀付⽀付宝⽀付⼊门"""1)⽀付宝API:六⼤接⼝https:///270/105900/2)⽀付宝⼯作流程(见下图):https:///270/105898/3)⽀付宝8次异步通知机制(⽀付宝对我们服务器发送POST请求,索要 success 7个字符)https:///270/105902/"""流程# 1、在沙箱环境下实名认证:https:///platform/appDaily.htm?tab=info# 2、电脑⽹站⽀付API:https:///270/105900/# 3、完成RSA密钥⽣成:https:///291/105971# 4、在开发中⼼的沙箱应⽤下设置应⽤公钥:填⼊⽣成的公钥⽂件中的内容# 5、Python⽀付宝开源框架:https:///fzlee/alipay# >: pip install python-alipay-sdk --upgrade# 7、公钥私钥设置"""# alipay_public_key.pem-----BEGIN PUBLIC KEY-----⽀付宝公钥-----END PUBLIC KEY-----# app_private_key.pem-----BEGIN RSA PRIVATE KEY-----⽤户私钥-----END RSA PRIVATE KEY-----"""# 8、⽀付宝链接"""开发:https:///gateway.do沙箱:https:///gateway.do"""后端使⽤测试代码⽰例:t_alipay.pyfrom alipay import AliPay# app_private_key_string = open("/path/to/your/private/key.pem").read()# alipay_public_key_string = open("/path/to/alipay/public/key.pem").read()app_private_key_string = """-----BEGIN RSA PRIVATE KEY-----MIIEpAIBAAKCAQEAq+PKAWg9R8ms8FPJROUsWoPxoPjzOihvqqAmcLoAPb/69e6sYt0SJGtz16aYz5EUkRsSaxEwObepnb58ziYg7dOblrrFbp46FPe4FeQb17s0xSSJHWbZT+3eu+kiaCznEvuQNdfjIxyyv63RbZth1+lblXj7TLMsHd4cggUvSn8aylq -----END RSA PRIVATE KEY-----"""alipay_public_key_string = """-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmiCxllecv79tYxmLKbW7VhgS5RvdrBHf/2RwwDH/72Lnhw/qLAtRrGXqhJWfZLMELGeI+WKoYUOTHwcEYdM0gdaX5PlgWZMGjtW2D6cRWsJtaJBCTBHB/Kf6aT3gVaBONd0SNc4tZ74s -----END PUBLIC KEY-----"""alipay = AliPay(appid="2021000116697102",app_notify_url='http://127.0.0.1:8000/free/course', # the default notify pathapp_private_key_string=app_private_key_string,# alipay public key, do not use your own public key!alipay_public_key_string=alipay_public_key_string,sign_type="RSA2", # RSA or RSA2debug=True # False by default)alipay_url='https:///gateway.do?'order_string = alipay.api_alipay_trade_page_pay (out_trade_no="20161112jc",total_amount=9999,subject='Dell外星⼈',return_url="https:///free-course",notify_url="https:///free-course")print(alipay_url+order_string)⽀付流程aliapy⼆次封装包GitHub开源框架# https:///fzlee/alipay依赖>: pip install python-alipay-sdk --upgrade# 如果抛ssl相关错误,代表缺失该包>: pip install pyopenssl结构libs├── iPay # aliapy⼆次封装包│├──__init__.py # 包⽂件│├── pem # 公钥私钥⽂件夹││├── alipay_public_key.pem # ⽀付宝公钥⽂件││├── app_private_key.pem # 应⽤私钥⽂件│├── pay.py # ⽀付⽂件└──└── settings.py # 应⽤配置alipay_public_key.pem-----BEGIN PUBLIC KEY-----拿应⽤公钥跟⽀付宝换来的⽀付宝公钥-----END PUBLIC KEY-----app_private_key.pem-----BEGIN RSA PRIVATE KEY-----通过⽀付宝公钥私钥签发软件签发的应⽤私钥-----END RSA PRIVATE KEY-----setting.pyimport os# 应⽤私钥APP_PRIVATE_KEY_STRING = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'pem', 'app_private_key.pem')).read() # ⽀付宝公钥ALIPAY_PUBLIC_KEY_STRING = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'pem', 'alipay_public_key.pem')).read() # 应⽤IDAPP_ID = '2016093000631831'# 加密⽅式SIGN = 'RSA2'# 是否是⽀付宝测试环境(沙箱环境),如果采⽤真是⽀付宝环境,配置FalseDEBUG = True# ⽀付⽹关GATEWAY = 'https:///gateway.do'if DEBUG else'https:///gateway.do'pay.pyfrom alipay import AliPayfrom . import settings# ⽀付对象alipay = AliPay(appid=settings.APP_ID,app_notify_url=None,app_private_key_string=settings.APP_PRIVATE_KEY_STRING,alipay_public_key_string=settings.ALIPAY_PUBLIC_KEY_STRING,sign_type=settings.SIGN,debug=settings.DEBUG)# ⽀付⽹关gateway = settings.GATEWAY_init_.py# 包对外提供的变量from .pay import gateway, alipay补充:在⾃⼰项⽬的配置⽂件中配置⽀付宝回调接⼝:settings.py | dev.py# 上线后必须换成公⽹地址# 后台基URLBASE_URL = 'http://127.0.0.1:8000'# 前台基URLLUFFY_URL = 'http://127.0.0.1:8080'# ⽀付宝同步异步回调接⼝配置# 后台异步回调接⼝NOTIFY_URL = BASE_URL + "/order/success/"# 前台同步回调接⼝,没有 / 结尾RETURN_URL = LUFFY_URL + "/pay/success"后台⽀付接⼝模型表:order/models.py# 订单表分析-订单表-订单详情# 代码from django.db import modelsfrom user.models import Userfrom course.models import Courseclass 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="⽀付时间")# ⼀个⽤户可以下多个订单,⼀个订单只属于⼀个⽤户,⼀对多的关系user = models.ForeignKey(User, related_name='order_user', on_delete=models.DO_NOTHING, db_constraint=False,verbose_name="下单⽤户")created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')updated_time = models.DateTimeField(auto_now=True, 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_list# 订单和订单详情是⼀对多,关联字段建在多的⼀⽅class OrderDetail(models.Model):"""订单详情"""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, db_constraint=False, verbose_name="课程", null=True)price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="课程原价")real_price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="课程实价")class Meta:db_table = "luffy_order_detail"verbose_name = "订单详情"verbose_name_plural = "订单详情"def__str__(self):try:return"%s的订单:%s" % (, self.order.out_trade_no)except:return super().__str__()数据迁移# python manage.py makemigrations# python manage.py migrate订单模块接⼝分析# 1 ⽀付接⼝(⽣成订单,,⽣成⽀付连接,返回⽀付连接)-order表和orderdetail表插⼊数据,重写create⽅法-⽣成订单号(uuid)-登录后才能做(jwt认证)-当前登录⽤户就是下单⽤户,存到order表中-下了三个课程,总价格100,前端提交的价格是99,异常处理'''#1)订单总价校验# 2)⽣成订单号# 3)⽀付⽤户:er# 4)⽀付链接⽣成# 5)⼊库(两个表)的信息准备'''# 2 ⽀付宝异步回调的post接⼝(验证签名,修改订单状态)# 3 当⽀付宝get回调前端,vue组件⼀创建,⽴马向后端发⼀个请求(get)⽀付接⼝分析:# 1 前端传什么格式数据-{course:[1,2,3],total_amount:100,subject:xx商品,pay_type:1,}# 2 后端接到数据要校验-course:[1,2,3]===》course:[obj1,obj2,obj3]-在序列化类中:course=serializers.PrimaryKeyRelatedField(queryset=Course.objects.all(), write_only=True, many=True) order/urls.pyfrom django.urls import path,re_path,includefrom rest_framework.routers import SimpleRouterfrom . import viewsrouter = SimpleRouter()router.register('pay', views.PayView, 'pay')urlpatterns = [path('', include(router.urls))]serializers.pyfrom rest_framework import serializersfrom rest_framework.exceptions import ValidationErrorfrom django.conf import settingsfrom . import modelsfrom course.models import Courseclass OrderSerializer(serializers.ModelSerializer):# 前端传什么格式数据# -{course:[1,2,3],total_amount:100,subject:xx商品,pay_type:1,}# user字段需要,但是不是传的,使⽤了jwt# 2 后端接到数据要校验# course: [1, 2, 3] == =》course: [obj1,obj2,obj3]# 在序列化类中:# ⽅法1:⽤局部钩⼦⾃⼰处理# course = serializers.CharField()# ⽅法2:# course = serializers.PrimaryKeyRelatedField(queryset=Course.objects.all(), write_only=True, many=True)course = serializers.PrimaryKeyRelatedField(queryset=Course.objects.all(), write_only=True, many=True)class Meta:model = models.Orderfields = ['total_amount', 'subject', 'pay_type', 'course']extra_kwargs = {"total_amount": {'required': True},"pay_type": {'required': True},}# 订单总价校验def _check_price(self, attrs):course_list = attrs.get('course')total_amount = attrs.get('total_amount')total_price = 0for course in course_list:total_price += course.priceif total_price != total_amount:raise ValidationError('价格不合法')return total_amount# ⽣成订单号def _gen_out_trade_no(self):import uuidcode = '%s' % uuid.uuid4()return code.replace('-', '')# 获取⽀付⽤户# 需要request对象(需要视图通过context把request对象传过来,重写create⽅法)def _get_user(self):return self.context.get('request').userdef _gen_pay_url(self, out_trade_no, total_amount, subject):from luffyapi.libs.al_pay import alipay, gate_wayorder_string = alipay.api_alipay_trade_page_pay(out_trade_no=out_trade_no,total_amount=float(total_amount), # 只有⽣成⽀付宝链接时,不能⽤Decimal,因为⽀付宝识别不了,需要转换成float类型 subject=subject,return_url=settings.RETURN_URL, # get回调,前台地址notify_url=settings.NOTIFY_URL, # post回调,后台地址)return gate_way + order_string# ⼊库(两个表)的信息准备def _before_create(self, attrs, user, pay_url, out_trade_no):attrs['user'] = userattrs['out_trade_no'] = out_trade_noself.context['pay_url'] = pay_url# 校验def validate(self, attrs):"""# 1)订单总价校验# 2)⽣成订单号# 3)⽀付⽤户:er# 4)⽀付链接⽣成# 5)⼊库(两个表)的信息准备"""# 1)订单总价校验total_amount = self._check_price(attrs)# 2)⽣成订单号out_trade_no = self._gen_out_trade_no()# 3)⽀付⽤户:eruser = self._get_user()# 4)⽀付链接⽣成pay_url = self._gen_pay_url(out_trade_no, total_amount, attrs.get('subject'))# 5)⼊库(两个表)的信息准备self._before_create(attrs, user, pay_url, out_trade_no)# 代表该校验⽅法通过,进⼊⼊库操作return attrs# 重写⼊库⽅法的⽬的:完成订单与订单详情两个表⼊库操作def create(self, validated_data):course_list = validated_data.pop('course')# 订单表⼊库,不需要courseorder = models.Order.objects.create(**validated_data)# 订单详情表⼊库:只需要订单对象,课程对象(courses要拆成⼀个个course)for course in course_list:models.OrderDetail.objects.create(order=order, course=course, price=course.price, real_price=course.price) # 先循环制造数据列表[{}, ..., {}],⽤群增完成⼊库 bulk_create(),效率⾼return orderviews.pyfrom django.shortcuts import renderfrom rest_framework.viewsets import GenericViewSetfrom rest_framework.mixins import CreateModelMixinfrom rest_framework.response import Responsefrom rest_framework_jwt.authentication import JSONWebTokenAuthenticationfrom rest_framework.permissions import IsAuthenticatedfrom . import modelsfrom . import serializersclass PayView(GenericViewSet, CreateModelMixin):authentication_classes = [JSONWebTokenAuthentication, ]permission_classes = [IsAuthenticated, ]queryset = models.Order.objects.all()serializer_class = serializers.OrderSerializer# 重写create⽅法,传request对象def create(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data, context={'request': request})serializer.is_valid(raise_exception=True)self.perform_create(serializer)return Response(serializer.context.get('pay_url'))。
javaweb在线支付功能实现代码
javaweb在线⽀付功能实现代码本⽂实例为⼤家分享了javaweb在线⽀付功能的具体实现代码,供⼤家参考,具体内容如下package com.learning.web.servlet;import java.io.IOException;import java.util.ResourceBundle;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.learning.utils.PaymentUtil;@WebServlet("/payOnline")public class PayOnline extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String orderid = request.getParameter("orderid");String money = request.getParameter("money");// 银⾏String pd_FrpId = request.getParameter("pd_FrpId");// 发给⽀付公司需要哪些数据String p0_Cmd = "Buy";String p1_MerId = ResourceBundle.getBundle("/WEB-INF/classes/merchantInfo").getString("p1_MerId");String p2_Order = orderid;String p3_Amt = money;String p4_Cur = "CNY";String p5_Pid = "";String p6_Pcat = "";String p7_Pdesc = "";// ⽀付成功回调地址 ---- 第三⽅⽀付公司会访问、⽤户访问// 第三⽅⽀付可以访问⽹址(本项⽬⽹址)String p8_Url = "http://115.170.37.189/day19pay/callback";String p9_SAF = "";String pa_MP = "";String pr_NeedResponse = "1";// 加密hmac 需要密钥String keyValue = ResourceBundle.getBundle("merchantInfo").getString("keyValue");String hmac = PaymentUtil.buildHmac(p0_Cmd, p1_MerId, p2_Order, p3_Amt,p4_Cur, p5_Pid, p6_Pcat, p7_Pdesc, p8_Url, p9_SAF, pa_MP,pd_FrpId, pr_NeedResponse, keyValue);// ⽣成url --- url?request.setAttribute("pd_FrpId", pd_FrpId);request.setAttribute("p0_Cmd", p0_Cmd);request.setAttribute("p1_MerId", p1_MerId);request.setAttribute("p2_Order", p2_Order);request.setAttribute("p3_Amt", p3_Amt);request.setAttribute("p4_Cur", p4_Cur);request.setAttribute("p5_Pid", p5_Pid);request.setAttribute("p6_Pcat", p6_Pcat);request.setAttribute("p7_Pdesc", p7_Pdesc);request.setAttribute("p8_Url", p8_Url);request.setAttribute("p9_SAF", p9_SAF);request.setAttribute("pa_MP", pa_MP);request.setAttribute("pr_NeedResponse", pr_NeedResponse);request.setAttribute("hmac", hmac);request.getRequestDispatcher("/confirm.jsp").forward(request, response);}}2.⽤户确认提交的信息(confirm.jsp)<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><%@taglib prefix="p" uri="/tag"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body><p:user /><!-- 确认⽀付form --><form action="https:///app-merchant-proxy/node"method="get"><h3>订单号:${p2_Order},付款⾦额:${p3_Amt }</h3><input type="hidden" name="pd_FrpId" value="${pd_FrpId }" /> <inputtype="hidden" name="p0_Cmd" value="${p0_Cmd }" /> <inputtype="hidden" name="p1_MerId" value="${p1_MerId }" /> <inputtype="hidden" name="p2_Order" value="${p2_Order }" /> <inputtype="hidden" name="p3_Amt" value="${p3_Amt }" /> <inputtype="hidden" name="p4_Cur" value="${p4_Cur }" /> <inputtype="hidden" name="p5_Pid" value="${p5_Pid }" /> <inputtype="hidden" name="p6_Pcat" value="${p6_Pcat }" /> <inputtype="hidden" name="p7_Pdesc" value="${p7_Pdesc }" /> <inputtype="hidden" name="p8_Url" value="${p8_Url }" /> <inputtype="hidden" name="p9_SAF" value="${p9_SAF }" /> <inputtype="hidden" name="pa_MP" value="${pa_MP }" /> <input type="hidden"name="pr_NeedResponse" value="${pr_NeedResponse }" /> <inputtype="hidden" name="hmac" value="${hmac }" /> <input type="submit"value="确认⽀付" /></form></body></html>3.⽹站获得第三⽅⽀付的信息package com.learning.web.servlet;import java.io.IOException;import java.util.ResourceBundle;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.learning.service.OrderService;import com.learning.utils.PaymentUtil;/*** 该Servlet会在⽀付成功后进⾏调⽤----- ⽀付公司、客户** @author seawind**/public class CallbackServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 获得回调所有数据String p1_MerId = request.getParameter("p1_MerId");String r0_Cmd = request.getParameter("r0_Cmd");String r1_Code = request.getParameter("r1_Code");String r2_TrxId = request.getParameter("r2_TrxId");String r3_Amt = request.getParameter("r3_Amt");String r4_Cur = request.getParameter("r4_Cur");String r5_Pid = request.getParameter("r5_Pid");String r6_Order = request.getParameter("r6_Order");String r7_Uid = request.getParameter("r7_Uid");String r8_MP = request.getParameter("r8_MP");String r9_BType = request.getParameter("r9_BType");String rb_BankId = request.getParameter("rb_BankId");String ro_BankOrderId = request.getParameter("ro_BankOrderId");String rp_PayDate = request.getParameter("rp_PayDate");String rq_CardNo = request.getParameter("rq_CardNo");String ru_Trxtime = request.getParameter("ru_Trxtime");// ⾝份校验 --- 判断是不是⽀付公司通知你String hmac = request.getParameter("hmac");String keyValue = ResourceBundle.getBundle("merchantInfo").getString("keyValue");// ⾃⼰对上⾯数据进⾏加密 --- ⽐较⽀付公司发过来hamcboolean isValid = PaymentUtil.verifyCallback(hmac, p1_MerId, r0_Cmd,r1_Code, r2_TrxId, r3_Amt, r4_Cur, r5_Pid, r6_Order, r7_Uid,r8_MP, r9_BType, keyValue);if (isValid) {// 响应数据有效if (r9_BType.equals("1")) {// 浏览器重定向response.setContentType("text/html;charset=utf-8");response.getWriter().println("<h1>付款成功!等待商城进⼀步操作!等待收货...</h1>"); } else if (r9_BType.equals("2")) {// 服务器点对点 --- ⽀付公司通知你System.out.println("付款成功!");// 修改订单状态为已付款OrderService orderService=new OrderService();orderService.modifyOrderState(p1_MerId);// 回复⽀付公司response.getWriter().print("success");}} else {// 数据⽆效System.out.println("数据被篡改!");}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}⽂件:merchantInfo.properties⼯具类:PaymentUtilpackage com.learning.utils;import java.io.UnsupportedEncodingException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Arrays;public class PaymentUtil {private static String encodingCharset = "UTF-8";/*** ⽣成hmac⽅法** @param p0_Cmd 业务类型* @param p1_MerId 商户编号* @param p2_Order 商户订单号* @param p3_Amt ⽀付⾦额* @param p4_Cur 交易币种* @param p5_Pid 商品名称* @param p6_Pcat 商品种类* @param p7_Pdesc 商品描述* @param p8_Url 商户接收⽀付成功数据的地址* @param p9_SAF 送货地址* @param pa_MP 商户扩展信息* @param pd_FrpId 银⾏编码* @param pr_NeedResponse 应答机制* @param keyValue 商户密钥* @return*/public static String buildHmac(String p0_Cmd,String p1_MerId,String p2_Order, String p3_Amt, String p4_Cur,String p5_Pid, String p6_Pcat,String p7_Pdesc,String p8_Url, String p9_SAF,String pa_MP,String pd_FrpId, String pr_NeedResponse,String keyValue) {StringBuilder sValue = new StringBuilder();// 业务类型sValue.append(p0_Cmd);// 商户编号sValue.append(p1_MerId);// 商户订单号sValue.append(p2_Order);// ⽀付⾦额sValue.append(p3_Amt);// 交易币种sValue.append(p4_Cur);// 商品名称sValue.append(p5_Pid);// 商品种类sValue.append(p6_Pcat);// 商品描述sValue.append(p7_Pdesc);// 商户接收⽀付成功数据的地址sValue.append(p8_Url);// 送货地址sValue.append(p9_SAF);// 商户扩展信息sValue.append(pa_MP);// 银⾏编码sValue.append(pd_FrpId);// 应答机制sValue.append(pr_NeedResponse);return PaymentUtil.hmacSign(sValue.toString(), keyValue);}/*** 返回校验hmac⽅法** @param hmac ⽀付⽹关发来的加密验证码* @param p1_MerId 商户编号* @param r0_Cmd 业务类型* @param r1_Code ⽀付结果* @param r2_TrxId 易宝⽀付交易流⽔号* @param r3_Amt ⽀付⾦额* @param r4_Cur 交易币种* @param r5_Pid 商品名称* @param r6_Order 商户订单号* @param r7_Uid 易宝⽀付会员ID* @param r8_MP 商户扩展信息* @param r9_BType 交易结果返回类型* @param keyValue 密钥* @return*/public static boolean verifyCallback(String hmac, String p1_MerId,String r0_Cmd, String r1_Code, String r2_TrxId, String r3_Amt,String r4_Cur, String r5_Pid, String r6_Order, String r7_Uid,String r8_MP, String r9_BType, String keyValue) {StringBuilder sValue = new StringBuilder();// 商户编号sValue.append(p1_MerId);// 业务类型sValue.append(r0_Cmd);// ⽀付结果sValue.append(r1_Code);// 易宝⽀付交易流⽔号sValue.append(r2_TrxId);// ⽀付⾦额sValue.append(r3_Amt);// 交易币种sValue.append(r4_Cur);// 商品名称sValue.append(r5_Pid);// 商户订单号sValue.append(r6_Order);// 易宝⽀付会员IDsValue.append(r7_Uid);// 商户扩展信息sValue.append(r8_MP);// 交易结果返回类型sValue.append(r9_BType);String sNewString = PaymentUtil.hmacSign(sValue.toString(), keyValue);return sNewString.equals(hmac);}/*** @param aValue* @param aKey* @return*/public static String hmacSign(String aValue, String aKey) {byte k_ipad[] = new byte[64];byte k_opad[] = new byte[64];byte keyb[];byte value[];try {keyb = aKey.getBytes(encodingCharset);value = aValue.getBytes(encodingCharset);} catch (UnsupportedEncodingException e) {keyb = aKey.getBytes();value = aValue.getBytes();}Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);Arrays.fill(k_opad, keyb.length, 64, (byte) 92);for (int i = 0; i < keyb.length; i++) {k_ipad[i] = (byte) (keyb[i] ^ 0x36);k_opad[i] = (byte) (keyb[i] ^ 0x5c);}MessageDigest md = null;try {md = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException e) {return null;}md.update(k_ipad);md.update(value);byte dg[] = md.digest();md.reset();md.update(k_opad);md.update(dg, 0, 16);dg = md.digest();return toHex(dg);}public static String toHex(byte input[]) {if (input == null)return null;StringBuffer output = new StringBuffer(input.length * 2);for (int i = 0; i < input.length; i++) {int current = input[i] & 0xff;if (current < 16)output.append("0");output.append(Integer.toString(current, 16));}return output.toString();}/**** @param args* @param key* @return*/public static String getHmac(String[] args, String key) {if (args == null || args.length == 0) {return (null);}StringBuffer str = new StringBuffer();for (int i = 0; i < args.length; i++) {str.append(args[i]);}return (hmacSign(str.toString(), key));}/*** @param aValue* @return*/public static String digest(String aValue) {aValue = aValue.trim();byte value[];try {value = aValue.getBytes(encodingCharset);} catch (UnsupportedEncodingException e) {value = aValue.getBytes();}MessageDigest md = null;try {md = MessageDigest.getInstance("SHA");} catch (NoSuchAlgorithmException e) {e.printStackTrace();return null;}return toHex(md.digest(value));}// public static void main(String[] args) {// System.out.println(hmacSign("AnnulCard1000043252120080620160450.0http://localhost/SZXpro/callback.asp杩?4564868265473632445648682654736324511","8UPp0KE8sq73zVP370vko7C39403rtK1YwX40Td6irH216036H27Eb12792t")); // }}以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
基于Java代码实现支付充值的通用流程
基于Java代码实现⽀付充值的通⽤流程废话不多说了,直接给⼤家贴java代码了。
具体代码如下所⽰:/*⽀付流程*//****Controller.java 代码如下:*/@RequestMapping(value = "/paySubmit.htm", method = RequestMethod.POST)public ModelAndView paySubmit(HttpServletRequest request,HttpServletResponse response, @RequestParam Map<String, Object> maps){ModelAndView model = new ModelAndView("***/submit");/*** 代码块*/return model;}/*submit.jsp 代码如下:*/<%@ page contentType="text/html;charset=UTF-8" language="java" trimDirectiveWhitespaces="true" %><%@ page import="com.***.util.PayUtil" %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>⽀付</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"></head><body><%request.setCharacterEncoding("UTF-8");String type = (String) request.getAttribute("type");String sHtmlText = "";if ("1".equals(type)){sHtmlText = PayUtil.buildForm((String) request.getAttribute("orderNo"),(String) request.getAttribute("amt"),type);}else{sHtmlText = PayUtil.allInPaybuildForm((String) request.getAttribute("orderNo"),(String) request.getAttribute("amt"),type,request);}out.println(sHtmlText);%></body></html>/* PayUtil.java 代码如下:*//*** ⽣成页⾯数据* @param url 三⽅⽀付的URL* @param sPara* @param strMethod* @return*/public static String buildRequest(String url, Map<String, String> sPara, String strMethod) {ArrayList keys = new ArrayList(sPara.keySet());StringBuffer sbHtml = new StringBuffer();sbHtml.append("<form id=\"paySubForm\" name=\"paySubForm\" action=\"" + url + "\" method=\"" + strMethod + "\">");for(int i = 0; i < keys.size(); ++i) {String name = (String)keys.get(i);String value = (String)sPara.get(name);sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");}sbHtml.append("<input type=\"submit\" name=\"b1\" value=\"确认\" style=\"display:none;\"></form>");sbHtml.append("<script>document.forms[\'paySubForm\'].submit();</script>");return sbHtml.toString();}/*** 以民⽣⽀付为例* @param orderNo* @param amt* @param type* @return*/public static String buildForm(String orderNo, String amt,String type) {//商户编号String merchantid = e_classLoador().getProperty("CMBC.pay.id");//订单编号商户的交易定单号,由商户⽹站⽣成,最⼤长度30String merorderid = orderNo;//⾦额String amountsum = amt;//商品种类String subject = e_classLoador().getProperty("CMBC.pay.type");//"empty";//币种 01 为cnyString currencytype = "01";//⾃动调转取货页⾯0→不跳转;1→跳转String autojump = "1";//跳转等待时间String waittime = "0";//商户取货URLString merurl = e_classLoador().getProperty("CMBC.pay.return.page.url");//是否通知商户: 0→不通知;1→通知String informmer = "1";//商户通知URLString informurl = e_classLoador().getProperty("CMBC.pay.return.notify.url");/*** 商户返回确认: 0→不返回;1→返回*/String confirm = "1";//⽀付银⾏String merbank = "empty";//⽀付类型 0→即时到账;1→担保交易String tradetype = "0";//是否在商户端选择银⾏:0→其他;1→在商户端选择银⾏String bankInput = "0";//接⼝版本String strInterface = "5.00";//备注 (可选) ⽀付备注信息,最⼤长度50String remark = "充值";//⽀付银⾏卡类型 00→借贷混合;01→纯借记String bankcardtype = "00";//商品描述String pdtdnm = "虚拟商品";//商品描述地址String pdtdetailurl = e_classLoador().getProperty("CMBC.pay.return.detail.url");//⽀付密钥(必填): 需在⽀付平台进⾏设置,可登录商户管理系统进⾏维护,⽤于上送商户⽀付及下传⽀付结果加密String MD5key = e_classLoador().getProperty("CMBC.pay.pwd");//拼接加密的源字符串String mac_src="merchantid="+merchantid+"&merorderid="+merorderid+"&amountsum="+amountsum+"&subject="+subject+"¤cytype="+currencytype+"&autojump="+autojump+ "&waittime=" + waittime +"&merurl="+merurl+ "&informmer=" + informmer +"&informurl=" +informurl+ "&confirm=" + confirm + "&merbank=" + merbank+ "&tradetype=" + tradetype + "&bankInput=" + bankInput+ "&interface=" + strInterface + "&bankcardtype=" + bankcardtype+ "&pdtdetailurl=" + pdtdetailurl + "&merkey="+MD5key;String mac = Crypto.GetMessageDigest(mac_src);// 把请求参数打包成mapMap<String, String> sParaTemp = new HashMap<String,String>();sParaTemp.put("merchantid", merchantid);sParaTemp.put("merorderid", merorderid);sParaTemp.put("amountsum", amountsum);sParaTemp.put("subject", subject);sParaTemp.put("currencytype", currencytype);sParaTemp.put("autojump", autojump);sParaTemp.put("waittime", waittime);sParaTemp.put("merurl", merurl);sParaTemp.put("informmer", informmer);sParaTemp.put("informurl", informurl);sParaTemp.put("confirm", confirm);sParaTemp.put("merbank", merbank);sParaTemp.put("tradetype", tradetype);sParaTemp.put("bankInput", bankInput);sParaTemp.put("interface", strInterface);sParaTemp.put("remark", remark);sParaTemp.put("bankcardtype", bankcardtype);sParaTemp.put("pdtdnm", pdtdnm);sParaTemp.put("pdtdetailurl", pdtdetailurl);sParaTemp.put("mac", mac);//建⽴请求String sHtmlText = buildRequest(e_classLoador().getProperty("CMBC.pay.url"), sParaTemp, "post");("McPay request: {}", sHtmlText);return sHtmlText;}/" Crypto.java 代码如下 "/import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;/*** <p>Title: MD5加密算法</p>* <p>Description: 商户不需要进⾏修改</p>* <p>******科技发展公司 2009. All rights reserved.</p>*/public class Crypto {/*** 功能:MD5加密* @param strSrc 加密的源字符串* @return 加密串长度32位*/public static String GetMessageDigest(String strSrc) {MessageDigest md = null;String strDes = null;final String ALGO_MD5 = "MD5";byte[] bt = strSrc.getBytes();try {md = MessageDigest.getInstance(ALGO_MD5);md.update(bt);strDes = bytes2Hex(md.digest());} catch (NoSuchAlgorithmException e) {throw new IllegalStateException("系统不⽀持的MD5算法!");}return strDes;}/*** 将字节数组转为HEX字符串(16进制串)* @param bts 要转换的字节数组* @return 转换后的HEX串*/public static String bytes2Hex(byte[] bts) {String des = "";String tmp = null;for (int i = 0; i < bts.length; i++) {tmp = (Integer.toHexString(bts[i] & 0xFF));if (tmp.length() == 1) {des += "0";}des += tmp;}return des;}}/*** ⽀付返回调⽤url(返回页⾯)* @param session* @param request* @return*/@RequestMapping(value = "/allPayReturn.htm", method = RequestMethod.POST)public ModelAndView allInPayReturnCall(HttpServletRequest request,HttpServletResponse response, @RequestParam Map<String, Object> maps){ModelAndView model = new ModelAndView("***/payReturn");/*** 代码块*/return model;}以上所述是⼩编给⼤家介绍的基于Java代码实现⽀付充值的通⽤流程的相关知识,希望对⼤家有所帮助,如果⼤家有任何疑问请给我留⾔,⼩编会及时回复⼤家的。
JAVA银联支付说明
JA V A银联支付说明一、术语电子商务Electronic Commerce 是指通过信息网络以电子数据信息流通的方式在全世界范围内进行并完成的各种商务活动、交易活动、金融活动和相关的综合服务活动。
网络贸易指在网络平台基础上直接进行在线贸易(Trade Online),利用数字化技术将企业、海关、运输、金融、商检和税务等有关部门有机连接起来,实现从浏览、洽谈、签约、交货到付款等全部或部分业务自动化处理。
网络贸易由信息共享、订购、支付、执行、服务与支持5个部分组成,每个部分在网络贸易中都各自承担了不同的任务B2C(Business to Consumer) 指企业与消费者之间的电子商务。
这是消费者利用因特网直接参与经济活动的形式,类同于商业电子化的零售服务。
目前,在因特网上有许许多多商各种类型的虚拟商店和虚拟企业,提供各种与商品销售有关的服务。
B2B(Business to Business) 指企业与企业间的电子商务。
企业可以使用因特网或其它网络对每笔交易寻找最佳合作伙伴,完成从丁鸥到结算的全部交易行为,包括向供应商订货、签约、接受发票和使用电子资金转移、信用证、银行托收等方式进行付款,以及在商贸过程中发生的其它问题,如索赔,商品发送管理和运输跟踪等。
商户具有电子商务功能的商店和企业银行卡商业银行所发行的储蓄卡、信用卡、储值卡、企业购物卡、购物联名卡、虚拟电子卡等支付工具持卡人银行卡的拥有者网上支付密码数字串。
发卡行用于鉴别网上持卡人身份,具体产生方法、使用范围和管理规范见各发卡行“业务规范”发卡行具有发银行卡功能的商业银行。
开户行指持卡人卡账户或企业资金账户所在的商业银行SSL(Source Socket Layer) 是一种基于网络传输层的安全网络传输协议,实现客户端与服务端间的数据安全传输二、订单签名函数1、JA V A语言方法说明:方法说明:Public String signOrder(String MerId, String OrId, String TransAmt, String CuryId, String TransDate, String TransType)参数说明:String MerId --商户编号,长度为15个字节的数字串,由ChinaPay或清算银行分配。
java支付宝支付文档(含代码)
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*说明:*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
支付宝app支付java后台流程demo
⽀付宝app⽀付java后台流程demo 使⽤ssm框架实现⽀付宝⽀付功能。
⽀付宝测试环境代码测试源代码https:///OUYANGSIHAI/sihai-maven-ssm-alipay1.下载电脑⽹站的官⽅demo:下载:https:///270/106291/2.下载解压导⼊eclipsereadme.txt请好好看⼀下。
只有⼀个Java配置类,其余都是JSP。
3.配置AlipayConfig(1) 注册蚂蚁⾦服开发者账号(免费,不像苹果会收取费⽤)注册地址:https:// ,⽤你的⽀付宝账号扫码登录(2) 设置app_id和gatewayUrl其中密钥需要⾃⼰⽣成,appID和⽀付宝⽹关是已经给好的,⽹关有dev字样,表明是⽤于开发测试。
点那个设置可以下载⽣成公钥注意部分:点击上图的⽣成⽅法下载跟你系统对⽤的程序,然后⽣成相应的密匙如果没有设置过,此时显⽰⽂本是"设置应⽤公钥",我这⾥是已经设置过得。
下⼀步:查看你的公钥把公钥的字符串复制过去ide AlipayConfig.java ⾥⾯以上的步骤基本上是完成搭建测试⽤的DEMO 仅此⽽已;如果是正式环境,需要上传到对应的应⽤中:基本开发⽂档全部可以在这⾥看⾃⼰可以梳理流程SSM+alipay源代码下载链接: https:///s/1n6GbEJiMzoGWJrSw0bb2Cg 密码: zd9e将⽀付宝⽀付整合到ssm框架1、项⽬架构项⽬架构:spring+springmvc+mybatis数据库:mysql部署环境:tomcat7.0开发环境:jdk8、idea⽀付:⽀付宝、微信整合到ssm⼀样,我们需要像沙箱测试环境⼀样,需要修改⽀付的配置信息2、数据库代码主要包括以下的数据库表:user:⽤户表order:⽀付产⽣的订单flow:流⽔账product:商品表:⽤于模拟购买商品。
drop table if exists user;/*==============================================================*//* Table: user *//*==============================================================*/create table user(id varchar(20) not null,username varchar(128),sex varchar(20),primary key (id));alter table user comment '⽤户表';CREATE TABLE `flow` (`id` varchar(20) NOT NULL,`flow_num` varchar(20) DEFAULT NULL COMMENT '流⽔号',`order_num` varchar(20) DEFAULT NULL COMMENT '订单号',`product_id` varchar(20) DEFAULT NULL COMMENT '产品主键ID',`paid_amount` varchar(11) DEFAULT NULL COMMENT '⽀付⾦额',`paid_method` int(11) DEFAULT NULL COMMENT '⽀付⽅式\r\n 1:⽀付宝\r\n 2:微信',`buy_counts` int(11) DEFAULT NULL COMMENT '购买个数',`create_time` datetime DEFAULT NULL COMMENT '创建时间',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流⽔表';CREATE TABLE `orders` (`id` varchar(20) NOT NULL,`order_num` varchar(20) DEFAULT NULL COMMENT '订单号',`order_status` varchar(20) DEFAULT NULL COMMENT '订单状态\r\n 10:待付款\r\n 20:已付款',`order_amount` varchar(11) DEFAULT NULL COMMENT '订单⾦额',`paid_amount` varchar(11) DEFAULT NULL COMMENT '实际⽀付⾦额',`product_id` varchar(20) DEFAULT NULL COMMENT '产品表外键ID',`buy_counts` int(11) DEFAULT NULL COMMENT '产品购买的个数',`create_time` datetime DEFAULT NULL COMMENT '订单创建时间',`paid_time` datetime DEFAULT NULL COMMENT '⽀付时间',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';CREATE TABLE `product` (`id` varchar(20) NOT NULL,`name` varchar(20) DEFAULT NULL COMMENT '产品名称',`price` varchar(11) DEFAULT NULL COMMENT '价格',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产品表 ';3、dao数据接⼝层这⾥就不介绍了,这个只包括简单的curd,可以使⽤`通⽤mapper`,或者`逆向⼯程`就⾏。
JAVA对接阿里扫码支付接口整理笔记
JAVA对接阿⾥扫码⽀付接⼝整理笔记注册沙箱账号根据情况选择接⼊⽅式,我们这⾥选择⾃研开发者,如果已经注册过的省略。
选择 开发服务 --> 研发服务 --> 沙箱,进⼊沙箱管理界⾯。
进⼊沙箱,第⼀次需要填写信息,记下appId,公钥设置处需要把下⾯步骤⽣成的公钥设置到这⾥。
⽣成公私秘钥下载相应的⼯具。
打开下载的⼯具,运⾏程序,选择 JAVA 2048 ⽅式,点击⽣成秘钥。
把此处⽣成的公钥复制设置到沙箱环境,就是上⾯的设置公钥配置,然后把公私秘钥保存起来,以备后⽤。
添加依赖添加项⽬依赖,主要是引⼊ alipay-sdk-java,提供⽀付宝⽀付⽀持。
pom.xml:配置信息⽂件因技术问题,暂且将相关信息以死值固定。
⽀付宝⽀付接⼝封装AlipayUtil是对⽀付宝⽀付功能的封装。
AlipayUtil.java:@Componentpublic class AlipayUtil {/*** ⽀付接⼝** @param alipayBean* @return* @throws AlipayApiException*/public String pay(AlipayBean alipayBean) throws AlipayApiException {// 1、获得初始化的AlipayClientString serverUrl = PropertiesConfig.GATEWAY_URL;String appId = PropertiesConfig.APP_ID;String privateKey = PropertiesConfig.PRIVARY_KEY;String format = "json";String charset = PropertiesConfig.CHARSET;String alipayPublicKey = PropertiesConfig.PUBLIC_KEY;String signType = PropertiesConfig.SIGN_TYPE;String returnUrl = PropertiesConfig.RETURN_URL;String notifyUrl = PropertiesConfig.NOTIFY_URL;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、请求⽀付宝进⾏付款,并获取⽀付结果(报500,有问题)// String result = alipayClient.pageExecute(alipayRequest).getBody(); //调⽤SDK⽣成表单//通过以下代码进⾏提交请求会默认返回请求url字符串(返回url,打开跳转⽀付宝⽀付页⾯)String result = alipayClient.pageExecute(alipayRequest, "GET").getBody();//扫⼆维码⽀付(将response的qr_code制作成⼆维码)//创建API对应的request类// AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest ();// request.setNotifyUrl(":80/order/aliPayCallBack.do");// request . setBizContent ( "{" +// "'out_trade_no':'"+alipayBean.getOut_trade_no()+"'," + //商户订单号// "\"total_amount\":'"+alipayBean.getTotal_amount()+"'," +// "\"subject\":'"+alipayBean.getSubject()+"'," +// "\"store_id\":\"NJ_001\"," +// "\"timeout_express\":'"+alipayBean.getTimeout_express()+"'}" ); //订单允许的最晚付款时间// AlipayTradePrecreateResponse response = alipayClient.execute (request);// //制作⼆维码// String body = response.getBody();// JSONObject jsonObject = JSONObject.fromObject(body);// String qr_code = jsonObject.getJSONObject("alipay_trade_precreate_response").getString("qr_code");// 返回付款信息return result;}}接⼝调⽤参数封装对象如下。
Springboot整合支付宝支付功能
Springboot整合⽀付宝⽀付功能1.需要的Maven依赖// ⽀付宝<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.8.73.ALL</version></dependency>2.controller层/*** 统⼀下单接⼝* @param orderNo 订单号* @param request* @return*/@PostMapping("/unifiedOrder")@CrossOrigin(origins = "*",maxAge = 3600)//跨域public ResultMap unifiedOrder(@RequestParam("orderNo") String orderNo,@RequestParam("payType") Integer payType,HttpServletRequest request){try {// 1、验证订单是否存在// 2、开始微信⽀付统⼀下单Orders orders = ordersService.FindOrder(orderNo);ResultMap resultMap =null;if(orders!=null){if(payType==1){String spbill_create_ip = getIpAddr(request);resultMap = wxPayService.unifiedOrder(orders.getOrderNo(),orders.getTotalPrice(),"云App",spbill_create_ip);Hotel hotel= hotelMapper.selHotelById(orders.getHId());Note note=new Note();String s=note.Notefs(hotel.getPhone(),1);ordersService.updataorderpaytype(orders.getOrderNo(),payType);return resultMap;}else if(payType==2){// 2、创建⽀付宝订单String orderStr = alipayService.createOrder(orders.getOrderNo(), orders.getTotalPrice(),"App");ordersService.updataorderpaytype(orders.getOrderNo(),payType);return ResultMap.ok().put("data",orderStr);}}return resultMap;//系统通⽤的返回结果集} catch (Exception e) {e.printStackTrace();System.out.println(e.getMessage());return ResultMap.error("服务器异常,付款失败");}}//这是⽀付宝异步回调函数/*** ⽀付异步通知* 接收到异步通知并验签通过后,⼀定要检查通知内容,* 包括通知中的app_id、out_trade_no、total_amount是否与请求中的⼀致,并根据trade_status进⾏后续业务处理。
- 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*说明:*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。