支付宝支付Java案例?

wen python案例 2

本文目录导读:

支付宝支付Java案例?

  1. 环境准备
  2. 核心配置类
  3. 支付服务实现
  4. DTO对象
  5. 控制层
  6. 工具类
  7. 集成测试示例
  8. 注意事项

我来为你提供一个完整的支付宝支付Java集成案例,包含当面付(扫码支付)和手机网站支付两种常见场景。

环境准备

1 Maven依赖

<dependencies>
    <!-- 支付宝SDK -->
    <dependency>
        <groupId>com.alipay.sdk</groupId>
        <artifactId>alipay-sdk-java</artifactId>
        <version>4.38.72.ALL</version>
    </dependency>
    <!-- JSON处理 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>2.0.40</version>
    </dependency>
    <!-- 日志 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.9</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.4.11</version>
    </dependency>
</dependencies>

2 配置文件 (application.yml)

alipay:
  # 应用ID
  app-id: your_app_id
  # 商户私钥
  app-private-key: your_app_private_key
  # 支付宝公钥
  alipay-public-key: your_alipay_public_key
  # 网关地址
  gateway-url: https://openapi.alipay.com/gateway.do
  # 签名类型
  sign-type: RSA2
  # 编码格式
  charset: UTF-8
  # 格式
  format: json
  # 异步通知地址
  notify-url: http://your-domain.com/alipay/notify
  # 同步返回地址
  return-url: http://your-domain.com/alipay/return

核心配置类

package com.example.alipay.config;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "alipay")
public class AlipayConfig {
    private String appId;
    private String appPrivateKey;
    private String alipayPublicKey;
    private String gatewayUrl;
    private String signType = "RSA2";
    private String charset = "UTF-8";
    private String format = "json";
    private String notifyUrl;
    private String returnUrl;
    // getters and setters...
    @Bean
    public AlipayClient alipayClient() {
        return new DefaultAlipayClient(
            gatewayUrl,
            appId,
            appPrivateKey,
            format,
            charset,
            alipayPublicKey,
            signType
        );
    }
}

支付服务实现

1 支付服务接口

package com.example.alipay.service;
import com.example.alipay.dto.AlipayOrderDTO;
import com.example.alipay.dto.AlipayQueryDTO;
import com.example.alipay.dto.AlipayRefundDTO;
import java.util.Map;
public interface AlipayService {
    /**
     * 当面付(扫码支付)
     */
    String qrcodePay(AlipayOrderDTO orderDTO) throws Exception;
    /**
     * 手机网站支付
     */
    String webPay(AlipayOrderDTO orderDTO) throws Exception;
    /**
     * 查询订单
     */
    AlipayQueryDTO queryOrder(String outTradeNo) throws Exception;
    /**
     * 退款
     */
    boolean refund(AlipayRefundDTO refundDTO) throws Exception;
    /**
     * 处理异步通知
     */
    String handleNotify(Map<String, String> params) throws Exception;
}

2 支付服务实现类

