JAVA PC端扫码支付(二)支付宝支付开发

Wesley13
• 阅读 555

一、配置

配置

  1. 用户注册

    首先用公司相关信息在蚂蚁金服开放平台注册一个支付宝账户(https://openhome.alipay.com/platform/home.htm) JAVA PC端扫码支付(二)支付宝支付开发

    然后在进入开放平台后进入开发者中心>网页&移动应用接入中

    JAVA PC端扫码支付(二)支付宝支付开发

    接着和支付宝签约,接入支付功能(手机网站支付)

    JAVA PC端扫码支付(二)支付宝支付开发

  2. 配置和获取相关开发信息

    进入申请的支付功能页面,配置授权回调地址和密钥

    JAVA PC端扫码支付(二)支付宝支付开发

ok,现在我们获取了APPID、支付宝网关、授权回调地址、商户私钥、应用公钥、支付宝公钥等相关信息,开发时我将会把他们写到配置文件中

另外,我们还需要一个支付宝的SDK,请大家自行下载

JAVA PC端扫码支付(二)支付宝支付开发 到此,所需的全部准备工作完成,大家可以愉快的开发了

二、开发

支付逻辑

  • 支付逻辑

    1. 商户系统调用支付宝预下单接口alipay.trade.precreate,获得该订单二维码图片地址。
    2. 发起轮询获得支付结果:等待5秒后调用交易查询接口alipay.trade.query通过支付时传入的商户订单号(out_trade_no)查询支付结果(返回参数TRADE_STATUS),如果仍然返回等待用户付款(WAIT_BUYER_PAY),则再次等待5秒后继续查询,直到返回确切的支付结果(成功TRADE_SUCCESS 或 已撤销关闭TRADE_CLOSED),或是超出轮询时间。在最后一次查询仍然返回等待用户付款的情况下,必须立即调用交易撤销接口alipay.trade.cancel将这笔交易撤销,避免用户继续支付。
    3. 这里是列表文本除了主动轮询,也可以通过接受异步通知获得支付结果。
    4. 和微信支付差异的地方就在支付宝返回查询用户付款状态的方式,支付宝除了主动轮询查询支付状态,还可以异步获取。在项目里我们将这两种方式交叉使用。

公共请求参数

  • 公共请求参数

    JAVA PC端扫码支付(二)支付宝支付开发

与支付无关的业务逻辑

  • 与支付无关的业务逻辑

    这部分代码已经在上篇文章微信支付中贴出,这里就不再重新贴一遍了

封装固定参数

  • 封装固定参数

    package com.andata.conf; /* * *类名:AlipayConfig *功能:基础配置类 *详细:设置帐户有关信息及返回路径 *提示:如何获取安全校验码和合作身份者ID *1.用您的签约支付宝账号登录支付宝网站(www.alipay.com) *2.点击“商家服务”(https://b.alipay.com/order/myOrder.htm) *3.点击“查询合作者身份(PID)”、“查询安全校验码(Key)” *安全校验码查看时,输入支付密码后,页面呈灰色的现象,怎么办? *解决方法: *1、检查浏览器配置,不让浏览器做弹框屏蔽设置 *2、更换浏览器或电脑,重新登录查询。 */ public class AlipayConfig { //ServiceURL public static String ServiceUrl="https://openapi.alipay.com/gateway.do"; //APP支付宝支付业务:app_id public static String app_id = "20180xxxxxxxxxxxxxx"; // 商户的私钥,使用支付宝自带的openssl工具生成。 public static String private_key = "xxxxxxxxxxxxxxxxxxx"; // 应用的公钥,无需修改该值 public static String ali_public_key = "xxxxxxxxxxxxxxxxxxxxx"; // 支付宝的公钥,去open.alipay.com对应应用下查看。 public static String zfb_public_key = "xxxxxxxxxxxxxxxxxxxxx"; // 字符编码格式 目前支持 gbk 或 utf-8 public static String input_charset = "UTF-8"; }

AliPayController

package com.andata.controller;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeCancelRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeCancelResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.andata.conf.AlipayConfig;
import com.andata.pojo.ProductOrders;
import com.andata.service.ProOrdersService;
import com.andata.util.QRCodeUtil;
import net.sf.json.JSONObject;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Controller
public class AliPayController {
    @Resource
    private ProOrdersService proOrdersService;
    /**
     * 支付逻辑
     * 1、商户系统调用支付宝预下单接口alipay.trade.precreate,获得该订单二维码图片地址。
     * 2、发起轮询获得支付结果:等待5秒后调用交易查询接口alipay.trade.query通过支付时传入的商户订单号(out_trade_no)查询支付结果(返回参数TRADE_STATUS),
     如果仍然返回等待用户付款(WAIT_BUYER_PAY),则再次等待5秒后继续查询,直到返回确切的支付结果(成功TRADE_SUCCESS 或 已撤销关闭TRADE_CLOSED),
     或是超出轮询时间。在最后一次查询仍然返回等待用户付款的情况下,必须立即调用交易撤销接口alipay.trade.cancel将这笔交易撤销,避免用户继续支付。
     * 3、除了主动轮询,也可以通过接受异步通知获得支付结果
     */
    /**
     * 阿里订单取消接口
     * 请求返回值示例:
     * {"alipay_trade_cancel_response":{"code":"40004","msg":"Business Failed","sub_code":"ACQ.INVALID_PARAMETER","sub_msg":"参数无效","out_trade_no":"20150320010101002",
     * "retry_flag":"N"},"sign":""}
     * @return
     * @throws AlipayApiException
     */
    @RequestMapping(value = "aliremove.do")
    @ResponseBody
    private Map<String, Object> remove(@Param("orderid")String orderid) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ServiceUrl, AlipayConfig.app_id, AlipayConfig.private_key, "json", AlipayConfig.input_charset, AlipayConfig.zfb_public_key, "RSA2"); //获得初始化的AlipayClient
        AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();//创建API对应的request类
        Map<String,Object> returnmap=new HashMap<>();
        try {
            //判断订单是否完成支付,完成支付的订单禁止撤销
            int i = this.proOrdersService.selectOrderStatus(orderid);
            if (i==1)
            {
                returnmap.put("type","0");
                returnmap.put("data","订单已支付,撤销订单失败");
            }else {
                Map<String,Object> map=new HashMap<>();
                map.put("out_trade_no",orderid);
                String returndata = JSONObject.fromObject(map).toString();
                request.setBizContent(returndata); //设置业务参数
                AlipayTradeCancelResponse response = alipayClient.execute(request);//通过alipayClient调用API,获得对应的response类
                JSONObject query_response = JSONObject.fromObject(response.getBody()).getJSONObject("alipay_trade_cancel_response");
                String code = query_response.getString("code");
                String msg = query_response.getString("msg");
                if (code.equals("10000") && msg.equals("Success")) {
                    System.out.println("阿里订单取消接口调用成功!");
                    returnmap.put("type","1");
                    returnmap.put("data","撤销订单成功");
                }else {
                    System.out.println("撤销订单请求失败");
                    returnmap.put("type","0");
                    returnmap.put("data",query_response.getString("sub_msg"));
                    System.out.println(query_response);//返回失败信息
                }
                //根据response中的结果继续业务逻辑处理
            }
        }catch (Exception e)
        {
            System.out.println("撤销订单异常");
            e.printStackTrace();
        }
        return returnmap;
    }

    /**
     * 阿里交易查询接口
     * out_trade_no    支付时传入的商户订单号,与trade_no必填一个
     *  trade_no    支付时返回的支付宝交易号,与out_trade_no必填一个
     *  请求返回值示例:
     *  {"alipay_trade_query_response":{"code":"10000","msg":"Success","buyer_logon_id":"159****4027","buyer_pay_amount":"0.01","buyer_user_id":"2088012351746164",
     *  "fund_bill_list":[{"amount":"0.01","fund_channel":"PCREDIT"}],"invoice_amount":"0.01","out_trade_no":"020910312752381","point_amount":"0.00","receipt_amount":"0.01",
     *  "send_pay_date":"2018-02-09 10:31:45","total_amount":"0.01","trade_no":"2018020921001004160275738069","trade_status":"TRADE_SUCCESS"},
     *  "sign":""}
     * @return
     * @throws Exception
     */
    @RequestMapping(value="/aliget")
    @ResponseBody
    private Map<String, Object> get(@Param("orderid")String orderid) throws AlipayApiException{
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ServiceUrl, AlipayConfig.app_id, AlipayConfig.private_key, "json", AlipayConfig.input_charset, AlipayConfig.zfb_public_key, "RSA2"); //获得初始化的AlipayClient
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();//创建API对应的request类
        Map<String,Object> map=new HashMap<>();
        map.put("out_trade_no",orderid);
        String returndata = JSONObject.fromObject(map).toString();
        request.setBizContent(returndata); //设置业务参数
        AlipayTradeQueryResponse response = alipayClient.execute(request);//通过alipayClient调用API,获得对应的response类
        JSONObject jsonObject = JSONObject.fromObject(response.getBody()).getJSONObject("alipay_trade_query_response");
        String code = jsonObject.getString("code");
        String msg = jsonObject.getString("msg");
        Map<String,Object> returnmap=new HashMap<>();
        if (code.equals("10000") && msg.equals("Success"))
        {
            System.out.println("交易查询请求成功");
            String trade_status = jsonObject.getString("trade_status");
            if (trade_status.equals("TRADE_SUCCESS"))
            {
                returnmap.put("type","1");
                returnmap.put("data","支付成功");
            }else {
                returnmap.put("type","0");
                returnmap.put("data",trade_status);
            }
        }else {
            System.out.println("交易查询请求失败");
            returnmap.put("type","0");
            returnmap.put("data",jsonObject.getString("sub_msg"));
            System.out.println(jsonObject);//返回失败信息
        }
        return returnmap;
    }
    /**
     * @name 预下单请求,阿里获取二维码接口
     * @throws AlipayApiException
     * @Param out_trade_no 商户订单号,64个字符以内、只能包含字母、数字、下划线;需保证在商户端不重复
     * @Param total_amount 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] 如果同时传入了【打折金额】,【不可打折金额】,
     * 【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
     * @Param subject 订单标题
     * @Param store_id 商户门店编号
     * @Param timeout_express 该笔订单允许的最晚付款时间,逾期将关闭交易。
     * 取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。
     */
    @RequestMapping(value="/alipay.do")
    @ResponseBody
    private Map list(HttpServletResponse responses, @Param("orderid")String orderid) throws AlipayApiException{
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ServiceUrl, AlipayConfig.app_id, AlipayConfig.private_key, "json", AlipayConfig.input_charset, AlipayConfig.zfb_public_key, "RSA2"); //获得初始化的AlipayClient
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();//创建API对应的request类

        Map<String,Object> map=new HashMap<>();
        if (orderid.isEmpty())
        {
            map.put("type","2");
            map.put("data","订单号不能为空");
            return map;
        }
        //设置回调地址
        request.setNotifyUrl("http://www.andata.com.cn/aliPayCallBack.do");
        //根据订单号查询订单信息
        ProductOrders productOrders = this.proOrdersService.selectByOrderId(orderid);
        Map<String,Object> maps=new HashMap<>();
        maps.put("out_trade_no",productOrders.getOrdernumber());
        maps.put("total_amount","0.01");
        maps.put("subject","小编机器人纠错");
        maps.put("store_id","XB001");
        maps.put("timeout_express","1m");
        //把订单信息转换为json对象的字符串
        String postdata = JSONObject.fromObject(maps).toString();
        request.setBizContent(postdata);
        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");
        //流输出
        ServletOutputStream sos = null;
        try {
            sos = responses.getOutputStream();
            //生成二维码
            QRCodeUtil.encode(qr_code, sos);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 支付宝支付成功回调
     */
    @RequestMapping(value = "aliPayCallBack.do")
    @ResponseBody
    public void aliPayCallBack(HttpServletResponse response, HttpServletRequest request) {
        System.out.println("支付宝回调成功");
        try {
            //获取支付宝POST过来反馈信息
            Map<String,String> params = new HashMap<String,String>();
            Map requestParams = request.getParameterMap();
            for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                //乱码解决,这段代码在出现乱码时使用。
                //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
                params.put(name, valueStr);
            }
            boolean flag = AlipaySignature.rsaCheckV1(params, AlipayConfig.zfb_public_key, AlipayConfig.input_charset,"RSA2");
            // 获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
            String order_no = request.getParameter("out_trade_no"); // 获取订单号

//            String trade_no = request.getParameter("trade_no"); // 支付宝交易号
//            String total_amount = request.getParameter("total_amount"); // 获取总金额
//            String subject = new String(request.getParameter("subject")
//                    .getBytes("ISO-8859-1"), "gbk");// 商品名称、订单名称
//            String body = "";
//            if (request.getParameter("body") != null) {
//                body = new String(request.getParameter("body").getBytes(
//                        "ISO-8859-1"), "gbk");// 商品描述、订单备注、描述
//            }
//            String buyer_email = request.getParameter("buyer_email"); // 买家支付宝账号
            String trade_status = request.getParameter("trade_status"); // 交易状态
            // 获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
            if (flag==true) {// 验证成功
                try{
                    int i = this.proOrdersService.updateByOrderId(order_no);
                    if (i==1)
                    {
                        System.out.println("支付宝订单支付成功!");
                    }
                }catch (Exception e)
                {
                    System.out.println("支付宝支付异常");
                    e.printStackTrace();
                }
            }
            response.getWriter().write("success");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

现在,基本的代码都贴完了,生成二维码的逻辑和微信一样,拿到code_url后,用二维码生成工具类生成二维码,把他贴到网页上需要支付的页面,就成功了~

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
AWS国庆双重礼,仅限7天
自2021年10月1日00:00起至2021年10月7日24:00,新注册并激活(需全部完成账号注册的五个步骤,否则账号状态并未激活)AWS海外区域账户,填写页面下方表单,即可申领价值$200美元的AWS海外区域账户服务抵扣券直充到您的账户,用以抵扣服务消费,助您轻松体验多个云迁移应用场景。同时,您还可获赠AWS精美祥云纪念T恤一件。,仅限7天$20
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
4个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这