bihuisong 5 mesi fa
parent
commit
6d2a03be67

+ 1 - 0
pom.xml

@@ -247,6 +247,7 @@
         <module>qmjszx-generator</module>
         <module>qmjszx-common</module>
         <module>qmjszx-business</module>
+        <module>qmjszx-pay</module>
     </modules>
     <packaging>pom</packaging>
 

+ 12 - 0
qmjszx-admin/src/main/resources/application.yml

@@ -146,6 +146,18 @@ rsa:
   publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIdmTeQdUyYK2a5ivPXdYArOgDMDKu6ob7YPlaC6R1/XxjHhGaSIucYGrzO+JhCFNkhgHxmc4POpyFq+PFdLuNMCAwEAAQ==
   # 私钥
   privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAh2ZN5B1TJgrZrmK89d1gCs6AMwMq7qhvtg+VoLpHX9fGMeEZpIi5xgavM74mEIU2SGAfGZzg86nIWr48V0u40wIDAQABAkBbgNXu7ap9sSN/aJcPCXaYlwmob+GZvBcS0OFr57fImsxTEzWg/OJWxcbHk7Li31AbHjwqQmVtUxk2wQ6GawthAiEAve5+CCaUHV3BIH7LhzU7MsPAr6IIx25t1NkNNg+dn3kCIQC2f7XtdTOVRtPUwO7QhwC0fX/wJu53pR01p55tqmgLqwIgYzUHr8o243/tOMQCG4W6fjGxnAvO+hy8UcluFSbi9kECIQCAK4NOyPA4V6zwD6vpgdcJ69YNiJoUJz8zboxCwtodzwIgNUN6uuiVJuZmBJDm+9AIY7Ury+ajGRZJ7l1FIBbxMPY=
+# 微信支付配置
+# 微信支付配置 notifyUrl:微信支付异步回调地址
+wx:
+  pay:
+    appId: #应用id
+    apiV3Key: #商户私钥key
+    notifyUrl: #支付回调地址
+    merchantId: #商户id
+    appSecret: #小程序密钥
+    privateKeyPath: #证书认证是生成文件
+    merchantserialNumber: #证书序列号
+
 
 
 

+ 76 - 0
qmjszx-pay/pom.xml

@@ -0,0 +1,76 @@
+<?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>
+        <groupId>qmjszx</groupId>
+        <artifactId>qmjszx</artifactId>
+        <version>4.8.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>qmjszx-pay</artifactId>
+
+    <description>
+        支付模块
+    </description>
+
+    <dependencies>
+        <!-- spring-boot-devtools -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional> <!-- 表示依赖不会传递 -->
+        </dependency>
+
+        <!-- swagger3-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-boot-starter</artifactId>
+        </dependency>
+
+        <!-- 防止进入swagger页面报类型转换错误,排除3.0.0中的引用,手动增加1.6.2版本 -->
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>1.6.2</version>
+        </dependency>
+
+        <!-- Mysql驱动包 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>qmjszx</groupId>
+            <artifactId>qmjszx-framework</artifactId>
+        </dependency>
+
+        <!-- 定时任务-->
+        <dependency>
+            <groupId>qmjszx</groupId>
+            <artifactId>qmjszx-quartz</artifactId>
+        </dependency>
+
+        <!-- 代码生成-->
+        <dependency>
+            <groupId>qmjszx</groupId>
+            <artifactId>qmjszx-generator</artifactId>
+        </dependency>
+
+        <!-- 微信支付-->
+        <dependency>
+            <groupId>com.github.wechatpay-apiv3</groupId>
+            <artifactId>wechatpay-java</artifactId>
+            <version>0.2.15</version>
+        </dependency>
+        <dependency>
+            <groupId>com.squareup.okio</groupId>
+            <artifactId>okio</artifactId>
+            <version>3.3.0</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 76 - 0
qmjszx-pay/src/main/java/beilv/pay/config/WxPayConfig.java

