loemkie 1 mês atrás
pai
commit
061fe0ef0b
46 arquivos alterados com 3085 adições e 28 exclusões
  1. 60 2
      pom.xml
  2. 36 0
      src/main/java/com/pay/wxpayback/Enum/WxApiType.java
  3. 67 0
      src/main/java/com/pay/wxpayback/Enum/WxPayStatusEnum.java
  4. 75 0
      src/main/java/com/pay/wxpayback/api/CommonController.java
  5. 121 0
      src/main/java/com/pay/wxpayback/api/CommonResult.java
  6. 18 0
      src/main/java/com/pay/wxpayback/api/IErrorCode.java
  7. 31 0
      src/main/java/com/pay/wxpayback/api/ResultCode.java
  8. 10 0
      src/main/java/com/pay/wxpayback/api/Supplier.java
  9. 91 0
      src/main/java/com/pay/wxpayback/config/mybatisPlus/CodeGenerator.java
  10. 30 0
      src/main/java/com/pay/wxpayback/config/mybatisPlus/MyMetaObjectHandler.java
  11. 38 0
      src/main/java/com/pay/wxpayback/config/mybatisPlus/MybatisPlusConfig.java
  12. 61 0
      src/main/java/com/pay/wxpayback/constant/SystemConstant.java
  13. 158 0
      src/main/java/com/pay/wxpayback/constant/wxpay/WXOrderConstant.java
  14. 38 0
      src/main/java/com/pay/wxpayback/constant/wxpay/WechatPayHttpHeaders.java
  15. 178 0
      src/main/java/com/pay/wxpayback/controller/OrderController.java
  16. 41 0
      src/main/java/com/pay/wxpayback/controller/ToolWxConfigController.java
  17. 85 0
      src/main/java/com/pay/wxpayback/controller/UserController.java
  18. 35 0
      src/main/java/com/pay/wxpayback/exception/ApiException.java
  19. 18 0
      src/main/java/com/pay/wxpayback/exception/Asserts.java
  20. 72 0
      src/main/java/com/pay/wxpayback/exception/GlobalExceptionHandler.java
  21. 18 0
      src/main/java/com/pay/wxpayback/mapper/OrderMapper.java
  22. 18 0
      src/main/java/com/pay/wxpayback/mapper/ToolWxConfigMapper.java
  23. 62 0
      src/main/java/com/pay/wxpayback/pojo/Order.java
  24. 64 0
      src/main/java/com/pay/wxpayback/pojo/ToolWxConfig.java
  25. 38 0
      src/main/java/com/pay/wxpayback/pojo/WxUser.java
  26. 17 0
      src/main/java/com/pay/wxpayback/pojo/dto/LoginParam.java
  27. 16 0
      src/main/java/com/pay/wxpayback/pojo/dto/UserParam.java
  28. 56 0
      src/main/java/com/pay/wxpayback/pojo/vo/ReCreateOrderVO.java
  29. 40 0
      src/main/java/com/pay/wxpayback/pojo/vo/ToCreateOrderVO.java
  30. 16 0
      src/main/java/com/pay/wxpayback/pojo/vo/UserInfo.java
  31. 16 0
      src/main/java/com/pay/wxpayback/pojo/vo/WxLoginVO.java
  32. 119 0
      src/main/java/com/pay/wxpayback/service/OrderService.java
  33. 24 0
      src/main/java/com/pay/wxpayback/service/ToolWxConfigService.java
  34. 33 0
      src/main/java/com/pay/wxpayback/service/UserService.java
  35. 371 0
      src/main/java/com/pay/wxpayback/service/impl/OrderServiceImpl.java
  36. 29 0
      src/main/java/com/pay/wxpayback/service/impl/ToolWxConfigServiceImpl.java
  37. 102 0
      src/main/java/com/pay/wxpayback/service/impl/UserServiceImpl.java
  38. 197 0
      src/main/java/com/pay/wxpayback/utils/IdWorker.java
  39. 230 0
      src/main/java/com/pay/wxpayback/utils/WxPayUtil.java
  40. 49 6
      src/main/java/com/qmrb/system/controller/AuthController.java
  41. 206 0
      src/main/java/com/qmrb/system/service/impl/JsapiService.java
  42. 64 0
      src/main/java/com/qmrb/system/service/impl/WeChatPayService.java
  43. 26 19
      src/main/resources/application-dev.yml
  44. 1 1
      src/main/resources/application.yml
  45. 5 0
      src/main/resources/mapper/OrderMapper.xml
  46. 5 0
      src/main/resources/mapper/ToolWxConfigMapper.xml

+ 60 - 2
pom.xml

@@ -194,7 +194,11 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-validation</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>javax.validation</groupId>
+            <artifactId>validation-api</artifactId>
+            <version>2.0.1.Final</version>
+        </dependency>
         <!-- 分布式文件存储 -->
         <dependency>
             <groupId>io.minio</groupId>
@@ -383,7 +387,61 @@
             <artifactId>pdfbox</artifactId>
             <version>2.0.25</version> <!-- 使用适合你项目的版本 -->
         </dependency>
-
+        <!--<dependency>
+            <groupId>com.github.wechatpay-apiv3</groupId>
+            <artifactId>wechatpay-apache-httpclient</artifactId>
+            <version>0.4.7</version>
+        </dependency>-->
+        <!--<dependency>
+            <groupId>com.github.wechatpay-apiv3</groupId>
+            <artifactId>wechatpay-java</artifactId>
+            <version>0.2.14</version>
+        </dependency>-->
+            <!-- HTTP客户端 -->
+            <!-- XML解析 -->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.13</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.13.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <version>1.70</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>4.0.1</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
+            <version>5.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <!--微信支付    -->
+        <dependency>
+            <groupId>com.github.wechatpay-apiv3</groupId>
+            <artifactId>wechatpay-apache-httpclient</artifactId>
+            <version>0.4.6</version>
+        </dependency>
+        <!--参数校验-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>3.5.1</version>
+        </dependency>
     </dependencies>
     <build>
         <finalName>${project.artifactId}</finalName>

+ 36 - 0
src/main/java/com/pay/wxpayback/Enum/WxApiType.java

@@ -0,0 +1,36 @@
+package com.pay.wxpayback.Enum;
+
+/**
+  *微信支付 api调用接口
+  * @author zhangjunrong
+  * @date 2022/5/9 19:57
+  */
+public enum WxApiType {
+
+    WX_LOGIN_URL ("https://api.weixin.qq.com/sns/jscode2session"),
+
+    /** 小程序 下单API */
+    CREATE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"),
+
+    /** 申请退款API 通过 outTradeNo 商户订单号 退单*/
+    REFUND_ORDER("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"),
+
+    /** 查询支付订单API ONE{}=>outTradeNo – 商户订单号 系统生 TOW{}=>mchId商户的商户号,由微信支付生成并下发。 */
+    QUERY_CREATE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{}?mchid={}"),
+
+    /** 查询退款订单API {}=>outRefundNo 商户退款单号*/
+    QUERY_REFUND_ORDER("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/{}"),
+
+    /** 关闭订单API {}=>outTradeNo 商户订单号*/
+    CLOSE_ORDER("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{}/close");
+
+    private final String value;
+
+    WxApiType(String value) {
+        this.value = value;
+    }
+
+    public String getValue() {
+        return value;
+    }
+}

+ 67 - 0
src/main/java/com/pay/wxpayback/Enum/WxPayStatusEnum.java

@@ -0,0 +1,67 @@
+package com.pay.wxpayback.Enum;
+
+/**
+ * @Description 微信支付状态
+ * @Author 小乌龟
+ * @Date 2022/5/14 10:56
+ */
+public enum WxPayStatusEnum {
+    /** 未支付 */
+    NOTPAY(0,"NOTPAY"),
+
+    /** 支付成功 */
+    SUCCESS(1,"SUCCESS"),
+
+    /** 转入退款 */
+    REFUND(2,"REFUND"),
+
+    /** 已关闭 */
+    CLOSED(3,"CLOSED"),
+    /**  退款处理中 */
+    REF_PROCESSING(2,"PROCESSING"),
+    /**  退款成功 */
+    REF_SUCCESS(3,"SUCCESS"),
+    /** 退款已关闭 */
+    REF_CLOSED(4,"CLOSED"),
+    /** 退款异常 */
+    REF_ABNORMAL(4,"ABNORMAL");
+
+
+
+
+    private final Integer code;
+    private final String value;
+
+    WxPayStatusEnum(Integer code,String value) {
+        this.code=code;
+        this.value = value;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    /**
+      *退款状态 转换 String => int
+      * @param value 退款String
+      * @return Integer
+      * @author zhangjunrong
+      * @date 2022/5/19 13:47
+      */
+    public static Integer getCode(String value){
+        switch(value){
+            case "PROCESSING":
+                return REF_PROCESSING.code;
+            case "SUCCESS":
+                return REF_SUCCESS.code;
+            case "CLOSED":
+                return REF_CLOSED.code;
+            default:
+                return REF_ABNORMAL.code;
+        }
+    }
+}

+ 75 - 0
src/main/java/com/pay/wxpayback/api/CommonController.java

@@ -0,0 +1,75 @@
+package com.pay.wxpayback.api;
+
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.pay.wxpayback.constant.SystemConstant;
+import com.pay.wxpayback.exception.ApiException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.ObjectError;
+
+import java.util.List;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+/**
+ * @Description controller层封装返回结果
+ * @Author 小乌龟
+ * @Date 2022/11/12 15:14
+ */
+@Slf4j
+public class CommonController {
+    /**
+     *
+     * @param br
+     * @param <M>
+     * @return
+     */
+    public <M> CommonResult<M> process(BindingResult br){
+        if (br.hasErrors()){
+            return errorResult(br);
+        }else {
+            return successResult();
+        }
+    }
+
+    public <M> CommonResult<M> process(Supplier<M> sp){
+        try {
+            M val = sp.get();
+            if (ObjectUtils.isEmpty(val)){
+                return  CommonResult.failed();
+            }
+            return CommonResult.success(val);
+        }catch (ApiException e) {
+            log.error(this.getClass().getSimpleName(), e);
+            log.error(this.getClass().getSimpleName(),e.getLocalizedMessage());
+            return CommonResult.failed(e.getErrorCode());
+        } catch (Exception e){
+            log.error(this.getClass().getSimpleName(), e);
+            log.error(this.getClass().getSimpleName(),e.getLocalizedMessage());
+            return CommonResult.failed(e.getMessage());
+        }
+    }
+
+    public <M> CommonResult<M> process(Supplier<M> sp, BindingResult br){
+        if (br.hasErrors()){
+            return errorResult(br);
+        }else {
+            return process(sp);
+        }
+    }
+
+    private <M> CommonResult<M> errorResult(BindingResult br) {
+        List<String> errs = br.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.toList());
+        return (CommonResult<M>) CommonResult.failed(ResultCode.VALIDATE_FAILED,errs.get(0));
+    }
+
+
+    private <M> CommonResult<M>  successResult() {
+        CommonResult<M> CommonResult = new CommonResult<>();
+        CommonResult.setCode(ResultCode.SUCCESS.getCode());
+        CommonResult.setMessage(ResultCode.SUCCESS.getMessage());
+        CommonResult.setData(null);
+        return CommonResult;
+    }
+
+}

+ 121 - 0
src/main/java/com/pay/wxpayback/api/CommonResult.java

@@ -0,0 +1,121 @@
+package com.pay.wxpayback.api;
+
+/**
+ * @Description 通用返回对象
+ * @Author 小乌龟
+ * @Date 2022/11/12 14:58
+ */
+public class CommonResult<T> {
+    /**
+     * 状态码
+     */
+    private long code;
+    /**
+     * 提示信息
+     */
+    private String message;
+    /**
+     * 数据封装
+     */
+    private T data;
+
+    protected CommonResult() {
+    }
+
+    protected CommonResult(long code, String message, T data) {
+        this.code = code;
+        this.message = message;
+        this.data = data;
+    }
+
+    /**
+     * 成功返回结果
+     *
+     * @param data 获取的数据
+     */
+    public static <T> CommonResult<T> success(T data) {
+        return new CommonResult<T>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);
+    }
+
+    /**
+     * 成功返回结果
+     *
+     * @param data 获取的数据
+     * @param  message 提示信息
+     */
+    public static <T> CommonResult<T> success(T data, String message) {
+        return new CommonResult<T>(ResultCode.SUCCESS.getCode(), message, data);
+    }
+
+    /**
+     * 失败返回结果
+     * @param errorCode 错误码
+     */
+    public static <T> CommonResult<T> failed(IErrorCode errorCode) {
+        return new CommonResult<T>(errorCode.getCode(), errorCode.getMessage(), null);
+    }
+
+    /**
+     * 失败返回结果
+     * @param errorCode 错误码
+     * @param message 错误信息
+     */
+    public static <T> CommonResult<T> failed(IErrorCode errorCode,String message) {
+        return new CommonResult<T>(errorCode.getCode(), message, null);
+    }
+
+    /**
+     * 失败返回结果
+     * @param message 提示信息
+     */
+    public static <T> CommonResult<T> failed(String message) {
+        return new CommonResult<T>(ResultCode.FAILED.getCode(), message, null);
+    }
+
+    /**
+     * 失败返回结果
+     */
+    public static <T> CommonResult<T> failed() {
+        return failed(ResultCode.FAILED);
+    }
+
+    /**
+     * 参数验证失败返回结果
+     */
+    public static <T> CommonResult<T> validateFailed() {
+        return failed(ResultCode.VALIDATE_FAILED);
+    }
+
+    /**
+     * 参数验证失败返回结果
+     * @param message 提示信息
+     */
+    public static <T> CommonResult<T> validateFailed(String message) {
+        return new CommonResult<T>(ResultCode.VALIDATE_FAILED.getCode(), message, null);
+    }
+
+
+    public long getCode() {
+        return code;
+    }
+
+    public void setCode(long code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+}

