1.什么是Stripe?
一体化全球支付平台,开启收入增长引擎,针对不同规模业务打造的支付解决方案,满足从初创公司到跨国企业的多维度需求,助力全球范围内线上线下付款。
转化更多客户: 通过内置的优化功能、100 多种支付方式及一键结账来提高转化率。实现线上和线下付款一体化,提供无缝的客户体验。
全球覆盖,本地体验: 引入多样化支付方式,采用当地货币呈现价格,以此快速拓展新市场,实现向 195+ 个国家/地区的跨境销售,有效降低管理多币种的成本。
减少欺诈,增加收入: Stripe 的机器学习优化功能基于数十亿数据点进行深度训练,为您自动降低欺诈风险,同时提升交易授权率。
降本增效,快速拓展: 通过提高开发人员的工作效率,节省时间和工程资源。凭借领先的可靠性避免宕机,并通过替代支付方式和路径降低成本。
2.代码工程
实验目标
1.实现一次支付功能 2.实现订阅支付功能
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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springboot-demo</artifactId> <groupId>com.et</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>stripe</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </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>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.stripe</groupId> <artifactId>stripe-java</artifactId> <version>25.7.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies> </project>
controller
package com.et.stripe.controller; import com.et.stripe.common.Response; import com.et.stripe.service.StripeService; import com.stripe.model.Coupon; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody;@ Controllerpublic class PaymentController {@ Value("${stripe.keys.public}") private String API_PUBLIC_KEY; private StripeService stripeService; public PaymentController(StripeService stripeService) { this.stripeService = stripeService; }@ GetMapping("/") public String homepage() { return "homepage"; }@ GetMapping("/subscription") public String subscriptionPage(Model model) { model.addAttribute("stripePublicKey", API_PUBLIC_KEY); return "subscription"; }@ GetMapping("/charge") public String chargePage(Model model) { model.addAttribute("stripePublicKey", API_PUBLIC_KEY); return "charge"; } /*========== REST APIs for Handling Payments ===================*/ @ PostMapping("/create-subscription") public@ ResponseBody Response createSubscription(String email, String token, String plan, String coupon) { //validate data if (token == null || plan.isEmpty()) { return new Response(false, "Stripe payment token is missing. Please, try again later."); } //create customer first String customerId = stripeService.createCustomer(email, token); if (customerId == null) { return new Response(false, "An error occurred while trying to create a customer."); } //create subscription String subscriptionId = stripeService.createSubscription(customerId, plan, coupon); if (subscriptionId == null) { return new Response(false, "An error occurred while trying to create a subscription."); } // Ideally you should store customerId and subscriptionId along with customer object here. // These values are required to update or cancel the subscription at later stage. return new Response(true, "Success! Your subscription id is " + subscriptionId); }@ PostMapping("/cancel-subscription") public@ ResponseBody Response cancelSubscription(String subscriptionId) { boolean status = stripeService.cancelSubscription(subscriptionId); if (!status) { return new Response(false, "Failed to cancel the subscription. Please, try later."); } return new Response(true, "Subscription cancelled successfully."); }@ PostMapping("/coupon-validator") public@ ResponseBody Response couponValidator(String code) { Coupon coupon = stripeService.retrieveCoupon(code); if (coupon != null && coupon.getValid()) { String details = (coupon.getPercentOff() == null ? "$" + (coupon.getAmountOff() / 100) : coupon.getPercentOff() + "%") + " OFF " + coupon.getDuration(); return new Response(true, details); } else { return new Response(false, "This coupon code is not available. This may be because it has expired or has " + "already been applied to your account."); } }@ PostMapping("/create-charge") public@ ResponseBody Response createCharge(String email, String token) { //validate data if (token == null) { return new Response(false, "Stripe payment token is missing. Please, try again later."); } //create charge String chargeId = stripeService.createCharge(email, token, 999); //$9.99 USD if (chargeId == null) { return new Response(false, "An error occurred while trying to create a charge."); } // You may want to store charge id along with order information return new Response(true, "Success! Your charge id is " + chargeId); } }
service
package com.et.stripe.service; import com.stripe.Stripe; import com.stripe.model.Charge; import com.stripe.model.Coupon; import com.stripe.model.Customer; import com.stripe.model.Subscription; import com.stripe.param.SubscriptionCancelParams; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map;@ Servicepublic class StripeService {@ Value("${stripe.keys.secret}") private String API_SECRET_KEY; public StripeService() {} public String createCustomer(String email, String token) { String id = null; try { Stripe.apiKey = API_SECRET_KEY; Map < String, Object > customerParams = new HashMap < > (); // add customer unique id here to track them in your web application customerParams.put("description", "Customer for " + email); customerParams.put("email", email); customerParams.put("source", token); // ^ obtained with Stripe.js //create a new customer Customer customer = Customer.create(customerParams); id = customer.getId(); } catch (Exception ex) { ex.printStackTrace(); } return id; } public String createSubscription(String customerId, String plan, String coupon) { String id = null; try { Stripe.apiKey = API_SECRET_KEY; Map < String, Object > item = new HashMap < > (); item.put("price", plan); Map < String, Object > items = new HashMap < > (); items.put("0", item); Map < String, Object > params = new HashMap < > (); params.put("customer", customerId); params.put("items", items); //add coupon if available if (!coupon.isEmpty()) { params.put("coupon", coupon); } Subscription sub = Subscription.create(params); id = sub.getId(); } catch (Exception ex) { ex.printStackTrace(); } return id; } public boolean cancelSubscription(String subscriptionId) { boolean status; try { Stripe.apiKey = API_SECRET_KEY; Subscription sub = Subscription.retrieve(subscriptionId); sub.cancel((SubscriptionCancelParams) null); status = true; } catch (Exception ex) { ex.printStackTrace(); status = false; } return status; } public Coupon retrieveCoupon(String code) { try { Stripe.apiKey = API_SECRET_KEY; return Coupon.retrieve(code); } catch (Exception ex) { ex.printStackTrace(); } return null; } public String createCharge(String email, String token, int amount) { String id = null; try { Stripe.apiKey = API_SECRET_KEY; Map < String, Object > chargeParams = new HashMap < > (); chargeParams.put("amount", amount); chargeParams.put("currency", "usd"); chargeParams.put("description", "Charge for " + email); chargeParams.put("source", token); // ^ obtained with Stripe.js //create a charge Charge charge = Charge.create(chargeParams); id = charge.getId(); } catch (Exception ex) { ex.printStackTrace(); } return id; } }
templates
homepage
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Homepage</title> <!--Bootstrap 4 CSS--> <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"> <!--Bootstrap 4 JavaScript--> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script> </head> <body class="bg-light pt-5"> <!--hero section--> <section class="py-5"> <div class="container"> <div class="row"> <div class="col-lg-7 col-md-10 col-12 my-auto mx-auto text-center"> <h1> Stripe Payment Examples </h1> <p class="lead mb-4"> What would you like to do? </p> <a class="btn btn-primary" th:href="@{/subscription}">Create Recurring Subscription</a> <a class="btn btn-success" th:href="@{/charge}">Create One-Time Charge</a> <p class="mt-5 text-muted"> <small>An example project by <a target="_blank" th:href="@{https://attacomsian.com}">Atta</a>.</small> </p> </div> </div> </div> </section> </body> </html>
charge
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Homepage</title> <!--Bootstrap 4 CSS--> <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"> <!--Bootstrap 4 JavaScript--> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script> </head> <body class="bg-light pt-5"> <!--hero section--> <section class="py-5"> <div class="container"> <div class="row"> <div class="col-lg-7 col-md-10 col-12 my-auto mx-auto text-center"> <h1> Stripe Payment Examples </h1> <p class="lead mb-4"> What would you like to do? </p> <a class="btn btn-primary" th:href="@{/subscription}">Create Recurring Subscription</a> <a class="btn btn-success" th:href="@{/charge}">Create One-Time Charge</a> <p class="mt-5 text-muted"> <small>An example project by <a target="_blank" th:href="@{https://attacomsian.com}">Atta</a>.</small> </p> </div> </div> </div> </section> </body> </html>
subscription
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Homepage</title> <!--Bootstrap 4 CSS--> <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"> <!--Bootstrap 4 JavaScript--> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script> </head> <body class="bg-light pt-5"> <!--hero section--> <section class="py-5"> <div class="container"> <div class="row"> <div class="col-lg-7 col-md-10 col-12 my-auto mx-auto text-center"> <h1> Stripe Payment Examples </h1> <p class="lead mb-4"> What would you like to do? </p> <a class="btn btn-primary" th:href="@{/subscription}">Create Recurring Subscription</a> <a class="btn btn-success" th:href="@{/charge}">Create One-Time Charge</a> <p class="mt-5 text-muted"> <small>An example project by <a target="_blank" th:href="@{https://attacomsian.com}">Atta</a>.</small> </p> </div> </div> </div> </section> </body> </html>
application.yaml
#Stripe keys - REPLACE WITH ACTUAL KEYS stripe.keys.public=pk_test_xxxxx stripe.keys.secret=sk_test_xxxxx #Don't cache thymeleaf files - FOR TEST PURPOSE ONLY spring.thymeleaf.cache=false
以上只是一些关键代码,所有代码请参见下面代码仓库
代码仓库
https://github.com/Harries/springboot-demo(stripe)
3.测试
启动Spring Boot应用
还没有评论,来说两句吧...