package com.example.alipay.service.impl;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.example.alipay.dto.AlipayOrderDTO;
import com.example.alipay.dto.AlipayQueryDTO;
import com.example.alipay.dto.AlipayRefundDTO;
import com.example.alipay.service.AlipayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Map;
import java.util.UUID;
@Slf4j
@Service
public class AlipayServiceImpl implements AlipayService {
    @Autowired
    private AlipayClient alipayClient;
    @Autowired
    private AlipayConfig alipayConfig;
    @Override
    public String qrcodePay(AlipayOrderDTO orderDTO) throws Exception {
        // 构建请求
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        request.setNotifyUrl(alipayConfig.getNotifyUrl());
        // 构建业务参数
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setOutTradeNo(orderDTO.getOutTradeNo());
        model.setTotalAmount(orderDTO.getTotalAmount().toString());
        model.setSubject(orderDTO.getSubject());
        model.setBody(orderDTO.getBody());
        request.setBizModel(model);
        // 发起请求
        AlipayTradePrecreateResponse response = alipayClient.execute(request);
        if (response.isSuccess()) {
            log.info("支付宝当面付成功,订单号:{},二维码链接:{}", 
                    orderDTO.getOutTradeNo(), response.getQrCode());
            return response.getQrCode();
        } else {
            log.error("支付宝当面付失败,错误码:{},错误信息:{}", 
                    response.getCode(), response.getMsg());
            throw new RuntimeException("支付失败:" + response.getMsg());
        }
    }
    @Override
    public String webPay(AlipayOrderDTO orderDTO) throws Exception {
        // 构建请求
        AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
        request.setNotifyUrl(alipayConfig.getNotifyUrl());
        request.setReturnUrl(alipayConfig.getReturnUrl());
        // 构建业务参数
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setOutTradeNo(orderDTO.getOutTradeNo());
        model.setTotalAmount(orderDTO.getTotalAmount().toString());
        model.setSubject(orderDTO.getSubject());
        model.setBody(orderDTO.getBody());
        model.setProductCode("QUICK_WAP_WAY");
        request.setBizModel(model);
        // 生成支付表单
        return alipayClient.pageExecute(request).getBody();
    }
    @Override
    public AlipayQueryDTO queryOrder(String outTradeNo) throws Exception {
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setOutTradeNo(outTradeNo);
        request.setBizModel(model);
        AlipayTradeQueryResponse response = alipayClient.execute(request);
        AlipayQueryDTO queryDTO = new AlipayQueryDTO();
        if (response.isSuccess()) {
            queryDTO.setTradeNo(response.getTradeNo());
            queryDTO.setOutTradeNo(response.getOutTradeNo());
            queryDTO.setTradeStatus(response.getTradeStatus());
            queryDTO.setTotalAmount(new BigDecimal(response.getTotalAmount()));
            queryDTO.setReceiptAmount(new BigDecimal(response.getReceiptAmount()));
            queryDTO.setBuyerLogonId(response.getBuyerLogonId());
            queryDTO.setGmtPayment(response.getGmtPayment());
        }
        return queryDTO;
    }
    @Override
    public boolean refund(AlipayRefundDTO refundDTO) throws Exception {
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setOutTradeNo(refundDTO.getOutTradeNo());
        model.setRefundAmount(refundDTO.getRefundAmount().toString());
        model.setRefundReason(refundDTO.getRefundReason());
        request.setBizModel(model);
        AlipayTradeRefundResponse response = alipayClient.execute(request);
        if (response.isSuccess()) {
            log.info("退款成功,订单号:{},退款金额:{}", 
                    refundDTO.getOutTradeNo(), refundDTO.getRefundAmount());
            return true;
        } else {
            log.error("退款失败,错误码:{},错误信息:{}", 
                    response.getCode(), response.getMsg());
            return false;
        }
    }
    @Override
    public String handleNotify(Map<String, String> params) throws Exception {
        // 验证签名
        boolean signVerified = AlipaySignature.rsaCheckV1(
            params,
            alipayConfig.getAlipayPublicKey(),
            alipayConfig.getCharset(),
            alipayConfig.getSignType()
        );
        if (!signVerified) {
            log.error("支付宝异步通知签名验证失败");
            return "failure";
        }
        // 获取通知参数
        String outTradeNo = params.get("out_trade_no");
        String tradeNo = params.get("trade_no");
        String tradeStatus = params.get("trade_status");
        String totalAmount = params.get("total_amount");
        String gmtPayment = params.get("gmt_payment");
        log.info("支付宝异步通知,订单号:{},交易状态:{}", outTradeNo, tradeStatus);
        // 处理业务逻辑(更新订单状态等)
        if ("TRADE_SUCCESS".equals(tradeStatus)) {
            // 支付成功,更新订单状态
            // 注意:需要判断处理过的通知不做重复处理
            boolean success = processPaymentSuccess(outTradeNo, tradeNo, totalAmount, gmtPayment);
            return success ? "success" : "failure";
        }
        return "success";
    }
    private boolean processPaymentSuccess(String outTradeNo, String tradeNo, 
                                          String totalAmount, String gmtPayment) {
        // 实现具体的业务逻辑,如更新数据库订单状态
        log.info("处理支付成功回调,订单号:{},支付宝交易号:{}", outTradeNo, tradeNo);
        return true;
    }
}

DTO对象

1 订单DTO

package com.example.alipay.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class AlipayOrderDTO {
    private String outTradeNo;      // 商户订单号
    private BigDecimal totalAmount; // 支付金额
    private String subject;         // 订单标题
    private String body;            // 订单描述
    private Integer timeoutExpress = 30; // 超时时间(分钟)
}

