Java 支付宝使用公钥证书加签 进行支付-查询-退款-转账

阿里支付官方文档(分app/网页支付):

https://opendocs.alipay.com/open/270/105898/

1、引入相关依赖 pom.xml

<dependency>
      <groupId>com.alipay.sdk</groupId>
      <artifactId>alipay-sdk-java</artifactId>
      <version>4.8.10.ALL</version>
      <scope>compile</scope>
</dependency>

2、配置文件 application.yml

[注意]  证书文件必须放到服务器上,放到项目里的证书,在win环境下可以根据路径找到,但打成jar包后就找不到项目里的证书文件了,解决办法是判断服务器环境,根据不同环境拼接证书路径

证书文件目录结构如下,在Linux服务器上部署时,将pay文件夹和jar包放到同一个文件夹下

 

# 支付
pay:
  alipay:
    gatewayUrl: https://openapi.alipay.com/gateway.do
    appid: *****
    appPrivateKey:
    alipayPublicKey:
    appCertPath: /pay/alipay/cert/appCertPublicKey****.crt
    alipayCertPath: /pay/alipay/cert/alipayCertPublicKey_RSA2.crt
    alipayRootCertPath: /pay/alipay/cert/alipayRootCert.crt
    returnUrl: ****
    notifyUrl: ****

3、读取配置文件

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
 
import javax.annotation.PostConstruct;
 
 
@Data
@Slf4j
@ConfigurationProperties(prefix = "pay.alipay")
public class AlipayProperties {
 
    /**
     * 支付宝gatewayUrl
     */
    private String gatewayUrl;
    /**
     * 商户应用id
     */
    private String appid;
    /**
     * RSA私钥,用于对商户请求报文加签
     */
    private String appPrivateKey;
    /**
     * 支付宝RSA公钥,用于验签支付宝应答
     */
    private String alipayPublicKey;
 
    /**
     * 签名类型
     */
    private String signType = "RSA2";
 
    /**
     * 格式
     */
    private String formate = "json";
    /**
     * 编码
     */
    private String charset = "UTF-8";
 
    /**
     * 同步地址
     */
    private String returnUrl;
 
    /**
     * 异步地址
     */
    private String notifyUrl;
 
    /**
     * 应用公钥证书
     */
    private String appCertPath;
 
    /**
     * 支付宝公钥证书
     */
    private String alipayCertPath;
 
    /**
     * 支付宝根证书
     */
    private String alipayRootCertPath;
 
 
    /**
     * 最大查询次数
     */
    private static int maxQueryRetry = 5;
    /**
     * 查询间隔(毫秒)
     */
    private static long queryDuration = 5000;
    /**
     * 最大撤销次数
     */
    private static int maxCancelRetry = 3;
    /**
     * 撤销间隔(毫秒)
     */
    private static long cancelDuration = 3000;
 
    private AlipayProperties() {
    }
 
    /**
     * PostContruct是spring框架的注解,在方法上加该注解会在项目启动的时候执行该方法,也可以理解为在spring容器初始化的时候执行该方法。
     */
    @PostConstruct
    public void init() {
        log.info(description());
    }
 
    public String description() {
        StringBuilder sb = new StringBuilder("\n支付宝Configs{");
        sb.append("支付宝网关: ").append(gatewayUrl).append("\n");
        sb.append(", appid: ").append(appid).append("\n");
        sb.append(", 商户RSA私钥: ").append(getKeyDescription(appPrivateKey)).append("\n");
        sb.append(", 应用公钥证书: ").append(appCertPath).append("\n");
        sb.append(", 支付宝公钥证书: ").append(alipayCertPath).append("\n");
        sb.append(", 支付宝根证书: ").append(alipayRootCertPath).append("\n");
        sb.append(", 支付宝RSA公钥: ").append(getKeyDescription(alipayPublicKey)).append("\n");
        sb.append(", 签名类型: ").append(signType).append("\n");
        sb.append(", 查询重试次数: ").append(maxQueryRetry).append("\n");
        sb.append(", 查询间隔(毫秒): ").append(queryDuration).append("\n");
        sb.append(", 撤销尝试次数: ").append(maxCancelRetry).append("\n");
        sb.append(", 撤销重试间隔(毫秒): ").append(cancelDuration).append("\n");
        sb.append("}");
        return sb.toString();
    }
 
