feat(ruoyi版本同步): ruoyi-3.8.9版本同步

This commit is contained in:
zhuangpeng.li
2025-04-17 09:44:10 +08:00
parent e404cd26d4
commit ff51ea78af
62 changed files with 1814 additions and 1579 deletions

View File

@@ -1,17 +1,18 @@
package com.fastbee.common.annotation;
import com.fastbee.common.utils.poi.ExcelHandlerAdapter;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.math.BigDecimal;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import com.fastbee.common.utils.poi.ExcelHandlerAdapter;
/**
* 自定义导出Excel数据注解
*
*
* @author ruoyi
*/
@Retention(RetentionPolicy.RUNTIME)
@@ -59,12 +60,12 @@ public @interface Excel
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
/**
* 导出时在excel中每个列的高度 单位为字符
* 导出时在excel中每个列的高度
*/
public double height() default 14;
/**
* 导出时在excel中每个列的宽 单位为字符
* 导出时在excel中每个列的宽
*/
public double width() default 16;
@@ -83,11 +84,21 @@ public @interface Excel
*/
public String prompt() default "";
/**
* 是否允许内容换行
*/
public boolean wrapText() default false;
/**
* 设置只能选择不能输入的列内容.
*/
public String[] combo() default {};
/**
* 是否从字典读数据到combo,默认不读取,如读取需要设置dictType注解.
*/
public boolean comboReadDict() default false;
/**
* 是否需要纵向合并单元格,应对需求:含有list集合单元格)
*/
@@ -114,7 +125,7 @@ public @interface Excel
public ColumnType cellType() default ColumnType.STRING;
/**
* 导出列头背景色
* 导出列头背景
*/
public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
@@ -124,7 +135,7 @@ public @interface Excel
public IndexedColors headerColor() default IndexedColors.WHITE;
/**
* 导出单元格背景色
* 导出单元格背景
*/
public IndexedColors backgroundColor() default IndexedColors.WHITE;
@@ -171,7 +182,7 @@ public @interface Excel
public enum ColumnType
{
NUMERIC(0), STRING(1), IMAGE(2);
NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
private final int value;
ColumnType(int value)
@@ -184,4 +195,4 @@ public @interface Excel
return this.value;
}
}
}
}

View File

@@ -1,16 +1,13 @@
package com.fastbee.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.enums.OperatorType;
import java.lang.annotation.*;
/**
* 自定义操作日志记录注解
*
*
* @author ruoyi
*
*/
@@ -20,7 +17,7 @@ import com.fastbee.common.enums.OperatorType;
public @interface Log
{
/**
* 模块
* 模块
*/
public String title() default "";
@@ -43,4 +40,9 @@ public @interface Log
* 是否保存响应的参数
*/
public boolean isSaveResponseData() default true;
/**
* 排除指定的请求参数
*/
public String[] excludeParamNames() default {};
}

View File

@@ -2,9 +2,11 @@ package com.fastbee.common.constant;
import io.jsonwebtoken.Claims;
import java.util.Locale;
/**
* 通用常量信息
*
*
* @author ruoyi
*/
public class Constants
@@ -19,6 +21,11 @@ public class Constants
*/
public static final String GBK = "GBK";
/**
* 系统语言
*/
public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
/**
* www主域
*/
@@ -63,7 +70,27 @@ public class Constants
* 登录失败
*/
public static final String LOGIN_FAIL = "Error";
/**
* 所有权限标识
*/
public static final String ALL_PERMISSION = "*:*:*";
/**
* 管理员角色权限标识
*/
public static final String SUPER_ADMIN = "admin";
/**
* 角色权限分隔符
*/
public static final String ROLE_DELIMETER = ",";
/**
* 权限标识分隔符
*/
public static final String PERMISSION_DELIMETER = ",";
/**
* 验证码有效期(分钟)
*/
@@ -129,14 +156,19 @@ public class Constants
*/
public static final String LOOKUP_LDAPS = "ldaps:";
/**
* 自动识别json对象白名单配置仅允许解析的包名范围越小越安全
*/
public static final String[] JSON_WHITELIST_STR = { "org.springframework", "com.ruoyi" };
/**
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
*/
public static final String[] JOB_WHITELIST_STR = { "com.fastbee" };
public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task" };
/**
* 定时任务违规的字符
*/
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
"org.springframework", "org.apache", "com.fastbee.common.utils.file", "com.fastbee.common.config" };
"org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config", "com.ruoyi.generator" };
}

View File

