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()); } }; } } 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(); } ruoyi-api/ruoyi-api-management/src/main/java/com/ruoyi/management/api/model/TVipSet.java
New file @@ -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 + "}"; } } 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; } 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()); } 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 ruoyi-auth/src/main/resources/bootstrap.yml
New file @@ -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} 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; /** * 对象创建成功 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 成功消息 ruoyi-gateway/src/main/resources/bootstrap.yml
New file @@ -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 ruoyi-modules/ruoyi-file/src/main/resources/bootstrap.yml
New file @@ -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} ruoyi-modules/ruoyi-gen/src/main/resources/bootstrap.yml
New file @@ -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} ruoyi-modules/ruoyi-job/src/main/resources/bootstrap.yml
New file @@ -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} ruoyi-modules/ruoyi-system/src/main/resources/bootstrap.yml
New file @@ -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} ruoyi-service/ruoyi-goods/src/main/resources/bootstrap.yml
New file @@ -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} 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(); } } 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; } 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> 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> 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> 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; /** ruoyi-service/ruoyi-management/src/main/resources/bootstrap.yml
New file @@ -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} ruoyi-service/ruoyi-parent/src/main/resources/bootstrap.yml
New file @@ -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} 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> 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("退出成功"); } } 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); 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; } ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/CollectionKit.java
New file @@ -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(); } } ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/DateUtil.java
New file @@ -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(); } } ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/HttpClientUtil.java
New file @@ -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(); } } } } ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/HttpResult.java
New file @@ -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; } } ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/MD5AndKL.java
New file @@ -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"))); } } ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/PayMoneyUtil.java
New file @@ -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; } } ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/StrKit.java
New file @@ -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)); } } } ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/ToolBoxException.java
New file @@ -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); } } ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/ToolUtil.java
New file @@ -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); } } ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/utils/UUIDUtil.java
New file @@ -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(); } } ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/vo/VipInfoVO.java
New file @@ -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; } ruoyi-service/ruoyi-study/src/main/resources/bootstrap.yml
New file @@ -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}