+ 18 - 0
src/main/java/com/pay/wxpayback/api/IErrorCode.java

@@ -0,0 +1,18 @@
+package com.pay.wxpayback.api;
+
+/**
+ * @Description 常用API返回对象接口
+ * @Author 小乌龟
+ * @Date 2022/11/12 14:58
+ */
+public interface IErrorCode {
+    /**
+     * 返回码
+     */
+    int getCode();
+
+    /**
+     * 返回信息
+     */
+    String getMessage();
+}

+ 31 - 0
src/main/java/com/pay/wxpayback/api/ResultCode.java

@@ -0,0 +1,31 @@
+package com.pay.wxpayback.api;
+
+/**
+ * @Description 常用API返回对象
+ * @Author 小乌龟
+ * @Date 2022/11/12 14:57
+ */
+public enum ResultCode implements IErrorCode{
+    SUCCESS(200, "操作成功"),
+    FAILED(500, "操作失败"),
+    VALIDATE_FAILED(404, "参数检验失败"),
+
+    PAY_FAILED(412, "参数检验失败");
+    private int code;
+    private String message;
+
+    private ResultCode(int code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    @Override
+    public int getCode() {
+        return code;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+}

+ 10 - 0
src/main/java/com/pay/wxpayback/api/Supplier.java

@@ -0,0 +1,10 @@
+package com.pay.wxpayback.api;
+
+/**
+ * controller层 函数编程
+ * @author 小乌龟
+ */
+@FunctionalInterface
+public interface Supplier<T> {
+    T get();
+}

+ 91 - 0
src/main/java/com/pay/wxpayback/config/mybatisPlus/CodeGenerator.java

@@ -0,0 +1,91 @@
+package com.pay.wxpayback.config.mybatisPlus;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.generator.FastAutoGenerator;
+import com.baomidou.mybatisplus.generator.config.OutputFile;
+import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
+import com.baomidou.mybatisplus.generator.fill.Column;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author 小王八
+ * @date 2022-09-05
+ * @Description:
+ */
+public class CodeGenerator {
+
+    public static void main(String[] args) {
+        FastAutoGenerator.create("jdbc:mysql://localhost:3306/wxpay?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai","root","password")
+                // 全局配置
+                .globalConfig((scanner, builder) -> builder
+                        .author(scanner.apply("请输入作者名称?")).fileOverride()
+                        // 开启 swagger 模式
+//                        .enableSwagger()
+                        // 覆盖已生成文件
+                        .fileOverride()
+                        //禁止打开输出目录
+                        .disableOpenDir()
+                        //配置时间
+                        .commentDate("yyyy-MM-dd")
+                        // 指定输出目录
+                        .outputDir(System.getProperty("user.dir")+"/src/main/java")
+                )
+                // 包配置
+                .packageConfig(builder -> {
+                    // 设置父包名
+                    builder.parent("com.pay.wxpayback")
+                            .entity("pojo")
+                            .controller("controller")
+                            .service("service")
+                            .serviceImpl("service.impl")
+                            .mapper("mapper")
+                            .xml("mapper.xml")
+                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml,System.getProperty("user.dir")+"/src/main/resources/mapper")); // 设置mapperXml生成路径
+                })
+                // 策略配置
+                .strategyConfig((scanner, builder) -> builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
+                        //controller 配置
+                        .controllerBuilder()
+                        .formatFileName("%sController")
+                        .enableRestStyle()
+                        .enableHyphenStyle()
+                        //service 配置
+                        .serviceBuilder()
+                        .formatServiceFileName("%sService")
+                        .formatServiceImplFileName("%sServiceImpl")
+                        //pojo 配置
+                        .entityBuilder()
+                        .enableLombok()
+                        //自动插入 更新时间 创造时间
+                        .addTableFills(new Column("gmt_create", FieldFill.INSERT))
+                        .addTableFills(new Column("gmt_update",FieldFill.INSERT_UPDATE))
+                        .enableTableFieldAnnotation()
+                        //mapper 配置
+                        .mapperBuilder()
+                        .superClass(BaseMapper.class)
+                        .formatMapperFileName("%sMapper")
+                        .enableMapperAnnotation()
+                        .formatXmlFileName("%sMapper")
+                        .build())
+                /*
+                    模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker
+                   .templateEngine(new BeetlTemplateEngine())
+                   */
+
+                   .templateEngine(new FreemarkerTemplateEngine())
+
+                .execute();
+    }
+
+
+        // 处理 all 情况
+        protected static List<String> getTables(String tables) {
+            return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
+        }
+
+
+}

+ 30 - 0
src/main/java/com/pay/wxpayback/config/mybatisPlus/MyMetaObjectHandler.java

@@ -0,0 +1,30 @@
+package com.pay.wxpayback.config.mybatisPlus;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import org.apache.ibatis.reflection.MetaObject;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author 小王八
+ * @date 2021/10/5
+ * @Description:
+ * mybatis自动填充功能
+ */
+
+@Component
+public class MyMetaObjectHandler implements MetaObjectHandler {
+
+    @Override
+    public void insertFill(MetaObject metaObject) {
+        this.strictInsertFill(metaObject, "gmtCreate", LocalDateTime.class, LocalDateTime.now());
+        this.strictUpdateFill(metaObject, "gmtUpdate",  LocalDateTime.class, LocalDateTime.now());
+    }
+
+    @Override
+    public void updateFill(MetaObject metaObject) {
+        this.strictUpdateFill(metaObject, "gmtUpdate",  LocalDateTime.class, LocalDateTime.now());
+    }
+}
+

+ 38 - 0
src/main/java/com/pay/wxpayback/config/mybatisPlus/MybatisPlusConfig.java

@@ -0,0 +1,38 @@
+package com.pay.wxpayback.config.mybatisPlus;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+/**
+ * @author 小王八
+ * @date 2021/9/23
+ * @Description:
+ */
+@Configuration
+@EnableTransactionManagement
+@MapperScan("com.pay.*.mapper")
+public class MybatisPlusConfig {
+
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        //分页配置
+        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
+        return interceptor;
+    }
+    @Bean
+    public MybatisPlusInterceptor paginationInterceptor() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        // 防止全表更新与删除
+        // 针对 update 和 delete 语句
+        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
+        return interceptor;
+    }
+
+}

+ 61 - 0
src/main/java/com/pay/wxpayback/constant/SystemConstant.java

@@ -0,0 +1,61 @@
+package com.pay.wxpayback.constant;
+
+/**
+ * @Description 系统常量
+ * @Author 小乌龟
+ * @Date 2022/11/10 19:53
+ */
+public class SystemConstant {
+
+    /**
+     * 微信支付
+     */
+    /**
+     * 支付回调url
+     */
+    public final static String PAY_NOTIFY_URL="https://域名配置/pay/order/wechatPayCallback";
+
+    public final static String REFUND_NOTIFY_URL="https://域名配置/pay/order/wechatRefundBack";
+    /**
+     * 固定支付参数 package
+     */
+    public final static String WX_PACKAGE="prepay_id=";
+
+    public final static String PAY_SUCCESS="支付成功";
+
+    /**
+     * 币种 RMB
+     */
+    public final static String CURRENCY_RMB="CNY";
+    /**
+     * 数字 0~11
+     */
+    public final static int NUM_NEGATIVE_ONE = -1;
+    public final static int NUM_ZERO = 0;
+    public final static int NUM_ONE = 1;
+    public final static int NUM_TWO = 2;
+    public final static int NUM_THREE = 3;
+    public final static int NUM_FOUR = 4;
+    public final static int NUM_FIVE = 5;
+    public final static int NUM_SIX = 6;
+    public final static int NUM_SEVEN = 7;
+    public final static int NUM_EIGHT = 8;
+    public final static int NUM_NINE = 9;
+    public final static int NUM_TEN = 10;
+    public final static int NUM_ELEVEN = 11;
+    public final static int NUM_15 = 15;
+    public final static int NUM_16 = 16;
+    public final static int NUM_19 = 19;
+    public final static int NUM_TWENTY = 20;
+    public final static int NUM_30 = 30;
+    public final static int NUM_32 = 32;
+    public final static int NUM_50 = 50;
+    public final static int NUM_60 = 60;
+    public final static int NUM_64 = 64;
+    public final static int NUM_90 = 90;
+    public final static int NUM_100 = 100;
+    public final static int NUM_200 = 200;
+    public final static int NUM_1024 = 1024;
+    public final static int NUM_5000 = 5000;
+    public final static int NUM_24_time =86400; //60*60*60*24 一天
+}

+ 158 - 0
src/main/java/com/pay/wxpayback/constant/wxpay/WXOrderConstant.java

@@ -0,0 +1,158 @@
+package com.pay.wxpayback.constant.wxpay;
+
+/**
+ * @Description 微信支付参数
+ * @Author 小乌龟
+ * @Date 2022/5/4 8:44
+ */
+public class WXOrderConstant {
+
+    /**
+     *应用ID
+     */
+    public final static String APPID ="appid";
+
+    /**
+     *直连商户号
+     */
+    public final static String MCHID ="mchid";
+
+    /**
+     *用户支付状态
+     */
+    public final static String TRADE_STATE ="trade_state";
+
+    /**
+     *用户退款状态
+     */
+    public final static String STATUS ="status";
+
+
+    /**
+     *商品描述
+     */
+    public final static String DESCRIPTION ="description";
+
+    /**
+     *通知地址
+     */
+    public final static String NOTIFY_URL ="notify_url";
+
+    /**
+     *预支付交易会话标识
+     */
+    public final static String PREPAY_ID ="prepay_id";
+
+    /**
+     *商户订单号
+     */
+    public final static String OUT_TRADE_NO ="out_trade_no";
+
+    /**
+     *商户退款单号
+     */
+    public final static String OUT_REFUND_NO ="out_refund_no";
+
+    /**
+     *微信支付系统生成的订单号
+     */
+    public final static String TRANSACTION_ID ="transaction_id";
+
+    /**
+     *微信支付系统生成的订单号
+     */
+    public final static String REFUND_ID ="refund_id";
+    /**
+     *订单金额
+     */
+    public final static String AMOUNT ="amount";
+    /**
+     *总金额	下单时系统计算金额 单位为分
+     */
+    public final static String AMOUNT_TOTAL ="total";
+
+    /**
+     *支付者
+     */
+    public final static String PAYER ="payer";
+
+    /**
+     *用户在直连商户appid下的唯一标识。 下单前需获取到用户的Openid
+     */
+    public final static String OPENID ="openid";
+
+    /**
+     *总金额	退款时 退款金额
+     */
+    public final static String AMOUNT_REFUND ="refund";
+
+    /**
+     *总金额	退款时 币种
+     */
+    public final static String AMOUNT_CURRENCY ="currency";
+
+    /**
+     *用户支付金额
+     */
+    public final static String AMOUNT_PAYER_TOTAL ="payer_total";
+    /**
+     *优惠功能
+     */
+    public final static String PROMOTION_DETAIL ="promotion_detail";
+    /**
+     *优惠类型
+     */
+    public final static String PROMOTION_DETAIL_TYPE ="type";
+    /**
+     * 微信优惠 CASH:充值型代金券
+     */
+    public final static String WX_DISCOUNT_TYPE="CASH";
+
+    /**
+     *下单回调给微信支付成功信息
+     */
+    public final static String WX_BACK_OK="SUCCESS";
+
+    /**
+     *退款回调 退款状态
+     */
+    public final static String REFUND_STATUS="refund_status";
+
+
+    /**
+     *微信回调 通知数据
+     */
+    public final static String RESOURCE="resource";
+
+    /**
+     *微信账单类型 交易账单
+     */
+    public final static String TRADE_BILL="tradebill";
+    /**
+     *微信账单类型 资金账单
+     */
+    public final static String FUND_FLOW_BILL="fundflowbill";
+    /**
+     *微信账单下载地址
+     */
+    public final static String DOWNLOAD_URL="download_url";
+
+    /**
+     *微信回调 通知数据=>数据密文
+     */
+    public final static String RESOURCE_CIPHERTEXT="ciphertext";
+
+    /**
+     *微信回调 通知数据=>附加数据
+     */
+    public final static String RESOURCE_ASSOCIATED_DATA="associated_data";
+
+    /**
+     *微信回调 通知数据=>随机串
+     */
+    public final static String RESOURCE_NONCE="nonce";
+
+
+
+
+}

+ 38 - 0
src/main/java/com/pay/wxpayback/constant/wxpay/WechatPayHttpHeaders.java

