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 = " ";
+ public static final String HTML_AMP = "&";
+ public static final String HTML_QUOTE = """;
+ public static final String HTML_LT = "<";
+ public static final String HTML_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, "default") = "default"
+ * nullToDefault("", "default") = ""
+ * nullToDefault(" ", "default") = " "
+ * nullToDefault("bat", "default") = "bat"
+ * </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("") = ""
+ * trim(" ") = ""
+ * trim("abc") = "abc"
+ * trim(" abc ") = "abc"
+ * </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("") = ""
+ * trimStart("abc") = "abc"
+ * trimStart(" abc") = "abc"
+ * trimStart("abc ") = "abc "
+ * trimStart(" abc ") = "abc "
+ * </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("") = ""
+ * trimEnd("abc") = "abc"
+ * trimEnd(" abc") = " abc"
+ * trimEnd("abc ") = "abc"
+ * trimEnd(" abc ") = " abc"
+ * </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, "abc") = false
+ * equals("abc", null) = false
+ * equals("abc", "abc") = true
+ * equals("abc", "ABC") = 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, "abc") = false
+ * equalsIgnoreCase("abc", null) = false
+ * equalsIgnoreCase("abc", "abc") = true
+ * equalsIgnoreCase("abc", "ABC") = 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