Pre Merge pull request !380 from 鲸落/master_zhp

This commit is contained in:
鲸落
2024-10-11 09:33:55 +00:00
committed by Gitee
160 changed files with 13236 additions and 2919 deletions

View File

@@ -18,6 +18,7 @@
<module>ruoyi-common-sensitive</module>
<module>ruoyi-common-datascope</module>
<module>ruoyi-common-datasource</module>
<module>ruoyi-common-sms</module>
</modules>
<artifactId>ruoyi-common</artifactId>

View File

@@ -106,7 +106,21 @@
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-annotation</artifactId>
<version>3.5.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -56,4 +56,20 @@ public class CacheConstants
* 登录IP黑名单 cache key
*/
public static final String SYS_LOGIN_BLACKIPLIST = SYS_CONFIG_KEY + "sys.login.blackIPList";
public static final String PROJET = "xymz:";
/**
* 渠道redis缓存键
*/
public static final String CHANNEL_ID = PROJET + "channel:id:";
/**
* 渠道redis缓存键
*/
public static final String CHANNEL_SIGN = PROJET + "channel:sign:";
/**
* 商户redis缓存键
*/
public static final String MERCHANT = PROJET + "merchant:key:";
}

View File

@@ -0,0 +1,42 @@
package com.ruoyi.common.core.constant;
public class RedisConstant {
/**
* 用户登录缓存
*/
public final static String APP_CUSTOMER_KEY = CacheConstants.PROJET + ":customer:key:";
/**
* 用户名缓存
*/
public final static String APP_CUSTOMER_USERNAME_KEY = CacheConstants.PROJET + ":app:customer:username:key:";
/**
* 渠道ID缓存
*/
public final static String APP_CUSTOMER_CHANNEL_KEY = CacheConstants.PROJET + ":app:customer:channel:key:";
/**
* 用户登录缓存
*/
public final static String APP_CUSTOMER_TOKEN_KEY = CacheConstants.PROJET + ":app:customer:token:key:";
/**
* app用户设备标识
*/
public final static String APP_DEVICE_IDENTIFICATION = CacheConstants.PROJET + ":app:app:device:identification:";
/**
* H5登录验证码
*/
public final static String H5_LOGIN_CACHE = CacheConstants.PROJET+"H5:login:cache:";
/**
* H5申请幂等校验
*/
public final static String H5_APPLY_CHECK = CacheConstants.PROJET+"H5:apply:check:";
/**
* 撞库幂等校验
*/
public final static String HIT_CHECK_CACHE = CacheConstants.PROJET+"hit:check:cache:";
}

View File

@@ -0,0 +1,9 @@
package com.ruoyi.common.core.domain;
import lombok.Data;
@Data
public class GetSumDto {
private Long merchantId;
}

View File

@@ -0,0 +1,35 @@
package com.ruoyi.common.core.domain;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* 概率计算
* @Author: daisi
* @Date: 2022/4/2 9:49
*/
@Data
@Accessors(chain = true)
public class GuestProbabilityReq implements Serializable {
private static final long serialVersionUID = -9096451963988288187L;
/**
* 计划Id
*/
private Long planId;
/**
* 排序价格
*/
private BigDecimal orderPrice;
/**
* 概率
*/
private Double guestProbability;
/**
* 计算结果概率
*/
private Integer resultGuestProbability;
}

View File

@@ -0,0 +1,57 @@
package com.ruoyi.common.core.domain.http;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import com.ruoyi.common.core.annotation.Excel;
import com.ruoyi.common.core.web.domain.BaseEntity;
/**
* 渠道配置对象 channel
*
* @author ruoyi
* @date 2024-09-15
*/
@Data
public class Channel extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** */
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/** 渠道名称 */
@Excel(name = "渠道名称")
private String channelName;
/** 渠道签名 */
@Excel(name = "渠道签名")
private String channelSign;
/** 渠道类型 1H5 2连登 3半流程 4全流程*/
@Excel(name = "渠道类型")
private String channelType;
/** 扣量比 */
@Excel(name = "扣量比")
private Long score;
/** 推广页名称 */
@Excel(name = "推广页名称")
private String htmlName;
/** 推广页地址 */
@Excel(name = "推广页地址")
private String htmlLocation;
/** 可访问IP */
@Excel(name = "可访问IP")
private String ips;
/** 开启关闭时段 */
@Excel(name = "开启关闭时段")
private String period;
}

View File

@@ -0,0 +1,138 @@
package com.ruoyi.common.core.domain.http;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.core.annotation.Excel;
import com.ruoyi.common.core.web.domain.BaseEntity;
/**
* 客户信息对象 customer
*
* @author ruoyi
* @date 2024-09-15
*/
@Data
public class Customer extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** $column.columnComment */
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**渠道ID**/
@Excel(name = "渠道ID")
private Long channelId;
/** 年龄 */
@Excel(name = "年龄")
private Integer age;
/** 0 男 1 女 */
@Excel(name = "0 男 1 女")
private Integer sex;
@Excel(name="身份证号")
private String idCard;
/** 昵称 */
@Excel(name = "昵称")
private String name;
/** 真实姓名 */
@Excel(name = "真实姓名")
private String acturlName;
/** 手机号 */
@Excel(name = "手机号")
private String phone;
/** 手机号MD5 */
@Excel(name = "手机号MD5")
private String phoneMd5;
/** 0 未实名 1已实名 */
@Excel(name = "0 未实名 1已实名")
private Boolean isAuth;
/** 城市 */
@Excel(name = "城市")
private String city;
/** 城市编码 */
@Excel(name = "城市编码")
private Integer cityCode;
/** 首次登录时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "首次登录时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date firstLoginTime;
/** 最后登录时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date lastLoginTime;
/** 最后登录IP */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "最后登录IP", width = 30, dateFormat = "yyyy-MM-dd")
private Date lastLoginIp;
/** 用户状态 1正常 2异常 可继续扩展 */
@Excel(name = "用户状态 1正常 2异常 可继续扩展")
private Integer status;
/** 无社保 */
@Excel(name = "社保")
private Integer socialSecurity;
/** 无车 */
@Excel(name = "")
private Integer car;
/** 保单缴纳不满一年 */
@Excel(name = "保单")
private Integer guaranteeSlip;
/** 初中 */
@Excel(name = "学历")
private Integer education;
/** 公积金未满6个月 */
@Excel(name = "公积金")
private Integer accumulationFund;
/** 本地无房 */
@Excel(name = "")
private Integer hourse;
/** 上班族 */
@Excel(name = "职业")
private Integer career;
/** 花呗5000以下 */
@Excel(name = "花呗")
private Integer huaBei;
/** 白条5000以下 */
@Excel(name = "白条")
private Integer baiTiao;
/** 芝麻分 */
@Excel(name = "芝麻分")
private Integer zhiMa;
/** 月收入 */
@Excel(name = "月收入")
private Integer income;
}

View File

@@ -0,0 +1,51 @@
package com.ruoyi.common.core.domain.http;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.core.annotation.Excel;
import com.ruoyi.common.core.web.domain.BaseEntity;
/**
* 客户申请记录对象 customer_apply_log
*
* @author ruoyi
* @date 2024-09-15
*/
@Data
public class CustomerApplyLog extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** $column.columnComment */
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/** 用户id */
@Excel(name = "用户id")
private Long customerId;
/** 商户ID */
@Excel(name = "商户ID")
private Long merchantId;
/** $column.columnComment */
@Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
private Long channelId;
/** 订单状态 0 已申请 1 注册中 2风控中 3下单中 4 下单成功 5已成交 */
@Excel(name = "订单状态 0 已申请 1 注册中 2风控中 3下单中 4 下单成功 5已成交 ")
private Long orderStatus;
/** 成交金额 分 */
@Excel(name = "成交金额 分")
private BigDecimal price;
@Excel(name = "订单号")
private String orderNo;
}

View File

@@ -0,0 +1,243 @@
package com.ruoyi.common.core.domain.http;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.core.annotation.Excel;
import com.ruoyi.common.core.web.domain.BaseEntity;
/**
* 商户对象 merchant
*
* @author ruoyi
* @date 2024-09-15
*/
@Data
public class Merchant extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** $column.columnComment */
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/** 商户类型 1H5 2连登 3半流程 4全流程 */
@Excel(name = "商户类型 1H5 2连登 3半流程 4全流程")
private Long merchantType;
/** 商户名称 */
@Excel(name = "商户名称")
private String merchantName;
/** 商户描述 */
@Excel(name = "商户描述")
private String merchantDescribe;
/** 商户主体 */
@Excel(name = "商户主体")
private String merchantCompany;
/** logo文件地址 */
@Excel(name = "logo文件地址")
private String logo;
/** 是否上下架 */
@Excel(name = "是否上下架")
private Integer status;
/** 定量数 */
@Excel(name = "定量数")
private Integer limitNum;
/** 是否定量 0否 1是 */
@Excel(name = "是否定量 0否 1是")
private Integer limitType;
/** 是否开启余额监控 0否 1是 */
@Excel(name = " 是否开启余额监控 0否 1是")
private Integer isBalanceMonitoring;
/** 余额监控余额 */
@Excel(name = "余额")
private Integer balanceMonitoring ;
/** 渠道限制ID */
@Excel(name = "渠道限制ID")
private String channelLimit;
/** 是否通过 0否 1是 */
@Excel(name = "是否通过 0否 1是")
private Integer ispass;
/** 渠道限制类型 0不限 1满足其一 2满足全部 */
@Excel(name = "渠道限制类型 0不限 1满足其一 2满足全部")
private Integer customerInfoFilterType;
/** 渠道限制类型 0不限 1准入 2禁入 */
@Excel(name = "渠道限制类型 0不限 1准入 2禁入")
private Integer channelLimitType;
/** 执行时段 */
@Excel(name = "执行时段")
private String period;
/**撞库地址**/
@Excel(name = "撞库地址")
private String hitUrl;
/**注册地址**/
@Excel(name = "注册地址")
private String registUrl;
/** 年龄限制开始 */
@Excel(name = "年龄限制开始")
private Integer ageLimitStart;
/** 年龄限制结束 */
@Excel(name = "年龄限制结束")
private Integer ageLimitEnd;
/** 手机号禁入号段英文逗号分隔 */
@Excel(name = "手机号禁入号段英文逗号分隔")
private String phoneLimit;
/** 标签 */
@Excel(name = "标签")
private String label;
/** 商户是否开启二要素 0 否 1 是 */
@Excel(name = "商户是否开启二要素")
private Boolean merchantAuth;
@Excel(name = "下游渠道标识")
private String channelSign;
/** 无社保 */
@Excel(name = "无社保")
private Boolean socialSecurityNo;
/** 社保未满6个月 */
@Excel(name = "社保未满6个月")
private Boolean socialSecurityLow;
/** 社保6个月以上 */
@Excel(name = "社保6个月以上")
private Boolean socialSecurityHigh;
/** 无车 */
@Excel(name = "无车")
private Boolean carNo;
/** 有车 */
@Excel(name = "有车")
private Boolean carHave;
/** 保单缴纳不满一年 */
@Excel(name = "保单缴纳不满一年")
private Boolean guaranteeSlipLow;
/** 保单缴纳一年以上 */
@Excel(name = "保单缴纳一年以上")
private Boolean guaranteeSlipCentre;
/** 保单缴纳2年以上 */
@Excel(name = "保单缴纳2年以上")
private Boolean guaranteeSlipHigh;
/** 初中 */
@Excel(name = "初中")
private Boolean educationMiddle;
/** 高中 */
@Excel(name = "高中")
private Boolean educationHighSchool;
/** 中专 */
@Excel(name = "中专")
private Boolean educationPolytechnic;
/** 大专 */
@Excel(name = "大专")
private Boolean educationJuniorCollege;
/** 本科 */
@Excel(name = "本科")
private Boolean educationUndergraduateCourse;
/** 研究生及以上 */
@Excel(name = "研究生及以上")
private Boolean educationPostgraduate;
/** 公积金未满6个月 */
@Excel(name = "公积金未满6个月")
private Boolean accumulationFundLow;
/** 公积金满6个月以上 */
@Excel(name = "公积金满6个月以上")
private Boolean accumulationFundHigh;
/** 本地无房 */
@Excel(name = "本地无房")
private Boolean hourseNo;
/** 本地全款房 */
@Excel(name = "本地全款房")
private Boolean hourseFullPayment;
/** 本地按揭 */
@Excel(name = "本地按揭")
private Boolean hourseMortgaging;
/** 上班族 */
@Excel(name = "上班族")
private Boolean officeWorker;
/** 公务员 */
@Excel(name = "公务员")
private Boolean civilServant;
/** 私营业主 */
@Excel(name = "私营业主")
private Boolean privatePropertyOwners;
/** 个体户 */
@Excel(name = "个体户")
private Boolean selfEmployedPerson;
/** 其他职业 */
@Excel(name = "其他职业")
private Boolean otherOccupations;
/** 花呗5000以下 */
@Excel(name = "花呗5000以下")
private Boolean huaBeiLow;
/** 花呗5000-10000 */
@Excel(name = "花呗5000-10000")
private Boolean huaBeiMiddle;
/** 花呗10000以上 */
@Excel(name = "花呗10000以上")
private Boolean huaBeiHigh;
/** 白条5000以下 */
@Excel(name = "白条5000以下")
private Boolean baiTiaoLow;
/** 白条5000-10000 */
@Excel(name = "白条5000-10000")
private Boolean baiTiaoMiddle;
/** 白条10000以上 */
@Excel(name = "白条10000以上")
private Boolean baiTiaoHigh;
/** 芝麻分 */
@Excel(name = "芝麻分")
private Integer zhiMa;
}