    private String getKeyDescription(String key) {
        int showLength = 6;
        if (StringUtils.isNotEmpty(key) && key.length() > showLength) {
            return new StringBuilder(key.substring(0, showLength)).append("******")
                    .append(key.substring(key.length() - showLength)).toString();
        }
        return null;
    }
}

4、在启动时初始化支付宝客户端

import com.alipay.api.AlipayApiException;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
 
import java.io.IOException;
 
 
@Configuration
@Slf4j
@EnableConfigurationProperties(AlipayProperties.class)
public class AlipayConfiguration {
 
    @Autowired
    private AlipayProperties properties;
 
//    /**
//     * 支付宝接口加签模式为公钥时使用
//     *
//     * @return
//     */
//    @Bean
//    public AlipayClient alipayClient() {
//        return new DefaultAlipayClient(properties.getGatewayUrl(),
//                properties.getAppid(),
//                properties.getAppPrivateKey(),
//                properties.getFormate(),
//                properties.getCharset(),
//                properties.getAlipayPublicKey(),
//                properties.getSignType());
//    }
 
    /**
     * 支付宝接口加签模式为公钥证书时使用
     *
     * @return
     */
    @Bean
    public DefaultAlipayClient alipayClient() throws AlipayApiException, IOException {
        log.info("---------创建支付宝客户端--------");
 
        //判断系统环境
        String osName = System.getProperty("os.name");
        log.info("-------系统环境--------" + osName);
        String serverpath = null;
        if (osName.startsWith("Windows")) {
            // windows
            serverpath = ResourceUtils.getURL("classpath:").getPath();
            serverpath += "static/app";
            log.info("-------------win文件路径----------" + serverpath);
//        } else if (osName.startsWith("Mac OS")) {
//            // 苹果
        } else {
            // unix or linux
            serverpath = System.getProperty("user.dir");
            log.info("-------------unix or linux文件路径----------" + serverpath);
        }
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        certAlipayRequest.setServerUrl(properties.getGatewayUrl());
        certAlipayRequest.setAppId(properties.getAppid());
        certAlipayRequest.setFormat(properties.getFormate());
        certAlipayRequest.setPrivateKey(properties.getAppPrivateKey());
        certAlipayRequest.setCharset(properties.getCharset());
        certAlipayRequest.setSignType(properties.getSignType());
        certAlipayRequest.setCertPath(serverpath + properties.getAppCertPath());
        certAlipayRequest.setAlipayPublicCertPath(serverpath + properties.getAlipayCertPath());
        certAlipayRequest.setRootCertPath(serverpath + properties.getAlipayRootCertPath());
        return new DefaultAlipayClient(certAlipayRequest);
    }
}

5、APP支付

import cn.hutool.core.date.DateUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayFundTransPayModel;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.Participant;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
 
/**
 * app支付
 */
@Slf4j
@Controller
@RequestMapping("/app/alipay/app")
public class AlipayAppPayController {
 
    @Autowired
    private AlipayProperties alipayProperties;
    @Autowired
    private AlipayClient alipayClient;
    @Autowired
    private AlipayProperties aliPayProperties;
 
