JAVA实现的支付宝扫描二维码支付

支付项目采用springMvc+Dubbo架构实现,只对外提供接口


前期酝酿准备

最近项目中要上线支付功能、前段时间刚开发完微信的扫码支付、不得不说微信开发团队的文档真是一个烂。但总算是对照着API把功能交付上线了。

前几天公司申请下来了企业支付宝,得空所以也把支付宝的扫码支付给集成进去。这里又不得不说,是支付宝的文档写的不咋地还是自己没有仔细阅读,总之翻遍了API最终在沙箱里面运行成功(切记、认真读文档,不然各种BUG等着你)

什么是扫码支付?

扫码支付,指用户打开支付宝钱包中的“扫一扫”功能,扫描商家展示在某收银场景下的二维码并进行支付的模式。该模式适用于线下实体店支付、面对面支付等场景。

业务流程:

使用步骤:

用户登陆支付宝钱包,点击首页“付款-扫码付”,进入扫一扫界面;

收银员在商家收银系统操作生成支付宝订单,用户确认支付金额,并生成二维码;

用户使用钱包的“扫码付”,扫收银员提供的二维码,确认支付;

用户付款后商家收银系统会拿到支付成功或者失败的结果。

具体产品介绍

如何快速接入?

前面的大家可以大体了解一下

开放平台服务端SDK下载地址(这里选择JAVA版本)、点击下载、里面有详细的API测试方法。

如何集成到项目中去?

下载DEMO解压、仔细阅读里面的readme.txt文件、里面有详细的项目结构。

参数配置zfbinfo.properties(沙箱环境网关参数不同)

# 支付宝网关名、partnerId和appId

#open_api_domain = https://openapi.alipay.com/gateway.do

#支付宝沙箱环境

open_api_domain = https://openapi.alipaydev.com/gateway.do

mcloud_api_domain = http://mcloudmonitor.com/gateway.do

pid = 此处请填写你的PID

appid = 此处请填写你当面付的APPID

# RSA私钥、公钥和支付宝公钥

private_key = 此处请填写你的商户私钥且转PKCS8格式

public_key = 此处请填写你的商户公钥

alipay_public_key = MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDI6d306Q8fIfCOaTXyiUeJHkrIvYISRcc73s3vF1ZT7XN8RNPwJxo8pWaJMmvyTn9N4HQ632qJBVHf8sxHi/fEsraprwCtzvzQETrNRwVxLO5jVmRGi60j8Ue1efIlzPXV9je9mkjzOmdssymZkh2QhUrCmZYI/FCEa3/cNMW0QIDAQAB

# 当面付最大查询次数和查询间隔(毫秒)

max_query_retry = 5

query_duration = 5000

# 当面付最大撤销次数和撤销间隔(毫秒)

max_cancel_retry = 3

cancel_duration = 2000

# 交易保障线程第一次调度延迟和调度间隔(秒)

heartbeat_delay = 5

heartbeat_duration = 900

RSA私钥、公钥和支付宝公钥 获取方法。

生成与配置密钥

这里我选择的是方式一,使用支付宝提供的一键生成工具(内附使用说明)。

如果是JAVA程序public_key参数对应rsa_private_key_pkcs8.pem文件里面的内容,

public_key参数对用rsa_public_key.pem文件里面的内容。然后把公钥复制到沙箱中的RSA(SHA1)密钥中生成支付宝公钥、对应的是alipay_public_key参数。

如何生成二维码订单?

然后你就可以运行Main.java 中的额main方法进行测试了,运行结果如下:

[acts_pay]|2016-11-04 15:23:35:530|Configs{支付宝openapi网关: https://openapi.alipaydev.com/gateway.do

, 支付宝mcloudapi网关域名: http://mcloudmonitor.com/gateway.do

, pid: 2088102169116018

, appid: 2016073000123724

, 商户RSA私钥: MIICdw******rLZis=

, 商户RSA公钥: MIGfMA******IDAQAB

, 支付宝RSA公钥: MIGfMA******IDAQAB

, 查询重试次数: 5

, 查询间隔(毫秒): 5000

, 撤销尝试次数: 3

, 撤销重试间隔(毫秒): 2000

, 交易保障调度延迟(秒): 5

, 交易保障调度间隔(秒): 900

}

[acts_pay]|2016-11-04 15:23:35:719|trade.precreate bizContent:{"out_trade_no":"tradeprecreate14782442155652020005","seller_id":"","total_amount":"0.01","undiscountable_amount":"0","subject":"xxx品牌xxx门店当面付扫码消费","body":"购买商品3件共20.00元","goods_detail":[{"goods_id":"goods_id001","goods_name":"xxx小面包","quantity":1,"price":"10"},{"goods_id":"goods_id002","goods_name":"xxx牙刷","quantity":2,"price":"5"}],"operator_id":"test_operator_id","store_id":"test_store_id","extend_params":{"sys_service_provider_id":"2088100200300400500"}}

