From f03d32030df81068b469c48b17ab68b8b4c7e4aa Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 15 Jul 2024 13:42:18 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81stripe=202=E3=80=81=E6=B8=B8=E5=AE=A2?= =?UTF-8?q?=E5=88=B0=E8=AF=95=E7=94=A8=E7=94=A8=E6=88=B7=E8=BA=AB=E4=BB=BD?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 9 +- .../security/filter/AuthenticationFilter.java | 2 +- .../ai/da/controller/StripeController.java | 41 +++ .../ai/da/service/PayPalCheckoutService.java | 2 + .../java/com/ai/da/service/StripeService.java | 11 + .../da/service/impl/AccountServiceImpl.java | 3 +- .../impl/PayPalCheckoutServiceImpl.java | 2 +- .../ai/da/service/impl/StripeServiceImpl.java | 285 ++++++++++++++++++ 8 files changed, 349 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/ai/da/controller/StripeController.java create mode 100644 src/main/java/com/ai/da/service/StripeService.java create mode 100644 src/main/java/com/ai/da/service/impl/StripeServiceImpl.java diff --git a/pom.xml b/pom.xml index 8ec5336d..3f0e4094 100644 --- a/pom.xml +++ b/pom.xml @@ -248,7 +248,7 @@ com.stripe stripe-java - 25.0.0 + 26.2.0 @@ -271,8 +271,11 @@ s3control - - + + com.google.code.gson + gson + 2.10.1 + diff --git a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java index 0d1bed1a..fdd4c6fe 100644 --- a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java +++ b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java @@ -50,7 +50,7 @@ public class AuthenticationFilter extends OncePerRequestFilter { "/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/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 diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java new file mode 100644 index 00000000..a7f8f76c --- /dev/null +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -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 pay(@PathVariable Integer amount) { + return Response.success(stripeService.pay(amount)); + } + + @ApiOperation("支付通知") + @PostMapping("/trade/notify") + public Response callback(HttpServletRequest request) throws ServletException, IOException { + Boolean result = stripeService.notify(request); + if (result){ + return Response.success(200,"success"); + }else { + return Response.fail(400,"failure"); + } + } +} diff --git a/src/main/java/com/ai/da/service/PayPalCheckoutService.java b/src/main/java/com/ai/da/service/PayPalCheckoutService.java index 450c521d..d9da17e4 100644 --- a/src/main/java/com/ai/da/service/PayPalCheckoutService.java +++ b/src/main/java/com/ai/da/service/PayPalCheckoutService.java @@ -19,6 +19,8 @@ public interface PayPalCheckoutService { Boolean doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException; + String getBody(HttpServletRequest request) throws IOException; + Order queryOrder(String orderNo) throws SerializeException; Order captureOrder(String orderId) throws IOException; diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java new file mode 100644 index 00000000..c4a09be1 --- /dev/null +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -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); +} diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index c6376ee0..5d73d098 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -508,7 +508,7 @@ public class AccountServiceImpl extends ServiceImpl impl QueryWrapper qw = new QueryWrapper<>(); qw.eq("BINARY user_email", accountTrialDTO.getEmail()); List accountList = accountMapper.selectList(qw); - if (CollectionUtil.isNotEmpty(accountList)) { + if (CollectionUtil.isNotEmpty(accountList) && !accountList.get(0).getSystemUser().equals(0)) { if (accountList.get(0).getIsTrial() == 1) { throw new BusinessException("The email has already been registered", ResultEnum.PROMPT.getCode()); } else { @@ -538,6 +538,7 @@ public class AccountServiceImpl extends ServiceImpl impl account = CopyUtil.copyObject(accountList.get(0), Account.class); account.setIsTrial(1); account.setIsBeginner(1); + account.setSystemUser(3); account.setValidStartTime(System.currentTimeMillis()); if (link) { account.setValidEndTime(Instant.now().plus(14, ChronoUnit.DAYS).toEpochMilli()); diff --git a/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java b/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java index f4fd04b4..796bea28 100644 --- a/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java @@ -189,7 +189,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { } // 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; StringBuilder stringBuilder = new StringBuilder(); BufferedReader bufferedReader = null; diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java new file mode 100644 index 00000000..a984048d --- /dev/null +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -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 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 params = new HashMap<>(); + params.put("type", "card"); + params.put("card", card); + PaymentMethod paymentMethod = PaymentMethod.create(params); + Map 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 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 priceParams = new HashMap<>(); +// BigDecimal actualAmount = createOrderEntity.getAmount().multiply(BigDecimal.valueOf(100)); //stripe的默认单位是分,即传入的amount实际上小数点会被左移两位 + BigDecimal actualAmount = new BigDecimal("600"); //stripe的默认单位是分,即传入的amount实际上小数点会被左移两位 + //给price绑定元数据并更新price用于检索 + Map 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 添加积分 + } + + +}