@@ -0,0 +1,76 @@
+package beilv.pay.config;
+
+
+import com.wechat.pay.java.core.RSAAutoCertificateConfig;
+import com.wechat.pay.java.core.util.IOUtil;
+import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
+import com.wechat.pay.java.service.refund.RefundService;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.IOException;
+
+@Data
+@Slf4j
+@Configuration
+@ConfigurationProperties(prefix = "wx.pay")
+public class WxPayConfig {
+
+    private String appId;
+
+    private String apiV3Key;
+
+    private String notifyUrl;
+
+    private String merchantId;
+
+    private String privateKeyPath;
+
+    private String merchantSerialNumber;
+
+    // RSA配置
+    private RSAAutoCertificateConfig RSAConfig;
+
+    // JSAPI支付
+    private JsapiServiceExtension jsapiServiceExtension;
+
+    // 退款
+    private RefundService refundService;
+
+    /**
+     * 初始化配置
+     */
+    @Bean
+    public void initWxPayConfig() throws IOException {
+        this.RSAConfig = buildRSAAutoCertificateConfig();
+        this.jsapiServiceExtension = buildJsapiServiceExtension(RSAConfig);
+        this.refundService = buildRefundService(RSAConfig);
+    }
+
+    // 构建并使用自动更新平台证书的RSA配置,一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
+    private RSAAutoCertificateConfig buildRSAAutoCertificateConfig() throws IOException {
+        // 将 resource 目录下的文件转为 InputStream,然后利用 IOUtil.toString(inputStream) 转化为密钥
+        String privateKey = IOUtil.toString(new ClassPathResource(privateKeyPath).getInputStream());
+        return new RSAAutoCertificateConfig.Builder()
+                .merchantId(merchantId)
+                .privateKey(privateKey)
+                .merchantSerialNumber(merchantSerialNumber)
+                .apiV3Key(apiV3Key)
+                .build();
+    }
+
+    // 构建JSAPI
+    private JsapiServiceExtension buildJsapiServiceExtension(RSAAutoCertificateConfig config) {
+        return new JsapiServiceExtension.Builder().config(config).build();
+    }
+
+    // 构建退款
+    private RefundService buildRefundService(RSAAutoCertificateConfig config) {
+        return new RefundService.Builder().config(config).build();
+    }
+
+}

+ 65 - 0
qmjszx-pay/src/main/java/beilv/pay/controller/WxUserPayController.java

@@ -0,0 +1,65 @@
+package beilv.pay.controller;
+
+import beilv.common.core.domain.AjaxResult;
+import beilv.pay.service.WxUserPayService;
+import cn.hutool.core.util.IdUtil;
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
+import com.wechat.pay.java.service.payments.model.Transaction;
+import com.wechat.pay.java.service.refund.model.Refund;
+import com.wechat.pay.java.service.refund.model.RefundNotification;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+@RestController
+@RequestMapping
+public class WxUserPayController {
+    @Resource
+    private WxUserPayService wxUserPayService;
+
+    /**
+     * JSAPI 下单
+     */
+    @GetMapping("/create/IndentPayment")
+    public AjaxResult creationIndentPayment(String openId) {
+        PrepayWithRequestPaymentResponse paymentResponse = wxUserPayService.creationIndentPayment(IdUtil.simpleUUID(), openId, 0.01);
+        return AjaxResult.success(paymentResponse);
+    }
+
+    /**
+     * JSAPI 下单回调
+     */
+    @PostMapping("/end/IndentPayment")
+    @Transactional(rollbackFor = Exception.class)
+    public synchronized AjaxResult endIndentPayment(HttpServletRequest request) {
+        // 获取下单信息
+        Transaction transaction = wxUserPayService.getTransaction(request);
+        // 修改订单状态
+        boolean result = wxUserPayService.indentPaymentBlack(transaction);
+//        ThrowUtils.throwIf(!result, ErrorCode.SYSTEM_ERROR, "修改订单失败");
+        return AjaxResult.success(result);
+    }
+
+    /**
+     * 退款
+     */
+    @GetMapping("/refund/IndentPayment")
+    public AjaxResult refundIndentPayment(@RequestParam String orderId, @RequestParam Double amount) {
+        Refund refund = wxUserPayService.refundIndentPayment(orderId, amount);
+        return AjaxResult.success(refund);
+    }
+
+    /**
+     * 退款回调
+     */
+    @PostMapping("/refund/black")
+    public AjaxResult endRefundIndent(HttpServletRequest request) {
+        // 获取退款信息
+        RefundNotification refundNotification = wxUserPayService.getRefundNotification(request);
+        // 修改订单状态
+        boolean result = wxUserPayService.refundIndentBlack(refundNotification);
+        return AjaxResult.success(result);
+    }
+}