@@ -0,0 +1,38 @@
+package com.pay.wxpayback.constant.wxpay;
+
+/**
+ *微信支付HTTP请求头相关常量
+ * @author zhangjunrong
+ * @return
+ */
+public final class WechatPayHttpHeaders {
+    //请求头配置
+    public static final String ACCEPT = "Accept";
+
+    public static final String CONTENT_TYPE = "Content-type";
+
+    public static final String APPLICATION_JSON = "application/json";
+
+    public static final String APPLICATION_JSON_UTF = "application/json; charset=utf-8";
+    /**
+      *微信回调参数==>微信序列号
+      */
+    public static final String WECHATPAY_SERIAL = "Wechatpay-Serial";
+    /**
+     *微信回调参数==>应答随机串
+     */
+    public static final String WECHATPAY_NONCE="Wechatpay-Nonce";
+    /**
+     *微信回调参数==>应答时间戳
+     */
+    public static final String WECHATPAY_TIMESTAMP="Wechatpay-Timestamp";
+    /**
+     *微信回调参数==>应答签名
+     */
+    public static final String WECHATPAY_SIGNATURE="Wechatpay-Signature";
+
+    private WechatPayHttpHeaders() {
+        // Don't allow instantiation
+    }
+
+}

+ 178 - 0
src/main/java/com/pay/wxpayback/controller/OrderController.java

@@ -0,0 +1,178 @@
+package com.pay.wxpayback.controller;
+
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.json.JSONUtil;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.pay.wxpayback.api.CommonController;
+import com.pay.wxpayback.api.CommonResult;
+import com.pay.wxpayback.constant.SystemConstant;
+import com.pay.wxpayback.constant.wxpay.WXOrderConstant;
+import com.pay.wxpayback.pojo.Order;
+import com.pay.wxpayback.pojo.ToolWxConfig;
+import com.pay.wxpayback.pojo.dto.LoginParam;
+import com.pay.wxpayback.pojo.dto.UserParam;
+import com.pay.wxpayback.pojo.vo.ReCreateOrderVO;
+import com.pay.wxpayback.pojo.vo.ToCreateOrderVO;
+import com.pay.wxpayback.pojo.vo.UserInfo;
+import com.pay.wxpayback.pojo.vo.WxLoginVO;
+import com.pay.wxpayback.service.OrderService;
+import com.pay.wxpayback.service.ToolWxConfigService;
+import com.pay.wxpayback.service.UserService;
+import com.pay.wxpayback.utils.WxPayUtil;
+import com.wechat.pay.contrib.apache.httpclient.exception.ParseException;
+import com.wechat.pay.contrib.apache.httpclient.exception.ValidationException;
+import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <p>
+ * 订单表 前端控制器
+ * </p>
+ *
+ * @author 小王八
+ * @since 2023-07-28
+ */
+@RestController
+@RequestMapping("/order")
+@Slf4j
+public class OrderController extends CommonController {
+
+    @Autowired
+    private OrderService orderService;
+
+    @Autowired
+    private UserService userService;
+
+    @Autowired
+    private ToolWxConfigService toolWxConfigService;
+
+    /**
+     * 根据code获取openId,session_key,用于支付
+     * @param loginVO
+     * @return
+     */
+    @PostMapping("/wxLogin")
+    public CommonResult<WxLoginVO> wxLogin(@RequestBody  WxLoginVO loginVO){
+        return process(() -> orderService.getOpenId(toolWxConfigService.findConf(),loginVO));
+    }
+
+    /**
+     * 获取当前默认用户信息
+     * @param userParam
+     * @return
+     */
+    @GetMapping("/getMyInfo")
+    public CommonResult<UserInfo> getMyInfo(UserParam userParam){
+        return process(() -> userService.getMyInfo(userParam));
+    }
+
+    /**
+     * 微信小程序登录
+     * @param loginParam
+     * @return
+     */
+    @GetMapping("/wxMpLogin")
+    public CommonResult<UserInfo> wxMpLogin(LoginParam loginParam){
+        return process(() -> userService.wxMpLogin(loginParam));
+    }
+
+
+    @PostMapping("/createOrder")
+    public CommonResult<ReCreateOrderVO> createOrder(@RequestBody  ToCreateOrderVO toCreatOrderVO){
+        Long id = IdUtil.getSnowflake().nextId();
+        toCreatOrderVO.setOutTradeNo(id.toString());
+        //订单入库
+        orderService.save(new Order().setAmount(toCreatOrderVO.getTotal())
+                .setPayDescription(toCreatOrderVO.getDescription())
+                 .setPkId(id)
+                 .setPayStatus(SystemConstant.NUM_ZERO));
+        return process(() -> orderService.createOrder(toolWxConfigService.findConf(),toCreatOrderVO));
+    }
+
+    @GetMapping("/refundOrder")
+    public CommonResult<String> refundOrder(@RequestParam("outTradeNo") String outTradeNo){
+        return process(() -> orderService.refundOrder(toolWxConfigService.findConf(), orderService.getById(outTradeNo)));
+    }
+
+    /**
+     * 支付回调给微信确认
+     * @param request
+     * @return
+     */
+    @PostMapping("/wechatPayCallback")
+    public String wechatCallback(HttpServletRequest request) {
+        ToolWxConfig wxConfig = toolWxConfigService.findConf();
+        log.info("微信退款回调通知调用=============================");
+        Map<String,String> result = new HashMap(SystemConstant.NUM_16);
+        result.put("code", "FAIL");
+        result.put("message","失败");
+        try {
+            //微信回调信息校验
+            // 构建request,传入必要参数
+            Notification notification = WxPayUtil.verifyBack(request, wxConfig);
+            log.info("=================微信验证签名成功=======成功时间=={}=====",notification.getCreateTime());
+            notification.getSummary();
+            if(SystemConstant.PAY_SUCCESS.equals(notification.getSummary())){
+                if (orderService.verifyCreateOrder(notification.getDecryptData())) {
+                    log.info("==============================微信退款成功订单=====================================");
+                    result.put("code", WXOrderConstant.WX_BACK_OK);
+                    result.put("message", "支付回调成功");
+                }
+            }
+        } catch (ValidationException | ParseException | IOException e) {
+            log.error("微信支付回调失败验证" + e);
+        }
+        log.info("微信返回结果"+result);
+        return JSONUtil.toJsonStr(result);
+    }
+
+    @GetMapping("/closeOrder")
+    public void closeOrder(@RequestParam("outTradeNo") String outTradeNo) {
+        orderService.closeOrder(toolWxConfigService.findConf(),outTradeNo);
+    }
+
+    @PostMapping("/wechatRefundBack")
+    public String wechatRefundBack(HttpServletRequest request) {
+        ToolWxConfig wxConfig = toolWxConfigService.findConf();
+        Map result = new HashMap();
+        result.put("code", "FAIL");
+        result.put("message","失败");
+        try {
+            //微信回调信息校验
+            // 构建request,传入必要参数
+            Notification notification = WxPayUtil.verifyBack(request, wxConfig);
+            log.info("=================微信验证签名成功=======成功时间=={}=====", notification.getCreateTime());
+            // 根据退款返回结果 更新订单状态 返回结果
+            if(orderService.updateRefundOrder(notification.getDecryptData())){
+                log.info("==============================微信退款成功订单=====================================");
+                result.put("code", WXOrderConstant.WX_BACK_OK);
+                result.put("message", "退款回调成功");
+            }
+        } catch (ValidationException | ParseException | IOException e) {
+            log.error("微信退款回调失败" + e);
+        }
+
+        return JSONUtil.toJsonStr(result);
+    }
+
+    @GetMapping("/toQueryOrderState")
+    public CommonResult<String> toQueryOrderState(@RequestParam("outTradeNo") String outTradeNo) {
+        return process(() -> orderService.queryCreateOrder(toolWxConfigService.findConf(), outTradeNo));
+    }
+
+    @GetMapping("/toQueryRefundState")
+    public CommonResult<String> toQueryRefundState(@RequestParam("refundNo") String refundNo) {
+        return process(() -> orderService.queryRefundOrder(toolWxConfigService.findConf(), refundNo));
+    }
+}

+ 41 - 0
src/main/java/com/pay/wxpayback/controller/ToolWxConfigController.java

@@ -0,0 +1,41 @@
+package com.pay.wxpayback.controller;
+
+
+import com.pay.wxpayback.constant.SystemConstant;
+import com.pay.wxpayback.constant.wxpay.WXOrderConstant;
+import com.pay.wxpayback.pojo.ToolWxConfig;
+import com.pay.wxpayback.service.ToolWxConfigService;
+import com.pay.wxpayback.utils.WxPayUtil;
+import com.wechat.pay.contrib.apache.httpclient.exception.ParseException;
+import com.wechat.pay.contrib.apache.httpclient.exception.ValidationException;
+import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <p>
+ * 微信支付参数表 前端控制器
+ * </p>
+ *
+ * @author 小乌龟
+ * @since 2022-11-09
+ */
+@RestController
+@RequestMapping("/tool-wx-config")
+@Slf4j
+public class ToolWxConfigController {
+
+    @Autowired
+    private ToolWxConfigService toolWxConfigService;
+
+
+}

+ 85 - 0
src/main/java/com/pay/wxpayback/controller/UserController.java

@@ -0,0 +1,85 @@
+package com.pay.wxpayback.controller;
+
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.json.JSONUtil;
+import com.pay.wxpayback.api.CommonController;
+import com.pay.wxpayback.api.CommonResult;
+import com.pay.wxpayback.constant.SystemConstant;
+import com.pay.wxpayback.constant.wxpay.WXOrderConstant;
+import com.pay.wxpayback.pojo.Order;
+import com.pay.wxpayback.pojo.ToolWxConfig;
+import com.pay.wxpayback.pojo.dto.LoginParam;
+import com.pay.wxpayback.pojo.dto.UserParam;
+import com.pay.wxpayback.pojo.vo.ReCreateOrderVO;
+import com.pay.wxpayback.pojo.vo.ToCreateOrderVO;
+import com.pay.wxpayback.pojo.vo.UserInfo;
+import com.pay.wxpayback.pojo.vo.WxLoginVO;
+import com.pay.wxpayback.service.OrderService;
+import com.pay.wxpayback.service.ToolWxConfigService;
+import com.pay.wxpayback.service.UserService;
+import com.pay.wxpayback.utils.WxPayUtil;
+import com.wechat.pay.contrib.apache.httpclient.exception.ParseException;
+import com.wechat.pay.contrib.apache.httpclient.exception.ValidationException;
+import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <p>
+ * 用户中心 前端控制器
+ * </p>
+ *
+ * @author 小王八
+ * @since 2023-07-28
+ */
+@RestController
+@RequestMapping("/ucenter")
+@Slf4j
+public class UserController extends CommonController {
+
+
+    @Autowired
+    private UserService userService;
+
+    @Autowired
+    private ToolWxConfigService toolWxConfigService;
+
+    /**
+     * 根据code获取openId,session_key,用于支付
+     * @param loginVO
+     * @return
+     */
+    @PostMapping("/wxLogin")
+    public CommonResult<WxLoginVO> wxLogin(@RequestBody  WxLoginVO loginVO){
+        return process(() -> userService.getOpenId(toolWxConfigService.findConf(),loginVO));
+    }
+
+    /**
+     * 获取当前默认用户信息
+     * @param userParam
+     * @return
+     */
+    @GetMapping("/getMyInfo")
+    public CommonResult<UserInfo> getMyInfo(UserParam userParam){
+        return process(() -> userService.getMyInfo(userParam));
+    }
+
+    /**
+     * 微信小程序登录
+     * @param loginParam
+     * @return
+     */
+    @GetMapping("/wxMpLogin")
+    public CommonResult<UserInfo> wxMpLogin(LoginParam loginParam){
+        return process(() -> userService.wxMpLogin(loginParam));
+    }
+
+
+}

+ 35 - 0
src/main/java/com/pay/wxpayback/exception/ApiException.java

@@ -0,0 +1,35 @@
+package com.pay.wxpayback.exception;
+
+import com.pay.wxpayback.api.IErrorCode;
+
+/**
+ * @Description 自定义API异常
+ * @Author 小乌龟
+ * @Date 2022/11/12 14:49
+ */
+public class ApiException extends RuntimeException{
+
+    private IErrorCode errorCode;
+
+    public ApiException(IErrorCode errorCode) {
+        super(errorCode.getMessage());
+        this.errorCode = errorCode;
+    }
+
+    public ApiException(String message) {
+        super(message);
+    }
+
+
+    public ApiException(Throwable cause) {
+        super(cause);
+    }
+
+    public ApiException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public IErrorCode getErrorCode() {
+        return errorCode;
+    }
+}

+ 18 - 0
src/main/java/com/pay/wxpayback/exception/Asserts.java

@@ -0,0 +1,18 @@
+package com.pay.wxpayback.exception;
+
+import com.pay.wxpayback.api.IErrorCode;
+
+/**
+ * @Description 断言处理类,用于抛出各种API异常
+ * @Author 小乌龟
+ * @Date 2022/11/12 14:49
+ */
+public class Asserts {
+    public static void fail(String message) {
+        throw new ApiException(message);
+    }
+
+    public static void fail(IErrorCode errorCode) {
+        throw new ApiException(errorCode);
+    }
+}

+ 72 - 0
src/main/java/com/pay/wxpayback/exception/GlobalExceptionHandler.java

