java实现支付宝支付二

前期配置准备可参考该链接文档:https://blog.csdn.net/weixin_42739916/article/details/104320830
 

1、设置支付宝环境参数,并导入支付SDK依赖

//支付宝环境参数设置
ali.pay.appId=AppID
ali.pay.appPrivateKey=应用私钥
ali.pay.publicKey=支付宝公钥
ali.pay.returnUrl=回调地址
ali.pay.notifyUrl=异步地址
ali.pay.gateway=网关(测试和正式环境的网关不同,需要注意)
ali.pay.signType=RSA2
ali.pay.charset=UTF-8
ali.pay.format=json
<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>4.8.10.ALL</version>
</dependency>

2、支付宝支付状态常量类

package com.ganguomob.dev.dsprwpt.domain.service.alipay;

import org.springframework.util.StringUtils;

/**
 * Created by luotj on 2019-08-15.
 */
public enum AliTradeStatus {

    WAIT_BUYER_PAY("WAIT_BUYER_PAY", "交易创建,等待买家付款"),
    TRADE_CLOSED("TRADE_CLOSED", "未付款交易超时关闭,或支付完成后全额退款"),
    TRADE_SUCCESS("TRADE_SUCCESS", "交易支付成功"),
    TRADE_FINISHED("TRADE_FINISHED", "交易结束,不可退款");
    private String code;
    private String msg;

    AliTradeStatus(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public static AliTradeStatus fromCode(String code) {

        if (StringUtils.pathEquals(code, WAIT_BUYER_PAY.code)) {
            return WAIT_BUYER_PAY;
        }
        if (StringUtils.pathEquals(code, TRADE_CLOSED.code)) {
            return TRADE_CLOSED;
        }
        if (StringUtils.pathEquals(code, TRADE_SUCCESS.code)) {
            return TRADE_SUCCESS;
        }
        if (StringUtils.pathEquals(code, TRADE_FINISHED.code)) {
            return TRADE_FINISHED;
        }

        throw new RuntimeException("code error");
    }
}

3、请求实体类

package com.ganguomob.dev.dsprwpt.ui.dto.request.api.alipay;

import lombok.Data;

import java.math.BigDecimal;

/**
 * @author: create by luotj
 * date: 2019-12-25 18:39
 **/
@Data
public class AliPayRequest {

    //支付金额
    private BigDecimal totalAmount;

    //客户支付编码
    private String outTradeNo;

    //订单名称
    private String subject;

    //商品描述
    private String body;

    //充值记录id
    private Long rechargeId;

    //支付方式:1.支付宝
    private Integer type;
}

4、支付宝回调响应类

package com.ganguomob.dev.dsprwpt.ui.dto.response.api.alipay;

import com.ganguomob.dev.dsprwpt.domain.service.alipay.AliTradeStatus;
import io.swagger.annotations.ApiModel;
import lombok.Data;

/**
 * @author: create by luotj
 * date: 2019-12-28 16:02
 **/
@ApiModel
@Data
public class AlipayCallbackResponse {

    // notify_time	通知时间	Date	是	通知的发送时间。格式为yyyy-MM-dd HH:mm:ss	2015-14-27 15:45:58
    private String notifyTime;

    //    notify_type	通知类型	String(64)	是	通知的类型	trade_status_sync
    private String notifyType;

    //    notify_id	通知校验ID	String(128)	是	通知校验ID	ac05099524730693a8b330c5ecf72da9786
    private String notifyId;

    //    app_id	支付宝分配给开发者的应用Id	String(32)	是	支付宝分配给开发者的应用Id	2014072300007148
    private String appId;

    //    charset	编码格式	String(10)	是	编码格式,如utf-8、gbk、gb2312等	utf-8
    private String charset;

    //    version	接口版本	String(3)	是	调用的接口版本,固定为:1.0	1.0
    private String version;

    //    sign_type	签名类型	String(10)	是	商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2	RSA2
    private String signType;

    //    sign	签名	String(256)	是	请参考文末 异步返回结果的验签	601510b7970e52cc63db0f44997cf70e
    private String sign;

    //    trade_no	支付宝交易号	String(64)	是	支付宝交易凭证号	2013112011001004330000121536
    private String tradeNo;

