java 对接 stripe支付

stripe 支付跟国内的 支付宝 、微信、等第三方支付平台不一样

 码字不易,开源更不易,点赞收藏关注,多多支持

开源地址  https://gitee.com/J-LJJ/stripe-demo

支付方式一

先看效果

 

 

支付方式2(需要配合回调)

2023-04-12更新.......

综上是支付方式1 创建商品、价格的方式进行支付

还有另外一种支付是自定义金额的方式进行支付,代码已同步到gitee,点我过去 ,

再看看效果图吧,嘻嘻

 

支付方式3(不需要回调)

2023-04-13更新.......

你敢相信? 还有第三种支付(Charge.create),代码同样更新gitee ,点我过去 ,

再看看效果图

流程

1、注册他们平台的账号   Sign Up and Create a Stripe Account | Stripe

2、然后得到私钥(注册账号,测试阶段可以不用去填写信息)

3、去他们后台管理页面去添加产品 Stripe Login | Sign in to the Stripe Dashboard

4、添加产品-> 添加产品的价格->然后再创建支付得到url (可以通过api接口方式进行在他们后台创建,也可以手动去创建)

5、得到了url,进去跳转,然后得到测试的visa卡进行支付  Test cards | Stripe Documentation

6、支付成功后,修改订单状态(这里需要用到stripe的回调 webhook)

回调配置

我之类在开发的时候遇到了一个大坑,总结就一句话,

你用checkout的api调用拉起支付,就必须要在stripe后台的webhook勾选checkout.xxx 

用PaymentIntent的api调用拉起支付,就必须要在stripe后台的webhook勾选payment_intent.xxx 

不能搞混 、 不能搞混 、 不能搞混

然后讲一下哪里配置 ,登录后台,然后点击开发人员,找到webhook,然后添加端点,我这里是用到的内网穿透,可以更方便的在本地调试,花生壳,natapp都可以内网穿透

 然后你支付成功了,可以看官方调用你接口的日志

代码部分

码字不易,开源更不易,点赞收藏关注,多多支持

开源地址  https://gitee.com/J-LJJ/stripe-demo

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.japhet</groupId>
    <artifactId>stripes-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>stripes-demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.28</version>
        </dependency>


        <!--  stripe  begin -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>2.0.3</version>
        </dependency>
        <dependency>
            <groupId>com.sparkjava</groupId>
            <artifactId>spark-core</artifactId>
            <version>2.9.4</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.9.1</version>
        </dependency>
        <dependency>
            <groupId>com.stripe</groupId>
            <artifactId>stripe-java</artifactId>
            <version>22.5.1</version>
        </dependency>
        <!--  stripe  end -->

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

controller

package com.japhet.stripesdemo.controller;

import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import com.stripe.Stripe;
import com.stripe.exception.StripeException;
import com.stripe.model.*;
import com.stripe.model.checkout.Session;
import com.stripe.param.PaymentIntentCreateParams;
import com.stripe.param.PriceListParams;
import com.stripe.param.PriceUpdateParams;
import com.stripe.param.checkout.SessionCreateParams;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.nio.file.Paths;
import java.util.*;

import static spark.Spark.staticFiles;

@RestController
public class StripeController {

    private static Gson gson = new Gson();

    static class CreatePayment {
        @SerializedName("items")
        Object[] items;

        public Object[] getItems() {
            return items;
        }
    }

    static class CreatePaymentResponse {
        private String clientSecret;
        public CreatePaymentResponse(String clientSecret) {
            this.clientSecret = clientSecret;
        }
    }

    static {
        // 管理平台里面的密钥  详情请看 demo-image/1.jpg ,图片地址链接: https://dashboard.stripe.com/test/apikeys
        Stripe.apiKey = "sk_test_51Mq6xRLbpF5IT5HsSAQtSW2iW6CJ2tm9Mrixxxxxxxxxxxx";
        staticFiles.externalLocation( Paths.get("public").toAbsolutePath().toString());
    }