@@ -0,0 +1,72 @@
+package com.pay.wxpayback.exception;
+
+import com.pay.wxpayback.api.CommonResult;
+import com.pay.wxpayback.constant.SystemConstant;
+import org.springframework.validation.BindException;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @Description 全局异常捕获
+ * @Author 小乌龟
+ * @Date 2022/11/12 14:49
+ */
+@ControllerAdvice
+public class GlobalExceptionHandler {
+
+    /**
+     * 自定义异常
+     */
+    @ResponseBody
+    @ExceptionHandler(value = ApiException.class)
+    public CommonResult handle(ApiException e) {
+        if (e.getErrorCode() != null) {
+            return CommonResult.failed(e.getErrorCode());
+        }
+        return CommonResult.failed(e.getMessage());
+    }
+
+    /**
+     *BindException MethodArgumentNotValidException  validation异常 ConstraintViolationException (全部都是参数异常)
+     */
+    @ResponseBody
+    @ExceptionHandler(value = MethodArgumentNotValidException.class)
+    public CommonResult handleValidException(MethodArgumentNotValidException e) {
+        return getCommonResult(e);
+    }
+
+    @ResponseBody
+    @ExceptionHandler(value = BindException.class)
+    public CommonResult handleValidException(BindException e) {
+        return getCommonResult(e);
+    }
+
+    @ResponseBody
+    @ExceptionHandler(value = ConstraintViolationException.class)
+    public CommonResult handleValidException(ConstraintViolationException e) {
+        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
+        String message = violations.stream().map(ConstraintViolation::getMessage).collect(Collectors.toList()).get(SystemConstant.NUM_ZERO);
+        return CommonResult.failed(message);
+    }
+
+    private CommonResult getCommonResult(BindException e) {
+        BindingResult bindingResult = e.getBindingResult();
+        String message = null;
+        if (bindingResult.hasErrors()) {
+            FieldError fieldError = bindingResult.getFieldError();
+            if (fieldError != null) {
+                message = fieldError.getDefaultMessage();
+            }
+        }
+        return CommonResult.validateFailed(message);
+    }
+}

+ 18 - 0
src/main/java/com/pay/wxpayback/mapper/OrderMapper.java

@@ -0,0 +1,18 @@
+package com.pay.wxpayback.mapper;
+
+import com.pay.wxpayback.pojo.Order;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 订单表 Mapper 接口
+ * </p>
+ *
+ * @author 小王八
+ * @since 2023-07-28
+ */
+@Mapper
+public interface OrderMapper extends BaseMapper<Order> {
+
+}

+ 18 - 0
src/main/java/com/pay/wxpayback/mapper/ToolWxConfigMapper.java

@@ -0,0 +1,18 @@
+package com.pay.wxpayback.mapper;
+
+import com.pay.wxpayback.pojo.ToolWxConfig;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 微信支付参数表 Mapper 接口
+ * </p>
+ *
+ * @author 小乌龟
+ * @since 2022-11-09
+ */
+@Mapper
+public interface ToolWxConfigMapper extends BaseMapper<ToolWxConfig> {
+
+}

+ 62 - 0
src/main/java/com/pay/wxpayback/pojo/Order.java

@@ -0,0 +1,62 @@
+package com.pay.wxpayback.pojo;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * <p>
+ * 订单表
+ * </p>
+ *
+ * @author 小王八
+ * @since 2023-07-28
+ */
+@Data
+@Accessors(chain = true)
+@TableName("pay_order")
+public class Order implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 本系统生成的订单
+     */
+    @TableId("pk_id")
+    private Long pkId;
+
+    /**
+     * 商品实付金额(单位:分)
+     */
+    @TableField("amount")
+    private Integer amount;
+
+    /**
+     * 下单时间
+     */
+    @TableField(value = "gmt_create", fill = FieldFill.INSERT)
+    private LocalDateTime gmtCreate;
+
+    /**
+     * 支付状态:0 未支付 1 已支付 2 退款中 3 已退款 4 退款失败
+     */
+    @TableField("pay_status")
+    private Integer payStatus;
+
+    /**
+     * 订单描述
+     */
+    @TableField("pay_description")
+    private String payDescription;
+
+
+}

+ 64 - 0
src/main/java/com/pay/wxpayback/pojo/ToolWxConfig.java

@@ -0,0 +1,64 @@
+package com.pay.wxpayback.pojo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 微信支付参数表
+ * </p>
+ *
+ * @author 小乌龟
+ * @since 2022-11-09
+ */
+@Data
+@TableName("tool_wx_config")
+public class ToolWxConfig implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId("pk_id")
+    private Integer pkId;
+
+    /**
+     * 微信开放平台申请APPID
+     */
+    @TableField("app_id")
+    private String appId;
+    /**
+     * 微信商户号
+     */
+    @TableField("mch_id")
+    private String mchId;
+
+    /**
+     * 商户证书序列号
+     */
+    @TableField("mch_serial_no")
+    private String mchSerialNo;
+
+    /**
+     * api密钥
+     */
+    @TableField("api_v3_key")
+    private String apiV3Key;
+
+    /**
+     * 商户密钥
+     */
+    @TableField("private_key")
+    private String privateKey;
+
+    /**
+     * 商户密钥
+     */
+    @TableField("app_secret")
+    private String appSecret;
+
+}

+ 38 - 0
src/main/java/com/pay/wxpayback/pojo/WxUser.java

@@ -0,0 +1,38 @@
+package com.pay.wxpayback.pojo;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 订单表
+ * </p>
+ *
+ * @author 小王八
+ * @since 2023-07-28
+ */
+@Data
+@Accessors(chain = true)
+@TableName("wx_user")
+public class WxUser {
+    private Long id; // 用户ID
+    private String userName; // 用户名
+    private String password; // 密码
+    private String avatarUrl; // 头像URL
+    private Integer type; // 用户类型
+    private String nickName; // 昵称
+    private String trueName; // 真实姓名
+    private String phone; // 手机号
+    private String email; // 邮箱
+    private Date birthday; // 生日
+    private Integer sex; // 性别(0: 未知, 1: 男, 2: 女)
+    private String sign; // 个性签名
+    private Date createTime; // 创建时间
+    private Date lastLoginTime; // 最后登录时间
+    private Integer idCardStatus; // 身份证认证状态(0: 未认证, 1: 已认证)
+    private Integer driverLicenseStatus; // 驾驶证认证状态(0: 未认证, 1: 已认证)
+
+}

+ 17 - 0
src/main/java/com/pay/wxpayback/pojo/dto/LoginParam.java

@@ -0,0 +1,17 @@
+package com.pay.wxpayback.pojo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class LoginParam {
+    String iv;
+    String encryptedData;
+    String session_key;
+    String code;
+}

+ 16 - 0
src/main/java/com/pay/wxpayback/pojo/dto/UserParam.java

@@ -0,0 +1,16 @@
+package com.pay.wxpayback.pojo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class UserParam {
+    String id;
+    String nickname;
+    String openId;
+}

+ 56 - 0
src/main/java/com/pay/wxpayback/pojo/vo/ReCreateOrderVO.java

@@ -0,0 +1,56 @@
+package com.pay.wxpayback.pojo.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+/**
+ * 微信创建订单
+ * @author 小乌龟
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class ReCreateOrderVO {
+    //微信小程序需要参数
+//    "appId": "wx499********7c70e",  // 微信开放平台 - 应用 - AppId,注意和微信小程序、公众号 AppId 可能不一致
+//    "timeStamp": 1597935292,        // 时间戳(单位:秒)
+//    "nonceStr": "c5sEwbaNPiXAF3iv", // 随机字符串
+//    "package": "wx202254********************fbe90000", // 小程序下单接口返回的prepay_id参数值,提交格式如:prepay_id=***;示例值:prepay_id=wx201410272009395522657a690389285100
+//    "signType": "RSA"    签名类型,默认为RSA,仅支持RSA。
+//    "paySign": "A842B45937F6EFF60DEC7A2EAA52D5A0" // 签名,这里用的 MD5/RSA 签名
+
+
+    /**
+     * 时间戳
+     */
+    private String timeStamp;
+
+    /**
+     * 随机字符串
+     */
+    private String nonceStr;
+
+    /**
+     * 订单详情扩展字符串 package
+     */
+    private String wxPackage;
+
+    /**
+     * 签名方式
+     */
+    private String signType;
+
+    /**
+     * 签名
+     */
+    private String paySign;
+
+    /**
+     * 订单号
+     */
+    private String outTradeNo;
+
+}

+ 40 - 0
src/main/java/com/pay/wxpayback/pojo/vo/ToCreateOrderVO.java

@@ -0,0 +1,40 @@
+package com.pay.wxpayback.pojo.vo;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @Description 前端=>微信创建订单
+ * @Author 小乌龟
+ * @Date 2022/4/13 19:49
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ToCreateOrderVO {
+
+    /**
+     * 订单号
+     */
+    String outTradeNo;
+
+    /**
+     * 金额
+     */
+    @NotNull
+    Integer total;
+
+    /**
+     * 订单描述
+     */
+    String description;
+
+    /**
+     * 用户openId
+     */
+    String openId;
+}

+ 16 - 0
src/main/java/com/pay/wxpayback/pojo/vo/UserInfo.java

@@ -0,0 +1,16 @@
+package com.pay.wxpayback.pojo.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class UserInfo {
+    String id;
+    String nickName;
+    String avatarUrl;
+}

+ 16 - 0
src/main/java/com/pay/wxpayback/pojo/vo/WxLoginVO.java

@@ -0,0 +1,16 @@
+package com.pay.wxpayback.pojo.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class WxLoginVO {
+    String code;
+    String openId;
+    String session_key;
+}

+ 119 - 0
src/main/java/com/pay/wxpayback/service/OrderService.java

@@ -0,0 +1,119 @@
+package com.pay.wxpayback.service;
+
+import com.pay.wxpayback.pojo.Order;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.pay.wxpayback.pojo.ToolWxConfig;
+import com.pay.wxpayback.pojo.vo.ReCreateOrderVO;
+import com.pay.wxpayback.pojo.vo.ToCreateOrderVO;
+import com.pay.wxpayback.pojo.vo.WxLoginVO;
+
+/**
+ * <p>
+ * 订单表 服务类
+ * </p>
+ *
+ * @author 小王八
+ * @since 2023-07-28
+ */
+public interface OrderService extends IService<Order> {
+    /**
+     * 根据code获取openId
+     * @param wxConfig
+     * @param loginVO
+     * @return
+     */
+    WxLoginVO getOpenId(ToolWxConfig wxConfig, WxLoginVO loginVO);
+
+    /**
+     * 微信下单
+     * @param wxConfig 微信参数
+     * @param toCreatOrderVO 订单数据
+     * @return
+     */
+    ReCreateOrderVO createOrder(ToolWxConfig wxConfig, ToCreateOrderVO toCreatOrderVO);
+
+    /**
+     *微信支付回调验证判定 核对成功 数据异步入库
+     * @param
+     * @param decryptOrder
+     * @return Boolean
+     * @author zhangjunrong
+     * @date 2022/5/3 8:23
+     */
+    Boolean verifyCreateOrder(String decryptOrder);
+
+    /**
+     * 关闭订单
+     * 使用场景:
+     * 1、商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;
+     * 2、系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
+     * 注意:关单没有时间限制,建议在订单生成后间隔几分钟(最短5分钟)再调用关单接口,避免出现订单状态同步不及时导致关单失败
+     *
+     * @param wxConfig
+     * @param outTradeNo
+     * @return String
+     * @author zhangjunrong
+     * @date 2022/4/14 17:02
+     */
+    void closeOrder(ToolWxConfig wxConfig, String outTradeNo);
+
+
+    /**
+     * 微信退款
+     * 注意:1、交易时间超过一年的订单无法提交退款
+     * 2、微信支付退款支持单笔交易分多次退款(不超50次),多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。申请退款总金额不能超过订单金额。 一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号
+     * 3、错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过6次
+     * 4、每个支付订单的部分退款次数不能超过50次
+     * 5、如果同一个用户有多笔退款,建议分不同批次进行退款,避免并发退款导致退款失败
+     * 6、申请退款接口的返回仅代表业务的受理情况,具体退款是否成功,需要通过退款查询接口获取结果
+     * 7、一个月之前的订单申请退款频率限制为:5000/min
+     * 8、同一笔订单多次退款的请求需相隔1分钟
+     * @param wxConfig 微信商家配置
+     * @param order 订单信息
+     * @return String
+     * @author zhangjunrong
+     * @date 2022/4/21 15:11
+     */
+    String refundOrder(ToolWxConfig wxConfig, Order order);
+
+    /**
+     *微信退款回调 修改订单状态
+     * @param decryptOrder
+     * @return Boolean
+     * @author zhangjunrong
+     * @date 2022/5/20 8:30
+     */
+    Boolean updateRefundOrder(String decryptOrder);
+
+    /**
+     * 查询订单
+     * 使用场景:
+     * 1.当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知。
+     * 2.调用支付接口后,返回系统错误或未知交易状态情况。
+     * 3.调用付款码支付API,返回USERPAYING(用户付费)的状态。
+     * 4.调用关单或撤销接口API之前,需确认支付状态。
+     *
+     * @param wxConfig   微信配置
+     * @param outTradeNo 商户订单号 系统生成
+     * @return String 订单交易状态
+     * @author zhangjunrong
+     * @date 2022/4/14 16:14
+     *
+     */
+    String queryCreateOrder(ToolWxConfig wxConfig, String outTradeNo);
+
+
+    /**
+     *微信退款查询
+     *注意:提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,建议在提交退款申请后1分钟发起查询退款状态,一般来说零钱支付的退款5分钟内到账,银行卡支付的退款1-3个工作日到账。
+     * @param wxConfig
+     * @param refundNo 退款订单号 系统生成
+     * @return String
+     * @author zhangjunrong
+     * @date 2022/4/21 15:15
+     */
+    String queryRefundOrder(ToolWxConfig wxConfig, String refundNo);
+
+
+
+}

