支付宝APP支付-JAVA

版权声明: https://blog.csdn.net/asd54090/article/details/81027510

做了许多微信、支付宝支付,却没写记录,尴尬,今天记录下。

要点:

  • 直接去支付宝下支付接入demo,引入到IDE中
  • 选择自己业务需要的功能接入
  • 蚂蚁开放平台的回调地址要与支付调用时传入的地址一致

直接撸代码

目录结构:
以下是我的目录及所用到的模块
这里写图片描述

Maven:

<!-- 阿里支付sdk alipay-sdk-java -->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>3.0.0</version>
        </dependency>

ALiOrderInfoUtil2:

package com.hakj.express.utils.alipayutils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;

/**
 *
 */
public class ALiOrderInfoUtil2 {

    /**
     * 构造授权参数列表
     *
     * @return
     */
    public static Map<String, String> buildAuthInfoMap(boolean rsa2) {
        Map<String, String> keyValues = new HashMap<String, String>();

        // 商户签约拿到的app_id,如:2013081700024223
        keyValues.put("app_id", ALiPayConfig.APPID);

        // 商户签约拿到的pid,如:2088102123816631
        keyValues.put("pid", ALiPayConfig.PID);

        // 服务接口名称, 固定值
        keyValues.put("apiname", "com.alipay.account.auth");

        // 商户类型标识, 固定值
        keyValues.put("app_name", "mc");

        // 业务类型, 固定值
        keyValues.put("biz_type", "openservice");

        // 产品码, 固定值
        keyValues.put("product_id", "APP_FAST_LOGIN");

        // 授权范围, 固定值
        keyValues.put("scope", "kuaijie");

        // 商户唯一标识,如:kkkkk091125
//        keyValues.put("target_id", target_id);

        // 授权类型, 固定值
        keyValues.put("auth_type", "AUTHACCOUNT");

        // 签名类型
        keyValues.put("sign_type", rsa2 ? "RSA2" : "RSA");

        return keyValues;
    }

    /**
     * 构造支付订单参数列表
     *
     * @return 返回未签名的共有参数
     */
    public static Map<String, String> buildOrderParamMap(double price, String openid, String orderName, String orderType) {

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Map<String, String> keyValues = new HashMap<String, String>();

        keyValues.put("app_id", ALiPayConfig.APPID);

        keyValues.put("biz_content",
                "{\"timeout_express\":\"30m\"," +
                        "\"product_code\":\"QUICK_MSECURITY_PAY\"," +
                        "\"total_amount\":\"" + price + "\"," +
                        "\"subject\":\""+orderName+"\"," +
                        "\"body\":\""+orderType+"\"," +
                        "\"out_trade_no\":\"" + openid + "\"}");

        keyValues.put("charset", ALiPayConfig.input_charset);

        keyValues.put("method", "alipay.trade.app.pay");

        keyValues.put("sign_type", ALiPayConfig.sign_type);

        String format = simpleDateFormat.format(new Date());
        keyValues.put("timestamp", format);

        keyValues.put("notify_url", ALiPayConfig.notify_url);

        keyValues.put("version", "1.0");

        return keyValues;
    }

    /**
     * 构造支付订单参数信息
     *
     * @param map 支付订单参数
     * @return
     */
    public static String buildOrderParam(Map<String, String> map) {
        List<String> keys = new ArrayList<String>(map.keySet());

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keys.size() - 1; i++) {
            String key = keys.get(i);
            String value = map.get(key);
            sb.append(buildKeyValue(key, value, true));
            sb.append("&");
        }

        String tailKey = keys.get(keys.size() - 1);
        String tailValue = map.get(tailKey);
        sb.append(buildKeyValue(tailKey, tailValue, true));