@@ -2,7 +2,7 @@ package com.fastbee.common.constant;
/**
* 用户常量信息
*
*
* @author ruoyi
*/
public class UserConstants
@@ -53,16 +53,16 @@ public class UserConstants
/** Layout组件标识 */
public final static String LAYOUT = "Layout";
/** ParentView组件标识 */
public final static String PARENT_VIEW = "ParentView";
/** InnerLink组件标识 */
public final static String INNER_LINK = "InnerLink";
/** 校验返回结果码 */
public final static String UNIQUE = "0";
public final static String NOT_UNIQUE = "1";
/** 校验是否唯一的返回标识 */
public final static boolean UNIQUE = true;
public final static boolean NOT_UNIQUE = false;
/**
* 用户名长度限制

View File

@@ -1,13 +1,14 @@
package com.fastbee.common.core.text;
import com.fastbee.common.utils.StringUtils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.util.Set;
import com.fastbee.common.utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
/**
* 类型转换器
@@ -364,6 +365,10 @@ public class Convert
*/
public static String[] toStrArray(String str)
{
if (StringUtils.isEmpty(str))
{
return new String[] {};
}
return toStrArray(",", str);
}
@@ -536,7 +541,7 @@ public class Convert
/**
* 转换为boolean<br>
* String支持的值为true、false、yes、ok、no1,0 如果给定的值为空,或者转换失败,返回默认值<br>
* String支持的值为true、false、yes、ok、no、1、0、是、否, 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
@@ -565,10 +570,12 @@ public class Convert
case "yes":
case "ok":
case "1":
case "":
return true;
case "false":
case "no":
case "0":
case "":
return false;
default:
return defaultValue;
@@ -791,14 +798,23 @@ public class Convert
{
return (String) obj;
}
else if (obj instanceof byte[])
else if (obj instanceof byte[] || obj instanceof Byte[])
{
return str((byte[]) obj, charset);
}
else if (obj instanceof Byte[])
{
byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj);
return str(bytes, charset);
if (obj instanceof byte[])
{
return str((byte[]) obj, charset);
}
else
{
Byte[] bytes = (Byte[]) obj;
int length = bytes.length;
byte[] dest = new byte[length];
for (int i = 0; i < length; i++)
{
dest[i] = bytes[i];
}
return str(dest, charset);
}
}
else if (obj instanceof ByteBuffer)
{
@@ -954,9 +970,7 @@ public class Convert
c[i] = (char) (c[i] - 65248);
}
}
String returnString = new String(c);
return returnString;
return new String(c);
}
/**
@@ -977,7 +991,12 @@ public class Convert
String s = "";
for (int i = 0; i < fraction.length; i++)
{
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
// 优化double计算精度丢失问题
BigDecimal nNum = new BigDecimal(n);
BigDecimal decimal = new BigDecimal(10);
BigDecimal scale = nNum.multiply(decimal).setScale(2, RoundingMode.HALF_EVEN);
double d = scale.doubleValue();
s += (digit[(int) (Math.floor(d * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
}
if (s.length() < 1)
{

View File

@@ -0,0 +1,60 @@
package com.fastbee.common.enums;
import com.fastbee.common.utils.DesensitizedUtil;
import java.util.function.Function;
/**
* 脱敏类型
*
* @author ruoyi
*/
public enum DesensitizedType
{
/**
* 姓名第2位星号替换
*/
USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
/**
* 密码,全部字符都用*代替
*/
PASSWORD(DesensitizedUtil::password),
/**
* 身份证中间10位星号替换
*/
ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{3}[Xx]|\\d{4})", "$1** **** ****$2")),
/**
* 手机号中间4位星号替换
*/
PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
/**
* 电子邮箱,仅显示第一个字母和@后面的地址显示,其他星号替换
*/
EMAIL(s -> s.replaceAll("(^.)[^@]*(@.*$)", "$1****$2")),
/**
* 银行卡号保留最后4位其他星号替换
*/
BANK_CARD(s -> s.replaceAll("\\d{15}(\\d{3})", "**** **** **** **** $1")),
/**
* 车牌号码,包含普通车辆、新能源车辆
*/
CAR_LICENSE(DesensitizedUtil::carLicense);
private final Function<String, String> desensitizer;
DesensitizedType(Function<String, String> desensitizer)
{
this.desensitizer = desensitizer;
}
public Function<String, String> desensitizer()
{
return desensitizer;
}
}

View File

