From 32866c0896969b3ac6f3eaddf0420507708c9c52 Mon Sep 17 00:00:00 2001
From: 44323 <443237572@qq.com>
Date: 星期五, 17 五月 2024 16:28:57 +0800
Subject: [PATCH] 代码提交

---
 ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/domain/TVipSet.java                         |    6 
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/UUIDUtil.java                                   |  101 
 ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml                                                     |   35 
 ruoyi-modules/ruoyi-gen/src/main/resources/bootstrap.yml                                                      |   36 
 ruoyi-service/ruoyi-management/src/main/resources/bootstrap.yml                                               |   59 
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/StrKit.java                                     | 1370 +++++++++++++
 ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/domain/TVipOrder.java                             |   18 
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TParentLoginController.java                |   20 
 ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/controller/TUserController.java             |   29 
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/HttpResult.java                                 |   31 
 ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/ITVipSetService.java                |    2 
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/HttpClientUtil.java                             |  272 ++
 ruoyi-service/ruoyi-study/src/main/resources/bootstrap.yml                                                    |   58 
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/ToolUtil.java                                   |  575 +++++
 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/AjaxResult.java                 |   16 
 ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/vo/VipSetVO.java                            |    5 
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/domain/TVipOrder.java                                 |   18 
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/DateUtil.java                                   |  329 +++
 ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/feignClient/ManagementClient.java       |    3 
 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/HttpStatus.java                   |    1 
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/MD5AndKL.java                                   |  116 +
 ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/factory/StudyFallbackFactory.java                 |    5 
 ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/domain/TVipOrder.java                       |   19 
 ruoyi-gateway/src/main/resources/bootstrap.yml                                                                |   88 
 ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/model/TVipSet.java                      |   88 
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/PayMoneyUtil.java                               | 1278 ++++++++++++
 ruoyi-auth/src/main/resources/bootstrap.yml                                                                   |   59 
 ruoyi-service/ruoyi-goods/src/main/resources/bootstrap.yml                                                    |   59 
 ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/mapper/TVipSetMapper.java                   |    2 
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/CollectionKit.java                              |  782 +++++++
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/vo/VipInfoVO.java                                     |   22 
 ruoyi-modules/ruoyi-system/src/main/resources/bootstrap.yml                                                   |   58 
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TUserController.java                       |  361 +++
 ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/ToolBoxException.java                           |   43 
 ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/factory/TManagementFallbackFactory.java |    6 
 ruoyi-service/ruoyi-parent/src/main/resources/bootstrap.yml                                                   |   59 
 ruoyi-service/ruoyi-study/pom.xml                                                                             |   21 
 ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/feignClient/StudyClient.java                      |   12 
 ruoyi-modules/ruoyi-job/src/main/resources/bootstrap.yml                                                      |   25 
 39 files changed, 6,028 insertions(+), 59 deletions(-)

diff --git a/ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/factory/TManagementFallbackFactory.java b/ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/factory/TManagementFallbackFactory.java
index 8ac3df0..9c592e4 100644
--- a/ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/factory/TManagementFallbackFactory.java
+++ b/ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/factory/TManagementFallbackFactory.java
@@ -4,6 +4,7 @@
 import com.ruoyi.common.core.web.domain.AjaxResult;
 import com.ruoyi.common.core.web.page.PageInfo;
 import com.ruoyi.management.api.feignClient.ManagementClient;
+import com.ruoyi.management.api.model.TVipSet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.cloud.openfeign.FallbackFactory;
@@ -29,6 +30,11 @@
             public R getPage1() {
                 return R.fail("获取注意事项失败"+cause.getMessage());
             }
+
+            @Override
+            public R<List<TVipSet>> getVipSet1() {
+                return R.fail("获取会员规格配置和说明失败"+cause.getMessage());
+            }
         };
     }
 }
diff --git a/ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/feignClient/ManagementClient.java b/ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/feignClient/ManagementClient.java
index 09dbab5..9a5400d 100644
--- a/ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/feignClient/ManagementClient.java
+++ b/ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/feignClient/ManagementClient.java
@@ -5,6 +5,7 @@
 import com.ruoyi.common.core.web.domain.AjaxResult;
 import com.ruoyi.management.api.factory.TManagementFallbackFactory;
 import com.ruoyi.management.api.model.TPage;
+import com.ruoyi.management.api.model.TVipSet;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -17,5 +18,7 @@
 
     @PostMapping(value = "/tSysSet/getPage1")
     R<List<TPage>> getPage1();
+    @PostMapping("/tUser/getVipSet1")
+    R<List<TVipSet>> getVipSet1();
 
 }
diff --git a/ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/model/TVipSet.java b/ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/model/TVipSet.java
new file mode 100644
index 0000000..8412274
--- /dev/null
+++ b/ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/model/TVipSet.java
@@ -0,0 +1,88 @@
+package com.ruoyi.management.api.model;
+
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ruoyi.common.core.web.domain.BaseModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.math.BigDecimal;
+
+/**
+ * <p>
+ * 会员价格设置
+ * </p>
+ *
+ * @author 无关风月
+ * @since 2024-04-26
+ */
+@TableName("t_vip_set")
+public class TVipSet extends BaseModel {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键id
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+    /**
+     * 价格
+     */
+    @ApiModelProperty(value = "价格")
+    private BigDecimal amount;
+    /**
+     * 有效期 单位月
+     */
+    @ApiModelProperty(value = "有效期 单位月")
+    private Integer time;
+    /**
+     * 会员说明
+     */
+    @ApiModelProperty(value = "会员说明")
+    private String info;
+
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public BigDecimal getAmount() {
+        return amount;
+    }
+
+    public void setAmount(BigDecimal amount) {
+        this.amount = amount;
+    }
+
+    public Integer getTime() {
+        return time;
+    }
+
+    public void setTime(Integer time) {
+        this.time = time;
+    }
+
+    public String getInfo() {
+        return info;
+    }
+
+    public void setInfo(String info) {
+        this.info = info;
+    }
+
+    @Override
+    public String toString() {
+        return "TVipSet{" +
+        ", id=" + id +
+        ", amount=" + amount +
+        ", time=" + time +
+        ", info=" + info +
+        "}";
+    }
+}
diff --git a/ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/domain/TVipOrder.java b/ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/domain/TVipOrder.java
index 26953e9..c5eb4ec 100644
--- a/ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/domain/TVipOrder.java
+++ b/ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/domain/TVipOrder.java
@@ -59,7 +59,23 @@
      */
     @ApiModelProperty(value = "有效期至")
     private Date time;
+    /**
+     * 支付方式 1微信2支付宝
+     */
+    @ApiModelProperty(value = "支付方式 1微信2支付宝")
+    private Integer payType;
 
-
+    /**
+     * 内部订单号 退款使用
+     */
+    private String outTradeNo;
+    /**
+     * 外部订单号 退款使用
+     */
+    private String transactionId;
+    /**
+     * 增加会员有效期 单位月
+     */
+    private Integer count;
 
 }
diff --git a/ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/factory/StudyFallbackFactory.java b/ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/factory/StudyFallbackFactory.java
index 4d28c73..cffb7e4 100644
--- a/ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/factory/StudyFallbackFactory.java
+++ b/ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/factory/StudyFallbackFactory.java
@@ -20,6 +20,11 @@
     public StudyClient create(Throwable cause) {
         return new StudyClient() {
             @Override
+            public R vipBack(Integer id) {
+                return R.fail("用户购买会员退款失败" + cause.getMessage());
+            }
+
+            @Override
             public R<PageInfo<AppUserVO>> couponReceive(AppUserQuery query) {
                 return R.fail("获取用户列表查询失败" + cause.getMessage());
             }
diff --git a/ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/feignClient/StudyClient.java b/ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/feignClient/StudyClient.java
index 9ffab99..bfe4919 100644
--- a/ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/feignClient/StudyClient.java
+++ b/ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/feignClient/StudyClient.java
@@ -22,14 +22,16 @@
 @FeignClient(contextId = "studyClient", value = ServiceNameConstants.STUDY_SERVICE, fallbackFactory = StudyFallbackFactory.class)
 public interface StudyClient {
 
+    @PostMapping("/base/user/vipBack/{id}")
+    R vipBack(@PathVariable("id") Integer id);
     @PostMapping("/base/user/userList")
-    R<PageInfo<AppUserVO>> couponReceive(AppUserQuery query);
+    R<PageInfo<AppUserVO>> couponReceive(@RequestBody AppUserQuery query);
     @PostMapping("/base/user/getUserInfo")
-     R<UserInfoVO> getUserInfo(UserInfoQuery dto);
-    @PostMapping("/base/user/freeze")
-     R freeze(Integer id);
+     R<UserInfoVO> getUserInfo(@RequestBody UserInfoQuery dto);
+    @PostMapping("/base/user/freeze/{id}")
+     R freeze(@PathVariable("id") Integer id);
     @PostMapping("/base/user/vipOrderList")
-     R<PageInfo<VipOrderVO>> vipOrderList(AppUserQuery query);
+     R<PageInfo<VipOrderVO>> vipOrderList(@RequestBody AppUserQuery query);
     /**
      * 选择故事列表查询
      * @param query
diff --git a/ruoyi-auth/src/main/resources/bootstrap.yml b/ruoyi-auth/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..509a56d
--- /dev/null
+++ b/ruoyi-auth/src/main/resources/bootstrap.yml
@@ -0,0 +1,59 @@
+
+# Spring
+spring:
+  profiles:
+    # 环境配置
+    active: dev
+  application:
+    # 应用名称
+    name: ruoyi-auth
+  main:
+    allow-bean-definition-overriding: true
+---
+spring:
+  config:
+    activate:
+      on-profile: dev
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 192.168.110.64:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+      config:
+        # 配置中心地址
+        server-addr: 192.168.110.64:8848
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+---
+spring:
+  config:
+    activate:
+      on-profile: prod
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 127.0.0.1:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: 3452d750-b08d-4485-a1e9-4fb0548f1fc2
+      config:
+        # 配置中心地址
+        server-addr: 127.0.0.1:8848
+        namespace: 3452d750-b08d-4485-a1e9-4fb0548f1fc2
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/HttpStatus.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/HttpStatus.java
index 220a21f..0baecfa 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/HttpStatus.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/HttpStatus.java
@@ -11,6 +11,7 @@
      * 操作成功
      */
     public static final int SUCCESS = 200;
+    public static final int TOKEN_ERROR = 600;
 
     /**
      * 对象创建成功
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/AjaxResult.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/AjaxResult.java
index 7778ec2..825fa3b 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/AjaxResult.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/AjaxResult.java
@@ -70,6 +70,22 @@
     }
 
     /**
+     * token失效
+     * @return
+     */
+    public static AjaxResult tokenError()
+    {
+        return AjaxResult.tokenError("登录失效");
+    }
+    public static AjaxResult tokenError(String msg)
+    {
+        return AjaxResult.tokenError(msg, null);
+    }
+    public static AjaxResult tokenError(String msg, Object data)
+    {
+        return new AjaxResult(HttpStatus.TOKEN_ERROR, msg, data);
+    }
+    /**
      * 返回成功数据
      * 
      * @return 成功消息
diff --git a/ruoyi-gateway/src/main/resources/bootstrap.yml b/ruoyi-gateway/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..815ea08
--- /dev/null
+++ b/ruoyi-gateway/src/main/resources/bootstrap.yml
@@ -0,0 +1,88 @@
+# Spring
+spring:
+  application:
+    # 应用名称
+    name: ruoyi-gateway
+  main:
+    allow-bean-definition-overriding: true
+  profiles:
+    # 环境配置
+    active: dev
+---
+spring:
+  config:
+    activate:
+      on-profile: dev
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 192.168.110.64:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+      config:
+        # 配置中心地址
+        server-addr: 192.168.110.64:8848
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+    sentinel:
+      # 取消控制台懒加载
+      eager: true
+      transport:
+        # 控制台地址
+        dashboard: 192.168.110.64:8718
+      # nacos配置持久化
+      datasource:
+        ds1:
+          nacos:
+            server-addr: 192.168.110.64:8848
+            dataId: sentinel-ruoyi-gateway
+            groupId: DEFAULT_GROUP
+            data-type: json
+            rule-type: gw-flow
+---
+spring:
+  config:
+    activate:
+      on-profile: prod
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 127.0.0.1:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: c2f47d1c-6355-4a68-b357-7523d73b2d13
+      config:
+        # 配置中心地址
+        server-addr: 127.0.0.1:8848
+        namespace: c2f47d1c-6355-4a68-b357-7523d73b2d13
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+    sentinel:
+      # 取消控制台懒加载
+      eager: true
+      transport:
+        # 控制台地址
+        dashboard: 122.9.150.46:8718
+      # nacos配置持久化
+      datasource:
+        ds1:
+          nacos:
+            server-addr: 127.0.0.1:8848
+            dataId: sentinel-ruoyi-gateway
+            groupId: DEFAULT_GROUP
+            data-type: json
+            rule-type: gw-flow
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml b/ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..b592e71
--- /dev/null
+++ b/ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml
@@ -0,0 +1,35 @@
+# Tomcat
+server:
+  port: 9300
+# Spring
+spring: 
+  application:
+    # 应用名称
+    name: ruoyi-file
+  profiles:
+    # 环境配置
+    active: dev
+---
+spring:
+  config:
+    activate:
+      on-profile: dev
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 127.0.0.1:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: 3b151778-d32e-4bf1-8e94-1efefabc777e
+      config:
+        # 配置中心地址
+        server-addr: 127.0.0.1:8848
+        namespace: 3b151778-d32e-4bf1-8e94-1efefabc777e
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/bootstrap.yml b/ruoyi-modules/ruoyi-gen/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..a4d64e9
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/bootstrap.yml
@@ -0,0 +1,36 @@
+# Tomcat
+server:
+  port: 9202
+
+# Spring
+spring: 
+  application:
+    # 应用名称
+    name: ruoyi-gen
+  profiles:
+    # 环境配置
+    active: dev
+---
+spring:
+  config:
+    activate:
+      on-profile: dev
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 192.168.110.64:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+      config:
+        # 配置中心地址
+        server-addr: 192.168.110.64:8848
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
diff --git a/ruoyi-modules/ruoyi-job/src/main/resources/bootstrap.yml b/ruoyi-modules/ruoyi-job/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..817a429
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/resources/bootstrap.yml
@@ -0,0 +1,25 @@
+# Tomcat
+server:
+  port: 9203
+
+# Spring
+spring: 
+  application:
+    # 应用名称
+    name: ruoyi-job
+  profiles:
+    # 环境配置
+    active: dev
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 127.0.0.1:8848
+      config:
+        # 配置中心地址
+        server-addr: 127.0.0.1:8848
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/bootstrap.yml b/ruoyi-modules/ruoyi-system/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..9c18933
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/bootstrap.yml
@@ -0,0 +1,58 @@
+# Spring
+spring: 
+  application:
+    # 应用名称
+    name: ruoyi-system
+  main:
+    allow-bean-definition-overriding: true
+  profiles:
+    # 环境配置
+    active: dev
+---
+spring:
+  config:
+    activate:
+      on-profile: dev
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 192.168.110.64:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+      config:
+        # 配置中心地址
+        server-addr: 192.168.110.64:8848
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+---
+spring:
+  config:
+    activate:
+      on-profile: prod
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 127.0.0.1:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: 3452d750-b08d-4485-a1e9-4fb0548f1fc2
+      config:
+        # 配置中心地址
+        server-addr: 127.0.0.1:8848
+        namespace: 3452d750-b08d-4485-a1e9-4fb0548f1fc2
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
\ No newline at end of file
diff --git a/ruoyi-service/ruoyi-goods/src/main/resources/bootstrap.yml b/ruoyi-service/ruoyi-goods/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..4544b98
--- /dev/null
+++ b/ruoyi-service/ruoyi-goods/src/main/resources/bootstrap.yml
@@ -0,0 +1,59 @@
+
+# Spring
+spring:
+  application:
+    # 应用名称
+    name: ruoyi-goods
+  main:
+    allow-bean-definition-overriding: true
+  profiles:
+    # 环境配置
+    active: dev
+---
+spring:
+  config:
+    activate:
+      on-profile: dev
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 192.168.110.64:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+      config:
+        # 配置中心地址
+        server-addr: 192.168.110.64:8848
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+---
+spring:
+  config:
+    activate:
+      on-profile: prod
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 127.0.0.1:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+      config:
+        # 配置中心地址
+        server-addr: 127.0.0.1:8848
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
diff --git a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/controller/TUserController.java b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/controller/TUserController.java
index d63cb2f..c12df85 100644
--- a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/controller/TUserController.java
+++ b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/controller/TUserController.java
@@ -19,10 +19,7 @@
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
 
@@ -34,7 +31,7 @@
  * @author 无关风月
  * @since 2024-04-26
  */
-@Controller
+@RestController
 @RequestMapping("/tUser")
 public class TUserController {
     @Autowired
@@ -44,7 +41,6 @@
 
     @Autowired
     private StudyClient studyClient;
-    @ResponseBody
     @PostMapping("/userList")
     @ApiOperation(value = "用户列表", tags = {"用户管理"})
     public AjaxResult<PageInfo<AppUserVO>> couponReceive(AppUserQuery query) {
@@ -63,12 +59,11 @@
 ////        }
 ////        res.setRecords(list);
 ////        res.setTotal(list.size());
-        R<PageInfo<AppUserVO>> pageInfoR = studyClient.couponReceive(query);
+        PageInfo<AppUserVO> data = studyClient.couponReceive(query).getData();
 
-        return AjaxResult.success(pageInfoR);
+        return AjaxResult.success(data);
     }
 
-    @ResponseBody
     @PostMapping("/getUserInfo")
     @ApiOperation(value = "查看用户详情", tags = {"用户管理"})
     public AjaxResult<UserInfoVO> getUserInfo(UserInfoQuery dto) {
@@ -116,7 +111,6 @@
 
         return AjaxResult.success(data);
     }
-    @ResponseBody
     @PostMapping("/freeze")
     @ApiOperation(value = "冻结/解冻", tags = {"用户管理"})
     public AjaxResult freeze(Integer id) {
@@ -129,14 +123,18 @@
             return AjaxResult.success("解冻成功");
         }
     }
-    @ResponseBody
     @PostMapping("/getVipSet")
     @ApiOperation(value = "获取会员设置", tags = {"用户管理"})
     public AjaxResult<List<TVipSet>> getVipSet() {
         List<TVipSet> list = vipSetService.list(new QueryWrapper<TVipSet>().orderByAsc("amount"));
         return AjaxResult.success(list);
     }
-    @ResponseBody
+    @PostMapping("/getVipSet1")
+    @ApiOperation(value = "获取会员设置", tags = {"家长端"})
+    public R<List<TVipSet>> getVipSet1() {
+        List<TVipSet> list = vipSetService.list(new QueryWrapper<TVipSet>().orderByAsc("amount"));
+        return R.ok(list);
+    }
     @PostMapping("/setVipSet")
     @ApiOperation(value = "获取会员设置", tags = {"用户管理"})
     public AjaxResult setVipSet(@RequestBody VipSetVO vo) {
@@ -150,7 +148,6 @@
         }
         return AjaxResult.success("保存成功");
     }
-    @ResponseBody
     @PostMapping("/vipOrderList")
     @ApiOperation(value = "列表查询", tags = {"会员管理"})
     public AjaxResult<PageInfo<VipOrderVO>> vipOrderList(AppUserQuery query) {
@@ -158,5 +155,11 @@
         PageInfo<VipOrderVO> data = studyClient.vipOrderList(query).getData();
         return AjaxResult.success(data);
     }
+    @PostMapping("/vipBack")
+    @ApiOperation(value = "会员退款", tags = {"会员管理"})
+    public AjaxResult vipOrderList(Integer id) {
+        studyClient.vipBack(id);
+        return AjaxResult.success();
+    }
 }
 
diff --git a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/domain/TVipOrder.java b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/domain/TVipOrder.java
index 7766ef3..71517d7 100644
--- a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/domain/TVipOrder.java
+++ b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/domain/TVipOrder.java
@@ -60,7 +60,22 @@
      */
     @ApiModelProperty(value = "有效期至")
     private Date time;
+    /**
+     * 支付方式 1微信2支付宝
+     */
+    @ApiModelProperty(value = "支付方式 1微信2支付宝")
+    private Integer payType;
 
-
-
+    /**
+     * 内部订单号 退款使用
+     */
+    private String outTradeNo;
+    /**
+     * 外部订单号 退款使用
+     */
+    private String transactionId;
+    /**
+     * 增加会员有效期 单位月
+     */
+    private Integer count;
 }
diff --git a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/domain/TVipSet.java b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/domain/TVipSet.java
index 46a0b5d..a13e645 100644
--- a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/domain/TVipSet.java
+++ b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/domain/TVipSet.java
@@ -1,15 +1,13 @@
 package com.ruoyi.management.domain;
 
 
-import java.math.BigDecimal;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
 import com.ruoyi.common.core.web.domain.BaseModel;
 import io.swagger.annotations.ApiModelProperty;
 
-import java.io.Serializable;
+import java.math.BigDecimal;
 
 /**
  * <p>
diff --git a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/mapper/TVipSetMapper.java b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/mapper/TVipSetMapper.java
index 12b3923..a60c896 100644
--- a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/mapper/TVipSetMapper.java
+++ b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/mapper/TVipSetMapper.java
@@ -1,7 +1,7 @@
 package com.ruoyi.management.mapper;
 
-import com.ruoyi.management.domain.TVipSet;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.management.domain.TVipSet;
 
 /**
  * <p>
diff --git a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/ITVipSetService.java b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/ITVipSetService.java
index 88ecfe2..cc24aae 100644
--- a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/ITVipSetService.java
+++ b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/service/ITVipSetService.java
@@ -1,7 +1,7 @@
 package com.ruoyi.management.service;
 
-import com.ruoyi.management.domain.TVipSet;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.management.domain.TVipSet;
 
 /**
  * <p>
diff --git a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/vo/VipSetVO.java b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/vo/VipSetVO.java
index 2a58bdd..ff9046b 100644
--- a/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/vo/VipSetVO.java
+++ b/ruoyi-service/ruoyi-management/src/main/java/com/ruoyi/management/vo/VipSetVO.java
@@ -1,15 +1,10 @@
 package com.ruoyi.management.vo;
 
 
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.ruoyi.common.core.web.domain.BaseModel;
 import com.ruoyi.management.domain.TVipSet;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
-import java.math.BigDecimal;
 import java.util.List;
 
 /**
diff --git a/ruoyi-service/ruoyi-management/src/main/resources/bootstrap.yml b/ruoyi-service/ruoyi-management/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..2883560
--- /dev/null
+++ b/ruoyi-service/ruoyi-management/src/main/resources/bootstrap.yml
@@ -0,0 +1,59 @@
+
+# Spring
+spring:
+  application:
+    # 应用名称
+    name: ruoyi-management
+  main:
+    allow-bean-definition-overriding: true
+  profiles:
+    # 环境配置
+    active: dev
+---
+spring:
+  config:
+    activate:
+      on-profile: dev
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 192.168.110.64:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+      config:
+        # 配置中心地址
+        server-addr: 192.168.110.64:8848
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+---
+spring:
+  config:
+    activate:
+      on-profile: prod
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 127.0.0.1:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: 3452d750-b08d-4485-a1e9-4fb0548f1fc2
+      config:
+        # 配置中心地址
+        server-addr: 127.0.0.1:8848
+        namespace: 3452d750-b08d-4485-a1e9-4fb0548f1fc2
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
diff --git a/ruoyi-service/ruoyi-parent/src/main/resources/bootstrap.yml b/ruoyi-service/ruoyi-parent/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..2f1847f
--- /dev/null
+++ b/ruoyi-service/ruoyi-parent/src/main/resources/bootstrap.yml
@@ -0,0 +1,59 @@
+
+# Spring
+spring:
+  application:
+    # 应用名称
+    name: ruoyi-management
+  main:
+    allow-bean-definition-overriding: true
+  profiles:
+    # 环境配置
+    active: dev
+---
+spring:
+  config:
+    activate:
+      on-profile: dev
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 192.168.110.64:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: 8ebd2324-30b4-477b-af79-b46e717c4fbe
+      config:
+        # 配置中心地址
+        server-addr: 192.168.110.64:8848
+        namespace: 8ebd2324-30b4-477b-af79-b46e717c4fbe
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+---
+spring:
+  config:
+    activate:
+      on-profile: prod
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 127.0.0.1:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: 3452d750-b08d-4485-a1e9-4fb0548f1fc2
+      config:
+        # 配置中心地址
+        server-addr: 127.0.0.1:8848
+        namespace: 3452d750-b08d-4485-a1e9-4fb0548f1fc2
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
diff --git a/ruoyi-service/ruoyi-study/pom.xml b/ruoyi-service/ruoyi-study/pom.xml
index d8a58d8..d096c5b 100644
--- a/ruoyi-service/ruoyi-study/pom.xml
+++ b/ruoyi-service/ruoyi-study/pom.xml
@@ -15,8 +15,25 @@
     </description>
 
     <dependencies>
-
-
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+            <version>2.9.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>1.6.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alipay.sdk</groupId>
+            <artifactId>alipay-sdk-java</artifactId>
+            <version>4.8.10.ALL</version>
+        </dependency>
         <dependency>
             <groupId>com.ruoyi</groupId>
             <artifactId>ruoyi-api-system</artifactId>
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TParentLoginController.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TParentLoginController.java
index f30ee1f..22ae8d3 100644
--- a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TParentLoginController.java
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TParentLoginController.java
@@ -2,6 +2,8 @@
 
 
 import com.ruoyi.common.core.web.domain.AjaxResult;
+import com.ruoyi.management.api.feignClient.ManagementClient;
+import com.ruoyi.study.vo.VipInfoVO;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
@@ -11,6 +13,7 @@
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
 
 import java.time.LocalDate;
 import java.util.Date;
@@ -19,19 +22,19 @@
 
 /**
  * <p>
- * 家长端登录 控制器
+ * 家长端 控制器
  * </p>
  *
  * @author 无关风月
  * @since 2024-04-26
  */
