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