+ 24 - 0
src/main/java/com/pay/wxpayback/service/ToolWxConfigService.java

@@ -0,0 +1,24 @@
+package com.pay.wxpayback.service;
+
+import com.pay.wxpayback.pojo.ToolWxConfig;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 微信支付参数表 服务类
+ * </p>
+ *
+ * @author 小乌龟
+ * @since 2022-11-09
+ */
+public interface ToolWxConfigService extends IService<ToolWxConfig> {
+
+    /**
+      *查询微信支付参数
+      * @param
+      * @return ToolWxConfig
+      * @author zhangjunrong
+      * @date 2022/11/10 10:33
+      */
+    ToolWxConfig findConf();
+}

+ 33 - 0
src/main/java/com/pay/wxpayback/service/UserService.java

@@ -0,0 +1,33 @@
+package com.pay.wxpayback.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.pay.wxpayback.pojo.Order;
+import com.pay.wxpayback.pojo.ToolWxConfig;
+import com.pay.wxpayback.pojo.dto.LoginParam;
+import com.pay.wxpayback.pojo.dto.UserParam;
+import com.pay.wxpayback.pojo.vo.ReCreateOrderVO;
+import com.pay.wxpayback.pojo.vo.ToCreateOrderVO;
+import com.pay.wxpayback.pojo.vo.UserInfo;
+import com.pay.wxpayback.pojo.vo.WxLoginVO;
+
+/**
+ * <p>
+ * 订单表 服务类
+ * </p>
+ *
+ * @author 小王八
+ * @since 2023-07-28
+ */
+public interface UserService extends IService<Order> {
+    /**
+     * 根据code获取openId
+     * @param wxConfig
+     * @param loginVO
+     * @return
+     */
+    WxLoginVO getOpenId(ToolWxConfig wxConfig, WxLoginVO loginVO);
+
+    public UserInfo getMyInfo(UserParam userParam);
+
+    public UserInfo wxMpLogin(LoginParam loginParam);
+}

+ 371 - 0
src/main/java/com/pay/wxpayback/service/impl/OrderServiceImpl.java