2 查询DTO

package com.example.alipay.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class AlipayQueryDTO {
    private String tradeNo;           // 支付宝交易号
    private String outTradeNo;        // 商户订单号
    private String tradeStatus;       // 交易状态
    private BigDecimal totalAmount;   // 交易金额
    private BigDecimal receiptAmount; // 实收金额
    private String buyerLogonId;     // 买家支付宝账号
    private String gmtPayment;       // 支付时间
}

3 退款DTO

package com.example.alipay.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class AlipayRefundDTO {
    private String outTradeNo;       // 商户订单号
    private BigDecimal refundAmount; // 退款金额
    private String refundReason;     // 退款原因
}

控制层

package com.example.alipay.controller;
import com.example.alipay.dto.AlipayOrderDTO;
import com.example.alipay.dto.AlipayQueryDTO;
import com.example.alipay.dto.AlipayRefundDTO;
import com.example.alipay.service.AlipayService;
import com.example.alipay.util.OrderNumberGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/alipay")
public class AlipayController {
    @Autowired
    private AlipayService alipayService;
    /**
     * 发起当面付(扫码支付)
     */
    @PostMapping("/qrcodePay")
    public Map<String, Object> qrcodePay(@RequestBody AlipayOrderDTO orderDTO) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 生成订单号
            orderDTO.setOutTradeNo(OrderNumberGenerator.generate());
            String qrCode = alipayService.qrcodePay(orderDTO);
            result.put("code", 200);
            result.put("message", "success");
            result.put("data", qrCode);
            result.put("outTradeNo", orderDTO.getOutTradeNo());
        } catch (Exception e) {
            log.error("发起支付宝支付失败", e);
            result.put("code", 500);
            result.put("message", "支付失败:" + e.getMessage());
        }
        return result;
    }
    /**
     * 发起手机网站支付
     */
    @PostMapping("/webPay")
    public Map<String, Object> webPay(@RequestBody AlipayOrderDTO orderDTO) {
        Map<String, Object> result = new HashMap<>();
        try {
            orderDTO.setOutTradeNo(OrderNumberGenerator.generate());
            String form = alipayService.webPay(orderDTO);
            result.put("code", 200);
            result.put("message", "success");
            result.put("data", form);
        } catch (Exception e) {
            log.error("发起手机网站支付失败", e);
            result.put("code", 500);
            result.put("message", "支付失败:" + e.getMessage());
        }
        return result;
    }
    /**
     * 查询订单
     */
    @GetMapping("/query/{outTradeNo}")
    public Map<String, Object> queryOrder(@PathVariable String outTradeNo) {
        Map<String, Object> result = new HashMap<>();
        try {
            AlipayQueryDTO queryDTO = alipayService.queryOrder(outTradeNo);
            result.put("code", 200);
            result.put("message", "success");
            result.put("data", queryDTO);
        } catch (Exception e) {
            log.error("查询订单失败", e);
            result.put("code", 500);
            result.put("message", "查询失败:" + e.getMessage());
        }
        return result;
    }
    /**
     * 退款
     */
    @PostMapping("/refund")
    public Map<String, Object> refund(@RequestBody AlipayRefundDTO refundDTO) {
        Map<String, Object> result = new HashMap<>();
        try {
            boolean success = alipayService.refund(refundDTO);
            result.put("code", success ? 200 : 500);
            result.put("message", success ? "退款成功" : "退款失败");
        } catch (Exception e) {
            log.error("退款失败", e);
            result.put("code", 500);
            result.put("message", "退款失败:" + e.getMessage());
        }
        return result;
    }
    /**
     * 异步通知处理
     */
    @PostMapping("/notify")
    public String handleNotify(HttpServletRequest request) {
        try {
            // 获取支付宝POST过来的参数
            Map<String, String> params = new HashMap<>();
            Map<String, String[]> requestParams = request.getParameterMap();
            for (String name : requestParams.keySet()) {
                String[] values = requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
                }
                params.put(name, valueStr);
            }
            return alipayService.handleNotify(params);
        } catch (Exception e) {
            log.error("处理支付宝异步通知失败", e);
            return "failure";
        }
    }
    /**
     * 同步返回处理
     */
    @GetMapping("/return")
    public String handleReturn(HttpServletRequest request) {
        // 处理同步返回,通常只是展示成功页面
        // 真正的业务逻辑应在异步通知中处理
        return "支付成功,正在返回...";
    }
}