        return sb.toString();
    }

    /**
     * 拼接键值对
     *
     * @param key
     * @param value
     * @param isEncode
     * @return
     */
    private static String buildKeyValue(String key, String value, boolean isEncode) {
        StringBuilder sb = new StringBuilder();
        sb.append(key);
        sb.append("=");
        if (isEncode) {
            try {
                sb.append(URLEncoder.encode(value, "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                sb.append(value);
            }
        } else {
            sb.append(value);
        }
        return sb.toString();
    }

    /**
     * 对支付参数信息进行签名
     *
     * @param map 待签名授权信息
     * @return
     */
    public static String getSign(Map<String, String> map) {
        List<String> keys = new ArrayList<String>(map.keySet());
        // key排序
        Collections.sort(keys);

        StringBuilder authInfo = new StringBuilder();
        for (int i = 0; i < keys.size() - 1; i++) {
            String key = keys.get(i);
            String value = map.get(key);
            authInfo.append(buildKeyValue(key, value, false));
            authInfo.append("&");
        }

        String tailKey = keys.get(keys.size() - 1);
        String tailValue = map.get(tailKey);
        authInfo.append(buildKeyValue(tailKey, tailValue, false));

        boolean rsa2 = ALiPayConfig.sign_type.equals("RSA2");
        String oriSign = AliSignUtils.sign(authInfo.toString(), ALiPayConfig.private_key, rsa2);
        String encodedSign = "";

        try {
            encodedSign = URLEncoder.encode(oriSign, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "sign=" + encodedSign;
    }

    /**
     * 要求外部订单号必须唯一。
     *
     * @return
     */
    private static String getOutTradeNo() {
        SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
        Date date = new Date();
        String key = format.format(date);

        Random r = new Random();
        key = key + r.nextInt();
        key = key.substring(0, 15);
        return key;
    }

}

ALiPayConfig:

package com.hakj.express.utils.alipayutils;

/**
 * Description:
 * Author:THP
 * Date:2018/05/09 15:38
 */
public class ALiPayConfig {

    // 合作身份者ID,以2088开头由16位纯数字组成的字符串
    public static String partner = "2088*********4";

    // 6.请求网关地址
    public static String URL = "https://openapi.alipay.com/gateway.do";

    public static String service = "mobile.securitypay.pay";//固定值

    public static String seller_id = "*******@163.com";
    //私钥
    public static String private_key = "***";
    // 商户的公钥钥
    public static String public_key = "***";
    // 支付宝的公钥,无需修改该值(不要删除也不要修改,在接收通知的时候需要进行签名认证)
    public static String ali_public_key = "***";

    // 字符编码格式 目前支持 gbk 或 utf-8
    public static String input_charset = "UTF-8";
    // 签名方式 不需修改
    public static String sign_type = "RSA2";

    //APPID
    public static String APPID = "***";
    //合作伙伴身份(PID)
    public static String PID = "***";

    //支付宝回调地址   要与蚂蚁开放平台回调地址一致,否则不回调
    public static String notify_url = "http://****/ali-pay/callback";

    // 8.返回格式
    public static String FORMAT = "json";
}

ALiPayUtil:

package com.hakj.express.utils.alipayutils;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.hakj.express.service.impl.UserConfigServiceimpl;
import lombok.extern.log4j.Log4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.util.Map;

/**
 * Description:支付宝支付工具类
 * Author:THP
 * Date:2018/05/07 15:17
 */
@Log4j
@Component
public class ALiPayUtil {
    //业务服务
    @Resource
    private UserConfigServiceimpl configService;

    /**
     * 支付宝下单
     *
     * @param goodsInfo   商品信息
     * @param goodsName   商品名
     * @param amount      金额
     * @param orderNumber 订单编号
     */
    @Deprecated
    public void pay(String goodsInfo, String goodsName, String amount, String orderNumber) {
        //实例化客户端
//        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2");
        AlipayClient alipayClient = new DefaultAlipayClient(ALiPayConfig.URL, ALiPayConfig.APPID, ALiPayConfig.private_key, ALiPayConfig.FORMAT, ALiPayConfig.input_charset, ALiPayConfig.ali_public_key, ALiPayConfig.sign_type);
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(goodsInfo);//商品信息
        model.setSubject(goodsName);// 商品名称
//        model.setOutTradeNo(outtradeno);
        model.setOutTradeNo(orderNumber); // 商户订单号
        model.setTimeoutExpress("30m");//支付超时时间
        model.setTotalAmount(amount);// 支付金额
//        model.setProductCode("QUICK_MSECURITY_PAY");// 销售产品码
        request.setBizModel(model);
        request.setNotifyUrl(ALiPayConfig.notify_url);// 回调地址
        try {
            //这里和普通的接口调用不同,使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            System.out.println(response.getBody());//就是orderString 可以直接给客户端请求,无需再做处理。
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
    }

    /**
     * 支付宝退款
     *
     * @param out_trade_no  订单支付时传入的商户订单号,不能和 trade_no同时为空。
     * @param trade_no      支付宝交易号,和商户订单号不能同时为空
     * @param refund_amount 需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数
     */
    public String alipayRefundRequest(String out_trade_no, String trade_no, double refund_amount) {
        // 发送请求
        String strResponse = null;
        AlipayClient alipayClient = new DefaultAlipayClient(ALiPayConfig.URL, ALiPayConfig.APPID, ALiPayConfig.private_key, ALiPayConfig.FORMAT, ALiPayConfig.input_charset, ALiPayConfig.ali_public_key, ALiPayConfig.sign_type);
        try {
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
//            AlipayRefundInfo alidata = new AlipayRefundInfo();
//            alidata.setOut_trade_no(out_trade_no);
//            alidata.setRefund_amount(refund_amount);
//            alidata.setTrade_no(trade_no);


            DecimalFormat df = new DecimalFormat("0.00");
            refund_amount *= configService.queryRate();
            String sa = df.format(refund_amount);
            refund_amount = Double.parseDouble(sa);

            request.setBizContent("{" +
                    "\"out_trade_no\":\"" + out_trade_no + "\"," +
                    "\"trade_no\":\"" + trade_no + "\"," +
                    "\"refund_amount\":" + refund_amount + "," +
                    "\"refund_reason\":\"正常退款\"," +
                    "\"out_request_no\":\"HZ01RF001\"" +
                    "  }");
            AlipayTradeRefundResponse response = alipayClient.execute(request);
            strResponse = response.getCode();
            if ("10000".equals(response.getCode())) {
                strResponse = "退款成功";
            } else {
                strResponse = response.getSubMsg();
            }
        } catch (Exception e) {
            log.error("alipayRefundRequest", e);
        }
        return strResponse;

    }


    /**
     * 余额提现
     *
     * @param orderNo 商户订单号
     * @param aliCode 支付宝账号
     * @param name    收款人姓名
     * @param amount  金额
     * @return 成功失败
     */
    public AlipayFundTransToaccountTransferResponse withDrawDeposit(String orderNo, String aliCode, String name, String amount) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(ALiPayConfig.URL, ALiPayConfig.APPID, ALiPayConfig.private_key, ALiPayConfig.FORMAT, ALiPayConfig.input_charset, ALiPayConfig.ali_public_key, ALiPayConfig.sign_type);
        AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest();
        DecimalFormat df = new DecimalFormat("#.00");
        double am = Double.parseDouble(amount);
        am *= configService.queryRate();
        amount = df.format(am);
        request.setBizContent("{" +
                "\"out_biz_no\":\"" + orderNo + "\"," +
                "\"payee_type\":\"ALIPAY_LOGONID\"," +
                "\"payee_account\":\"" + aliCode + "\"," +
                "\"amount\":\"" + amount + "\"," +
                "\"payer_show_name\":\"展示的短内容\"," +
                "\"payee_real_name\":\"" + name + "\"," +
                "\"remark\":\"这里是内容\"" +
                "}");
        AlipayFundTransToaccountTransferResponse response = alipayClient.execute(request);
//        if (response.isSuccess()) {
//            System.out.println("成功");
//        } else {
//            System.out.println("失败");
//        }
        return response;
    }

    /**
     * 查支付宝订单信息
     *
     * @param orderNo    商家订单号
     * @param AliOrderNo 支付宝订单号
     * @throws AlipayApiException
     */
    public String queryAliOrderInfo(String orderNo, String AliOrderNo) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(ALiPayConfig.URL, ALiPayConfig.APPID, ALiPayConfig.private_key, ALiPayConfig.FORMAT, ALiPayConfig.input_charset, ALiPayConfig.ali_public_key, ALiPayConfig.sign_type);
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        request.setBizContent("{" +
                "\"out_trade_no\":\"" + orderNo + "\"," +
                "\"trade_no\":\"" + AliOrderNo + "\"" +
                "  }");
        AlipayTradeQueryResponse response = alipayClient.execute(request);
        if (response.isSuccess()) {
            System.out.println("调用成功");
        } else {
            System.out.println("调用失败");
        }
        return response.toString();
    }

    /**
     * 签名
     *
     * @param price     价格
     * @param openid    商户订单号
     * @param orderName 订单名
     * @param orderType 订单类型 (业务需要)
     * @return 订单签名后的数据
     */
    public String getOrderInfo(double price, String openid, String orderName, String orderType) {
        DecimalFormat df = new DecimalFormat("#.00");
        price *= configService.queryRate();
        String sa = df.format(price);
        price = Double.parseDouble(sa);
        Map<String, String> params = ALiOrderInfoUtil2.buildOrderParamMap(price, openid, orderName, orderType);
        String orderParam = ALiOrderInfoUtil2.buildOrderParam(params);
        String sign = ALiOrderInfoUtil2.getSign(params);
        return orderParam + "&" + sign;
    }

}

AliRSA:

package com.hakj.express.utils.alipayutils;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * Description:
 * Author:THP
 * Date:2018/05/17 10:09
 */
public class AliRSA {
    public static final String SIGN_ALGORITHMS = "SHA1WithRSA";

    /**
     * RSA签名
     *
     * @param content       待签名数据
     * @param privateKey    商户私钥
     * @param input_charset 编码格式
     * @return 签名值
     */
    public static String sign(String content, String privateKey, String input_charset) {
        try {
            byte[] decode = new Base64().decode(privateKey);
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(decode);
            KeyFactory keyf = KeyFactory.getInstance("RSA");
            PrivateKey priKey = keyf.generatePrivate(priPKCS8);

            java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);

            signature.initSign(priKey);
            signature.update(content.getBytes(input_charset));

            byte[] signed = signature.sign();

            return new String(new Base64().encode(signed));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * RSA验签名检查
     *
     * @param content        待签名数据
     * @param sign           签名值
     * @param ali_public_key 支付宝公钥
     * @param input_charset  编码格式
     * @return 布尔值
     */
    public static boolean verify(String content, String sign, String ali_public_key, String input_charset) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] encodedKey = new Base64().decode(ali_public_key);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
            java.security.Signature signature = java.security.Signature
                    .getInstance(SIGN_ALGORITHMS);

            signature.initVerify(pubKey);
            signature.update(content.getBytes(input_charset));

            boolean bverify = signature.verify(new Base64().decode(sign));
            return bverify;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    /**
     * 解密
     *
     * @param content       密文
     * @param private_key   商户私钥
     * @param input_charset 编码格式
     * @return 解密后的字符串
     */
    public static String decrypt(String content, String private_key, String input_charset) throws Exception {
        PrivateKey prikey = getPrivateKey(private_key);

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, prikey);

        InputStream ins = new ByteArrayInputStream(new Base64().decode(content));
        ByteArrayOutputStream writer = new ByteArrayOutputStream();
        //rsa解密的字节大小最多是128,将需要解密的内容,按128位拆开解密
        byte[] buf = new byte[128];
        int bufl;

        while ((bufl = ins.read(buf)) != -1) {
            byte[] block = null;

            if (buf.length == bufl) {
                block = buf;
            } else {
                block = new byte[bufl];
                for (int i = 0; i < bufl; i++) {
                    block[i] = buf[i];
                }
            }

            writer.write(cipher.doFinal(block));
        }

        return new String(writer.toByteArray(), input_charset);
    }


    /**
     * 得到私钥
     *
     * @param key 密钥字符串(经过base64编码)
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String key) throws Exception {

        byte[] keyBytes;

        keyBytes = new Base64().decode(key);

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        return privateKey;
    }
}

AliSignUtils:

package com.hakj.express.utils.alipayutils;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;

/**
 * Description:
 * Author:THP
 * Date:2018/05/17 13:22
 */
public class AliSignUtils {
    private static final String ALGORITHM = "RSA";

    private static final String SIGN_ALGORITHMS = "SHA1WithRSA";

    private static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA";

    private static final String DEFAULT_CHARSET = "UTF-8";


    private static String getAlgorithms(boolean rsa2) {
        return rsa2 ? SIGN_SHA256RSA_ALGORITHMS : SIGN_ALGORITHMS;
    }

    public static String sign(String content, String privateKey, boolean rsa2) {
        try {
            Security.addProvider(new BouncyCastleProvider());
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
                    Base64.decode(privateKey));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM, "BC");
            PrivateKey priKey = keyFactory.generatePrivate(priPKCS8);

            java.security.Signature signature = java.security.Signature
                    .getInstance(getAlgorithms(rsa2));

            signature.initSign(priKey);
            signature.update(content.getBytes(DEFAULT_CHARSET));

            byte[] signed = signature.sign();

            return Base64.encode(signed);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

}

Base64:

package com.hakj.express.utils.alipayutils;

/**
 * Description:Base64加密
 * Author:THP
 * Date:2018/05/17 13:23
 */
public class Base64 {
    private static final int BASELENGTH = 128;
    private static final int LOOKUPLENGTH = 64;
    private static final int TWENTYFOURBITGROUP = 24;
    private static final int EIGHTBIT = 8;
    private static final int SIXTEENBIT = 16;
    private static final int FOURBYTE = 4;
    private static final int SIGN = -128;
    private static char PAD = '=';
    private static byte[] base64Alphabet = new byte[BASELENGTH];
    private static char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];

    static {
        for (int i = 0; i < BASELENGTH; ++i) {
            base64Alphabet[i] = -1;
        }
        for (int i = 'Z'; i >= 'A'; i--) {
            base64Alphabet[i] = (byte) (i - 'A');
        }
        for (int i = 'z'; i >= 'a'; i--) {
            base64Alphabet[i] = (byte) (i - 'a' + 26);
        }

        for (int i = '9'; i >= '0'; i--) {
            base64Alphabet[i] = (byte) (i - '0' + 52);
        }

        base64Alphabet['+'] = 62;
        base64Alphabet['/'] = 63;

        for (int i = 0; i <= 25; i++) {
            lookUpBase64Alphabet[i] = (char) ('A' + i);
        }

        for (int i = 26, j = 0; i <= 51; i++, j++) {
            lookUpBase64Alphabet[i] = (char) ('a' + j);
        }

        for (int i = 52, j = 0; i <= 61; i++, j++) {
            lookUpBase64Alphabet[i] = (char) ('0' + j);
        }
        lookUpBase64Alphabet[62] = (char) '+';
        lookUpBase64Alphabet[63] = (char) '/';

    }

    private static boolean isWhiteSpace(char octect) {
        return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
    }

    private static boolean isPad(char octect) {
        return (octect == PAD);
    }

    private static boolean isData(char octect) {
        return (octect < BASELENGTH && base64Alphabet[octect] != -1);
    }

    /**
     * Encodes hex octects into Base64
     *
     * @param binaryData
     *            Array containing binaryData
     * @return Encoded Base64 array
     */
    public static String encode(byte[] binaryData) {

        if (binaryData == null) {
            return null;
        }

        int lengthDataBits = binaryData.length * EIGHTBIT;
        if (lengthDataBits == 0) {
            return "";
        }

        int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
        int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
        int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1
                : numberTriplets;
        char encodedData[] = null;

        encodedData = new char[numberQuartet * 4];

        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;

        int encodedIndex = 0;
        int dataIndex = 0;

        for (int i = 0; i < numberTriplets; i++) {
            b1 = binaryData[dataIndex++];
            b2 = binaryData[dataIndex++];
            b3 = binaryData[dataIndex++];

            l = (byte) (b2 & 0x0f);
            k = (byte) (b1 & 0x03);

            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
                    : (byte) ((b1) >> 2 ^ 0xc0);
            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
                    : (byte) ((b2) >> 4 ^ 0xf0);
            byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
                    : (byte) ((b3) >> 6 ^ 0xfc);

            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
        }

        // form integral number of 6-bit groups
        if (fewerThan24bits == EIGHTBIT) {
            b1 = binaryData[dataIndex];
            k = (byte) (b1 & 0x03);

            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
                    : (byte) ((b1) >> 2 ^ 0xc0);
            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
            encodedData[encodedIndex++] = PAD;
            encodedData[encodedIndex++] = PAD;
        } else if (fewerThan24bits == SIXTEENBIT) {
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex + 1];
            l = (byte) (b2 & 0x0f);
            k = (byte) (b1 & 0x03);

            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
                    : (byte) ((b1) >> 2 ^ 0xc0);
            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
                    : (byte) ((b2) >> 4 ^ 0xf0);

            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
            encodedData[encodedIndex++] = PAD;
        }

        return new String(encodedData);
    }

    /**
     * Decodes Base64 data into octects
     *
     * @param encoded
     *            string containing Base64 data
     * @return Array containind decoded data.
     */
    public static byte[] decode(String encoded) {

        if (encoded == null) {
            return null;
        }

        char[] base64Data = encoded.toCharArray();
        // remove white spaces
        int len = removeWhiteSpace(base64Data);

        if (len % FOURBYTE != 0) {
            return null;// should be divisible by four
        }

        int numberQuadruple = (len / FOURBYTE);

        if (numberQuadruple == 0) {
            return new byte[0];
        }

        byte decodedData[] = null;
        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
        char d1 = 0, d2 = 0, d3 = 0, d4 = 0;

        int i = 0;
        int encodedIndex = 0;
        int dataIndex = 0;
        decodedData = new byte[(numberQuadruple) * 3];

        for (; i < numberQuadruple - 1; i++) {

            if (!isData((d1 = base64Data[dataIndex++]))
                    || !isData((d2 = base64Data[dataIndex++]))
                    || !isData((d3 = base64Data[dataIndex++]))
                    || !isData((d4 = base64Data[dataIndex++]))) {
                return null;
            }// if found "no data" just return null

            b1 = base64Alphabet[d1];
            b2 = base64Alphabet[d2];
            b3 = base64Alphabet[d3];
            b4 = base64Alphabet[d4];

            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
        }

        if (!isData((d1 = base64Data[dataIndex++]))
                || !isData((d2 = base64Data[dataIndex++]))) {
            return null;// if found "no data" just return null
        }

        b1 = base64Alphabet[d1];
        b2 = base64Alphabet[d2];

        d3 = base64Data[dataIndex++];
        d4 = base64Data[dataIndex++];
        if (!isData((d3)) || !isData((d4))) {// Check if they are PAD characters
            if (isPad(d3) && isPad(d4)) {
                if ((b2 & 0xf) != 0)// last 4 bits should be zero
                {
                    return null;
                }
                byte[] tmp = new byte[i * 3 + 1];
                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
                tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
                return tmp;
            } else if (!isPad(d3) && isPad(d4)) {
                b3 = base64Alphabet[d3];
                if ((b3 & 0x3) != 0)// last 2 bits should be zero
                {
                    return null;
                }
                byte[] tmp = new byte[i * 3 + 2];
                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
                tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
                tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
                return tmp;
            } else {
                return null;
            }
        } else { // No PAD e.g 3cQl
            b3 = base64Alphabet[d3];
            b4 = base64Alphabet[d4];
            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);

        }

        return decodedData;
    }

    /**
     * remove WhiteSpace from MIME containing encoded Base64 data.
     *
     * @param data
     *            the byte array of base64 data (with WS)
     * @return the new length
     */
    private static int removeWhiteSpace(char[] data) {
        if (data == null) {
            return 0;
        }

        // count characters that's not whitespace
        int newSize = 0;
        int len = data.length;
        for (int i = 0; i < len; i++) {
            if (!isWhiteSpace(data[i])) {
                data[newSize++] = data[i];
            }
        }
        return newSize;
    }

}