@@ -0,0 +1,371 @@
+package com.pay.wxpayback.service.impl;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.text.StrFormatter;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSON;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.pay.wxpayback.Enum.WxApiType;
+import com.pay.wxpayback.Enum.WxPayStatusEnum;
+import com.pay.wxpayback.constant.SystemConstant;
+import com.pay.wxpayback.constant.wxpay.WXOrderConstant;
+import com.pay.wxpayback.constant.wxpay.WechatPayHttpHeaders;
+import com.pay.wxpayback.exception.ApiException;
+import com.pay.wxpayback.pojo.Order;
+import com.pay.wxpayback.mapper.OrderMapper;
+import com.pay.wxpayback.pojo.ToolWxConfig;
+import com.pay.wxpayback.pojo.vo.ReCreateOrderVO;
+import com.pay.wxpayback.pojo.vo.ToCreateOrderVO;
+import com.pay.wxpayback.pojo.vo.WxLoginVO;
+import com.pay.wxpayback.service.OrderService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.pay.wxpayback.utils.WxPayUtil;
+import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.util.EntityUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.security.PrivateKey;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * <p>
+ * 订单表 服务实现类
+ * </p>
+ *
+ * @author 小王八
+ * @since 2023-07-28
+ */
+@Service
+@Slf4j
+public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
+
+
+    private final ReentrantLock reentrantLock1 = new ReentrantLock();
+
+    private final ReentrantLock reentrantLock2 = new ReentrantLock();
+
+    /**
+     * 调用微信支付 get请求 统一配置
+     *要微信签名认证
+     * @param url
+     * @return String
+     * @author zhangjunrong
+     * @date 2022/5/9 20:39
+     */
+    private String getHttpGet(ToolWxConfig wxConfig, String url) throws URISyntaxException, IOException {
+        //1.构造httpGet请求
+        URIBuilder uriBuilder = null;
+        uriBuilder = new URIBuilder(url);
+        HttpGet httpGet = new HttpGet(uriBuilder.build());
+        httpGet.addHeader(WechatPayHttpHeaders.ACCEPT, WechatPayHttpHeaders.APPLICATION_JSON);
+        //2.调起微信查询订单接口
+        CloseableHttpResponse response = WxPayUtil.getHttpClient(wxConfig, WxPayUtil.getVerifier(wxConfig)).execute(httpGet);
+        //3.返回结果信息
+        return EntityUtils.toString(response.getEntity());
+    }
+    public  WxLoginVO getOpenId(ToolWxConfig wxConfig, WxLoginVO loginVO){
+        //获取当前的openid
+        Map hashMap = new HashMap();
+        hashMap.put("appid", wxConfig.getAppId());
+        hashMap.put("secret", wxConfig.getAppSecret());
+        hashMap.put("js_code", loginVO.getCode());
+        hashMap.put("grant_type", "authorization_code");
+        String json = HttpUtil.get(WxApiType.WX_LOGIN_URL.getValue(), hashMap);
+        JSONObject jsonObject = JSONUtil.parseObj(json);
+        String openid = jsonObject.getStr("openid");
+        String sessionKey = jsonObject.getStr("session_key");
+        WxLoginVO result = new WxLoginVO();
+        result.setOpenId(openid);
+        result.setSession_key(sessionKey);
+        return result;
+    }
+
+
+    @Override
+    public ReCreateOrderVO createOrder(ToolWxConfig wxConfig, ToCreateOrderVO toCreatOrderVO) {
+        try {
+            //1.请求配置参数
+            HttpPost httpPost = new HttpPost(WxApiType.CREATE_ORDER.getValue());
+            //格式配置
+            httpPost.addHeader(WechatPayHttpHeaders.ACCEPT, WechatPayHttpHeaders.APPLICATION_JSON);
+            httpPost.addHeader(WechatPayHttpHeaders.CONTENT_TYPE, WechatPayHttpHeaders.APPLICATION_JSON_UTF);
+            //2.读取privateKey私钥
+            PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(wxConfig.getPrivateKey().getBytes(StandardCharsets.UTF_8)));
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            ObjectMapper objectMapper = new ObjectMapper();
+            //3.配置下单参数
+            ObjectNode rootNode = objectMapper.createObjectNode();
+            rootNode.put(WXOrderConstant.MCHID, wxConfig.getMchId())
+                    .put(WXOrderConstant.APPID, wxConfig.getAppId())
+                    .put(WXOrderConstant.DESCRIPTION, toCreatOrderVO.getDescription())
+                    .put(WXOrderConstant.NOTIFY_URL, SystemConstant.PAY_NOTIFY_URL)
+                    .put(WXOrderConstant.OUT_TRADE_NO, toCreatOrderVO.getOutTradeNo());
+            rootNode.putObject(WXOrderConstant.AMOUNT)
+                    //total 微信需要int类型 为了不丢失精度 单位为分
+                    .put(WXOrderConstant.AMOUNT_TOTAL, toCreatOrderVO.getTotal());
+            // 用户在直连商户appid下的唯一标识。 下单前需获取到用户的Openid
+            rootNode.putObject(WXOrderConstant.PAYER)
+                    .put(WXOrderConstant.OPENID, toCreatOrderVO.getOpenId());
+
+            objectMapper.writeValue(bos, rootNode);
+            //4.调用微信下单接口
+            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
+            //接口返回值 申请获取prepay_id
+            CloseableHttpResponse response = WxPayUtil.getHttpClient(wxConfig, WxPayUtil.getVerifier(wxConfig)).execute(httpPost);
+            //预支付交易会话标识 prepay_id
+            String bodyAsString = EntityUtils.toString(response.getEntity());
+            //5.APP调起支付API 构造签名串
+            String timestamp = DateUtil.currentSeconds() + "";
+            String nonce = RandomUtil.randomString(SystemConstant.NUM_32);
+            StringBuilder builder = new StringBuilder();
+            //应用id
+            builder.append(wxConfig.getAppId()).append("\n");
+            //时间戳
+            builder.append(timestamp).append("\n");
+            //随机字符串
+            builder.append(nonce).append("\n");
+            //预支付交易会话标识 prepay_id  通过bodyAsString获取 prepay_id
+            JsonNode node = objectMapper.readTree(bodyAsString);
+            // prepay_id=wx201410272009395522657a690389285100  必须以此格式
+            String wxPackage = SystemConstant.WX_PACKAGE + node.get(WXOrderConstant.PREPAY_ID).textValue();
+            builder.append(wxPackage).append("\n");
+
+            log.info("微信签名请求体: {}", builder.toString());
+
+            //6.计算签名
+            String sign = WxPayUtil.sign(builder.toString().getBytes(StandardCharsets.UTF_8), merchantPrivateKey);
+
+            //7.返回参数 让前端调微信支付
+            return new ReCreateOrderVO(timestamp, nonce, wxPackage, "RSA", sign,toCreatOrderVO.getOutTradeNo());
+        } catch (Exception e) {
+            log.error(toCreatOrderVO.getOutTradeNo() + "订单下单失败");
+            log.error(e.toString());
+            //下单失败抛异常
+            throw new ApiException("下单失败 重新尝试付款");
+        }
+    }
+
+    Integer queryAmountByOrderNo(String orderNo) {
+        QueryWrapper<Order> wrapper = new QueryWrapper<>();
+        wrapper.select("amount").eq("pk_id",orderNo);
+        return getOne(wrapper).getAmount();
+    }
+
+    void updateStatus(Integer status,String pkId) {
+        UpdateWrapper<Order> wrapper = new UpdateWrapper<>();
+        wrapper.set("pay_status",status).eq("pk_id",pkId);
+        update(wrapper);
+    }
+
+    Integer getStatus(String pkId) {
+        QueryWrapper<Order> wrapper = new QueryWrapper<>();
+        wrapper.select("pay_status").eq("pk_id",pkId);
+        return getOne(wrapper).getPayStatus();
+    }
+
+    @Override
+    public Boolean verifyCreateOrder(String decryptOrder) {
+        //在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
+        //实现: 加入一把可重入锁
+        if (reentrantLock1.tryLock()) {
+            try {
+                log.info("===================================进入微信支付回调核对订单中========================================");
+                ObjectMapper objectMapper = new ObjectMapper();
+                //微信回调 解密后 信息
+                JsonNode node = objectMapper.readTree(decryptOrder);
+                //获取订单商户号
+                String orderNo = node.get(WXOrderConstant.OUT_TRADE_NO).textValue();
+
+                log.info(node.get(WXOrderConstant.OUT_TRADE_NO) + "订单回调信息记录:订单状态:" + orderNo);
+                //2.如果回调 支付类型为成功 核对金额 入数据库
+                //获取支付状态
+                String tradeState = node.get(WXOrderConstant.TRADE_STATE).textValue();
+                if (StrUtil.equals(WXOrderConstant.WX_BACK_OK, tradeState)) {
+                    //1.查询数据库 对比支付金额
+                    if(WxPayUtil.verifyMoney(node, queryAmountByOrderNo(orderNo))) {
+                        //2.对比成功 账单状态 已支付
+                        updateStatus(SystemConstant.NUM_ONE,orderNo);
+                    }
+                    //支付成功 就返回true
+                    return true;
+                }
+
+            } catch (Exception e) {
+                log.error("订单支付异常===>订单回调信息记录:订单状态:" + decryptOrder);
+            }finally {
+                //释放锁
+                reentrantLock1.unlock();
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void closeOrder(ToolWxConfig wxConfig, String outTradeNo) {
+        try {
+            //1.微信接口编辑
+            String url = StrFormatter.format(WxApiType.CLOSE_ORDER.getValue(), outTradeNo);
+            HttpPost httpPost = new HttpPost(url);
+            //格式配置
+            httpPost.addHeader(WechatPayHttpHeaders.ACCEPT, WechatPayHttpHeaders.APPLICATION_JSON);
+            httpPost.addHeader(WechatPayHttpHeaders.CONTENT_TYPE, WechatPayHttpHeaders.APPLICATION_JSON_UTF);
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            //2.添加商户id
+            ObjectMapper objectMapper = new ObjectMapper();
+            ObjectNode rootNode = objectMapper.createObjectNode();
+            rootNode.put(WXOrderConstant.MCHID, wxConfig.getMchId());
+            objectMapper.writeValue(bos, rootNode);
+            //3.调起微信关单接口
+            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
+            CloseableHttpResponse response = WxPayUtil.getHttpClient(wxConfig, WxPayUtil.getVerifier(wxConfig)).execute(httpPost);
+            log.info("=====关单结果======={}====",response);
+        } catch (Exception e) {
+            log.error("关单失败" + outTradeNo + e);
+        }
+    }
+
+    @Override
+    public String refundOrder(ToolWxConfig wxConfig,Order order) {
+        try {
+            //1.请求配置参数
+                HttpPost httpPost = new HttpPost(WxApiType.REFUND_ORDER.getValue());
+                //格式配置
+                httpPost.addHeader(WechatPayHttpHeaders.ACCEPT, WechatPayHttpHeaders.APPLICATION_JSON);
+                httpPost.addHeader(WechatPayHttpHeaders.CONTENT_TYPE, WechatPayHttpHeaders.APPLICATION_JSON_UTF);
+                ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                ObjectMapper objectMapper = new ObjectMapper();
+                ObjectNode rootNode = objectMapper.createObjectNode();
+                //2.配置参数 订单商户号 退款订单号 微信订单号(微信生成) 退款回调地址(与下单回调地址不一样) 金额信息 amount: 原订单金额 total 退款金额 refund (单位都是分) 退款币种 CNY 人民币
+                //商户订单号 下单时生成
+                rootNode.put(WXOrderConstant.OUT_TRADE_NO, order.getPkId().toString())
+                        //微信支付系统生成的订单号 下单时生成(系统生成)
+                        .put(WXOrderConstant.OUT_REFUND_NO, order.getPkId().toString())
+                        //退款回调地址
+                        .put(WXOrderConstant.NOTIFY_URL, SystemConstant.REFUND_NOTIFY_URL);
+                //金额信息 amount: 原订单金额 total 退款金额 refund (单位都是分)
+                rootNode.putObject(WXOrderConstant.AMOUNT)
+                        //现阶段 total==refund 不支持部分退款
+                        //原订单金额 total
+                        .put(WXOrderConstant.AMOUNT_TOTAL, order.getAmount())
+                        //退款金额 refund
+                        .put(WXOrderConstant.AMOUNT_REFUND, order.getAmount())
+                        //退款币种 CNY 人民币
+                        .put(WXOrderConstant.AMOUNT_CURRENCY, SystemConstant.CURRENCY_RMB);
+                objectMapper.writeValue(bos, rootNode);
+                //3.调用微信退款接口
+                httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
+                //接口返回值
+                CloseableHttpResponse response = WxPayUtil.getHttpClient(wxConfig, WxPayUtil.getVerifier(wxConfig)).execute(httpPost);
+                String bodyAsString = EntityUtils.toString(response.getEntity());
+                log.info("微信申请退款返回结果" + "response:" + bodyAsString);
+                JsonNode refundNode = objectMapper.readTree(bodyAsString);
+                // 修改订单退款状态 微信退款入数据库
+              String status = refundNode.get(WXOrderConstant.STATUS).textValue();
+              log.info("微信方=====退款状态====={}======",status);
+              Integer statusCode = WxPayStatusEnum.getCode(status);
+              updateStatus(statusCode,order.getPkId().toString());
+                return "退款申请成功 注意退款查收";
+        } catch (Exception e) {
+            log.info("微信退款" +order.getPkId() + "失败");
+            throw new ApiException("退款失败,请联系客服解决");
+        }
+    }
+
+
+    @Override
+    public Boolean updateRefundOrder(String decryptOrder) {
+        //在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
+        //实现: 加入一把可重入锁
+        if (reentrantLock2.tryLock()) {
+            try {
+                if (ObjectUtil.isNotEmpty(decryptOrder)) {
+                    ObjectMapper objectMapper = new ObjectMapper();
+                    //string=>json 方便获取数据
+                    JsonNode jsonNode = objectMapper.readTree(decryptOrder);
+                    log.info("微信退款回调参数===================={}====================", decryptOrder);
+                    //获取退款单编号(系统生成)
+                    String outRefundNo = jsonNode.get(WXOrderConstant.OUT_REFUND_NO).textValue();
+                    String refundStatus = jsonNode.get(WXOrderConstant.REFUND_STATUS).textValue();
+                    //数据库核对 如果退款状态已退款说明已处理 直接返回即可
+                    if (getStatus(outRefundNo) == SystemConstant.NUM_THREE) {
+                        return true;
+                    }
+                    Integer statusCode = WxPayStatusEnum.getCode(refundStatus);
+                    log.info("微信退款回调 退款订单编号(系统生成)============{}===========订单状态======{}", outRefundNo, refundStatus);
+                    //1.退款表状态修改 微信退款id(微信生成)  退款 调起退款则给用户退款 不根据本系统回调反馈 所以修改状态不成功 依旧返回true
+                      updateStatus(statusCode,outRefundNo);
+                    return true;
+                }
+            } catch (Exception e) {
+                log.warn("微信退款回调接口====修改订单状态失败" + e);
+            } finally {
+                //释放锁
+                reentrantLock2.unlock();
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public String queryCreateOrder(ToolWxConfig wxConfig, String outTradeNo) {
+        try {
+            //1.查单 微信接口 编辑 微信订单号 + 商户号
+            String url = StrFormatter.format(WxApiType.QUERY_CREATE_ORDER.getValue(), outTradeNo, wxConfig.getMchId());
+            //2.调用微信接口
+            String bodyAsString = getHttpGet(wxConfig, url);
+            log.info("支付查单信息" + bodyAsString);
+            //返回查单结果信息
+            if (ObjectUtil.isNotEmpty(bodyAsString)){
+                ObjectMapper objectMapper = new ObjectMapper();
+                JsonNode jsonNode = objectMapper.readTree(bodyAsString);
+                return jsonNode.get(WXOrderConstant.TRADE_STATE).textValue();
+            }
+        } catch (Exception e) {
+            log.error("支付查单失败" + outTradeNo);
+        }
+        return null;
+    }
+
+    @Override
+    public String queryRefundOrder(ToolWxConfig wxConfig, String refundNo) {
+        try {
+            //1.查单 微信接口 拼接url
+            String url = StrFormatter.format(WxApiType.QUERY_REFUND_ORDER.getValue(), refundNo);
+            //2.调用微信接口
+            String bodyAsString = getHttpGet(wxConfig, url);
+            log.info("退单查询信息============{}========" + bodyAsString);
+            //返回查单结果信息
+            if (ObjectUtil.isNotEmpty(bodyAsString)){
+                ObjectMapper objectMapper = new ObjectMapper();
+                JsonNode jsonNode = objectMapper.readTree(bodyAsString);
+                return jsonNode.get(WXOrderConstant.STATUS).textValue();
+            }
+        } catch (Exception e) {
+            log.error("退单查单失败" + refundNo);
+        }
+        return null;
+    }
+}

+ 29 - 0
src/main/java/com/pay/wxpayback/service/impl/ToolWxConfigServiceImpl.java

@@ -0,0 +1,29 @@
+package com.pay.wxpayback.service.impl;
+
+import com.pay.wxpayback.pojo.ToolWxConfig;
+import com.pay.wxpayback.mapper.ToolWxConfigMapper;
+import com.pay.wxpayback.service.ToolWxConfigService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 微信支付参数表 服务实现类
+ * </p>
+ *
+ * @author 小乌龟
+ * @since 2022-11-09
+ */
+@Service
+@CacheConfig(cacheNames = "wxconf")
+public class ToolWxConfigServiceImpl extends ServiceImpl<ToolWxConfigMapper, ToolWxConfig> implements ToolWxConfigService {
+
+    @Override
+    @Cacheable(key = "'config'")
+    public ToolWxConfig findConf() {
+        return getById(1L);
+    }
+}

+ 102 - 0
src/main/java/com/pay/wxpayback/service/impl/UserServiceImpl.java

@@ -0,0 +1,102 @@
+package com.pay.wxpayback.service.impl;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.text.StrFormatter;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.pay.wxpayback.Enum.WxApiType;
+import com.pay.wxpayback.Enum.WxPayStatusEnum;
+import com.pay.wxpayback.constant.SystemConstant;
+import com.pay.wxpayback.constant.wxpay.WXOrderConstant;
+import com.pay.wxpayback.constant.wxpay.WechatPayHttpHeaders;
+import com.pay.wxpayback.exception.ApiException;
+import com.pay.wxpayback.mapper.OrderMapper;
+import com.pay.wxpayback.pojo.Order;
+import com.pay.wxpayback.pojo.ToolWxConfig;
+import com.pay.wxpayback.pojo.dto.LoginParam;
+import com.pay.wxpayback.pojo.dto.UserParam;
+import com.pay.wxpayback.pojo.vo.ReCreateOrderVO;
+import com.pay.wxpayback.pojo.vo.ToCreateOrderVO;
+import com.pay.wxpayback.pojo.vo.UserInfo;
+import com.pay.wxpayback.pojo.vo.WxLoginVO;
+import com.pay.wxpayback.service.OrderService;
+import com.pay.wxpayback.service.UserService;
+import com.pay.wxpayback.utils.WxPayUtil;
+import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.catalina.User;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.util.EntityUtils;
+import org.springframework.stereotype.Service;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.security.PrivateKey;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * <p>
+ * 订单表 服务实现类
+ * </p>
+ *
+ * @author 小王八
+ * @since 2023-07-28
+ */
+@Service
+@Slf4j
+public class UserServiceImpl extends ServiceImpl<OrderMapper, Order> implements UserService {
+    public  WxLoginVO getOpenId(ToolWxConfig wxConfig, WxLoginVO loginVO){
+        //获取当前的openid
+        Map hashMap = new HashMap();
+        hashMap.put("appid", wxConfig.getAppId());
+        hashMap.put("secret", wxConfig.getAppSecret());
+        hashMap.put("js_code", loginVO.getCode());
+        hashMap.put("grant_type", "authorization_code");
+        String json = HttpUtil.get(WxApiType.WX_LOGIN_URL.getValue(), hashMap);
+        JSONObject jsonObject = JSONUtil.parseObj(json);
+        String openid = jsonObject.getStr("openid");
+        String sessionKey = jsonObject.getStr("session_key");
+        WxLoginVO result = new WxLoginVO();
+        result.setOpenId(openid);
+        result.setSession_key(sessionKey);
+        return result;
+    }
+
+    public UserInfo getMyInfo(UserParam userParam){
+        UserInfo userInfo = new UserInfo();
+        userInfo.setId("1");
+        userInfo.setNickName("小王八");
+        return userInfo;
+    }
+
+    /**
+     * 获取头像登录
+     * @param loginParam
+     * @return
+     */
+    @Override
+    public UserInfo wxMpLogin(LoginParam loginParam) {
+        String jsonStr = WxPayUtil.decryptS5(loginParam.getEncryptedData(), loginParam.getSession_key(), loginParam.getIv());
+        return JSONUtil.toBean(jsonStr, UserInfo.class, true);
+    }
+
+}

+ 197 - 0
src/main/java/com/pay/wxpayback/utils/IdWorker.java

@@ -0,0 +1,197 @@
+package com.pay.wxpayback.utils;
+
+
+import org.springframework.stereotype.Component;
+
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+
+/**
+ * <p>名称:IdWorker.java</p>
+ * <p>描述:分布式自增长ID</p>
+ * <pre>
+ *     Twitter的 Snowflake JAVA实现方案
+ * </pre>
+ * 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
+ * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
+ * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
+ * 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
+ * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
+ * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
+ * 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
+ * <p>
+ * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
+ *
+ * @author Polim
+ */
+@Component
+public class IdWorker {
+    // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
+    private final static long twepoch = 1288834974657L;
+    // 机器标识位数
+    private final static long workerIdBits = 5L;
+    // 数据中心标识位数
+    private final static long datacenterIdBits = 5L;
+    // 机器ID最大值
+    private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
+    // 数据中心ID最大值
+    private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
+    // 毫秒内自增位
+    private final static long sequenceBits = 12L;
+    // 机器ID偏左移12位
+    private final static long workerIdShift = sequenceBits;
+    // 数据中心ID左移17位
+    private final static long datacenterIdShift = sequenceBits + workerIdBits;
+    // 时间毫秒左移22位
+    private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
+
+    private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
+    /* 上次生产id时间戳 */
+    private static long lastTimestamp = -1L;
+    // 0,并发控制
+    private long sequence = 0L;
+
+    private final long workerId;
+    // 数据标识id部分
+    private final long datacenterId;
+
+    public IdWorker(){
+        this.datacenterId = getDatacenterId(maxDatacenterId);
+        this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
+    }
+    /**
+     * @param workerId
+     *            工作机器ID
+     * @param datacenterId
+     *            序列号
+     */
+    public IdWorker(long workerId, long datacenterId) {
+        if (workerId > maxWorkerId || workerId < 0) {
+            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
+        }
+        if (datacenterId > maxDatacenterId || datacenterId < 0) {
+            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
+        }
+        this.workerId = workerId;
+        this.datacenterId = datacenterId;
+    }
+    /**
+     * 获取下一个ID
+     *
+     * @return
+     */
+    public synchronized String nextId() {
+        long timestamp = timeGen();
+        if (timestamp < lastTimestamp) {
+            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
+        }
+
+        if (lastTimestamp == timestamp) {
+            // 当前毫秒内,则+1
+            sequence = (sequence + 1) & sequenceMask;
+            if (sequence == 0) {
+                // 当前毫秒内计数满了,则等待下一秒
+                timestamp = tilNextMillis(lastTimestamp);
+            }
+        } else {
+            sequence = 0L;
+        }
+        lastTimestamp = timestamp;
+        // ID偏移组合生成最终的ID,并返回ID
+        long nextId = ((timestamp - twepoch) << timestampLeftShift)
+                | (datacenterId << datacenterIdShift)
+                | (workerId << workerIdShift) | sequence;
+
+        return Long.toString(nextId);
+    }
+
+    /**
+     * 获取下一个ID,返回Long
+     *
+     * @return
+     */
+    public synchronized Long nextLongId() {
+        long timestamp = timeGen();
+        if (timestamp < lastTimestamp) {
+            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
+        }
+
+        if (lastTimestamp == timestamp) {
+            // 当前毫秒内,则+1
+            sequence = (sequence + 1) & sequenceMask;
+            if (sequence == 0) {
+                // 当前毫秒内计数满了,则等待下一秒
+                timestamp = tilNextMillis(lastTimestamp);
+            }
+        } else {
+            sequence = 0L;
+        }
+        lastTimestamp = timestamp;
+        // ID偏移组合生成最终的ID,并返回ID
+        long nextId = ((timestamp - twepoch) << timestampLeftShift)
+                | (datacenterId << datacenterIdShift)
+                | (workerId << workerIdShift) | sequence;
+
+        return nextId;
+    }
+
+    private long tilNextMillis(final long lastTimestamp) {
+        long timestamp = this.timeGen();
+        while (timestamp <= lastTimestamp) {
+            timestamp = this.timeGen();
+        }
+        return timestamp;
+    }
+
+    private long timeGen() {
+        return System.currentTimeMillis();
+    }
+
+    /**
+     * <p>
+     * 获取 maxWorkerId
+     * </p>
+     */
+    protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
+        StringBuffer mpid = new StringBuffer();
+        mpid.append(datacenterId);
+        String name = ManagementFactory.getRuntimeMXBean().getName();
+        if (!name.isEmpty()) {
+         /*
+          * GET jvmPid
+          */
+            mpid.append(name.split("@")[0]);
+        }
+      /*
+       * MAC + PID 的 hashcode 获取16个低位
+       */
+        return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
+    }
+
+    /**
+     * <p>
+     * 数据标识id部分
+     * </p>
+     */
+    protected static long getDatacenterId(long maxDatacenterId) {
+        long id = 0L;
+        try {
+            InetAddress ip = InetAddress.getLocalHost();
+            NetworkInterface network = NetworkInterface.getByInetAddress(ip);
+            if (network == null) {
+                id = 1L;
+            } else {
+                byte[] mac = network.getHardwareAddress();
+                id = ((0x000000FF & (long) mac[mac.length - 1])
+                        | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
+                id = id % (maxDatacenterId + 1);
+            }
+        } catch (Exception e) {
+            System.out.println(" getDatacenterId: " + e.getMessage());
+        }
+        return id;
+    }
+
+
+}

+ 230 - 0
src/main/java/com/pay/wxpayback/utils/WxPayUtil.java

@@ -0,0 +1,230 @@
+package com.pay.wxpayback.utils;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.pay.wxpayback.constant.SystemConstant;
+import com.pay.wxpayback.constant.wxpay.WXOrderConstant;
+import com.pay.wxpayback.constant.wxpay.WechatPayHttpHeaders;
+import com.pay.wxpayback.exception.ApiException;
+import com.pay.wxpayback.pojo.ToolWxConfig;
+import com.pay.wxpayback.pojo.vo.UserInfo;
+import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
+import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
+import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
+import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
+import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
+import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
+import com.wechat.pay.contrib.apache.httpclient.exception.ParseException;
+import com.wechat.pay.contrib.apache.httpclient.exception.ValidationException;
+import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
+import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
+import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
+import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
+
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.util.Base64;
+
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+
+/**
+ * @Description
+ * @Author 小乌龟
+ * @Date 2022/4/10 20:14
+ */
+public class WxPayUtil {
+    private static final Logger log = LoggerFactory.getLogger(WxPayUtil.class);
+
+    /**
+      *签名生成 计算签名
+      * @param message  签名体
+      * @param privateKey 商户私钥
+      * @return String
+      * @author zhangjunrong
+      * @date 2022/4/10 20:15
+      */
+    public static String sign(byte[] message, PrivateKey privateKey) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
+        Signature sign = Signature.getInstance("SHA256withRSA");
+        sign.initSign(privateKey);
+        sign.update(message);
+        return Base64.getEncoder().encodeToString(sign.sign());
+    }
+
+   /**
+     *构造HttpClient 实现 微信申请接口 调用功能
+     * @param wxConfig 微信支付数据库参数
+     * @param verifier 微信验签器
+     * @return CloseableHttpClient
+     * @author zhangjunrong
+     * @date 2022/5/16 8:54
+     */
+    public static CloseableHttpClient getHttpClient(ToolWxConfig wxConfig, Verifier verifier) {
+        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(wxConfig.getPrivateKey().getBytes(StandardCharsets.UTF_8)));
+        //通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
+        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
+                .withMerchant(wxConfig.getMchId(), wxConfig.getMchSerialNo(), merchantPrivateKey)
+                .withValidator(new WechatPay2Validator(verifier));
+        return builder.build();
+    }
+    /**
+      *构造HttpClient 实现 微信申请接口 调用功能  不用微信签名认证 账单申请中可用到
+      * @param wxConfig 微信支付数据库参数
+      * @param verifier 微信验签器
+      * @return CloseableHttpClient
+      * @author zhangjunrong
+      * @date 2022/6/29 20:49
+      */
+    public static CloseableHttpClient getHttpClientNoSign(ToolWxConfig wxConfig, Verifier verifier) {
+        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(wxConfig.getPrivateKey().getBytes(StandardCharsets.UTF_8)));
+        //通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签
+        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
+                .withMerchant(wxConfig.getMchId(), wxConfig.getMchSerialNo(), merchantPrivateKey)
+                .withValidator(new WechatPay2Validator(verifier))
+                .withValidator(response -> true);
+        return builder.build();
+    }
+
+    /**
+      *获取验证功能
+      * @param wxConfig 微信支付数据库参数
+      * @return Verifier 微信验签器
+      * @author zhangjunrong
+      * @date 2022/5/16 8:53
+      */
+    public static Verifier getVerifier(ToolWxConfig wxConfig)  {
+        try {
+            PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(wxConfig.getPrivateKey().getBytes(StandardCharsets.UTF_8)));
+            //定时更新平台证书功能
+            // 获取证书管理器实例
+            CertificatesManager certificatesManager = CertificatesManager.getInstance();
+            // 向证书管理器增加需要自动更新平台证书的商户信息
+            certificatesManager.putMerchant(wxConfig.getMchId(), new WechatPay2Credentials(wxConfig.getMchId(),
+                    new PrivateKeySigner(wxConfig.getMchSerialNo(), merchantPrivateKey)), wxConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
+            // 从证书管理器中获取verifier=>验签器
+            return certificatesManager.getVerifier(wxConfig.getMchId());
+        } catch (Exception e) {
+            log.warn("验证出错");
+            throw new ApiException("微信证书出错 联系客服");
+        }
+    }
+
+    /**
+     *回调验证
+     * @param request 微信回调请求
+     * @param wxConfig 微信基本配置信息
+     * @return String
+     * @author zhangjunrong
+     * @date 2022/4/21 15:02
+     */
+    public static Notification verifyBack(HttpServletRequest request, ToolWxConfig wxConfig) throws IOException, ValidationException, ParseException {
+        //应答报文主体
+        BufferedReader br = request.getReader();
+        String str;
+        StringBuilder builder = new StringBuilder();
+        while ((str = br.readLine()) != null) {
+            builder.append(str);
+        }
+        // 构建request,传入必要参数
+        //参数 1.微信序列号 2.应答随机串 3.应答时间戳 4.应答签名 5.应答报文主体
+        NotificationRequest notificationRequest = new NotificationRequest.Builder()
+                .withSerialNumber(request.getHeader(WechatPayHttpHeaders.WECHATPAY_SERIAL))
+                .withNonce(request.getHeader(WechatPayHttpHeaders.WECHATPAY_NONCE))
+                .withTimestamp(request.getHeader(WechatPayHttpHeaders.WECHATPAY_TIMESTAMP))
+                .withSignature(request.getHeader(WechatPayHttpHeaders.WECHATPAY_SIGNATURE))
+                .withBody(builder.toString())
+                .build();
+        NotificationHandler handler = new NotificationHandler(WxPayUtil.getVerifier(wxConfig), wxConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
+        // 验签和解析请求体
+        log.info("验签和解析请求体==============================开始验证==============================");
+        Notification notification = handler.parse(notificationRequest);
+        return notification;
+    }
+    /**
+     *验证用户支付金额 场景 微信回调验证
+     * todo 待具体需求测试
+     * @param node 微信回调json 返回参数
+     * @param total 数据库记录金额
+     * @return Boolean
+     * @author zhangjunrong
+     * @date 2022/5/16 8:39
+     */
+    public static Boolean verifyMoney(JsonNode node,Integer total){
+        //总金额计数值 用户支付计算
+        int userPayTotal = SystemConstant.NUM_ZERO;
+        //1.验证订单金额
+        //用户支付金额
+        int payerTotal = node.get(WXOrderConstant.AMOUNT).get(WXOrderConstant.AMOUNT_PAYER_TOTAL).asInt();
+        userPayTotal = userPayTotal + payerTotal;
+        //CASH充值型代金券 要加上优惠金额 银行优惠 获取
+        //排空 如果没有优惠则跳过
+        if (!ObjectUtil.isEmpty(node.get(WXOrderConstant.PROMOTION_DETAIL))) {
+            for (JsonNode objNode : node.get(WXOrderConstant.PROMOTION_DETAIL)) {
+                //如果优惠类型为CASH 则要和 用户支付金额 累加
+                if (WXOrderConstant.WX_DISCOUNT_TYPE.equals(objNode.get(WXOrderConstant.PROMOTION_DETAIL_TYPE).textValue())) {
+                    userPayTotal = userPayTotal + objNode.get(WXOrderConstant.AMOUNT).asInt();
+                }
+            }
+        }
+        //2.总金额 预支付时的 金额 与 total 用户支付金额
+        //微信端返回的支付总金额
+        int wxTotal = node.get(WXOrderConstant.AMOUNT).get(WXOrderConstant.AMOUNT_TOTAL).asInt();
+        //校验通知的信息是否与商户侧的信息一致,防止数据泄露导致出现“假通知”,造成资金损失。
+        log.info("微信回调金额===比较=== "+"微信端返回的支付总金额"+node.get(WXOrderConstant.AMOUNT).get(WXOrderConstant.AMOUNT_TOTAL).asInt()+"================用户支付总金额计算"+userPayTotal);
+        return wxTotal == userPayTotal && total == wxTotal;
+    }
+
+    /**
+     System.out.println(decryptS5(encryptedData,
+     "utf-8",session_key, iv));,
+     * 解密工具直接放进去即可
+     */
+    public static String decryptS5(String sSrc, String sKey, String ivParameter) {
+        try {
+            String encodingFormat = "UTF-8";
+
+            // 使用 java.util.Base64 替代 BASE64Decoder
+            Base64.Decoder decoder = Base64.getDecoder();
+
+            // 解码密钥
+            byte[] raw = decoder.decode(sKey);
+            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
+
+            // 解码 IV
+            IvParameterSpec iv = new IvParameterSpec(decoder.decode(ivParameter));
+
+            // 初始化 Cipher
+            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
+
+            // 解码待解密的数据
+            byte[] myendicod = decoder.decode(sSrc);
+
+            // 解密
+            byte[] original = cipher.doFinal(myendicod);
+
+            // 返回解密后的字符串
+            return new String(original, encodingFormat);
+        } catch (Exception ex) {
+            ex.printStackTrace(); // 打印异常信息以便调试
+            return null;
+        }
+    }
+
+    public static void main(String[] args) {
+        String s = WxPayUtil.decryptS5("kfm+KkHxMqn416kISl/XgnZ5f5I/oZCkEpXOaIYrln16j0ehmSzefPnhOYatCZSgmyAv1tmUVQI6NRRBfZKkHii6geRBiHQBDQMFlh2A83SKYAwiy8UaD9Ya/HUwxqg9hyIeXD1GnFDR0dN9jnkVCg450Bs4p0PNQjYI2fChmJj5NxTmSADHKbvC07IFu56UbKw9NSMYfL7cS9Eq58nxW3lkzqTKn5B0hTRit06S81R2H54dmAioxuc+XwW+eQktRY+bu5Q47i7ZKrxbFCMxvlUiF9u4wsHOes6fjRuVHMYssDGG+N2GDdDuyrwuR8hSIG2Oz1IH8qjN26fIOBs0f8gYJrGOk/HwCQf9L+8Mee6rnI9G/2kF4dVTqCxZr5BnxGvk19mjL36sDd0FzfXKP7UHAJKow0NvvWznbcq7RFCv4hHz9gSNq1XmuiJOzb/g", "OU8KXYTQwsjrB7SJrh1nVQ==", "zENlDBsSJnTls5U37ILsxQ==");
+        System.out.println(s);
+        UserInfo bean = JSONUtil.toBean(s, UserInfo.class, true);
+        System.out.println(bean);
+    }
+}

+ 49 - 6
src/main/java/com/qmrb/system/controller/AuthController.java

@@ -11,26 +11,25 @@ import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.qmrb.system.framework.resubmit.Resubmit;
 import com.qmrb.system.framework.security.CaConstants;
 import com.qmrb.system.pojo.dto.SoapReturnDTO;
 import com.qmrb.system.pojo.dto.SoapTemplateDTO;
+import com.qmrb.system.pojo.form.UserForm;
+import jakarta.validation.Valid;
 import lombok.extern.slf4j.Slf4j;
 import org.checkerframework.common.value.qual.StringVal;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import com.qmrb.system.common.constant.SecurityConstants;
 import com.qmrb.system.common.result.Result;
@@ -326,4 +325,48 @@ public class AuthController {
         }
         return Result.failed("其他错误");
     }
+
+
+    /**
+     * openId当用户名
+     * @param openId
+     * @return
+     */
+    @Operation(summary = "自动登录")
+    @GetMapping("/getTokenByOpenId")
+    public Result getTokenByOpenId(@RequestParam String openId) {
+        //验证当前医生是否存在
+        UserAuthInfo authInfo=userService.getUserAuthInfo(openId);
+        if (authInfo == null){
+            return Result.success("openId不存在");
+        }
+        List<SimpleGrantedAuthority> roleList = authInfo.getRoles()
+                .stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).toList();
+        UsernamePasswordAuthenticationToken authenticationToken =
+                new UsernamePasswordAuthenticationToken(authInfo.getUsername(), authInfo.getUsername(),
+                        roleList);
+        SysUserDetails sysUserDetails = new SysUserDetails(authInfo);
+        authenticationToken.setDetails(sysUserDetails);
+        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+        String accessToken = jwtTokenManager.createToken(authenticationToken);
+        LoginResult loginResult = LoginResult.builder()
+                .tokenType("Bearer")
+                .accessToken(accessToken)
+                .build();
+        return Result.success(loginResult);
+    }
+
+    /**
+     * openId作为用户名
+     * @param userForm
+     * @return
+     */
+    @Operation(summary = "微信用户注册", security = {@SecurityRequirement(name = "Authorization")})
+    @PostMapping
+    public Result<?> regUser(
+            @RequestBody @Valid UserForm userForm
+    ) {
+        boolean result = userService.saveUser(userForm);
+        return Result.judge(result);
+    }
 }