工具类

1 订单号生成器

package com.example.alipay.util;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
public class OrderNumberGenerator {
    private static int sequence = 0;
    private static final Object lock = new Object();
    /**
     * 生成唯一订单号
     */
    public static String generate() {
        synchronized (lock) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
            String dateStr = sdf.format(new Date());
            // 序列号,确保同一毫秒内不会重复
            if (sequence >= 1000) {
                sequence = 0;
            }
            sequence++;
            return dateStr + String.format("%03d", sequence) + getRandomChar(3);
        }
    }
    /**
     * 生成随机字符
     */
    private static String getRandomChar(int length) {
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int index = (int) (Math.random() * chars.length());
            sb.append(chars.charAt(index));
        }
        return sb.toString();
    }
}

2 金额工具类

package com.example.alipay.util;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class AmountUtil {
    /**
     * 元转分
     */
    public static long yuanToFen(BigDecimal yuan) {
        return yuan.multiply(new BigDecimal(100))
                  .setScale(0, RoundingMode.HALF_UP)
                  .longValue();
    }
    /**
     * 分转元
     */
    public static BigDecimal fenToYuan(long fen) {
        return new BigDecimal(fen)
                  .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
    }
    /**
     * 格式化金额
     */
    public static String format(BigDecimal amount) {
        return amount.setScale(2, RoundingMode.HALF_UP).toString();
    }
}

集成测试示例

package com.example.alipay;
import com.example.alipay.dto.AlipayOrderDTO;
import com.example.alipay.service.AlipayService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.math.BigDecimal;
@Slf4j
@SpringBootTest
public class AlipayPaymentTest {
    @Autowired
    private AlipayService alipayService;
    @Test
    public void testQrcodePay() throws Exception {
        // 准备订单数据
        AlipayOrderDTO orderDTO = new AlipayOrderDTO();
        orderDTO.setOutTradeNo("ORDER" + System.currentTimeMillis());
        orderDTO.setTotalAmount(new BigDecimal("0.01"));
        orderDTO.setSubject("测试商品");
        orderDTO.setBody("测试商品描述");
        // 发起支付
        String qrCode = alipayService.qrcodePay(orderDTO);
        log.info("生成的二维码链接:{}", qrCode);
        System.out.println("请使用支付宝扫描以下二维码进行支付:");
        System.out.println(qrCode);
    }
    @Test
    public void testQueryOrder() throws Exception {
        String outTradeNo = "ORDER1234567890";
        com.example.alipay.dto.AlipayQueryDTO queryDTO = alipayService.queryOrder(outTradeNo);
        log.info("订单信息:{}", queryDTO);
    }
}

注意事项

1 配置文件示例

# 支付宝配置
alipay.app-id=2021000118600001
alipay.app-private-key=MIIEvQIBADANB... (完整RSA私钥)
alipay.alipay-public-key=MIIBIjANBg... (完整RSA公钥)
alipay.gateway-url=https://openapi.alipay.com/gateway.do
alipay.sign-type=RSA2
alipay.charset=UTF-8
alipay.format=json
alipay.notify-url=http://your-domain.com/alipay/notify
alipay.return-url=http://your-domain.com/alipay/return

2 重要提示

  1. 密钥安全:私钥不要在代码中硬编码,建议使用配置中心或环境变量
  2. 异步通知:一定要验证签名,并确保回调幂等性
  3. 订单号唯一性:确保生成的订单号全局唯一
  4. 金额精度:使用BigDecimal处理金额,避免浮点数精度问题
  5. 日志记录:记录所有关键操作的日志,便于排查问题

3 常见问题处理

// 签名失败处理
public static boolean verifySign(Map<String, String> params, String alipayPublicKey) {
    try {
        return AlipaySignature.rsaCheckV1(params, alipayPublicKey, "UTF-8", "RSA2");
    } catch (Exception e) {
        log.error("签名验证异常", e);
        return false;
    }
}

这个案例涵盖了支付宝支付的主要功能,可根据实际需求进行调整和扩展,建议在沙箱环境中测试通过后再切换到生产环境。

抱歉,评论功能暂时关闭!