支付宝支付相比于微信支付要简单点,支付流程如下所示,之前介绍过微信支付(一)(二)(三),在此基础上继续完善支付宝支付。

springboot中实现支付宝接口时不跳转 springboot支付宝支付流程_支付宝

一、前期准备工作

首先根据支付宝官方文档拿到一些参数,主要是APPID,商户应用私钥和公钥,支付宝公钥,授权回调地址。

springboot中实现支付宝接口时不跳转 springboot支付宝支付流程_android_02


springboot中实现支付宝接口时不跳转 springboot支付宝支付流程_spring boot_03


springboot中实现支付宝接口时不跳转 springboot支付宝支付流程_后端_04


这里对于准备工作省略!

二、Springboot后端

导入依赖

<!--支付宝支付SDK-->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.21.10.ALL</version>
        </dependency>
WxPayController
/**
     * 支付宝下单
     * @return
     * @throws Exception
     */
    @ApiOperation("调用统一下单API,生成支付宝下单的请求")
    @PostMapping("/alipay/order")
    public R AliPay() throws Exception {

        log.info("发起支付宝支付请求 Alipay");

        //返回支付所需要的参数给Android端
        String resultdata = wxPayService.aliPay();
        log.info("map====>{}",resultdata);
        return R.ok().data("result",resultdata);
    }

/**
     * 支付宝支付通知
     * 微信支付通过支付通知接口将用户支付成功消息通知给商户
     */
    @ApiOperation("支付通知")
    @PostMapping("/app/alinotify")
    public String AliNotify(HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {

//获取支付宝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);
        }

//异步验签:切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
//公钥证书模式验签,alipayPublicCertPath是支付宝公钥证书引用路径地址,需在对应应用中下载
//boolean signVerified= AlipaySignature.rsaCertCheckV1(params, alipayPublicCertPath, "GBK","RSA2");
//普通公钥模式验签,切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
        boolean flag = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, "UTF-8","RSA2");

/* 实际验证过程建议商户务必添加以下校验:
    1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
    2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
    3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
    4、验证app_id是否为该商户本身。
    */
        if(flag) {//验证成功
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //交易状态
            String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");

            if(trade_status.equals("TRADE_FINISHED")){
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
                //如果有做过处理,不执行商户的业务程序

                //注意:
                //退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
            }else if (trade_status.equals("TRADE_SUCCESS")){
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
                //如果有做过处理,不执行商户的业务程序

                //注意:
                //付款完成后,支付宝系统发送该交易状态通知
            }

            System.out.println("success");
        }else {//验证失败
            System.out.println("fail");
        }
        return null;

    }

    /**
     * 支付宝查单
     * @param orderNo
     * @param
     * @return
     * @throws Exception
     */
    @ApiOperation("支付宝查单")
    @GetMapping("/queryali/{orderNo}")//也可以用微信的订单号查询
    public R queryAliOrder(@PathVariable String orderNo) throws Exception {

        log.info("查询支付宝订单");
        String result = wxPayService.queryAliOrder(orderNo);
        return R.ok().setMessage("查询成功").data("result", result);

    }
WxPayService
/**
     * 支付宝支付
     * @return
     */
    String aliPay() throws AlipayApiException;

    /**
     * 支付宝查单
     * @param orderNo
     * @param
     * @return
     */
    String queryAliOrder(String orderNo) throws AlipayApiException;
WxPayServiceImpl
/**
     * 支付宝支付
     * @return
     */
    @Override
    public String aliPay() throws AlipayApiException {

            /** 支付宝网关 **/
            String URL = "https://openapi.alipay.com/gateway.do";

            /** 应用id,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/
            String APP_ID = "写自己的";

            /** 应用私钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
            String APP_PRIVATE_KEY = "写自己的";

            /** 支付宝公钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602487431 **/
            String ALIPAY_PUBLIC_KEY = "写自己的";

            /** 初始化 **/
            AlipayClient alipayClient = new DefaultAlipayClient(URL,APP_ID,APP_PRIVATE_KEY,"json","UTF-8",ALIPAY_PUBLIC_KEY,"RSA2");

            /** 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称: alipay.trade.app.pay(app 支付接口) **/
            AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();

            /** 设置业务参数 **/
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();

            /** 商户订单号,商户自定义,需保证在商户端不重复,如:20200612000001 **/
            model.setOutTradeNo(OrderNoUtils.getOrderNo());

            /** 订单标题 **/
            model.setSubject("whq烤肉byali");

            /** 销售产品码,固定值:QUICK_MSECURITY_PAY **/
            model.setProductCode("QUICK_MSECURITY_PAY");

            /** 订单金额,精确到小数点后两位 **/
            model.setTotalAmount("0.01");

            /** 订单描述 **/
            model.setBody("订单描述");

            /** 业务扩展参数 **/
            //ExtendParams extendParams = new ExtendParams();

            /** 花呗分期参数传值前提:必须有该接口花呗收款准入条件,且需签约花呗分期 **/
            /** 指定可选期数,只支持3/6/12期,还款期数越长手续费越高 **/
            // extendParams.setHbFqNum("3");

            /** 指定花呗分期手续费承担方式,手续费可以由用户全承担(该值为0),也可以商户全承担(该值为100),但不可以共同承担,即不可取0和100外的其他值。 **/
            //extendParams.setHbFqSellerPercent("0");

            //model.setExtendParams(extendParams);

            /** 将业务参数传至request中 **/
            request.setBizModel(model);

            /** 异步通知地址,以http或者https开头的,商户外网可以post访问的异步地址,用于接收支付宝返回的支付结果,如果未收到该通知可参考该文档进行确认:https://opensupport.alipay.com/support/helpcenter/193/201602475759 **/
            request.setNotifyUrl("写自己的");

            /**第三方调用(服务商模式),传值app_auth_token后,会收款至授权token对应商家账号,如何获传值app_auth_token请参考文档:https://opensupport.alipay.com/support/helpcenter/79/201602494631 **/
            //request.putOtherTextParam("app_auth_token", "传入获取到的app_auth_token值");

            AlipayTradeAppPayResponse response = null;
            try {

                /** 通过alipayClient调用API,获得对应的response类  **/
                response = alipayClient.sdkExecute(request);

            } catch (AlipayApiException e) {

                e.printStackTrace();
            }

            /** response.getBody()打印结果就是orderString,可以直接给客户端请求,无需再做处理。 如果传值客户端失败,可根据返回错误信息到该文档寻找排查方案:https://opensupport.alipay.com/support/helpcenter/89 **/
            System.out.println(response.getBody());

        return response.getBody();
    }