+ 206 - 0
src/main/java/com/qmrb/system/service/impl/JsapiService.java

@@ -0,0 +1,206 @@
+//package com.qmrb.system.service.impl;
+//
+//import com.wechat.pay.java.core.Config;
+//import com.wechat.pay.java.core.RSAAutoCertificateConfig;
+//import com.wechat.pay.java.core.exception.HttpException;
+//import com.wechat.pay.java.core.exception.MalformedMessageException;
+//import com.wechat.pay.java.core.exception.ServiceException;
+//import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
+//
+//public class JsapiService {
+//
+//
+//    //V3api密钥
+//
+//    /**
+//     * appid
+//     */
+//    public static String appid = "";
+//
+//    /**
+//     * 商户号
+//     */
+//    public static String merchantId = "";
+//
+//    /**
+//     * 商户API私钥路径
+//     */
+//    public static String privateKeyPath = "D:\\apiclient_key.pem";
+//
+//    /**
+//     * 商户证书序列号
+//     */
+//    public static String merchantSerialNumber = "";
+//
+//    /**
+//     * 商户APIV3密钥
+//     */
+//    public static String apiV3Key = "";
+//
+//    /**
+//     * 小程序APPSECRET
+//     */
+//    public static  String appSecret ="";
+//
+//    /**
+//     * service
+//     */
+//    public static   com.wechat.pay.java.service.payments.jsapi.JsapiService  service;
+//    /**
+//     * 服务扩展
+//     */
+//    public static  com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension serviceExtension;
+//
+//    /**
+//     * 参数初始话
+//     */
+//    public static void init() {
+//
+//        Config config =
+//                new RSAAutoCertificateConfig.Builder()
+//                        .merchantId(merchantId)
+//                        .privateKeyFromPath(privateKeyPath)
+//                        .merchantSerialNumber(merchantSerialNumber)
+//                        .apiV3Key(apiV3Key)
+//                        .build();
+//
+//        // request.setXxx(val)设置所需参数,具体参数可见Request定义
+//
+//        // ... 调用接口
+//        try {
+//            service = new JsapiService.Builder().config(config).build();
+//            serviceExtension = new JsapiServiceExtension.Builder().config(config).build();
+//
+////            closeOrder();
+//        } catch (HttpException e) { // 发送HTTP请求失败
+//            // 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
+//        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
+//            // 调用e.getResponseBody()获取返回体打印日志或上报监控,更多方法见ServiceException定义
+//        } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
+//            // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
+//        }
+//    }
+//
+//    /**
+//     * 关闭订单
+//     */
+//    public static void closeOrder() {
+//
+//        CloseOrderRequest request = new CloseOrderRequest();
+//        // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
+//        // 调用接口
+//
+//        service.closeOrder(request);
+//    }
+//
+//    /**
+//     * JSAPI支付下单
+//     */
+//    public static PrepayResponse prepay() {
+//        PrepayRequest request = new PrepayRequest();
+//        // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
+//        // 调用接口
+//        Amount amount = new Amount();
+//        Payer  payer =new Payer();
+//
+//        request.setAppid(appid);
+//        request.setMchid(merchantId);
+//        request.setDescription("测试商品标题");
+//        request.setOutTradeNo("out_trade_no_001");
+//        request.setNotifyUrl("https://notify_url");
+//
+//        amount.setTotal(1*100); //订单金额,单位为 “分”
+//        request.setAmount(amount);
+//
+//        payer.setOpenid("o3ZOa617dWCaW17K_HKRPieIJNPo"); // openid
+//        request.setPayer(payer);
+//
+//        PrepayResponse response = service.prepay(request);
+//        System.out.println(response);
+//        return  response;
+//    }
+//
+//    /**
+//     * JSAPI支付下单 ****官方推荐用法*****
+//     */
+//    public static PrepayWithRequestPaymentResponse prepayExt()
+//    {
+//        PrepayRequest request = new PrepayRequest();
+//        Amount amount = new Amount();
+//        Payer  payer =new Payer();
+//
+//        request.setAppid(appid);
+//        request.setMchid(merchantId);
+//        request.setDescription("测试商品标题");
+//        request.setOutTradeNo("out_trade_no_001");
+//        request.setNotifyUrl("https://notify_url");
+//
+//        amount.setTotal(1*100); //订单金额,单位为 “分”
+//        request.setAmount(amount);
+//
+//        payer.setOpenid("o3ZOa617dWCaW17K_HKRPieIJNPo"); // openid
+//        request.setPayer(payer);
+//        PrepayWithRequestPaymentResponse response = serviceExtension.prepayWithRequestPayment(request);
+//        System.out.println("*********prepayExt()"+response);
+//        return  response;
+//    }
+//
+//
+//
+//
+//
+//    /**
+//     * 微信支付订单号查询订单
+//     */
+//    public static Transaction queryOrderById() {
+//
+//        QueryOrderByIdRequest request = new QueryOrderByIdRequest();
+//        // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
+//        // 调用接口
+//        return service.queryOrderById(request);
+//    }
+//
+//    /**
+//     * 商户订单号查询订单
+//     */
+//    public static Transaction queryOrderByOutTradeNo() {
+//
+//        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
+//        // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
+//        // 调用接口
+//        return service.queryOrderByOutTradeNo(request);
+//    }
+//    public static boolean verifier(CertificateProvider provider)
+//    {
+//        RSAVerifier verifier =new RSAVerifier(provider);
+//        return  true;
+//
+//    }
+//
+//    /**
+//     * 获取openid
+//     * @param code
+//     * @return
+//     */
+//    public static  String getOpenid(String code)
+//    {
+//        String openid =null;
+//        if (code == null || code.equals("")) {
+//            return ("请求参数有误!");
+//        }
+//        String grant_type = "authorization_code";
+//        String appId= appid;
+//        String secret= appSecret ;
+//        //拼接参数
+//        String param = "grant_type=" + grant_type + "&appid=" + appId + "&secret=" + secret + "&js_code=" + code;
+//        //创建请求对象
+//        //调用获取access_token接口
+//
+//        String res = HttpUtil.get("https://api.weixin.qq.com/sns/jscode2session",param);
+//        JSONObject jsonObj = JSONObject.fromObject(res);
+//        if(jsonObj!=null)
+//        {
+//            openid =jsonObj.get("openid").toString();
+//        }
+//        return  openid;
+//}

