# 一、支付宝 - 沙箱版配置

进入支付宝的开发平台页面:https://auth.alipay.com/login/ant_sso_index.htm?goto=https%3A%2F%2Fopen.alipay.com%2Fdevelop%2Fsandbox%2Faccount

需要扫码然后进入

image-20240303161638927

# 二、下载所需的工具 -(密钥工具)

访问下载地址:https://opendocs.alipay.com/open/02kipk?pathHash=3dce99f3

image-20240303161656044

下载完后打开这个工具,然后生成密钥

image-20240303161710370

# 三、接口加签方式配置密钥

🔑

回到开发平台,打开控制台再次进入沙箱应用,配置公钥模式

1、点击 自定义密钥

2、点击设置并查看

image-20240303161730054

打开后,把刚刚在下载的密钥工具中生成的应用公钥复制进去

image-20240303161753291

复制进去之后点保存,就可以了

image-20240303161808335

# 四、配置 yml

这个配置当时被配置在了 nacos 中,然后使用 @Value 进行读取这些值

pay:
 alipay:
  # APPID
  APP_ID: 9021000131682336
  # 支付宝公钥
  APP_PRIVATE_KEY: MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCK07qIDJgLq18PlNwU7MokEiHCY/4vylHmpBAIeJuCsJ9KpwBTsIbtpob74a+NaRSTtJYucRpmmpBUemfDth9oLn4IZYGrxq3xpwO30e8wuZUj7zX/ZUIM7hTgk8gmQXA67Nplmsw7AUIXc/vLX8NIsRZgSM+SwJ5YnL/FoSvLwf8x38SPbFu0DSDLo+yCOz8i2imsotdxP0Pg6NsRZyPHVmnQw8nqDWl3odC1hOmjt6WK+xuEoGh/hsFGt1WSo+aNHQSiZ4tDILWEnlGuo4NagJXIVJR5hA0ZA2SOfxFbpvY663N0ep6o/2pO+d06ifgvFWfYxHNaUG99MFs5AWmXAgMBAAECggEATLBXi45Bc7jQQ4A870Y7CCAIDCVGpknCYoFg5f0SEujUpd2JHbIXZzKlwIDUhG520n1gtPj/14wsjK4tofx6bwe30ZWZQzX2otZbBHFxC16JV5duIc5i5VejqseYOiHOCI8MujH//dxdES2d+6PD8eT5cmjmWbAUCOlWOqsk0WJhl3teViGf0SsDKSBP7OzEPaPNvX5xbEwEwmeyxAOdEq8Dd+5UqvKlk1avYt/SBDZo7ZzC/D2P8NigTBAzvG/25RAgaBJUCZoKug1lvC8ukPeVacbPVyEr41teSuRf7/7sACrCYjmo/h4M6NZ2A+OWYD52LIdKpjsAdTLRma/BaQKBgQDIToLjexksjstKGqA6XFw3FT2+veSAG9rV0esD3R4WCtVAQ+SZa2ZxpSFtapXl+r3leDyqSvWZzXatv1/9Y/ZYZJEHLPm2K6ZU6YxumORR3XVQwDyONwri7cG1DmXrtrEswkO7hOWKnLB3YsYzZVxELHoBCLnDICIFbb6oqDAGwwKBgQCxbTPlRrNhswP2hnMGa9fhmp5Ehs8maqUzuZT5FaZr8cAWkkwBJM2H5+lQFVFs7BmOQ2VusZk9vUflRyUcn7Tr0uSN0tz4Yn8I9QPflKBryi0PduYHrKFSeKZDIb/CwCD4l+lmOlMzfQYLVVdnCQyCR4Rz1oQFwdwOzCqaz1FsnQKBgBz2XS6PKgCrVPGOEATgPeUpCRh/VH7BiE7KX3Tbj/IX9uWn63HTeaiM+9xaQPpT2wlG7V6iIAjxEGvm8/Yrcf8t61piQmj4vsAgVNHZAYpkvwXCBf96LfTJ8+w9/LasX8nc/PYsLRRxu4JHoejkiwbAd5OWs2VnTAQE7kBssSUJAoGACLvRZCXYyqRfO5FetCA23joYNFNWexOg0iz+ckxohsO9qt7EswG2xEvcJj8GZRAyKdiTc6F2Y52fnl+kKgaKh1k4Our4SZm/mxdEe4r7YpLvKOW3aQVMY5zgwkk1AUcn2FTR/mA8nDo5Q/GNfdrqLLeMg485rHbgeDIAnuI5pdkCgYAZzz5HAW6qSKwae1xEElm5OdPpZTcvxKIIBoKrXQ30qTKklAt6NV4FmMy9r62zZaEHhLywL9KhX4AGssZ+yaA4tj2NEHuwh2/48TebiRk+ajvYd8EzNBR5a8aH20j3/g/vA8EW+fqBDVWxmsIvGvdIOOhFLEwNWPaVqBq+H5RGGQ==
  # 应用私钥
  ALIPAY_PUBLIC_KEY: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqGTsrjk0otSLuCXUItONzHWQkWUhlV74bAbOpoQrzr82ixtnpsZVj8r6xTao2sPkVe4TlURyezmrX1sTN+4KHQaFK8VUBDLoFs1l/6ESZRLxh1iu3D6G6BikyLQ2pJ36QfZ/HYFZk5ZInP8pCD1zFzacdmA7YMy/+7dzRGkYx7DX/8E+7beQ+Rqr1JDx58ihHH1gCEZG3EQW6/oClABh7IKgSrRIz0pZjxpmg2Y2LkzbiWrZ16tpbmPhbDZ8blcufgME9+YeBdqCwfHgC8YNXvauF7aCPcy7OYbLBAZJwJML8sudIgqQlwpwuHHrbV/S7QI/cGbg5tEvFaQvCwF0SwIDAQAB