    //    out_trade_no	商户订单号	String(64)	是	原支付请求的商户订单号	6823789339978248
    private String outTradeNo;

    //    out_biz_no	商户业务号	String(64)	否	商户业务ID,主要是退款通知中返回退款申请的流水号	HZRF001
    private String outBizNo;

    //    buyer_id	买家支付宝用户号	String(16)	否	买家支付宝账号对应的支付宝唯一用户号。以2088开头的纯16位数字	2088102122524333
    private String buyerId;

    //    buyer_logon_id	买家支付宝账号	String(100)	否	买家支付宝账号	15901825620
    private String buyerLogonId;

    //    seller_id	卖家支付宝用户号	String(30)	否	卖家支付宝用户号	2088101106499364
    private String sellerId;

    //    seller_email	卖家支付宝账号	String(100)	否	卖家支付宝账号	[email protected]
    private String sellerEmail;

    //    trade_status	交易状态	String(32)	否	交易目前所处的状态,见下张表 交易状态说明	TRADE_CLOSED
    private AliTradeStatus tradeStatus;

    //    total_amount	订单金额	Number(9,2)	否	本次交易支付的订单金额,单位为人民币(元)	20
    private String totalAmount;

    //    receipt_amount	实收金额	Number(9,2)	否	商家在交易中实际收到的款项,单位为元	15
    private String receiptAmount;

    //    invoice_amount	开票金额	Number(9,2)	否	用户在交易中支付的可开发票的金额	10.00
    private String invoiceAmount;

    //    buyer_pay_amount	付款金额	Number(9,2)	否	用户在交易中支付的金额	13.88
    private String buyerPayAmount;

    //    point_amount	集分宝金额	Number(9,2)	否	使用集分宝支付的金额	12.00
    private String pointAmount;

    //    refund_fee	总退款金额	Number(9,2)	否	退款通知中,返回总退款金额,单位为元,支持两位小数	2.58
    private String refundFee;

    //    subject	订单标题	String(256)	否	商品的标题/交易标题/订单标题/订单关键字等,是请求时对应的参数,原样通知回来	当面付交易
    private String subject;

    //    body	商品描述	String(400)	否	该订单的备注、描述、明细等。对应请求时的body参数,原样通知回来	当面付交易内容
    private String body;

    //    gmt_create	交易创建时间	Date	否	该笔交易创建的时间。格式为yyyy-MM-dd HH:mm:ss	2015-04-27 15:45:57
    private String gmtCreate;

    //    gmt_payment	交易付款时间	Date	否	该笔交易的买家付款时间。格式为yyyy-MM-dd HH:mm:ss	2015-04-27 15:45:57
    private String gmtPayment;

    //    gmt_refund	交易退款时间	Date	否	该笔交易的退款时间。格式为yyyy-MM-dd HH:mm:ss.S	2015-04-28 15:45:57.320
    private String gmtRefund;

    //    gmt_close	交易结束时间	Date	否	该笔交易结束时间。格式为yyyy-MM-dd HH:mm:ss	2015-04-29 15:45:57
    private String gmtClose;

    //    fund_bill_list	支付金额信息	String(512)	否	支付成功的各个渠道金额信息,详见下表 资金明细信息说明	[{“amount”:“15.00”,“fundChannel”:“ALIPAYACCOUNT”}]
    private String fundBillList;

    //    passback_params	回传参数	String(512)	否	公共回传参数,如果请求时传递了该参数,则返回给商户时会在异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付宝	merchantBizType%3d3C%26merchantBizNo%3d2016010101111
    private String passbackParams;

    //    voucher_detail_list	优惠券信息	String	否	本交易支付时所使用的所有优惠券信息,详见下表 优惠券信息说明	[{“amount”:“0.20”,“merchantContribute”:“0.00”,“name”:“一键创建券模板的券名称”,“otherContribute”:“0.20”,“type”:“ALIPAY_DISCOUNT_VOUCHER”,“memo”:“学生卡8折优惠”]
    private String voucherDetailList;
}

5、支付查询结果响应类

package com.ganguomob.dev.dsprwpt.ui.dto.response.api.alipay;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * 阿里支付查询响应
 *
 * @author: create by luotj
 * date: 2020-01-14 14:32
 **/
@ApiModel
@Data
public class AliQueryResponse {