+ 30 - 0
qmjszx-pay/src/main/java/beilv/pay/service/WxUserPayService.java

@@ -0,0 +1,30 @@
+package beilv.pay.service;
+
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
+import com.wechat.pay.java.service.payments.model.Transaction;
+import com.wechat.pay.java.service.refund.model.Refund;
+import com.wechat.pay.java.service.refund.model.RefundNotification;
+
+import javax.servlet.http.HttpServletRequest;
+
+public interface WxUserPayService {
+
+
+    // 微信支付
+    PrepayWithRequestPaymentResponse creationIndentPayment(String indentId, String myOpenId, Double amount);
+
+    // 获取支付回调信息
+    Transaction getTransaction(HttpServletRequest request);
+
+    // 支付回调
+    boolean indentPaymentBlack(Transaction transaction);
+
+    // 退款申请
+    Refund refundIndentPayment(String refundId, Double amount);
+
+    // 获取退款回调信息
+    RefundNotification getRefundNotification(HttpServletRequest request);
+
+    // 退款回调
+    boolean refundIndentBlack(RefundNotification refundNotification);
+}

+ 165 - 0
qmjszx-pay/src/main/java/beilv/pay/service/impl/WxUserPayServiceImpl.java

@@ -0,0 +1,165 @@
+package beilv.pay.service.impl;
+
+import beilv.pay.config.WxPayConfig;
+import beilv.pay.service.WxUserPayService;
+import com.wechat.pay.java.core.notification.NotificationParser;
+import com.wechat.pay.java.core.notification.RequestParam;
+import com.wechat.pay.java.service.payments.jsapi.model.Amount;
+import com.wechat.pay.java.service.payments.jsapi.model.Payer;
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
+import com.wechat.pay.java.service.payments.model.Transaction;
+import com.wechat.pay.java.service.refund.model.AmountReq;
+import com.wechat.pay.java.service.refund.model.CreateRequest;
+import com.wechat.pay.java.service.refund.model.Refund;
+import com.wechat.pay.java.service.refund.model.RefundNotification;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.math.BigDecimal;
+
+@Service
+@Slf4j
+public class WxUserPayServiceImpl implements WxUserPayService {
+
+    @Resource
+    private WxPayConfig wxPayConfig;
+//    @Resource
+//    private UserOrderMapper userOrderMapper;
+    /**
+     * 请求参数
+     */
+    public static RequestParam requestParam = null;
+
+    @Override
+    public PrepayWithRequestPaymentResponse creationIndentPayment(String orderId, String myOpenId, Double amount) {
+        PrepayRequest request = new PrepayRequest();
+        // 金额
+        Amount WxAmount = new Amount();
+        WxAmount.setTotal(new BigDecimal(String.valueOf(amount)).movePointRight(2).intValue());
+        WxAmount.setCurrency("CNY");
+        request.setAmount(WxAmount);
+        // 公众号appId
+        request.setAppid(wxPayConfig.getAppId());
+        // 商户号
+        request.setMchid(wxPayConfig.getMerchantId());
+        // 支付者信息
+        Payer payer = new Payer();
+        payer.setOpenid(myOpenId);
+        request.setPayer(payer);
+        // 描述
+        request.setDescription("代办服务");
+        // 微信回调地址
+        request.setNotifyUrl(wxPayConfig.getNotifyUrl() + "/end/IndentPayment");
+        //系统内部订单号
+        request.setOutTradeNo(orderId);
+        //返回数据,前端调起支付
+        return wxPayConfig.getJsapiServiceExtension().prepayWithRequestPayment(request);
+    }
+
+    // 获取支付回调信息
+    @Override
+    public Transaction getTransaction(HttpServletRequest request) {
+        NotificationParser notificationParser = getNotificationParser(request);
+        return notificationParser.parse(requestParam, Transaction.class);
+    }
+
+    // 支付回调
+    @Override
+    public boolean indentPaymentBlack(Transaction transaction) {
+        System.out.println("---------------------------修改订单状态信息(下单)-------------------------------");
+        // 获取订单号
+        String orderId = transaction.getOutTradeNo();
+//        UserOrder userOrder = userOrderMapper.selectById(orderId);
+//        if (userOrder == null) {
+//            log.error("订单不存在");
+//            throw new BusinessException(40004,"订单不存在:" + transaction.getOutTradeNo());
+//        }
+//        log.info("下单成功");
+//        LambdaUpdateWrapper<UserOrder> updateWrapper = new LambdaUpdateWrapper<>();
+//        updateWrapper.set(UserOrder::getIsTrue,"已支付").eq(UserOrder::getOrderId,orderId);
+//        userOrderMapper.update(null,updateWrapper);
+        System.out.println("---------------------------修改订单状态信息完毕-------------------------------");
+        System.out.println("---------------------------添加微信支付记录完毕-------------------------------");
+        return true;
+    }
+
+    @Override
+    public Refund refundIndentPayment(String refundId, Double amount) {
+        // 退款请求
+        CreateRequest createRequest = new CreateRequest();
+        // 商户订单号
+        createRequest.setOutTradeNo(refundId);
+        // 商户退款单号
+        createRequest.setOutRefundNo(refundId);
+        // 退款结果回调
+        createRequest.setNotifyUrl(wxPayConfig.getNotifyUrl() + "/refund/black");
+        // 退款金额
+        AmountReq amountReq = new AmountReq();
+        long refundAmount = new BigDecimal(String.valueOf(amount)).movePointRight(2).intValue();
+        amountReq.setRefund(refundAmount);
+        amountReq.setTotal(refundAmount);
+        amountReq.setCurrency("CNY");
+        createRequest.setAmount(amountReq);
+        // 申请退款
+        System.out.println("退款请求:" + createRequest);
+        Refund refund = wxPayConfig.getRefundService().create(createRequest);
+        System.out.println("退款申请结果:" + refund);
+        return refund;
+    }
+
+    // 获取退款回调信息
+    @Override
+    public RefundNotification getRefundNotification(HttpServletRequest request) {
+        NotificationParser notificationParser = getNotificationParser(request);
+        return notificationParser.parse(requestParam, RefundNotification.class);
+    }
+
+    // 退款回调
+    @Override
+    public boolean refundIndentBlack(RefundNotification refundNotification) {
+        System.out.println("---------------------------修改订单状态信息(退款)-------------------------------");
+        // 获取订单号
+        String indentIdByString = refundNotification.getOutTradeNo();
+        System.out.println("---------------------------修改订单状态信息完毕-------------------------------");
+        return true;
+    }
+
+    /**
+     * 根据微信官方发送的请求获取信息
+     */
+    @SneakyThrows
+    public NotificationParser getNotificationParser(HttpServletRequest request) {
+        System.out.println("---------------------------获取信息-------------------------------");
+        // 获取RSA配置
+        NotificationParser notificationParser = new NotificationParser(wxPayConfig.getRSAConfig());
+        // 构建请求
+        StringBuilder bodyBuilder = new StringBuilder();
+        BufferedReader reader = request.getReader();
+        String line;
+        while ((line = reader.readLine()) != null) {
+            bodyBuilder.append(line);
+        }
+        String body = bodyBuilder.toString();
+        String timestamp = request.getHeader("Wechatpay-Timestamp");
+        String nonce = request.getHeader("Wechatpay-Nonce");
+        String signature = request.getHeader("Wechatpay-Signature");
+        String singType = request.getHeader("Wechatpay-Signature-Type");
+        String wechatPayCertificateSerialNumber = request.getHeader("Wechatpay-Serial");
+        requestParam = new RequestParam.Builder()
+                .serialNumber(wechatPayCertificateSerialNumber)
+                .nonce(nonce)
+                .signature(signature)
+                .timestamp(timestamp)
+                .signType(singType)
+                .body(body)
+                .build();
+        System.out.println(requestParam.toString());
+        System.out.println("---------------------------信息获取完毕-------------------------------");
+        return notificationParser;
+    }
+}