对应如下:

APPID

image-20240303161839100

支付宝公钥

应用私钥

image-20240303161904933

其中还有一个很重要的东西就是 支付宝网关地址,查看如下:

image-20240303161929563

# 编写代码演示如下:

需要的依赖:

支付宝

<!-- 支付宝 SDK -->
<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>4.38.128.ALL</version>
</dependency>
<!-- 支付宝 SDK 依赖的日志 -->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>

生成二维码

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.3.3</version>
</dependency>
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>javase</artifactId>
    <version>3.3.3</version>
</dependency>

controller 代码

@Controller
public class PayTestController {
    @Value("${pay.alipay.APP_ID}")
    String APP_ID;
    @Value("${pay.alipay.APP_PRIVATE_KEY}")
    String APP_PRIVATE_KEY;
    @Value("${pay.alipay.ALIPAY_PUBLIC_KEY}")
    String ALIPAY_PUBLIC_KEY;
    @RequestMapping("alipaytest")
    public void doPost(HttpServletRequest httpRequest,
                       HttpServletResponse httpResponse) throws ServletException, IOException, AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, APP_ID, APP_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();// 创建 API 对应的 request
//        alipayRequest.setReturnUrl("http://domain.com/CallBack/return_url.jsp");
//        alipayRequest.setNotifyUrl ("http://tjxt-user-t.itheima.net/xuecheng/orders/paynotify");// 在公共参数中设置回跳和通知地址
        alipayRequest.setBizContent("{" +
                "    \"out_trade_no\":\"20230320010102005\"," +
                "    \"total_amount\":0.1," +
                "    \"subject\":\"Iphone14 16G\"," +
                "    \"product_code\":\"QUICK_WAP_WAY\"" +
                "  }");// 填充业务参数
        String form = alipayClient.pageExecute(alipayRequest).getBody(); // 调用 SDK 生成表单
        httpResponse.setContentType("text/html;charset=" + AlipayConfig.CHARSET);
        httpResponse.getWriter().write(form);// 直接将完整的表单 html 输出到页面
        httpResponse.getWriter().flush();
    }
}

config 代码

public class AlipayConfig {
  // 商户 appid
//	public static String APPID = "";
  // 私钥 pkcs8 格式的
//	public static String RSA_PRIVATE_KEY = "";
  // 服务器异步通知页面路径 需 http:// 或者 https:// 格式的完整路径,不能加?id=123 这类自定义参数,必须外网可以正常访问
  public static String notify_url = "http://商户网关地址/alipay.trade.wap.pay-JAVA-UTF-8/notify_url.jsp";
  // 页面跳转同步通知页面路径 需 http:// 或者 https:// 格式的完整路径,不能加?id=123 这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
  public static String return_url = "http://商户网关地址/alipay.trade.wap.pay-JAVA-UTF-8/return_url.jsp";
  // 请求网关地址
  public static String URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
  // 编码
  public static String CHARSET = "UTF-8";
  // 返回格式
  public static String FORMAT = "json";
  // 支付宝公钥
//	public static String ALIPAY_PUBLIC_KEY = "";
  // 日志记录目录
  public static String log_path = "/log";
  // RSA2
  public static String SIGNTYPE = "RSA2";
 }

生成二维码的代码:

public class QRCodeUtil {
    /**
     * 生成二维码
     *
     * @param content 二维码对应的 URL
     * @param width   二维码图片宽度
     * @param height  二维码图片高度
     * @return
     */
    public String createQRCode(String content, int width, int height) throws IOException {
        String resultImage = "";
        // 除了尺寸,传入内容不能为空
        if (!StringUtils.isEmpty(content)) {
            ServletOutputStream stream = null;
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            // 二维码参数
            @SuppressWarnings("rawtypes")
            HashMap<EncodeHintType, Comparable> hints = new HashMap<>();
            // 指定字符编码为 “utf-8”
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            //L M Q H 四个纠错等级从低到高,指定二维码的纠错等级为 M
            // 纠错级别越高,可以修正的错误就越多,需要的纠错码的数量也变多,相应的二维吗可储存的数据就会减少
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            // 设置图片的边距
            hints.put(EncodeHintType.MARGIN, 1);
            try {
                //zxing 生成二维码核心类
                QRCodeWriter writer = new QRCodeWriter();
                // 把输入文本按照指定规则转成二维吗
                BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
                // 生成二维码图片流
                BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
                // 输出流
                ImageIO.write(bufferedImage, "png", os);
                /**
                 * 原生转码前面没有 data:image/png;base64 这些字段,返回给前端是无法被解析,所以加上前缀
                 */
                resultImage = new String("data:image/png;base64," + EncryptUtil.encodeBase64(os.toByteArray()));
                return resultImage;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("生成二维码出错");
            } finally {
                if (stream != null) {
                    stream.flush();
                    stream.close();
                }
            }
        }
        return null;
    }
    public static void main(String[] args) throws IOException {
        QRCodeUtil qrCodeUtil = new QRCodeUtil();
        System.out.println(qrCodeUtil.createQRCode("http://192.168.0.103:63030/orders/alipaytest", 200, 200));
    }
}

👀

当调用 QRCodeUtil 类中的 main 函数时就会打印出一个二维码的 url 供访问,访问后就会跳转到支付宝的支付 controller 层接口中进行操作,它会获取 APPID,公钥,私钥 。然后向用户返回支付的信息。

如果报错提示 公钥或私钥不匹配,一定要注意自己是否按照流程一步来的,是否 一开始使用了一个应用公钥去生成了一个 加签内容时,但是却又生成了一次应用公钥这样会导致密钥不匹配而出现错误问题。