[acts_pay]|2016-11-04 15:23:37:875|{"alipay_trade_precreate_response":{"code":"10000","msg":"Success","out_trade_no":"tradeprecreate14782442155652020005","qr_code":"https:\/\/qr.alipay.com\/bax03938xgzra2b5pijd00d2"},"sign":"LA2d5txq43c3t12sCsNEEGvu3plXUrqrd/uyzOy4HIMM5eRkWXaFkL+wqVNcYX/Jfn6no72yqiAUvYAivaWZkXZA3UxTRYlW+0EwZ96HrpnjFCK+QGOSDZuoiA2AyQlFgM/cQwdgTFGI+R2X9QZWxft1z3zYVG1uRGEZXed5RPQ="}

[acts_pay]|2016-11-04 15:23:37:878|支付宝预下单成功: )

[acts_pay]|2016-11-04 15:23:37:878|code:10000, msg:Success

[acts_pay]|2016-11-04 15:23:37:878|body:{"alipay_trade_precreate_response":{"code":"10000","msg":"Success","out_trade_no":"tradeprecreate14782442155652020005","qr_code":"https:\/\/qr.alipay.com\/bax03938xgzra2b5pijd00d2"},"sign":"LA2d5txq43c3t12sCsNEEGvu3plXUrqrd/uyzOy4HIMM5eRkWXaFkL+wqVNcYX/Jfn6no72yqiAUvYAivaWZkXZA3UxTRYlW+0EwZ96HrpnjFCK+QGOSDZuoiA2AyQlFgM/cQwdgTFGI+R2X9QZWxft1z3zYVG1uRGEZXed5RPQ="}

[acts_pay]|2016-11-04 15:23:37:878|filePath:D:\qr.png

最后下载沙箱钱包就可以完成手机支付了。

下载地址

如何实现异步通知?

相关参数说明

用户会用手机扫码给支付宝付款,然后支付宝收到之后会发送一条支付成功的消息给我们设置的notify_url

import java.io.BufferedOutputStream;

import java.util.Enumeration;

import java.util.HashMap;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import com.acts.web.acc.service.IWeixinPayService;

import com.acts.web.common.utils.LogUtil;

import com.alipay.api.AlipayApiException;

import com.alipay.api.internal.util.AlipaySignature;

import com.alipay.demo.trade.config.Configs;

@Controller

@RequestMapping(value = "alipay")

public class AliPayController {

    //初始化参数 不然signVerified会验证失败

    static {

            Configs.init("zfbinfo.properties");

    }

    /**

    * 支付宝支付回调

    * @Author 小柒

    * @param request

    * @param response

    * @throws Exception

    *            void

    * @Date 2016年10月31日 更新日志 2016年10月31日 小柒 首次创建

    *

    */

    @SuppressWarnings("unchecked")

    @RequestMapping(value = "pay",method = RequestMethod.POST)

    public void alipay_notify(HttpServletRequest request, HttpServletResponse response) throws Exception {

        LogUtil.info("支付宝付款异步通知!");

        String  message = "success";

        Map<String, String> params = new HashMap<String, String>();

        // 取出所有参数是为了验证签名

        Enumeration<String> parameterNames = request.getParameterNames();

        while (parameterNames.hasMoreElements()) {

            String parameterName = parameterNames.nextElement();

            params.put(parameterName, request.getParameter(parameterName));

        }

        //验证签名

        boolean signVerified = false;

        try {

            signVerified = AlipaySignature.rsaCheckV1(params, Configs.getAlipayPublicKey(), "UTF-8");

        } catch (AlipayApiException e) {

            e.printStackTrace();

            message =  "failed";

        }

        if (signVerified) {

            LogUtil.info("验证签名成功!");

            // 若参数中的appid和填入的appid不相同,则为异常通知

            if (!Configs.getAppid().equals(params.get("app_id"))) {

                LogUtil.info("与付款时的appid不同,此为异常通知,应忽略!");

                message =  "failed";

            }else{

                String outtradeno = params.get("out_trade_no");

                LogUtil.info(outtradeno + "号订单回调通知。");

                //在数据库中查找订单号对应的订单,并将其金额与数据库中的金额对比,若对不上,也为异常通知

                String status = params.get("trade_status");

                if (status.equals("WAIT_BUYER_PAY")) { // 如果状态是正在等待用户付款

                } else if (status.equals("TRADE_CLOSED")) { // 如果状态是未付款交易超时关闭,或支付完成后全额退款

                } else if (status.equals("TRADE_SUCCESS") || status.equals("TRADE_FINISHED")) { // 如果状态是已经支付成功

                    //成功 更新状态

                } else {

                    weixinpayBack.updateAccOrder(outtradeno);

                }

                LogUtil.info(outtradeno + "订单的状态已经修改为" + status);

            }

        } else { // 如果验证签名没有通过

            message =  "failed";

            LogUtil.info("验证签名失败!");

        }

        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());

        out.write(message.getBytes());

        out.flush();

        out.close();

    }

}

如果你想学好JAVA这门技术,也想在IT行业拿高薪,可以参加我们的训练营课程,选择最适合自己的课程学习,技术大牛亲授,8个月后,进入名企拿高薪。我们的课程内容有:Java工程化、高性能及分布式、高性能、深入浅出。高架构。性能调优、Spring,MyBatis,Netty源码分析和大数据等多个知识点。如果你想拿高薪的,想学习的,想就业前景好的,想跟别人竞争能取得优势的,想进阿里面试但担心面试不过的,你都可以来,q群号为:180705916 进群免费领取学习资料。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容