1、stripe
2、游客到试用用户身份转换
This commit is contained in:
9
pom.xml
9
pom.xml
@@ -248,7 +248,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.stripe</groupId>
|
<groupId>com.stripe</groupId>
|
||||||
<artifactId>stripe-java</artifactId>
|
<artifactId>stripe-java</artifactId>
|
||||||
<version>25.0.0</version>
|
<version>26.2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- aws s3 -->
|
<!-- aws s3 -->
|
||||||
@@ -271,8 +271,11 @@
|
|||||||
<artifactId>s3control</artifactId>
|
<artifactId>s3control</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.10.1</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class AuthenticationFilter extends OncePerRequestFilter {
|
|||||||
"/api/third/party/existNoLoginRequired","/api/third/party/getRedirectUrl",
|
"/api/third/party/existNoLoginRequired","/api/third/party/getRedirectUrl",
|
||||||
"/api/python/flush","/api/account/healthy","/api/ali-pay/trade/notify","/api/paypal/ipn/back","/api/alipay-hk/trade/notify",
|
"/api/python/flush","/api/account/healthy","/api/ali-pay/trade/notify","/api/paypal/ipn/back","/api/alipay-hk/trade/notify",
|
||||||
"/api/portfolio/page", "/api/portfolio/detail", "/api/portfolio/commentPage", "/api/portfolio/viewsIncrease",
|
"/api/portfolio/page", "/api/portfolio/detail", "/api/portfolio/commentPage", "/api/portfolio/viewsIncrease",
|
||||||
"/api/account/designWorksRegister","/api/account/questionnaire"
|
"/api/account/designWorksRegister","/api/account/questionnaire","/api/stripe/trade/notify"
|
||||||
);
|
);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
41
src/main/java/com/ai/da/controller/StripeController.java
Normal file
41
src/main/java/com/ai/da/controller/StripeController.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package com.ai.da.controller;
|
||||||
|
|
||||||
|
import com.ai.da.common.response.Response;
|
||||||
|
import com.ai.da.service.StripeService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Api(tags = "Stripe模块")
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/stripe")
|
||||||
|
public class StripeController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private StripeService stripeService;
|
||||||
|
|
||||||
|
@ApiOperation("创建支付链接")
|
||||||
|
@PostMapping("/createOrder/{amount}")
|
||||||
|
public Response<String> pay(@PathVariable Integer amount) {
|
||||||
|
return Response.success(stripeService.pay(amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("支付通知")
|
||||||
|
@PostMapping("/trade/notify")
|
||||||
|
public Response<String> callback(HttpServletRequest request) throws ServletException, IOException {
|
||||||
|
Boolean result = stripeService.notify(request);
|
||||||
|
if (result){
|
||||||
|
return Response.success(200,"success");
|
||||||
|
}else {
|
||||||
|
return Response.fail(400,"failure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@ public interface PayPalCheckoutService {
|
|||||||
Boolean doPost(HttpServletRequest req, HttpServletResponse resp)
|
Boolean doPost(HttpServletRequest req, HttpServletResponse resp)
|
||||||
throws ServletException, IOException;
|
throws ServletException, IOException;
|
||||||
|
|
||||||
|
String getBody(HttpServletRequest request) throws IOException;
|
||||||
|
|
||||||
Order queryOrder(String orderNo) throws SerializeException;
|
Order queryOrder(String orderNo) throws SerializeException;
|
||||||
|
|
||||||
Order captureOrder(String orderId) throws IOException;
|
Order captureOrder(String orderId) throws IOException;
|
||||||
|
|||||||
11
src/main/java/com/ai/da/service/StripeService.java
Normal file
11
src/main/java/com/ai/da/service/StripeService.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package com.ai.da.service;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
public interface StripeService {
|
||||||
|
|
||||||
|
String pay(Integer quantity);
|
||||||
|
|
||||||
|
Boolean notify(HttpServletRequest request);
|
||||||
|
}
|
||||||
@@ -508,7 +508,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
|||||||
QueryWrapper<Account> qw = new QueryWrapper<>();
|
QueryWrapper<Account> qw = new QueryWrapper<>();
|
||||||
qw.eq("BINARY user_email", accountTrialDTO.getEmail());
|
qw.eq("BINARY user_email", accountTrialDTO.getEmail());
|
||||||
List<Account> accountList = accountMapper.selectList(qw);
|
List<Account> accountList = accountMapper.selectList(qw);
|
||||||
if (CollectionUtil.isNotEmpty(accountList)) {
|
if (CollectionUtil.isNotEmpty(accountList) && !accountList.get(0).getSystemUser().equals(0)) {
|
||||||
if (accountList.get(0).getIsTrial() == 1) {
|
if (accountList.get(0).getIsTrial() == 1) {
|
||||||
throw new BusinessException("The email has already been registered", ResultEnum.PROMPT.getCode());
|
throw new BusinessException("The email has already been registered", ResultEnum.PROMPT.getCode());
|
||||||
} else {
|
} else {
|
||||||
@@ -538,6 +538,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
|||||||
account = CopyUtil.copyObject(accountList.get(0), Account.class);
|
account = CopyUtil.copyObject(accountList.get(0), Account.class);
|
||||||
account.setIsTrial(1);
|
account.setIsTrial(1);
|
||||||
account.setIsBeginner(1);
|
account.setIsBeginner(1);
|
||||||
|
account.setSystemUser(3);
|
||||||
account.setValidStartTime(System.currentTimeMillis());
|
account.setValidStartTime(System.currentTimeMillis());
|
||||||
if (link) {
|
if (link) {
|
||||||
account.setValidEndTime(Instant.now().plus(14, ChronoUnit.DAYS).toEpochMilli());
|
account.setValidEndTime(Instant.now().plus(14, ChronoUnit.DAYS).toEpochMilli());
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Simple helper method to fetch request data as a string from HttpServletRequest object.
|
// Simple helper method to fetch request data as a string from HttpServletRequest object.
|
||||||
private static String getBody(HttpServletRequest request) throws IOException {
|
public String getBody(HttpServletRequest request) throws IOException {
|
||||||
String body;
|
String body;
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
BufferedReader bufferedReader = null;
|
BufferedReader bufferedReader = null;
|
||||||
|
|||||||
285
src/main/java/com/ai/da/service/impl/StripeServiceImpl.java
Normal file
285
src/main/java/com/ai/da/service/impl/StripeServiceImpl.java
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
package com.ai.da.service.impl;
|
||||||
|
|
||||||
|
import com.ai.da.service.PayPalCheckoutService;
|
||||||
|
import com.ai.da.service.StripeService;
|
||||||
|
import com.stripe.Stripe;
|
||||||
|
import com.stripe.exception.SignatureVerificationException;
|
||||||
|
import com.stripe.exception.StripeException;
|
||||||
|
import com.stripe.model.*;
|
||||||
|
import com.stripe.model.checkout.Session;
|
||||||
|
import com.stripe.model.issuing.Card;
|
||||||
|
import com.stripe.net.Webhook;
|
||||||
|
import com.stripe.param.*;
|
||||||
|
import com.stripe.param.checkout.SessionCreateParams;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class StripeServiceImpl implements StripeService {
|
||||||
|
|
||||||
|
private static final String privateKey = "sk_test_51P4ZZL02n1TEydyN8qQHjOA9imsFU7Oxs2HMHGy2urHnnQgSHnZuu5vVP6pKhEACwUpsKNyrbZpdcg5TJWJLRHcY008dEO1fn2";
|
||||||
|
// private static final String privateKey = "pk_test_51P4ZZL02n1TEydyNluht6VDxnBMoBw8S524otzlXV3CMCZI8HmkcUr3CKy8Z0eQ2WssSJ9sAaZnIQJI04fARHHJi00pcIB4sKU";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 1、创建customer,获取customerId
|
||||||
|
// 2、创建客户支付方式 (从前端获取)
|
||||||
|
// 3、创建支付 paymentIntent
|
||||||
|
// 4、确认订单
|
||||||
|
// 5、捕获金额(执行扣款操作)
|
||||||
|
public static String createCustomer() throws StripeException {
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
|
||||||
|
// Customer允许重复使用
|
||||||
|
CustomerCreateParams params =
|
||||||
|
CustomerCreateParams.builder()
|
||||||
|
.setName("xp")
|
||||||
|
.setEmail("xupei3360@163.com")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Customer customer = Customer.create(params);
|
||||||
|
|
||||||
|
return customer.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createPaymentMethod(String customerId) throws StripeException {
|
||||||
|
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
|
||||||
|
PaymentMethodCreateParams params =
|
||||||
|
PaymentMethodCreateParams.builder()
|
||||||
|
.setType(PaymentMethodCreateParams.Type.CARD)
|
||||||
|
.setCard(
|
||||||
|
// 测试中,不建议使用卡号,会不安全的异常,必须使用token(https://docs.stripe.com/testing?testing-method=tokens#visa)
|
||||||
|
PaymentMethodCreateParams.Token.builder().setToken("tok_visa").build()
|
||||||
|
// PaymentMethodCreateParams.CardDetails.builder()
|
||||||
|
// .setNumber("4242424242424242")
|
||||||
|
// .setExpMonth(8L)
|
||||||
|
// .setExpYear(2026L)
|
||||||
|
// .setCvc("314")
|
||||||
|
// .build()
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
PaymentMethod paymentMethod = PaymentMethod.create(params);
|
||||||
|
|
||||||
|
/*try{
|
||||||
|
Map<String, Object> card = new HashMap<>();
|
||||||
|
card.put("exp_month",8L);
|
||||||
|
card.put("exp_year",2026L);
|
||||||
|
card.put("number","4242 4242 4242 42422");
|
||||||
|
card.put("cvc","314");
|
||||||
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.put("type", "card");
|
||||||
|
params.put("card", card);
|
||||||
|
PaymentMethod paymentMethod = PaymentMethod.create(params);
|
||||||
|
Map<String, Object> params2 = new HashMap<>();
|
||||||
|
params2.put("customer", customerId);
|
||||||
|
paymentMethod.attach(params2);
|
||||||
|
return paymentMethod.getId();
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}*/
|
||||||
|
// return null;
|
||||||
|
return paymentMethod.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createPaymentIntent(String paymentMethodId, String customerId) throws StripeException {
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
|
||||||
|
Long amount = 600L;
|
||||||
|
PaymentIntentCreateParams params =
|
||||||
|
PaymentIntentCreateParams.builder()
|
||||||
|
.setAmount(amount)
|
||||||
|
// .setPaymentMethod(paymentMethodId)
|
||||||
|
.setCustomer(customerId)
|
||||||
|
.setCurrency("hkd")
|
||||||
|
.setAutomaticPaymentMethods(
|
||||||
|
PaymentIntentCreateParams.AutomaticPaymentMethods.builder()
|
||||||
|
.setEnabled(true)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
PaymentIntent paymentIntent = PaymentIntent.create(params);
|
||||||
|
return paymentIntent.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String confirmPaymentIntent(String clientSecret) throws StripeException {
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
|
||||||
|
PaymentIntent resource = PaymentIntent.retrieve(clientSecret);
|
||||||
|
|
||||||
|
PaymentIntentConfirmParams params =
|
||||||
|
PaymentIntentConfirmParams.builder()
|
||||||
|
.setPaymentMethod("pm_card_visa")
|
||||||
|
.setReturnUrl("https://www.example.com")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
PaymentIntent paymentIntent = resource.confirm(params);
|
||||||
|
return paymentIntent.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String capturePaymentIntent(String clientSecret) throws StripeException {
|
||||||
|
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
|
||||||
|
PaymentIntent resource = PaymentIntent.retrieve(clientSecret);
|
||||||
|
|
||||||
|
PaymentIntentCaptureParams params = PaymentIntentCaptureParams.builder().build();
|
||||||
|
|
||||||
|
PaymentIntent paymentIntent = resource.capture(params);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws StripeException {
|
||||||
|
// String customerId = createCustomer();
|
||||||
|
// log.info(customerId);
|
||||||
|
String paymentMethodId = createPaymentMethod("cus_Pvc92hQPBgLE2t");
|
||||||
|
log.info(paymentMethodId);
|
||||||
|
// String substring = paymentMethodId.substring(0, paymentMethodId.lastIndexOf("_"));
|
||||||
|
// log.info(substring);
|
||||||
|
// log.info(substring.substring(0, substring.lastIndexOf("_")));
|
||||||
|
// String paymentIntentId = createPaymentIntent(null, "cus_Pvc92hQPBgLE2t");
|
||||||
|
// log.info(paymentIntentId);
|
||||||
|
|
||||||
|
// confirmPaymentIntent("pi_3P5lr002n1TEydyN0caeqdfq");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String pay(Integer quantity) {
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
try {
|
||||||
|
//创建产品
|
||||||
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.put("name", "AiDA 积分");
|
||||||
|
// PriceCreateParams.ProductData productData = new PriceCreateParams.ProductData.Builder().setName("AiDA 积分").build();
|
||||||
|
Product product = Product.create(params);
|
||||||
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||||
|
String format = simpleDateFormat.format(new Date());
|
||||||
|
|
||||||
|
//创建价格
|
||||||
|
Map<String, Object> priceParams = new HashMap<>();
|
||||||
|
// BigDecimal actualAmount = createOrderEntity.getAmount().multiply(BigDecimal.valueOf(100)); //stripe的默认单位是分,即传入的amount实际上小数点会被左移两位
|
||||||
|
BigDecimal actualAmount = new BigDecimal("600"); //stripe的默认单位是分,即传入的amount实际上小数点会被左移两位
|
||||||
|
//给price绑定元数据并更新price用于检索
|
||||||
|
Map<String, Object> metadata = new HashMap<>();
|
||||||
|
metadata.put("orderId", format);
|
||||||
|
priceParams.put("metadata", metadata); //通过订单号关联用于检索price信息(可选)
|
||||||
|
priceParams.put("unit_amount", actualAmount.intValue());
|
||||||
|
priceParams.put("currency", "HKD");
|
||||||
|
priceParams.put("product", product.getId());
|
||||||
|
// priceParams.put("product_data", product.getId());
|
||||||
|
// PriceCreateParams priceParam = PriceCreateParams.builder().setCurrency("HKD").setProductData(productData).setUnitAmount(Long.valueOf("6")).build();
|
||||||
|
Price price = Price.create(priceParams);
|
||||||
|
|
||||||
|
//创建支付信息得到url
|
||||||
|
SessionCreateParams params3 = SessionCreateParams.builder()
|
||||||
|
.setMode(SessionCreateParams.Mode.PAYMENT)
|
||||||
|
.setSuccessUrl("https://www.example.com") //可自定义成功页面
|
||||||
|
.setCancelUrl("https://www.example.com")
|
||||||
|
.addLineItem(
|
||||||
|
SessionCreateParams.LineItem.builder()
|
||||||
|
.setQuantity(Long.valueOf(quantity))
|
||||||
|
/*.setPriceData(
|
||||||
|
new SessionCreateParams.LineItem.PriceData.Builder()
|
||||||
|
.setCurrency("HKD")
|
||||||
|
.setUnitAmount(Long.valueOf("600"))
|
||||||
|
.setProductData(
|
||||||
|
new SessionCreateParams.LineItem.PriceData.ProductData.Builder()
|
||||||
|
.setName("AiDaA 积分")
|
||||||
|
.build())
|
||||||
|
.build())*/
|
||||||
|
.setPrice(price.getId())
|
||||||
|
.build())
|
||||||
|
.putMetadata("orderId",format) //通过订单号关联用于检索支付信息(可选)
|
||||||
|
.build();
|
||||||
|
Session session = Session.create(params3);
|
||||||
|
System.out.println("sessionId:" +session.getId());
|
||||||
|
String sessionId = session.getId(); //退款方式1:拿到sessionId入库,退款的时候根据这个id找到PaymentIntent的id然后发起退款
|
||||||
|
return session.getUrl();
|
||||||
|
}catch (Exception e){
|
||||||
|
log.error("创建支付会话出现异常:",e);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PayPalCheckoutService payPalCheckoutService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean notify(HttpServletRequest request){
|
||||||
|
log.info("stripe异步通知进行中");
|
||||||
|
String payload = null;
|
||||||
|
String sigHeader= null;
|
||||||
|
// String endpointSecret = "whsec_xxxgx92OjXdBf1lc2c";//webhook秘钥签名
|
||||||
|
String endpointSecret = "whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w";//webhook秘钥签名
|
||||||
|
try {
|
||||||
|
sigHeader = request.getHeader("Stripe-Signature");
|
||||||
|
payload = payPalCheckoutService.getBody(request);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("stripe 支付回调参数解析异常:errorMsg {}", e.getMessage());
|
||||||
|
log.info("request sigHeader = {}", sigHeader);
|
||||||
|
log.info("request body = {}", payload);
|
||||||
|
e.printStackTrace();
|
||||||
|
return Boolean.FALSE;
|
||||||
|
// response.setStatus(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
Event event = null;
|
||||||
|
try {
|
||||||
|
assert sigHeader != null;
|
||||||
|
event = Webhook.constructEvent(payload, sigHeader, endpointSecret);
|
||||||
|
} catch (SignatureVerificationException e) {
|
||||||
|
log.info("stripe 验签,获取事件异常, errorMsg=" + e.getMessage());
|
||||||
|
log.info("request sigHeader = {}", sigHeader);
|
||||||
|
log.info("request body = {}", payload);
|
||||||
|
e.printStackTrace();
|
||||||
|
return Boolean.FALSE;
|
||||||
|
// response.setStatus(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//获取自定义参数
|
||||||
|
// Deserialize the nested object inside the event
|
||||||
|
assert event != null;
|
||||||
|
EventDataObjectDeserializer dataObjectDeserializer = event.getDataObjectDeserializer();
|
||||||
|
StripeObject stripeObject = null;
|
||||||
|
if (dataObjectDeserializer.getObject().isPresent()) {
|
||||||
|
stripeObject = dataObjectDeserializer.getObject().get();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log.info("stripe 验签失败!");
|
||||||
|
log.info("request sigHeader = {}", sigHeader);
|
||||||
|
log.info("request body = {}", payload);
|
||||||
|
return Boolean.FALSE;
|
||||||
|
// response.setStatus(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getType().equals("checkout.session.completed")){
|
||||||
|
|
||||||
|
}
|
||||||
|
log.info("stripe验签成功");
|
||||||
|
return Boolean.TRUE;
|
||||||
|
// response.setStatus(200);
|
||||||
|
|
||||||
|
|
||||||
|
// 1、验签
|
||||||
|
|
||||||
|
// 2、处理订单
|
||||||
|
// 2.1 更新订单状态
|
||||||
|
// 2.2 添加积分
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user