    /**
     * 去支付
     * <p>
     *
     * @param response
     * @throws Exception
     */
    @RequestMapping("/createOrder")
    public void createOrder(HttpServletRequest request, HttpServletResponse response,
                            @RequestBody Map<String, String> mapParams) throws AlipayApiException {
        
        BaseResault resPo = new BaseResault();
        // 订单模型
        String productCode = "QUICK_MSECURITY_PAY";
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        Order bean = orderService.getOrderByNum(mapParams.get("orderNum"));
        model.setOutTradeNo(bean.getOrderNum());
        log.info("----订单编号----" + model.getOutTradeNo());
        model.setSubject(bean.getShopName());
        log.info("----subject----" + model.getSubject());
        model.setTotalAmount(bean.getTotalMoney().toString());
        log.info("----金额----" + model.getTotalAmount());
        model.setTimeoutExpress("30m");
        model.setProductCode(productCode);
        AlipayTradeAppPayRequest appPayRequest = new AlipayTradeAppPayRequest();
        appPayRequest.setNotifyUrl(‘服务器域名’ + alipayProperties.getNotifyUrl());
        log.info("----notifyUrl----" + appPayRequest.getNotifyUrl());
        appPayRequest.setBizModel(model);
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
        AlipayTradeAppPayResponse ali_response = alipayClient.sdkExecute(appPayRequest); //这里和使用公钥加签支付使用的方法不同
        //就是orderString 可以直接给客户端请求,无需再做处理。
        log.info("---------支付宝返回---------{}", ali_response.getBody());
        resPo.setObj(ali_response.getBody());
        resPo.setCode(ConstantApp.AppTokenValidResult.SUCCESS.getCode());
        resPo.setMessage(ConstantApp.AppTokenValidResult.SUCCESS.getMessage());
        ResponseJsonUtils.json(response, resPo);
    }<br>} 

6、查询订单

/**
 * 订单查询(最主要用于查询订单的支付状态)
 *
 * @param orderNo 商户订单号
 * @return
 */
@GetMapping("/query")
public void query(HttpServletRequest request, HttpServletResponse response, String orderNo) throws AlipayApiException {
    BaseResault resPo = new BaseResault();
    AlipayTradeQueryRequest aliRequest = new AlipayTradeQueryRequest();
    AlipayTradeQueryModel bizModel = new AlipayTradeQueryModel();
    bizModel.setTradeNo(orderNo);
    aliRequest.setBizModel(bizModel);
    AlipayTradeQueryResponse aliResponse = alipayClient.certificateExecute(aliRequest);
    if (aliResponse.isSuccess()) {
        log.info("查询支付宝支付状态-----调用成功{}", aliResponse.getBody());
        if (aliResponse.getTradeStatus().equals("TRADE_SUCCESS") || aliResponse.getTradeStatus().equals("TRADE_FINISHED")) {
            //订单编号
            String orderNum = aliResponse.getOutTradeNo();
            // 处理业务
            resPo.setObj(aliResponse.getBody());
            resPo.setCode(ConstantApp.AppTokenValidResult.SUCCESS.getCode());
            resPo.setMessage(ConstantApp.AppTokenValidResult.SUCCESS.getMessage());
            ResponseJsonUtils.json(response, resPo);
            return;
        } else {
            log.error("支付宝订单" + orderNo + "交易失败,交易状态:" + aliResponse.getTradeStatus());
            resPo.setObj(aliResponse.getBody());
            resPo.setCode(ConstantApp.AppTokenValidResult.SYSTEM_ERROR.getCode());
            resPo.setMessage(ConstantApp.AppTokenValidResult.SYSTEM_ERROR.getMessage());
            ResponseJsonUtils.json(response, resPo);
            return;
        }
    } else {
        log.info("查询支付宝支付状态------调用失败{}", aliResponse.getBody());
        resPo.setObj(aliResponse.getBody());
        resPo.setCode(ConstantApp.AppTokenValidResult.SYSTEM_ERROR.getCode());
        resPo.setMessage(ConstantApp.AppTokenValidResult.SYSTEM_ERROR.getMessage());
        ResponseJsonUtils.json(response, resPo);
        return;
    }
}

 

7、转账给用户