    @ApiModelProperty("交易支付成功:1,其他类型返回0")
    public Integer status;

    @ApiModelProperty("支付返回data")
    public String data;

}

6、Controller层发起请求

package com.ganguomob.dev.dsprwpt.ui.controller.api.user;

import com.ganguomob.dev.dsprwpt.service.api.user.UserService;
import com.ganguomob.dev.dsprwpt.ui.dto.request.api.alipay.AliPayRequest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Api(tags = "01. 账户管理")
@RestController
@RequestMapping("/api/account")
public class AccountController {

    @Autowired
    private UserServiceImpl mUserService;

    @ApiOperation(value = "支付充值")
    @PutMapping("/pay")
    public String payRecharge() {
        //支付宝支付信息
        AliPayRequest aliPayRequest = new AliPayRequest()
                .setBody("测试Body")
                .setOutTradeNo("45313153")
                .setSubject("测试subject")
                .setRechargeId(1L)
                .setType(1)
                .setTotalAmount(new BigDecimal(100));
        return mUserService.alipayPreCreate(aliPayRequest);
    }

}

7、异步回调地址Controller

package com.ganguomob.dev.dsprwpt.ui.controller.api.alipay;

import com.ganguomob.dev.dsprwpt.service.api.alipay.AliPayService;
import com.ganguomob.dev.dsprwpt.ui.dto.response.api.alipay.AliQueryResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * @author: create by luotj
 * date: 2019-12-27 10:47
 **/
@RestController
@Slf4j
@Api(tags = "12. 支付宝接口")
@RequestMapping("/api/alipay")
public class AdminAlipayNotificationController {

    @Autowired
    private UserServiceImpl mUserServiceImpl;

    @ApiOperation(value = "异步消息回调")
    @PostMapping("/notify/callback")
    public String alipayCallback(HttpServletRequest request) {
        return mUserServiceImpl.alipayCallback(request);
    }

    @ApiOperation(value = "查询订单支付状态")
    @GetMapping("/check-status/{orderNo}")
    public AliQueryResponse checkOrderPayingStatus(
            @PathVariable("orderNo") @ApiParam(value = "订单号", required = true) String orderNo) {
        return mUserServiceImpl.alipayQuery(orderNo);
    }
}

8、Service层生成预支付,并返回信息给前端生成支付二维码(实现逻辑核心)

package com.ganguomob.dev.dsprwpt.service.api.user;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
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.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ganguomob.dev.base.infrastructure.exception.CommonBusinessException;
import com.ganguomob.dev.dsprwpt.constant.PayType;
import com.ganguomob.dev.dsprwpt.constant.RechargeStatus;
import com.ganguomob.dev.dsprwpt.domain.repository.fee.IFeeRecordRepository;
import com.ganguomob.dev.dsprwpt.domain.repository.user.IUserRepository;
import com.ganguomob.dev.dsprwpt.domain.service.alipay.AliTradeStatus;
import com.ganguomob.dev.dsprwpt.infrastructure.util.xinbao.XinBaoUtils;
import com.ganguomob.dev.dsprwpt.jooq.tables.pojos.FeeRecordPOJO;
import com.ganguomob.dev.dsprwpt.ui.dto.request.api.alipay.AliPayRequest;
import com.ganguomob.dev.dsprwpt.ui.dto.response.api.alipay.AliQueryResponse;
import com.ganguomob.dev.dsprwpt.ui.dto.response.api.alipay.AlipayCallbackResponse;
import com.google.common.base.CaseFormat;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Slf4j
@Service
public class UserServiceImpl{

@Value("${ali.pay.appId}")
private String appId;

@Value("${ali.pay.appPrivateKey}")
private String privateKey;

@Value("${ali.pay.publicKey}")
private String aliKey;

@Value("${ali.pay.returnUrl}")
private String returnUrl;

@Value("${ali.pay.notifyUrl}")
private String notifyUrl;

@Value("${ali.pay.gateway}")
private String gateWay;

@Value("${ali.pay.signType}")
private String signType;

@Value("${ali.pay.charset}")
private String charset;

@Value("${ali.pay.format}")
private String format;