+ 64 - 0
src/main/java/com/qmrb/system/service/impl/WeChatPayService.java

@@ -0,0 +1,64 @@
+/*
+package com.qmrb.system.service.impl;
+
+import com.github.wxpay.sdk.WXPay;
+import com.github.wxpay.sdk.WXPayConfig;
+import com.github.wxpay.sdk.WXPayConstants;
+import com.github.wxpay.sdk.WXPayUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class WeChatPayService {
+
+    private WXPay wxpay;
+    private WXPayConfig config;
+
+    public WeChatPayService(WXPayConfig config) throws Exception {
+        this.config = config;
+        this.wxpay = new WXPay(config, WXPayConstants.SignType.MD5, true);
+    }
+
+    */
+/**
+     * 统一下单,生成预支付订单
+     *//*
+
+    public Map<String, String> createOrder(String outTradeNo, int totalFee, String openid) throws Exception {
+        Map<String, String> data = new HashMap<>();
+        data.put("body", "测试商品");
+        data.put("out_trade_no", outTradeNo);
+        data.put("total_fee", String.valueOf(totalFee));
+        data.put("spbill_create_ip", "用户IP");
+        data.put("notify_url", config.getNotifyUrl());
+        data.put("trade_type", "JSAPI");
+        data.put("openid", openid);
+
+        Map<String, String> response = wxpay.unifiedOrder(data);
+        if ("SUCCESS".equals(response.get("return_code")) {
+            return response;
+        } else {
+            throw new Exception("微信支付统一下单失败:" + response.get("return_msg"));
+        }
+    }
+
+    */
+/**
+     * 生成小程序支付参数
+     *//*
+
+    public Map<String, String> getPaymentParams(String prepayId) throws Exception {
+        Map<String, String> params = new HashMap<>();
+        params.put("appId", config.getAppID());
+        params.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
+        params.put("nonceStr", WXPayUtil.generateNonceStr());
+        params.put("package", "prepay_id=" + prepayId);
+        params.put("signType", "MD5");
+
+        // 生成签名
+        String sign = WXPayUtil.generateSignature(params, config.getKey());
+        params.put("paySign", sign);
+
+        return params;
+    }
+}*/

+ 26 - 19
src/main/resources/application-dev.yml

@@ -1,5 +1,5 @@
 server:
-  port: 9999
+  port: 2203
 
 spring:
   main:
@@ -19,21 +19,9 @@ spring:
         master:
           type: com.alibaba.druid.pool.DruidDataSource
           driver-class-name: com.mysql.cj.jdbc.Driver
-          url: jdbc:mysql://127.0.0.1:3306/ca_sign?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=true&useSSL=false
+          url: jdbc:mysql://127.0.0.1:3306/park_car?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=true&useSSL=false
           username: root
           password: 3409git
-        hissource:
-          type: com.alibaba.druid.pool.DruidDataSource
-          driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
-          url: jdbc:sqlserver://192.1.33.96:1433;DatabaseName=zsyydb_bak;characterEncoding=UTF-8;userSSL=true;encrypt=true;trustServerCertificate=true
-          username: ceshi
-          password: ceshi@1234
-        emrsource:
-          type: com.alibaba.druid.pool.DruidDataSource
-          driver-class-name: oracle.jdbc.OracleDriver
-          url: jdbc:oracle:thin:@192.1.33.125:1521/jhemr
-          username: emr
-          password: Jhemr_2750
   data:
     redis:
       database: 2
@@ -72,7 +60,6 @@ logging:
   level:
     com.qmrb.system.mapper.mapper: debug
 
-
 # 认证配置
 auth:
   token:
@@ -174,7 +161,27 @@ ca-sign:
   rtms-server: http://192.0.33.104:8080
   ocr-server: http://192.6.33.2:1224
 
-pda:
-  url: http://10.95.22.235:8080/api/pda/web
-  app-id: sTqAN8QPSaqhnYfAnJuHoiC1H8yinnCB
-  app-secret: LGkI6tiLgKCOh8U8KN5wS5R2NdUVxByH
+wxpay:
+  #应用编号
+  appId: xxxxxxxxxxxxx
+
+  #商户号
+  mchId: xxxxxxxxxxxxx
+
+  # APIv3密钥
+  apiV3Key: xxxxxxxxxxxxx
+
+  # 支付通知回调, 本地测试内网穿透地址
+  notifyUrl: http://405c3382p5.goho.co:25325/wenbo-pay/notify/payNotify
+
+  # 退款通知回调,  本地测试内网穿透地址
+  refundNotifyUrl: http://405c3382p5.goho.co:25325/wenbo-pay/notify/refundNotify
+
+  # 密钥路径,resources根目录下
+  keyPemPath: apiclient_key.pem
+
+  # 商户证书序列号
+  serialNo: xxxxxxxxxxxxx
+
+  # 小程序密钥
+  appSecret: xxxxxxxxxxxxx

+ 1 - 1
src/main/resources/application.yml

@@ -1,6 +1,6 @@
 spring:
   application:
-    name: ca-sign-server
+    name: parking-server
   profiles:
     active: dev
   servlet: 

+ 5 - 0
src/main/resources/mapper/OrderMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.pay.wxpayback.mapper.OrderMapper">
+
+</mapper>

+ 5 - 0
src/main/resources/mapper/ToolWxConfigMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.pay.wxpayback.mapper.ToolWxConfigMapper">
+
+</mapper>