/**
    * alipay.fund.trans.uni.transfer(单笔转账接口)
    * <p>文档地址
    * https://docs.open.alipay.com/api_28/alipay.fund.trans.uni.transfer/
    *
    * @param response
    * @throws Exception
    */
   @RequestMapping("/alipayToUser")
   public void alipayToUser(HttpServletRequest request, HttpServletResponse response) throws AlipayApiException {
       BaseResault resPo = new BaseResault();
       //转账金额  不能少于0.1元
       String money = request.getParameter("money");
      //支付宝账号,支持邮箱、电话号码
       String phone = request.getParameter("phone");
       //支付宝账户名称
       String name = request.getParameter("name");
       // 订单模型
       AlipayFundTransPayModel model = new AlipayFundTransPayModel();
       //商户端的唯一订单号
       String orderNum = UUID.randomUUID().toString().replace("-", "");
       log.info("============支付宝转账给用户-订单号:" + orderNum + "==============");
       model.setOutBizNo(orderNum);
       //订单总金额,单位为元,精确到小数点后两位
       model.setTransAmount(money);
       //业务产品码,
       //收发现金红包固定为:STD_RED_PACKET;
       //单笔无密转账到支付宝账户固定为:TRANS_ACCOUNT_NO_PWD;
       //单笔无密转账到银行卡固定为:TRANS_BANKCARD_NO_PWD
       model.setProductCode("TRANS_ACCOUNT_NO_PWD");
       //收款方信息
       Participant participant = new Participant();
       //参与方的唯一标识
       participant.setIdentity(phone);
       //参与方的标识类型,目前支持如下类型:
       //1、ALIPAY_USER_ID 支付宝的会员ID
       //2、ALIPAY_LOGON_ID:支付宝登录号,支持邮箱和手机号格式
       participant.setIdentityType("ALIPAY_LOGON_ID");
       //参与方真实姓名,如果非空,将校验收款支付宝账号姓名一致性。当identity_type=ALIPAY_LOGON_ID时,本字段必填。
       participant.setName(name);
       model.setPayeeInfo(participant);
       //业务备注
       model.setRemark("转账测试");
       model.setBizScene("DIRECT_TRANSFER");
       AlipayFundTransUniTransferRequest appPayRequest = new AlipayFundTransUniTransferRequest();
       appPayRequest.setBizModel(model);
       //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.fund.trans.uni.transfer(单笔转账接口)
       AlipayFundTransUniTransferResponse ali_response = alipayClient.certificateExecute(appPayRequest);
       if (ali_response.isSuccess()) {
           log.info("========支付宝转账给用户-调用成功=======" + ali_response.getBody());
           resPo.setObj(ali_response.getBody());
           resPo.setCode(ConstantApp.AppTokenValidResult.SUCCESS.getCode());
           resPo.setMessage(ConstantApp.AppTokenValidResult.SUCCESS.getMessage());
           ResponseJsonUtils.json(response, resPo);
       } else {
           log.info("========支付宝转账给用户-调用失败=======" + ali_response.getBody());
           resPo.setObj(ali_response.getBody());
           resPo.setCode(ConstantApp.AppTokenValidResult.SYSTEM_ERROR.getCode());
           resPo.setMessage(ConstantApp.AppTokenValidResult.SYSTEM_ERROR.getMessage());
           ResponseJsonUtils.json(response, resPo);
       }
   }

 

8、异步通知

/**
    * 证书支付异步通知
    * https://docs.open.alipay.com/194/103296
    */
   @RequestMapping("/notify")
   public String notify(HttpServletRequest request) {
       log.info("-----------支付异步通知----------------");
       Map requestParams = request.getParameterMap();
       log.info(">>>支付宝回调参数:" + requestParams);
       Map<String, String> params = new HashMap<>();
       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);
       }
       log.info(">>>支付宝回调参数解析:" + params);
       try {
           String alipayCertPath = System.getProperty("user.dir") + aliPayProperties.getAlipayCertPath();
           //切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
           boolean flag = AlipaySignature.rsaCertCheckV1(
                   params,
                   alipayCertPath,
                   aliPayProperties.getCharset(),
                   aliPayProperties.getSignType());
           if (flag) {
               log.info(">>>支付宝回调签名认证成功");
               //商户订单号
               String out_trade_no = params.get("out_trade_no");
               //交易状态
               String trade_status = params.get("trade_status");
               //交易金额
               String amount = params.get("total_amount");
               //商户app_id
               String app_id = params.get("app_id");
 
               if ("TRADE_SUCCESS".equals(trade_status) || "TRADE_FINISHED".equals(trade_status)) {
                   /**
                    * 自己的业务处理,一定要判断是否已经处理过订单
                    */
                   log.info("-----------^v^支付成功^v^------------");
                  
                   }
               } else {
                   log.error("没有处理支付宝回调业务,支付宝交易状态:{},params:{}", trade_status, params);
               }
           } else {
               log.info("支付宝回调签名认证失败,signVerified=false, params:{}", params);
               return "failure";
           }
       } catch (Exception e) {
           log.error(e.getMessage(), e);
           log.info("支付宝回调签名认证失败,signVerified=false, params:{}", params);
           return "failure";
       }
       return "success";
   }