    /**
     * 支付宝支付回调逻辑
     * @param request
     * @return
     */
    @Override
    public String alipayCallback(HttpServletRequest request) {
        //将异步通知中收到的所有参数都存放到 map 中
        Map<String, String> paramsMap = callbackRequestToMap(request);

        alipayCheckRSAV1By(paramsMap);

        AlipayCallbackResponse response = mapToAlipayResponse(paramsMap);

        log.info("支付宝回调信息:订单序列号{}", response.getOutTradeNo());

        if (response.getTradeStatus() == null) {
            log.error("ali pay callback response status is null " + "\n"
                    + "out trade no:" + response.getOutTradeNo());
            return "fail";
        }
        String orderNumber = response.getOutTradeNo();

        //支付查询是否支付成功
        AliQueryResponse queryResponse = alipayQuery(orderNumber);
        if (queryResponse.getStatus() == 1) {
            //支付成功回调接口,并做状态的判断更改,逻辑
            
            if (recordPOJO.getRechargeStatus().equals(RechargeStatus.PAY_FAIL)) {
                //支付失败,逻辑

            }
            return "success";
        } else {
            log.info("订单序列号:{},支付失败", orderNumber);
            return "fail";
        }
    }

//生成预支付逻辑方法
public String alipayPreCreate(AliPayRequest aliPayRequest) {
        log.info("预支付生成二维码");
        //校验数据
        checkPayParamsValid(aliPayRequest);
        //创建客户端 
        AlipayClient alipayClient = new DefaultAlipayClient(gateWay, appId, privateKey, format,charset, aliKey, signType);
        //SDK中的请求实体类
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();

        //判断订单号是否为空
        Map<String, Object> paramMap = new HashMap<>();
        if (aliPayRequest.getOutTradeNo().isEmpty()) {
            paramMap.put("type", "2");
            paramMap.put("data", "订单号不能为空");
            return null;
        }
        //设置异步、回调地址
        request.setNotifyUrl(notifyUrl);
        request.setReturnUrl(returnUrl);

        //设置主要参数,参数说明参考文档
        paramMap.put("timeout_express", "5m");
        paramMap.put("out_trade_no", aliPayRequest.getOutTradeNo());
        paramMap.put("total_amount", aliPayRequest.getTotalAmount().doubleValue());
        paramMap.put("subject", aliPayRequest.getSubject());
        //将数据转换为json数据,并设置到request中
        ObjectMapper mapper = new ObjectMapper();
        String qrCode = null;
        try {
            //发起预支付请求
            String bizContent = mapper.writeValueAsString(paramMap);
            request.setBizContent(bizContent);
            AlipayTradePrecreateResponse precreateResponse = alipayClient.execute(request);
            //获取支付二维码内容
            qrCode = precreateResponse.getQrCode();
        } catch (AlipayApiException e) {
            log.error("AlipayApiException,错误信息:{},ErrMsg:{},msg:{}",
                    e.getErrCode(), e.getErrMsg(), e.getMessage());
        } catch (JsonProcessingException e) {
            log.error("转换数据失败,错误信息:{}", e.getMessage());
        }
        //返回支付二维码内容(前段根据该内容生成支付二维码)
        return qrCode;
    }


    /**
     * 阿里支付查询
     *
     * @return
     */
    @Override
    public AliQueryResponse alipayQuery(String outTradeNo) {
        AlipayClient alipayClient = new DefaultAlipayClient(gateWay, appId, privateKey, format,
                charset, aliKey, signType);

        //创建查询对象
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("out_trade_no", outTradeNo);
        //转换为json数据
        ObjectMapper mapper = new ObjectMapper();
        AliQueryResponse queryResponse = new AliQueryResponse();
        try {
            String queryMap = mapper.writeValueAsString(paramMap);
            request.setBizContent(queryMap);
            //执行查询
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            JSONObject jsonObject = JSON.parseObject(response.getBody())
                    .getJSONObject("alipay_trade_query_response");
            String code = jsonObject.getString("code");
            String msg = jsonObject.getString("msg");
            if ("10000".equals(code) && "Success".equals(msg)) {
                //支付成功,逻辑
                queryResponse.setStatus(1)
                            .setData(tradeStatus);
            } else {
                //其它状态,逻辑
                queryResponse.setStatus(0)
                            .setData(tradeStatus);
            }
        } catch (Exception e) {
            log.error("数据转换异常:msg{}", e.getMessage());
        }
        return queryResponse;
    }