/**
     * 支付宝查单
     * @param orderNo
     * @param
     * @return
     */
    @Override
    public String queryAliOrder(String orderNo) throws AlipayApiException {
          /** 支付宝网关 **/
        String URL = "https://openapi.alipay.com/gateway.do";

		String APP_ID = "写自己的";
		
        /** 应用私钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
        String APP_PRIVATE_KEY = "写自己的";

        /** 支付宝公钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602487431 **/
        String ALIPAY_PUBLIC_KEY = "写自己的";

        AlipayClient alipayClient = new DefaultAlipayClient(URL ,APP_ID ,APP_PRIVATE_KEY,"json","UTF-8",ALIPAY_PUBLIC_KEY,"RSA2");
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", orderNo);
//bizContent.put("trade_no", "2014112611001004680073956707");
        request.setBizContent(bizContent.toString());
        AlipayTradeQueryResponse response = alipayClient.execute(request);
        log.info("明文数据 ===> {}", response.getBody());
        if(response.isSuccess()){
            System.out.println("调用成功");
        } else {
            System.out.println("调用失败");
        }
        return response.getBody();
    }

在这里也可以将申请到的参数放在配置文件中,我测试时直接写在代码中了。

三、Android端

Android端按照文档导入SDK。下面直接放代码

springboot中实现支付宝接口时不跳转 springboot支付宝支付流程_后端_05


springboot中实现支付宝接口时不跳转 springboot支付宝支付流程_spring boot_06

PayResult
public class PayResult {
	private String resultStatus;
	private String result;
	private String memo;

	public PayResult(Map<String, String> rawResult) {
		if (rawResult == null) {
			return;
		}

		for (String key : rawResult.keySet()) {
			if (TextUtils.equals(key, "resultStatus")) {
				resultStatus = rawResult.get(key);
			} else if (TextUtils.equals(key, "result")) {
				result = rawResult.get(key);
			} else if (TextUtils.equals(key, "memo")) {
				memo = rawResult.get(key);
			}
		}
	}

	@Override
	public String toString() {
		return "resultStatus={" + resultStatus + "};memo={" + memo
				+ "};result={" + result + "}";
	}

	/**
	 * @return the resultStatus
	 */
	public String getResultStatus() {
		return resultStatus;
	}

	/**
	 * @return the memo
	 */
	public String getMemo() {
		return memo;
	}

	/**
	 * @return the result
	 */
	public String getResult() {
		return result;
	}
}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".WeChatPay">

    <Button
        android:id="@+id/wechatpay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="微信支付"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.501"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.322" />

    <Button
        android:id="@+id/aliPay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="支付宝支付"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.501"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/wechatpay"
        app:layout_constraintVertical_bias="0.197" />