    /**
     *   去支付
     * 1、创建产品
     * 2、设置价格
     * 3、创建支付信息 得到url
     * @return
     */
    @PostMapping("/pay")
    public String pay() throws StripeException {

        /* 这里生成随机价格  1000-9000的价格*/
        int max=9000;
        int min=1000;
        Random random = new Random();
        int randMoney = random.nextInt(max)%(max-min+1) + min;

        //创建产品 https://stripe.com/docs/api/products/create
        Map<String, Object> params = new HashMap<>();
        params.put("name", "产品名称-1");
        Product product = Product.create(params);

        //创建价格 https://stripe.com/docs/api/prices/create
        Map<String, Object> recurring = new HashMap<>();
        recurring.put("interval", "month");
        Map<String, Object> params2 = new HashMap<>();
        params2.put("unit_amount", randMoney);
        params2.put("currency", "usd");
        params2.put("recurring", recurring);
        params2.put("product", product.getId());
        Price price = Price.create(params2);
        System.out.println(price.toString());

        //创建支付信息 得到url
        SessionCreateParams params3 = SessionCreateParams.builder()
                        .setMode(SessionCreateParams.Mode.SUBSCRIPTION)
                        .setSuccessUrl("http://127.0.0.1:9900/success")
                        .setCancelUrl( "http://127.0.0.1:9900/cancel")
                        .addLineItem(
                                SessionCreateParams.LineItem.builder()
                                        .setQuantity(1L)
                                        .setPrice(price.getId())
                                        .build()).putMetadata("orderId",UUID.randomUUID().toString())
                        .build();
        Session session = Session.create(params3);
        return session.getUrl();

    }

    /**
     *           基本上会用到的api
     * 创建产品
     * 修改产品
     * 创建产品的价格
     * 修改产品的价格(注意这里,修改产品的价格是去把价格存档,然后再新增一条价格数据)
     * 得到这个产品的价格列表
     * 创建支付信息 得到url
     * @return
     */
    public void aa() throws StripeException {
        int max=9000;
        int min=1000;
        Random random = new Random();
        int randMoney = random.nextInt(max)%(max-min+1) + min;
        System.out.println(randMoney);

        //创建产品 https://stripe.com/docs/api/products/create
        Map<String, Object> params = new HashMap<>();
        params.put("name", "Gold Special");
        Product product = Product.create(params);
        System.out.println(product.toString());

        //修改产品 https://stripe.com/docs/api/products/update
        Product product2 = Product.retrieve(product.getId());
        Map<String, Object> params2 = new HashMap<>();
        params2.put("name", product.getName()+randMoney);
        Product updatedProduct = product2.update(params2);
        System.out.println(updatedProduct.toString());

        //创建价格 https://stripe.com/docs/api/prices/create
        Map<String, Object> recurring = new HashMap<>();
        recurring.put("interval", "month");
        Map<String, Object> params3 = new HashMap<>();
        params3.put("unit_amount", randMoney);
        params3.put("currency", "usd");
        params3.put("recurring", recurring);
        params3.put("product", product.getId());
        Price price = Price.create(params3);
        System.out.println(price.toString());

        //修改价格 (新建price,老的价格不用,存档) https://stripe.com/docs/products-prices/manage-prices?dashboard-or-api=api#edit-price
        Price resource = Price.retrieve(price.getId());
        PriceUpdateParams params4 = PriceUpdateParams.builder().setLookupKey(price.getLookupKey()).setActive(false).build();
        Price price2 = resource.update(params4);
        System.out.println(price2);

        //重新创建价格 https://stripe.com/docs/api/prices/create
        int randMoney3 = random.nextInt(max)%(max-min+1) + min;
        System.out.println(randMoney3);
        Map<String, Object> recurring2 = new HashMap<>();
        recurring2.put("interval", "month");
        Map<String, Object> params5 = new HashMap<>();
        params5.put("unit_amount", randMoney3);
        params5.put("currency", "usd");
        params5.put("recurring", recurring2);
        params5.put("product", product.getId());
        Price price3 = Price.create(params5);
        System.out.println(price3.toString());

        //得到这个产品的价格列表
        PriceListParams params6 = PriceListParams.builder().setProduct(product.getId()).setActive(true).build();
        PriceCollection prices = Price.list(params6);
        System.out.println(prices.toString());

        //创建支付信息 得到url
        SessionCreateParams params7 =
                SessionCreateParams.builder()
                        .setMode(SessionCreateParams.Mode.SUBSCRIPTION)
                        .setSuccessUrl("http://127.0.0.1:9900/success")
                        .setCancelUrl( "http://127.0.0.1:9900/cancel")
                        .addLineItem(
                                SessionCreateParams.LineItem.builder()
                                        .setQuantity(1L)// 购买数量
                                        .setPrice(price3.getId())// 购买价格
                                        .build())
                        .putMetadata("orderId",UUID.randomUUID().toString())//订单id 支付成功后,回调的时候拿到这个订单id,进行修改数据库状态
                        .build();
        Session session = Session.create(params7);
        System.out.println(session.toString());
        System.out.println("最后去支付的url:"+session.getUrl());
    }