    private Map<String, String> callbackRequestToMap(HttpServletRequest request) {
        // 获取支付宝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(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, name), valueStr);
        }
        return params;
    }

    //检查签名
    public void alipayCheckRSAV1By(Map<String, String> paramsMap) {
        boolean signVerified = false;
        try {
            //调用SDK验证签名
            signVerified = AlipaySignature.rsaCheckV1(paramsMap, aliKey, charset, signType);

            log.info("pay callback rsa check flag:" + signVerified);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.error("pay callback rsa check error" + "\n" +
                    "error code:" + e.getErrCode() + "\n" +
                    "error msg:" + e.getErrMsg());

            throw new RuntimeException();
        }
    }


    //校验数据
    private void checkPayParamsValid(AliPayRequest params) {

        //订单编码不能为空
        if (Strings.isBlank(params.getOutTradeNo())) {
            throw new RuntimeException("订单编码不能为空");
        }
        //商品信息不能为空
        if (Strings.isBlank(params.getBody())) {
            throw new RuntimeException("商品信息不能为空");
        }
        //订单名称不能为空
        if (Strings.isBlank(params.getSubject())) {
            throw new RuntimeException("订单名称不能为空");
        }
        //支付价格必须大于0
        if (params.getTotalAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new RuntimeException("支付价格必须大于0");
        }
    }

    private AlipayCallbackResponse mapToAlipayResponse(Map<String, String> params) {
        AlipayCallbackResponse response = new AlipayCallbackResponse();
        response.setNotifyTime(params.get("notify_time"));
        response.setNotifyType(params.get("notify_type"));
        response.setNotifyId(params.get("notify_id"));
        response.setAppId(params.get("app_id"));
        response.setCharset(params.get("charset"));
        response.setVersion(params.get("version"));
        response.setSignType(params.get("sign_type"));
        response.setSign(params.get("sign"));
        response.setTradeNo(params.get("trade_no"));
        response.setOutTradeNo(params.get("out_trade_no"));
        response.setOutBizNo(params.getOrDefault("out_biz_no", ""));
        response.setBuyerId(params.getOrDefault("buyerId", ""));
        response.setBuyerLogonId(params.getOrDefault("buyer_logon_id", ""));
        response.setSellerId(params.getOrDefault("seller_id", ""));
        response.setSellerEmail(params.getOrDefault("seller_email", ""));
        response.setTradeStatus(params.containsKey("trade_status") ?
                AliTradeStatus.fromCode(params.get("trade_status")) : null);
        response.setTotalAmount(params.getOrDefault("total_amount", ""));
        response.setReceiptAmount(params.getOrDefault("receipt_amount", ""));
        response.setInvoiceAmount(params.getOrDefault("invoice_amount", ""));
        response.setBuyerPayAmount(params.getOrDefault("buyer_pay_amount", ""));
        response.setPointAmount(params.getOrDefault("point_amount", ""));
        response.setRefundFee(params.getOrDefault("refund_fee", ""));
        response.setSubject(params.getOrDefault("subject", ""));
        response.setBody(params.getOrDefault("body", ""));
        response.setGmtCreate(params.getOrDefault("gmt_create", ""));
        response.setGmtPayment(params.getOrDefault("gmt_payment", ""));
        response.setGmtRefund(params.getOrDefault("gmt_refund", ""));
        response.setGmtClose(params.getOrDefault("gmt_close", ""));
        response.setFundBillList(params.getOrDefault("fund_bill_list", ""));
        response.setPassbackParams(params.getOrDefault("passback_params", ""));
        response.setVoucherDetailList(params.getOrDefault("voucher_detail_list", ""));
        return response;
    }
}

 

支付页面效果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章