View File

@@ -0,0 +1,636 @@
package com.ruoyi.common.core.utils;
import cn.hutool.core.codec.Base64;
import org.apache.commons.codec.binary.Hex;
import org.springframework.stereotype.Component;
import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.regex.Pattern;
/**
* @program: JieYiHua-Cloud
* @description: 加密解密
* @author: LiYu
* @create: 2021-07-23 17:02
**/
@Component
public class EncryptUtil {
public static final String MD5 = "MD5";
public static final String SHA1 = "SHA1";
public static final String HmacMD5 = "HmacMD5";
public static final String HmacSHA1 = "HmacSHA1";
public static final String DES = "DES";
public static final String AES = "AES";
public static final Charset CHARSET = StandardCharsets.UTF_8;
public static final byte keyStrSize = 16;
public static final byte ivStrSize = 16;
public static final String AES_CBC_NOPADDING = "AES/CBC/NoPadding";
public static final String DES_ECB_PKCS7PADDING = "DES/ECB/PKCS7Padding";
public static final String AES_ECB_PKCS5PADDING = "AES/ECB/PKCS5Padding";
/**
* 编码格式默认使用uft-8
*/
public static String charset = "utf-8";
/**
* DES
*/
public static int keysizeDES = 0;
/**
* AES
*/
public static int keysizeAES = 128;
public static EncryptUtil me;
private EncryptUtil() {
//单例
}
//双重锁
public static EncryptUtil getInstance() {
if (me == null) {
synchronized (EncryptUtil.class) {
if (me == null) {
me = new EncryptUtil();
}
}
}
return me;
}
/**
* 使用MessageDigest进行单向加密无密码
*
* @param res 被加密的文本
* @param algorithm 加密算法名称
* @return
*/
private static String messageDigest(String res, String algorithm) {
try {
MessageDigest md = MessageDigest.getInstance(algorithm);
byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset);
return base64(md.digest(resBytes));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 使用KeyGenerator进行单向/双向加密(可设密码)
*
* @param res 被加密的原文
* @param algorithm 加密使用的算法名称
* @param key 加密使用的秘钥
* @return
*/
private String keyGeneratorMac(String res, String algorithm, String key) {
try {
SecretKey sk = null;
if (key == null) {
KeyGenerator kg = KeyGenerator.getInstance(algorithm);
sk = kg.generateKey();
} else {
byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset);
sk = new SecretKeySpec(keyBytes, algorithm);
}
Mac mac = Mac.getInstance(algorithm);
mac.init(sk);
byte[] result = mac.doFinal(res.getBytes());
return base64(result);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 使用KeyGenerator双向加密DES/AES注意这里转化为字符串的时候是将2进制转为16进制格式的字符串不是直接转因为会出错
*
* @param res 加密的原文
* @param algorithm 加密使用的算法名称
* @param key 加密的秘钥
* @param keysize
* @param isEncode
* @return
*/
private static String keyGeneratorES(String res, String algorithm, String key, int keysize, boolean isEncode) {
try {
KeyGenerator kg = KeyGenerator.getInstance(algorithm);
if (keysize == 0) {
byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset);
kg.init(new SecureRandom(keyBytes));
} else if (key == null) {
kg.init(keysize);
} else {
byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset);
kg.init(keysize, new SecureRandom(keyBytes));
}
SecretKey sk = kg.generateKey();
SecretKeySpec sks = new SecretKeySpec(sk.getEncoded(), algorithm);
Cipher cipher = Cipher.getInstance(algorithm);
if (isEncode) {
cipher.init(Cipher.ENCRYPT_MODE, sks);
byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset);
return parseByte2HexStr(cipher.doFinal(resBytes));
} else {
cipher.init(Cipher.DECRYPT_MODE, sks);
return new String(cipher.doFinal(parseHexStr2Byte(res)));
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Deprecated
private static String base64(byte[] res) {
return Base64.encode(res);
}
/**
* 将二进制转换成16进制
*/
public static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**
* 将16进制转换为二进制
*/
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1) {
return null;
}
byte[] result = new byte[hexStr.length() / 2];
for (int i = 0; i < hexStr.length() / 2; i++) {
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
/**
* md5加密算法进行加密不可逆
*
* @param res 需要加密的原文
* @return
*/
@Deprecated
public String MD5(String res) {
return messageDigest(res, MD5);
}
/**
* md5加密算法进行加密不可逆
*
* @param res 需要加密的原文
* @param key 秘钥
* @return
*/
@Deprecated
public String MD5(String res, String key) {
return keyGeneratorMac(res, HmacMD5, key);
}
/**
* 使用SHA1加密算法进行加密不可逆
*
* @param res 需要加密的原文
* @return
*/
public static String SHA1(String res) {
return messageDigest(res, SHA1);
}
/**
* 使用SHA1加密算法进行加密不可逆
*
* @param res 需要加密的原文
* @param key 秘钥
* @return
*/
public String SHA1(String res, String key) {
return keyGeneratorMac(res, HmacSHA1, key);
}
/**
* 使用DES加密算法进行加密可逆
*
* @param res 需要加密的原文
* @param key 秘钥
* @return
*/
public static String DESencode(String res, String key) {
return keyGeneratorES(res, DES, key, keysizeDES, true);
}
/**
* 对使用DES加密算法的密文进行解密可逆
*
* @param res 需要解密的密文
* @param key 秘钥
* @return
*/
public String DESdecode(String res, String key) {
return keyGeneratorES(res, DES, key, keysizeDES, false);
}
/**
* 使用异或进行加密
*
* @param res 需要加密的密文
* @param key 秘钥
* @return
*/
public String XORencode(String res, String key) {
byte[] bs = res.getBytes();
for (int i = 0; i < bs.length; i++) {
bs[i] = (byte) ((bs[i]) ^ key.hashCode());
}
return parseByte2HexStr(bs);
}
/**
* 使用异或进行解密
*
* @param res 需要解密的密文
* @param key 秘钥
* @return
*/
public String XORdecode(String res, String key) {
byte[] bs = parseHexStr2Byte(res);
for (int i = 0; i < bs.length; i++) {
bs[i] = (byte) ((bs[i]) ^ key.hashCode());
}
return new String(bs);
}
/**
* 直接使用异或(第一调用加密,第二次调用解密)
*
* @param res 密文
* @param key 秘钥
* @return
*/
public int XOR(int res, String key) {
return res ^ key.hashCode();
}
/**
* 使用Base64进行加密
*
* @param res 密文
* @return
*/
public String Base64Encode(String res) {
return Base64.encode(res.getBytes());
}
/**
* 使用Base64进行解密
*
* @param res
* @return
*/
public String Base64Decode(String res) {
return new String(Base64.decode(res));
}
private static final int length = 128;
/**
* 加密
*
* @param content 需要加密的内容
* @param password 加密密码
* @return
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws UnsupportedEncodingException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
private static byte[] encrypt(String content, String password)
throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(password.getBytes());
kgen.init(length, secureRandom);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(byteContent);
return result; // 加密
}
/**
* 解密
*
* @param content 待解密内容
* @param password 解密密钥
* @return
*/
private static byte[] decrypt(byte[] content, String password)
throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(password.getBytes());
kgen.init(length, secureRandom);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(content);
return result; // 加密
}
/**
* 加密
*
* @param content 需要加密的内容
* @param password 加密密码
* @return
*/
public static byte[] encrypt2(String content, String password) {
try {
SecretKeySpec key = new SecretKeySpec(password.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(byteContent);
return result; // 加密
} catch (NoSuchAlgorithmException | NoSuchPaddingException | UnsupportedEncodingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
@Deprecated
public static String AESencode(String content, String password) {
try {
byte[] encryptResult = encrypt(content, password);
return Base64.encode(encryptResult);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Deprecated
public static String AESdecode(String content, String password) {
try {
byte[] decryptResult = decrypt(Base64.decode(content), password);
return new String(decryptResult, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
return content;
}
}
public static boolean isBase64(String str) {
String base64Pattern = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$";
return Pattern.matches(base64Pattern, str);
}
public static void main(String[] args) {
// String s = AESencode("430602200007025537", "wfwbkdyrdmr");
// System.out.println(s);
// String s = AESencode("18058743226", "gsdfeygasfw");
// String s1 = AESencode("张三", "gsdfeygasfw");
// System.out.println(s);
// System.out.println(s1);
// System.out.println(Arrays.toString(Base64.decode("5vpdaf8bTigPCRakqzIZXA==")));
// String s = AESdecode("Lsz+2WDokzxEuAaoZYf0cQ==", "gsdfeygasfw");
//
// String phone = AESdecode("j6rj21kehQqc4JJS4NxTug==", "fdsasdfsdds");
// System.out.println("phone:" + phone);
// String s = AESencode("18058743226", "gsdfeygasfw");
// String s1 = AESdecode("CVr/+AgX/sHe00OQnXet9Q==", "wfwbkdyrdmr");许
// System.out.println(s1);
// String s = AESencode("13750869639", "gsdfeygasfw");
// System.out.println(s);
// System.out.println(AESdecode("O1ZWNkiAaIJLDGzwAaTfug==","gsdfeygasfw"));
// String a = AESdecode("罗娜","wfwbkdyrdmr");
// System.out.println(a);
// System.out.println(MD5Utils.encrypt(a));
// System.out.println(AESencode("17707051035","gsdfeygasfw"));
System.out.println(AESdecode("W+/dxhwi5yBWiDnqtLKY+w==", "gsdfeygasfw"));
System.out.println(AESdecode("J88FbYTTmTeKXfIBBedw1A==", "gsdfeygasfw"));
}
/***
* 利用Apache的工具类实现SHA-256加密
* @param str 加密后的报文
* @return
*/
public static String getSHA256Str(String str){
MessageDigest messageDigest;
String encdeStr = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
byte[] hash = messageDigest.digest(str.getBytes(StandardCharsets.UTF_8));
encdeStr = Hex.encodeHexString(hash);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return encdeStr;
}
/**
* 用 AES 算法加密 inputStr。
* 使用 secretStr 作为 keyivStr作为 iv。
* 并对加密后的字节数组调用 sun.misc.BASE64Encoder.encode 方法,
* 转换成 base64 字符串返回。
*
* (仅作为测试用途,具体加密流程以接口文档为准)
*
* @param secretStr
* @param inputStr
* @return
*/
public static String base64StrDecode(String secretStr, String ivStr, String inputStr){
byte[] inputBytes;
inputBytes = org.apache.commons.codec.binary.Base64.decodeBase64(inputStr);
String outputStr = new String(decode(secretStr, ivStr, inputBytes), CHARSET);
System.out.println("base64Decode > base64 decrypt " + outputStr);
return outputStr.trim();
}
/**
* 用 AES 算法解密 inputStr。
* 使用 secretStr 作为 keyivStr作为 iv。
*
* @param secretStr
* @param ivStr
* @return
*/
public static byte[] decode(String secretStr, String ivStr, byte[] inputBytes){
if (keyStrSize != secretStr.length() || ivStrSize != ivStr.length()) {
return null;
}
byte[] secretKeyBytes = secretStr.getBytes(CHARSET);
byte[] ivBytes = ivStr.getBytes(CHARSET);
byte[] outputBytes = decryptCBCNoPadding(secretKeyBytes, ivBytes, inputBytes);
return outputBytes;
}
/**
* AES/CBC/NoPadding decrypt
* 16 bytes secretKeyStr
* 16 bytes intVector
*
* @param secretKeyBytes
* @param intVectorBytes
* @param input
* @return
*/
public static byte[] decryptCBCNoPadding(byte[] secretKeyBytes, byte[] intVectorBytes, byte[] input) {
try {
IvParameterSpec iv = new IvParameterSpec(intVectorBytes);
SecretKey secretKey = new SecretKeySpec(secretKeyBytes, AES);
Cipher cipher = Cipher.getInstance(AES_CBC_NOPADDING);
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] encryptBytes = cipher.doFinal(input);
return encryptBytes;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* DES 加密加密模式 ECB填充方式 Pkcs7输出方式 Base64字符集 utf8
* @param data
* @param password
* @return
*/
public static String encryptECBPkcs7(String data, String password) {
if (password== null || password.length() < 8) { throw new RuntimeException("加密失败key不能小于8位"); }
if(StringUtils.isBlank(data)){ return null; }
try {
//下面这行在进行PKCS7Padding加密时必须加上否则报错
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
//根据传入的秘钥内容生成符合DES加密解密格式的秘钥内容
DESKeySpec dks = new DESKeySpec(password.getBytes());
//获取DES秘钥生成器对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
// 生成秘钥key的长度不能够小于8位字节
Key secretKey = keyFactory.generateSecret(dks);
//获取DES/ECB/PKCS7Padding该种级别的加解密对象
Cipher cipher = Cipher.getInstance(DES_ECB_PKCS7PADDING);
//初始化加解密对象【opmode:确定是加密还是解密模式secretKey是加密解密所用秘钥】
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] bytes = cipher.doFinal(data.getBytes(CHARSET));
return Base64.encode(bytes);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String decryptECBPkcs7(String data, String password) {
if (password== null || password.length() < 8) { throw new RuntimeException("解密失败key不能小于8位"); }
if(StringUtils.isBlank(data)){ return null; }
try {
//下面这行在进行PKCS7Padding加密时必须加上否则报错
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
//根据传入的秘钥内容生成符合DES加密解密格式的秘钥内容
DESKeySpec dks = new DESKeySpec(password.getBytes());
//获取DES秘钥生成器对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
// 生成秘钥key的长度不能够小于8位字节
Key secretKey = keyFactory.generateSecret(dks);
//获取DES/ECB/PKCS7Padding该种级别的加解密对象
Cipher cipher = Cipher.getInstance(DES_ECB_PKCS7PADDING);
//初始化加解密对象【opmode:确定是加密还是解密模式secretKey是加密解密所用秘钥】
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return new String(cipher.doFinal(Base64.decode(data.getBytes(charset))), charset);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* AES加密
* @param content 内容
* @param password 密钥
* @return 加密后数据
*/
public static byte[] encryptECBPkcs5(byte[] content, byte[] password) {
if (content == null || password == null)
return null;
try {
Cipher cipher = Cipher.getInstance(AES_ECB_PKCS5PADDING);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(password, AES));
return cipher.doFinal(content);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* AES解密
* @param content 加密内容
* @param password 密钥
* @return 解密后数据
*/
public static byte[] decryptECBPkcs5(byte[] content, byte[] password) {
if (content == null || password == null)
return null;
try {
Cipher cipher = Cipher.getInstance(AES_ECB_PKCS5PADDING);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(password, AES));
return cipher.doFinal(content);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@@ -0,0 +1,483 @@
package com.ruoyi.common.core.utils;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
/**
* @program: JieYiHua-Cloud
* @description: 时间工具类
* @author: LiYu
* @create: 2021-08-04 15:45
**/
public class LocalDateTimeUtils {
/**
* 获取指定日期所属周的周一的日期
*
* @param localDate
* @return
*/
public static LocalDateTime getMondayForThisWeek(LocalDate localDate) {
LocalDateTime monday = LocalDateTime.of(localDate, LocalTime.MIN).with(DayOfWeek.MONDAY);
return monday;
}
/**
* 获取指定日期所属周的周日的日期
*
* @param localDate
* @return
*/
public static LocalDateTime getSundayForThisWeek(LocalDate localDate) {
LocalDateTime sunday = LocalDateTime.of(localDate, LocalTime.MIN).with(DayOfWeek.SUNDAY);
return sunday;
}
/**
* 获取指定日期所属周的下周一的日期
*
* @param localDate
* @return
*/
public static LocalDateTime getMondayForNextWeek(LocalDate localDate) {
LocalDateTime monday = LocalDateTime.of(localDate, LocalTime.MIN).plusWeeks(1).with(DayOfWeek.MONDAY);
return monday;
}
/**
* 获取指定日期所属周的下周日的日期
*
* @param localDate
* @return
*/
public static LocalDateTime getSundayForNextWeek(LocalDate localDate) {
LocalDateTime sunday = LocalDateTime.of(localDate, LocalTime.MIN).plusWeeks(1).with(DayOfWeek.SUNDAY);
return sunday;
}
/**
* 指定格式为"yyyy-MM-dd HH:mm:ss"的字符串时间转化为LocalDateTime类型
*
* @param dateStr
* @return
*/
public static LocalDateTime getLocalDateTimeFromString(String dateStr) {
LocalDateTime localDateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
return localDateTime;
}
/**
* 指定格式为"yyyy-MM-ddTHH:mm:ss"的字符串时间转化为LocalDateTime类型
*
* @param dateStr
* @return
*/
public static LocalDateTime getLocalDateTimeFromString2(String dateStr) {
LocalDateTime localDateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd w hh:mm:ss"));
return localDateTime;
}
/**
* LocalDateTime类型转化为格式为"yyyy-MM-dd HH:mm:ss"的字符串时间类型
*
* @param localDateTime
* @return
*/
public static String getStringFromLocalDateTime(LocalDateTime localDateTime) {
String localDateTimeStr = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
return localDateTimeStr;
}
/**
* LocalDateTime类型转化为格式为"yyyy-MM-dd"的字符串时间类型
*
* @param localDateTime 时间
* @return 结果
*/
public static String getStringFromLocalDateTime2(LocalDateTime localDateTime) {
if (localDateTime == null) { return null; }
return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}
/**
* LocalDateTime类型转化为格式为"yyyy-MM-dd HH"的字符串时间类型
*
* @param localDateTime 时间
* @return 结果
*/
public static String getStringFromLocalDateTime4(LocalDateTime localDateTime) {
if (localDateTime == null) { return null; }
return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH"));
}
/**
* LocalDateTime类型转化为格式为"yyyy-MM"的字符串时间类型
*/
public static String getStringFromLocalDateTime3(LocalDateTime localDateTime) {
if (localDateTime == null) {
return null;
}
return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM"));
}
/**
* Date类型时间转化为LocalDateTime类型
*
* @param date
* @return
*/
public static LocalDateTime getLocalDateTimeFromDate(Date date) {
LocalDateTime localDateTime = date.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime();
return localDateTime;
}
/**
* LocalDateTime类型转化为Date类型时间
*
* @param localDateTime
* @return
*/
public static Date getDateFromLocalDateTime(LocalDateTime localDateTime) {
Date date = Date.from(localDateTime.toInstant(ZoneOffset.of("+8")));
return date;
}
/**
* 获取指定时间的00:00:00
*
* @param localDateTime
* @return
*/
public static LocalDateTime getLocalDateTimeForBegin(LocalDateTime localDateTime) {
LocalDateTime begin = LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MIN);
return begin;
}
/**
* 获取指定时间的23:59:59
*
* @param localDateTime
* @return
*/
public static LocalDateTime getLocalDateTimeForEnd(LocalDateTime localDateTime) {
LocalDateTime end = LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MAX);
return end;
}
/**
* 时间戳(毫秒)转化为LocalDateTime格式
*
* @param timestamp
* @return
*/
public static LocalDateTime getLocalDateTimeFromTimestamp(Long timestamp) {
LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(timestamp / 1000, 0, ZoneOffset.ofHours(8));
return localDateTime;
}
/**
* LocalDateTime格式转化为时间戳(毫秒)
*
* @param localDateTime
* @return
*/
public static Long getTimestampFromLocalDateTime(LocalDateTime localDateTime) {
Long timestamp = localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
return timestamp;
}
/**
* 时间戳(毫秒)转 yyyy-MM-dd HH:mm:ss
* @param timestamp
* @return
*/
public static String getStringFromTimestamp(Long timestamp) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return dateFormat.format(timestamp);
}
/**
* 获取本月开始时间
*
* @return 开始时间
*/
public static LocalDateTime getFirstDayOfMonth() {
return LocalDateTime.of(LocalDate.from(LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth())), LocalTime.MIN);
}
/**
* 获取月初
*
* @param localDateTime 时间
* @return 数据
*/
public static LocalDateTime getTheBeginningOfTheMonth(LocalDateTime localDateTime) {
return LocalDateTime.of(LocalDate.from(localDateTime.with(TemporalAdjusters.firstDayOfMonth())), LocalTime.MIN);
}
/**
* 获取本月结束时间
*
* @return 结束时间
*/
public static LocalDateTime getLastDay() {
return LocalDateTime.of(LocalDate.from(LocalDateTime.now().with(TemporalAdjusters.lastDayOfMonth())), LocalTime.MAX);
}
public static LocalDateTime getTheEndOfTheMonth(LocalDateTime localDateTime) {
return LocalDateTime.of(LocalDate.from(localDateTime.with(TemporalAdjusters.lastDayOfMonth())), LocalTime.MAX);
}
/**
* 获取时间差 (秒)
*
* @param startTime 开始时间
* @param endTime 结束时间
* @return 秒
*/
public static Long getTimeDifference(LocalDateTime startTime, LocalDateTime endTime) {
Duration duration = Duration.between(startTime, endTime);
return duration.toMinutes() * 60;
}
/**
* 获取两个时间差 (天数)
*
* @param localDateTime 时间
* @return 天数
*/
public static Long timeDifferenceByDay(LocalDateTime localDateTime) {
LocalDateTime now = LocalDateTime.now();
Duration duration = Duration.between(localDateTime, now);
return duration.toDays();
}
/**
* 获取两天时间间隔
*
* @param startingTime 开始时间
* @param endTime 结束时间
* @return 结果
*/
public static Long twoDayInterval(LocalDateTime startingTime, LocalDateTime endTime) {
Duration duration = Duration.between(startingTime, endTime);
return duration.toDays();
}
/**
* 转白话
*
* @param localDateTime 时间
* @return 字符串
*/
public static String toTheVernacular(LocalDateTime localDateTime) {
return localDateTime.getYear() + "" + localDateTime.getMonthValue() + "" + localDateTime.getDayOfMonth() + "";
}
/**
* 获取昨天
*
* @return 获取昨天
*/
public static LocalDateTime getYesterdaySDate() {
return LocalDateTime.now().plusDays(1);
}
/**
* 获取昨天
*
* @return 获取昨天
*/
public static LocalDateTime getMinusDays() {
return LocalDateTime.now().minusDays(1);
}
/**
* 获取明天
*
* @return 获取明天
*/
public static LocalDateTime getPlusDays() {
return LocalDateTime.now().plusDays(1);
}
/**
* 获取今年开始时间
*
* @return 开始时间
*/
public static LocalDateTime startThisYear() {
return LocalDateTime.of(LocalDate.from(LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear())), LocalTime.MIN);
}
/**
* 根据日期获取 星期 2019-05-06 ——> 星期一)
*
* @param datetime
* @return
*/
public static int dateToWeek(LocalDateTime datetime) {
//获取当前时间
LocalDateTime currentDate = LocalDateTime.now();
//获取当前周
int week = currentDate.getDayOfWeek().getValue();
System.out.println("获取当前周:" + week);
return week;
}
public static void main(String[] args) {
System.out.println(twoDayInterval(LocalDateTime.now(),LocalDateTime.now()));
System.out.println(getNowBeforeHourTime(-24L));
}
/**
* 获取今天开始时间
*
* @return 结果
*/
public static LocalDateTime getTodayStartTime() {
return getLocalDateTimeForBegin(LocalDateTime.now());
}
/**
* 获取今天结束时间
*
* @return 结果
*/
public static LocalDateTime getTodayEndTime() {
return getLocalDateTimeForEnd(LocalDateTime.now());
}
/**
* 相隔所有时间
*
* @param startingTime 开始时间
* @param endTime 结束时间
* @return 结果
*/
public static List<String> allTimeApart(String startingTime, String endTime) {
Long size = LocalDateTimeUtils.twoDayInterval(LocalDateTimeUtils.getLocalDateTimeFromString(startingTime), LocalDateTimeUtils.getLocalDateTimeFromString(endTime));
List<String> list = new ArrayList<>(Math.toIntExact(size));
LocalDateTime time = getLocalDateTimeFromString(endTime);
for (int i = 0; i <= size; i++) {
LocalDateTime localDateTime = time.minusDays(i);
list.add(getStringFromLocalDateTime2(localDateTime));
}
return list;
}
/**
* 判断当前用户登录时段是否在09:00-18:00
* @param
* @return
*/
public static boolean setFirstLogTime(){
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm");//获取时,分
//当前系统时间
Date data = new Date();
String dateString = formatter.format(data);
String format = "HH:mm";
try{
Date nowTime = new SimpleDateFormat(format).parse(dateString);
Date startTime = new SimpleDateFormat(format).parse("09:00");
Date endTime = new SimpleDateFormat(format).parse("18:00");
return isEffectiveDate(nowTime, startTime, endTime);
}catch (Exception e){
e.printStackTrace();
return false;
}
}
/**
* 判断当前时间是否在[startTime, endTime]区间,注意时间格式要一致
*
* @param nowTime 当前时间
* @param startTime 开始时间
* @param endTime 结束时间
* @return
*/
public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
if (nowTime.getTime() == startTime.getTime() || nowTime.getTime() == endTime.getTime()) {
return true;
}
Calendar date = Calendar.getInstance();
date.setTime(nowTime);
Calendar begin = Calendar.getInstance();
begin.setTime(startTime);
Calendar end = Calendar.getInstance();
end.setTime(endTime);
if (date.after(begin) && date.before(end)) {
return true;
} else {
return false;
}
}
/**
* 判断当前日期是否大于某个日期
* @param date yyyy-MM-dd
* @return
*/
public static boolean afterDate(LocalDateTime date){
//针对好享管家图片相反
String times = "2022-08-23";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
//把String转为LocalDate
LocalDate localTime=LocalDate.parse(times,dtf);
//判断当前日期是否大于指定日期
return date.toLocalDate().isAfter(localTime);
}
/**
* 获取当前时间指定偏移多长小时前的时间
* @param hour 负向前偏移 正向后偏移
* @return
*/
public static LocalDateTime getNowBeforeHourTime(Long hour){
LocalDateTime localDateTime = LocalDateTime.now(ZoneId.systemDefault());
return localDateTime.plusHours(hour);
}
public static Long timeDifferenceByLocalDate(LocalDateTime localDateTime) {
LocalDate toLocalDate = localDateTime.toLocalDate();
LocalDate now = LocalDate.now();
long until = toLocalDate.until(now, ChronoUnit.DAYS);
return toLocalDate.until(now, ChronoUnit.DAYS);
}
/**
* 判断时间是否是今天
* @param localDateTime 时间
* @return 结果
*/
public static boolean isToday(LocalDateTime localDateTime) {
return localDateTime.toLocalDate().equals(LocalDate.now());
}
/**
* 判断日期是否是指定天数内
* @param localDateTime 时间
* @param day 天数
* @return 结果
*/
public static boolean isDay(LocalDateTime localDateTime,Long day) {
return localDateTime.toLocalDate().equals(LocalDate.now().plusDays(day));
}
public static long getTimeStamp(String dateTime){
LocalDateTime time = LocalDateTimeUtils.getLocalDateTimeFromString(dateTime);
return time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
}

View File

@@ -0,0 +1,155 @@
package com.ruoyi.common.core.utils;
import com.ruoyi.common.core.domain.GuestProbabilityReq;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.util.*;
/**
* 计算助贷计划概率
* @Author: daisi
* @Date: 2022/4/2 11:10
*/
@Slf4j
public class ProbitUtil {
public static GuestProbabilityReq calculatePlanTheProbability(List<GuestProbabilityReq> guestProbabilityReqs) {
//按排序价格排序
Collections.sort(guestProbabilityReqs, new Comparator<GuestProbabilityReq>() {
@Override
public int compare(GuestProbabilityReq o1, GuestProbabilityReq o2) {
return o2.getOrderPrice().compareTo(o1.getOrderPrice());
}
});
List<GuestProbabilityReq> list = new ArrayList<>(5);
for (GuestProbabilityReq guestProbabilityReq : guestProbabilityReqs) {
// if (guestProbabilityReq.getOrderPrice().compareTo(guestProbabilityReqs.get(0).getOrderPrice()) == 0) {
// list.add(guestProbabilityReq);
// }
list.add(guestProbabilityReq);
}
log.info("排序后的数据:{}",list);
//重置概率
resetTranslate(list);
int index = drawGift(list);
return guestProbabilityReqs.get(index);
}
private static List<GuestProbabilityReq> resetTranslate(List<GuestProbabilityReq> reqs) {
if (reqs.size()!=1){
//高值得一部分
int count = 0;
//获取计数
BigDecimal orderPrice = reqs.get(0).getOrderPrice();
for (int i = 0; i < reqs.size(); i++) {
if (i+1<reqs.size()&&reqs.get(i).getOrderPrice().compareTo(reqs.get(i+1).getOrderPrice())==0&&orderPrice.compareTo(reqs.get(i).getOrderPrice())==0){
count++;
}
}
///获取最高的概率
BigDecimal bigDecimal = new BigDecimal(reqs.get(0).getGuestProbability().toString());
if (count!=0){
//用最高的概率除以计数 得到最高价的平均概率
BigDecimal divide = bigDecimal.divide(new BigDecimal(count+1),3,BigDecimal.ROUND_DOWN);
for (int i = 0; i <= count; i++) {
//循环重设最高概率
reqs.get(i).setGuestProbability(divide.doubleValue());
}
}
//低值得一部分
BigDecimal remTotal = new BigDecimal(1).subtract(bigDecimal);
BigDecimal b = remTotal.divide(new BigDecimal((reqs.size()-count-1)==0?1:(reqs.size()-count-1)),3,BigDecimal.ROUND_HALF_UP);
for (int i = count+1; i < reqs.size(); i++) {
reqs.get(i).setGuestProbability(b.doubleValue());
}
}
//log.info("重置概率后的概率,{}",reqs);
return reqs;
}
public static int drawGift(List<GuestProbabilityReq> guestProbabilityReqList) {
if (null != guestProbabilityReqList && guestProbabilityReqList.size() > 0) {
List<Double> orgProbList = new ArrayList<Double>(guestProbabilityReqList.size());
for (GuestProbabilityReq guest : guestProbabilityReqList) {
//按顺序将概率添加到集合中
orgProbList.add(guest.getGuestProbability());
}
return draw(orgProbList);
}
return -1;
}
public static int draw(List<Double> giftProbList) {
List<Double> sortRateList = new ArrayList<Double>();
// 计算概率总和
Double sumRate = 0D;
for (Double prob : giftProbList) {
sumRate += prob;
}
if (sumRate != 0) {
double rate = 0D; //概率所占比例
for (Double prob : giftProbList) {
rate += prob;
// 构建一个比例区段组成的集合(避免概率和不为1)
sortRateList.add(rate / sumRate);
}
// 随机生成一个随机数,并排序
double random = Math.random();
sortRateList.add(random);
Collections.sort(sortRateList);
// 返回该随机数在比例集合中的索引
return sortRateList.indexOf(random);
}
return -1;
}
// public static void main(String[] args) {
//// System.out.println(LocalDateTimeUtils.getStringFromLocalDateTime(LocalDateTimeUtil.beginOfDay(LocalDateTimeUtil.offset(LocalDateTime.now(), -7, ChronoUnit.DAYS))));
//// System.out.println(LocalDateTimeUtils.getStringFromLocalDateTime(LocalDateTimeUtil.endOfDay(LocalDateTimeUtil.offset(LocalDateTime.now(), -1, ChronoUnit.DAYS))));
// int a=0;
// List<GuestProbabilityReq> guestProbabilityReqs = new ArrayList<>();
// for (int i = 0; i < 20; i++) {
// List<GuestProbabilityReq> list = new ArrayList<>();
// GuestProbabilityReq req = new GuestProbabilityReq();
// req.setPlanId(1L).setOrderPrice(new BigDecimal(104.00)).setGuestProbability(0.8D);
//
// GuestProbabilityReq req1 = new GuestProbabilityReq();
// req1.setPlanId(2L).setOrderPrice(new BigDecimal(120)).setGuestProbability(0.8D);
//
// GuestProbabilityReq req2 = new GuestProbabilityReq();
// req2.setPlanId(3L).setOrderPrice(new BigDecimal(90)).setGuestProbability(0.8D);
//
// GuestProbabilityReq req3 = new GuestProbabilityReq();
// req3.setPlanId(4L).setOrderPrice(new BigDecimal(110)).setGuestProbability(0.4D);
//
// GuestProbabilityReq req4 = new GuestProbabilityReq();
// req4.setPlanId(5L).setOrderPrice(new BigDecimal(110)).setGuestProbability(0.6D);
////
//// GuestProbabilityReq req5 = new GuestProbabilityReq();
//// req5.setPlanId(6L).setOrderPrice(new BigDecimal(80)).setGuestProbability(0.6D);
//
// list.add(req);
// list.add(req1);
// list.add(req2);
// list.add(req3);
// list.add(req4);
//// list.add(req5);
//
// guestProbabilityReqs.add(calculatePlanTheProbability(list));
//
// }
// int b = 0;
// int c = 0;
// for (GuestProbabilityReq req:guestProbabilityReqs) {
// if (req.getPlanId()==2){
// b++;
// }else {
// c++;
// }
// }
// System.out.println("几率:"+c+" "+b);
// }
}

View File

@@ -0,0 +1,517 @@
package com.ruoyi.common.core.utils;
import com.ruoyi.common.core.constant.HttpStatus;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Objects;
import java.util.Random;
import java.util.regex.Pattern;
/**
* @author LiYu
* @ClassName SecureUtil.java
* @Description 加解密工具类
* @createTime 2024年05月20日 11:04:00
*/
@Slf4j
public class SecureUtils {
/**
* md5加密
*/
public static class Md5Util {
/**
* 判断是否为md5加密
*
* @param str 字符串
* @return 结果
*/
public static boolean isMd5(String str) {
return str.matches("^[a-f0-9]{32}$");
}
/**
* MD5加密并转大写
*
* @param str 字符串
* @return 结果
*/
public static String md5ToUpperCase(String str) {
return StringUtils.hasText(str) ? isMd5(str) ? str : cn.hutool.crypto.SecureUtil.md5(str).toUpperCase() : null;
}
/**
* MD5加密并转小写
*
* @param str 字符串
* @return 结果
*/
public static String md5ToLowerCase(String str) {
return StringUtils.hasText(str) ? isMd5(str) ? str : cn.hutool.crypto.SecureUtil.md5(str).toLowerCase() : null;
}
/**
* MD5加密
*
* @param str 字符串
* @return 结果
*/
public static String md5(String str) {
return StringUtils.hasText(str) ? isMd5(str) ? str : cn.hutool.crypto.SecureUtil.md5(str) : null;
}
}
/**
* des加密
*/
public static class DesUtil {
/**
* 加密key
*/
public static final String KEY = "_@Ks`Y*9jLb.hvho}C;GwDpw";
/**
* 偏移量
*/
public static final String IV = "2%8iTpSi";
/**
* 创建加密对象
*
* @param iv 偏移量
* @param mode 模式
* @return 结果
*/
private static Cipher createCipher(String iv, int mode) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, InvalidAlgorithmParameterException {
byte[] key = KEY.getBytes();
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
cipher.init(mode, new SecretKeySpec(key, "DESede"), ivParameterSpec);
return cipher;
}
/**
* 加密
*
* @param data 数据
* @param iv 偏移量
* @return 结果
*/
public static String encrypt(String data, String iv) {
try {
Cipher cipher = createCipher(iv, Cipher.ENCRYPT_MODE);
return URLEncoder.encode(Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes())), "UTF-8");
} catch (Exception e) {
log.error("加密失败", e);
}
return null;
}
/**
* 加密
*
* @param data 数据
* @return 结果
*/
public static String encrypt(String data) {
return encrypt(data, IV);
}
/**
* 解密
*
* @param data 数据
* @param iv 偏移量
* @return 结果
*/
public static String decrypt(String data, String iv) {
try {
Cipher cipher = createCipher(iv, Cipher.DECRYPT_MODE);
return new String(cipher.doFinal(Base64.getDecoder().decode(URLDecoder.decode(data, "UTF-8"))));
} catch (Exception e) {
log.error("解密失败", e);
}
return null;
}
/**
* 解密
*
* @param data 数据
* @return 结果
*/
public static String decrypt(String data) {
return decrypt(data, IV);
}
}
/**
* AES加解密
*/
public static class AesUtil {
/**
* 加密模式之 ECB算法/模式/补码方式
*/
public static final String AES_ECB = "AES/ECB/PKCS5Padding";
/**
* 加密模式之 CBC算法/模式/补码方式
*/
public static final String AES_CBC = "AES/CBC/PKCS5Padding";
/**
* 加密模式之 CFB算法/模式/补码方式
*/
public static final String AES_CFB = "AES/CFB/PKCS5Padding";
/**
* AES 中的 IV 必须是 16 字节128位
*/
public static final Integer IV_LENGTH = 16;
/***
* 空校验
* @param str 需要判断的值
*/
public static boolean isEmpty(Object str) {
return null == str || "".equals(str);
}
/***
* String 转 byte
* @param str 需要转换的字符串
*/
public static byte[] getBytes(String str) {
if (isEmpty(str)) {
return null;
}
try {
return str.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/***
* 初始化向量IV它是一个随机生成的字节数组用于增加加密和解密的安全性
*/
public static String getIv() {
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < IV_LENGTH; i++) {
int number = random.nextInt(str.length());
sb.append(str.charAt(number));
}
return sb.toString();
}
/***
* 获取一个 AES 密钥规范
*/
public static SecretKeySpec getSecretKeySpec(String key) {
return new SecretKeySpec(Objects.requireNonNull(getBytes(key)), "AES");
}
/**
* 加密 - 模式 ECB
*
* @param text 需要加密的文本内容
* @param key 加密的密钥 key
*/
public static String encrypt(String text, String key) {
if (isEmpty(text) || isEmpty(key)) {
return null;
}
try {
// 创建AES加密器
Cipher cipher = Cipher.getInstance(AES_ECB);
SecretKeySpec secretKeySpec = getSecretKeySpec(key);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
// 加密字节数组
byte[] encryptedBytes = cipher.doFinal(Objects.requireNonNull(getBytes(text)));
// 将密文转换为 Base64 编码字符串
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 解密 - 模式 ECB
*
* @param text 需要解密的文本内容
* @param key 解密的密钥 key
*/
public static String decrypt(String text, String key) {
if (isEmpty(text) || isEmpty(key)) {
return null;
}
// 将密文转换为16字节的字节数组
byte[] textBytes = Base64.getDecoder().decode(text);
try {
// 创建AES加密器
Cipher cipher = Cipher.getInstance(AES_ECB);
SecretKeySpec secretKeySpec = getSecretKeySpec(key);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
// 解密字节数组
byte[] decryptedBytes = cipher.doFinal(textBytes);
// 将明文转换为字符串
return new String(decryptedBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 加密 - 自定义加密模式
*
* @param text 需要加密的文本内容
* @param key 加密的密钥 key
* @param iv 初始化向量
* @param mode 加密模式
*/
public static String encrypt(String text, String key, String iv, String mode) {
if (isEmpty(text) || isEmpty(key) || isEmpty(iv)) {
return null;
}
try {
// 创建AES加密器
Cipher cipher = Cipher.getInstance(mode);
SecretKeySpec secretKeySpec = getSecretKeySpec(key);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(Objects.requireNonNull(getBytes(iv))));
// 加密字节数组
byte[] encryptedBytes = cipher.doFinal(Objects.requireNonNull(getBytes(text)));
// 将密文转换为 Base64 编码字符串
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 加密
*
* @param content 待加密内容
* @param password 加密密钥
* @return 加密后的内容
*/
public static String AesEncode(String content, String password) {
try {
byte[] encryptResult = encryptByte(content, password);
return Base64Util.encode(encryptResult);
} catch (Exception e) {
log.error("加密出现问题!", e);
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
String s = "{\"accumulationFund\":1,\"age\":18,\"car\":1,\"career\":1,\"city\":\"重庆\",\"cityCode\":1000,\"creditCard\":1,\"education\":1,\"guarantee\":1,\"hourse\":1,\"idCardMd5\":\"331d17d1ca8a091410e3238fab16a863\",\"monthlyIncome\":5000,\"nameMd5\":\"331d17d1ca8a091410e3238fab16a863\",\"phoneMd5\":\"331d17d1ca8a091410e3238fab16a863\",\"sex\":0,\"socialSecurity\":1,\"zhiMa\":600}";
String s1 = "{\"accumulationFund\":1,\"age\":18,\"car\":1,\"career\":1,\"city\":\"重庆\",\"cityCode\":1000,\"creditCard\":1,\"education\":1,\"guarantee\":1,\"hourse\":1,\"idCard\":\"341202199306023511\",\"idCardMd5\":\"331d17d1ca8a091410e3238fab16a863\",\"monthlyIncome\":5000,\"name\":\"朱三\",\"nameMd5\":\"331d17d1ca8a091410e3238fab16a863\",\"phone\":\"15205600635\",\"phoneMd5\":\"331d17d1ca8a091410e3238fab16a863\",\"sex\":0,\"socialSecurity\":1,\"zhiMa\":600}";
String s3 = "{\n" +
" \"orderNo\":\"111111\",\n" +
" \"md5\":\"aaaaaa\",\n" +
" \"price\":100.00,\n" +
" \"orderStatus\":\"2\"\n" +
"}";
System.out.println(AesEncode(s1,"g5N8XTYaOEwEmBgg"));
}
/**
* 解密
*
* @param content 待解密内容
* @param password 解密密钥
* @return 解密后的内容
*/
public static String AesDecode(String content, String password) {
try {
byte[] decryptResult = decryptByte(Base64Util.decodeToByteArray(content), password);
return new String(decryptResult, StandardCharsets.UTF_8);
} catch (Exception e) {
log.error("解密出现问题!", e);
return null;
}
}
/**
* 加密 - 模式 CBC
*
* @param text 需要加密的文本内容
* @param key 加密的密钥 key
* @param iv 初始化向量
* @return 加密后的内容
*/
public static String encryptCbc(String text, String key, String iv) {
return encrypt(text, key, iv, AES_CBC);
}
/**
* 解密 - 自定义加密模式
*
* @param text 需要解密的文本内容
* @param key 解密的密钥 key
* @param iv 初始化向量
* @param mode 加密模式
*/
public static String decrypt(String text, String key, String iv, String mode) {
if (isEmpty(text) || isEmpty(key) || isEmpty(iv)) {
return null;
}
// 将密文转换为16字节的字节数组
byte[] textBytes = Base64.getDecoder().decode(text);
try {
// 创建AES加密器
Cipher cipher = Cipher.getInstance(mode);
SecretKeySpec secretKeySpec = getSecretKeySpec(key);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(Objects.requireNonNull(getBytes(iv))));
// 解密字节数组
byte[] decryptedBytes = cipher.doFinal(textBytes);
// 将明文转换为字符串
return new String(decryptedBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 解密
*
* @param content 待解密内容
* @param password 解密密钥
* @return 解密后的内容
*/
private static byte[] decryptByte(byte[] content, String password)
throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(password.getBytes());
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(content);
}
/**
* 加密
*
* @param content 需要加密的内容
* @param password 加密密码
* @return 加密后的字节数组
*/
private static byte[] encryptByte(String content, String password)
throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(password.getBytes());
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(byteContent);
}
/**
* 解密 - 模式 CBC
*
* @param text 需要加密的文本内容
* @param key 加密的密钥 key
* @param iv 初始化向量
* @return 加密后的内容
*/
public static String decryptCbc(String text, String key, String iv) {
return decrypt(text, key, iv, AES_CBC);
}
}
/**
* Base64加解密
*/
public static class Base64Util {
/**
* 编码字符串为Base64
*
* @param input 需要编码的字符串
* @return 编码后的Base64字符串
*/
public static String encode(String input) {
return Base64.getEncoder().encodeToString(input.getBytes());
}
/**
* 从Base64编码解码为字符串
*
* @param input Base64编码的字符串
* @return 解码后的字符串
*/
public static String decode(String input) {
byte[] decodedBytes = Base64.getDecoder().decode(input);
return new String(decodedBytes);
}
/**
* 编码字节数组为Base64字符串
*
* @param input 需要编码的字节数组
* @return 编码后的Base64字符串
*/
public static String encode(byte[] input) {
return Base64.getEncoder().encodeToString(input);
}
/**
* 解码Base64字符串为字节数组
*
* @param input Base64编码的字符串
* @return 解码后的字节数组
*/
public static byte[] decodeToByteArray(String input) {
return Base64.getDecoder().decode(input);
}
/**
* 判断是否为Base64编码
*
* @param str 字符串
* @return 结果
*/
public static boolean isBase64(String str) {
String base64Pattern = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$";
return Pattern.matches(base64Pattern, str);
}
}
public static void main(String[] args) {
}
}

View File

@@ -0,0 +1,456 @@
package com.ruoyi.common.core.utils.match;
import com.ruoyi.common.core.domain.http.Customer;
import com.ruoyi.common.core.domain.http.Merchant;
import lombok.extern.slf4j.Slf4j;
import java.util.Objects;
@Slf4j
public class MatchQualification {
/**
* 是否可以匹配上产品
* @param customer 用户信息
* @param merchant 产品前筛
* openInfoFilter 开启资质筛选 0:不筛选, 1:满足1, 2:满足全部
*
* @return 结构
*/
public static Boolean doesItMatchProduct(Customer customer, Merchant merchant) {
// if (Objects.isNull(merchant)){
// return true;
// }
//
// if (Objects.isNull(merchant.getCustomerInfoFilterType()) || merchant.getCustomerInfoFilterType() == 0){
// return true;
// }
//
// //满足1个
// boolean openOne = merchant.getCustomerInfoFilterType() == 1;
// //满足所有
// boolean openAll = merchant.getCustomerInfoFilterType() == 2;
// //结果
// boolean result = false;
//
// String userInfo = customer.getId() + "-" + customer.getChannelId() + "-" + merchant.getId();
//
// //社保
// if (merchant.getSocialSecurityHigh() || merchant.getSocialSecurityNo() ||merchant.getSocialSecurityLow()) {
// if (openAll && Objects.isNull(customer.getSocialSecurity())){
// log.info("资质匹配筛选, 配置[满足所有]-社保为空, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
// return false;
// }
//
// Integer infoByCode = customer.getSocialSecurity();
// if (Objects.nonNull(customer.getSocialSecurity())) {
// if (merchant.getSocialSecurityNo()) {
// if (customer.getSocialSecurity()==merchant.getSocialSecurityNo())) {
// result = true;
// }
// }
//
// if (merchant.getSocialSecurityLow()) {
// if (customer.getSocialSecurity().equals(CustomerSocialSecurityType.GREAT_SOCIAL_SECURITY.getCode())) {
// result = true;
// }
// }
//
// //条件为 满足一个即可, 恰巧现在就有满足的, 则返回true通过
// if (openOne && result) {
//// log.info("资质匹配筛选, 配置[满足其一]-社保:{}, 匹配通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getSocialSecurity() + "-" + infoByCode, userInfo);
// return result;
// }
// }
//
// //条件为 满足全部, 恰巧现在这个不满足, 则返回false(不通过)
// if (openAll && !result) {
// log.info("资质匹配筛选, 配置[满足所有]-社保:{}, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getSocialSecurity() + "-" + infoByCode, userInfo);
// return false;
// }
// }
//
// //公积金
// if (productLimit.getSmallProvidentFund() || productLimit.getGreatProvidentFund()) {
// if (openAll && Objects.isNull(userDetailsDTO.getProvidentFund())){
// log.info("资质匹配筛选, 配置[满足所有]-公积金为空, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
// return false;
// }
//
// //判断结果置默认
// result = false;
// String infoByCode = CustomerProvidentFundType.getInfoByCode(userDetailsDTO.getProvidentFund());
// if (Objects.nonNull(userDetailsDTO.getProvidentFund())) {
// if (productLimit.getSmallProvidentFund()) {
// if (userDetailsDTO.getProvidentFund().equals(CustomerProvidentFundType.SMALL_PROVIDENT_FUND.getCode())) {
// result = true;
// }
// }
//
// if (productLimit.getGreatProvidentFund()) {
// if (userDetailsDTO.getProvidentFund().equals(CustomerProvidentFundType.GREAT_PROVIDENT_FUND.getCode())) {
// result = true;
// }
// }
//
// //条件为 满足一个即可, 恰巧现在就有满足的, 则返回true通过
// if (openOne && result) {
//// log.info("资质匹配筛选, 配置[满足其一]-公积金:{}, 匹配通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getProvidentFund() + "-" + infoByCode, userInfo);
// return result;
// }
// }
//
// //条件为 满足全部, 恰巧现在这个不满足, 则返回false(不通过)
// if (openAll && !result) {
//// log.info("资质匹配筛选, 配置[满足所有]-公积金:{}, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getProvidentFund() + "-" + infoByCode, userInfo);
// return false;
// }
// }
//
// //车产
// if (productLimit.getHavaCar()) {
// if (openAll && Objects.isNull(userDetailsDTO.getCarProduction())){
// log.info("资质匹配筛选, 配置[满足所有]-车产为空, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
// return false;
// }
//
// //判断结果置默认
// result = false;
// String infoByCode = CustomerCarProductionType.getInfoByCode(userDetailsDTO.getCarProduction());
// if (Objects.nonNull(userDetailsDTO.getCarProduction())) {
// if (userDetailsDTO.getCarProduction().equals(CustomerCarProductionType.HAVE_CAR.getCode())) {
// result = true;
// }
//
// //条件为 满足一个即可, 恰巧现在就有满足的, 则返回true通过
// if (openOne && result) {
// log.info("资质匹配筛选, 配置[满足其一]-车产:{}, 匹配通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getCarProduction() + "-" + infoByCode, userInfo);
// return result;
// }
// }
//
// //条件为 满足全部, 恰巧现在这个不满足, 则返回false(不通过)
// if (openAll && !result) {
// log.info("资质匹配筛选, 配置[满足所有]-车产:{}, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getCarProduction() + "-" + infoByCode, userInfo);
// return false;
// }
// }
//
// //房产
// if (productLimit.getHaveMortgageRoom() || productLimit.getHaveFullRoom()) {
// if (openAll && Objects.isNull(userDetailsDTO.getEstate())){
// log.info("资质匹配筛选, 配置[满足所有]-房产为空, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
// return false;
// }
//
// //判断结果置默认
// result = false;
// String infoByCode = CustomerEstateType.getInfoByCode(userDetailsDTO.getEstate());
// if (Objects.nonNull(userDetailsDTO.getEstate())) {
// if (productLimit.getHaveMortgageRoom()){
// if (userDetailsDTO.getEstate().equals(CustomerEstateType.HAVE_PROPERTY.getCode())){
// result = true;
// }
// }
//
// if (productLimit.getHaveFullRoom()){
// if (userDetailsDTO.getEstate().equals(CustomerEstateType.FULL_PAYMENT_FOR_HOUSING.getCode())){
// result = true;
// }
// }
//
// //条件为 满足一个即可, 恰巧现在就有满足的, 则返回true通过
// if (openOne && result) {
//// log.info("资质匹配筛选, 配置[满足其一]-房产:{}, 匹配通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getEstate() + "-" + infoByCode, userInfo);
// return result;
// }
// }
//
// //条件为 满足全部, 恰巧现在这个不满足, 则返回false(不通过)
// if (openAll && !result) {
// log.info("资质匹配筛选, 配置[满足所有]-房产:{}, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getEstate() + "-" + infoByCode, userInfo);
// return false;
// }
// }
//
// //保单
// if (productLimit.getPolicyLessThanOneYear() || productLimit.getPolicyPaymentForOneYear() || productLimit.getPolicyPaymentForTwoYear()) {
// if (openAll && Objects.isNull(userDetailsDTO.getPersonalInsurance())){
// log.info("资质匹配筛选, 配置[满足所有]-保单为空, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
// return false;
// }
//
// //判断结果置默认
// result = false;
// String infoByCode = CustomerInsurancePolicyType.getInfoByCode(userDetailsDTO.getPersonalInsurance());
// if (Objects.nonNull(userDetailsDTO.getPersonalInsurance())) {
// if (productLimit.getPolicyLessThanOneYear()) {
// if (userDetailsDTO.getPersonalInsurance().equals(CustomerInsurancePolicyType.POLICY_LESS_THAN_ONE_YEAR.getCode())) {
// result = true;
// }
// }
//
// if (productLimit.getPolicyPaymentForOneYear()) {
// if (userDetailsDTO.getPersonalInsurance().equals(CustomerInsurancePolicyType.POLICY_PAYMENT_FOR_ONE_YEAR.getCode())) {
// result = true;
// }
// }
//
// if (productLimit.getPolicyPaymentForTwoYear()) {
// if (userDetailsDTO.getPersonalInsurance().equals(CustomerInsurancePolicyType.POLICY_PAYMENT_FOR_TWO_YEAR.getCode())) {
// result = true;
// }
// }
//
// //条件为 满足一个即可, 恰巧现在就有满足的, 则返回true通过
// if (openOne && result) {
// log.info("资质匹配筛选, 配置[满足其一]-保单:{}, 匹配通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getPersonalInsurance() + "-" + infoByCode, userInfo);
// return result;
// }
// }
//
// //条件为 满足全部, 恰巧现在这个不满足, 则返回false(不通过)
// if (openAll && !result) {
// log.info("资质匹配筛选, 配置[满足所有]-保单:{}, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getPersonalInsurance() + "-" + infoByCode, userInfo);
// return false;
// }
// }
//
// //芝麻分
// if (Objects.nonNull(productLimit.getSesame())){
// if (openAll && Objects.isNull(userDetailsDTO.getSesame())){
// log.info("资质匹配筛选, 配置[满足所有]-芝麻分为空, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
// return false;
// }
//
// //判断结果置默认
// result = false;
// if (Objects.nonNull(userDetailsDTO.getSesame())) {
// if (userDetailsDTO.getSesame() >= productLimit.getSesame()){
// result = true;
// }
//
// //条件为 满足一个即可, 恰巧现在就有满足的, 则返回true通过
// if (openOne && result) {
// log.info("资质匹配筛选, 配置[满足其一]-芝麻分:{}, 匹配通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getSesame(), userInfo);
// return result;
// }
// }
//
// //条件为 满足全部, 恰巧现在这个不满足, 则返回false(不通过)
// if (openAll && !result) {
// log.info("资质匹配筛选, 配置[满足所有]-芝麻分:{}, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getSesame(), userInfo);
// return false;
// }
// }
//
// //职业
// if (productLimit.getOfficeWorker() ||
// productLimit.getCivilServant() ||
// productLimit.getPrivateOwners() ||
// productLimit.getSmallPrivateBusiness() ||
// productLimit.getOtherOccupations()) {
//
// if (openAll && Objects.isNull(userDetailsDTO.getProfessionalIdentity())){
// log.info("资质匹配筛选, 配置[满足所有]-职业为空, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
// return false;
// }
//
// //判断结果置默认
// result = false;
// String infoByCode = CustomerProfessionalIdentityType.getInfoByCode(userDetailsDTO.getProfessionalIdentity());
// if (Objects.nonNull(userDetailsDTO.getProfessionalIdentity())) {
// if (productLimit.getOfficeWorker()){
// if (userDetailsDTO.getProfessionalIdentity().equals(CustomerProfessionalIdentityType.OFFICE_WORKER.getCode())) {
// result = true;
// }
// }
//
// if (productLimit.getCivilServant()){
// if (userDetailsDTO.getProfessionalIdentity().equals(CustomerProfessionalIdentityType.CIVIL_SERVANT.getCode())) {
// result = true;
// }
// }
//
// if (productLimit.getPrivateOwners()){
// if (userDetailsDTO.getProfessionalIdentity().equals(CustomerProfessionalIdentityType.PRIVATE_OWNERS.getCode())) {
// result = true;
// }
// }
//
// if (productLimit.getSmallPrivateBusiness()){
// if (userDetailsDTO.getProfessionalIdentity().equals(CustomerProfessionalIdentityType.SMALL_PRIVATE_BUSINESS.getCode())) {
// result = true;
// }
// }
//
// if (productLimit.getOtherOccupations()){
// if (userDetailsDTO.getProfessionalIdentity().equals(CustomerProfessionalIdentityType.OTHER_OCCUPATIONS.getCode())) {
// result = true;
// }
// }
//
// //条件为 满足一个即可, 恰巧现在就有满足的, 则返回true通过
// if (openOne && result) {
// log.info("资质匹配筛选, 配置[满足其一]-职业:{}, 匹配通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getProfessionalIdentity() + "-" + infoByCode, userInfo);
// return result;
// }
// }
//
// //条件为 满足全部, 恰巧现在这个不满足, 则返回false(不通过)
// if (openAll && !result) {
// log.info("资质匹配筛选, 配置[满足所有]-职业:{}, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getProfessionalIdentity() + "-" + infoByCode, userInfo);
// return false;
// }
// }
//
// //学历 字典映射 1: "初中及以下,2: "高中",3: "中专",4: "大专",5: "本科",6: "研究生及以上"
// if (productLimit.getJuniorMiddleSchool() ||
// productLimit.getSeniorMiddleSchool() ||
// productLimit.getMiddleSchool() ||
// productLimit.getCollege() ||
// productLimit.getUndergraduate() ||
// productLimit.getPostgraduate()) {
//
// if (openAll && Objects.isNull(userDetailsDTO.getEducation())){
// log.info("资质匹配筛选, 配置[满足所有]-学历为空, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
// return false;
// }
//
// //判断结果置默认
// result = false;
// String infoByCode = getEducationByCode(userDetailsDTO.getEducation());
// if (Objects.nonNull(userDetailsDTO.getEducation())) {
// if (productLimit.getJuniorMiddleSchool() && userDetailsDTO.getEducation() == 1) { //初中
// result = true;
// }
//
// if (productLimit.getSeniorMiddleSchool() && userDetailsDTO.getEducation() == 2) { //高中
// result = true;
// }
//
// if (productLimit.getMiddleSchool() && userDetailsDTO.getEducation() == 3) { //中专
// result = true;
// }
//
// if (productLimit.getCollege() && userDetailsDTO.getEducation() == 4) { //大专
// result = true;
// }
//
// if (productLimit.getUndergraduate() && userDetailsDTO.getEducation() == 5) { //本科
// result = true;
// }
//
// if (productLimit.getPostgraduate() && userDetailsDTO.getEducation() == 6) { //研究生
// result = true;
// }
//
// //条件为 满足一个即可, 恰巧现在就有满足的, 则返回true通过
// if (openOne && result) {
// log.info("资质匹配筛选, 配置[满足其一]-学历:{}, 匹配通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getEducation() + "-" + infoByCode, userInfo);
// return result;
// }
// }
//
// //条件为 满足全部, 恰巧现在这个不满足, 则返回false(不通过)
// if (openAll && !result) {
// log.info("资质匹配筛选, 配置[满足所有]-学历:{}, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getEducation() + "-" + infoByCode, userInfo);
// return false;
// }
// }
//
// //白条可用额度 字典映射 1: 无额度,2: 2000以下,3: 2000-10000,4: 大于10000
// if (productLimit.getBaiTiaoLevelOne() ||
// productLimit.getBaiTiaoLevelTwo() ||
// productLimit.getBaiTiaoLevelThree()) {
//
// if (openAll && Objects.isNull(userDetailsDTO.getBaiTiaoQuota())){
// log.info("资质匹配筛选, 配置[满足所有]-白条为空, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
// return false;
// }
//
// //判断结果置默认
// result = false;
// String infoByCode = getBaiTiaoByCode(userDetailsDTO.getBaiTiaoQuota());
// if (Objects.nonNull(userDetailsDTO.getBaiTiaoQuota())) {
// if (productLimit.getBaiTiaoLevelOne() && userDetailsDTO.getBaiTiaoQuota() == 2) { //2000以下
// result = true;
// }
//
// if (productLimit.getBaiTiaoLevelTwo() && userDetailsDTO.getBaiTiaoQuota() == 3) { //2000-10000
// result = true;
// }
//
// if (productLimit.getBaiTiaoLevelThree() && userDetailsDTO.getBaiTiaoQuota() == 4) { //大于10000
// result = true;
// }
//
// //条件为 满足一个即可, 恰巧现在就有满足的, 则返回true通过
// if (openOne && result) {
// log.info("资质匹配筛选, 配置[满足其一]-白条:{}, 匹配通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getBaiTiaoQuota() + "-" + infoByCode, userInfo);
// return result;
// }
// }
//
// //条件为 满足全部, 恰巧现在这个不满足, 则返回false(不通过)
// if (openAll && !result) {
// log.info("资质匹配筛选, 配置[满足所有]-白条:{}, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getBaiTiaoQuota() + "-" + infoByCode, userInfo);
// return false;
// }
// }
//
// //花呗可用额度 字典映射 1: 无额度,2: 2000以下,3: 2000-10000,4: 大于10000
// if (productLimit.getHuaBeiLevelOne() ||
// productLimit.getHuaBeiLevelTwo() ||
// productLimit.getHuaBeiLevelThree()) {
//
// if (openAll && Objects.isNull(userDetailsDTO.getHuaBeiQuota())){
// log.info("资质匹配筛选, 配置[满足所有]-花呗为空, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
// return false;
// }
//
// //判断结果置默认
// result = false;
// String infoByCode = getBaiTiaoByCode(userDetailsDTO.getHuaBeiQuota());
// if (Objects.nonNull(userDetailsDTO.getHuaBeiQuota())) {
// if (productLimit.getHuaBeiLevelOne() && userDetailsDTO.getHuaBeiQuota() == 2) { //2000以下
// result = true;
// }
//
// if (productLimit.getHuaBeiLevelTwo() && userDetailsDTO.getHuaBeiQuota() == 3) { //2000-10000
// result = true;
// }
//
// if (productLimit.getHuaBeiLevelThree() && userDetailsDTO.getHuaBeiQuota() == 4) { //大于10000
// result = true;
// }
//
// //条件为 满足一个即可, 恰巧现在就有满足的, 则返回true通过
// if (openOne && result) {
// log.info("资质匹配筛选, 配置[满足其一]-花呗:{}, 匹配通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getHuaBeiQuota() + "-" + infoByCode, userInfo);
// return result;
// }
// }
//
// //条件为 满足全部, 恰巧现在这个不满足, 则返回false(不通过)
// if (openAll && !result) {
// log.info("资质匹配筛选, 配置[满足所有]-花呗:{}, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userDetailsDTO.getHuaBeiQuota() + "-" + infoByCode, userInfo);
// return false;
// }
// }
//
// //满足其一, 但结果为false, 则不通过
// if (openOne && !result){
//// log.info("资质匹配筛选, 配置[满足其一]-未匹配成功, 匹配不通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
// return result;
// }
//
// if (openAll && result){
// log.info("资质匹配筛选, 配置[满足所有]-匹配成功, 匹配通过, 结束匹配, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
// return result;
// }
//
// log.info("资质匹配筛选, 此行日志我觉得不会输出, 用户id-渠道id-渠道名称-产品id:{}", userInfo);
return true;
}
}

View File

@@ -129,6 +129,17 @@ public class BaseController
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
}
/**
* 响应返回结果
*
* @param rows 影响行数
* @return 操作结果
*/
protected AjaxResult toAjax(Long rows)
{
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
}
/**
* 响应返回结果
*

View File

@@ -4,6 +4,8 @@ import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
@@ -19,9 +21,11 @@ public class BaseEntity implements Serializable
/** 搜索值 */
@JsonIgnore
@TableField(exist = false)
private String searchValue;
/** 创建者 */
@TableField(exist = false)
private String createBy;
/** 创建时间 */
@@ -29,6 +33,7 @@ public class BaseEntity implements Serializable
private Date createTime;
/** 更新者 */
@TableField(exist = false)
private String updateBy;
/** 更新时间 */
@@ -40,6 +45,7 @@ public class BaseEntity implements Serializable
/** 请求参数 */
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@TableField(exist = false)
private Map<String, Object> params;
public String getSearchValue()

View File

@@ -0,0 +1,391 @@
package com.ruoyi.common.redis.service;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.core.constant.RedisConstant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* Created with IntelliJ IDEA.
*
* @Author:
* @Date: 18点29分
* @Description: 用户token管理
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class CustomerTokenService {
private final RedisService redisService;
/**
* token过期时间
*/
private static final Long EXPIRE_TIME = 30 * 24 * 60 * 60L;
/**
* 随机生成128位的token包含数字、大小写字母
*
* @param customerId 用户id
* @param phone 手机号
* @param deviceType 设备类型
* @param channelId 渠道id
* @return token
*/
public String generateToken(Long customerId, String phone, String deviceType, Long channelId) {
//获取到老的token
String oldToken = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_KEY + customerId);
if (StringUtils.hasText(oldToken)) {
//删除老的token
this.refreshToken(oldToken);
}
String newToken = null;
boolean exit = true;
while (exit) {
newToken = RandomUtil.randomString(128);
if (!redisService.hasKey(RedisConstant.APP_CUSTOMER_USERNAME_KEY + newToken)) {
exit = false;
}
}
redisService.setCacheObject(RedisConstant.APP_CUSTOMER_USERNAME_KEY + newToken, phone, EXPIRE_TIME, TimeUnit.SECONDS);
redisService.setCacheObject(RedisConstant.APP_CUSTOMER_KEY + customerId, newToken, EXPIRE_TIME, TimeUnit.SECONDS);
redisService.setCacheObject(RedisConstant.APP_CUSTOMER_CHANNEL_KEY + newToken, channelId, EXPIRE_TIME, TimeUnit.SECONDS);
redisService.setCacheObject(RedisConstant.APP_CUSTOMER_TOKEN_KEY + newToken, customerId, EXPIRE_TIME, TimeUnit.SECONDS);
redisService.setCacheObject(RedisConstant.APP_DEVICE_IDENTIFICATION + newToken, deviceType.toString(), EXPIRE_TIME, TimeUnit.SECONDS);
return newToken;
}
/**
* 判断token是否过期
*
* @param token token
* @return true过期false未过期
*/
public boolean isExpire(String token) {
String customerId = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_TOKEN_KEY + token) + StrUtil.EMPTY;
String originalToken = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_KEY + customerId);
String username = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_USERNAME_KEY + token) + StrUtil.EMPTY;
return StringUtils.isEmpty(customerId) || StringUtils.isEmpty(originalToken) || !originalToken.equals(token) || !StringUtils.hasText(username);
}
/**
* 刷新token有效期
*
* @param token token
* @param booleans 是否需要退出登录
*/
public void refreshToken(String token, Boolean... booleans) {
boolean logOut = isLogOut(booleans);
Long customerId = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_TOKEN_KEY + token);
if (Objects.isNull(customerId) && logOut) {
new Exception("登录已过期,请重新登录");
}
redisService.expire(RedisConstant.APP_CUSTOMER_USERNAME_KEY + token, EXPIRE_TIME, TimeUnit.SECONDS);
redisService.expire(RedisConstant.APP_CUSTOMER_KEY + customerId, EXPIRE_TIME, TimeUnit.SECONDS);
redisService.expire(RedisConstant.APP_CUSTOMER_CHANNEL_KEY + token, EXPIRE_TIME, TimeUnit.SECONDS);
redisService.expire(RedisConstant.APP_CUSTOMER_TOKEN_KEY + token, EXPIRE_TIME, TimeUnit.SECONDS);
redisService.expire(RedisConstant.APP_DEVICE_IDENTIFICATION + token, EXPIRE_TIME, TimeUnit.SECONDS);
}
/**
* 根据用户id刷新token有效期
*
* @param customerId 用户id
* @param booleans 是否需要退出登录
* @return token
*/
public String refreshToken(Long customerId, Boolean... booleans) {
boolean logOut = isLogOut(booleans);
String token = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_KEY + customerId);
if (StringUtils.isEmpty(token) && logOut) {
new Exception("登录已过期,请重新登录");
}
this.refreshToken(token);
return token;
}
/**
* 刷新token有效期
*
* @param request 请求
*/
public void refreshToken(HttpServletRequest request) {
String token = getToken(request);
this.refreshToken(token);
}
/**
* 移除token
*
* @param token token
* @param booleans 是否需要退出登录
*/
public void removeToken(String token, Boolean... booleans) {
boolean logOut = isLogOut(booleans);
Long customerId = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_TOKEN_KEY + token);
if (Objects.isNull(customerId) && logOut) {
new Exception("登录已过期,请重新登录");
}
redisService.deleteObject(RedisConstant.APP_CUSTOMER_KEY + customerId);
redisService.deleteObject(RedisConstant.APP_CUSTOMER_TOKEN_KEY + token);
redisService.deleteObject(RedisConstant.APP_CUSTOMER_USERNAME_KEY + token);
redisService.deleteObject(RedisConstant.APP_CUSTOMER_CHANNEL_KEY + token);
redisService.deleteObject(RedisConstant.APP_DEVICE_IDENTIFICATION + token);
}
/**
* 根据用户id移除token
*
* @param customerId 用户id
*/
public void removeToken(Long customerId) {
String token = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_KEY + customerId);
this.removeToken(token);
}
/**
* 根据HttpServletRequest获取token
*
* @param request HttpServletRequest
* @param booleans 是否需要退出登录
* @return token
*/
public String getToken(HttpServletRequest request, Boolean... booleans) {
boolean logOut = isLogOut(booleans);
String token = request.getHeader("Authorization");
if (StringUtils.isEmpty(token) && logOut) {
String requestURI = request.getRequestURI();
log.info("登录过期重新登录, requestURI:{}, logOut:{}, token:{}", requestURI, logOut, token);
new Exception("登录已过期,请重新登录");
}
return token;
}
/**
* 根据用户id获取到token
*
* @param customerId 用户id
* @return token
*/
public String getToken(Long customerId) {
String token = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_KEY + customerId);
if (StringUtils.isEmpty(token)) {
return null;
}
return token;
}
/**
* 通过token获取到用户的ID
*
* @param token token
* @param logOut 是否需要退出登录
* @return 用户ID
*/
public Long getCustomerId(String token, Boolean logOut) {
Long customerId = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_TOKEN_KEY + token);
if (Objects.isNull(customerId) && logOut) {
new Exception("登录已过期,请重新登录");
}
return customerId;
}
/**
* 根据HttpServletRequest获取到用户的ID
*
* @param request HttpServletRequest
* @param booleans 是否需要退出登录
* @return 用户ID
*/
public Long getCustomerId(HttpServletRequest request, Boolean... booleans) {
boolean logOut = isLogOut(booleans);
String token = getToken(request, logOut);
if (StringUtils.isEmpty(token)) {
return null;
}
return getCustomerId(token, logOut);
}
/**
* 根据token获取到用户的手机号 未解密
*
* @param token token
* @param booleans 是否需要退出登录
* @return 手机号
*/
public String getPhone(String token, Boolean... booleans) {
boolean logOut = isLogOut(booleans);
String phone = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_USERNAME_KEY + token);
if (Objects.isNull(phone) && logOut) {
new Exception("登录已过期,请重新登录");
}
return phone;
}
/**
* 根据用户ID获取手机号码
*
* @param customerId 用户ID
* @param booleans 是否需要退出登录
* @return 手机号
*/
public String getPhone(Long customerId, Boolean... booleans) {
String token = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_KEY + customerId);
if (Objects.isNull(token) && isLogOut(booleans)) {
new Exception("登录已过期,请重新登录");
}
String phone = getPhone(token);
// try {
// phone = EncryptUtil.AESdecode(phone, redisService.getAppEncrypted());
// }catch (Exception e) {
// return phone;
// }
return phone;
}
/**
* 根据HttpServletRequest获取到用户的手机号
*
* @param request HttpServletRequest
* @return 手机号
*/
public String getPhone(HttpServletRequest request) {
String token = getToken(request);
return getPhone(token);
}
/**
* 根据token获取到用户的渠道ID
*
* @param token token
* @param booleans 是否需要退出登录
* @return 渠道ID
*/
public Long getChannelId(String token, Boolean... booleans) {
Long channelId = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_CHANNEL_KEY + token);
if (Objects.isNull(channelId) && isLogOut(booleans)) {
new Exception("登录已过期,请重新登录");
}
return channelId;
}
/**
* 根据HttpServletRequest获取到用户的渠道ID
*
* @param request HttpServletRequest
* @return 渠道ID
*/
public Long getChannelId(HttpServletRequest request, Boolean... booleans) {
String token = getToken(request,booleans);
return getChannelId(token,booleans);
}
/**
* 根据用户ID获取渠道ID
*
* @param customerId 用户ID
* @param booleans 是否需要退出登录
* @return 渠道ID
*/
public Long getChannelId(Long customerId, Boolean... booleans) {
String token = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_KEY + customerId);
if (Objects.isNull(token) && isLogOut(booleans)) {
new Exception("登录已过期,请重新登录");
}
Long channelId = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_CHANNEL_KEY + token);
if (Objects.isNull(channelId) && isLogOut(booleans)) {
new Exception("登录已过期,请重新登录");
}
return channelId;
}
/**
* 更新渠道
* @param customerId 用户ID
* @param channelId 渠道ID
*/
public void setChannelId(Long customerId,Long channelId) {
String token = getToken(customerId);
redisService.setCacheObject(RedisConstant.APP_CUSTOMER_CHANNEL_KEY + token, channelId, EXPIRE_TIME, TimeUnit.SECONDS);
}
/**
* 根据token获取设备类型
*
* @param token token
* @param booleans 是否需要退出登录
* @return 设备类型
*/
public String getDeviceType(String token, Boolean... booleans) {
String deviceType = redisService.getCacheObject(RedisConstant.APP_DEVICE_IDENTIFICATION + token);
if (Objects.isNull(deviceType) && isLogOut(booleans)) {
new Exception("登录已过期,请重新登录");
}
return deviceType;
}
/**
* 根据HttpServletRequest获取设备类型
*
* @param request HttpServletRequest
* @return 设备类型
*/
public String getDeviceType(HttpServletRequest request,Boolean... booleans) {
String token = getToken(request,booleans);
return getDeviceType(token,booleans);
}
/**
* 根据HttpServletRequest获取设备类型
*
* @param request HttpServletRequest
* @return 设备类型
*/
public String getDeviceTypeStr(HttpServletRequest request) {
String token = getToken(request);
return getDeviceType(token);
}
/**
* 根据用户ID获取设备类型
*
* @param customerId 用户ID
* @param booleans 是否需要退出登录
* @return 设备类型
*/
public String getDeviceType(Long customerId, Boolean... booleans) {
String token = redisService.getCacheObject(RedisConstant.APP_CUSTOMER_KEY + customerId);
if (Objects.isNull(token) && isLogOut(booleans)) {
new Exception("登录已过期,请重新登录");
}
String deviceType = redisService.getCacheObject(RedisConstant.APP_DEVICE_IDENTIFICATION + token);
if (!StringUtils.hasText(deviceType)) {
deviceType = "ANDROID";
}
return deviceType;
}
/**
* 是否需要退出登录
*
* @param booleans 参数值
* @return 是否需要退出登录
*/
public Boolean isLogOut(Boolean... booleans) {
if (booleans == null || booleans.length == 0) {
return true;
}
return booleans[0];
}
}