回调
payCallback:

package com.hakj.express.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.hakj.express.utils.OrderUtil;
import com.hakj.express.utils.alipayutils.ALiPayConfig;
import com.hakj.express.utils.alipayutils.ALiPayUtil;
import lombok.Data;
import lombok.extern.log4j.Log4j;
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 javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * Description: 支付宝支付处理接口
 * Author:THP
 * Date:2018/05/07 15:27
 */
@Log4j
@RestController
public class ALiPayController {

    @Resource
    private ALiPayUtil aLiPayUtil;
    @Resource
    private OrderUtil orderUtil;

    /**
     * 支付回调
     *
     * @param request
     * @throws Exception
     */
    @RequestMapping("/ali-pay/callback")
    public String payCallback(HttpServletRequest request) throws Exception {
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<>();
        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);
        }
        //封装必须参数
        String out_trade_no = request.getParameter("out_trade_no"); // 商户订单号
        System.err.println("out_trade_no==================================" + out_trade_no);
        String orderType = request.getParameter("body"); // 订单内容
        System.out.println("orderType==================================" + orderType);
        //交易金额
        String totalAmount = request.getParameter("total_amount");
        //支付宝订单号
        String trade_no = request.getParameter("trade_no");
        System.err.println("trade_no=================================" + trade_no);
        String tradeStatus = request.getParameter("trade_status"); // 交易状态
        System.err.println("tradeStatus=================================" + tradeStatus);

        //切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
        boolean flag = AlipaySignature.rsaCheckV1(params, ALiPayConfig.ali_public_key, ALiPayConfig.input_charset, ALiPayConfig.sign_type);

        //对验签进行处理
        if (flag) {
            // 验签通过
            if (tradeStatus.equals("TRADE_SUCCESS")) {
                // 只处理支付成功的订单:修改交易表状态,支付成功
                //自己的业务逻辑操作
                orderUtil.upOrderState(out_trade_no, orderType, Double.parseDouble(totalAmount), 3, trade_no);
                return "success";
            }
        }
        return "";
    }

    @PostMapping("/quer-order/alipay")
    public String queryAliOrder(String orderNo, String aliOrderNo) throws AlipayApiException {
        return aLiPayUtil.queryAliOrderInfo(orderNo, aliOrderNo);
    }


    /**
     * 手动退款
     *
     * @param orderNo    商户订单号
     * @param aliOrderNo 支付宝订单号
     * @param amount     金额
     * @return 结果
     */
    @PostMapping("/ali/back")
    public String aliback(String orderNo, String aliOrderNo, double amount) {
        return aLiPayUtil.alipayRefundRequest(orderNo, aliOrderNo, amount);
    }

}

收到支付宝回调,并处理业务成功,一定要返回字符串:success
收到支付宝回调,并处理业务成功,一定要返回字符串:success
收到支付宝回调,并处理业务成功,一定要返回字符串:success
否则支付宝会认为你没收到回调或业务处理失败,每隔一段时间就发一次,具体间隔多少时间看官方文档

好了,就这么多了,应该能应对大部分需求了
至于调试,发布到远程服务器上调试不方便,可以使用内网穿透工具natapp(有免费和收费的,免费的就够用了),然后对着官方文档,足以解决90%的问题,还是不行,Google一下

希望对各位有所帮助,如有不足之处,欢迎点出!

猜你喜欢

转载自blog.csdn.net/asd54090/article/details/81027510
今日推荐