@@ -0,0 +1,49 @@
package com.fastbee.common.utils;
/**
* 脱敏工具类
*
* @author ruoyi
*/
public class DesensitizedUtil
{
/**
* 密码的全部字符都用*代替,比如:******
*
* @param password 密码
* @return 脱敏后的密码
*/
public static String password(String password)
{
if (StringUtils.isBlank(password))
{
return StringUtils.EMPTY;
}
return StringUtils.repeat('*', password.length());
}
/**
* 车牌中间用*代替,如果是错误的车牌,不处理
*
* @param carLicense 完整的车牌号
* @return 脱敏后的车牌
*/
public static String carLicense(String carLicense)
{
if (StringUtils.isBlank(carLicense))
{
return StringUtils.EMPTY;
}
// 普通车牌
if (carLicense.length() == 7)
{
carLicense = StringUtils.hide(carLicense, 3, 6);
}
else if (carLicense.length() == 8)
{
// 新能源车牌
carLicense = StringUtils.hide(carLicense, 3, 7);
}
return carLicense;
}
}

View File

@@ -1,13 +1,14 @@
package com.fastbee.common.utils;
import java.util.Collection;
import java.util.List;
import com.alibaba.fastjson2.JSONArray;
import com.fastbee.common.constant.CacheConstants;
import com.fastbee.common.core.domain.entity.SysDictData;
import com.fastbee.common.core.redis.RedisCache;
import com.fastbee.common.utils.spring.SpringUtils;
import java.util.Collection;
import java.util.List;
/**
* 字典工具类
*
@@ -56,6 +57,10 @@ public class DictUtils
*/
public static String getDictLabel(String dictType, String dictValue)
{
if (StringUtils.isEmpty(dictValue))
{
return StringUtils.EMPTY;
}
return getDictLabel(dictType, dictValue, SEPARATOR);
}
@@ -68,6 +73,10 @@ public class DictUtils
*/
public static String getDictValue(String dictType, String dictLabel)
{
if (StringUtils.isEmpty(dictLabel))
{
return StringUtils.EMPTY;
}
return getDictValue(dictType, dictLabel, SEPARATOR);
}
@@ -83,31 +92,31 @@ public class DictUtils
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNotNull(datas))
if (StringUtils.isNull(datas))
{
if (StringUtils.containsAny(separator, dictValue))
return StringUtils.EMPTY;
}
if (StringUtils.containsAny(separator, dictValue))
{
for (SysDictData dict : datas)
{
for (SysDictData dict : datas)
for (String value : dictValue.split(separator))
{
for (String value : dictValue.split(separator))
if (value.equals(dict.getDictValue()))
{
if (value.equals(dict.getDictValue()))
{
propertyString.append(dict.getDictLabel()).append(separator);
break;
}
propertyString.append(dict.getDictLabel()).append(separator);
break;
}
}
}
else
}
else
{
for (SysDictData dict : datas)
{
for (SysDictData dict : datas)
if (dictValue.equals(dict.getDictValue()))
{
if (dictValue.equals(dict.getDictValue()))
{
return dict.getDictLabel();
}
return dict.getDictLabel();
}
}
}
@@ -126,8 +135,11 @@ public class DictUtils
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas))
if (StringUtils.isNull(datas))
{
return StringUtils.EMPTY;
}
if (StringUtils.containsAny(separator, dictLabel))
{
for (SysDictData dict : datas)
{
@@ -154,6 +166,48 @@ public class DictUtils
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
* 根据字典类型获取字典所有值
*
* @param dictType 字典类型
* @return 字典值
*/
public static String getDictValues(String dictType)
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNull(datas))
{
return StringUtils.EMPTY;
}
for (SysDictData dict : datas)
{
propertyString.append(dict.getDictValue()).append(SEPARATOR);
}
return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
}
/**
* 根据字典类型获取字典所有标签
*
* @param dictType 字典类型
* @return 字典值
*/
public static String getDictLabels(String dictType)
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNull(datas))
{
return StringUtils.EMPTY;
}
for (SysDictData dict : datas)
{
propertyString.append(dict.getDictLabel()).append(SEPARATOR);
}
return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
}
/**
* 删除指定字典缓存
*

View File

@@ -1,19 +1,27 @@
package com.fastbee.common.utils;
import com.fastbee.common.constant.Constants;
import com.fastbee.common.constant.HttpStatus;
import com.fastbee.common.core.domain.entity.SysRole;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.exception.ServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.fastbee.common.constant.HttpStatus;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.exception.ServiceException;
import org.springframework.util.PatternMatchUtils;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* 安全服务工具类
*
*
* @author ruoyi
*/
public class SecurityUtils
{
/**
* 用户ID
**/
@@ -43,7 +51,7 @@ public class SecurityUtils
throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED);
}
}
/**
* 获取用户账户
**/
@@ -109,7 +117,7 @@ public class SecurityUtils
/**
* 是否为管理员
*
*
* @param userId 用户ID
* @return 结果
*/
@@ -117,4 +125,55 @@ public class SecurityUtils
{
return userId != null && 1L == userId;
}
/**
* 验证用户是否具备某权限
*
* @param permission 权限字符串
* @return 用户是否具备某权限
*/
public static boolean hasPermi(String permission)
{
return hasPermi(getLoginUser().getPermissions(), permission);
}
/**
* 判断是否包含权限
*
* @param authorities 权限列表
* @param permission 权限字符串
* @return 用户是否具备某权限
*/
public static boolean hasPermi(Collection<String> authorities, String permission)
{
return authorities.stream().filter(StringUtils::hasText)
.anyMatch(x -> Constants.ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission));
}
/**
* 验证用户是否拥有某个角色
*
* @param role 角色标识
* @return 用户是否具备某角色
*/
public static boolean hasRole(String role)
{
List<SysRole> roleList = getLoginUser().getUser().getRoles();
Collection<String> roles = roleList.stream().map(SysRole::getRoleKey).collect(Collectors.toSet());
return hasRole(roles, role);
}
/**
* 判断是否包含角色
*
* @param roles 角色列表
* @param role 角色
* @return 用户是否具备某角色权限
*/
public static boolean hasRole(Collection<String> roles, String role)
{
return roles.stream().filter(StringUtils::hasText)
.anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role));
}
}