View File

@@ -1,2 +1,3 @@
com.ruoyi.common.redis.configure.RedisConfig
com.ruoyi.common.redis.service.RedisService
com.ruoyi.common.redis.service.CustomerTokenService

View File

@@ -4,6 +4,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import com.ruoyi.common.core.constant.RedisConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -42,6 +44,11 @@ public class TokenService
private final static Long MILLIS_MINUTE_TEN = CacheConstants.REFRESH_TIME * MILLIS_MINUTE;
/**
* token过期时间
*/
private static final Long EXPIRE_TIME = 30 * 24 * 60 * 60L;
/**
* 创建令牌
*/
@@ -69,6 +76,40 @@ public class TokenService
return rspMap;
}
/**
* 创建令牌
*/
public String createTokenApp(Long customerId,Long channelId)
{
String token = IdUtils.fastUUID();
// Long userId = loginUser.getSysUser().getUserId();
// String userName = loginUser.getSysUser().getUserName();
// loginUser.setToken(token);
// loginUser.setUserid(userId);
// loginUser.setUsername(userName);
// loginUser.setIpaddr(IpUtils.getIpAddr());
// refreshToken(loginUser);
// Jwt存储信息
Map<String, Object> claimsMap = new HashMap<String, Object>();
claimsMap.put(SecurityConstants.USER_KEY, token);
claimsMap.put(SecurityConstants.DETAILS_USER_ID, customerId);
claimsMap.put(SecurityConstants.DETAILS_USERNAME, "userName");
// 接口返回信息
Map<String, Object> rspMap = new HashMap<String, Object>();
String token1 = JwtUtils.createToken(claimsMap);
rspMap.put("access_token", token1);
rspMap.put("expires_in", expireTime);
redisService.setCacheObject(RedisConstant.APP_CUSTOMER_USERNAME_KEY + token1, customerId, EXPIRE_TIME, TimeUnit.SECONDS);
redisService.setCacheObject(RedisConstant.APP_CUSTOMER_KEY + customerId, token1, EXPIRE_TIME, TimeUnit.SECONDS);
redisService.setCacheObject(RedisConstant.APP_CUSTOMER_CHANNEL_KEY + token1, channelId, EXPIRE_TIME, TimeUnit.SECONDS);
redisService.setCacheObject(RedisConstant.APP_CUSTOMER_TOKEN_KEY + token1, customerId, EXPIRE_TIME, TimeUnit.SECONDS);
redisService.setCacheObject( CacheConstants.LOGIN_TOKEN_KEY+token,customerId,EXPIRE_TIME,TimeUnit.SECONDS);
return token1;
}
/**
* 获取用户身份信息
*

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.4</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-sms</artifactId>
<description>
ruoyi-common-sms 短信模块
</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version> <!-- 或其他兼容版本 -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,24 @@
package com.ruoyi.common.sms;
import com.ruoyi.common.sms.component.SmsComponent;
import com.ruoyi.common.sms.properties.XunDaYunXinProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
@EnableConfigurationProperties(XunDaYunXinProperties.class)
public class XunDaYunXinAutoConfiguration {
@Bean
public SmsComponent smsComponent() {
return new SmsComponent();
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

View File

@@ -0,0 +1,145 @@
package com.ruoyi.common.sms.component;
import com.ruoyi.common.sms.entity.response.SmsEntity;
import com.ruoyi.common.sms.entity.response.SmsResponse;
import com.ruoyi.common.sms.properties.XunDaYunXinProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import java.util.*;
@Slf4j
public class SmsComponent {
@Autowired
private XunDaYunXinProperties properties;
@Autowired
private RestTemplate restTemplate;
/**
* 点对点
*
* @param mobileContentKvp 号码内容键值对 示例 {"15100000000":"【测试】test1","15100000001":"【测试】test2"}
* @return SmsResponse<SmsEntity>
*/
public SmsResponse sendP2PMsg(Map<String, String> mobileContentKvp) {
Map<String, Object> extraParams = new HashMap<>();
for (Map.Entry<String, String> entry : mobileContentKvp.entrySet()) {
String oldValue = entry.getValue();
String newValue = replaceCode(properties.getTemplate(), oldValue);
entry.setValue(newValue);
}
extraParams.put("mobileContentKvp", mobileContentKvp);
return sendSmsRequest("p2p", extraParams, new ParameterizedTypeReference<SmsResponse>() {
});
}
/**
* 发送群发信息
*
* @param mobile 电话号码按照,分割 示例 "15100000000,15100000001"
* @param content 内容 一般为验证码
* @return SmsResponse<SmsEntity>
*/
public SmsResponse<SmsEntity> sendGroupMsg(String mobile, String content) {
Map<String, Object> extraParams = new HashMap<>();
extraParams.put("mobile", removeDuplicates(mobile));
extraParams.put("content", replaceCode(properties.getTemplate(), content));
return sendSmsRequest("send", extraParams, new ParameterizedTypeReference<SmsResponse<SmsEntity>>() {
});
}
public SmsResponse<?> checkBalance() {
String url = properties.getBaseUrl() + "/smsv2";
Map<String, Object> params = new HashMap<>();
params.put("action", "balance");
params.put("account", properties.getAccount());
params.put("password", properties.getPassword());
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(params);
ResponseEntity<SmsResponse<?>> responseEntity = restTemplate.exchange(
url,
HttpMethod.POST,
requestEntity,
new ParameterizedTypeReference<SmsResponse<?>>() {
}
);
return responseEntity.getBody();
}
/**
* 发送短信请求的通用方法,适用于不同的短信操作。
*
* @param action 短信操作的类型,例如 "p2p"、"send" "balance"。
* @param extraParams 附加的请求参数,具体取决于短信操作的需求。可以为 null。
* @param responseType 返回值的泛型类型,用于指定响应的具体类型。
* @param <T> 响应体中泛型的类型参数。
* @return 包含响应结果的 SmsResponse 对象,响应体中可能包含不同类型的数据。
*/
private <T> T sendSmsRequest(String action, Map<String, Object> extraParams, ParameterizedTypeReference<T> responseType) {
// 拼接请求的 URL 地址
String url = properties.getBaseUrl() + "/smsv2";
// 创建请求参数 Map并填充必需的账户信息和操作类型
Map<String, Object> params = new HashMap<>();
params.put("action", action); // 设置请求的操作类型,如发送短信或查询余额
params.put("account", properties.getAccount()); // 设置账户名
params.put("password", properties.getPassword()); // 设置密码
params.put("extno", properties.getExtno()); // 虚拟接入码
// 如果有额外的参数,则将它们添加到请求参数中
if (extraParams != null) {
params.putAll(extraParams);
}
// 构建 HttpEntity 实体,包含请求参数
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(params);
// 使用 RestTemplate 的 exchange 方法发送 POST 请求,并指定返回的泛型类型
ResponseEntity<T> responseEntity = restTemplate.exchange(
url, // 请求 URL
HttpMethod.POST, // HTTP 方法类型为 POST
requestEntity, // 请求体包含请求参数
responseType // 指定返回类型的泛型引用,用于保留泛型信息
);
// 返回响应体(根据调用方法传入的类型)
return responseEntity.getBody();
}
/**
* 相同号码去重
*
* @param input 字符串电话号码 逗号分隔符分割
* @return String 去重之后的手机电话号码
*/
private String removeDuplicates(String input) {
// 使用 LinkedHashSet 保持插入顺序并去重
Set<String> uniqueSet = new LinkedHashSet<>(Arrays.asList(input.split(",")));
if (uniqueSet.size() >= 1000) {
throw new IllegalArgumentException("群发不建议超过1000个电话号码");
}
// 将去重后的集合转换回字符串
return String.join(",", uniqueSet);
}
/**
* 模板替换占位符
*
* @param template 模板
* @param code 实际值
* @return 替换之后的模板
*/
public String replaceCode(String template, String code) {
return template.replace("{code}", code);
}
}

