精华内容
下载资源
问答
  • 付条怎么写
    千次阅读
    2020-11-25 11:18:34

    代码就是程序员用开发工具所支持的语言写出来的源文件,是一组由字符、符号或信号码元以离散形式表示信息的明确的规则体系。代码写作费时费力,找代写是个不错的选择。接下来我们就来看看代写代码一般多少钱。

    6-1PF515461BE.png

    一、代写代码一般多少钱

    程序类型

    行数

    价格

    完成时间

    C#代码

    300行

    700元

    3天

    C++代码

    300行

    600元

    3天

    PHP代码

    400行

    700元

    4天

    Java代码

    400行

    900元

    4天

    android代码

    100行

    300元

    2天

    Python代码

    200行

    500元

    5天

    VB代码

    200行

    400元

    3天

    asp代码

    300行

    600元

    3天

    MATLAB代码

    200行

    500元

    3天

    .NET代码

    300行

    600元

    5天

    单片机代码

    100行

    300元

    2天

    二、代写代码流程

    1、提交代写需求: 首先,请提交您的代写需求。 提供具体要求,这些要求包括代码类型、代码行数、实现功能、专业级别,完成时间,以及相关的资料(有些单位或专业有具体的附件要求,比如要基于提供的数据表格进行分析,或对其公司资料进行分析等),只有拿到具体的要求,报价才是最终报价,提交订单的时候没有提供这些资料,那报价只能作为初步报价。

    2、报价: 您提交具体代码需求后,我们将在半小时内给您报价。

    3、支付定金,发信息确认,开始写作代码: 支付定金后,请立即发送支付凭证并通知我们查款,以便及时开始写作。

    4、拟定代码写作思路: 付款后,我们通常会在1天内完成代码撰写思路。

    5、完稿付尾款。 完成代码的设计,进行在线演示,确认符合写作要求,验收通过付尾款。

    6、需要修改的代码,请尽快发来,我们会在第一时间进行修改,直至通过。

    三、代写代码如何防骗

    第一,中介骗子。淘宝上有一些店铺以低价的方式吸引客户,随意拼凑代码,或使用一些其他论文上的现成代码,让客户先好评再收代码,客户拿到的代码基本上不能用。

    第二,超低价格。无论本科还是硕士,代码代做通常是300元起步,如果低于这个水平,要么是程序员献爱心,要么就是非专业人员,而大多数是后者,非专业人员一般会骗取定金,或者从网上东拼西凑给你一段代码,无法实现具体功能。所以不要为了图便宜上当受骗,程序员不是大白菜,简单的程序代码也差不多有100行,程序员根据主题写代码,调试,运行,整套流程下来,顺利的话也需要半天,如果遇到bug,那就是好几天。程序员日工资为500元左右,你们自己算算,一段简单的代码程序需要多少时间成本。

    第三,不合理流程。全款必骗。索要信息者,危险。说一个比较正常的流程吧,基本是微信、QQ沟通,买方提供要求,写手获取需要的信息后,付定金,3-5天提供代码,查看代码运行演示,满足要求付尾款。

    第四,不限定代做范围。如果一个代做机构不问具体要求,就满口说自己什么代码都能代做,也要注意了,因为一些专业性极强、难度高的代码程序,不一定能找到专业的写手,所以如果在你还没有给出具体的代做要求前,就告知你什么都可以代做的,要谨慎了。

    四、如何选择靠谱的代写代码公司?

    1、先看公司网站

    公司网站是一个公司的门面,如果您看到的代写公司的网站,页面粗糙,颜色搭配不协调,线条粗细不均,甚至有页面乱码的现象,基本就可以判定这家公司的实力。很难相信一个对自己门面都不在乎的公司,会对您的代写要求以及细节精益求精。

    2、看公司的创始人团队

    由于代写行业在我国尚属于初创期,行业中泥沙俱下。一些小作坊甚至建个网站,拉根网线就开张了。如果选择这样的公司,专业性就很难得到保证。

    3、看有无成功案例

    如果您在代写公司的网站上看不到成功案例,看不到代写前后对比变化。那您怎么会相信这家公司的实力呢?

    “代写代码一般多少钱”就为你介绍到这里,如需了解更多代写代码相关知识,详情点击以下链接。

    相关内容补充:

    更多相关内容
  • C#爬虫基础 分析网页一个爬去网络小说的程序(完整代码)-附件资源
  • 皇叔,听说你了三本畅销书赚了几百万?哎?我怎么不知道我赚了这么多,不够你能给我补补? 前年有粉丝得知我北京买房了,说你书赚那么多啊,我心里纳闷,这房子2016年买的,第一本书是在2017年出版的,我又没有...

    视频版本
    视频版本,欢迎大家去B站三连~
    http://liuwangshu.cn/show/book-money.html

    皇叔,听说你写了三本畅销书赚了几百万?哎?我怎么不知道我赚了这么多,不够你能给我补补?
    前年有粉丝得知我北京买房了,说你写书赚那么多啊,我心里纳闷,这房子2016年买的,第一本书是在2017年出版的,我又没有时光机。
    今年我又买了辆奔驰,又有群友说,大家赶紧买书啊,助力皇叔换玛莎拉蒂。嗯,助力我买个模型玛莎拉蒂还是可以的。
    最近联系了一个前同事,他在阿里上班,问我是不是全职写书呢?写一本赚了得有一百万吧。我要是全职写,坟头草估计都一人高了。

    看起来,很多人对写技术书是有误解的,认为只要是写书就赚钱。不少人一看书的定价,比如99元,就以为买了一本,作者赚了99,那卖1万本作者不就是赚百万了,作者真是乐死了,那叫出版社和印刷厂情何以堪?
    今天就和大家普及下写书到底赚多少,以及写书后会遇到什么,供后来者参考学习。

    写一本技术畅销书到底赚多少

    一般来说能卖到1万册的就算技术畅销书。什么?你说一万册卖的太少?现实是一万人买正版书,五万人看盗版pdf,你说“卖”的多不多呢?

    技术书不能跟大众所读的一些小说和励志图书相比,毕竟技术书的受众群体相对来说少太多了,而且技术分支又很多。技术书总体分为入门书和进阶书,一般情况下都是入门书比较好卖,如果一本进阶书能卖一万册那算是销量非常不错了。
    如果你在正规出版社出版一本书到底能赚多少呢?
    首先我们来了解稿酬的计算方式,稿酬主要有两种支付形式,一种是买断,一种是版税。
    买断就是出一个价格直接买走你的书的版权,以后这本书热卖多少册,和作者无关。这种买断的形式不是很常见。
    版税指出版社以图书定价卖出数量版税率的方式向作者付稿酬。这具体又分统一版税和阶梯版税两种。
    统一版税很好说,就是不管这本书卖多少,都是统一的版税率。比如我的第一本书定价89,版税就是8%,卖了1万多册,那么收入就是89*8%*10000=7.12万,然后还得纳10%左右的税,到手也就6万出头。

    阶梯版税就是卖出多少本以后,版税率会上浮,比如卖出3000本之前的版税率为8%,3000本之后的版税为9%,我的第二本和第三本书都是采用的阶梯版税的计算方式,但大家也看到了,一般上涨的版税率都很低,几乎都可以忽略不计。
    那么按照现在的算法,我写的三本畅销书不是赚了几百万,而是二十万就不错了。付出的代价也是惨烈的,用了四年的几乎所有的上班后的业余时间写的,身体变差了不说,熬夜写书从140斤胖成了170斤,从帅小伙变成了现在的土肥圆。如果按照金钱的角度来说,写技术书,尤其是写小众技术书是付出和回报最不成正比的事了。如果你想赚钱,去接私活、写付费专栏、录课都比写书要强很多。那么写书能带给我们带来什么好处呢?

    写畅销书的好处

    嗯,常规的大家都知道的好处我就不多说了,比如提升技术啊,提升写作啊,就说说大家可能不知道的一些事吧。
    第一个,也就是很多想写书的人最关心的问题,找工作总体确实比以前更好找了,但面试呈现两级分化。
    就是相信你的基本也不问啥技术了,聊聊家常,扯扯淡就进去了。不相信你的,那就是啥都问你,别人面试一小时,你得面试两小时,他们的内心OS是:你不是写书了吗?你不是牛逼吗?那我得好好的打压下你,让你难堪,而且这个不是个例,是一个非常普遍的现象。我就记得有一次我去一个大型公司面试,技术VP还不忘嘲讽我,说你这么牛逼怎么不去谷歌呢?

    第二个,就是会收到一些大厂的面试或者加盟邀请,比如阿里、头条、平安等公司的技术leader会找我过去聊聊,甚至还有一些认可我的人直接邀请我加盟他们公司,比如华为鸿蒙的一个带百人以上团队的负责人,看了我的第二本书,很认可我的实力,通过我的公号找到了我,邀请我加盟他们。

    第三个,会收到一些技术大会的演讲邀请,这个以前是很难有机会参加的,技术演讲会锻炼自己的演讲水平,也许一开始你会觉得紧张,但一旦你跨出了这一步,你会发现,其实演讲并不是那么难,演讲这一技能在很多领域都是杀手锏,得到这一技能能让你如虎添翼。

    第四个,加强个人IP,增加了个人副业发展的机会,使你的眼界不在局限于工作。大家都知道,公司毕竟不是家,拉屎不方便不说,到了岁数还容易被保安拖出去,但是如果你写出了畅销书,那么这本书就是你的背书,你无需再依靠公司的光环,甚至无需公司给你的工资,因为你本身就有能力成为一家小型公司,自给自足。

    第五个,建立行业影响力,书一旦畅销,在行业中一定是有影响力的,一本书的销售周期大概是三年,如果书的内容不易过时,那么销售周期会达到5到10年之久,好似酒香一样,气味绵延持续时间很长,闻香者络绎不觉,不断的加强的你的影响力。拿我举例,我的三本书都是畅销书,并且一直持续再卖,那么影响力就是持续叠加的,最近我就凭借在行业中的影响力获得了TVP(腾讯云最具价值专家),这个是被整个技术界认可的认证,里面有很多技术界公认的大佬,比如:池建强(极客邦科技总裁)、惠新宸(贝壳找房副总裁)、左耳朵陈皓等等。

    第六个,能够更好的和自己进行独处,得到别人得不到的感悟,能接触到形形色色的人,更好的了解人性,如果利用好了,内心也会被锻炼的异常强大。这个后面我会进行说明。

    第七个,就是找女友相对好找了,理由不言而喻,如果你想要找到更优质的女朋友,写一本畅销书会助力你不少。我的一任前女友就是这样,当时我甚至还没出书,她就是再网上看到我写的博客,对我是大增好感,见了两次面后,就成了。
    这七条总结出一句话就是,写出一本技术畅销书会给你带来很多机会,使你的命运从此改变。值不值200万呢?我想每个人都会有不同的答案。

    写畅销书后所要面对的

    写出畅销书后,表面是风光的,但多多少少会接触到一些阴暗的事。每个畅销书作者都或多或少的见识过,只不过没有必要跟大家说,因为说这个,很少有人会理解,还容易被说矫情,但我就无所谓了,我也不怕别人怎么说我,因为已经受过三年的“特训”了。
    很多技术博主说写文章会被喷,这一点很普遍,因此也劝退了一些技术博主,在写书之前我被喷的很少,虽然我的技术博客访问量那时已经接近200万,但是我第一本书出版时,却收到了很多人的私信,言语像是刨了他家祖坟般的难听,我当时很是诧异,我想写书是为了普及技术,书本身质量就算不好,那也绝对不至于当我刨了他家祖坟,为何会受到如此待遇呢?后来我明白了,是因为我冒头了,这就是螃蟹理论,不知道螃蟹理论的可以查查。当然,喷你算是轻的,还有黑你的,在各个技术群,还有一些平台里造谣诋毁,这就说明,你要火了!
    写书这三四年我被喷被诋毁的次数,是我这前30年的几倍之多,本身我逆商就不低,这经历更锻炼出我强大的内心和心里素质,提前变得更成熟,更加明确自己要什么。被黑被诋毁,这是一把双刃剑,利用好了,可以转化为动力,会促进你更加成长,比如我就是在完成第一本书后,马不停蹄的又出了两本技术畅销书,喷我黑我的人就少了,原因是我已经是爬出来的螃蟹了,攻击根本伤害不到我,反而还会转为我的动力,另一方面黑我实际上又是为我免费做宣传,我想但凡有点脑子的黑子都不想看到这一情况。

    所以方才在前面也说了,写一本畅销书的好处是有机会让你更加了解人性,内心变得异常强大。

    今天说的事比较冷门,不过可以普及下写书的一些事,甚至可以帮助那些想要写技术书的人,提前搭建好心理建设,那就是有意义的。

    如果想获得更多的内容,可以关注我的博客: liuwangshu.cn/

    我的公号:后厂技术官
    在这里插入图片描述

    展开全文
  • 昨晚一个朋友让我帮忙 sql, 说是有一张订单表, 要查询出每天有多少人下单, 有多少人付款。听到这里可能很多人以为用 group by 分组, count 和 sum统计函数,问题就解决了。例如: select 下单时间,count...

    写在前面

    昨晚一个朋友让我帮忙写一条 sql, 说是有一张订单表, 要查询出每天有多少人下单, 有多少人付款。听到这里可能很多人以为用 group by 分组, count 和 sum统计函数,问题就解决了。例如:

    select 下单时间,count(下单时间)as 订单数量, sum(付款金额) as 实付金额 from 订单表 group by 下单时间
    
    
    

    但是我们要考虑的是,用户有可能今天下订单,但是到第二天或者第三天才付款。这个时候这条订单的付款数据 要算到 第二天或者第三天去。有可能因为我的表达有问题,有的人没听懂,下面就贴出详细过程。


    解决过程

    1. 创建表

    根据他的描述,我临时建了一张表。 当然,实际的订单表很复杂, 为了简化并突出重点,我只抽出了其中几个字段,字段名和类型也是随便写的。表结构如下:

    CREATE TABLE `tb_order` (
      `id` varchar(32) NOT NULL DEFAULT '', --  id
      `status` varchar(20) DEFAULT NULL,   -- 订单状态
      `createtime` datetime DEFAULT NULL,  -- 订单创建时间
      `paytime` datetime DEFAULT NULL,     -- 订单支付时间
      `total` decimal(10,0) DEFAULT NULL,  -- 订单支付金额
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
    
    

    2. 插入数据

    插入的数据要涵盖实际生产的所有情况,这里总共插入了 8 条订单数据, 下单日期为 2019-03-11 至 2019-03-15 五天的数据。订单类型有

    1. 当天下单 并 当天付款的

    2. 当天下单 但 一直未付款的

    3. 当天下单 但 第二天才付款的

    INSERT INTO `tb_order` VALUES ('1', '1', '2019-03-11 21:44:18', NULL, 100);
    INSERT INTO `tb_order` VALUES ('2', '2', '2019-03-12 21:44:46', '2019-03-12 21:45:12', 200);
    INSERT INTO `tb_order` VALUES ('3', '2', '2019-03-13 21:45:27', '2019-03-13 21:45:32', 120);
    INSERT INTO `tb_order` VALUES ('4', '2', '2019-03-14 21:45:49', '2019-03-14 21:46:50', 50);
    INSERT INTO `tb_order` VALUES ('5', '1', '2019-03-15 21:46:14', NULL, 60);
    INSERT INTO `tb_order` VALUES ('6', '2', '2019-03-11 21:53:36', '2019-03-12 21:53:42', 100);
    INSERT INTO `tb_order` VALUES ('7', '2', '2019-03-15 21:56:11', '2019-03-15 21:56:15', 60);
    INSERT INTO `tb_order` VALUES ('8', '2', '2019-03-12 21:57:31', '2019-03-12 21:57:37', 100);
    
    
    

    3. 数据展示

    4. 分析

    根据我们的问题, 我们先找出几个关键字, 根据 “每天” 我们想到了用 group by 对下单时间进行分组 ,然后我们需要查询出来的字段有 “下单时间”, ”下单数量“,”付款金额“。但是我们上面说了,付款金额这个字段比较难查,我们暂时先忽略这个字段,于是就有了下面的 sql

    select t.createtime, count(t.createtime) as '下单数量'
        from tb_order t 
    group by DATE_FORMAT(t.createtime,'%Y-%m-%d');
    
    
    

    此时我们的任务完成了三分之一,接下来我们只查询出每天订单的 ‘实付金额’, sql 如下:

    select paytime, sum(total)as '实付金额' from tb_order group by DATE_FORMAT(paytime,'%Y-%m-%d');
    
    
    

    到这里,任务只能说完成了三分之二,因为我们需要同时查出来‘ 订单数’ 和 ‘实付金额’ 这两个字段。既然我们能通过对同一张表分开查的方法实现我们的需求,那么我们对同一张表进行表关联是不是就可以同时查出两个字段了 ?答案是 yes 。下面是完整的 sql:

    SELECT t.createtime, COUNT(t.createtime) AS '下单数量', t1.tol AS '实付金额' FROM tb_order t 
    LEFT JOIN
        (
    	    SELECT paytime, SUM(total) AS tol FROM tb_order 
    	        WHERE `status`='2'    
    	    GROUP BY DATE_FORMAT(paytime,'%Y-%m-%d')
        ) t1 
    ON DATE_FORMAT(t1.paytime,'%Y-%m-%d')=DATE_FORMAT(t.createtime,'%Y-%m-%d')
    GROUP BY DATE_FORMAT(t.createtime,'%Y-%m-%d')
    
    
    

    5. 执行结果


    总结

    当我们不能从同一张表同时查询出这两个字段,但是我们可以分开查的时候,可以尝试用关联表,上面最终的 sql 很简单,把我们分析过程的 第一步 和 第二步 的 sql,用一个 left join 连接起来,最后加上下面的条件,就解决了当天下单,隔天付款的情况。

    ON DATE_FORMAT(t1.paytime,'%Y-%m-%d')=DATE_FORMAT(t.createtime,'%Y-%m-%d')
    
    

    转载于:https://my.oschina.net/u/3984985/blog/3023322

    展开全文
  • 支付宝 当面(扫描支付) 对接逻辑 这两天给网站 博客下方添加了 打赏功能 使用的是 支付宝的 当面功能 特此记录一下,觉得不错的可以在下方打赏 嘿嘿 ,下面先来看一下效果图。 1.当面产品介绍 支付宝...

    支付宝 当面付(扫描支付) 对接逻辑

    这两天给网站 博客下方添加了 打赏功能 使用的是 支付宝的 当面付功能 特此记录一下,觉得不错的可以在下方打赏 嘿嘿 ,下面先来看一下效果图。

    image-20210426232134924

    1.当面付产品介绍

    支付宝当面付产品官网介绍

    本篇主要介绍 扫码支付

    当面付帮助商家在线下消费场景中实现快速收款,支持 条码支付扫码支付 两种付款方式。商家可通过以下两种任一方式进行收款,提升收银效率,实现资金实时到账

    • 条码支付:买家出示支付宝钱包中的条码、二维码,商家扫描用户条码即可完成 条码支付 收款。
    • 扫码支付:买家通过使用支付宝 扫一扫 功能,扫描商家收款二维码即可完成 扫码支付 付款。

    2.扫码支付应用场景

    适用于单件商品单独定价、无人值守自助售货机 打赏等商家。用户打开支付宝中的 扫一扫 功能,扫描商家展示的二维码进行支付。该模式适用于线下实体店支付、面对面支付、自助售货机等场景。

    image-20210426232434270

    3.准入条件 (商家想用该功能的条件)

    需要有营业执照和门头照片,门头照片可以网上随便找一个上传上去, 营业执照需要和商家账户名相同 ,本人是没有的 ,所以大概 30天后 就无法使用了。。

    • 该能力对企业支付宝账户和个体工商户开放。

    • 商家的收银系统需要有红外扫描枪设备,或其他的扫码、展示码设备。

    • 签约申请提交资料:

      • 经营场所照片。

        • 有门头照的经营场所,需提供门头照。
        • 无门头照的经营场所,需提供内景照或场景照。
      • 同名的营业执照(即与支付宝账户认证名称一致)。

        • 您可以在支付宝 PC 端登录 商家中心,进入 产品签约管理,通过资质凭证补全来恢复产品的正常使用。

          账户类型收款额度规则入驻资质要求(页面需要填写)使用时间
          个人账户单笔收款 ≤ 500元,单日收款 ≤ 5000元,不区分借记或贷记渠道。1、需按规范提交经营场景照片(如门头照、门店地址);2、提供本人同名营业执照。30天。如提交资料均不通过,商家需要在合约生效后的30天内补全门头照等资料,否则会影响正常收款温馨提示:当使用时间到期(从合约生效开始计算 30天)系统会在到期前 15 天和 3 天发出代办通知,30 天到期,为了更好的产品使用体验,建议您及时补全资质)。
          个人账户收款不受限额。1、需按规范提交经营场景照片(如门头照、门店地址);2、提供本人同名营业执照。若提交资料均通过,收款不受限。
          企业账户收款不受限额。
        -   若签约时提供了同名营业执照,或者签约后补充了同名营业执照,商家收款无限额。

    4.接入准备

    需要获取 以下参数供 后续调用接口:

    APPID :通过创建应用后 应用头像下发的 202100xxxxx 这个就是APPID

    应用私钥: 通过密钥在线生成器 可以直接生成

    应用公钥: 通过密钥在线生成器 可以直接生成

    支付宝公钥: 这个要注意,是通过 上面的应用公钥 去换取的 ,在应用 开发信息 -》 接口加签方式 -》设置

    4.1 创建应用

    登录 支付宝开放平台,创建应用并提交审核,审核通过后会生成应用唯一标识 APPID,并且可以申请开通开放产品使用权限。通过 APPID 应用才能调用开放产品的接口能力。详情请参考 创建应用

    image-20210426233500081

    4.2 配置应用

    应用创建完成后,系统会自动跳转到应用详情页面。您可以在 能力列表 中点击 添加能力 来添加 当面付 功能

    image-20210426233407440

    4.3 设置接口加签方式

    在 应用 -》开发信息 -》 接口加签方式 -》设置

    支付宝开放平台的应用管理体系,使用了公私钥的机制,商户可通过设置接口加签方式为自身应用配置 公私钥/公私钥证书 来保障商户应用和支付宝交互的安全性。密钥的获取方式请参见 生成密钥 可以选择Web在线生成方式

    image-20210426233924123

    公钥证书与公钥的区别请参见 普通公钥与公钥证书区别

    填入 上面在线生成的 公钥字符 点击保存设置

    image-20210426234027959

    通过应用公钥 换取 支付宝公钥 这个后面调用接口是有用的

    image-20210426234109273

    4.4 上线应用

    商户在添加功能和配置密钥后,即可将应用提交审核,预计会有一个工作日的审核时间,请耐心等待,详细步骤可参考 上线应用

    应用上线后,还需要完成应用签约才能在线上环境(生产环境)使用当面付功能。

    image-20210426235255354

    4.5 签约 当面付

    这个也很重要 必须签约后 才能使用

    当面付 需要签约 上传 门头照片 和 营业执照 ,门头照片可以网上随便找一个无水印的, 营业执照可以暂时不传,不传大概可以使用30天

    签约完成后 应用部分会多出一个 应用2.0签约xxxxx 自动生成的

    image-20210426233330970

    当上面的接入准备都做完后 即可获得 以下几个数据

    APPID :通过创建应用后 应用头像下发的 202100xxxxx 这个就是APPID

    应用私钥: 通过密钥在线生成器 可以直接生成

    应用公钥: 通过密钥在线生成器 可以直接生成

    支付宝公钥: 这个要注意,是通过 上面的应用公钥 去换取的 ,在应用 开发信息 -》 接口加签方式 -》设置

    5.扫码支付 逻辑

    当面付扫描支付逻辑

    来看看 支付宝提供的 接入流程图

    开发者需要确认自己的应用在审核通过后显示 已上线,同时完成当面付功能的签约后,才能顺利调用以下接口。否则会有缺少权限的报错。

    image-20210426235207462

    调用流程

    image-20210426235331071

    1. 后台 调用 支付宝的 预下单请求(可以设置二维码过期时间) 获取二维码
    2. 后台将二维码 生成图片 返回给 前端
    3. 用户进行扫码 支付完成后 可以通过配置 支付成功异步调用接口,或者后台自主轮训查询接口 来判断是否支付完成
    4. 如果二维码过期或者 在指定时间内 用户未支付 调用 cancel 接口去 撤销关闭交易
    5. 当面付推荐使用 自主轮训查询,我这里使用的异步通知接口 为了尝试看看
    1. 商户系统调用 alipay.trade.precreate(统一收单线下交易预创建)接口,获得该订单的二维码串 qr_code,开发者需要利用二维码生成工具获得最终的订单二维码图片;
    2. 发起轮询获得支付结果:等待 5 秒后调用 alipay.trade.query(统一收单线下交易查询)接口,通过支付时传入的商户订单号(out_trade_no)查询支付结果(返回参数 TRADE_STATUS),如果仍然返回等待用户付款(WAIT_BUYER_PAY),则再次等待 5 秒后继续查询,直到返回确切的支付结果(成功 TRADE_SUCCESS 或 已撤销关闭 TRADE_CLOSED),或是超出轮询时间。在最后一次查询仍然返回等待用户付款的情况下,必须立即调用 alipay.trade.cancel(统一收单交易撤销接口)将这笔交易撤销,避免用户继续支付;
    3. 除了主动轮询,当订单支付成功时,商户也可以通过设置异步通知(notify_url)来获得支付宝服务端返回的支付结果,详见 扫码异步通知,注意一定要对异步通知验签,确保通知是支付宝发出的。

    6. 服务端 SDK (新版) 简述

    服务端的新版SDK 连接

    支付宝提供了 2种 SDK 一个是老版本 一个是新版本,我把两个都试了下,这里我选用 新版来介绍和使用,新版主要使用 Factory 类

    image-20210427000048152

    POM 引入 新版sdk alipay-easysdk

           <!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-easysdk -->
            <dependency>
                <groupId>com.alipay.sdk</groupId>
                <artifactId>alipay-easysdk</artifactId>
                <version>2.1.2</version>
            </dependency>

    调用示例

    仔细看看 示例没啥难的,需要注意的是 alipayPublicKey = 支付宝公钥,不是应用公钥,就是上面拿应用公钥去换取的 支付宝公钥, 我这里使用的 非正书模式

    import com.alipay.easysdk.factory.Factory;
    import com.alipay.easysdk.factory.Factory.Payment;
    import com.alipay.easysdk.kernel.Config;
    import com.alipay.easysdk.kernel.util.ResponseChecker;
    import com.alipay.easysdk.payment.facetoface.models.AlipayTradePrecreateResponse;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            // 1. 设置参数(全局只需设置一次)
            Factory.setOptions(getOptions());
            try {
                // 2. 发起API调用(以创建当面付收款二维码为例)
                AlipayTradePrecreateResponse response = Payment.FaceToFace()
                        .preCreate("Apple iPhone11 128G", "2234567890", "5799.00");
                // 3. 处理响应或异常
                if (ResponseChecker.success(response)) {
                    System.out.println("调用成功");
                } else {
                    System.err.println("调用失败,原因:" + response.msg + "," + response.subMsg);
                }
            } catch (Exception e) {
                System.err.println("调用遭遇异常,原因:" + e.getMessage());
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    
        private static Config getOptions() {
            Config config = new Config();
            config.protocol = "https";
            config.gatewayHost = "openapi.alipay.com";
            config.signType = "RSA2";
    
            config.appId = "<-- 请填写您的AppId,例如:2019091767145019 -->";
    
            // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
            config.merchantPrivateKey = "<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->";
    
            //注:证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径,优先从文件系统中加载,加载失败后会继续尝试从CLASS_PATH中加载
            config.merchantCertPath = "<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->";
            config.alipayCertPath = "<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->";
            config.alipayRootCertPath = "<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt -->";
    
            //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
            // config.alipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->";
    
            //可设置异步通知接收服务地址(可选)
            config.notifyUrl = "<-- 请填写您的支付类接口异步通知接收服务地址,例如:https://www.test.com/callback -->";
    
            //可设置AES密钥,调用AES加解密相关接口时需要(可选)
            config.encryptKey = "<-- 请填写您的AES密钥,例如:aa4BtZ4tspm2wnXLb1ThQA== -->";
    
            return config;
        }
    }

    7.异步通知 (仅用于扫码支付)

    异步通知文档连接

    POST 方式 ,异步通知地址 notify_url

    ​ //可设置异步通知接收服务地址(可选) ​ config.notifyUrl = "<-- 请填写您的支付类接口异步通知接收服务地址,例如:https://www.test.com/callback -->";

    异步通知是指当收银台调用 预下单 请求 API 生成二维码展示给用户后,用户通过手机扫描二维码进行支付,支付宝会将该笔订单的变更信息,沿着商户调用预下单请求时所传入的异步通知地址 notify_url,通过 POST 请求的形式将支付结果作为参数通知到商户系统

    主要使用下面的 通知参数来接收数据

    7.1 异步通知参数

    参数类型必填描述
    notify_timeDate通知时间。通知的发送时间。格式为yyyy-MM-dd HH:mm:ss。示例值:2011-12-27 06:30:30
    notify_typeString(64)通知类型。示例值:trade_status_sync
    notify_idString(128)通知校验 ID。示例值:ac05099524730693a8b330c5ecf72da9786
    sign_typeString(10)签名类型。商户生成签名字符串所使用的签名算法类型,目前支持 RSA2 和 RSA,推荐使用 RSA2(如果开发者手动验签,不使用 SDK 验签,可以不传此参数)。示例值:RSA2
    signString(256)签名。请参考异步返回结果的验签(如果开发者手动验签,不使用 SDK 验签,可以不传此参数)。示例值:601510b7970e52cc63db0f44997cf70e
    trade_noString(64)支付宝交易号。支付宝交易凭证号。示例值:2013112011001004330000121536
    app_idString(32)开发者的 app_id。支付宝分配给开发者的应用 APPID。示例值:2014072300007148
    out_trade_noString(64)商户订单号。原支付请求的商户订单号。示例值:6823789339978248
    out_biz_noString(64)商户业务号。商户业务 ID,主要是退款通知中返回退款申请的流水号。示例值:HZRF001
    buyer_idString(16)买家支付宝用户号。买家支付宝账号对应的支付宝唯一用户号。示例值:2088102122524333
    buyer_logon_idString(100)买家支付宝账号。示例值:15901825620
    seller_idString(30)卖家支付宝用户号。示例值:2088101106499364
    seller_emailString(100)卖家支付宝账号。示例值:zhuzhanghu@alitest.com
    trade_statusString(32)交易状态。交易目前所处的状态。示例值:TRADE_CLOSED
    total_amountNumber(9,2)订单金额。本次交易支付的订单金额,单位为人民币(元)。示例值:20
    receipt_amountNumber(9,2)实收金额。商户在交易中实际收到的款项,单位为人民币(元)。示例值:15
    invoice_amountNumber(9,2)开票金额。用户在交易中支付的可开发票的金额。示例值:10.00
    buyer_pay_amountNumber(9,2)付款金额。用户在交易中支付的金额。示例值:13.88
    point_amountNumber(9,2)集分宝金额。使用集分宝支付的金额。示例值:12.00
    refund_feeNumber(9,2)总退款金额。退款通知中,返回总退款金额,单位为元,支持两位小数。示例值:2.58
    send_back_feeNumber(9,2)实际退款金额。商户实际退款给用户的金额,单位为元,支持两位小数。示例值:2.08
    subjectString(256)订单标题。商品的标题/交易标题/订单标题/订单关键字等,是请求时对应的参数,原样通知回来。示例值:当面付交易
    bodyString(400)商品描述。该订单的备注、描述、明细等。对应请求时的 body 参数,原样通知回来。示例值:当面付交易内容
    gmt_createDate交易创建时间。该笔交易创建的时间。格式为 yyyy-MM-dd HH:mm:ss。示例值:2015-04-27 15:45:57
    gmt_paymentDate交易付款时间。该笔交易的买家付款时间。格式为 yyyy-MM-dd HH:mm:ss。示例值:2015-04-27 15:45:57
    gmt_refundDate交易退款时间。该笔交易的退款时间。格式为 yyyy-MM-dd HH:mm:ss.S。示例值:2015-04-28 15:45:57.320
    gmt_closeDate交易结束时间。该笔交易结束时间。格式为 yyyy-MM-dd HH:mm:ss。示例值:2015-04-29 15:45:57
    fund_bill_listString(512)支付金额信息。支付成功的各个渠道金额信息,详见下表 资金明细信息说明示例值:[{"amount":"15.00","fundChannel":"ALIPAYACCOUNT"}]
    voucher_detail_listString优惠券信息。本交易支付时所使用的所有优惠券信息,详见下表 优惠券信息说明示例值:[{“amount”:“0.20”,“merchantContribute”:“0.00”,“name”:“一键创建券模板的券名称”,“otherContribute”:“0.20”,“type”:“ALIPAY_BIZ_VOUCHER”,“memo”:“学生卡8折优惠”}]

    8. 集成博客系统 打赏功能 案例代码

    使用的是 新版SDK Factory

    8.1 提供获取二维码功能

        @RequestMapping("/qrCode")
        @CrossOrigin
        public void getPayQr(String money, HttpServletRequest request, HttpServletResponse response) {
            aliPayService.getPayQr(money, new ServletWebRequest(request, response));
        }

    主要就是调用 预付款接口 Factory.Payment.FaceToFace().preCreate() 接口 获取到二维码的 code ,根据google 的 zxing core 生成二维码图片

    通过ImageIO.write 把二维码图片写到 outputstream 中

    ImageIO.write(qrBufferedImage, aliPayTradeQrConfig.getQrSuffix(), request.getResponse().getOutputStream());

    
    
    @Override
        public void getPayQr(String money, ServletWebRequest request) {
            log.info("【----------------------start getPayQr--------------------------】");
            long currentTimes = System.currentTimeMillis();
            try {
                // 2. 发起API调用(以创建当面付收款二维码为例)
                String outTradeNo = "" + currentTimes
                        + (long) (Math.random() * 10000000L);
                Map<String, Object> paramMap = new HashMap<>();
                //二维码10分钟后 失效
                paramMap.put("timeout_express", aliPayTradeQrConfig.getQrExpireMinute() + "m");
                AlipayTradePrecreateResponse response = Factory.Payment.FaceToFace()
                        .batchOptional(paramMap)
                        .preCreate(subject, outTradeNo, money);
                // 3. 处理响应或异常
                if (ResponseChecker.success(response)) {
                    log.info("预付款 preCreate 调用成功 业务订单号outTradeNo : {}", outTradeNo);
                    // 需要修改为运行机器上的路径
                    BufferedImage qrBufferedImage = ZxingUtils.getQRBufferedImage(response.getQrCode(), aliPayTradeQrConfig.getQrWidth(), aliPayTradeQrConfig.getQrHeight());
                    if (qrBufferedImage != null) {
                        //保存业务订单信息
                        taskExecutor.execute(() -> {
                            long expireTime = currentTimes + (aliPayTradeQrConfig.getQrExpireMinute() * 60 * 1000);
                            AliPayTradeQrDelayContext.DELAY_QUEUE.put(AliPayTradeQrDelayContext.buildAliPayTradeQrDelayInfo(outTradeNo,
                                    expireTime));
                            payOrderService.buildPayOrderInfo(subject, outTradeNo, money, expireTime);
                        });
                        //打印图片 将文件流放入response中
                        if (request.getResponse() != null) {
                            ImageIO.write(qrBufferedImage, aliPayTradeQrConfig.getQrSuffix(), request.getResponse().getOutputStream());
                        }
                    }
                } else {
                    log.error("调用失败,原因:{}", response.msg + "," + response.subMsg);
                }
            } catch (Exception e) {
                log.error("调用遭遇异常,原因:{}", e.getMessage());
                throw new RuntimeException(e.getMessage(), e);
            }
            log.info("【----------------------end getPayQr--------------------------】");
        }

    com.google.zxing

    <!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.3.0</version>
    </dependency>

    ZxingUtils 生成图片二维码 工具类

    /**
     * @author johnny
     * @create 2021-04-25 9:29 下午
     **/
    public class ZxingUtils {
    
        private static Log log = LogFactory.getLog(ZxingUtils.class);
    
        private static final int BLACK = 0xFF000000;
        private static final int WHITE = 0xFFFFFFFF;
    
        private static BufferedImage toBufferedImage(BitMatrix matrix) {
            int width = matrix.getWidth();
            int height = matrix.getHeight();
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
                }
            }
            return image;
        }
    
        private static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
            BufferedImage image = toBufferedImage(matrix);
            if (!ImageIO.write(image, format, file)) {
                throw new IOException("Could not write an image of format " + format + " to " + file);
            }
        }
    
        /**
         * 将内容contents生成长宽均为width的图片,图片路径由imgPath指定
         */
        public static File getQRCodeImge(String contents, int width, String imgPath) {
            return getQRCodeImge(contents, width, width, imgPath);
        }
    
        /**
         * 将内容contents生成长为width,宽为width的图片,图片路径由imgPath指定
         */
        public static File getQRCodeImge(String contents, int width, int height, String imgPath) {
            try {
                Map<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
                hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
                hints.put(EncodeHintType.CHARACTER_SET, "UTF8");
    
                BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints);
    
                File imageFile = new File(imgPath);
                writeToFile(bitMatrix, "png", imageFile);
    
                return imageFile;
    
            } catch (Exception e) {
                log.error("create QR code error!", e);
                return null;
            }
        }
    
        public static BufferedImage getQRBufferedImage(String contents, int width, int height) {
            try {
                Map<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
                hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
                hints.put(EncodeHintType.CHARACTER_SET, "UTF8");
    
                BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints);
    
                BufferedImage image = toBufferedImage(bitMatrix);
    
                return image;
            } catch (Exception e) {
                log.error("create QR code error!", e);
                return null;
            }
        }
    }

    8.2 提供异步通知接口

    支付宝 异步通知 文档中 明确说了,需要对异步通知接口收到的消息进行 以下的校验

    1.订单校验

    2.签名参数的校验

    3.总金额校验

    等等。。

    异步返回结果验签

    1. 在通知返回参数列表中,除去 sign、sign_type 两个参数外,凡是通知返回回来的参数皆是待验签的参数;

    2. 将剩下参数进行 url_decode, 然后进行字典排序,组成字符串,得到待签名字符串:

      gmt_create=2015-06-11 22:33:46&gmt_payment=2015-06-11 22:33:59&notify_id=42af7baacd1d3746cf7b56752b91edcj34&notify_time=2015-06-11 22:34:03&notify_type=trade_status_sync&out_trade_no=21repl2ac2eOutTradeNo322&seller_email=testyufabu07@alipay.com&seller_id=2088211521646673&subject=FACE_TO_FACE_PAYMENT_PRECREATE中文&trade_no=2015061121001004400068549373&trade_status=TRADE_SUCCESS
    1. 将签名参数(sign)使用 base64 解码为字节码串;
    2. 使用 RSA/RSA2 的验签方法,通过签名字符串、签名参数(经过 base64 解码)及支付宝公钥验证签名;
    3. 需要严格按照如下描述校验通知数据的正确性:
      • 商户需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号。
      • 判断 total_amount 是否确实为该订单的实际金额(即商户订单创建时的金额)。
      • 校验通知中的 seller_id(或者seller_email) 是否为 out_trade_no 这笔单据的对应的操作方(有的时候,一个商户可能有多个 seller_id/seller_email)。

    上述有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。

    新版SDK 校验方法

    signVerified = Factory.Payment.Common().verifyNotify(params);

      /**
         * https://opendocs.alipay.com/open/194/103296
         *
         * @param request
         * @return
         */
        @RequestMapping("/callback")
        @CrossOrigin
        public String callback(HttpServletRequest request) {
            // 将异步通知中收到的待验证所有参数都存放到map中
            Map<String, String> params = convertRequestParamsToMap(request);
            String paramsJson = gson.toJson(params);
            log.info("支付宝回调,{}", paramsJson);
            try {
                // 支付宝配置 老版本这样做 ,新版本使用  Factory.setOptions(AliPayConfigUtils.getOptions());
                //AlipayConfig alipayConfig = new AlipayConfig();
                boolean signVerified = false;
                // 调用老的 SDK验证签名
    //            boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipay_public_key(),
    //                    alipayConfig.getCharset(), alipayConfig.getSigntype());
                try {
                  // 调用老的 SDK验证签名
                    signVerified = Factory.Payment.Common().verifyNotify(params);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (signVerified) {
                    log.info("支付宝回调签名认证成功");
                    AlipayNotifyParam alipayNotifyParam = buildAlipayNotifyParam(params);
                    // 按照支付结果异步通知中的描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failure
                    aliPayService.checkNotifyParam(alipayNotifyParam);
                    // 另起线程处理业务
                    taskExecutor.execute(() -> {
                        String tradeStatus = alipayNotifyParam.getTradeStatus();
                        // 支付成功
                        if (AliPayTradeStatusEnum.TRADE_SUCCESS.name().equals(tradeStatus)
                                || AliPayTradeStatusEnum.TRADE_FINISHED.name().equals(tradeStatus)) {
                            try {
                                // 处理支付成功逻辑
                                aliPayService.processSuccess(alipayNotifyParam);
                                log.info("【支付 回调成功: 】");
                            } catch (Exception e) {
                                log.error("支付宝回调业务处理报错,params:" + paramsJson, e);
                            }
                        } else if (AliPayTradeStatusEnum.TRADE_CLOSED.name().equals(tradeStatus)) {
                            log.error("支付宝回调业务,支付宝交易状态:{}, params:{}", tradeStatus, paramsJson);
                            aliPayService.processSuccess(alipayNotifyParam);
                        } else {
                            log.error("没有处理支付宝回调业务,支付宝交易状态:{},params:{}", tradeStatus, paramsJson);
                        }
                    });
                    // 如果签名验证正确,立即返回success,后续业务另起线程单独处理
                    // 业务处理失败,可查看日志进行补偿,跟支付宝已经没多大关系。
                    return "success";
                } else {
                    log.info("支付宝回调签名认证失败,signVerified=false, paramsJson:{}", paramsJson);
                    return "failure";
                }
            } catch (AlipayApiException e) {
                log.error("支付宝回调签名认证失败,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage());
                return "failure";
            }
        }
    
    

    校验方法

        @Override    public void checkNotifyParam(AlipayNotifyParam alipayNotifyParam) throws AlipayApiException {        String outTradeNo = alipayNotifyParam.getOutTradeNo();        // 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,        log.info("【receive outTradeNo : {}】", outTradeNo);        PayOrderInfo payOrderInfo = payOrderService.findByOutTradeNoAndAppId(outTradeNo, AliPayConfigUtils.getOptions().appId);        if (payOrderInfo == null) {            throw new AlipayApiException("out_trade_no错误");        }//        // 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),        long total_amount = alipayNotifyParam.getTotalAmount().multiply(new BigDecimal(100)).longValue();        if (total_amount != payOrderInfo.getQrCodeAmount().multiply(new BigDecimal(100)).longValue()) {            throw new AlipayApiException("error total_amount");        }        // 3、校验通知中的seller_id(或者seller_email)是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),//        // 第三步可根据实际情况省略//        // 4、验证app_id是否为该商户本身。        if (!alipayNotifyParam.getAppId().equals(AliPayConfigUtils.getOptions().appId)) {            throw new AlipayApiException("app_id不一致");        }    }

    8.3 延迟队列去监听 过期交易 发送alipay.trade.cancel 撤销交易

    延迟队列去调用 cancel 撤销接口 延迟队列的使用就不介绍了

    内部涉及了 延迟队列的使用 ,逻辑就是 获取到二维码图片后 把订单任务放入延迟队列中,由另外一个线程从延迟队列中获取数据 去判断该条订单记录是否支付完成,如果未支付完成 则调用 cancel 订单撤销接口

    long expireTime = currentTimes + (aliPayTradeQrConfig.getQrExpireMinute() * 60 * 1000);                        AliPayTradeQrDelayContext.DELAY_QUEUE.put(AliPayTradeQrDelayContext.buildAliPayTradeQrDelayInfo(outTradeNo,                                expireTime));
    /** * @author johnny * @create 2021-04-26 8:53 下午 **/@Service@Slf4jpublic class AliPayTradeQrDelayContext {    public static final DelayQueue<AliPayTradeQrDelayInfo> DELAY_QUEUE = new DelayQueue<>();    @Autowired    private ThreadPoolTaskExecutor taskExecutor;    @Autowired    private AliPayService aliPayService;    @PostConstruct    public void init() {        //启动 延迟 二维码过期 监听线程        taskExecutor.execute(new AliPayTradeQrDelayConsumer(aliPayService));    }    /**     * 构造 AliPayTradeQrDelayInfo     */    public static AliPayTradeQrDelayInfo buildAliPayTradeQrDelayInfo(String outTradeNo, long expireTime) {        return new AliPayTradeQrDelayInfo(outTradeNo, expireTime);    }}
    /** * 二维码延迟队列中的 info * * @author johnny * @create 2021-04-26 8:46 下午 **/@Datapublic class AliPayTradeQrDelayInfo implements Delayed {    private String outTradeNo;    private long expireTime;    public AliPayTradeQrDelayInfo(String outTradeNo, long expireTime) {        this.outTradeNo = outTradeNo;        this.expireTime = expireTime;    }    @Override    public long getDelay(TimeUnit unit) {        //判断expireTime是否大于当前系统时间,并将结果转换成MILLISECONDS        long diffTime = expireTime - System.currentTimeMillis();        return unit.convert(diffTime, TimeUnit.MILLISECONDS);    }    @Override    public int compareTo(Delayed o) {        //compareTo用在AliPayTradeQrDelayInfo的排序        return (int) (this.getExpireTime() - ((AliPayTradeQrDelayInfo) o).getExpireTime());    }}

    队列监听者

    /** * @author johnny * @create 2021-04-26 4:56 下午 **/@Slf4jpublic class AliPayTradeQrDelayConsumer implements Runnable {    private AliPayService aliPayService;    public AliPayTradeQrDelayConsumer(AliPayService aliPayService) {        this.aliPayService = aliPayService;    }    @Override    public void run() {        log.info("【监控过期二维码线程启动】");        while (true) {            try {                //阻塞 获取 DELAY_QUEUE 队列中的数据 判断是否订单完成 未完成则需要去 调用alipay.trade.canal 撤销交易                AliPayTradeQrDelayInfo aliPayTradeQrDelayInfo = AliPayTradeQrDelayContext.DELAY_QUEUE.take();                if (StringUtils.isNotEmpty(aliPayTradeQrDelayInfo.getOutTradeNo())) {                    //调用 撤销订单操作                    aliPayService.judgeCancel(aliPayTradeQrDelayInfo.getOutTradeNo());                }            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}    /**     * 如果是异步的回调,则安排定时任务和延迟队列 去 执行 过期的支付订单的  撤销交易     * 如果是主动轮训, 则轮训结束后 还没成功,则直接调用该方法  撤销交易          * Factory.Payment.Common().cancel     * @param outTradeNo     */    @Override    public void judgeCancel(String outTradeNo) {        log.info("【----------------------start judgeCancel--------------------------】");        PayOrderInfo payOrderInfo = payOrderService.findByOutTradeNoAndAppId(outTradeNo, AliPayConfigUtils.getOptions().appId);        if (payOrderInfo != null) {            if (!Arrays.asList(AliPayTradeStatusEnum.TRADE_SUCCESS.name(), AliPayTradeStatusEnum.TRADE_FINISHED.name())                    .contains(payOrderInfo.getTradeStatus())) {                //未完成的 表示已经 过期了                try {                    log.info("call cancel request outTradeNo : {}", outTradeNo);                    AlipayTradeCancelResponse cancelResponse = Factory.Payment.Common().cancel(outTradeNo);                    if (ResponseChecker.success(cancelResponse)) {                        //业务订单 状态给修改一下 撤销成功 或者 删除等操作                        log.info("call cancel request success : {}", outTradeNo);                        payOrderService.deletePayOrderByOutTradeNo(payOrderInfo.getOutTradeNo());                        // payOrderInfo.setTradeStatus(AliPayTradeStatusEnum.TRADE_CLOSED.name());                        //payOrderService.savePayOrderInfo(payOrderInfo);                    } else {                        log.error("【撤销交易 失败: msg: {} ,  subMsg {}】", cancelResponse.msg, cancelResponse.subMsg);                    }                } catch (Exception e) {                    e.printStackTrace();                }            } else {                log.info("【outTradeNo ready success finish 】");            }        }        log.info("【----------------------end  judgeCancel--------------------------】");    }

    8.4 二维码 ConfigurationProperties 配置

    @Data@ConfigurationProperties(prefix = "qr")public class AliPayTradeQrConfig {      //二维码过期分钟数    private int qrExpireMinute;      //二维码图片生成宽度    private int qrWidth;    //二维码图片生成高度    private int qrHeight;        //二维码图片生成后缀 PNG 。。    private String qrSuffix;}

    8.5 AliPayConfigUtils 配置参数

    接入准备工作 获取到的参数

    APPID :通过创建应用后 应用头像下发的 202100xxxxx 这个就是APPID

    应用私钥: 通过密钥在线生成器 可以直接生成

    应用公钥: 通过密钥在线生成器 可以直接生成

    支付宝公钥: 这个要注意,是通过 上面的应用公钥 去换取的 ,在应用 开发信息 -》 接口加签方式 -》设置

    /** * @author johnny * @create 2021-04-26 1:03 上午 **/public class AliPayConfigUtils {    private static Config config = new Config();    public static void initConfig() {        config.protocol = "https";        config.gatewayHost = "openapi.alipay.com";        config.signType = "RSA2";        config.appId = "2021002141XXXXXXX";        // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中        config.merchantPrivateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSXXXXXXX";        //注:证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径,优先从文件系统中加载,加载失败后会继续尝试从CLASS_PATH中加载        //config.merchantCertPath = "<-- 请填写您的应用公钥证书文件路径,例如:/foo/appCertPublicKey_2019051064521003.crt -->";        //config.alipayCertPath = "<-- 请填写您的支付宝公钥证书文件路径,例如:/foo/alipayCertPublicKey_RSA2.crt -->";        //config.alipayRootCertPath = "<-- 请填写您的支付宝根证书文件路径,例如:/foo/alipayRootCert.crt -->";        //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可        config.alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKXXXXXXX;        //可设置异步通知接收服务地址(可选)        config.notifyUrl = "http://yanqqe.natappfree.cc/blogs/alipay/callback";        //可设置AES密钥,调用AES加解密相关接口时需要(可选)        config.encryptKey = "";    }    public static Config getOptions() {        return config;    }}

    效果展示

    前端代码就不展示了。。 拿出手机扫描即可 支付 。。

    image-20210426232134924

    总结

    本篇主要讲解了 如何从头到尾接入 支付宝的当面付功能, 从创建应用 应用配置 签约 获取密钥参数等 到 使用新版SDK 调用 获取二维码 以及 异步通知接口的 代码编写逻辑 多看文档就好。

    本文由博客一文多发平台 OpenWrite 发布!

    展开全文
  • 我用九天时间,深挖一闲鱼诈骗黑色产业链。

    千次阅读 多人点赞 2019-12-27 21:58:14
    在该后台中是可以看到浏览商品的受害者IP以及他们填写的收货地址姓名手机号,我粗略的看了下,上当概率蛮高的,一共七十多的浏览记录,其中有二十多人了款。 受害者的IP地址 为了更全面的收集信息,我将这些受害...
  • Java流处理之高效读写的缓冲流

    千次阅读 2022-04-28 12:44:56
    若有作奸犯科及为忠善者,宜有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。 1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追...
  • 以上事情仅仅是个例,足以见得我们生活中处处都是陷阱,一不小心就跳进去了,然后导致很多人躺枪,其实我个人用的第三方平台不止是宝还有其他的平台,只不过用这个比较多,看到了一些新闻就想自己旁观者的...
  • 代码这路,能走多远?

    万次阅读 2019-04-19 17:26:13
    PPT 路线:这路线,是从代码的岗位转入项目管理、运营增长的岗位,需要较强的策划和执行能力,比如产品、运营等。 适合于走哪个路线,需要结合自己的性格来定。工程师都有一个共同的性格特点,追求简单,追求...
  • 代码这路,能走多远?阿里算法专家告诉你

    千次阅读 多人点赞 2019-04-27 17:25:04
    PPT 路线:这路线,是从代码的岗位转入项目管理、运营增长的岗位,需要较强的策划和执行能力,比如产品、运营等。 适合于走哪个路线,需要结合自己的性格来定。工程师都有一个共同的性格特点,追求简单,追求...
  • ,在编完上一本PDF《字节码编程》被下载了2000份以后,蠢蠢欲动开始计划第二本。于是从????5月20日那天投身实战型设计模式打磨,通过模拟互联网业务开发实际需求作为学习场景,讲解设计模式。 全书共计22个真实...
  • 大家知道,win32窗口的内置滚动自绘是个非常棘手的问题,在这篇文章之前首先感谢下CSDN的mynamelj,他的那个SkinSB开源的时候我就开始使用来美化一般win32窗口的滚动,很好用,但是最近有想把自己的应用迁移到...
  • 我在淘宝帮别人代码,月入10万!

    千次阅读 2021-07-12 00:09:20
    在一次偶然的机会中得知,客户3000元,自己只能拿到1000元,这才知道淘宝中介有多黑。很多淘宝商家不让程序员直接跟客户沟通,怕被抢客户,也怕程序员知道真实的价格。 该程序员说,如果这份工作能挣到和工资...
  • js获取滚动宽度

    千次阅读 2018-08-10 14:41:41
    思路:通过创建一个元素,不要给元素设置边框,然后给元素设置overflowY:scroll,再根据元素的offsetWidth-clientWidth来计算滚动宽度。 代码: &lt;!DOCTYPE html&gt; &lt;html lang="en&...
  • 完全搞定iframe(框架)里的滚动!(一) 说明:1、本文参考了网络上大量资料,本人在此深表感谢!2、本文假设读者,有一定的HTML、CSS、JS基础。3、本文讨论的目标是,通过A页面里
  • 如何专利

    万次阅读 多人点赞 2018-12-18 11:20:36
    手把手教你专利申请书·如何申请专利   摘要 小前言 (一)申请前的准备工作  1、申请前查询  2、其他方面的考虑  3、申请文件准备 (二)填写专利申请系列文档  1、实际操作步骤  2、具体操作  3、经验...
  • 假设你是金主爸爸,你要雇一个人来给你打工一周(7天),并且每天他的报酬必须是一样的。 你手里有1根金条,还有1把无比锋利的可以切开金条的刀,但是你只能切2刀。 你要怎么切,怎么分配,才能保证每天给工人的...
  • select a.*,lag(a.id,1) over (order by id desc) lag from 表 alag(要选择的字段,前面一) over(根据字段排序)lag
  • 项目集成支付宝接口接入–实践–支付宝当面申请–绝对详细 支付宝–官网-申请当面步骤 前言: 今天是看到同学,申请了一波支付宝当面,而且成功了,现在已经可以应用到项目中,就是手续费有点高(0.6%)100块...
  • 支付宝当面扫码支付接口开发

    千次阅读 2018-12-15 21:13:00
    其实支付宝这块的api开发接口文档等还是的比较明白的,如果真的是有搞不定的地方也是可以在线询问支付宝技术客服的,而且回复的速度也是挺快。现在支付宝的验签功能已经封装了,不需要我们在自己实现验签功能。挺...
  • 【单选题】如要将x的十位和个位交换(如13变为31),... (6.0分)【判断题】通过发行股票筹资,可以不利息,因此其成本比借款筹资的成本低。【填空题】下列 Python语句的输出结果是? def f(): return 'No' f() (4.0分)...
  • 没有一链能通吃全世界

    万次阅读 2019-05-16 18:38:22
    出人意料的是,IP协议极其简单,用5张纸就能完所有技术细节。IP没有安全功能,没有加密协议,不支持大数据包,不能解析地址,也不管传输质量好坏,简单到简陋。 可IP协议为什么能在过去50年中,成为整个互联网...
  • /usr/bin/python #-*-coding:utf-8-*- # 免责声明:以下脚本内容仅...接码记得勾选多 2 雷电模拟器 弄完一个删掉 免费测婚姻 1;诺基亚:2台,使用2年以上,质量没问题,过时扔了。 总结:质量不错。 2;三星:6台,
  • keras+卷积神经网络HWDB手写汉字识别

    千次阅读 2018-08-31 10:34:19
    在前面 HWDB手写汉字数据集来自于中科院自动化研究所,下载地址: http://www.nlpr.ia.ac.cn/databases/download/feature_data/HWDB1.1trn_gnt.zip ... 源码 在gith...
  • [转]全球虚拟卡申请流程~

    千次阅读 2019-09-27 19:19:09
    所以真是不出来啊,要是其他网友在使用支付过程中遇到问题,请提出来让大家都知晓以避免以后遇到相同的问题。 ) 另外充值在Global Cash账户中是人民币,结算是美元,腕包$9.99,实时汇率折合下来约¥61.21,...
  • 6)公司只你 5 天的薪水,尽量不要在周末加班干活,把这个时间留给自己,有家庭的多陪陪家人,单身的可以看点书提升自己,最重要的,每周进行锻炼,身体是革命的本钱,照顾好自己。 7)解决问题和优化的过程可能...
  • 辞职信:给我的“藤野先生”

    千次阅读 多人点赞 2017-02-15 09:13:26
    做易极对账时,我们两个从百万数据里找出那么几导致资金数目对不上账的数据,用sql来检查资金平衡,甚至手动用计算器去计算结果,这很不容易。 ... 在团队文化构建上,我竭尽所能,做到自己最好的一面...
  • 后感 写作本文,一共花了4个小时。 分期支付的利率问题,看似简单,但想要得出经得起推敲的结论,却需要用数学代数去推导。 人生处处皆学问,金融数学不分家。 小雷-金融实践者 2016年11月1日 北京-宋家庄
  • css 更改滚动样式

    千次阅读 2017-08-09 15:22:35
    // 以 o 为对象,将对象包含的class名为Scroller-Container的元素给 对象 o } } //Private methods this . _setPos = function ( x , y ) { if ( x < this . viewableWidth - ...
  • 用C语言一个查单词的小demo

    千次阅读 2021-07-03 17:36:31
    用C语言一个查单词的小demo #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc, const char *argv[]) { // 用只读的方式打开我们的单词库 FILE *fp = fopen(...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 30,038
精华内容 12,015
关键字:

付条怎么写