9、退款

/**
    * 同一订单多次退款
    *
    * @param orderNo 商户订单号
    * @return
    */
   @Override
   public String multipleRefunds(String orderNo, String refundAmount, String refundReason) throws AlipayApiException {
       log.info("------------支付宝退款开始--------------");
       AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
       AlipayTradeRefundModel model = new AlipayTradeRefundModel();
       // 商户订单号
       model.setOutTradeNo(orderNo);
       // 退款金额 单位元
       model.setRefundAmount(refundAmount);
       // 退款原因
       model.setRefundReason(refundReason);
       // 退款订单号(同一个订单可以分多次部分退款,当分多次时必传)
       model.setOutRequestNo(UUID.randomUUID().toString());
       log.info("------退款参数-----{}-----{}-----{}------{}", orderNo, refundAmount, refundReason, model.getOutRequestNo());
       alipayRequest.setBizModel(model);
       AlipayTradeRefundResponse alipayResponse = alipayClient.certificateExecute(alipayRequest);
       log.info("--------支付宝退款结果---------" + alipayResponse.getBody() + "---------订单号--" + orderNo);
       return alipayResponse.getBody();
   }

希望对你有所帮助!

原创:https://www.cnblogs.com/binaryStar/p/12584694.html

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要实现Java支付宝转账到银行卡,需要使用支付宝提供的转账接口,具体操作步骤如下: 1. 注册支付宝开发者账号,并创建应用获取应用的 appId、私钥和公钥; 2. 引入支付宝Java SDK; 3. 初始化 AlipayClient 对象,设置请求参数; 4. 调用 AlipayFundTransToaccountTransferRequest 请求对象的 setBizContent() 方法设置转账的参数,包括转账的金额、收款人账号和姓名等信息; 5. 调用 AlipayClient 的 execute() 方法发起请求,获取响应结果。 以下是一个示例代码: ``` import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayClient; import com.alipay.api.DefaultAlipayClient; import com.alipay.api.request.AlipayFundTransToaccountTransferRequest; import com.alipay.api.response.AlipayFundTransToaccountTransferResponse; public class AlipayTransferDemo { // 应用的 appId private static final String APP_ID = "your_app_id"; // 商户私钥 private static final String PRIVATE_KEY = "your_private_key"; // 支付宝公钥 private static final String ALIPAY_PUBLIC_KEY = "alipay_public_key"; // 支付宝网关 private static final String GATEWAY_URL = "https://openapi.alipay.com/gateway.do"; public static void main(String[] args) { // 初始化 AlipayClient AlipayClient client = new DefaultAlipayClient(GATEWAY_URL, APP_ID, PRIVATE_KEY, "json", "utf-8", ALIPAY_PUBLIC_KEY, "RSA2"); // 创建转账请求对象 AlipayFundTransToaccountTransferRequest request = new AlipayFundTransToaccountTransferRequest(); // 设置转账参数 request.setBizContent("{\"out_biz_no\":\"201806300001\",\"payee_type\":\"ALIPAY_LOGONID\",\"payee_account\":\"alipay_user_id\",\"amount\":\"1.00\",\"payer_show_name\":\"示例名称\",\"payee_real_name\":\"示例姓名\",\"remark\":\"转账备注\"}"); try { // 发起转账请求 AlipayFundTransToaccountTransferResponse response = client.execute(request); if (response.isSuccess()) { System.out.println("转账成功!"); } else { System.out.println("转账失败,错误码:" + response.getCode() + ",错误信息:" + response.getMsg()); } } catch (AlipayApiException e) { e.printStackTrace(); } } } ``` 需要注意的是,转账到银行卡需要在支付宝后台进行配置,开通转账到银行卡的功能。开通后,需要使用银行卡转账的接口进行转账操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值