-@Controller
-@RequestMapping("/login/parent")
+@RestController
+@RequestMapping("/parent")
 public class TParentLoginController {
 
-    @ResponseBody
+
     @PostMapping("/loginSms")
-    @ApiOperation(value = "短信验证码登录", tags = {"APP-登录注册"})
+    @ApiOperation(value = "短信验证码登录", tags = {"家长端-登录注册"})
     @ApiImplicitParams({
             @ApiImplicitParam(value = "电话号码", name = "phone", dataType = "string", required = true),
             @ApiImplicitParam(value = "短信验证码", name = "code", dataType = "string", required = true),
@@ -40,9 +43,8 @@
 
         return null;
     }
-    @ResponseBody
-    @PostMapping("/base/appUser/logout")
-    @ApiOperation(value = "退出登录", tags = {"我的"})
+    @PostMapping("/logout")
+    @ApiOperation(value = "退出登录", tags = {"家长端-退出登录"})
     @ApiImplicitParams({
             @ApiImplicitParam(name = "Authorization", value = "Bearer eyJhbGciOiJIUzUxMiJ....", required = true, paramType = "header")
     })
@@ -50,5 +52,7 @@
 
         return AjaxResult.success("退出成功");
     }
+
+
 }
 
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TUserController.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TUserController.java
index 433086e..cc0d7d8 100644
--- a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TUserController.java
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TUserController.java
@@ -1,32 +1,36 @@
 package com.ruoyi.study.controller;
 
 
+import com.alipay.api.AlipayApiException;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.ruoyi.common.core.domain.R;
 import com.ruoyi.common.core.web.domain.AjaxResult;
 import com.ruoyi.common.core.web.page.PageInfo;
+import com.ruoyi.common.security.service.TokenService;
 import com.ruoyi.management.api.feignClient.ManagementClient;
 import com.ruoyi.management.api.model.TPage;
+import com.ruoyi.management.api.model.TVipSet;
 import com.ruoyi.study.domain.TUser;
+import com.ruoyi.study.domain.TVipOrder;
 import com.ruoyi.study.dto.AppUserQuery;
 import com.ruoyi.study.dto.UserInfoQuery;
 import com.ruoyi.study.service.ITUserService;
 import com.ruoyi.study.service.IVipOrderService;
-import com.ruoyi.study.vo.AppUserVO;
-import com.ruoyi.study.vo.UserGameRecordVO;
-import com.ruoyi.study.vo.UserInfoVO;
-import com.ruoyi.study.vo.VipOrderVO;
+import com.ruoyi.study.utils.PayMoneyUtil;
+import com.ruoyi.study.utils.UUIDUtil;
+import com.ruoyi.study.vo.*;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Controller;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
 
 /**
  * <p>
@@ -46,6 +50,169 @@
     private IVipOrderService vipOrderService;
     @Autowired
     private ManagementClient managementClient;
+    @PostMapping("/vipInfo")
+    @ApiOperation(value = "会员中心-获取会员说明、当前登录用户是否为会员、会员购买规格", tags = {"家长端-个人中心"})
+    public AjaxResult<List<VipInfoVO>> vipInfo() {
+        List<VipInfoVO> vipInfoVOS = new ArrayList<>();
+        List<TVipSet> data = managementClient.getVipSet1().getData();
+        for (TVipSet datum : data) {
+            VipInfoVO vipInfoVO = new VipInfoVO();
+            vipInfoVO.setInfo(datum.getInfo());
+            vipInfoVO.setId(datum.getId());
+//            vipInfoVO.setIsVip();
+            vipInfoVO.setTime(datum.getTime());
+            vipInfoVO.setAmount(datum.getAmount());
+        }
+        return AjaxResult.ok(vipInfoVOS);
+    }
+    @Autowired
+    private PayMoneyUtil payMoneyUtil;
+
+    @PostMapping("/order")
+    @ApiOperation(value = "购买会员下单操作", tags = {"家长端-个人中心"})
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "Authorization", value = "Bearer eyJhbGciOiJIUzUxMiJ....", required = true, paramType = "header"),
+            @ApiImplicitParam(name = "payType", value = "支付类型 1=微信 2=支付宝", required = true),
+            @ApiImplicitParam(name = "id", value = "会员规格id", required = true),
+    })
+    public AjaxResult order(Integer payType,Integer id) throws Exception {
+        TVipOrder tVipOrder = new TVipOrder();
+        List<TVipSet> data = managementClient.getVipSet1().getData();
+        Integer time = 0;
+        for (TVipSet datum : data) {
+            if (datum.getId() == id){
+                tVipOrder.setMoney(datum.getAmount());
+                time = datum.getTime();
+            }
+        }
+        tVipOrder.setPayState(1);
+//        tVipOrder.setUserId();
+//        tVipOrder.setPayTime();
+//        tVipOrder.setBackTime();
+//        tVipOrder.setTime();
+        tVipOrder.setPayType(payType);
+        tVipOrder.setCount(time);
+        switch (payType){
+            case 1:
+                return payMoneyUtil.weixinpay
+                        ("购买会员", "",
+                                id+"_"+tVipOrder.getId() + "_"+
+                                        UUIDUtil.getRandomCode(8),
+                                tVipOrder.getMoney().toString(),
+                                "/base/wxPayBuyVip", "APP", "");
+            case 2:
+                return payMoneyUtil.alipay
+                        ("购买会员",
+                                "购买会员下单支付",
+                                "",
+                                id+"_"+tVipOrder.getId()+"_"+
+                                        UUIDUtil.getRandomCode(8),
+                                tVipOrder.getMoney().toString(),
+                                "/base/aliPayBuyVip");
+        }
+        return AjaxResult.success();
+    }
+    @ResponseBody
+    @PostMapping("/base/aliPayBuyVip")
+    public void addVipPaymentAliCallback(HttpServletRequest request, HttpServletResponse response) {
+        try {
+            Map<String, String> map = payMoneyUtil.alipayCallback(request);
+            if (null != map) {
+                String out_trade_no = map.get("out_trade_no");
+                String trade_no = map.get("trade_no");
+                // 会员规格id
+                String s = out_trade_no.split("_")[0];
+                Integer integer = Integer.valueOf(s);
+                Integer time  = 0;
+                for (TVipSet datum : managementClient.getVipSet1().getData()) {
+                    if (datum.getId() == integer){
+                        time = datum.getTime();
+                    }
+                }
+                // 订单id
+                String s1 = out_trade_no.split("_")[1];
+                Integer integer1 = Integer.valueOf(s1);
+                TVipOrder byId = vipOrderService.getById(integer1);
+                byId.setPayState(2);
+                byId.setTransactionId(trade_no);
+                byId.setOutTradeNo(out_trade_no);
+                byId.setPayTime(new Date());
+                Calendar calendar = Calendar.getInstance();
+                calendar.setTime(new Date());
+                calendar.add(Calendar.MONTH, time);
+                Date dateAfterOneMonth = calendar.getTime();
+                byId.setTime(dateAfterOneMonth);
+                // 修改订单状态
+                vipOrderService.updateById(byId);
+                TUser byId1 = userService.getById(byId.getUserId());
+                if (byId1.getVipPayTime() == null){
+                    // 是否是首次充值会员
+                    byId1.setVipPayTime(new Date());
+                }
+                byId1.setVipEndTime(dateAfterOneMonth);
+                // 修改用户会员续期信息
+                userService.updateById(byId1);
+                PrintWriter out = response.getWriter();
+                out.write("success");
+                out.flush();
+                out.close();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    @ResponseBody
+    @PostMapping("/base/wxPayBuyVip")
+    public void wxPayBuyPackage(HttpServletRequest request, HttpServletResponse response) {
+        try {
+            Map<String, String> map = payMoneyUtil.weixinpayCallback(request);
+            if (null != map) {
+                // 内部订单号
+                String out_trade_no = map.get("out_trade_no");
+                // 微信订单号
+                String transaction_id = map.get("transaction_id");
+                String result = map.get("result");
+                // 会员规格id
+                String s = out_trade_no.split("_")[0];
+                Integer integer = Integer.valueOf(s);
+                Integer time  = 0;
+                for (TVipSet datum : managementClient.getVipSet1().getData()) {
+                    if (datum.getId() == integer){
+                        time = datum.getTime();
+                    }
+                }
+                // 订单id
+                String s1 = out_trade_no.split("_")[1];
+                Integer integer1 = Integer.valueOf(s1);
+                TVipOrder byId = vipOrderService.getById(integer1);
+                byId.setPayState(2);
+                byId.setTransactionId(transaction_id);
+                byId.setOutTradeNo(out_trade_no);
+                byId.setPayTime(new Date());
+                Calendar calendar = Calendar.getInstance();
+                calendar.setTime(new Date());
+                calendar.add(Calendar.MONTH, time);
+                Date dateAfterOneMonth = calendar.getTime();
+                byId.setTime(dateAfterOneMonth);
+                // 修改订单状态
+                vipOrderService.updateById(byId);
+                TUser byId1 = userService.getById(byId.getUserId());
+                if (byId1.getVipPayTime() == null){
+                    // 是否是首次充值会员
+                    byId1.setVipPayTime(new Date());
+                }
+                byId1.setVipEndTime(dateAfterOneMonth);
+                // 修改用户会员续期信息
+                userService.updateById(byId1);
+                PrintWriter out = response.getWriter();
+                out.write(result);
+                out.flush();
+                out.close();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
     @PostMapping("/getPage")
     @ApiOperation(value = "获取注意事项", tags = {"家长端-注意事项"})
     public AjaxResult<TPage> getPage() {
@@ -57,16 +224,176 @@
         }
         return AjaxResult.success();
     }
+    @Autowired
+    private TokenService tokenService;
+//    @Autowired
+//    private HWSendSms hwSendSms;
+//    @ResponseBody
+//    @PostMapping("/getSMSCode")
+//    @ApiOperation(value = "获取短信验证码", tags = {"家长端-登录注册"})
+//    @ApiImplicitParams({
+//            @ApiImplicitParam(value = "类型(1:登录,2:注册,3:修改密码,4:忘记密码,5:修改绑定手机号)", name = "type", dataType = "int", required = true),
+//            @ApiImplicitParam(value = "电话号码", name = "phone", dataType = "string", required = true)
+//    })
+//    public AjaxResult getSMSCode(Integer type, String phone) {
+//        if (ToolUtil.isEmpty(phone)) {
+//            return AjaxResult.paranErr("phone");
+//        }
+//        if (ToolUtil.isEmpty(type)) {
+//            return AjaxResult.paranErr("type");
+//        }
+//        try {
+//            if (type == 2) {
+//                AppUser tAppUser = appUserService.selectOne(new EntityWrapper<AppUser>()
+//                        .eq("phone", phone).ne("state", 3));
+//                if (null != tAppUser) {
+//                    return AjaxResult.error("账号已存在");
+//                }
+//            }
+//            if (type == 5) {
+//                AppUser tAppUser = appUserService.selectOne(new EntityWrapper<AppUser>()
+//                        .eq("phone", phone).ne("state", 3));
+//                if (null != tAppUser) {
+//                    return AjaxResult.error("账号已存在");
+//                }
+//            }
+//            String numberRandom = UUIDUtil.getNumberRandom(6);
+//            String templateCode = "";
+//            if (type == 1 || type == 2) {
+//                templateCode = "SMS_161275250";
+//            }
+//            if (type == 3 || type == 4) {
+//                templateCode = "SMS_160960014";
+//            }
+////            aLiSendSms.sendSms(phone, templateCode, "{\"code\":\"" + numberRandom + "\"}");
+//            hwSendSms.sendSms(numberRandom,phone);
+//            redisUtil.setStrValue(phone, numberRandom, 300);
+//            return AjaxResult.success();
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//            return ResultUtil.runErr();
+//        }
+//    }
+
     @PostMapping("/updateUserInfo")
     @ApiOperation(value = "修改个人资料", tags = {"家长端-个人中心"})
-
-    public AjaxResult updateUserInfo() {
-
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "Authorization", value = "Bearer eyJhbGciOiJIUzUxMiJ....", required = true, paramType = "header"),
+            @ApiImplicitParam(name = "name", value = "姓名 改什么就只传什么"),
+            @ApiImplicitParam(name = "phone", value = "电话 改什么就只传什么"),
+            @ApiImplicitParam(name = "headImg", value = "头像 改什么就只传什么"),
+    })
+    public AjaxResult updateUserInfo(String name, String phone,String headImg) {
+        // todo 获取用户id
+        Long userid = tokenService.getLoginUser().getUserid();
+        TUser byId = userService.getById(userid);
+        if (StringUtils.hasLength(name)){
+            byId.setName(name);
+        }
+        if (StringUtils.hasLength(phone)){
+            // 先判断手机号是否和当前用户手机号一致
+//            if (byId == null){
+//                return AjaxResult.tokenError("登录失效");
+//            }
+            if (phone.equals(byId.getPhone())){
+                return AjaxResult.error("更换的手机号不能和原手机号相同");
+            }
+            byId.setPhone(phone);
+        }
+        if (StringUtils.hasLength(headImg)){
+            byId.setHeadImg(headImg);
+        }
+        userService.updateById(byId);
         return AjaxResult.success("修改成功");
+    }
+    @PostMapping("/vipBack/{id}")
+    @ApiOperation(value = "会员退款", tags = {"管理后台-会员退款"})
+    public R vipBack(@PathVariable("id") Integer id) throws AlipayApiException {
+        TVipOrder byId = vipOrderService.getById(id);
+        // 外部订单号
+        String transactionId = byId.getTransactionId();
+        // 内部订单号
+        String outTradeNo = byId.getOutTradeNo();
+        switch (byId.getPayType()){
+            case 1:
+                 // 微信退款
+                Map<String, String> stringStringMap = payMoneyUtil.wxRefund(transactionId, outTradeNo, byId.getMoney().toString(), byId.getMoney().toString(), "/base/wxRefund");
+                if (stringStringMap.get("code").equals("SUCCESS")){
+                    byId.setPayState(3);
+                    byId.setBackTime(new Date());
+                    vipOrderService.updateById(byId);
+                    // 用户的vip剩余时间减少
+                    Calendar calendar = Calendar.getInstance();
+                    calendar.setTime(new Date());
+                    calendar.add(Calendar.MONTH, -byId.getCount());
+                    Date dateAfterOneMonth = calendar.getTime();
+                    Integer userId = byId.getUserId();
+                    TUser byId1 = userService.getById(userId);
+                    // 判断用户是不是第一次充值
+                    List<TVipOrder> list = vipOrderService.list(new QueryWrapper<TVipOrder>()
+                            .eq("userId", userId)
+                            .eq("payState", 2)
+                            .orderByDesc("createTime"));
+                    int size = list.size();
+                    if (size == 0){
+                        // 证明这是用户第一次充值会员 将首次充值会员时间和会员到期时间清空
+                        byId1.setVipEndTime(null);
+                        byId1.setVipPayTime(null);
+                        userService.updateById(byId1);
+                    }else{
+                        // 最近的一次充值会员时间
+                        TVipOrder tVipOrder = list.get(0);
+                        // 将会员到期时间回退到上一次
+                        byId1.setVipEndTime(tVipOrder.getTime());
+                        userService.updateById(byId1);
+                    }
+
+                    return R.ok();
+                }else{
+                    return R.fail(stringStringMap.get("msg"));
+                }
+            case 2:
+                // 支付宝退款
+                Map<String, String> stringStringMap1 = payMoneyUtil.aliRefund(transactionId,byId.getMoney().toString());
+                if (stringStringMap1.get("code").equals("10000")){
+                    byId.setPayState(3);
+                    byId.setBackTime(new Date());
+                    vipOrderService.updateById(byId);
+                    // 用户的vip剩余时间减少
+                    Calendar calendar = Calendar.getInstance();
+                    calendar.setTime(new Date());
+                    calendar.add(Calendar.MONTH, -byId.getCount());
+                    Date dateAfterOneMonth = calendar.getTime();
+                    Integer userId = byId.getUserId();
+                    TUser byId1 = userService.getById(userId);
+                    // 判断用户是不是第一次充值
+                    List<TVipOrder> list = vipOrderService.list(new QueryWrapper<TVipOrder>()
+                            .eq("userId", userId)
+                            .eq("payState", 2)
+                            .orderByDesc("createTime"));
+                    int size = list.size();
+                    if (size == 0){
+                        // 证明这是用户第一次充值会员 将首次充值会员时间和会员到期时间清空
+                        byId1.setVipEndTime(null);
+                        byId1.setVipPayTime(null);
+                        userService.updateById(byId1);
+                    }else{
+                        // 最近的一次充值会员时间
+                        TVipOrder tVipOrder = list.get(0);
+                        // 将会员到期时间回退到上一次
+                        byId1.setVipEndTime(tVipOrder.getTime());
+                        userService.updateById(byId1);
+                    }
+                    return R.ok();
+                }else{
+                    return R.fail(stringStringMap1.get("msg"));
+                }
+        }
+        return R.ok();
     }
     @PostMapping("/userList")
     @ApiOperation(value = "用户列表", tags = {"管理后台-用户管理"})
-    public R<PageInfo<AppUserVO>> couponReceive(AppUserQuery query) {
+    public R<PageInfo<AppUserVO>> couponReceive(@RequestBody AppUserQuery query) {
         PageInfo<AppUserVO> res = new PageInfo<>(query.getPageNumber(), query.getPageSize());
         List<AppUserVO> list =  userService.listAll(query);
         for (AppUserVO appUserVO : list) {
@@ -87,7 +414,7 @@
 
     @PostMapping("/getUserInfo")
     @ApiOperation(value = "查看用户详情", tags = {"管理后台-用户管理"})
-    public R<UserInfoVO> getUserInfo(UserInfoQuery dto) {
+    public R<UserInfoVO> getUserInfo(@RequestBody UserInfoQuery dto) {
         SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd");
         UserInfoVO res = new UserInfoVO();
         PageInfo<UserGameRecordVO> list = new PageInfo<>(dto.getPageNumber(), dto.getPageSize());
@@ -130,15 +457,17 @@
         res.setGameRecords(list);
         return R.ok(res);
     }
-    @PostMapping("/freeze")
+    @PostMapping("/freeze/{id}")
     @ApiOperation(value = "冻结/解冻", tags = {"管理后台-用户管理"})
-    public R freeze(Integer id) {
+    public R freeze(@PathVariable("id")  Integer id) {
         TUser byId = userService.getById(id);
         if (byId.getState() == 1) {
             byId.setState(2);
+            userService.updateById(byId);
             return R.ok("冻结成功");
         }else {
             byId.setState(1);
+            userService.updateById(byId);
             return R.ok("解冻成功");
         }
     }
@@ -146,7 +475,7 @@
 
     @PostMapping("/vipOrderList")
     @ApiOperation(value = "列表查询", tags = {"管理后台-会员管理"})
-    public R<PageInfo<VipOrderVO>> vipOrderList(AppUserQuery query) {
+    public R<PageInfo<VipOrderVO>> vipOrderList(@RequestBody AppUserQuery query) {
         PageInfo<VipOrderVO> res = new PageInfo<>(query.getPageNumber(), query.getPageSize());
         List<VipOrderVO> list =  vipOrderService.listAll(query);
         res.setRecords(list);
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/domain/TVipOrder.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/domain/TVipOrder.java
index 8c544ee..d769e57 100644
--- a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/domain/TVipOrder.java
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/domain/TVipOrder.java
@@ -59,7 +59,23 @@
      */
     @ApiModelProperty(value = "有效期至")
     private Date time;