</android.support.constraint.ConstraintLayout>
WeChatPay
public class WeChatPay extends AppCompatActivity {
    private Button wechatpay;
    private Button Alipay;

//    private final IWXAPI msgApi = WXAPIFactory.createWXAPI(this, null);
    private IWXAPI msgApi;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_we_chat_pay);
        wechatpay = findViewById(R.id.wechatpay);
        Alipay = findViewById(R.id.aliPay);

        //初始化操作
        msgApi = WXAPIFactory.createWXAPI(this, null);
        msgApi.registerApp(Constants.APP_ID);

        wechatpay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getWeChatPayData();
            }
        });

        Alipay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getAliPayData();
            }
        });


    }


    private void getWeChatPayData(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                MediaType JSON = MediaType.parse("application/json;charset=utf-8");
                JSONObject jsonObject = new JSONObject();
                //创建OkHttp对象
                OkHttpClient httpClient = new OkHttpClient();
                try {
//                    jsonObject.put("productId",1);
                    RequestBody requestBody = RequestBody.create(JSON, String.valueOf(jsonObject));
                    String url = "写自己的";
                    Request request = new Request.Builder()
                            .url(url)
                            .post(requestBody)
                            .build();

                    //发送请求获取返回数据
                    Response response = httpClient.newCall(request).execute();
                    Log.d("WcChatPay","请求APP下单");
                    //处理返回的数据
                    String resData = response.body().string();
                    Message message = new Message();
                    message.what = 1;
                    message.obj = resData;
                    wechathandeler.sendMessage(message);
                }catch (Exception e){
                    e.printStackTrace();
                }


            }
        }).start();
    }

    private void getAliPayData(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                MediaType JSON = MediaType.parse("application/json;charset=utf-8");
                JSONObject jsonObject = new JSONObject();
                //创建OkHttp对象
                OkHttpClient httpClient = new OkHttpClient();
                try {
//                    jsonObject.put("productId",1);
                    RequestBody requestBody = RequestBody.create(JSON, String.valueOf(jsonObject));
                    String url = "写自己的";
                    Request request = new Request.Builder()
                            .url(url)
                            .post(requestBody)
                            .build();

                    //发送请求获取返回数据
                    Response response = httpClient.newCall(request).execute();
                    Log.d("AliPay","请求APP下单");
                    //处理返回的数据
                    String resData = response.body().string();
                    Message message = new Message();
                    message.what = 2;
                    message.obj = resData;
                    wechathandeler.sendMessage(message);
                }catch (Exception e){
                    e.printStackTrace();
                }


            }
        }).start();
    }

    /**
     * 支付宝支付
     * @param orderInfo
     */
    private void AliPay(String orderInfo) {
        Runnable payRunnable = new Runnable() {
            @Override
            public void run() {
                PayTask alipay = new PayTask(WeChatPay.this);
                Map<String, String> result = alipay.payV2(orderInfo, true);
                Message msg = new Message();
                msg.what = 3;
                msg.obj = result;
                wechathandeler.sendMessage(msg);
            }
        };
        // 必须异步调用
        Thread payThread = new Thread(payRunnable);
        payThread.start();
    }


    @SuppressLint("HandlerLeak")
    Handler wechathandeler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 1:
                    //微信

                    try {
                        JSONObject jsonObject = new JSONObject(msg.obj.toString());
                        JSONObject resultData = new JSONObject(jsonObject.getString("data"));
//                        JSONObject resultData = data.getJSONObject("result");
                        String appid = resultData.getString("appid");
                        String partnerid = resultData.getString("partnerid");
                        String noncestr = resultData.getString("noncestr");
                        String packagevalue = resultData.getString("packagevalue");
                        String prepayid = resultData.getString("prepayid");
                        String sign = resultData.getString("sign");
                        String timestamp = resultData.getString("timestamp");

                        //调起支付
                        PayReq request = new PayReq();
                        request.appId = Constants.APP_ID;
                        request.partnerId = partnerid;
                        request.prepayId = prepayid;
                        request.packageValue = packagevalue;
                        request.nonceStr = noncestr;
                        request.timeStamp = timestamp;
                        request.sign = sign;
                        Log.d("WcChatPay","sign====>"+sign);
                        msgApi.sendReq(request);
                        Log.d("WcChatPay","调起支付");


                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    break;
                case 2:
                    try {
                        JSONObject jsonObject = new JSONObject(msg.obj.toString());
                        String paydata =  jsonObject.getString("data");
                        JSONObject returndata = new JSONObject(paydata);
                        String resultdata =  returndata.getString("result");
                        AliPay(resultdata);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    break;
                case 3:
                    PayResult payResult = new PayResult((Map<String, String>) msg.obj);
                    /**
                     * 对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
                     */
                    String resultStatus = payResult.getResultStatus();
                    // 判断resultStatus 为9000则代表支付成功
                    if (TextUtils.equals(resultStatus, "9000")) {
                        // 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
                        Toast.makeText(WeChatPay.this,"支付成功",Toast.LENGTH_LONG).show();
                        Log.d("AliPay","支付成功"+payResult);
                    } else {
                        // 该笔订单真实的支付结果,需要依赖服务端的异步通知。
                        Toast.makeText(WeChatPay.this,"支付失败",Toast.LENGTH_LONG).show();
                        Log.d("AliPay","支付失败"+payResult);
                    }
            }
        }
    };

}

四、测试

springboot中实现支付宝接口时不跳转 springboot支付宝支付流程_后端_07


springboot中实现支付宝接口时不跳转 springboot支付宝支付流程_java_08


springboot中实现支付宝接口时不跳转 springboot支付宝支付流程_java_09