View File

@@ -1,43 +1,35 @@
package com.fastbee.common.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import org.springframework.util.AntPathMatcher;
import com.fastbee.common.constant.Constants;
import com.fastbee.common.core.text.StrFormatter;
import org.springframework.util.AntPathMatcher;
import java.util.*;
/**
* 字符串工具类
*
* @author ruoyi
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils {
/**
* 空字符串
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils
{
/** 空字符串 */
private static final String NULLSTR = "";
/**
* 下划线
*/
/** 下划线 */
private static final char SEPARATOR = '_';
/** 星号 */
private static final char ASTERISK = '*';
/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public static <T> T nvl(T value, T defaultValue) {
public static <T> T nvl(T value, T defaultValue)
{
return value != null ? value : defaultValue;
}
@@ -47,7 +39,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param coll 要判断的Collection
* @return true为空 false非空
*/
public static boolean isEmpty(Collection<?> coll) {
public static boolean isEmpty(Collection<?> coll)
{
return isNull(coll) || coll.isEmpty();
}
@@ -57,7 +50,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param coll 要判断的Collection
* @return true非空 false
*/
public static boolean isNotEmpty(Collection<?> coll) {
public static boolean isNotEmpty(Collection<?> coll)
{
return !isEmpty(coll);
}
@@ -65,9 +59,10 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* * 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
* * @return true为空 false非空
** @return true为空 false非空
*/
public static boolean isEmpty(Object[] objects) {
public static boolean isEmpty(Object[] objects)
{
return isNull(objects) || (objects.length == 0);
}
@@ -77,7 +72,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param objects 要判断的对象数组
* @return true非空 false
*/
public static boolean isNotEmpty(Object[] objects) {
public static boolean isNotEmpty(Object[] objects)
{
return !isEmpty(objects);
}
@@ -87,7 +83,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param map 要判断的Map
* @return true为空 false非空
*/
public static boolean isEmpty(Map<?, ?> map) {
public static boolean isEmpty(Map<?, ?> map)
{
return isNull(map) || map.isEmpty();
}
@@ -97,7 +94,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param map 要判断的Map
* @return true非空 false
*/
public static boolean isNotEmpty(Map<?, ?> map) {
public static boolean isNotEmpty(Map<?, ?> map)
{
return !isEmpty(map);
}
@@ -107,7 +105,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param str String
* @return true为空 false非空
*/
public static boolean isEmpty(String str) {
public static boolean isEmpty(String str)
{
return isNull(str) || NULLSTR.equals(str.trim());
}
@@ -117,7 +116,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param str String
* @return true非空串 false空串
*/
public static boolean isNotEmpty(String str) {
public static boolean isNotEmpty(String str)
{
return !isEmpty(str);
}
@@ -127,7 +127,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param object Object
* @return true为空 false非空
*/
public static boolean isNull(Object object) {
public static boolean isNull(Object object)
{
return object == null;
}
@@ -137,7 +138,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param object Object
* @return true非空 false
*/
public static boolean isNotNull(Object object) {
public static boolean isNotNull(Object object)
{
return !isNull(object);
}
@@ -147,37 +149,87 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param object 对象
* @return true是数组 false不是数组
*/
public static boolean isArray(Object object) {
public static boolean isArray(Object object)
{
return isNotNull(object) && object.getClass().isArray();
}
/**
* 去空格
*/
public static String trim(String str) {
public static String trim(String str)
{
return (str == null ? "" : str.trim());
}
/**
* 替换指定字符串的指定区间内字符为"*"
*
* @param str 字符串
* @param startInclude 开始位置(包含)
* @param endExclude 结束位置(不包含)
* @return 替换后的字符串
*/
public static String hide(CharSequence str, int startInclude, int endExclude)
{
if (isEmpty(str))
{
return NULLSTR;
}
final int strLength = str.length();
if (startInclude > strLength)
{
return NULLSTR;
}
if (endExclude > strLength)
{
endExclude = strLength;
}
if (startInclude > endExclude)
{
// 如果起始位置大于结束位置,不替换
return NULLSTR;
}
final char[] chars = new char[strLength];
for (int i = 0; i < strLength; i++)
{
if (i >= startInclude && i < endExclude)
{
chars[i] = ASTERISK;
}
else
{
chars[i] = str.charAt(i);
}
}
return new String(chars);
}
/**
* 截取字符串
*
* @param str 字符串
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start) {
if (str == null) {
public static String substring(final String str, int start)
{
if (str == null)
{
return NULLSTR;
}
if (start < 0) {
if (start < 0)
{
start = str.length() + start;
}
if (start < 0) {
if (start < 0)
{
start = 0;
}
if (start > str.length()) {
if (start > str.length())
{
return NULLSTR;
}
@@ -187,41 +239,99 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/**
* 截取字符串
*
* @param str 字符串
* @param str 字符串
* @param start 开始
* @param end 结束
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end) {
if (str == null) {
public static String substring(final String str, int start, int end)
{
if (str == null)
{
return NULLSTR;
}
if (end < 0) {
if (end < 0)
{
end = str.length() + end;
}
if (start < 0) {
if (start < 0)
{
start = str.length() + start;
}
if (end > str.length()) {
if (end > str.length())
{
end = str.length();
}
if (start > end) {
if (start > end)
{
return NULLSTR;
}
if (start < 0) {
if (start < 0)
{
start = 0;
}
if (end < 0) {
if (end < 0)
{
end = 0;
}
return str.substring(start, end);
}
/**
* 在字符串中查找第一个出现的 `open` 和最后一个出现的 `close` 之间的子字符串
*
* @param str 要截取的字符串
* @param open 起始字符串
* @param close 结束字符串
* @return 截取结果
*/
public static String substringBetweenLast(final String str, final String open, final String close)
{
if (isEmpty(str) || isEmpty(open) || isEmpty(close))
{
return NULLSTR;
}
final int start = str.indexOf(open);
if (start != INDEX_NOT_FOUND)
{
final int end = str.lastIndexOf(close);
if (end != INDEX_NOT_FOUND)
{
return str.substring(start + open.length(), end);
}
}
return NULLSTR;
}
/**
* 判断是否为空,并且不是空白字符
*
* @param str 要判断的value
* @return 结果
*/
public static boolean hasText(String str)
{
return (str != null && !str.isEmpty() && containsText(str));
}
private static boolean containsText(CharSequence str)
{
int strLen = str.length();
for (int i = 0; i < strLen; i++)
{
if (!Character.isWhitespace(str.charAt(i)))
{
return true;
}
}
return false;
}
/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
@@ -232,11 +342,13 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* 转义\ format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param template 文本模板,被替换的部分用 {} 表示
* @param params 参数值
* @param params 参数值
* @return 格式化后的文本
*/
public static String format(String template, Object... params) {
if (isEmpty(params) || isEmpty(template)) {
public static String format(String template, Object... params)
{
if (isEmpty(params) || isEmpty(template))
{
return template;
}
return StrFormatter.format(template, params);
@@ -248,7 +360,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param link 链接
* @return 结果
*/
public static boolean ishttp(String link) {
public static boolean ishttp(String link)
{
return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
}
@@ -259,35 +372,42 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param sep 分隔符
* @return set集合
*/
public static final Set<String> str2Set(String str, String sep) {
public static final Set<String> str2Set(String str, String sep)
{
return new HashSet<String>(str2List(str, sep, true, false));
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @param trim 去掉首尾空白
* @return list集合
*/
public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {
public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)
{
List<String> list = new ArrayList<String>();
if (StringUtils.isEmpty(str)) {
if (StringUtils.isEmpty(str))
{
return list;
}
// 过滤空白字符串
if (filterBlank && StringUtils.isBlank(str)) {
if (filterBlank && StringUtils.isBlank(str))
{
return list;
}
String[] split = str.split(sep);
for (String string : split) {
if (filterBlank && StringUtils.isBlank(string)) {
for (String string : split)
{
if (filterBlank && StringUtils.isBlank(string))
{
continue;
}
if (trim) {
if (trim)
{
string = string.trim();
}
list.add(string);
@@ -297,18 +417,24 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
}
/**
* 判断给定的set列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
* 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
*
* @param set 给定的集合
* @param collection 给定的集合
* @param array 给定的数组
* @return boolean 结果
*/
public static boolean containsAny(Collection<String> collection, String... array) {
if (isEmpty(collection) || isEmpty(array)) {
public static boolean containsAny(Collection<String> collection, String... array)
{
if (isEmpty(collection) || isEmpty(array))
{
return false;
} else {
for (String str : array) {
if (collection.contains(str)) {
}
else
{
for (String str : array)
{
if (collection.contains(str))
{
return true;
}
}
@@ -319,16 +445,20 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
*
* @param cs 指定字符串
* @param cs 指定字符串
* @param searchCharSequences 需要检查的字符串数组
* @return 是否包含任意一个字符串
*/
public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) {
if (isEmpty(cs) || isEmpty(searchCharSequences)) {
public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences)
{
if (isEmpty(cs) || isEmpty(searchCharSequences))
{
return false;
}
for (CharSequence testStr : searchCharSequences) {
if (containsIgnoreCase(cs, testStr)) {
for (CharSequence testStr : searchCharSequences)
{
if (containsIgnoreCase(cs, testStr))
{
return true;
}
}
@@ -338,8 +468,10 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/**
* 驼峰转下划线命名
*/
public static String toUnderScoreCase(String str) {
if (str == null) {
public static String toUnderScoreCase(String str)
{
if (str == null)
{
return null;
}
StringBuilder sb = new StringBuilder();
@@ -349,23 +481,31 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
boolean curreCharIsUpperCase = true;
// 下一字符是否大写
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++) {
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
if (i > 0) {
if (i > 0)
{
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
} else {
}
else
{
preCharIsUpperCase = false;
}
curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1)) {
if (i < (str.length() - 1))
{
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
{
sb.append(SEPARATOR);
} else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
}
else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
{
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
@@ -377,14 +517,18 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strs) {
if (str != null && strs != null) {
for (String s : strs) {
if (str.equalsIgnoreCase(trim(s))) {
public static boolean inStringIgnoreCase(String str, String... strs)
{
if (str != null && strs != null)
{
for (String s : strs)
{
if (str.equalsIgnoreCase(trim(s)))
{
return true;
}
}
@@ -398,21 +542,27 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name) {
public static String convertToCamelCase(String name)
{
StringBuilder result = new StringBuilder();
// 快速检查
if (name == null || name.isEmpty()) {
if (name == null || name.isEmpty())
{
// 没必要转换
return "";
} else if (!name.contains("_")) {
}
else if (!name.contains("_"))
{
// 不含下划线,仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// 用下划线将原始字符串分割
String[] camels = name.split("_");
for (String camel : camels) {
for (String camel : camels)
{
// 跳过原始字符串中开头、结尾的下换线或双重下划线
if (camel.isEmpty()) {
if (camel.isEmpty())
{
continue;
}
// 首字母大写
@@ -423,24 +573,37 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
}
/**
* 驼峰式命名法 例如user_name->userName
* 驼峰式命名法
* 例如user_name->userName
*/
public static String toCamelCase(String s) {
if (s == null) {
public static String toCamelCase(String s)
{
if (s == null)
{
return null;
}
if (s.indexOf(SEPARATOR) == -1)
{
return s;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++) {
for (int i = 0; i < s.length(); i++)
{
char c = s.charAt(i);
if (c == SEPARATOR) {
if (c == SEPARATOR)
{
upperCase = true;
} else if (upperCase) {
}
else if (upperCase)
{
sb.append(Character.toUpperCase(c));
upperCase = false;
} else {
}
else
{
sb.append(c);
}
}
@@ -450,16 +613,20 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs) {
if (isEmpty(str) || isEmpty(strs)) {
public static boolean matches(String str, List<String> strs)
{
if (isEmpty(str) || isEmpty(strs))
{
return false;
}
for (String pattern : strs) {
if (isMatch(pattern, str)) {
for (String pattern : strs)
{
if (isMatch(pattern, str))
{
return true;
}
}
@@ -473,202 +640,67 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
* @param url 需要匹配的url
* @return
*/
public static boolean isMatch(String pattern, String url) {
public static boolean isMatch(String pattern, String url)
{
AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url);
}
@SuppressWarnings("unchecked")
public static <T> T cast(Object obj) {
public static <T> T cast(Object obj)
{
return (T) obj;
}
/**
* 数字左边补齐0使之达到指定长度。注意如果数字转换为字符串后长度大于size则只保留 最后size个字符。
*
* @param num 数字对象
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式,该字符串为指定长度。
*/
public static final String padl(final Number num, final int size) {
public static final String padl(final Number num, final int size)
{
return padl(num.toString(), size, '0');
}
/**
* 字符串左补齐。如果原始字符串s长度大于size则只保留最后size个字符。
*
* @param s 原始字符串
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
* @param c 用于补齐的字符
* @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
*/
public static final String padl(final String s, final int size, final char c) {
public static final String padl(final String s, final int size, final char c)
{
final StringBuilder sb = new StringBuilder(size);
if (s != null) {
if (s != null)
{
final int len = s.length();
if (s.length() <= size) {
for (int i = size - len; i > 0; i--) {
if (s.length() <= size)
{
for (int i = size - len; i > 0; i--)
{
sb.append(c);
}
sb.append(s);
} else {
}
else
{
return s.substring(len - size, len);
}
} else {
for (int i = size; i > 0; i--) {
}
else
{
for (int i = size; i > 0; i--)
{
sb.append(c);
}
}
return sb.toString();
}
/*将字符串转小写,首字母大写,其他小写*/
public static String upperCase(String str) {
char[] ch = str.toLowerCase().toCharArray();
if (ch[0] >= 'a' && ch[0] <= 'z') {
ch[0] = (char) (ch[0] - 32);
}
return new String(ch);
}
public static String toString(Object value) {
if (value == null) {
return "null";
}
if (value instanceof ByteBuf) {
return ByteBufUtil.hexDump((ByteBuf) value);
}
if (!value.getClass().isArray()) {
return value.toString();
}
StringBuilder root = new StringBuilder(32);
toString(value, root);
return root.toString();
}
public static StringBuilder toString(Object value, StringBuilder builder) {
if (value == null) {
return builder;
}
builder.append('[');
int start = builder.length();
if (value instanceof long[]) {
long[] array = (long[]) value;
for (long t : array) {
builder.append(t).append(',');
}
} else if (value instanceof int[]) {
int[] array = (int[]) value;
for (int t : array) {
builder.append(t).append(',');
}
} else if (value instanceof short[]) {
short[] array = (short[]) value;
for (short t : array) {
builder.append(t).append(',');
}
} else if (value instanceof byte[]) {
byte[] array = (byte[]) value;
for (byte t : array) {
builder.append(t).append(',');
}
} else if (value instanceof char[]) {
char[] array = (char[]) value;
for (char t : array) {
builder.append(t).append(',');
}
} else if (value instanceof double[]) {
double[] array = (double[]) value;
for (double t : array) {
builder.append(t).append(',');
}
} else if (value instanceof float[]) {
float[] array = (float[]) value;
for (float t : array) {
builder.append(t).append(',');
}
} else if (value instanceof boolean[]) {
boolean[] array = (boolean[]) value;
for (boolean t : array) {
builder.append(t).append(',');
}
} else if (value instanceof String[]) {
String[] array = (String[]) value;
for (String t : array) {
builder.append(t).append(',');
}
} else if (isArray1(value)) {
Object[] array = (Object[]) value;
for (Object t : array) {
toString(t, builder).append(',');
}
} else if (value instanceof Object[]) {
Object[] array = (Object[]) value;
for (Object t : array) {
builder.append(t).append(',');
}
}
int end = builder.length();
if (end <= start) {
builder.append(']');
} else {
builder.setCharAt(end - 1, ']');
}
return builder;
}
private static boolean isArray1(Object value) {
Class<?> componentType = value.getClass().getComponentType();
if (componentType == null) {
return false;
}
return componentType.isArray();
}
public static String leftPad(String str, int size, char ch) {
int length = str.length();
int pads = size - length;
if (pads > 0) {
char[] result = new char[size];
str.getChars(0, length, result, pads);
while (pads > 0) {
result[--pads] = ch;
}
return new String(result);
}
return str;
}
/**
* 获取字符串中的数字
* @param str
* @return
*/
public static Integer matcherNum(String str){
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(str);
while (matcher.find()){
return Integer.parseInt(matcher.group());
}
return 0;
}
}

View File

@@ -1,20 +1,39 @@
package com.fastbee.common.utils.ip;
import com.fastbee.common.utils.ServletUtils;
import com.fastbee.common.utils.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest;
import com.fastbee.common.utils.StringUtils;
/**
* 获取IP方法
*
*
* @author ruoyi
*/
public class IpUtils
{
public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
// 匹配 ip
public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")";
public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))";
// 匹配网段
public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")";
/**
* 获取客户端IP
*
*
* @return IP地址
*/
public static String getIpAddr()
{
return getIpAddr(ServletUtils.getRequest());
}
/**
* 获取客户端IP
*
* @param request 请求对象
* @return IP地址
*/
@@ -52,7 +71,7 @@ public class IpUtils
/**
* 检查是否为内部IP地址
*
*
* @param ip IP地址
* @return 结果
*/
@@ -64,7 +83,7 @@ public class IpUtils
/**
* 检查是否为内部IP地址
*
*
* @param addr byte地址
* @return 结果
*/
@@ -107,7 +126,7 @@ public class IpUtils
/**
* 将IPv4地址转换成字节
*
*
* @param text IPv4地址
* @return byte 字节
*/
@@ -195,7 +214,7 @@ public class IpUtils
/**
* 获取IP地址
*
*
* @return 本地IP地址
*/
public static String getHostIp()
@@ -212,7 +231,7 @@ public class IpUtils
/**
* 获取主机名
*
*
* @return 本地主机名
*/
public static String getHostName()
@@ -248,7 +267,7 @@ public class IpUtils
}
}
}
return ip;
return StringUtils.substring(ip, 0, 255);
}
/**
@@ -261,4 +280,104 @@ public class IpUtils
{
return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
}
}
/**
* 是否为IP
*/
public static boolean isIP(String ip)
{
return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);
}
/**
* 是否为IP或 *为间隔的通配符地址
*/
public static boolean isIpWildCard(String ip)
{
return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD);
}
/**
* 检测参数是否在ip通配符里
*/
public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip)
{
String[] s1 = ipWildCard.split("\\.");
String[] s2 = ip.split("\\.");
boolean isMatchedSeg = true;
for (int i = 0; i < s1.length && !s1[i].equals("*"); i++)
{
if (!s1[i].equals(s2[i]))
{
isMatchedSeg = false;
break;
}
}
return isMatchedSeg;
}
/**
* 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串
*/
public static boolean isIPSegment(String ipSeg)
{
return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG);
}
/**
* 判断ip是否在指定网段中
*/
public static boolean ipIsInNetNoCheck(String iparea, String ip)
{
int idx = iparea.indexOf('-');
String[] sips = iparea.substring(0, idx).split("\\.");
String[] sipe = iparea.substring(idx + 1).split("\\.");
String[] sipt = ip.split("\\.");
long ips = 0L, ipe = 0L, ipt = 0L;
for (int i = 0; i < 4; ++i)
{
ips = ips << 8 | Integer.parseInt(sips[i]);
ipe = ipe << 8 | Integer.parseInt(sipe[i]);
ipt = ipt << 8 | Integer.parseInt(sipt[i]);
}
if (ips > ipe)
{
long t = ips;
ips = ipe;
ipe = t;
}
return ips <= ipt && ipt <= ipe;
}
/**
* 校验ip是否符合过滤串规则
*
* @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`
* @param ip 校验IP地址
* @return boolean 结果
*/
public static boolean isMatchedIp(String filter, String ip)
{
if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip))
{
return false;
}
String[] ips = filter.split(";");
for (String iStr : ips)
{
if (isIP(iStr) && iStr.equals(ip))
{
return true;
}
else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip))
{
return true;
}
else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip))
{
return true;
}
}
return false;
}
}

View File

@@ -1,19 +1,24 @@
package com.fastbee.common.utils.poi;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Workbook;
/**
* Excel数据格式处理适配器
*
*
* @author ruoyi
*/
public interface ExcelHandlerAdapter
{
/**
* 格式化
*
*
* @param value 单元格数据值
* @param args excel注解args参数组
* @param cell 单元格对象
* @param wb 工作簿对象
*
* @return 处理后的值
*/
Object format(Object value, String[] args);
Object format(Object value, String[] args, Cell cell, Workbook wb);
}

View File

@@ -5,7 +5,7 @@ import com.fastbee.common.utils.StringUtils;
/**
* sql操作工具类
*
*
* @author ruoyi
*/
public class SqlUtil
@@ -13,13 +13,18 @@ public class SqlUtil
/**
* 定义常用的 sql关键字
*/
public static String SQL_REGEX = "and |extractvalue|updatexml|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |+|user()";
public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
/**
* 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
*/
public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
/**
* 限制orderBy最大长度
*/
private static final int ORDER_BY_MAX_LENGTH = 500;
/**
* 检查字符,防止注入绕过
*/
@@ -29,6 +34,10 @@ public class SqlUtil
{
throw new UtilException("参数不符合规范,不能进行查询");
}
if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH)
{
throw new UtilException("参数已超过最大限制,不能进行查询");
}
return value;
}