-
+    /**
+     * 支付方式 1微信2支付宝
+     */
+    @ApiModelProperty(value = "支付方式 1微信2支付宝")
+    private Integer payType;
+    /**
+     * 内部订单号 退款使用
+     */
+    private String outTradeNo;
+    /**
+     * 外部订单号 退款使用
+     */
+    private String transactionId;
+    /**
+     * 增加会员有效期 单位月
+     */
+    private Integer count;
 
 
 }
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/CollectionKit.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/CollectionKit.java
new file mode 100644
index 0000000..36bcf5f
--- /dev/null
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/CollectionKit.java
@@ -0,0 +1,782 @@
+package com.ruoyi.study.utils;
+
+import java.lang.reflect.Array;
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * 集合相关工具类,包括数组
+ * 
+ * @author xiaoleilu
+ * 
+ */
+public class CollectionKit {
+	
+	private CollectionKit() {
+		// 静态类不可实例化
+	}
+	
+	/**
+	 * 以 conjunction 为分隔符将集合转换为字符串
+	 * 
+	 * @param <T> 被处理的集合
+	 * @param collection 集合
+	 * @param conjunction 分隔符
+	 * @return 连接后的字符串
+	 */
+	public static <T> String join(Iterable<T> collection, String conjunction) {
+		StringBuilder sb = new StringBuilder();
+		boolean isFirst = true;
+		for (T item : collection) {
+			if (isFirst) {
+				isFirst = false;
+			} else {
+				sb.append(conjunction);
+			}
+			sb.append(item);
+		}
+		return sb.toString();
+	}
+	
+	/**
+	 * 以 conjunction 为分隔符将数组转换为字符串
+	 * 
+	 * @param <T> 被处理的集合
+	 * @param array 数组
+	 * @param conjunction 分隔符
+	 * @return 连接后的字符串
+	 */
+	public static <T> String join(T[] array, String conjunction) {
+		StringBuilder sb = new StringBuilder();
+		boolean isFirst = true;
+		for (T item : array) {
+			if (isFirst) {
+				isFirst = false;
+			} else {
+				sb.append(conjunction);
+			}
+			sb.append(item);
+		}
+		return sb.toString();
+	}
+	
+	/**
+	 * 将多个集合排序并显示不同的段落(分页)
+	 * @param pageNo 页码
+	 * @param numPerPage 每页的条目数
+	 * @param comparator 比较器
+	 * @param colls 集合数组
+	 * @return 分页后的段落内容
+	 */
+
+
+	/**
+	 * 将多个集合排序并显示不同的段落(分页)
+	 * @param pageNo 页码
+	 * @param numPerPage 每页的条目数
+	 * @param comparator 比较器
+	 * @param colls 集合数组
+	 * @return 分业后的段落内容
+	 */
+//	@SafeVarargs
+//	public static <T> List<T> sortPageAll2(int pageNo, int numPerPage, Comparator<T> comparator, Collection<T>... colls) {
+//		BoundedPriorityQueue<T> queue = new BoundedPriorityQueue<T>(pageNo * numPerPage);
+//		for (Collection<T> coll : colls) {
+//			queue.addAll(coll);
+//		}
+//
+//		//第一页且数目少于第一页显示的数目
+//		if(pageNo <=1 && queue.size() <= numPerPage) {
+//			return queue.toList();
+//		}
+//
+//		final int[] startEnd = PageKit.transToStartEnd(pageNo, numPerPage);
+//		return queue.toList().subList(startEnd[0], startEnd[1]);
+//	}
+
+	/**
+	 * 将Set排序(根据Entry的值)
+	 *
+	 * @param set 被排序的Set
+	 * @return 排序后的Set
+	 */
+	public static List<Entry<Long, Long>> sortEntrySetToList(Set<Entry<Long, Long>> set) {
+		List<Entry<Long, Long>> list = new LinkedList<Entry<Long, Long>>(set);
+		Collections.sort(list, new Comparator<Entry<Long, Long>>(){
+
+			@Override
+			public int compare(Entry<Long, Long> o1, Entry<Long, Long> o2) {
+				if (o1.getValue() > o2.getValue()){
+					return 1;
+				}
+				if (o1.getValue() < o2.getValue()){
+					return -1;
+				}
+				return 0;
+			}
+		});
+		return list;
+	}
+
+	/**
+	 * 切取部分数据
+	 *
+	 * @param <T> 集合元素类型
+	 * @param surplusAlaDatas 原数据
+	 * @param partSize 每部分数据的长度
+	 * @return 切取出的数据或null
+	 */
+	public static <T> List<T> popPart(Stack<T> surplusAlaDatas, int partSize) {
+		if (surplusAlaDatas == null || surplusAlaDatas.size() <= 0){
+			return null;
+		}
+
+		final List<T> currentAlaDatas = new ArrayList<T>();
+		int size = surplusAlaDatas.size();
+		// 切割
+		if (size > partSize) {
+			for (int i = 0; i < partSize; i++) {
+				currentAlaDatas.add(surplusAlaDatas.pop());
+			}
+		} else {
+			for (int i = 0; i < size; i++) {
+				currentAlaDatas.add(surplusAlaDatas.pop());
+			}
+		}
+		return currentAlaDatas;
+	}
+
+	/**
+	 * 切取部分数据
+	 *
+	 * @param <T> 集合元素类型
+	 * @param surplusAlaDatas 原数据
+	 * @param partSize 每部分数据的长度
+	 * @return 切取出的数据或null
+	 */
+	public static <T> List<T> popPart(Deque<T> surplusAlaDatas, int partSize) {
+		if (surplusAlaDatas == null || surplusAlaDatas.size() <= 0){
+			return null;
+		}
+
+		final List<T> currentAlaDatas = new ArrayList<T>();
+		int size = surplusAlaDatas.size();
+		// 切割
+		if (size > partSize) {
+			for (int i = 0; i < partSize; i++) {
+				currentAlaDatas.add(surplusAlaDatas.pop());
+			}
+		} else {
+			for (int i = 0; i < size; i++) {
+				currentAlaDatas.add(surplusAlaDatas.pop());
+			}
+		}
+		return currentAlaDatas;
+	}
+
+	/**
+	 * 新建一个HashMap
+	 *
+	 * @return HashMap对象
+	 */
+	public static <T, K> HashMap<T, K> newHashMap() {
+		return new HashMap<T, K>();
+	}
+
+	/**
+	 * 新建一个HashMap
+	 * @param size 初始大小,由于默认负载因子0.75,传入的size会实际初始大小为size / 0.75
+	 * @return HashMap对象
+	 */
+	public static <T, K> HashMap<T, K> newHashMap(int size) {
+		return new HashMap<T, K>((int)(size / 0.75));
+	}
+
+	/**
+	 * 新建一个HashSet
+	 *
+	 * @return HashSet对象
+	 */
+	public static <T> HashSet<T> newHashSet() {
+		return new HashSet<T>();
+	}
+
+	/**
+	 * 新建一个HashSet
+	 *
+	 * @return HashSet对象
+	 */
+	@SafeVarargs
+	public static <T> HashSet<T> newHashSet(T... ts) {
+		HashSet<T> set = new HashSet<T>();
+		for (T t : ts) {
+			set.add(t);
+		}
+		return set;
+	}
+
+	/**
+	 * 新建一个ArrayList
+	 *
+	 * @return ArrayList对象
+	 */
+	public static <T> ArrayList<T> newArrayList() {
+		return new ArrayList<T>();
+	}
+
+	/**
+	 * 新建一个ArrayList
+	 *
+	 * @return ArrayList对象
+	 */
+	@SafeVarargs
+	public static <T> ArrayList<T> newArrayList(T... values) {
+		return new ArrayList<T>(Arrays.asList(values));
+	}
+
+	/**
+	 * 将新元素添加到已有数组中<br/>
+	 * 添加新元素会生成一个新的数组,不影响原数组
+	 *
+	 * @param buffer 已有数组
+	 * @param newElement 新元素
+	 * @return 新数组
+	 */
+	public static <T> T[] append(T[] buffer, T newElement) {
+		T[] t = resize(buffer, buffer.length + 1, newElement.getClass());
+		t[buffer.length] = newElement;
+		return t;
+	}
+
+	/**
+	 * 生成一个新的重新设置大小的数组
+	 *
+	 * @param buffer 原数组
+	 * @param newSize 新的数组大小
+	 * @param componentType 数组元素类型
+	 * @return 调整后的新数组
+	 */
+	public static <T> T[] resize(T[] buffer, int newSize, Class<?> componentType) {
+		T[] newArray = newArray(componentType, newSize);
+		System.arraycopy(buffer, 0, newArray, 0, buffer.length >= newSize ? newSize : buffer.length);
+		return newArray;
+	}
+
+	/**
+	 * 新建一个空数组
+	 * @param componentType 元素类型
+	 * @param newSize 大小
+	 * @return 空数组
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T> T[] newArray(Class<?> componentType, int newSize) {
+		return (T[]) Array.newInstance(componentType, newSize);
+	}
+
+	/**
+	 * 生成一个新的重新设置大小的数组<br/>
+	 * 新数组的类型为原数组的类型
+	 *
+	 * @param buffer 原数组
+	 * @param newSize 新的数组大小
+	 * @return 调整后的新数组
+	 */
+	public static <T> T[] resize(T[] buffer, int newSize) {
+		return resize(buffer, newSize, buffer.getClass().getComponentType());
+	}
+
+	/**
+	 * 将多个数组合并在一起<br>
+	 * 忽略null的数组
+	 *
+	 * @param arrays 数组集合
+	 * @return 合并后的数组
+	 */
+	@SafeVarargs
+	public static <T> T[] addAll(T[]... arrays) {
+		if (arrays.length == 1) {
+			return arrays[0];
+		}
+
+		int length = 0;
+		for (T[] array : arrays) {
+			if(array == null) {
+				continue;
+			}
+			length += array.length;
+		}
+		T[] result = newArray(arrays.getClass().getComponentType().getComponentType(), length);
+
+		length = 0;
+		for (T[] array : arrays) {
+			if(array == null) {
+				continue;
+			}
+			System.arraycopy(array, 0, result, length, array.length);
+			length += array.length;
+		}
+		return result;
+	}
+
+	/**
+	 * 克隆数组
+	 * @param array 被克隆的数组
+	 * @return 新数组
+	 */
+	public static <T> T[] clone(T[] array) {
+		if (array == null) {
+			return null;
+		}
+		return array.clone();
+	}
+
+	/**
+	 * 生成一个数字列表<br>
+	 * 自动判定正序反序
+	 * @param excludedEnd 结束的数字(不包含)
+	 * @return 数字列表
+	 */
+	public static int[] range(int excludedEnd) {
+		return range(0, excludedEnd, 1);
+	}
+
+	/**
+	 * 生成一个数字列表<br>
+	 * 自动判定正序反序
+	 * @param includedStart 开始的数字(包含)
+	 * @param excludedEnd 结束的数字(不包含)
+	 * @return 数字列表
+	 */
+	public static int[] range(int includedStart, int excludedEnd) {
+		return range(includedStart, excludedEnd, 1);
+	}
+
+	/**
+	 * 生成一个数字列表<br>
+	 * 自动判定正序反序
+	 * @param includedStart 开始的数字(包含)
+	 * @param excludedEnd 结束的数字(不包含)
+	 * @param step 步进
+	 * @return 数字列表
+	 */
+	public static int[] range(int includedStart, int excludedEnd, int step) {
+		if(includedStart > excludedEnd) {
+			int tmp = includedStart;
+			includedStart = excludedEnd;
+			excludedEnd = tmp;
+		}
+
+		if(step <=0) {
+			step = 1;
+		}
+
+		int deviation = excludedEnd - includedStart;
+		int length = deviation / step;
+		if(deviation % step != 0) {
+			length += 1;
+		}
+		int[] range = new int[length];
+		for(int i = 0; i < length; i++) {
+			range[i] = includedStart;
+			includedStart += step;
+		}
+		return range;
+	}
+
+	/**
+	 * 截取数组的部分
+	 * @param list 被截取的数组
+	 * @param start 开始位置(包含)
+	 * @param end 结束位置(不包含)
+	 * @return 截取后的数组,当开始位置超过最大时,返回null
+	 */
+	public static <T> List<T> sub(List<T> list, int start, int end) {
+		if(list == null || list.isEmpty()) {
+			return null;
+		}
+
+		if(start < 0) {
+			start = 0;
+		}
+		if(end < 0) {
+			end = 0;
+		}
+
+		if(start > end) {
+			int tmp = start;
+			start = end;
+			end = tmp;
+		}
+
+		final int size = list.size();
+		if(end > size) {
+			if(start >= size) {
+				return null;
+			}
+			end = size;
+		}
+
+		return list.subList(start, end);
+	}
+
+	/**
+	 * 截取集合的部分
+	 * @param list 被截取的数组
+	 * @param start 开始位置(包含)
+	 * @param end 结束位置(不包含)
+	 * @return 截取后的数组,当开始位置超过最大时,返回null
+	 */
+	public static <T> List<T> sub(Collection<T> list, int start, int end) {
+		if(list == null || list.isEmpty()) {
+			return null;
+		}
+
+		return sub(new ArrayList<T>(list), start, end);
+	}
+
+	/**
+	 * 数组是否为空
+	 * @param array 数组
+	 * @return 是否为空
+	 */
+	public static <T> boolean isEmpty(T[] array) {
+		return array == null || array.length == 0;
+	}
+
+	/**
+	 * 数组是否为非空
+	 * @param array 数组
+	 * @return 是否为非空
+	 */
+	public static <T> boolean isNotEmpty(T[] array) {
+		return false == isEmpty(array);
+	}
+
+	/**
+	 * 集合是否为空
+	 * @param collection 集合
+	 * @return 是否为空
+	 */
+	public static boolean isEmpty(Collection<?> collection) {
+		return collection == null || collection.isEmpty();
+	}
+
+	/**
+	 * 集合是否为非空
+	 * @param collection 集合
+	 * @return 是否为非空
+	 */
+	public static boolean isNotEmpty(Collection<?> collection) {
+		return false == isEmpty(collection);
+	}
+
+	/**
+	 * Map是否为空
+	 * @param map 集合
+	 * @return 是否为空
+	 */
+	public static boolean isEmpty(Map<?, ?> map) {
+		return map == null || map.isEmpty();
+	}
+
+	/**
+	 * Map是否为非空
+	 * @param map 集合
+	 * @return 是否为非空
+	 */
+	public static <T> boolean isNotEmpty(Map<?, ?> map) {
+		return false == isEmpty(map);
+	}
+
+	/**
+	 * 映射键值(参考Python的zip()函数)<br>
+	 * 例如:<br>
+	 * 		keys =    [a,b,c,d]<br>
+	 *		values = [1,2,3,4]<br>
+	 * 则得到的Map是 {a=1, b=2, c=3, d=4}<br>
+	 * 如果两个数组长度不同,则只对应最短部分
+	 * @param keys 键列表
+	 * @param values 值列表
+	 * @return Map
+	 */
+	public static <T, K> Map<T, K> zip(T[] keys, K[] values) {
+		if(isEmpty(keys) || isEmpty(values)) {
+			return null;
+		}
+
+		final int size = Math.min(keys.length, values.length);
+		final Map<T, K> map = new HashMap<T, K>((int)(size / 0.75));
+		for(int i = 0; i < size; i++) {
+			map.put(keys[i], values[i]);
+		}
+
+		return map;
+	}
+
+	/**
+	 * 映射键值(参考Python的zip()函数)<br>
+	 * 例如:<br>
+	 * 		keys =    a,b,c,d<br>
+	 *		values = 1,2,3,4<br>
+	 *		delimiter = ,
+	 * 则得到的Map是 {a=1, b=2, c=3, d=4}<br>
+	 * 如果两个数组长度不同,则只对应最短部分
+	 * @param keys 键列表
+	 * @param values 值列表
+	 * @return Map
+	 */
+	public static Map<String, String> zip(String keys, String values, String delimiter) {
+		return zip(StrKit.split(keys, delimiter), StrKit.split(values, delimiter));
+	}
+	
+	/**
+	 * 映射键值(参考Python的zip()函数)<br>
+	 * 例如:<br>
+	 * 		keys =    [a,b,c,d]<br>
+	 *		values = [1,2,3,4]<br>
+	 * 则得到的Map是 {a=1, b=2, c=3, d=4}<br>
+	 * 如果两个数组长度不同,则只对应最短部分
+	 * @param keys 键列表
+	 * @param values 值列表
+	 * @return Map
+	 */
+	public static <T, K> Map<T, K> zip(Collection<T> keys, Collection<K> values) {
+		if(isEmpty(keys) || isEmpty(values)) {
+			return null;
+		}
+		
+		final List<T> keyList = new ArrayList<T>(keys);
+		final List<K> valueList = new ArrayList<K>(values);
+		
+		final int size = Math.min(keys.size(), values.size());
+		final Map<T, K> map = new HashMap<T, K>((int)(size / 0.75));
+		for(int i = 0; i < size; i++) {
+			map.put(keyList.get(i), valueList.get(i));
+		}
+		
+		return map;
+	}
+	
+	/**
+	 * 数组中是否包含元素
+	 * @param array 数组
+	 * @param value 被检查的元素
+	 * @return 是否包含
+	 */
+	public static <T> boolean contains(T[] array, T value) {
+		final Class<?> componetType = array.getClass().getComponentType();
+		boolean isPrimitive = false;
+		if(null != componetType) {
+			isPrimitive = componetType.isPrimitive();
+		}
+		for (T t : array) {
+			if(t == value) {
+				return true;
+			}else if(false == isPrimitive && null != value && value.equals(t)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	/**
+	 * 将Entry集合转换为HashMap
+	 * @param entryCollection entry集合
+	 * @return Map
+	 */
+	public static <T, K> HashMap<T, K> toMap(Collection<Entry<T, K>> entryCollection) {
+		HashMap<T,K> map = new HashMap<T, K>();
+		for (Entry<T, K> entry : entryCollection) {
+			map.put(entry.getKey(), entry.getValue());
+		}
+		return map;
+	}
+	
+	/**
+	 * 将集合转换为排序后的TreeSet
+	 * @param collection 集合
+	 * @param comparator 比较器
+	 * @return treeSet
+	 */
+	public static <T> TreeSet<T> toTreeSet(Collection<T> collection, Comparator<T> comparator){
+		final TreeSet<T> treeSet = new TreeSet<T>(comparator);
+		for (T t : collection) {
+			treeSet.add(t);
+		}
+		return treeSet;
+	}
+	
+	/**
+	 * 排序集合
+	 * @param collection 集合
+	 * @param comparator 比较器
+	 * @return treeSet
+	 */
+	public static <T> List<T> sort(Collection<T> collection, Comparator<T> comparator){
+		List<T> list = new ArrayList<T>(collection);
+		Collections.sort(list, comparator);
+		return list;
+	}
+	
+	//------------------------------------------------------------------- 基本类型的数组转换为包装类型数组
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Integer[] wrap(int... values){
+		final int length = values.length;
+		Integer[] array = new Integer[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Long[] wrap(long... values){
+		final int length = values.length;
+		Long[] array = new Long[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Character[] wrap(char... values){
+		final int length = values.length;
+		Character[] array = new Character[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Byte[] wrap(byte... values){
+		final int length = values.length;
+		Byte[] array = new Byte[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Short[] wrap(short... values){
+		final int length = values.length;
+		Short[] array = new Short[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Float[] wrap(float... values){
+		final int length = values.length;
+		Float[] array = new Float[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Double[] wrap(double... values){
+		final int length = values.length;
+		Double[] array = new Double[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Boolean[] wrap(boolean... values){
+		final int length = values.length;
+		Boolean[] array = new Boolean[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 判定给定对象是否为数组类型
+	 * @param obj 对象
+	 * @return 是否为数组类型
+	 */
+	public static boolean isArray(Object obj){
+		return obj.getClass().isArray();
+	}
+	
+	/**
+	 * 数组或集合转String
+	 * 
+	 * @param obj 集合或数组对象
+	 * @return 数组字符串,与集合转字符串格式相同
+	 */
+	public static String toString(Object obj) {
+		if (null == obj) {
+			return null;
+		}
+		if (isArray(obj)) {
+			try {
+				return Arrays.deepToString((Object[]) obj);
+			} catch (Exception e) {
+				final String className = obj.getClass().getComponentType().getName();
+				switch (className) {
+					case "long":
+						return Arrays.toString((long[]) obj);
+					case "int":
+						return Arrays.toString((int[]) obj);
+					case "short":
+						return Arrays.toString((short[]) obj);
+					case "char":
+						return Arrays.toString((char[]) obj);
+					case "byte":
+						return Arrays.toString((byte[]) obj);
+					case "boolean":
+						return Arrays.toString((boolean[]) obj);
+					case "float":
+						return Arrays.toString((float[]) obj);
+					case "double":
+						return Arrays.toString((double[]) obj);
+					default:
+						throw new ToolBoxException(e);
+				}
+			}
+		}
+		return obj.toString();
+	}
+}
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/DateUtil.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/DateUtil.java
new file mode 100644
index 0000000..cbb41fc
--- /dev/null
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/DateUtil.java
@@ -0,0 +1,329 @@
+/**
+ * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.ruoyi.study.utils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DateFormatUtils;
+import org.apache.commons.lang3.time.DateUtils;
+
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class DateUtil {
+
+    private static TimeZone tz = TimeZone.getTimeZone("GMT+8");
+
+    /**
+     * 获取YYYY格式
+     */
+    public static String getYear() {
+        return formatDate(new Date(), "yyyy");
+    }
+
+    /**
+     * 获取YYYY格式
+     */
+    public static String getYear(Date date) {
+        return formatDate(date, "yyyy");
+    }
+
+    /**
+     * 获取YYYY-MM-DD格式
+     */
+    public static String getDay() {
+        return formatDate(new Date(), "yyyy-MM-dd");
+    }
+
+    /**
+     * 获取YYYY-MM-DD格式
+     */
+    public static String getDay(Date date) {
+        return formatDate(date, "yyyy-MM-dd");
+    }
+
+    /**
+     * 获取YYYYMMDD格式
+     */
+    public static String getDays() {
+        return formatDate(new Date(), "yyyyMMdd");
+    }
+
+    /**
+     * 获取YYYYMMDD格式
+     */
+    public static String getDays(Date date) {
+        return formatDate(date, "yyyyMMdd");
+    }
+
+    /**
+     * 获取YYYY-MM-DD HH:mm:ss格式
+     */
+    public static String getTime() {
+        return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
+    }
+
+    /**
+     * 获取YYYY-MM-DD HH:mm:ss.SSS格式
+     */
+    public static String getMsTime() {
+        return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
+    }
+
+    /**
+     * 获取YYYYMMDDHHmmss格式
+     */
+    public static String getAllTime() {
+        return formatDate(new Date(), "yyyyMMddHHmmss");
+    }
+
+    /**
+     * 获取YYYY-MM-DD HH:mm:ss格式
+     */
+    public static String getTime(Date date) {
+        return formatDate(date, "yyyy-MM-dd HH:mm:ss");
+    }
+
+    public static String formatDate(Date date, String pattern) {
+        String formatDate = null;
+        if (StringUtils.isNotBlank(pattern)) {
+            formatDate = DateFormatUtils.format(date, pattern);
+        } else {
+            formatDate = DateFormatUtils.format(date, "yyyy-MM-dd");
+        }
+        return formatDate;
+    }
+
+    /**
+     * 日期比较,如果s>=e 返回true 否则返回false)
+     *
+     * @author luguosui
+     */
+    public static boolean compareDate(String s, String e) {
+        if (parseDate(s) == null || parseDate(e) == null) {
+            return false;
+        }
+        return parseDate(s).getTime() >= parseDate(e).getTime();
+    }
+
+    /**
+     * 格式化日期
+     */
+    public static Date parseDate(String date) {
+        return parse(date, "yyyy-MM-dd");
+    }
+
+    /**
+     * 格式化日期
+     */
+    public static Date parseTimeMinutes(String date) {
+        return parse(date, "yyyy-MM-dd HH:mm");
+    }
+
+    /**
+     * 格式化日期
+     */
+    public static Date parseTime(String date) {
+        return parse(date, "yyyy-MM-dd HH:mm:ss");
+    }
+
+    /**
+     * 格式化日期
+     */
+    public static Date parse(String date, String pattern) {
+        try {
+            return DateUtils.parseDate(date, pattern);
+        } catch (ParseException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 格式化日期
+     */
+    public static String format(Date date, String pattern) {
+        return DateFormatUtils.format(date, pattern);
+    }
+
+    /**
+     * 把日期转换为Timestamp
+     */
+    public static Timestamp format(Date date) {
+        return new Timestamp(date.getTime());
+    }
+
+    /**
+     * 校验日期是否合法
+     */
+    public static boolean isValidDate(String s) {
+        return parse(s, "yyyy-MM-dd HH:mm:ss") != null;
+    }
+
+    /**
+     * 校验日期是否合法
+     */
+    public static boolean isValidDate(String s, String pattern) {
+        return parse(s, pattern) != null;
+    }
+
+    public static int getDiffYear(String startTime, String endTime) {
+        DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
+        try {
+            int years = (int) (((fmt.parse(endTime).getTime() - fmt.parse(
+                    startTime).getTime()) / (1000 * 60 * 60 * 24)) / 365);
+            return years;
+        } catch (Exception e) {
+            // 如果throw java.text.ParseException或者NullPointerException,就说明格式不对
+            return 0;
+        }
+    }
+
+    /**
+     * <li>功能描述:时间相减得到天数
+     */
+    public static long getDaySub(String beginDateStr, String endDateStr) {
+        long day = 0;
+        SimpleDateFormat format = new SimpleDateFormat(
+                "yyyy-MM-dd");
+        Date beginDate = null;
+        Date endDate = null;
+
+        try {
+            beginDate = format.parse(beginDateStr);
+            endDate = format.parse(endDateStr);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        day = (endDate.getTime() - beginDate.getTime()) / (24 * 60 * 60 * 1000);
+        // System.out.println("相隔的天数="+day);
+
+        return day;
+    }
+
+    /**
+     * 得到n天之后的日期
+     */
+    public static String getAfterDayDate(String days) {
+        int daysInt = Integer.parseInt(days);
+
+        Calendar canlendar = Calendar.getInstance(); // java.util包
+        canlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动
+        Date date = canlendar.getTime();
+
+        SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String dateStr = sdfd.format(date);
+
+        return dateStr;
+    }
+
+    /**
+     * 得到n天之后是周几
+     */
+    public static String getAfterDayWeek(String days) {
+        int daysInt = Integer.parseInt(days);
+
+        Calendar canlendar = Calendar.getInstance(); // java.util包
+        canlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动
+        Date date = canlendar.getTime();
+
+        SimpleDateFormat sdf = new SimpleDateFormat("E");
+        String dateStr = sdf.format(date);
+
+        return dateStr;
+    }
+
+
+    /**
+     * 得到系统日期
+     *
+     * @return
+     */
+    public static Date getDate() {
+        TimeZone.setDefault(tz);
+        return new Date();
+    }
+
+    /**
+     * 获取当前毫秒数
+     *
+     * @return long
+     */
+    public static long getCurMilli() {
+        long millisecond = 0;
+        Calendar cal = Calendar.getInstance();
+        millisecond = cal.getTimeInMillis();
+        return millisecond;
+    }
+
+    /**
+     * 得到系统Calendar日期
+     *
+     * @return
+     */
+    public static Calendar getCalendar() {
+        TimeZone.setDefault(tz);
+        Calendar cal = Calendar.getInstance();
+        return cal;
+    }
+    /**
+     * 毫秒转日期时间
+     *
+     * @param millisecond
+     * @return
+     */
+    public static String getDateTime(long millisecond) {
+        if (millisecond == 0) {
+            millisecond = getCurMilli();
+        }
+        SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Calendar calendar = getCalendar();
+        calendar.setTimeInMillis(millisecond);
+        return dateformat.format(calendar.getTime());
+    }
+
+    /**
+     * 日期转毫秒(加分钟)
+     *
+     * @param date
+     * @return
+     */
+    public static long getMillisecond_fz(String date, Integer day) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String newDate = "";
+        if ("".equals(date)) {
+            newDate = sdf.format(DateUtil.getDate());
+        } else {
+            newDate = getDateTime(Long.parseLong(date));
+        }
+        Date dt = null;
+        try {
+            dt = sdf.parse(newDate);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        Calendar rightNow = Calendar.getInstance();
+        rightNow.setTime(dt);
+        rightNow.add(Calendar.MINUTE, day);
+        Date dt1 = rightNow.getTime();
+        return dt1.getTime();
+    }
+
+}
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/HttpClientUtil.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/HttpClientUtil.java
new file mode 100644
index 0000000..72e3ff5
--- /dev/null
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/HttpClientUtil.java
@@ -0,0 +1,272 @@
+package com.ruoyi.study.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+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.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.ssl.SSLContexts;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import javax.net.ssl.SSLContext;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.security.KeyStore;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * http工具类
+ */
+@Component
+public class HttpClientUtil {
+
+    private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
+
+    private static PoolingHttpClientConnectionManager connectionManager;
+
+
+    {
+        //1.创建连接池管理器
+        connectionManager = new PoolingHttpClientConnectionManager(60000,
+                TimeUnit.MILLISECONDS);
+        connectionManager.setMaxTotal(1000);
+        connectionManager.setDefaultMaxPerRoute(50);
+    }
+
+    /**
+     * 创建一个httpClient对象
+     */
+    private static CloseableHttpClient getHttpCline() {
+        return HttpClients.custom()
+                .setConnectionManager(connectionManager)
+                .disableAutomaticRetries()
+                .build();
+    }
+
+    private static RequestConfig getRequestConfig() {
+        RequestConfig.Builder builder = RequestConfig.custom();
+        builder.setSocketTimeout(60000)//3.1设置客户端等待服务端返回数据的超时时间
+                .setConnectTimeout(30000)//3.2设置客户端发起TCP连接请求的超时时间
+                .setExpectContinueEnabled(true)
+                .setConnectionRequestTimeout(30000);//3.3设置客户端从连接池获取链接的超时时间
+        return builder.build();
+    }
+
+
+    /**
+     * 创建一个POST请求实例
+     *
+     * @param url    请求地址
+     * @param params 请求参数
+     */
+    public static CloseableHttpResponse setPostHttpRequset(String url, Map<String, Object> params, Map<String, String> header, String contentType) throws Exception {
+        HttpPost httpPost = new HttpPost(url);
+        httpPost.setConfig(getRequestConfig());
+        if (null != header) {
+            for (String key : header.keySet()) {
+                httpPost.setHeader(key, header.get(key));
+            }
+        }
+        List<NameValuePair> list = new ArrayList<>();
+        if (null != params) {
+            Set<String> keys = params.keySet();
+            for (String key : keys) {
+                list.add(new BasicNameValuePair(key, null == params.get(key) ? null : params.get(key).toString()));
+            }
+        }
+        switch (contentType) {
+            case "form":
+                httpPost.setEntity(new UrlEncodedFormEntity(list, "UTF-8"));
+                break;
+            case "json":
+                ObjectMapper objectMapper = new ObjectMapper();
+                String s = objectMapper.writeValueAsString(params);
+                httpPost.setEntity(new StringEntity(s, ContentType.create(ContentType.APPLICATION_JSON.getMimeType(), Charset.forName("UTF-8"))));
+                break;
+        }
+        return getHttpCline().execute(httpPost);
+    }
+
+
+    /**
+     * 获取get请求实例
+     *
+     * @param url    请求地址
+     * @param params 请求参数
+     */
+    private static CloseableHttpResponse setGetHttpRequset(String url, Map<String, Object> params, Map<String, String> header) throws Exception {
+        StringBuffer sb = new StringBuffer();
+        String p = "";
+        if (null != params) {
+            Set<String> keys = params.keySet();
+            for (String key : keys) {
+                sb.append(key + "=" + params.get(key) + "&");
+            }
+            p = "?" + sb.substring(0, sb.length() - 1);
+        }
+        HttpGet httpGet = new HttpGet(url + p);
+        httpGet.setConfig(getRequestConfig());
+        if (null != header) {
+            for (String key : header.keySet()) {
+                httpGet.setHeader(key, header.get(key));
+            }
+        }
+        return getHttpCline().execute(httpGet);
+    }
+
+
+    /**
+     * 发送http请求
+     *
+     * @param mothed      "GET、POST、PUT、HEAD、DELETE、HEAD、OPTIONS"
+     * @param url         请求地址
+     * @param params      请求参数
+     * @param header      请求头
+     * @param contentType 参数请求方式form/json
+     * @return
+     */
+    public static HttpResult pushHttpRequset(String mothed, String url, Map<String, Object> params, Map<String, String> header, String contentType) throws Exception {
+        String randome = UUID.randomUUID().toString();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
+        logger.info(sdf.format(new Date()) + "----(" + randome + ")请求参数:" + JSON.toJSONString(params));
+        CloseableHttpResponse httpResponse = null;
+        switch (mothed) {
+            case "GET":
+                httpResponse = setGetHttpRequset(url, params, header);
+                break;
+            case "POST":
+                httpResponse = setPostHttpRequset(url, params, header, contentType);
+                break;
+        }
+        int statusCode = httpResponse.getStatusLine().getStatusCode();
+        String content = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
+        logger.info(sdf.format(new Date()) + "----(" + randome + ")返回结果:" + content);
+        HttpResult httpResult = HttpResult.getHttpResult(statusCode, content);
+        close(httpResponse);
+        return httpResult;
+    }
+
+
+    /**
+     * 发送XML请求
+     *
+     * @param url    请求地址
+     * @param xml    XML数据
+     * @param header 自定义请求头
+     * @return
+     */
+    public static HttpResult pushHttpRequsetXml(String url, String xml, Map<String, String> header) throws Exception {
+        HttpPost httpPost = new HttpPost(url);
+        httpPost.setConfig(getRequestConfig());
+        for (String key : header.keySet()) {
+            httpPost.setHeader(key, header.get(key));
+        }
+        httpPost.setHeader("Content-Type", "application/xml");
+        httpPost.setEntity(new StringEntity(xml, "UTF-8"));
+        CloseableHttpResponse httpResponse = getHttpCline().execute(httpPost);
+        int statusCode = httpResponse.getStatusLine().getStatusCode();
+        String content = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
+        HttpResult httpResult = HttpResult.getHttpResult(statusCode, content);
+        close(httpResponse);
+        return httpResult;
+    }
+
+
+    /**
+     * 请求https发送XML请求
+     *
+     * @param url          接口路径
+     * @param xml          内容
+     * @param header       请求头
+     * @param certPassword 证书密码
+     * @param certPath     证书路径
+     * @param certType     证书类型
+     * @return
+     * @throws Exception
+     */
+    public static String pushHttpsRequsetXml(String url, String xml, Map<String, String> header, String certPassword, String certPath, String certType) throws Exception {
+        HttpPost httpPost = new HttpPost(url);
+        for (String key : header.keySet()) {
+            httpPost.setHeader(key, header.get(key));
+        }
+        httpPost.setHeader("Content-Type", "application/xml");
+        httpPost.setEntity(new StringEntity(xml, "UTF-8"));
+        CloseableHttpClient httpCline = initCert(certPassword, certPath, certType);
+        CloseableHttpResponse httpResponse = httpCline.execute(httpPost);
+        String content = null;
+        if (httpResponse.getStatusLine().getStatusCode() == 200) {
+            content = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
+        } else {
+            content = "返回状态码:" + httpResponse.getStatusLine() + "。" + EntityUtils.toString(httpResponse.getEntity());
+        }
+        close(httpResponse);
+        httpCline.close();
+        return content;
+    }
+
+
+    /**
+     * 初始化https对象(带证书)
+     *
+     * @param key      证书密码
+     * @param certPath 证书路径
+     * @param certType 证书类型
+     * @throws Exception
+     */
+    private static CloseableHttpClient initCert(String key, String certPath, String certType) throws Exception {
+        KeyStore keyStore = KeyStore.getInstance(certType);
+        InputStream inputStream = new FileInputStream(new File(certPath));
+        try {
+            keyStore.load(inputStream, key.toCharArray());
+        } finally {
+            inputStream.close();
+        }
+        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray()).build();
+        SSLConnectionSocketFactory sslsf =
+                new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null,
+                        SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+        return HttpClients.custom().setSSLSocketFactory(sslsf).build();
+    }
+
+
+    /**
+     * 关闭资源
+     */
+    private static void close(CloseableHttpResponse httpResponse) {
+        try {
+            if (null != httpResponse) {
+                EntityUtils.consume(httpResponse.getEntity());//此处高能,通过源码分析,由EntityUtils是否回收HttpEntity
+                httpResponse.close();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (null != httpResponse) {
+                    httpResponse.close();
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+
+}
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/HttpResult.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/HttpResult.java
new file mode 100644
index 0000000..d584973
--- /dev/null
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/HttpResult.java
@@ -0,0 +1,31 @@
+package com.ruoyi.study.utils;
+
+import lombok.Data;
+
+/**
+ * http请求返回封装
+ */
+@Data
+public class HttpResult {
+    /**
+     * 返回状态码
+     */
+    private Integer code;
+    /**
+     * 返回结果
+     */
+    private String data;
+
+    /**
+     * 返回封装结果
+     * @param code
+     * @param data
+     * @return
+     */
+    public static HttpResult getHttpResult(Integer code, String data){
+        HttpResult httpResult = new HttpResult();
+        httpResult.setCode(code);
+        httpResult.setData(data);
+        return httpResult;
+    }
+}
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/MD5AndKL.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/MD5AndKL.java
new file mode 100644
index 0000000..eb4ce3d
--- /dev/null
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/MD5AndKL.java
@@ -0,0 +1,116 @@
+package com.ruoyi.study.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.security.MessageDigest;
+
+public class MD5AndKL {
+
+	private static Logger logger = LoggerFactory.getLogger(MD5AndKL.class);
+	
+	/**
+	 * MD5加码。32位
+	 * 
+	 * @param inStr
+	 * @return
+	 */
+	public static String MD5(String inStr) {
+		MessageDigest md5 = null;
+		try {
+			md5 = MessageDigest.getInstance("MD5");
+		} catch (Exception e) {
+			throw new RuntimeException(e.toString());
+		}
+		byte[] md5Bytes = md5.digest(inStr.getBytes());
+		StringBuffer hexValue = new StringBuffer();
+		for (int i = 0; i < md5Bytes.length; i++) {
+			int val = ((int) md5Bytes[i]) & 0xff;
+			if (val < 16) {
+				hexValue.append("0");
+			}
+			hexValue.append(Integer.toHexString(val));
+		}
+		return hexValue.toString();
+	}
+
+	/**
+	 * 可逆的加密算法
+	 * 
+	 * @param inStr
+	 * @return
+	 */
+	public static String KL(String inStr) {
+		char[] a = inStr.toCharArray();
+		for (int i = 0; i < a.length; i++) {
+			a[i] = (char) (a[i] ^ 't');
+		}
+		String s = new String(a);
+		return s;
+	}
+
+	/**
+	 * 加密后解密
+	 * 
+	 * @param inStr
+	 * @return
+	 */
+	public static String JM(String inStr) {
+		char[] a = inStr.toCharArray();
+		for (int i = 0; i < a.length; i++) {
+			a[i] = (char) (a[i] ^ 't');
+		}
+		String k = new String(a);
+		return k;
+	}
+
+
+
+	private static String byteArrayToHexString(byte b[]) {
+		StringBuffer resultSb = new StringBuffer();
+		for (int i = 0; i < b.length; i++)
+			resultSb.append(byteToHexString(b[i]));
+
+		return resultSb.toString();
+	}
+
+	private static String byteToHexString(byte b) {
+		int n = b;
+		if (n < 0)
+			n += 256;
+		int d1 = n / 16;
+		int d2 = n % 16;
+		return hexDigits[d1] + hexDigits[d2];
+	}
+
+	public static String MD5Encode(String origin, String charsetname) {
+		String resultString = null;
+		try {
+			resultString = new String(origin);
+			MessageDigest md = MessageDigest.getInstance("MD5");
+			if (charsetname == null || "".equals(charsetname)){
+				resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
+			}else{
+				resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
+			}
+		} catch (Exception exception) {
+			exception.printStackTrace();
+		}
+		return resultString;
+	}
+
+	private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
+			"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
+
+	public static void main(String args[]) {
+//		logger.debug("MD5后再加密:" + KL(MD5("123456")));
+//		logger.debug(MD5("123456"));
+//		 logger.debug("加密:" + KL(MD5("123456")));
+		// s = KL(s);
+		// logger.debug("解密:" + KL("81dc9bdb52d04dc20036dbd8313ed055"));
+		// logger.debug("解密:" + JM(KL(s)));
+		// logger.debug("解密为MD5后的:" + KL(KL(MD5(s))));
+//		 logger.debug(JM("5d62957bb57d3e49dcf48a0df064be4c"));
+		// logger.debug(MD5AndKL.KL(MD5AndKL.MD5("admin"+"87654321")));
+	}
+}
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/PayMoneyUtil.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/PayMoneyUtil.java
new file mode 100644
index 0000000..40aab9e
--- /dev/null
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/PayMoneyUtil.java
@@ -0,0 +1,1278 @@
+package com.ruoyi.study.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alipay.api.AlipayApiException;
+import com.alipay.api.AlipayClient;
+import com.alipay.api.CertAlipayRequest;
+import com.alipay.api.DefaultAlipayClient;
+import com.alipay.api.domain.*;
+import com.alipay.api.request.*;
+import com.alipay.api.response.*;
+import com.ruoyi.common.core.web.domain.AjaxResult;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.http.HttpServletRequest;
+import java.io.*;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Security;
+import java.util.*;
+
+//import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingReceiver;
+//import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingRequest;
+//import com.github.binarywang.wxpay.service.ProfitSharingV3Service;
+//import com.github.binarywang.wxpay.service.WxPayService;
+
+/**
+ * 第三方支付工具类
+ */
+@Component
+public class PayMoneyUtil {
+    private String aliAppid = "2021004137643228";//支付宝appid
+
+    private String appPrivateKey = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCBMKFpKKMTSL9XAotOLeWsFMwzj6UEnukKX6pkZ4Nn1/0VayNc1N+BJqVA8aCr09dDsrBKJ67bJYNwwgr4rfVRz6DxJmctapfyf41/fwMGLwkG96Mcis1+XI8fRqMctf7RoWwVbuvkX0x93kpuNlHJCSuKzc+iT9qPWNp0DwPQa/T354fzztAmGWREY6v67OeTI/kFO5pnOvRqvPPgGCkvqQmGoSk6BQavQSy0jqyOf98FfvCT3GZPhohHqxUAIy1NjUs98KgLUTgv9Uo7OoLrzGOkQBIkL53bgh7rkLukgbo9D/qYxo3rK55LgJtDgP+qZrsVPDwa65Ntyi/r0WJLAgMBAAECggEAI11AkhzBp0G+vv6/S4Nc36JB08t6jK1DdceCSUHcwsxpRzew0nSjSiNeEU0TgnXW830yrNn4D51RQcicYD6ebOq9T8YHcHNBbOxlu4T1OvgdLH8Vc3a7kd+cfh9D/1QCkTfy8lsOz9EWi04SaeEMuk98T97O+8uINL1J74M8tAyzzNZqcsGjCvCSoVqdUGVVJX/5tkTq1HI4y+jAyJYg+JhhKzxI0grHb6ktzdJ+iIClHJ7hV3CFV6S4FKcAhOjcsB+r7W6pc98mlHqK+EuN3i7SUv81XWVfHrp12hiFn6J4x+NturK3i2MfQA9aH7BRJTTo+DH7tYseID5s8q3GgQKBgQDeLWfuzSbS2RoBHdO89tsUPaSgif5RbJvp/Cl5zBnfyWxk/knUWMzTyqYiuOVU9/qWF4i5uvFCnpaS8oPKvCiG2YEG+k0bT63r129K8gRqqx62PisNqEeLmOjj+HuI9flV8pOzJBkLNNbdundkh3Li6eiv1Di47+H3dPdha3K60QKBgQCU21y7qssRRS7pbi3GygoZC1Xq236RZJor2ZPPOJi4flyyLhQI0S+dpzyb8t32y8mHTIrDZnK/km16tQChe9cCkKOyaUYvJOIbfce0A+GWM5jzS3Yan0GtoNBNqd+ayrqAVxjS++RU55wBpgEFNB1lyp+Es982HjYivrWCDoPaWwKBgDcMbQoADrSDUiwgpcvWJiX3uAiG6FpoXKE291fUODz4fUDwuH5Cmk2Hkm5b/YZ2AsKZhijupsRo4sn6CKl8wVXYIl4GOoCf12nt8QdSu8FqMKva73Ps0/1En7+MW59twp+HAQ2LziC2sN4zS02/Obn7Vsnp/TvlQ8m6U2jx5HVhAoGAY4Q7/OL0G7mq4ThdtjbAhXnEmNzhQwaE46f0X2cxArbH9f9EOZjQQo/Zv1ChACvBsYiEhJnrQRP9yTlVEKCgYACez9n9p+r6lvKCHmEx4Z7hNFZQwP+Tgyat3B4jdXLvOHoCCJuKTREChT+cEwSCWtkZyDgQlDeibZwd8LMPh10CgYBnZtYU6bo7l5CtXWQbpZB/cl7bznHxtfNYhiqKNcUx1+zh6tLDcwmk+CkFjHWYgWCiXOu+EeSQys7v/ps/C1nKUVEy1bytLNU3pdy63aZ/6WzD8MIwOwkZZch9sm9LK//Ar+E7CtC2NsxSN1elqjoEVeQMqKSj5MNt8XlDlCzwVQ==";//支付宝开发者应用私钥
+
+    private String alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAouYvZ1v4RiydwNOnGcU0Hb4hQu0x6XUooaE2Bi6/atNOobtFdunnATGP6OMOW7yF9DpP8qH5mbFXAiaQD721y/7qlayI50UcV4mngRU4ZcaAVE3bp721Eg2H85RISa+Tb1CiOh+pc9p4l5UBseKsvB2ruHHForfZDPI8FL7AVUKBYCQPsa4zL6KAO2C6KULaTg/lCa+bYQKU0n9ca569VtdsqJUyxB9eSZjVd+9nKl62FLqp2NELGj7cXqiVBgDnBnVS5ZUO3mrBM5z/AxQbw3RwE3JqdkhzUA1BFjejAlT2zIGNOjUFagF8ao0wGElYfuk0bum6Hz5qWAt02QdNNwIDAQAB";//支付宝应用公钥
+
+    private String alipay_public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw4KgQIQq9Pl91tG9NS8N9bs7xF89/L2jHgLWuG5kStoorvm5j3W5Bc0jSW01HgEXSks99xKeOhfebHurTehuamIs/2G8atT4haejl4Qip2ZvkhsQm+So3oFj2E8Q1QGrpISc9TwHxfpErEJInc8xd5TjYkPxVFQY25oQ3O2yOvvWxdxGZttdEDm6mE+udNjY72YqUvh1U9cMCIpj+4AugHh/5L3eo5VHQNA6rIvX1WSFqJ/vcXrT3RSPSg33lD0MEMR9+ICR88mPi6zbt5dTbCR8us/qK7+hJ3yb3LyQxNH+2DmyVYX5pSEkXMK+2mTwaUWd1z5Oeg1iXW6ev3f+9wIDAQAB";//支付宝支付公钥
+
+    private String smid = "2088330203191220";//平台支付宝商户号...
+
+    private String appid = "wx41d32f362ba0f911";//微信appid
+
+    private String appSecret = "cf0ebf950f5926a69041a0e2bbe20f3e";
+
+    private String mchId = "1501481761";//微信商户号
+
+    private String key = "6f5e0c2dcabfa9c27b5da5836a362fef";//微信商户号
+
+    private String callbackPath = "https://jkcyl.cn/app";//支付回调网关地址
+
+    private String app_cert_path = "C:/cert/alipay/user/app_cert_path.crt";//应用公钥证书路径
+
+    private String alipay_cert_path = "C:/cert/alipay/user/alipay_cert_path.crt";//支付宝公钥证书文件路径
+
+    private String alipay_root_cert_path = "C:/cert/alipay/user/alipay_root_cert_path.crt";//支付宝CA根证书文件路径
+
+    private String certPath = "/usr/playpai/cert/weixin/apiclient_cert.p12";//微信证书
+
+
+    /**
+     * 支付宝支付
+     */
+    public AjaxResult alipay(String body, String subject, String passbackParams, String outTradeNo, String amount, String notifyUrl) {
+        //实例化客户端
+        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", aliAppid, appPrivateKey, "json", "UTF-8", alipay_public_key, "RSA2");
+        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
+        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
+        //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
+        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
+        model.setBody(body);//对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。
+        model.setSubject(subject);//商品的标题/交易标题/订单标题/订单关键字等。
+        model.setOutTradeNo(outTradeNo);//商户网站唯一订单号
+        model.setTimeoutExpress("30m");
+        model.setTotalAmount(new BigDecimal(amount).setScale(2, RoundingMode.HALF_UP).toString());//付款金额
+        model.setProductCode("QUICK_MSECURITY_PAY");
+        model.setPassbackParams(passbackParams);//自定义参数
+        request.setBizModel(model);
+        request.setNotifyUrl(callbackPath + notifyUrl);
+        try {
+            //这里和普通的接口调用不同,使用的是sdkExecute
+            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
+            Map<String, String> map = new HashMap<>();
+            map.put("orderString", response.getBody());
+            map.put("returnId", passbackParams);
+            System.out.println(map);//就是orderString 可以直接给客户端请求,无需再做处理。
+            return AjaxResult.success(map);
+        } catch (AlipayApiException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 支付宝扫码支付下单
+     *
+     * @param body
+     * @param subject
+     * @param outTradeNo
+     * @param amount
+     * @param notifyUrl
+     * @return
+     */
+    public AjaxResult aliScanCodePay(String body, String subject, String outTradeNo, String amount, String notifyUrl) {
+        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", aliAppid, appPrivateKey, "json", "UTF-8", alipay_public_key, "RSA2"); //获得初始化的AlipayClient
+        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();//创建API对应的request类
+        request.setBizContent("{" +
+                "    \"out_trade_no\":\"" + outTradeNo + "\"," +//商户订单号
+                "    \"total_amount\":\"" + 1 + "\"," +
+                "    \"subject\":\"" + subject + "\"," +
+                "    \"notify_url\":\"" + callbackPath + notifyUrl + "\"," +
+                "    \"body\":\"" + body + "\"," +
+                "    \"store_id\":\"NJ_001\"," +
+                "    \"timeout_express\":\"90m\"}");//订单允许的最晚付款时间
+        AlipayTradePrecreateResponse response = null;
+        try {
+            response = alipayClient.execute(request);
+        } catch (AlipayApiException e) {
+            e.printStackTrace();
+        }
+        JSONObject alipay_trade_precreate_response = JSON.parseObject(response.getBody()).getJSONObject("alipay_trade_precreate_response");
+
+        System.err.print(alipay_trade_precreate_response.getString("qr_code"));
+        return AjaxResult.success(alipay_trade_precreate_response.getString("qr_code"));
+    }
+    // 直付通模式 alipay.trade.settle.confirm(统一收单确认结算接口)
+    public AjaxResult confirm(String smid1,String code, String outTradeNo, String amount) {
+        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
+                aliAppid,
+                appPrivateKey,
+                "json",
+                "GBK",
+                alipay_public_key,
+                "RSA2");
+        AlipayTradeSettleConfirmRequest request = new AlipayTradeSettleConfirmRequest();
+        request.setBizContent("{" +
+                "  \"out_request_no\":\""+code+"\"," +
+                "  \"trade_no\":\""+outTradeNo+"\"," +
+                "  \"settle_info\":{" +
+                "    \"settle_detail_infos\":[" +
+                "      {" +
+                "        \"trans_in_type\":\"defaultSettle\"," +
+                "        \"settle_entity_id\":\""+smid1+"\"," +
+                "        \"settle_entity_type\":\"SecondMerchant\"," +
+                "        \"amount\":"+amount+"," +
+                "      }" +
+                "    ]" +
+                "  }," +
+                "  \"extend_params\":{" +
+                "    \"royalty_freeze\":\"false\"" +
+                "  }" +
+                "}");
+        AlipayTradeSettleConfirmResponse response = null;
+        try {
+            response = alipayClient.execute(request);
+        } catch (AlipayApiException e) {
+            e.printStackTrace();
+        }
+        if(response.isSuccess()){
+            System.out.println("调用成功");
+            return AjaxResult.success();
+        } else {
+            System.out.println("调用失败");
+            return AjaxResult.error("出现问题啦");
+        }
+    }
+
+    /**
+     * 支付成功后的回调处理逻辑
+     *
+     * @param request
+     */
+    public Map<String, String> alipayCallback(HttpServletRequest request) {
+        //获取支付宝POST过来反馈信息
+        Map<String, String> params = new HashMap<String, String>();
+        Map requestParams = request.getParameterMap();
+        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
+            String name = (String) iter.next();
+            String[] values = (String[]) requestParams.get(name);
+            String valueStr = "";
+            for (int i = 0; i < values.length; i++) {
+                valueStr = (i == values.length - 1) ? valueStr + values[i]
+                        : valueStr + values[i] + "_";
+            }
+            //乱码解决,这段代码在出现乱码时使用。
+            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
+            params.put(name, valueStr);
+        }
+        //切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
+        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
+//        try {
+//            boolean flag = AlipaySignature.rsaCheckV1(params, alipay_public_key, "UTF-8","RSA2");
+//            if(flag){
+//                Map<String, String> map = new HashMap<>();
+//                String out_trade_no = params.get("out_trade_no");
+//                String subject = params.get("subject");
+//                String total_amount = params.get("total_amount");
+//                String trade_no = params.get("trade_no");
+//                String passback_params = params.get("passback_params");
+//                map.put("out_trade_no", out_trade_no);//商家订单号
+//                map.put("subject", subject);
+//                map.put("total_amount", total_amount);
+//                map.put("trade_no", trade_no);//支付宝交易号
+//                map.put("passback_params", passback_params);//回传参数
+//                return map;
+//            }else{
+//                System.err.println("验签失败");
+//            }
+//
+//        } catch (AlipayApiException e) {
+//            e.printStackTrace();
+//        }
+//        return null;
+
+
+        Map<String, String> map = new HashMap<>();
+        String out_trade_no = params.get("out_trade_no");
+        String subject = params.get("subject");
+        String total_amount = params.get("total_amount");
+        String trade_no = params.get("trade_no");
+        String passback_params = params.get("passback_params");
+        map.put("out_trade_no", out_trade_no);//商家订单号
+        map.put("subject", subject);
+        map.put("total_amount", total_amount);
+        map.put("trade_no", trade_no);//支付宝交易号
+        map.put("passback_params", passback_params);//回传参数
+        return map;
+    }
+
+
+    /**
+     * 支付宝查询订单支付状态
+     *
+     * @param out_trade_no
+     * @return
+     * @throws Exception
+     */
+    public AlipayTradeQueryResponse queryALIOrder(String out_trade_no) throws Exception {
+        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", aliAppid, appPrivateKey, "json", "UTF-8", alipay_public_key, "RSA2");
+        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
+        request.setBizContent("{" +
+                "  \"out_trade_no\":\"" + out_trade_no + "\"" +
+                "}");
+        AlipayTradeQueryResponse response = alipayClient.execute(request);
+        return response;
+//        if(response.isSuccess()){
+//            String tradeStatus = response.getTradeStatus();//交易状态:WAIT_BUYER_PAY(交易创建,等待买家付款)、TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)、TRADE_SUCCESS(交易支付成功)、TRADE_FINISHED(交易结束,不可退款)
+//            return ResultUtil.success(response);
+//        } else {
+//            return ResultUtil.error(response.getMsg());
+//        }
+    }
+
+
+    /**
+     * 微信统一下单
+     *
+     * @param body         商品描述
+     * @param attach       附加数据
+     * @param out_trade_no 商户订单号
+     * @param total_fee    标价金额
+     * @param notify_url   通知地址
+     * @param tradeType    交易类型
+     * @return
+     */
+    public AjaxResult weixinpay(String body, String attach, String out_trade_no, String total_fee, String notify_url, String tradeType, String openId) throws Exception {
+        int i = new BigDecimal(total_fee).multiply(new BigDecimal("100")).intValue();
+        String hostAddress = null;
+        try {
+            hostAddress = InetAddress.getLocalHost().getHostAddress();
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+        }
+        String nonce_str = UUIDUtil.getRandomCode(16);
+        Map<String, Object> map = new HashMap<>();
+        map.put("appid", appid);
+        map.put("mch_id", mchId);
+        map.put("nonce_str", nonce_str);
+        map.put("body", body);
+        map.put("attach", attach);//存储订单id
+        map.put("out_trade_no", out_trade_no);//存储的订单code
+        map.put("total_fee", i);
+        map.put("spbill_create_ip", hostAddress);
+        map.put("notify_url", callbackPath + notify_url);
+        map.put("trade_type", tradeType);
+        if ("JSAPI".equals(tradeType)) {
+            map.put("openid", openId);
+        }
+        String s = this.weixinSignature(map);
+        map.put("sign", s);
+
+        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_XML);
+        StringBuffer xmlString = new StringBuffer();
+        Set<String> strings = map.keySet();
+        String[] keys = {};
+        keys = strings.toArray(keys);
+        Arrays.sort(keys);
+        xmlString.append("<xml>");
+        for (int l = 0; l < keys.length; l++) {
+            xmlString.append("<" + keys[l] + ">" + map.get(keys[l]) + "</" + keys[l] + ">");
+        }
+        xmlString.append("</xml>");
+
+        Map<String, String> map1 = null;
+        String body1 = HttpClientUtil.pushHttpRequsetXml(url, xmlString.toString(), new HashMap<>()).getData();
+        //将结果xml解析成map
+        body1 = body1.replaceAll("<!\\[CDATA\\[", "");
+        body1 = body1.replaceAll("]]>", "");
+        try {
+            map1 = this.xmlToMap(body1, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        String return_code = map1.get("return_code");
+        if ("SUCCESS".equals(return_code)) {
+            String result_code = map1.get("result_code");
+            if ("SUCCESS".equals(result_code)) {
+                String type = map1.get("trade_type");
+                String prepay_id = map1.get("prepay_id");
+                switch (type) {
+                    case "JSAPI":
+                        //重新进行签名后返回给前端
+                        Map<String, Object> map2 = new HashMap<>();
+                        map2.put("appId", map1.get("appid"));
+                        map2.put("nonceStr", map1.get("nonce_str"));
+                        map2.put("package", "prepay_id=" + prepay_id);
+                        map2.put("signType", "MD5");
+                        map2.put("timeStamp", new Date().getTime() + "");
+                        String s2 = this.weixinSignature(map2);
+
+                        map2.put("prepay_id", prepay_id);
+                        map2.put("mch_id", map1.get("mch_id"));
+                        map2.put("trade_type", map1.get("trade_type"));
+
+                        map2.put("sign", s2);
+                        return AjaxResult.success(map2);
+                    case "NATIVE":
+                        String code_url = map1.get("code_url");
+                        return AjaxResult.success(code_url);
+                    case "APP":
+                        //重新进行签名后返回给前端
+                        Map<String, Object> map3 = new HashMap<>();
+                        map3.put("appid", appid);
+                        map3.put("noncestr", nonce_str);
+                        map3.put("package", "Sign=WXPay");
+                        map3.put("partnerid", mchId);
+                        map3.put("prepayid", prepay_id);
+                        map3.put("timestamp", new Date().getTime() / 1000);
+                        String s1 = this.weixinSignature(map3);
+                        map3.put("sign", s1);
+                        System.err.println(map3);
+                        return AjaxResult.success(map3);
+                }
+                return null;
+            } else {
+                System.err.println(map1.get("err_code_des"));
+                return AjaxResult.error(map1.get("err_code_des"));
+            }
+        } else {
+            System.err.println(map1.get("return_msg") + appid + "----" + mchId);
+            return AjaxResult.error(map1.get("return_msg"), new JSONObject());
+        }
+    }
+
+
+
+    /**
+     * 微信支付成功后的回调处理
+     *
+     * @param request
+     */
+    public Map<String, String> weixinpayCallback(HttpServletRequest request) {
+        try {
+            String param = this.getParam(request);
+            param = param.replaceAll("<!\\[CDATA\\[", "");
+            param = param.replaceAll("]]>", "");
+            Map<String, String> map = this.xmlToMap(param, "UTF-8");
+            String return_code = map.get("return_code");
+            if ("SUCCESS".equals(return_code)) {
+                String result_code = map.get("result_code");
+                if ("SUCCESS".equals(result_code)) {
+                    Map<String, String> map1 = new HashMap<>();
+                    map1.put("nonce_str", map.get("nonce_str"));
+                    map1.put("out_trade_no", map.get("out_trade_no"));//存储的订单code
+                    map1.put("attach", map.get("attach"));//存储订单id
+                    map1.put("total_fee", map.get("total_fee"));
+                    map1.put("transaction_id", map.get("transaction_id"));//微信支付订单号
+                    String result = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
+                    map1.put("result", result);
+                    return map1;
+                } else {
+                    System.err.println(map.get("err_code_des"));
+                }
+            } else {
+                System.err.println(map.get("return_msg"));
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return null;
+    }
+
+
+//    @Autowired
+//    private WxPayService wxPayService;
+    //分账
+//    public ResultUtil order(String code) throws Exception {
+//
+//
+//
+//                  Integer    coursePackagePayments = coursePackageClient.queryByCode(code);
+//                  Integer paymentCompetitions = competitionsClient.queryByCode(code);
+//                  Integer siteBookings = siteClient.queryByCode(code);
+//        List<Integer> stores = new ArrayList<>();
+//                stores.add(coursePackagePayments);
+//                stores.add(paymentCompetitions);
+//                stores.add(siteBookings);
+//
+//                OperatorUser operatorUser = siteClient.queryOperator(stores);
+//
+//
+////        WxPayService myWxPayService = wxPayService.switchoverTo("mch_id");
+////
+////        ProfitSharingV3Service profitSharingV3Service = myWxPayService.getProfitSharingV3Service();
+//
+//        String nonceStr = RandomUtil.randomString(32);
+//        String appId = "您的appid";
+//
+//
+//        //添加分账方
+//
+////        ProfitSharingReceiver profitSharingReceiver = new ProfitSharingReceiver();
+////        profitSharingReceiver.setAccount("appid对应的openId");
+////        profitSharingReceiver.setAmount(1l);
+////        profitSharingReceiver.setAppid(appId);
+////        profitSharingReceiver.setType("PERSONAL_OPENID");
+////        profitSharingReceiver.setRelationType("PARTNER");
+////        profitSharingV3Service.addProfitSharingReceiver(profitSharingReceiver);
+//
+//        //分账
+//        ProfitSharingRequest profitSharingRequest = new ProfitSharingRequest();
+//        profitSharingRequest.setAppid(appId);
+//        profitSharingRequest.setTransactionId("微信支付订单号");
+//        profitSharingRequest.setOutOrderNo("业务系统唯一编号");
+//        //分账完成后,剩余金额自动解冻并返回给商户账号,默认false
+//        profitSharingRequest.setUnfreezeUnsplit(true);
+//        //待分账金额1元
+//        Long money = 1L;
+//        List<ProfitSharingReceiver> profitSharingReceivers = new ArrayList<>();
+//        ProfitSharingReceiver profitSharingReceiver = new ProfitSharingReceiver();
+//        profitSharingReceiver.setAccount("appid对应的openId,分账用户1");
+//
+//
+//        //分账百分之5
+//        profitSharingReceiver.setAmount(money * 100 / 5);
+//        profitSharingReceiver.setAppid(appId);
+//        profitSharingReceiver.setType("PERSONAL_OPENID");
+//        profitSharingReceiver.setRelationType("PARTNER");
+//        profitSharingReceiver.setDescription("test01");
+//        profitSharingReceivers.add(profitSharingReceiver);
+//
+//        ProfitSharingReceiver receiver = new ProfitSharingReceiver();
+//        receiver.setAccount("appid对应的openId,分账用户2");
+//        //百分之10
+//        receiver.setAmount(money * 100 / 10);
+//        receiver.setAppid(appId);
+//        receiver.setType("PERSONAL_OPENID");
+//        receiver.setRelationType("PARTNER");
+//        receiver.setDescription("test02");
+//        profitSharingReceivers.add(receiver);
+//
+//
+//        profitSharingRequest.setReceivers(profitSharingReceivers);
+//
+//        profitSharingV3Service.profitSharing(profitSharingRequest);
+//
+//
+//
+//
+////                    Map<String,String> headers = new HashMap<>();
+////                    headers.put("Authorization",map.get("sign"));
+////                    headers.put("Accept","application/json");
+////                    headers.put("Wechatpay-Serial",certPath);
+////
+////                    List<Receivers> receivers = new ArrayList<>();
+////
+////                    Map<String,Object> body = new HashMap<>();
+////                    body.put("appid",appid);
+////                    body.put("transaction_id",map.get("transaction_id"));
+////                    body.put("out_order_no",map.get("out_trade_no"));
+////                    body.put("receivers",receivers);
+////                    body.put("unfreeze_unsplit",true);
+//
+//                    //支付分账
+////                    String url ="https://api.mch.weixin.qq.com/v3/profitsharing/orders";
+////                    CloseableHttpResponse closeableHttpResponse = HttpClientUtil.setPostHttpRequset(url, body, headers, "application/json");
+////
+//
+//            return  null;
+//
+//
+//
+//
+//    }
+
+    /**
+     * 微信扫码收款
+     *
+     * @param body         商品描述
+     * @param attach       附加数据
+     * @param nonce_str    随机字符串
+     * @param out_trade_no 商户订单号
+     * @param total_fee    订单金额
+     * @param auth_code    授权码	扫码支付授权码,设备读取用户微信中的条码或者二维码信息(注:用户付款码条形码规则:18位纯数字,以10、11、12、13、14、15开头)
+     * @return
+     */
+    public AjaxResult wxScanQRCodePay(String body, String attach, String nonce_str, String out_trade_no, String total_fee, String auth_code) {
+        int i = new BigDecimal(total_fee).multiply(new BigDecimal("100")).intValue();
+        String hostAddress = null;
+        try {
+            InetAddress address = InetAddress.getLocalHost();
+            hostAddress = address.getHostAddress();
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+        }
+        String randomCode = null;
+        try {
+            randomCode = UUIDUtil.getRandomCode(10);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        Map<String, Object> map = new HashMap<>();
+        map.put("appid", appid);
+        map.put("mch_id", mchId);
+        map.put("nonce_str", nonce_str);//存储的支付人员id,员工扫描二维码支付的时候存储的是收款员工id
+        map.put("body", body);
+        map.put("attach", attach);//存储的费用月份数据,员工扫描二维码支付的时候存储的是收费项id
+        map.put("out_trade_no", randomCode + "_" + out_trade_no);//存储的房间id
+        map.put("total_fee", i);
+        map.put("spbill_create_ip", hostAddress);
+        map.put("auth_code", auth_code);
+        String s = this.weixinSignature(map);
+        map.put("sign", s);
+
+        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_XML);
+        StringBuffer xmlString = new StringBuffer();
+        Set<String> strings = map.keySet();
+        String[] keys = {};
+        keys = strings.toArray(keys);
+        Arrays.sort(keys);
+        xmlString.append("<xml>");
+        for (int l = 0; l < keys.length; l++) {
+            xmlString.append("<" + keys[l] + ">" + map.get(keys[l]) + "</" + keys[l] + ">");
+        }
+        xmlString.append("</xml>");
+
+        Map<String, String> map1 = null;
+        String body1 = null;
+        try {
+            body1 = HttpClientUtil.pushHttpRequsetXml(url, xmlString.toString(), new HashMap<>()).getData();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        //将结果xml解析成map
+        body1 = body1.replaceAll("<!\\[CDATA\\[", "");
+        body1 = body1.replaceAll("]]>", "");
+        try {
+            map1 = this.xmlToMap(body1, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        String return_code = map1.get("return_code");
+        if ("SUCCESS".equals(return_code)) {
+            String result_code = map1.get("result_code");
+            if ("SUCCESS".equals(result_code)) {
+                String type = map1.get("trade_type");
+                switch (type) {
+                    case "JSAPI":
+                        break;
+                    case "NATIVE":
+                        String code_url = map1.get("code_url");
+                        return AjaxResult.success(code_url);
+                    case "APP":
+                        String prepay_id = map1.get("prepay_id");
+                        //重新进行签名后返回给前端
+                        Map<String, Object> map2 = new HashMap<>();
+                        map2.put("appid", appid);
+                        map2.put("noncestr", nonce_str);
+                        map2.put("package", "Sign=WXPay");
+                        map2.put("partnerid", mchId);
+                        map2.put("prepayid", prepay_id);
+                        map2.put("timestamp", new Date().getTime() + "");
+                        String s1 = this.weixinSignature(map2);
+
+                        map2.put("pac", "Sign=WXPay");
+                        map2.put("sign", s1);
+//                      System.err.println(map2);
+                        return AjaxResult.success(map2);
+                }
+                return null;
+            } else {
+//                System.err.println(map1.get("err_code_des"));
+                return AjaxResult.error(map1.get("err_code_des"));
+            }
+        } else {
+//            System.err.println(map1.get("return_msg") + appid + "----" + mchId);
+            return AjaxResult.error(map1.get("return_msg"), new JSONObject());
+        }
+    }
+
+
+    /**
+     * 支付宝扫码收款
+     *
+     * @param data
+     * @return
+     */
+    public Object aliScanQRCodePay(String data) {
+        return null;
+    }
+
+
+    /**
+     * 微信退款申请
+     *
+     * @param transaction_id 微信订单号。微信生成的订单号,在支付通知中有返回
+     * @param out_refund_no  商户退款单号。商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。
+     * @param total_fee      订单金额。订单总金额,单位为分,只能为整数
+     * @param refund_fee     退款金额。退款总金额,订单总金额,单位为分,只能为整数
+     * @param notify_url     退款结果通知url。异步接收微信支付退款结果通知的回调地址,通知URL必须为外网可访问的url,不允许带参数 如果参数中传了notify_url,则商户平台上配置的回调地址将不会生效。
+     * @return
+     */
+    public Map<String, String> wxRefund(String transaction_id, String out_refund_no,
+                                        String total_fee,
+                                        String refund_fee,
+                                        String notify_url) {
+        int tf = new BigDecimal(total_fee).multiply(new BigDecimal("100")).intValue();
+        int rf = new BigDecimal(refund_fee).multiply(new BigDecimal("100")).intValue();
+        String nonce_str = UUIDUtil.getRandomCode();
+        Map<String, Object> map = new HashMap<>();
+        map.put("appid", appid);
+        map.put("mch_id", mchId);
+        map.put("nonce_str", nonce_str);
+        map.put("transaction_id", transaction_id);
+        map.put("out_refund_no", out_refund_no);
+        map.put("total_fee", tf);
+        map.put("refund_fee", rf);
+        map.put("notify_url", callbackPath + notify_url);
+        String s = this.weixinSignature(map, key);
+        map.put("sign", s);
+
+        String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_XML);
+        StringBuffer xmlString = new StringBuffer();
+        Set<String> strings = map.keySet();
+        String[] keys = {};
+        keys = strings.toArray(keys);
+        Arrays.sort(keys);
+        xmlString.append("<xml>");
+        for (int l = 0; l < keys.length; l++) {
+            xmlString.append("<" + keys[l] + ">" + map.get(keys[l]) + "</" + keys[l] + ">");
+        }
+        xmlString.append("</xml>");
+
+        Map<String, String> map1 = null;
+        String body1 = null;
+        try {
+            body1 = HttpClientUtil.pushHttpsRequsetXml(url, xmlString.toString(), new HashMap<>(), mchId, certPath, "PKCS12");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        System.err.println(body1);
+        //将结果xml解析成map
+        body1 = body1.replaceAll("<!\\[CDATA\\[", "");
+        body1 = body1.replaceAll("]]>", "");
+        try {
+            map1 = this.xmlToMap(body1, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        String return_code = map1.get("return_code");
+        Map<String, String> map2 = new HashMap<>();
+        if ("SUCCESS".equals(return_code)) {
+            String result_code = map1.get("result_code");
+            if ("SUCCESS".equals(result_code)) {
+                map2.put("return_code", result_code);
+                map2.put("refund_id", String.valueOf(map1.get("refund_id")));//微信退款订单号
+                map2.put("refund_fee", String.valueOf(map1.get("refund_fee")));//退款金额
+                return map2;
+            } else {
+                map2.put("return_code", result_code);
+                map2.put("return_msg", map1.get("err_code_des"));
+                return map2;
+            }
+        } else {
+            map2.put("return_code", return_code);
+            map2.put("return_msg", map1.get("return_msg"));
+            return map2;
+        }
+    }
+
+
+    /**
+     * 微信退款成功后的回调处理
+     *
+     * @param request
+     * @return
+     */
+    public Map<String, String> wxRefundCallback(HttpServletRequest request) {
+        try {
+            String param = this.getParam(request);
+            param = param.replaceAll("<!\\[CDATA\\[", "");
+            param = param.replaceAll("]]>", "");
+            Map<String, String> map = this.xmlToMap(param, "UTF-8");
+            String return_code = map.get("return_code");
+            if ("SUCCESS".equals(return_code)) {
+                String req_info = map.get("req_info");//加密信息请用商户秘钥进行解密
+                String s = this.wxDecrypt(req_info);
+                s = s.replaceAll("<!\\[CDATA\\[", "");
+                s = s.replaceAll("]]>", "");
+                map = this.xmlToMap(s, "UTF-8");
+                Map<String, String> map1 = new HashMap<>();
+                map1.put("refund_id", map.get("refund_id"));
+                map1.put("out_refund_no", map.get("out_refund_no"));
+                String result = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
+                map1.put("result", result);
+                return map1;
+            } else {
+//                System.err.println(map.get("return_msg"));
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        } catch (InvalidKeyException e) {
+            e.printStackTrace();
+        } catch (NoSuchPaddingException e) {
+            e.printStackTrace();
+        } catch (BadPaddingException e) {
+            e.printStackTrace();
+        } catch (NoSuchProviderException e) {
+            e.printStackTrace();
+        } catch (IllegalBlockSizeException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 支付宝退款
+     *
+     * @param trade_no      支付宝交易号
+     * @param refund_amount 退款金额
+     * @return
+     * @throws AlipayApiException
+     */
+    public Map<String, String> aliRefund(String trade_no, String refund_amount)
+            throws AlipayApiException {
+        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", aliAppid, appPrivateKey, "json", "UTF-8", alipay_public_key, "RSA2");
+        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("trade_no", trade_no);
+        jsonObject.put("refund_amount", refund_amount);
+        request.setBizContent(jsonObject.toJSONString());
+        AlipayTradeRefundResponse response = alipayClient.execute(request);
+        Map<String, String> map = new HashMap<>();
+        if (response.isSuccess()) {
+            System.out.println("调用成功");
+            String outTradeNo = response.getOutTradeNo();
+            map.put("code", response.getCode());//10000
+            map.put("trade_no", response.getTradeNo());//支付宝交易号
+            map.put("out_trade_no", outTradeNo);//商户订单号
+        } else {
+            System.out.println("调用失败");
+            map.put("code", response.getCode());
+            map.put("msg", response.getSubMsg());
+        }
+        return map;
+    }
+
+
+    /**
+     * 查询微信支付订单
+     *
+     * @return
+     * @throws Exception
+     */
+    public AjaxResult<Map<String, String>> queryWXOrder(String out_trade_no, String transaction_id) throws Exception {
+        String url = "https://api.mch.weixin.qq.com/pay/orderquery";
+        String nonce_str = UUIDUtil.getRandomCode(16);
+        Map<String, Object> map = new HashMap<>();
+        map.put("appid", appid);
+        map.put("mch_id", mchId);
+        map.put("out_trade_no", out_trade_no);//商户订单号
+        map.put("transaction_id", transaction_id);//微信订单号
+        map.put("nonce_str", nonce_str);//随机字符串
+        String s = this.weixinSignature(map);
+        map.put("sign", s);
+
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_XML);
+        StringBuffer xmlString = new StringBuffer();
+        Set<String> strings = map.keySet();
+        String[] keys = {};
+        keys = strings.toArray(keys);
+        Arrays.sort(keys);
+        xmlString.append("<xml>");
+        for (int l = 0; l < keys.length; l++) {
+            xmlString.append("<" + keys[l] + ">" + map.get(keys[l]) + "</" + keys[l] + ">");
+        }
+        xmlString.append("</xml>");
+
+        Map<String, String> map1 = null;
+        String body1 = HttpClientUtil.pushHttpRequsetXml(url, xmlString.toString(), new HashMap<>()).getData();
+        //将结果xml解析成map
+        body1 = body1.replaceAll("<!\\[CDATA\\[", "");
+        body1 = body1.replaceAll("]]>", "");
+        try {
+            map1 = this.xmlToMap(body1, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        String return_code = map1.get("return_code");
+        if ("SUCCESS".equals(return_code)) {
+            String result_code = map1.get("result_code");
+            if ("SUCCESS".equals(result_code)) {
+                Map<String, String> map2 = new HashMap<>();
+                map2.put("trade_type", map1.get("trade_type"));
+                map2.put("trade_state", map1.get("trade_state"));//订单状态SUCCESS—支付成功,REFUND—转入退款,NOTPAY—未支付,CLOSED—已关闭,REVOKED—已撤销(刷卡支付),USERPAYING--用户支付中,PAYERROR--支付失败(其他原因,如银行返回失败)
+                map2.put("transaction_id", map1.get("transaction_id"));
+                return AjaxResult.success(map2);
+            } else {
+                System.err.println(map1.get("err_code_des"));
+                return AjaxResult.error(map1.get("err_code_des"));
+            }
+        } else {
+            System.err.println(map1.get("return_msg") + appid + "----" + mchId);
+            return AjaxResult.error(map1.get("return_msg"));
+        }
+    }
+
+
+    /**
+     * 微信转账功能(企业付款到零钱)
+     *
+     * @param openid           商户appid下,某用户的openid
+     * @param desc             企业付款备注,必填。
+     * @param total_fee        企业付款金额
+     * @param partner_trade_no 商户订单号,需保持唯一性
+     * @return
+     */
+    public Map<String, String> wxTransfers(String openid, String desc, String total_fee, String partner_trade_no) throws Exception {
+        int amount = new BigDecimal(total_fee).multiply(new BigDecimal("100")).intValue();
+        String nonce_str = UUIDUtil.getRandomCode();
+        Map<String, Object> map = new HashMap<>();
+        map.put("mch_appid", appid);//申请商户号的appid或商户号绑定的appid
+        map.put("mchid", mchId);//微信支付分配的商户号
+        map.put("nonce_str", nonce_str);//随机字符串,不长于32位
+        map.put("partner_trade_no", partner_trade_no);//商户订单号,需保持唯一性
+        map.put("openid", openid);//商户appid下,某用户的openid
+        map.put("check_name", "NO_CHECK");//NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名
+        map.put("amount", amount);//企业付款金额,单位为分
+        map.put("desc", desc);//企业付款备注,必填。
+        String s = this.weixinSignature(map, key);
+        map.put("sign", s);
+
+        String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_XML);
+        StringBuffer xmlString = new StringBuffer();
+        Set<String> strings = map.keySet();
+        String[] keys = {};
+        keys = strings.toArray(keys);
+        Arrays.sort(keys);
+        xmlString.append("<xml>");
+        for (int l = 0; l < keys.length; l++) {
+            xmlString.append("<" + keys[l] + ">" + map.get(keys[l]) + "</" + keys[l] + ">");
+        }
+        xmlString.append("</xml>");
+
+        Map<String, String> map1 = null;
+        String body1 = HttpClientUtil.pushHttpsRequsetXml(url, xmlString.toString(), new HashMap<>(), mchId, certPath, "PKCS12");
+        //将结果xml解析成map
+        body1 = body1.replaceAll("<!\\[CDATA\\[", "");
+        body1 = body1.replaceAll("]]>", "");
+        try {
+            map1 = this.xmlToMap(body1, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        String return_code = map1.get("return_code");
+        Map<String, String> map2 = new HashMap<>();
+        if ("SUCCESS".equals(return_code)) {
+            String result_code = map1.get("result_code");
+            if ("SUCCESS".equals(result_code)) {
+                map2.put("return_code", result_code);
+                map2.put("payment_no", String.valueOf(map1.get("payment_no")));//付款订单号
+                map2.put("payment_time", String.valueOf(map1.get("payment_time")));//付款时间
+                return map2;
+            } else {
+                map2.put("return_code", result_code);
+                map2.put("err_code", map1.get("err_code"));
+                map2.put("err_code_des", map1.get("err_code_des"));
+                return map2;
+            }
+        } else {
+            map2.put("return_code", return_code);
+            map2.put("return_msg", map1.get("return_msg"));
+            return map2;
+        }
+    }
+
+
+    /**
+     * 微信转账功能(企业付款到银行卡)
+     *
+     * @param desc             备注信息
+     * @param total_fee        转账金额
+     * @param partner_trade_no 订单号
+     * @param enc_bank_no      银行卡号
+     * @param enc_true_name    收款方用户名
+     * @param bankName         银行名称
+     * @return
+     * @throws Exception
+     */
+    public Map<String, String> wxPayBank(String desc, String total_fee, String partner_trade_no, String enc_bank_no, String enc_true_name, String bankName) throws Exception {
+        int amount = new BigDecimal(total_fee).multiply(new BigDecimal("100")).intValue();
+        String nonce_str = UUIDUtil.getRandomCode();
+        Map<String, Object> map = new HashMap<>();
+        map.put("mch_id", mchId);//微信支付分配的商户号
+        map.put("nonce_str", nonce_str);//随机字符串,不长于32位
+        map.put("partner_trade_no", partner_trade_no);//商户订单号,需保持唯一性
+        map.put("enc_bank_no", enc_bank_no);//收款方银行卡号(采用标准RSA算法,公钥由微信侧提供)
+        map.put("enc_true_name", enc_true_name);//收款方用户名(采用标准RSA算法,公钥由微信侧提供)
+        map.put("bank_code", findBankCode(bankName));//
+        map.put("amount", amount);//企业付款金额,单位为分
+        map.put("desc", desc);//企业付款备注,必填。
+        String s = this.weixinSignature(map, key);
+        map.put("sign", s);
+
+        String url = "https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank";
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_XML);
+        StringBuffer xmlString = new StringBuffer();
+        Set<String> strings = map.keySet();
+        String[] keys = {};
+        keys = strings.toArray(keys);
+        Arrays.sort(keys);
+        xmlString.append("<xml>");
+        for (int l = 0; l < keys.length; l++) {
+            xmlString.append("<" + keys[l] + ">" + map.get(keys[l]) + "</" + keys[l] + ">");
+        }
+        xmlString.append("</xml>");
+
+        Map<String, String> map1 = null;
+        String body1 = HttpClientUtil.pushHttpsRequsetXml(url, xmlString.toString(), new HashMap<>(), mchId, certPath, "PKCS12");
+        //将结果xml解析成map
+        body1 = body1.replaceAll("<!\\[CDATA\\[", "");
+        body1 = body1.replaceAll("]]>", "");
+        try {
+            map1 = this.xmlToMap(body1, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (DocumentException e) {
+            e.printStackTrace();
+        }
+        String return_code = map1.get("return_code");
+        Map<String, String> map2 = new HashMap<>();
+        if ("SUCCESS".equals(return_code)) {
+            String result_code = map1.get("result_code");
+            if ("SUCCESS".equals(result_code)) {
+                map2.put("return_code", result_code);
+                map2.put("payment_no", String.valueOf(map1.get("payment_no")));//付款订单号
+                map2.put("cmms_amt", String.valueOf(map1.get("cmms_amt")));//手续费金额 RMB:分
+                return map2;
+            } else {
+                map2.put("return_code", result_code);
+                map2.put("err_code", map1.get("err_code"));
+                map2.put("err_code_des", map1.get("err_code_des"));
+                return map2;
+            }
+        } else {
+            map2.put("return_code", return_code);
+            map2.put("return_msg", map1.get("return_msg"));
+            return map2;
+        }
+    }
+
+    /**
+     * 微信转账到银行卡不编号
+     *
+     * @param bankName
+     * @return
+     */
+    public String findBankCode(String bankName) {
+        String json = "{\"工商银行 \":1002,\"农业银行\":1005,\"建设银行\":1003,\"中国银行\":1026,\"交通银行 \":1020,\"招商银行 \":1001,\"邮储银行\":1066,\"民生银行 \":1006,\"平安银行 \":1010,\"中信银行\":1021,\"浦发银行 \":1004,\"兴业银行 \":1009,\"光大银行 \":1022,\"广发银行\":1027,\"华夏银行\":1025,\"宁波银行\":1056,\"北京银行\":4836,\"上海银行\":1024,\"南京银行\":1054,\"长子县融汇村镇银行\":4755,\"长沙银行\":4216,\"浙江泰隆商业银行\":4051,\"中原银行 \":4753,\"企业银行(中国)\":4761,\"顺德农商银行 \":4036,\"衡水银行\":4752,\"长治银行\":4756,\"大同银行\":4767,\"河南省农村信用社\":4115,\"宁夏黄河农村商业银行\":4150,\"山西省农村信用社\":4156,\"安徽省农村信用社\":4166,\"甘肃省农村信用社\":4157,\"天津农村商业银行\":4153,\"广西壮族自治区农村信用社\":4113,\"陕西省农村信用社\":4108,\"深圳农村商业银行\":4076,\"宁波鄞州农村商业银行\":4052,\"浙江省农村信用社联合社\":4764,\"江苏省农村信用社联合社\":4217,\"江苏紫金农村商业银行股份有限公司 \":4072,\"北京中关村银行股份有限公司 \":4769,\"星展银行( 中国) 有限公司 \":4778,\"枣庄银行股份有限公司 \":4766,\"海口联合农村商业银行股份有限公司 \":4758,\"南洋商业银行( 中国) 有限公司 \":4763}";
+        JSONObject jsonObject = JSON.parseObject(json);
+        Set<String> strings = jsonObject.keySet();
+        for (String key : strings) {
+            if (key.indexOf(bankName) >= 0) {
+                return jsonObject.getString(key);
+            }
+        }
+        return "";
+    }
+
+
+    /**
+     * 支付宝转账
+     *
+     * @param out_biz_no   商家侧唯一订单号,由商家自定义。对于不同转账请求,商家需保证该订单号在自身系统唯一。
+     * @param trans_amount 订单总金额,单位为元,精确到小数点后两位
+     * @param order_title  转账业务的标题,用于在支付宝用户的账单里显示
+     * @param identity     参与方的唯一标识(收款方支付宝账号)
+     * @param name         参与方真实姓名,如果非空,将校验收款支付宝账号姓名一致性。
+     * @param remark       业务备注
+     * @return
+     * @throws Exception
+     */
+    public Map<String, Object> aliTransfer(String out_biz_no, Double trans_amount, String order_title, String identity, String name, String remark) throws Exception {
+        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
+        certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");  //gateway:支付宝网关(固定)https://openapi.alipay.com/gateway.do
+        certAlipayRequest.setAppId(aliAppid);  //APPID 即创建应用后生成,详情见创建应用并获取 APPID
+        certAlipayRequest.setPrivateKey(appPrivateKey);  //开发者应用私钥,由开发者自己生成
+        certAlipayRequest.setFormat("json");  //参数返回格式,只支持 json 格式
+        certAlipayRequest.setCharset("UTF-8");  //请求和签名使用的字符编码格式,支持 GBK和 UTF-8
+        certAlipayRequest.setSignType("RSA2");  //商户生成签名字符串所使用的签名算法类型,目前支持 RSA2 和 RSA,推荐商家使用 RSA2。
+        certAlipayRequest.setCertPath(app_cert_path); //应用公钥证书路径(app_cert_path 文件绝对路径)
+        certAlipayRequest.setAlipayPublicCertPath(alipay_cert_path); //支付宝公钥证书文件路径(alipay_cert_path 文件绝对路径)
+        certAlipayRequest.setRootCertPath(alipay_root_cert_path);  //支付宝CA根证书文件路径(alipay_root_cert_path 文件绝对路径)
+        AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
+        AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
+        request.setBizContent("{" +
+                "\"out_biz_no\":\"" + out_biz_no + "\"," +
+                "\"trans_amount\":" + trans_amount + "," +
+                "\"product_code\":\"TRANS_ACCOUNT_NO_PWD\"," +
+                "\"biz_scene\":\"DIRECT_TRANSFER\"," +
+                "\"order_title\":\"" + order_title + "\"," +
+                "\"payee_info\":{" +
+                "\"identity\":\"" + identity + "\"," +
+                "\"identity_type\":\"ALIPAY_USER_ID\"," +
+                "\"name\":\"" + name + "\"," +
+                "}," +
+                "\"remark\":\"" + remark + "\"" +
+                "}");
+        AlipayFundTransUniTransferResponse response = alipayClient.certificateExecute(request);
+        Map<String, Object> map = new HashMap<>();
+        if (response.isSuccess()) {
+            String status = response.getStatus();
+            if (status.equals("SUCCESS")) {//成功
+                map.put("code", response.getCode());
+                map.put("order_id", response.getOrderId());//支付宝订单号
+                map.put("pay_fund_order_id", response.getPayFundOrderId());//支付宝流水号
+            } else {
+                map.put("code", response.getCode());
+                map.put("sub_msg", response.getSubMsg());
+            }
+        } else {
+            map.put("code", response.getSubCode());
+            map.put("sub_msg", response.getSubMsg());
+        }
+        return map;
+    }
+
+
+    /**
+     * 获取请求内容
+     *
+     * @param request
+     * @return
+     * @throws IOException
+     */
+    private String getParam(HttpServletRequest request) throws IOException {
+        // 读取参数
+        InputStream inputStream;
+        StringBuilder sb = new StringBuilder();
+        inputStream = request.getInputStream();
+        String s;
+        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+        while ((s = in.readLine()) != null) {
+            sb.append(s);
+        }
+        in.close();
+        inputStream.close();
+        return sb.toString();
+    }
+
+
+    /**
+     * 微信下单的签名算法
+     *
+     * @param map
+     * @return
+     */
+    private String weixinSignature(Map<String, Object> map) {
+        try {
+            Set<Map.Entry<String, Object>> entries = map.entrySet();
+            List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(entries);
+            // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
+            Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
+                public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
+                    return (o1.getKey()).toString().compareTo(o2.getKey());
+                }
+            });
+            // 构造签名键值对的格式
+            StringBuilder sb = new StringBuilder();
+            for (Map.Entry<String, Object> item : infoIds) {
+                if (item.getKey() != null || item.getKey() != "") {
+                    String key = item.getKey();
+                    Object val = item.getValue();
+                    if (!(val == "" || val == null)) {
+                        sb.append(key + "=" + val + "&");
+                    }
+                }
+            }
+            sb.append("key=" + key);
+            String sign = MD5AndKL.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); //注:MD5签名方式
+            return sign;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 微信下单的签名算法
+     *
+     * @param map
+     * @return
+     */
+    private String weixinSignature(Map<String, Object> map, String key_) {
+        try {
+            Set<Map.Entry<String, Object>> entries = map.entrySet();
+            List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(entries);
+            // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
+            Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
+                public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
+                    return (o1.getKey()).toString().compareTo(o2.getKey());
+                }
+            });
+            // 构造签名键值对的格式
+            StringBuilder sb = new StringBuilder();
+            for (Map.Entry<String, Object> item : infoIds) {
+                if (item.getKey() != null || item.getKey() != "") {
+                    String key = item.getKey();
+                    Object val = item.getValue();
+                    if (!(val == "" || val == null)) {
+                        sb.append(key + "=" + val + "&");
+                    }
+                }
+            }
+            sb.append("key=" + key_);
+            String sign = MD5AndKL.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); //注:MD5签名方式
+            return sign;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 微信退款成功后的解密
+     *
+     * @param req_info
+     * @return
+     */
+    private String wxDecrypt(String req_info) throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException,
+            InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
+        byte[] decode = Base64.getDecoder().decode(req_info);
+        String sign = MD5AndKL.MD5Encode(key, "UTF-8").toLowerCase();
+        if (Security.getProvider("BC") == null) {
+            Security.addProvider(new BouncyCastleProvider());
+        }
+        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
+        SecretKeySpec secretKeySpec = new SecretKeySpec(sign.getBytes(), "AES");
+        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
+        return new String(cipher.doFinal(decode));
+    }
+
+
+//    public static void main(String[] ages){
+//        PayMoneyUtil payMoneyUtil = new PayMoneyUtil();
+//        ResultUtil ce = payMoneyUtil.alipay("测试", "测试", "", "121456457", "10", "http://123.com");
+//        System.err.println(ce);
+//        ResultUtil resultUtil = null;
+//        try {
+//            resultUtil = payMoneyUtil.queryALIOrder("121456457");
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
+//        System.err.println(resultUtil);
+//    }
+
+
+    /**
+     * xml转map
+     *
+     * @param xml
+     * @param charset
+     * @return
+     * @throws UnsupportedEncodingException
+     * @throws DocumentException
+     */
+    public static Map<String, String> xmlToMap(String xml, String charset) throws UnsupportedEncodingException, DocumentException {
+
+        Map<String, String> respMap = new HashMap<String, String>();
+
+        SAXReader reader = new SAXReader();
+        Document doc = reader.read(new ByteArrayInputStream(xml.getBytes(charset)));
+        Element root = doc.getRootElement();
+        xmlToMap(root, respMap);
+        return respMap;
+    }
+
+    public static Map<String, String> xmlToMap(Element tmpElement, Map<String, String> respMap) {
+        if (tmpElement.isTextOnly()) {
+            respMap.put(tmpElement.getName(), tmpElement.getText());
+            return respMap;
+        }
+
+        @SuppressWarnings("unchecked")
+        Iterator<Element> eItor = tmpElement.elementIterator();
+        while (eItor.hasNext()) {
+            Element element = eItor.next();
+            xmlToMap(element, respMap);
+        }
+        return respMap;
+    }
+}
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/StrKit.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/StrKit.java
new file mode 100644
index 0000000..4f68aae
--- /dev/null
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/StrKit.java
@@ -0,0 +1,1370 @@
+package com.ruoyi.study.utils;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * 字符串工具类
+ * 
+ * @author xiaoleilu
+ *
+ */
+public class StrKit {
+
+	public static final String SPACE = " ";
+	public static final String DOT = ".";
+	public static final String SLASH = "/";
+	public static final String BACKSLASH = "\\";
+	public static final String EMPTY = "";
+	public static final String CRLF = "\r\n";
+	public static final String NEWLINE = "\n";
+	public static final String UNDERLINE = "_";
+	public static final String COMMA = ",";
+
+	public static final String HTML_NBSP = "&nbsp;";
+	public static final String HTML_AMP = "&amp";
+	public static final String HTML_QUOTE = "&quot;";
+	public static final String HTML_LT = "&lt;";
+	public static final String HTML_GT = "&gt;";
+
+	public static final String EMPTY_JSON = "{}";
+
+
+	/**
+	 * 首字母变小写
+	 */
+	public static String firstCharToLowerCase(String str) {
+		char firstChar = str.charAt(0);
+		if (firstChar >= 'A' && firstChar <= 'Z') {
+			char[] arr = str.toCharArray();
+			arr[0] += ('a' - 'A');
+			return new String(arr);
+		}
+		return str;
+	}
+	
+	/**
+	 * 首字母变大写
+	 */
+	public static String firstCharToUpperCase(String str) {
+		char firstChar = str.charAt(0);
+		if (firstChar >= 'a' && firstChar <= 'z') {
+			char[] arr = str.toCharArray();
+			arr[0] -= ('a' - 'A');
+			return new String(arr);
+		}
+		return str;
+	}
+
+	// ------------------------------------------------------------------------ Blank
+	/**
+	 * 字符串是否为空白 空白的定义如下: <br>
+	 * 1、为null <br>
+	 * 2、为不可见字符(如空格)<br>
+	 * 3、""<br>
+	 * 
+	 * @param str 被检测的字符串
+	 * @return 是否为空
+	 */
+	public static boolean isBlank(String str) {
+		int length;
+		if ((str == null) || ((length = str.length()) == 0)) {
+			return true;
+		}
+		for (int i = 0; i < length; i++) {
+			// 只要有一个非空字符即为非空字符串
+			if (false == Character.isWhitespace(str.charAt(i))) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * 字符串是否为非空白 空白的定义如下: <br>
+	 * 1、不为null <br>
+	 * 2、不为不可见字符(如空格)<br>
+	 * 3、不为""<br>
+	 * 
+	 * @param str 被检测的字符串
+	 * @return 是否为非空
+	 */
+	public static boolean notBlank(String str) {
+		return false == isBlank(str);
+	}
+
+	/**
+	 * 是否包含空字符串
+	 * 
+	 * @param strs 字符串列表
+	 * @return 是否包含空字符串
+	 */
+	public static boolean hasBlank(String... strs) {
+		if (CollectionKit.isEmpty(strs)) {
+			return true;
+		}
+		for (String str : strs) {
+			if (isBlank(str)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * 给定所有字符串是否为空白
+	 * 
+	 * @param strs 字符串
+	 * @return 所有字符串是否为空白
+	 */
+	public static boolean isAllBlank(String... strs) {
+		if (CollectionKit.isEmpty(strs)) {
+			return true;
+		}
+		for (String str : strs) {
+			if (notBlank(str)) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	// ------------------------------------------------------------------------ Empty
+	/**
+	 * 字符串是否为空,空的定义如下 1、为null <br>
+	 * 2、为""<br>
+	 * 
+	 * @param str 被检测的字符串
+	 * @return 是否为空
+	 */
+	public static boolean isEmpty(String str) {
+		return str == null || str.length() == 0;
+	}
+
+	/**
+	 * 字符串是否为非空白 空白的定义如下: <br>
+	 * 1、不为null <br>
+	 * 2、不为""<br>
+	 * 
+	 * @param str 被检测的字符串
+	 * @return 是否为非空
+	 */
+	public static boolean isNotEmpty(String str) {
+		return false == isEmpty(str);
+	}
+
+	/**
+	 * 当给定字符串为null时,转换为Empty
+	 * 
+	 * @param str 被转换的字符串
+	 * @return 转换后的字符串
+	 */
+	public static String nullToEmpty(String str) {
+		return nullToDefault(str, EMPTY);
+	}
+
+	/**
+	 * 如果字符串是<code>null</code>,则返回指定默认字符串,否则返回字符串本身。
+	 * 
+	 * <pre>
+	 * nullToDefault(null, &quot;default&quot;)  = &quot;default&quot;
+	 * nullToDefault(&quot;&quot;, &quot;default&quot;)    = &quot;&quot;
+	 * nullToDefault(&quot;  &quot;, &quot;default&quot;)  = &quot;  &quot;
+	 * nullToDefault(&quot;bat&quot;, &quot;default&quot;) = &quot;bat&quot;
+	 * </pre>
+	 * 
+	 * @param str 要转换的字符串
+	 * @param defaultStr 默认字符串
+	 * 
+	 * @return 字符串本身或指定的默认字符串
+	 */
+	public static String nullToDefault(String str, String defaultStr) {
+		return (str == null) ? defaultStr : str;
+	}
+
+	/**
+	 * 当给定字符串为空字符串时,转换为<code>null</code>
+	 * 
+	 * @param str 被转换的字符串
+	 * @return 转换后的字符串
+	 */
+	public static String emptyToNull(String str) {
+		return isEmpty(str) ? null : str;
+	}
+
+	/**
+	 * 是否包含空字符串
+	 * 
+	 * @param strs 字符串列表
+	 * @return 是否包含空字符串
+	 */
+	public static boolean hasEmpty(String... strs) {
+		if (CollectionKit.isEmpty(strs)) {
+			return true;
+		}
+
+		for (String str : strs) {
+			if (isEmpty(str)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * 是否全部为空字符串
+	 * 
+	 * @param strs 字符串列表
+	 * @return 是否全部为空字符串
+	 */
+	public static boolean isAllEmpty(String... strs) {
+		if (CollectionKit.isEmpty(strs)) {
+			return true;
+		}
+
+		for (String str : strs) {
+			if (isNotEmpty(str)) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	// ------------------------------------------------------------------------ Trim
+	/**
+	 * 除去字符串头尾部的空白,如果字符串是<code>null</code>,依然返回<code>null</code>。
+	 * 
+	 * <p>
+	 * 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。
+	 * 
+	 * <pre>
+	 * trim(null)          = null
+	 * trim(&quot;&quot;)            = &quot;&quot;
+	 * trim(&quot;     &quot;)       = &quot;&quot;
+	 * trim(&quot;abc&quot;)         = &quot;abc&quot;
+	 * trim(&quot;    abc    &quot;) = &quot;abc&quot;
+	 * </pre>
+	 * 
+	 * </p>
+	 * 
+	 * @param str 要处理的字符串
+	 * 
+	 * @return 除去空白的字符串,如果原字串为<code>null</code>,则返回<code>null</code>
+	 */
+	public static String trim(String str) {
+		return (null == str) ? null : trim(str, 0);
+	}
+
+	/**
+	 * 给定字符串数组全部做去首尾空格
+	 * 
+	 * @param strs 字符串数组
+	 */
+	public static void trim(String[] strs) {
+		if (null == strs) {
+			return;
+		}
+		String str;
+		for (int i = 0; i < strs.length; i++) {
+			str = strs[i];
+			if (null != str) {
+				strs[i] = str.trim();
+			}
+		}
+	}
+
+	/**
+	 * 除去字符串头部的空白,如果字符串是<code>null</code>,则返回<code>null</code>。
+	 * 
+	 * <p>
+	 * 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。
+	 * 
+	 * <pre>
+	 * trimStart(null)         = null
+	 * trimStart(&quot;&quot;)           = &quot;&quot;
+	 * trimStart(&quot;abc&quot;)        = &quot;abc&quot;
+	 * trimStart(&quot;  abc&quot;)      = &quot;abc&quot;
+	 * trimStart(&quot;abc  &quot;)      = &quot;abc  &quot;
+	 * trimStart(&quot; abc &quot;)      = &quot;abc &quot;
+	 * </pre>
+	 * 
+	 * </p>
+	 * 
+	 * @param str 要处理的字符串
+	 * 
+	 * @return 除去空白的字符串,如果原字串为<code>null</code>或结果字符串为<code>""</code>,则返回 <code>null</code>
+	 */
+	public static String trimStart(String str) {
+		return trim(str, -1);
+	}
+
+	/**
+	 * 除去字符串尾部的空白,如果字符串是<code>null</code>,则返回<code>null</code>。
+	 * 
+	 * <p>
+	 * 注意,和<code>String.trim</code>不同,此方法使用<code>Character.isWhitespace</code> 来判定空白, 因而可以除去英文字符集之外的其它空白,如中文空格。
+	 * 
+	 * <pre>
+	 * trimEnd(null)       = null
+	 * trimEnd(&quot;&quot;)         = &quot;&quot;
+	 * trimEnd(&quot;abc&quot;)      = &quot;abc&quot;
+	 * trimEnd(&quot;  abc&quot;)    = &quot;  abc&quot;
+	 * trimEnd(&quot;abc  &quot;)    = &quot;abc&quot;
+	 * trimEnd(&quot; abc &quot;)    = &quot; abc&quot;
+	 * </pre>
+	 * 
+	 * </p>
+	 * 
+	 * @param str 要处理的字符串
+	 * 
+	 * @return 除去空白的字符串,如果原字串为<code>null</code>或结果字符串为<code>""</code>,则返回 <code>null</code>
+	 */
+	public static String trimEnd(String str) {
+		return trim(str, 1);
+	}
+
+	/**
+	 * 除去字符串头尾部的空白符,如果字符串是<code>null</code>,依然返回<code>null</code>。
+	 * 
+	 * @param str 要处理的字符串
+	 * @param mode <code>-1</code>表示trimStart,<code>0</code>表示trim全部, <code>1</code>表示trimEnd
+	 * 
+	 * @return 除去指定字符后的的字符串,如果原字串为<code>null</code>,则返回<code>null</code>
+	 */
+	public static String trim(String str, int mode) {
+		if (str == null) {
+			return null;
+		}
+
+		int length = str.length();
+		int start = 0;
+		int end = length;
+
+		// 扫描字符串头部
+		if (mode <= 0) {
+			while ((start < end) && (Character.isWhitespace(str.charAt(start)))) {
+				start++;
+			}
+		}
+
+		// 扫描字符串尾部
+		if (mode >= 0) {
+			while ((start < end) && (Character.isWhitespace(str.charAt(end - 1)))) {
+				end--;
+			}
+		}
+
+		if ((start > 0) || (end < length)) {
+			return str.substring(start, end);
+		}
+
+		return str;
+	}
+	
+	/**
+	 * 是否以指定字符串开头
+	 * @param str 被监测字符串
+	 * @param prefix 开头字符串
+	 * @param isIgnoreCase 是否忽略大小写
+	 * @return 是否以指定字符串开头
+	 */
+	public static boolean startWith(String str, String prefix, boolean isIgnoreCase){
+		if(isIgnoreCase){
+			return str.toLowerCase().startsWith(prefix.toLowerCase());
+		}else{
+			return str.startsWith(prefix);
+		}
+	}
+	
+	/**
+	 * 是否以指定字符串结尾
+	 * @param str 被监测字符串
+	 * @param suffix 结尾字符串
+	 * @param isIgnoreCase 是否忽略大小写
+	 * @return 是否以指定字符串结尾
+	 */
+	public static boolean endWith(String str, String suffix, boolean isIgnoreCase){
+		if(isIgnoreCase){
+			return str.toLowerCase().endsWith(suffix.toLowerCase());
+		}else{
+			return str.endsWith(suffix);
+		}
+	}
+	
+	/**
+	 * 是否包含特定字符,忽略大小写,如果给定两个参数都为<code>null</code>,返回true
+	 * @param str 被检测字符串
+	 * @param testStr 被测试是否包含的字符串
+	 * @return 是否包含
+	 */
+	public static boolean containsIgnoreCase(String str, String testStr){
+		if(null == str){
+			//如果被监测字符串和 
+			return null == testStr;
+		}
+		return str.toLowerCase().contains(testStr.toLowerCase());
+	}
+
+	/**
+	 * 获得set或get方法对应的标准属性名<br/>
+	 * 例如:setName 返回 name
+	 * 
+	 * @param getOrSetMethodName
+	 * @return 如果是set或get方法名,返回field, 否则null
+	 */
+	public static String getGeneralField(String getOrSetMethodName) {
+		if (getOrSetMethodName.startsWith("get") || getOrSetMethodName.startsWith("set")) {
+			return cutPreAndLowerFirst(getOrSetMethodName, 3);
+		}
+		return null;
+	}
+
+	/**
+	 * 生成set方法名<br/>
+	 * 例如:name 返回 setName
+	 * 
+	 * @param fieldName 属性名
+	 * @return setXxx
+	 */
+	public static String genSetter(String fieldName) {
+		return upperFirstAndAddPre(fieldName, "set");
+	}
+
+	/**
+	 * 生成get方法名
+	 * 
+	 * @param fieldName 属性名
+	 * @return getXxx
+	 */
+	public static String genGetter(String fieldName) {
+		return upperFirstAndAddPre(fieldName, "get");
+	}
+
+	/**
+	 * 去掉首部指定长度的字符串并将剩余字符串首字母小写<br/>
+	 * 例如:str=setName, preLength=3 -> return name
+	 * 
+	 * @param str 被处理的字符串
+	 * @param preLength 去掉的长度
+	 * @return 处理后的字符串,不符合规范返回null
+	 */
+	public static String cutPreAndLowerFirst(String str, int preLength) {
+		if (str == null) {
+			return null;
+		}
+		if (str.length() > preLength) {
+			char first = Character.toLowerCase(str.charAt(preLength));
+			if (str.length() > preLength + 1) {
+				return first + str.substring(preLength + 1);
+			}
+			return String.valueOf(first);
+		}
+		return null;
+	}
+
+	/**
+	 * 原字符串首字母大写并在其首部添加指定字符串 例如:str=name, preString=get -> return getName
+	 * 
+	 * @param str 被处理的字符串
+	 * @param preString 添加的首部
+	 * @return 处理后的字符串
+	 */
+	public static String upperFirstAndAddPre(String str, String preString) {
+		if (str == null || preString == null) {
+			return null;
+		}
+		return preString + upperFirst(str);
+	}
+
+	/**
+	 * 大写首字母<br>
+	 * 例如:str = name, return Name
+	 * 
+	 * @param str 字符串
+	 * @return 字符串
+	 */
+	public static String upperFirst(String str) {
+		return Character.toUpperCase(str.charAt(0)) + str.substring(1);
+	}
+
+	/**
+	 * 小写首字母<br>
+	 * 例如:str = Name, return name
+	 * 
+	 * @param str 字符串
+	 * @return 字符串
+	 */
+	public static String lowerFirst(String str) {
+		if(isBlank(str)){
+			return str;
+		}
+		return Character.toLowerCase(str.charAt(0)) + str.substring(1);
+	}
+
+	/**
+	 * 去掉指定前缀
+	 * 
+	 * @param str 字符串
+	 * @param prefix 前缀
+	 * @return 切掉后的字符串,若前缀不是 preffix, 返回原字符串
+	 */
+	public static String removePrefix(String str, String prefix) {
+		if(isEmpty(str) || isEmpty(prefix)){
+			return str;
+		}
+		
+		if (str.startsWith(prefix)) {
+			return str.substring(prefix.length());
+		}
+		return str;
+	}
+
+	/**
+	 * 忽略大小写去掉指定前缀
+	 * 
+	 * @param str 字符串
+	 * @param prefix 前缀
+	 * @return 切掉后的字符串,若前缀不是 prefix, 返回原字符串
+	 */
+	public static String removePrefixIgnoreCase(String str, String prefix) {
+		if(isEmpty(str) || isEmpty(prefix)){
+			return str;
+		}
+		
+		if (str.toLowerCase().startsWith(prefix.toLowerCase())) {
+			return str.substring(prefix.length());
+		}
+		return str;
+	}
+
+	/**
+	 * 去掉指定后缀
+	 * 
+	 * @param str 字符串
+	 * @param suffix 后缀
+	 * @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串
+	 */
+	public static String removeSuffix(String str, String suffix) {
+		if(isEmpty(str) || isEmpty(suffix)){
+			return str;
+		}
+		
+		if (str.endsWith(suffix)) {
+			return str.substring(0, str.length() - suffix.length());
+		}
+		return str;
+	}
+	
+	/**
+	 * 获得字符串对应byte数组
+	 * @param str 字符串
+	 * @param charset 编码,如果为<code>null</code>使用系统默认编码
+	 * @return bytes
+	 */
+	public static byte[] getBytes(String str, Charset charset){
+		if(null == str){
+			return null;
+		}
+		return null == charset ? str.getBytes() : str.getBytes(charset);
+	}
+
+	/**
+	 * 忽略大小写去掉指定后缀
+	 * 
+	 * @param str 字符串
+	 * @param suffix 后缀
+	 * @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串
+	 */
+	public static String removeSuffixIgnoreCase(String str, String suffix) {
+		if(isEmpty(str) || isEmpty(suffix)){
+			return str;
+		}
+		
+		if (str.toLowerCase().endsWith(suffix.toLowerCase())) {
+			return str.substring(0, str.length() - suffix.length());
+		}
+		return str;
+	}
+	
+	/**
+	 * 如果给定字符串不是以prefix开头的,在开头补充 prefix
+	 * @param str 字符串
+	 * @param prefix 前缀
+	 * @return 补充后的字符串
+	 */
+	public static String addPrefixIfNot(String str, String prefix){
+		if(isEmpty(str) || isEmpty(prefix)){
+			return str;
+		}
+		if(false == str.startsWith(prefix)){
+			str = prefix + str;
+		}
+		return str;
+	}
+	
+	/**
+	 * 如果给定字符串不是以suffix结尾的,在尾部补充 suffix
+	 * @param str 字符串
+	 * @param suffix 后缀
+	 * @return 补充后的字符串
+	 */
+	public static String addSuffixIfNot(String str, String suffix){
+		if(isEmpty(str) || isEmpty(suffix)){
+			return str;
+		}
+		if(false == str.endsWith(suffix)){
+			str += suffix;
+		}
+		return str;
+	}
+
+	/**
+	 * 清理空白字符
+	 * 
+	 * @param str 被清理的字符串
+	 * @return 清理后的字符串
+	 */
+	public static String cleanBlank(String str) {
+		if (str == null) {
+			return null;
+		}
+
+		return str.replaceAll("\\s*", EMPTY);
+	}
+
+	/**
+	 * 切分字符串<br>
+	 * a#b#c -> [a,b,c] <br>
+	 * a##b#c -> [a,"",b,c]
+	 * 
+	 * @param str 被切分的字符串
+	 * @param separator 分隔符字符
+	 * @return 切分后的集合
+	 */
+	public static List<String> split(String str, char separator) {
+		return split(str, separator, 0);
+	}
+
+	/**
+	 * 切分字符串
+	 * 
+	 * @param str 被切分的字符串
+	 * @param separator 分隔符字符
+	 * @param limit 限制分片数
+	 * @return 切分后的集合
+	 */
+	public static List<String> split(String str, char separator, int limit) {
+		if (str == null) {
+			return null;
+		}
+		List<String> list = new ArrayList<String>(limit == 0 ? 16 : limit);
+		if (limit == 1) {
+			list.add(str);
+			return list;
+		}
+
+		boolean isNotEnd = true; // 未结束切分的标志
+		int strLen = str.length();
+		StringBuilder sb = new StringBuilder(strLen);
+		for (int i = 0; i < strLen; i++) {
+			char c = str.charAt(i);
+			if (isNotEnd && c == separator) {
+				list.add(sb.toString());
+				// 清空StringBuilder
+				sb.delete(0, sb.length());
+
+				// 当达到切分上限-1的量时,将所剩字符全部作为最后一个串
+				if (limit != 0 && list.size() == limit - 1) {
+					isNotEnd = false;
+				}
+			} else {
+				sb.append(c);
+			}
+		}
+		list.add(sb.toString());// 加入尾串
+		return list;
+	}
+
+	/**
+	 * 切分字符串<br>
+	 * from jodd
+	 * 
+	 * @param str 被切分的字符串
+	 * @param delimiter 分隔符
+	 * @return 字符串
+	 */
+	public static String[] split(String str, String delimiter) {
+		if (str == null) {
+			return null;
+		}
+		if (str.trim().length() == 0) {
+			return new String[] { str };
+		}
+
+		int dellen = delimiter.length(); // del length
+		int maxparts = (str.length() / dellen) + 2; // one more for the last
+		int[] positions = new int[maxparts];
+
+		int i, j = 0;
+		int count = 0;
+		positions[0] = -dellen;
+		while ((i = str.indexOf(delimiter, j)) != -1) {
+			count++;
+			positions[count] = i;
+			j = i + dellen;
+		}
+		count++;
+		positions[count] = str.length();
+
+		String[] result = new String[count];
+
+		for (i = 0; i < count; i++) {
+			result[i] = str.substring(positions[i] + dellen, positions[i + 1]);
+		}
+		return result;
+	}
+
+	/**
+	 * 改进JDK subString<br>
+	 * index从0开始计算,最后一个字符为-1<br>
+	 * 如果from和to位置一样,返回 "" <br>
+	 * 如果from或to为负数,则按照length从后向前数位置,如果绝对值大于字符串长度,则from归到0,to归到length<br>
+	 * 如果经过修正的index中from大于to,则互换from和to
+	 * example: <br>
+	 * 	abcdefgh 2 3 -> c <br>
+	 * 	abcdefgh 2 -3 -> cde <br>
+	 * 
+	 * @param string String
+	 * @param fromIndex 开始的index(包括)
+	 * @param toIndex 结束的index(不包括)
+	 * @return 字串
+	 */
+	public static String sub(String string, int fromIndex, int toIndex) {
+		int len = string.length();
+		if (fromIndex < 0) {
+			fromIndex = len + fromIndex;
+			if(fromIndex < 0 ) { 
+				fromIndex = 0;
+			}
+		} else if(fromIndex >= len) {
+			fromIndex = len -1;
+		}
+		if (toIndex < 0) {
+			toIndex = len + toIndex;
+			if(toIndex < 0) {
+				toIndex = len;
+			}
+		} else if(toIndex > len) {
+			toIndex = len;
+		}
+		if (toIndex < fromIndex) {
+			int tmp = fromIndex;
+			fromIndex = toIndex;
+			toIndex = tmp;
+		}
+		if (fromIndex == toIndex) {
+			return EMPTY;
+		}
+		char[] strArray = string.toCharArray();
+		char[] newStrArray = Arrays.copyOfRange(strArray, fromIndex, toIndex);
+		return new String(newStrArray);
+	}
+
+	/**
+	 * 切割前部分
+	 * 
+	 * @param string 字符串
+	 * @param toIndex 切割到的位置(不包括)
+	 * @return 切割后的字符串
+	 */
+	public static String subPre(String string, int toIndex) {
+		return sub(string, 0, toIndex);
+	}
+
+	/**
+	 * 切割后部分
+	 * 
+	 * @param string 字符串
+	 * @param fromIndex 切割开始的位置(包括)
+	 * @return 切割后的字符串
+	 */
+	public static String subSuf(String string, int fromIndex) {
+		if (isEmpty(string)) {
+			return null;
+		}
+		return sub(string, fromIndex, string.length());
+	}
+
+	/**
+	 * 给定字符串是否被字符包围
+	 * 
+	 * @param str 字符串
+	 * @param prefix 前缀
+	 * @param suffix 后缀
+	 * @return 是否包围,空串不包围
+	 */
+	public static boolean isSurround(String str, String prefix, String suffix) {
+		if (StrKit.isBlank(str)) {
+			return false;
+		}
+		if (str.length() < (prefix.length() + suffix.length())) {
+			return false;
+		}
+
+		return str.startsWith(prefix) && str.endsWith(suffix);
+	}
+
+	/**
+	 * 给定字符串是否被字符包围
+	 * 
+	 * @param str 字符串
+	 * @param prefix 前缀
+	 * @param suffix 后缀
+	 * @return 是否包围,空串不包围
+	 */
+	public static boolean isSurround(String str, char prefix, char suffix) {
+		if (StrKit.isBlank(str)) {
+			return false;
+		}
+		if (str.length() < 2) {
+			return false;
+		}
+
+		return str.charAt(0) == prefix && str.charAt(str.length() - 1) == suffix;
+	}
+
+	/**
+	 * 重复某个字符
+	 * 
+	 * @param c 被重复的字符
+	 * @param count 重复的数目
+	 * @return 重复字符字符串
+	 */
+	public static String repeat(char c, int count) {
+		char[] result = new char[count];
+		for (int i = 0; i < count; i++) {
+			result[i] = c;
+		}
+		return new String(result);
+	}
+
+	/**
+	 * 重复某个字符串
+	 * 
+	 * @param str 被重复的字符
+	 * @param count 重复的数目
+	 * @return 重复字符字符串
+	 */
+	public static String repeat(String str, int count) {
+
+		// 检查
+		final int len = str.length();
+		final long longSize = (long) len * (long) count;
+		final int size = (int) longSize;
+		if (size != longSize) {
+			throw new ArrayIndexOutOfBoundsException("Required String length is too large: " + longSize);
+		}
+
+		final char[] array = new char[size];
+		str.getChars(0, len, array, 0);
+		int n;
+		for (n = len; n < size - n; n <<= 1) {// n <<= 1相当于n *2
+			System.arraycopy(array, 0, array, n, n);
+		}
+		System.arraycopy(array, 0, array, n, size - n);
+		return new String(array);
+	}
+
+	/**
+	 * 比较两个字符串(大小写敏感)。
+	 * 
+	 * <pre>
+	 * equals(null, null)   = true
+	 * equals(null, &quot;abc&quot;)  = false
+	 * equals(&quot;abc&quot;, null)  = false
+	 * equals(&quot;abc&quot;, &quot;abc&quot;) = true
+	 * equals(&quot;abc&quot;, &quot;ABC&quot;) = false
+	 * </pre>
+	 * 
+	 * @param str1 要比较的字符串1
+	 * @param str2 要比较的字符串2
+	 * 
+	 * @return 如果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code>
+	 */
+	public static boolean equals(String str1, String str2) {
+		if (str1 == null) {
+			return str2 == null;
+		}
+
+		return str1.equals(str2);
+	}
+
+	/**
+	 * 比较两个字符串(大小写不敏感)。
+	 * 
+	 * <pre>
+	 * equalsIgnoreCase(null, null)   = true
+	 * equalsIgnoreCase(null, &quot;abc&quot;)  = false
+	 * equalsIgnoreCase(&quot;abc&quot;, null)  = false
+	 * equalsIgnoreCase(&quot;abc&quot;, &quot;abc&quot;) = true
+	 * equalsIgnoreCase(&quot;abc&quot;, &quot;ABC&quot;) = true
+	 * </pre>
+	 * 
+	 * @param str1 要比较的字符串1
+	 * @param str2 要比较的字符串2
+	 * 
+	 * @return 如果两个字符串相同,或者都是<code>null</code>,则返回<code>true</code>
+	 */
+	public static boolean equalsIgnoreCase(String str1, String str2) {
+		if (str1 == null) {
+			return str2 == null;
+		}
+
+		return str1.equalsIgnoreCase(str2);
+	}
+
+	/**
+	 * 格式化文本, {} 表示占位符<br>
+	 * 例如:format("aaa {} ccc", "bbb")   ---->    aaa bbb ccc
+	 * 
+	 * @param template 文本模板,被替换的部分用 {} 表示
+	 * @param values 参数值
+	 * @return 格式化后的文本
+	 */
+	public static String format(String template, Object... values) {
+		if (CollectionKit.isEmpty(values) || isBlank(template)) {
+			return template;
+		}
+
+		final StringBuilder sb = new StringBuilder();
+		final int length = template.length();
+
+		int valueIndex = 0;
+		char currentChar;
+		for (int i = 0; i < length; i++) {
+			if (valueIndex >= values.length) {
+				sb.append(sub(template, i, length));
+				break;
+			}
+
+			currentChar = template.charAt(i);
+			if (currentChar == '{') {
+				final char nextChar = template.charAt(++i);
+				if (nextChar == '}') {
+					sb.append(values[valueIndex++]);
+				} else {
+					sb.append('{').append(nextChar);
+				}
+			} else {
+				sb.append(currentChar);
+			}
+
+		}
+
+		return sb.toString();
+	}
+
+	/**
+	 * 格式化文本,使用 {varName} 占位<br>
+	 * map = {a: "aValue", b: "bValue"}
+	 * format("{a} and {b}", map)    ---->    aValue and bValue
+	 * 
+	 * @param template 文本模板,被替换的部分用 {key} 表示
+	 * @param map 参数值对
+	 * @return 格式化后的文本
+	 */
+	public static String format(String template, Map<?, ?> map) {
+		if (null == map || map.isEmpty()) {
+			return template;
+		}
+
+		for (Entry<?, ?> entry : map.entrySet()) {
+			template = template.replace("{" + entry.getKey() + "}", entry.getValue().toString());
+		}
+		return template;
+	}
+	
+	/**
+	 * 编码字符串
+	 * 
+	 * @param str 字符串
+	 * @param charset 字符集,如果此字段为空,则解码的结果取决于平台
+	 * @return 编码后的字节码
+	 */
+	public static byte[] bytes(String str, String charset) {
+		return bytes(str, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset));
+	}
+
+	/**
+	 * 编码字符串
+	 * 
+	 * @param str 字符串
+	 * @param charset 字符集,如果此字段为空,则解码的结果取决于平台
+	 * @return 编码后的字节码
+	 */
+	public static byte[] bytes(String str, Charset charset) {
+		if (str == null) {
+			return null;
+		}
+
+		if (null == charset) {
+			return str.getBytes();
+		}
+		return str.getBytes(charset);
+	}
+	
+	/**
+	 * 将byte数组转为字符串
+	 * 
+	 * @param bytes byte数组
+	 * @param charset 字符集
+	 * @return 字符串
+	 */
+	public static String str(byte[] bytes, String charset) {
+		return str(bytes, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset));
+	}
+
+	/**
+	 * 解码字节码
+	 * 
+	 * @param data 字符串
+	 * @param charset 字符集,如果此字段为空,则解码的结果取决于平台
+	 * @return 解码后的字符串
+	 */
+	public static String str(byte[] data, Charset charset) {
+		if (data == null) {
+			return null;
+		}
+
+		if (null == charset) {
+			return new String(data);
+		}
+		return new String(data, charset);
+	}
+	
+	/**
+	 * 将编码的byteBuffer数据转换为字符串
+	 * @param data 数据
+	 * @param charset 字符集,如果为空使用当前系统字符集
+	 * @return 字符串
+	 */
+	public static String str(ByteBuffer data, String charset){
+		if(data == null) {
+			return null;
+		}
+		
+		return str(data, Charset.forName(charset));
+	}
+	
+	/**
+	 * 将编码的byteBuffer数据转换为字符串
+	 * @param data 数据
+	 * @param charset 字符集,如果为空使用当前系统字符集
+	 * @return 字符串
+	 */
+	public static String str(ByteBuffer data, Charset charset){
+		if(null == charset) {
+			charset = Charset.defaultCharset();
+		}
+		return charset.decode(data).toString();
+	}
+	
+	/**
+	 * 字符串转换为byteBuffer
+	 * @param str 字符串
+	 * @param charset 编码
+	 * @return byteBuffer
+	 */
+	public static ByteBuffer byteBuffer(String str, String charset) {
+		return ByteBuffer.wrap(StrKit.bytes(str, charset));
+	}
+
+	/**
+	 * 以 conjunction 为分隔符将多个对象转换为字符串
+	 * 
+	 * @param conjunction 分隔符
+	 * @param objs 数组
+	 * @return 连接后的字符串
+	 */
+	public static String join(String conjunction, Object... objs) {
+		StringBuilder sb = new StringBuilder();
+		boolean isFirst = true;
+		for (Object item : objs) {
+			if (isFirst) {
+				isFirst = false;
+			} else {
+				sb.append(conjunction);
+			}
+			sb.append(item);
+		}
+		return sb.toString();
+	}
+	
+	/**
+	 * 将驼峰式命名的字符串转换为下划线方式。如果转换前的驼峰式命名的字符串为空,则返回空字符串。</br>
+	 * 例如:HelloWorld->hello_world
+	 *
+	 * @param camelCaseStr 转换前的驼峰式命名的字符串
+	 * @return 转换后下划线大写方式命名的字符串
+	 */
+	public static String toUnderlineCase(String camelCaseStr) {
+		if (camelCaseStr == null) {
+			return null;
+		}
+
+		final int length = camelCaseStr.length();
+		StringBuilder sb = new StringBuilder();
+		char c;
+		boolean isPreUpperCase = false;
+		for (int i = 0; i < length; i++) {
+			c = camelCaseStr.charAt(i);
+			boolean isNextUpperCase = true;
+			if (i < (length - 1)) {
+				isNextUpperCase = Character.isUpperCase(camelCaseStr.charAt(i + 1));
+			}
+			if (Character.isUpperCase(c)) {
+				if (!isPreUpperCase || !isNextUpperCase) {
+					if (i > 0) sb.append(UNDERLINE);
+				}
+				isPreUpperCase = true;
+			} else {
+				isPreUpperCase = false;
+			}
+			sb.append(Character.toLowerCase(c));
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * 将下划线方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br>
+	 * 例如:hello_world->HelloWorld
+	 *
+	 * @param name 转换前的下划线大写方式命名的字符串
+	 * @return 转换后的驼峰式命名的字符串
+	 */
+	public static String toCamelCase(String name) {
+		if (name == null) {
+			return null;
+		}
+		if (name.contains(UNDERLINE)) {
+			name = name.toLowerCase();
+
+			StringBuilder sb = new StringBuilder(name.length());
+			boolean upperCase = false;
+			for (int i = 0; i < name.length(); i++) {
+				char c = name.charAt(i);
+
+				if (c == '_') {
+					upperCase = true;
+				} else if (upperCase) {
+					sb.append(Character.toUpperCase(c));
+					upperCase = false;
+				} else {
+					sb.append(c);
+				}
+			}
+			return sb.toString();
+		} else
+			return name;
+	}
+
+	/**
+	 * 包装指定字符串
+	 * 
+	 * @param str 被包装的字符串
+	 * @param prefix 前缀
+	 * @param suffix 后缀
+	 * @return 包装后的字符串
+	 */
+	public static String wrap(String str, String prefix, String suffix) {
+		return format("{}{}{}", prefix, str, suffix);
+	}
+
+	/**
+	 * 指定字符串是否被包装
+	 * 
+	 * @param str 字符串
+	 * @param prefix 前缀
+	 * @param suffix 后缀
+	 * @return 是否被包装
+	 */
+	public static boolean isWrap(String str, String prefix, String suffix) {
+		return str.startsWith(prefix) && str.endsWith(suffix);
+	}
+
+	/**
+	 * 指定字符串是否被同一字符包装(前后都有这些字符串)
+	 * 
+	 * @param str 字符串
+	 * @param wrapper 包装字符串
+	 * @return 是否被包装
+	 */
+	public static boolean isWrap(String str, String wrapper) {
+		return isWrap(str, wrapper, wrapper);
+	}
+
+	/**
+	 * 指定字符串是否被同一字符包装(前后都有这些字符串)
+	 * 
+	 * @param str 字符串
+	 * @param wrapper 包装字符
+	 * @return 是否被包装
+	 */
+	public static boolean isWrap(String str, char wrapper) {
+		return isWrap(str, wrapper, wrapper);
+	}
+
+	/**
+	 * 指定字符串是否被包装
+	 * 
+	 * @param str 字符串
+	 * @param prefixChar 前缀
+	 * @param suffixChar 后缀
+	 * @return 是否被包装
+	 */
+	public static boolean isWrap(String str, char prefixChar, char suffixChar) {
+		return str.charAt(0) == prefixChar && str.charAt(str.length() - 1) == suffixChar;
+	}
+
+	/**
+	 * 补充字符串以满足最小长度 StrUtil.padPre("1", 3, '0');//"001"
+	 * 
+	 * @param str 字符串
+	 * @param minLength 最小长度
+	 * @param padChar 补充的字符
+	 * @return 补充后的字符串
+	 */
+	public static String padPre(String str, int minLength, char padChar) {
+		if (str.length() >= minLength) {
+			return str;
+		}
+		StringBuilder sb = new StringBuilder(minLength);
+		for (int i = str.length(); i < minLength; i++) {
+			sb.append(padChar);
+		}
+		sb.append(str);
+		return sb.toString();
+	}
+
+	/**
+	 * 补充字符串以满足最小长度 StrUtil.padEnd("1", 3, '0');//"100"
+	 * 
+	 * @param str 字符串
+	 * @param minLength 最小长度
+	 * @param padChar 补充的字符
+	 * @return 补充后的字符串
+	 */
+	public static String padEnd(String str, int minLength, char padChar) {
+		if (str.length() >= minLength) {
+			return str;
+		}
+		StringBuilder sb = new StringBuilder(minLength);
+		sb.append(str);
+		for (int i = str.length(); i < minLength; i++) {
+			sb.append(padChar);
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * 创建StringBuilder对象
+	 * 
+	 * @return StringBuilder对象
+	 */
+	public static StringBuilder builder() {
+		return new StringBuilder();
+	}
+
+	/**
+	 * 创建StringBuilder对象
+	 * 
+	 * @return StringBuilder对象
+	 */
+	public static StringBuilder builder(int capacity) {
+		return new StringBuilder(capacity);
+	}
+
+	/**
+	 * 创建StringBuilder对象
+	 * 
+	 * @return StringBuilder对象
+	 */
+	public static StringBuilder builder(String... strs) {
+		final StringBuilder sb = new StringBuilder();
+		for (String str : strs) {
+			sb.append(str);
+		}
+		return sb;
+	}
+
+	/**
+	 * 获得StringReader
+	 * 
+	 * @param str 字符串
+	 * @return StringReader
+	 */
+	public static StringReader getReader(String str) {
+		return new StringReader(str);
+	}
+
+	/**
+	 * 获得StringWriter
+	 * 
+	 * @return StringWriter
+	 */
+	public static StringWriter getWriter() {
+		return new StringWriter();
+	}
+
+		/**
+	 * 编码字符串
+	 * 
+	 * @param str 字符串
+	 * @param charset 字符集,如果此字段为空,则解码的结果取决于平台
+	 * @return 编码后的字节码
+	 */
+	public static byte[] encode(String str, String charset) {
+		if (str == null) {
+			return null;
+		}
+
+		if(isBlank(charset)) {
+			return str.getBytes();
+		}
+		try {
+			return str.getBytes(charset);
+		} catch (UnsupportedEncodingException e) {
+			throw new RuntimeException(format("Charset [{}] unsupported!", charset));
+		}
+	}
+
+	/**
+	 * 解码字节码
+	 * 
+	 * @param data 字符串
+	 * @param charset 字符集,如果此字段为空,则解码的结果取决于平台
+	 * @return 解码后的字符串
+	 */
+	public static String decode(byte[] data, String charset) {
+		if (data == null) {
+			return null;
+		}
+
+		if(isBlank(charset)) {
+			return new String(data);
+		}
+		try {
+			return new String(data, charset);
+		} catch (UnsupportedEncodingException e) {
+			throw new RuntimeException(format("Charset [{}] unsupported!", charset));
+		}
+	}
+}
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/ToolBoxException.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/ToolBoxException.java
new file mode 100644
index 0000000..c6d4d84
--- /dev/null
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/ToolBoxException.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.ruoyi.study.utils;
+
+/**
+ * 工具类初始化异常
+ */
+public class ToolBoxException extends RuntimeException{
+	private static final long serialVersionUID = 8247610319171014183L;
+
+	public ToolBoxException(Throwable e) {
+		super(e.getMessage(), e);
+	}
+	
+	public ToolBoxException(String message) {
+		super(message);
+	}
+	
+	public ToolBoxException(String messageTemplate, Object... params) {
+		super(StrKit.format(messageTemplate, params));
+	}
+	
+	public ToolBoxException(String message, Throwable throwable) {
+		super(message, throwable);
+	}
+	
+	public ToolBoxException(Throwable throwable, String messageTemplate, Object... params) {
+		super(StrKit.format(messageTemplate, params), throwable);
+	}
+}
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/ToolUtil.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/ToolUtil.java
new file mode 100644
index 0000000..4f32246
--- /dev/null
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/ToolUtil.java
@@ -0,0 +1,575 @@
+/**
+ * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.ruoyi.study.utils;
+
+
+import cn.hutool.core.date.DateUtil;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Array;
+import java.math.BigDecimal;
+import java.net.URISyntaxException;
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * 高频方法集合类
+ */
+public class ToolUtil {
+
+    /**
+     * 获取随机位数的字符串
+     *
+     * @author fengshuonan
+     * @Date 2017/8/24 14:09
+     */
+    public static String getRandomString(int length) {
+        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
+        Random random = new Random();
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < length; i++) {
+            int number = random.nextInt(base.length());
+            sb.append(base.charAt(number));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 判断一个对象是否是时间类型
+     *
+     * @author stylefeng
+     * @Date 2017/4/18 12:55
+     */
+    public static String dateType(Object o) {
+        if (o instanceof Date) {
+            return com.ruoyi.study.utils.DateUtil.getDay((Date) o);
+        } else {
+            return o.toString();
+        }
+    }
+
+    /**
+     * 获取异常的具体信息
+     *
+     * @author fengshuonan
+     * @Date 2017/3/30 9:21
+     * @version 2.0
+     */
+    public static String getExceptionMsg(Exception e) {
+        StringWriter sw = new StringWriter();
+        try {
+            e.printStackTrace(new PrintWriter(sw));
+        } finally {
+            try {
+                sw.close();
+            } catch (IOException e1) {
+                e1.printStackTrace();
+            }
+        }
+        return sw.getBuffer().toString().replaceAll("\\$", "T");
+    }
+
+    /**
+     * 比较两个对象是否相等。<br>
+     * 相同的条件有两个,满足其一即可:<br>
+     * 1. obj1 == null && obj2 == null; 2. obj1.equals(obj2)
+     *
+     * @param obj1 对象1
+     * @param obj2 对象2
+     * @return 是否相等
+     */
+    public static boolean equals(Object obj1, Object obj2) {
+        return (obj1 != null) ? (obj1.equals(obj2)) : (obj2 == null);
+    }
+
+    /**
+     * 计算对象长度,如果是字符串调用其length函数,集合类调用其size函数,数组调用其length属性,其他可遍历对象遍历计算长度
+     *
+     * @param obj 被计算长度的对象
+     * @return 长度
+     */
+    public static int length(Object obj) {
+        if (obj == null) {
+            return 0;
+        }
+        if (obj instanceof CharSequence) {
+            return ((CharSequence) obj).length();
+        }
+        if (obj instanceof Collection) {
+            return ((Collection<?>) obj).size();
+        }
+        if (obj instanceof Map) {
+            return ((Map<?, ?>) obj).size();
+        }
+
+        int count;
+        if (obj instanceof Iterator) {
+            Iterator<?> iter = (Iterator<?>) obj;
+            count = 0;
+            while (iter.hasNext()) {
+                count++;
+                iter.next();
+            }
+            return count;
+        }
+        if (obj instanceof Enumeration) {
+            Enumeration<?> enumeration = (Enumeration<?>) obj;
+            count = 0;
+            while (enumeration.hasMoreElements()) {
+                count++;
+                enumeration.nextElement();
+            }
+            return count;
+        }
+        if (obj.getClass().isArray() == true) {
+            return Array.getLength(obj);
+        }
+        return -1;
+    }
+
+    /**
+     * 对象中是否包含元素
+     *
+     * @param obj     对象
+     * @param element 元素
+     * @return 是否包含
+     */
+    public static boolean contains(Object obj, Object element) {
+        if (obj == null) {
+            return false;
+        }
+        if (obj instanceof String) {
+            if (element == null) {
+                return false;
+            }
+            return ((String) obj).contains(element.toString());
+        }
+        if (obj instanceof Collection) {
+            return ((Collection<?>) obj).contains(element);
+        }
+        if (obj instanceof Map) {
+            return ((Map<?, ?>) obj).values().contains(element);
+        }
+
+        if (obj instanceof Iterator) {
+            Iterator<?> iter = (Iterator<?>) obj;
+            while (iter.hasNext()) {
+                Object o = iter.next();
+                if (equals(o, element)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        if (obj instanceof Enumeration) {
+            Enumeration<?> enumeration = (Enumeration<?>) obj;
+            while (enumeration.hasMoreElements()) {
+                Object o = enumeration.nextElement();
+                if (equals(o, element)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        if (obj.getClass().isArray() == true) {
+            int len = Array.getLength(obj);
+            for (int i = 0; i < len; i++) {
+                Object o = Array.get(obj, i);
+                if (equals(o, element)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 对象是否不为空(新增)
+     *
+     * @param obj String,List,Map,Object[],int[],long[]
+     * @return
+     */
+    public static boolean isNotEmpty(Object o) {
+        return !isEmpty(o);
+    }
+
+    /**
+     * 对象是否为空
+     *
+     * @param obj String,List,Map,Object[],int[],long[]
+     * @return
+     */
+    @SuppressWarnings("rawtypes")
+    public static boolean isEmpty(Object o) {
+        if (o == null) {
+            return true;
+        }
+        if (o instanceof String) {
+            if (o.toString().trim().equals("")) {
+                return true;
+            }
+        } else if (o instanceof List) {
+            if (((List) o).size() == 0) {
+                return true;
+            }
+        } else if (o instanceof Map) {
+            if (((Map) o).size() == 0) {
+                return true;
+            }
+        } else if (o instanceof Set) {
+            if (((Set) o).size() == 0) {
+                return true;
+            }
+        } else if (o instanceof Object[]) {
+            if (((Object[]) o).length == 0) {
+                return true;
+            }
+        } else if (o instanceof int[]) {
+            if (((int[]) o).length == 0) {
+                return true;
+            }
+        } else if (o instanceof long[]) {
+            if (((long[]) o).length == 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 对象组中是否存在 Empty Object
+     *
+     * @param os 对象组
+     * @return
+     */
+    public static boolean isOneEmpty(Object... os) {
+        for (Object o : os) {
+            if (isEmpty(o)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 对象组中是否全是 Empty Object
+     *
+     * @param os
+     * @return
+     */
+    public static boolean isAllEmpty(Object... os) {
+        for (Object o : os) {
+            if (!isEmpty(o)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 是否为数字
+     *
+     * @param obj
+     * @return
+     */
+    public static boolean isNum(Object obj) {
+        try {
+            Integer.parseInt(obj.toString());
+        } catch (Exception e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 如果为空, 则调用默认值
+     *
+     * @param str
+     * @return
+     */
+    public static Object getValue(Object str, Object defaultValue) {
+        if (isEmpty(str)) {
+            return defaultValue;
+        }
+        return str;
+    }
+
+    /**
+     * 格式化文本
+     *
+     * @param template 文本模板,被替换的部分用 {} 表示
+     * @param values   参数值
+     * @return 格式化后的文本
+     */
+    public static String format(String template, Object... values) {
+        return StrKit.format(template, values);
+    }
+
+    /**
+     * 格式化文本
+     *
+     * @param template 文本模板,被替换的部分用 {key} 表示
+     * @param map      参数值对
+     * @return 格式化后的文本
+     */
+    public static String format(String template, Map<?, ?> map) {
+        return StrKit.format(template, map);
+    }
+
+    /**
+     * 强转->string,并去掉多余空格
+     *
+     * @param str
+     * @return
+     */
+    public static String toStr(Object str) {
+        return toStr(str, "");
+    }
+
+    /**
+     * 强转->string,并去掉多余空格
+     *
+     * @param str
+     * @param defaultValue
+     * @return
+     */
+    public static String toStr(Object str, String defaultValue) {
+        if (null == str) {
+            return defaultValue;
+        }
+        return str.toString().trim();
+    }
+
+    /**
+     * 强转->int
+     *
+     * @param obj
+     * @return
+     */
+//	public static int toInt(Object value) {
+//		return toInt(value, -1);
+//	}
+
+    /**
+     * 强转->int
+     *
+     * @param obj
+     * @param defaultValue
+     * @return
+     */
+//	public static int toInt(Object value, int defaultValue) {
+//		return Convert.toInt(value, defaultValue);
+//	}
+
+    /**
+     * 强转->long
+     *
+     * @param obj
+     * @return
+     */
+//	public static long toLong(Object value) {
+//		return toLong(value, -1);
+//	}
+
+    /**
+     * 强转->long
+     *
+     * @param obj
+     * @param defaultValue
+     * @return
+     */
+//	public static long toLong(Object value, long defaultValue) {
+//		return Convert.toLong(value, defaultValue);
+//	}
+//
+//	public static String encodeUrl(String url) {
+//		return URLKit.encode(url, CharsetKit.UTF_8);
+//	}
+//
+//	public static String decodeUrl(String url) {
+//		return URLKit.decode(url, CharsetKit.UTF_8);
+//	}
+
+    /**
+     * map的key转为小写
+     *
+     * @param map
+     * @return Map<String , Object>
+     */
+    public static Map<String, Object> caseInsensitiveMap(Map<String, Object> map) {
+        Map<String, Object> tempMap = new HashMap<>();
+        for (String key : map.keySet()) {
+            tempMap.put(key.toLowerCase(), map.get(key));
+        }
+        return tempMap;
+    }
+
+    /**
+     * 获取map中第一个数据值
+     *
+     * @param <K> Key的类型
+     * @param <V> Value的类型
+     * @param map 数据源
+     * @return 返回的值
+     */
+    public static <K, V> V getFirstOrNull(Map<K, V> map) {
+        V obj = null;
+        for (Entry<K, V> entry : map.entrySet()) {
+            obj = entry.getValue();
+            if (obj != null) {
+                break;
+            }
+        }
+        return obj;
+    }
+
+    /**
+     * 创建StringBuilder对象
+     *
+     * @return StringBuilder对象
+     */
+    public static StringBuilder builder(String... strs) {
+        final StringBuilder sb = new StringBuilder();
+        for (String str : strs) {
+            sb.append(str);
+        }
+        return sb;
+    }
+
+    /**
+     * 创建StringBuilder对象
+     *
+     * @return StringBuilder对象
+     */
+    public static void builder(StringBuilder sb, String... strs) {
+        for (String str : strs) {
+            sb.append(str);
+        }
+    }
+
+    /**
+     * 去掉指定后缀
+     *
+     * @param str    字符串
+     * @param suffix 后缀
+     * @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串
+     */
+    public static String removeSuffix(String str, String suffix) {
+        if (isEmpty(str) || isEmpty(suffix)) {
+            return str;
+        }
+
+        if (str.endsWith(suffix)) {
+            return str.substring(0, str.length() - suffix.length());
+        }
+        return str;
+    }
+
+
+
+    /**
+     * 首字母大写
+     *
+     * @author stylefeng
+     * @Date 2017/5/7 22:01
+     */
+    public static String firstLetterToUpper(String val) {
+        return StrKit.firstCharToUpperCase(val);
+    }
+
+    /**
+     * 首字母小写
+     *
+     * @author stylefeng
+     * @Date 2017/5/7 22:02
+     */
+    public static String firstLetterToLower(String val) {
+        return StrKit.firstCharToLowerCase(val);
+    }
+
+    /**
+     * 判断是否是windows操作系统
+     *
+     * @author stylefeng
+     * @Date 2017/5/24 22:34
+     */
+    public static Boolean isWinOs() {
+        String os = System.getProperty("os.name");
+        if (os.toLowerCase().startsWith("win")) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * 获取临时目录
+     *
+     * @author stylefeng
+     * @Date 2017/5/24 22:35
+     */
+    public static String getTempPath() {
+        return System.getProperty("java.io.tmpdir");
+    }
+
+    /**
+     * 把一个数转化为int
+     *
+     * @author fengshuonan
+     * @Date 2017/11/15 下午11:10
+     */
+    public static Integer toInt(Object val) {
+        if (val instanceof Double) {
+            BigDecimal bigDecimal = new BigDecimal((Double) val);
+            return bigDecimal.intValue();
+        } else {
+            return Integer.valueOf(val.toString());
+        }
+
+    }
+
+    /**
+     * 获取项目路径
+     */
+    public static String getWebRootPath(String filePath) {
+        try {
+            String path = ToolUtil.class.getClassLoader().getResource("").toURI().getPath();
+            path = path.replace("/WEB-INF/classes/", "");
+            path = path.replace("/target/classes/", "");
+            path = path.replace("file:/", "");
+            if (ToolUtil.isEmpty(filePath)) {
+                return path;
+            } else {
+                return path + "/" + filePath;
+            }
+        } catch (URISyntaxException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 获取文件后缀名 不包含点
+     */
+    public static String getFileSuffix(String fileWholeName) {
+        if (ToolUtil.isEmpty(fileWholeName)) {
+            return "none";
+        }
+        int lastIndexOf = fileWholeName.lastIndexOf(".");
+        return fileWholeName.substring(lastIndexOf + 1);
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/UUIDUtil.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/UUIDUtil.java
new file mode 100644
index 0000000..d1b5fe8
--- /dev/null
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/UUIDUtil.java
@@ -0,0 +1,101 @@
+package com.ruoyi.study.utils;
+
+
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.UUID;
+
+/**
+ * 定义生成随机码的工具类
+ */
+public class UUIDUtil {
+
+    private int i = 1;
+
+
+    /**
+     * 定义生成原生的UUID随机码
+     * @return
+     */
+    public synchronized static String getNativeUUID(){
+        return UUID.randomUUID().toString();
+    }
+
+
+    /**
+     * 生成32位随机码
+     * @return
+     */
+    public synchronized static String getRandomCode(){
+        return UUIDUtil.getNativeUUID().replaceAll("-", "");
+    }
+
+
+    /**
+     * 获取给定长度的随机码
+     * @param num
+     * @return
+     * @throws Exception
+     */
+    public synchronized static String getRandomCode(Integer num) throws Exception{
+        String str = null;
+        if(0 < num){
+            if(num % 32 > 0){
+                Integer s = num / 32;
+                Integer l = num % 32;
+                StringBuffer sb = new StringBuffer();
+                for(int i = 0; i < s; i++){
+                    sb.append(UUIDUtil.getRandomCode());
+                }
+                sb.append(UUIDUtil.getRandomCode().substring(0, l));
+                str = sb.toString();
+            }else if(num % 32 == 0){
+                Integer s = num / 32;
+                StringBuffer sb = new StringBuffer();
+                for(int i = 0; i < s; i++){
+                    sb.append(UUIDUtil.getRandomCode());
+                }
+                str = sb.toString();
+            }else{
+                str = UUIDUtil.getRandomCode().substring(0, num);
+            }
+        }else{
+            throw new Exception("参数只能大于0");
+        }
+        return str;
+    }
+
+
+    /**
+     * 获取根据当前时间的字符串数据
+     * @return
+     */
+    public synchronized static String getTimeStr(){
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmssSSS");
+        return simpleDateFormat.format(new Date());
+    }
+
+
+    /**
+     * @Description: 获取数字随机码
+     * @Author pzb
+     * @Date 2021/8/11 16:52
+     * @Param
+     * @Return
+     * @Exception
+     */
+    public synchronized static String getNumberRandom(Integer num){
+        if(null == num){
+            num = 32;
+        }
+        StringBuffer sb = new StringBuffer();
+        for(int i = 0; i < num; i++){
+            sb.append(Double.valueOf(Math.random() * 10).intValue());
+        }
+        return sb.toString();
+    }
+
+
+
+}
diff --git a/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/vo/VipInfoVO.java b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/vo/VipInfoVO.java
new file mode 100644
index 0000000..901b339
--- /dev/null
+++ b/ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/vo/VipInfoVO.java
@@ -0,0 +1,22 @@
+package com.ruoyi.study.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@ApiModel(value = "会员中心VO")
+public class VipInfoVO {
+    @ApiModelProperty(value = "id")
+    private Integer id;
+    @ApiModelProperty(value = "会员说明")
+    private String info;
+    @ApiModelProperty(value = "当前用户是否是会员0否1是")
+    private Integer isVip;
+    @ApiModelProperty(value = "有效期单位月")
+    private Integer time;
+    @ApiModelProperty(value = "金额")
+    private BigDecimal amount;
+}
\ No newline at end of file
diff --git a/ruoyi-service/ruoyi-study/src/main/resources/bootstrap.yml b/ruoyi-service/ruoyi-study/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..48aa858
--- /dev/null
+++ b/ruoyi-service/ruoyi-study/src/main/resources/bootstrap.yml
@@ -0,0 +1,58 @@
+# Spring
+spring:
+  application:
+    # 应用名称
+    name: ruoyi-study
+  main:
+    allow-bean-definition-overriding: true
+  profiles:
+    # 环境配置
+    active: dev
+---
+spring:
+  config:
+    activate:
+      on-profile: dev
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 192.168.110.64:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+      config:
+        # 配置中心地址
+        server-addr: 192.168.110.64:8848
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
+---
+spring:
+  config:
+    activate:
+      on-profile: prod
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 127.0.0.1:8848
+        service: ${spring.application.name}
+        group: DEFAULT_GROUP
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+      config:
+        # 配置中心地址
+        server-addr: 127.0.0.1:8848
+        namespace: c6482de2-9508-4425-bde5-08abe35abace
+        group: DEFAULT_GROUP
+        name: ${spring.application.name}
+        # 配置文件格式
+        file-extension: yml
+        # 共享配置
+        shared-configs:
+          - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

--
Gitblit v1.7.1