View File

@@ -0,0 +1 @@
package com.ruoyi.common.sms.entity;

View File

@@ -0,0 +1 @@
package com.ruoyi.common.sms.entity.request;

View File

@@ -0,0 +1,32 @@
package com.ruoyi.common.sms.entity.response;
public class SmsEntity {
private String mid;
private String mobile;
private int result;
// Getters and Setters
public String getMid() {
return mid;
}
public void setMid(String mid) {
this.mid = mid;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public int getResult() {
return result;
}
public void setResult(int result) {
this.result = result;
}
}

View File

@@ -0,0 +1,12 @@
package com.ruoyi.common.sms.entity.response;
import lombok.Data;
import java.util.List;
@Data
public class SmsResponse<T> {
private Integer status;
private Integer balance;
private List<T> list;
}

View File

@@ -0,0 +1,40 @@
package com.ruoyi.common.sms.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 迅达云信短信 配置类
*/
@Data
@ConfigurationProperties(prefix = "xundayunxin")
public class XunDaYunXinProperties {
/**
* 请求地址
*/
private String baseUrl = "http://47.96.236.136:7862/";
/**
* 账号
*/
private String account = "932425";
/**
* 密码
*/
private String password = "alDE77Gmo";
/**
* 虚拟接入码
*/
private String extno = "10690367";
/**
* 是否启用手机号加密
*/
private boolean encryptionEnabled;
/**
* 短信模板
*/
private String template = "【信用秒租】验证码为:{code}您正在登录信用秒租请在3分钟内完成验证如非本人操作请忽略本短信。";
}

View File

@@ -0,0 +1,2 @@
com.ruoyi.common.sms.XunDaYunXinAutoConfiguration
com.ruoyi.common.sms.component.SmsComponent