    @RequestMapping("/success")
    public String success(){
        return "success";
    }

    @RequestMapping("/cancel")
    public String cancel(){
        return "cancel";
    }

}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <div>
        <button type="button" onclick="toPay()">创建商品并去支付</button>
    </div>

    <script ></script>
    <script src="/jquery.min.js"></script>
    <script>
        function toPay() {
            $.ajax({
                type : 'post',
                url : '/pay',
                data : {},
                success : function(res) {
                    alert(res)
                    window.location.href = res;
                },
                error : function(res) {
                    alert("网络错误");
                }
            });
        }
    </script>

</body>
</html>

支付成功回调

package com.japhet.stripesdemo.controller;

import com.alibaba.fastjson.JSONObject;
import com.stripe.model.*;
import com.stripe.net.Webhook;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;


@Controller
public class StripeBackController {
    @ResponseBody
    @RequestMapping(value = {"/stripe_events"}, method = RequestMethod.POST)
    public void stripe_events(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("------进入回调了------");
        try {
            String endpointSecret = "whsec_bdenE7xxxxxxxxxxx";//webhook秘钥签名
            InputStream inputStream = request.getInputStream();
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024*4];
            int n = 0;
            while (-1 != (n = inputStream.read(buffer))) {
                output.write(buffer, 0, n);
            }
            byte[] bytes = output.toByteArray();
            String payload = new String(bytes, "UTF-8");
            String sigHeader = request.getHeader("Stripe-Signature");
            Event event = Webhook.constructEvent(payload, sigHeader, endpointSecret);//验签,并获取事件

            switch(event.getType()) {
                case "checkout.session.completed"://支付完成
                    System.out.println("---------------success2222222---------------");
                    String s = event.getDataObjectDeserializer().getObject().get().toJson();
                    JSONObject jsonObject = JSONObject.parseObject(s);
                    JSONObject jsonObject2 = (JSONObject)jsonObject.get("metadata");
                    String orderId = jsonObject2.getString("orderId");
                    System.out.println("订单号为:"+orderId);
                    System.out.println("根据订单号从数据库中找到订单,并将状态置为支付成功状态");
                    break;
                case "checkout.session.expired"://过期
                    System.out.println("---------------checkout.session.expired---------------");
                    break;
                default:
                    break;
            }
        } catch (Exception e) {
            System.out.println("stripe异步通知(webhook事件)"+e);
        }
    }
}

--------------------------------------------------------------------------------

2023-07-28 10:15:00更新 ~~~~

写了这篇博客我看好多朋友都有疑问,都说要加我联系方式,我这里给出来大家可以加我,有问题可以及时与我沟通: QQ或微信都可以加我 517861659 

如果没有及时回复,可以点我先问问AI机器人icon-default.png?t=N7T8https://chatgpt.byabstudio.com/login?code=202307011314  

--------------------------------------------------------------------------------

2023-10-09 16:20:00更新 ~~~~

建群的目的是看到好多朋友都说有遇到一些问题,由于个人时间、技术、精力有限,所以大家有遇到相同的问题可以在群里讨论,大家互相帮助一下

猜你喜欢

转载自blog.csdn.net/Japhet_jiu/article/details/129838657