feat: 代码一键生成类的引入

代码一键生成类的引入代码一键生成类的引入
This commit is contained in:
yangjiyu
2022-11-23 15:49:14 +08:00
parent ad63d614cc
commit 2026a75301
28 changed files with 4557 additions and 0 deletions
@@ -0,0 +1,48 @@
package com.aos.element.common.exception;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 开发环境时输出更多的异常信息 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 14:55
* @since 1.0.0
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExceptionInfo implements Serializable {
/** serialVersionUID */
private static final long serialVersionUID = -5072425562316472427L;
/** 请求路径 */
private String path;
/** 请求参数 */
private Object params;
/** 请求方式 */
private String method;
/** 请求方地址 */
private String remoteAddr;
/** header */
private Object headers;
/** 追踪 id */
private String traceId;
/** 异常类 */
private String exceptionClass;
/** 错误信息 */
private String errorMessage;
/** 异常堆栈 */
private String stackTrace;
/** 日志系统链接 */
private String hyperlink;
}
@@ -0,0 +1,62 @@
package com.aos.starter.core;
import com.aos.element.basic.basic.bundle.DynamicBundle;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.function.Supplier;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: 消息外置, 需要在 resources/messages 创建对应的 [CoreBundle.properties] 文件 </p>
*
* @author dong4j
* @version 1.4.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.05.19 09:26
* @since 1.4.0
*/
public final class CoreBundle extends DynamicBundle {
/** BUNDLE */
@NonNls
private static final String BUNDLE = "messages.CoreBundle";
/** INSTANCE */
private static final CoreBundle INSTANCE = new CoreBundle();
/**
* Plugin bundle
*
* @since 0.0.1
*/
@Contract(pure = true)
private CoreBundle() {
super(BUNDLE);
}
/**
* Message
*
* @param key key
* @param params params
* @return the string
* @since 1.4.0
*/
@NotNull
public static String message(@NotNull String key, Object... params) {
return INSTANCE.getMessage(key, params);
}
/**
* Message pointer
*
* @param key key
* @param params params
* @return the supplier
* @since 1.4.0
*/
public static @NotNull Supplier<String> messagePointer(@NotNull String key, Object... params) {
return INSTANCE.getLazyMessage(key, params);
}
}
@@ -0,0 +1,98 @@
package com.aos.starter.core.api;
import com.aos.element.basic.basic.Result;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.0.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.10.14 00:55
* @since 1.6.0
*/
public interface GeneralResult {
/**
* 请求成功
*
* @param <T> parameter
* @return the result
* @since 1.0.0
*/
default <T> Result<T> ok() {
return this.ok(null);
}
/**
* 请求成功
*
* @param <T> 对象泛型
* @param data 数据内容
* @return the result
* @since 1.0.0
*/
default <T> Result<T> ok(T data) {
return R.succeed(data);
}
/**
* 请求失败
*
* @param <T> parameter
* @param msg 提示内容
* @return the result
* @since 1.0.0
*/
default <T> Result<T> fail(String msg) {
return R.failed(msg);
}
/**
* 请求失败
*
* @param <T> parameter
* @param errorCode 请求错误码
* @return the result
* @since 1.0.0
*/
default <T> Result<T> fail(IResultCode errorCode) {
return R.failed(errorCode);
}
/**
* Status result.
*
* @param flag the flag
* @return the result
* @since 1.0.0
*/
default Result<Boolean> status(boolean flag) {
return this.status(flag, BaseCodes.FAILURE);
}
/**
* Status result
*
* @param flag flag
* @param resultCode result code
* @return the result
* @since 1.0.0
*/
default Result<Boolean> status(boolean flag, IResultCode resultCode) {
return R.status(flag, resultCode);
}
/**
* Status result
*
* @param flag flag
* @param message message
* @return the result
* @since 1.0.0
*/
default Result<Boolean> status(boolean flag, String message) {
return R.status(flag, message);
}
}
@@ -0,0 +1,223 @@
package com.aos.starter.core.assertion;
import com.aos.element.basic.basic.asserts.Assertions;
import com.aos.element.basic.core.function.CheckedCallable;
import com.aos.element.basic.core.function.CheckedRunnable;
import com.aos.starter.core.exception.BaseException;
import java.util.Collection;
import java.util.Map;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 枚举类异常断言,提供简便的方式判断条件,并在条件满足时抛出异常
* 错误码和错误信息定义在枚举类中,在本断言方法中,传递错误信息需要的参数
* 底层会使用 {@link Assertions}
* </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.26 20:06
* @since 1.0.0
*/
public interface IAssert {
/**
* New exception
*
* @param args args
* @return the base exception
* @since 1.7.0
*/
BaseException newException(Object... args);
/**
* New exception
*
* @param t t
* @param args args
* @return the base exception
* @since 1.7.0
*/
BaseException newException(Throwable t, Object... args);
/**
* Not blank
*
* @param str str
* @param args args
* @since 1.7.0
*/
default void notBlank(String str, Object... args) {
Assertions.notBlank(str, () -> this.newException(args));
}
/**
* Not empty
*
* @param arrays arrays
* @param args args
* @since 1.7.0
*/
default void notEmpty(Object[] arrays, Object... args) {
Assertions.notEmpty(arrays, () -> this.newException(args));
}
/**
* Not empty
*
* @param c c
* @param args args
* @since 1.7.0
*/
default void notEmpty(Collection<?> c, Object... args) {
Assertions.notEmpty(c, () -> this.newException(args));
}
/**
* Not empty
*
* @param map map
* @param args args
* @since 1.7.0
*/
default void notEmpty(Map<?, ?> map, Object... args) {
Assertions.notEmpty(map, () -> this.newException(args));
}
/**
* Is false
*
* @param expression expression
* @param args args
* @since 1.7.0
*/
default void isFalse(boolean expression, Object... args) {
Assertions.isFalse(expression, () -> this.newException(args));
}
/**
* Is true
*
* @param expression expression
* @param args args
* @since 1.7.0
*/
default void isTrue(boolean expression, Object... args) {
Assertions.isTrue(expression, () -> this.newException(args));
}
/**
* Is null
*
* @param obj obj
* @param args args
* @since 1.7.0
*/
default void isNull(Object obj, Object... args) {
Assertions.isNull(obj, () -> this.newException(args));
}
/**
* Not null
*
* @param obj obj
* @param args args
* @since 1.7.0
*/
default void notNull(Object obj, Object... args) {
Assertions.notNull(obj, () -> this.newException(args));
}
/**
* 适用于没有占位符的错误消息
*
* @param obj obj
* @param runnable runnable
* @since 1.7.0
*/
default void notNull(Object obj, CheckedRunnable runnable) {
Assertions.notNull(obj, this::newException, runnable);
}
/**
* Equals
*
* @param o1 o 1
* @param o2 o 2
* @param args args
* @since 1.7.0
*/
default void equals(Object o1, Object o2, Object... args) {
Assertions.equals(o1, o2, () -> this.newException(args));
}
/**
* Not equals
*
* @param o1 o 1
* @param o2 o 2
* @param args args
* @since 1.7.0
*/
default void notEquals(Object o1, Object o2, Object... args) {
Assertions.notEquals(o1, o2, () -> this.newException(args));
}
/**
* Wrapper
*
* @param runnable runnable
* @param args args
* @since 1.7.0
*/
default void wrapper(CheckedRunnable runnable, Object... args) {
try {
runnable.run();
} catch (Throwable throwable) {
this.fail(throwable, args);
}
}
/**
* Wrapper
*
* @param <T> parameter
* @param callable callable
* @param args args
* @return the t
* @since 1.8.0
*/
default <T> T wrapper(CheckedCallable<T> callable, Object... args) {
try {
return callable.call();
} catch (Throwable throwable) {
this.fail(throwable, args);
}
return null;
}
/**
* Fail
*
* @param args args
* @since 1.7.0
*/
default void fail(Object... args) {
this.fail(this.newException(args));
}
/**
* Fail
*
* @param t t
* @param args args
* @since 1.7.0
*/
default void fail(Throwable t, Object... args) {
Assertions.fail(() -> this.newException(t, args));
}
}
@@ -0,0 +1,78 @@
package com.aos.starter.core.convert;
import org.jetbrains.annotations.Contract;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 类型 转换 服务,添加了 IEnum 转换 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 18:06
* @since 1.0.0
*/
public final class CustomConversionService extends ApplicationConversionService {
/**
* Custom conversion service
*
* @since 1.0.0
*/
private CustomConversionService() {
this(null);
}
/**
* Custom conversion service
*
* @param embeddedValueResolver the embedded value resolver
* @since 1.0.0
*/
private CustomConversionService(@Nullable StringValueResolver embeddedValueResolver) {
super(embeddedValueResolver);
super.addConverter(new EnumToStringConverter());
super.addConverter(new StringToEnumConverter());
}
/**
* Gets instance.
*
* @return the instance
* @since 1.0.0
*/
@Contract(pure = true)
public static GenericConversionService getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 静态内部类实现单例</p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 18:06
* @since 1.0.0
*/
private static final class SingletonHolder {
/** INSTANCE */
private static final CustomConversionService INSTANCE = new CustomConversionService();
/**
* Singleton holder
*
* @since 1.0.0
*/
@Contract(pure = true)
private SingletonHolder() {
}
}
}
@@ -0,0 +1,99 @@
package com.aos.starter.core.convert;
import com.aos.element.basic.basic.util.ClassUtils;
import com.aos.element.basic.core.function.CheckedFunction;
import com.aos.starter.core.util.ConvertUtils;
import com.aos.starter.core.util.ReflectionUtils;
import com.aos.starter.core.util.Unchecked;
import org.jetbrains.annotations.NotNull;
import org.springframework.cglib.core.Converter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 组合 spring cglib Converter 和 spring ConversionService </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 18:06
* @since 1.0.0
*/
@Slf4j
@AllArgsConstructor
public class CustomConverter implements Converter {
/** TYPE_CACHE */
private static final ConcurrentMap<String, TypeDescriptor> TYPE_CACHE = new ConcurrentHashMap<>();
/** Source clazz */
private final Class<?> sourceClazz;
/** Target clazz */
private final Class<?> targetClazz;
/**
* cglib convert
*
* @param value 源对象属性
* @param target 目标对象属性类
* @param fieldName 目标的field名,原为 set 方法名,MicaBeanCopier 里做了更改
* @return {Object}
* @since 1.0.0
*/
@Override
@Nullable
@SuppressWarnings("checkstyle:ReturnCount")
public Object convert(Object value, Class target, Object fieldName) {
if (value == null) {
return null;
}
// 类型一样,不需要转换
if (ClassUtils.isAssignableValue(target, value)) {
return value;
}
try {
TypeDescriptor targetDescriptor = CustomConverter.getTypeDescriptor(this.targetClazz, (String) fieldName);
// 1. 判断 sourceClazz 为 Map
if (Map.class.isAssignableFrom(this.sourceClazz)) {
return ConvertUtils.convert(value, targetDescriptor);
} else {
TypeDescriptor sourceDescriptor = CustomConverter.getTypeDescriptor(this.sourceClazz, (String) fieldName);
return ConvertUtils.convert(value, sourceDescriptor, targetDescriptor);
}
} catch (Exception e) {
log.warn("Converter error", e);
}
return null;
}
/**
* Gets type descriptor *
*
* @param clazz clazz
* @param fieldName field name
* @return the type descriptor
* @since 1.0.0
*/
private static TypeDescriptor getTypeDescriptor(@NotNull Class<?> clazz, String fieldName) {
String srcCacheKey = clazz.getName() + fieldName;
// 忽略抛出异常的函数,定义完整泛型,避免编译问题
CheckedFunction<String, TypeDescriptor> uncheckedFunction = key -> {
// 这里 property 理论上不会为 null
Field field = ReflectionUtils.getField(clazz, fieldName);
if (field == null) {
throw new NoSuchFieldException(fieldName);
}
return new TypeDescriptor(field);
};
return TYPE_CACHE.computeIfAbsent(srcCacheKey, Unchecked.function(uncheckedFunction));
}
}
@@ -0,0 +1,160 @@
package com.aos.starter.core.convert;
import com.google.common.collect.Maps;
import com.aos.starter.core.util.ConvertUtils;
import com.fasterxml.jackson.annotation.JsonValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import lombok.extern.slf4j.Slf4j;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 接收参数 同 jackson Enum -> String 转换 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 18:05
* @since 1.0.0
*/
@Slf4j
public class EnumToStringConverter implements ConditionalGenericConverter {
/** 缓存 Enum 类信息,提供性能 */
private static final ConcurrentMap<Class<?>, AccessibleObject> ENUM_CACHE_MAP = Maps.newConcurrentMap();
/**
* Matches boolean
*
* @param sourceType source type
* @param targetType target type
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean matches(@NotNull TypeDescriptor sourceType, @NotNull TypeDescriptor targetType) {
return true;
}
/**
* Gets convertible types *
*
* @return the convertible types
* @since 1.0.0
*/
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
Set<ConvertiblePair> pairSet = new HashSet<>(4);
pairSet.add(new ConvertiblePair(Enum.class, String.class));
pairSet.add(new ConvertiblePair(Enum.class, Integer.class));
pairSet.add(new ConvertiblePair(Enum.class, Long.class));
return Collections.unmodifiableSet(pairSet);
}
/**
* Convert object
*
* @param source source
* @param sourceType source type
* @param targetType target type
* @return the object
* @since 1.0.0
*/
@Override
@SuppressWarnings("all")
public Object convert(@Nullable Object source, @NotNull TypeDescriptor sourceType, @NotNull TypeDescriptor targetType) {
if (source == null) {
return null;
}
Class<?> sourceClazz = sourceType.getType();
AccessibleObject accessibleObject = ENUM_CACHE_MAP.computeIfAbsent(sourceClazz, EnumToStringConverter::getAnnotation);
Class<?> targetClazz = targetType.getType();
// 如果为null,走默认的转换
if (accessibleObject == null) {
if (String.class == targetClazz) {
return ((Enum) source).name();
}
int ordinal = ((Enum) source).ordinal();
return ConvertUtils.convert(ordinal, targetClazz);
}
try {
return EnumToStringConverter.invoke(sourceClazz, accessibleObject, source, targetClazz);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
/**
* Gets annotation *
*
* @param clazz clazz
* @return the annotation
* @since 1.0.0
*/
@Nullable
@SuppressWarnings("java:S3011")
private static AccessibleObject getAnnotation(@NotNull Class<?> clazz) {
Set<AccessibleObject> accessibleObjects = new HashSet<>();
// JsonValue METHOD, FIELD
Field[] fields = clazz.getDeclaredFields();
Collections.addAll(accessibleObjects, fields);
// methods
Method[] methods = clazz.getDeclaredMethods();
Collections.addAll(accessibleObjects, methods);
for (AccessibleObject accessibleObject : accessibleObjects) {
// 复用 jackson 的 JsonValue 注解
JsonValue jsonValue = accessibleObject.getAnnotation(JsonValue.class);
if (jsonValue != null && jsonValue.value()) {
accessibleObject.setAccessible(true);
return accessibleObject;
}
}
return null;
}
/**
* Invoke object
*
* @param clazz clazz
* @param accessibleObject accessible object
* @param source source
* @param targetClazz target clazz
* @return the object
* @throws IllegalAccessException illegal access exception
* @throws InvocationTargetException invocation target exception
* @since 1.0.0
*/
@Nullable
private static Object invoke(Class<?> clazz, AccessibleObject accessibleObject, Object source, Class<?> targetClazz)
throws IllegalAccessException, InvocationTargetException {
Object value = null;
if (accessibleObject instanceof Field) {
Field field = (Field) accessibleObject;
value = field.get(source);
} else if (accessibleObject instanceof Method) {
Method method = (Method) accessibleObject;
Class<?> paramType = method.getParameterTypes()[0];
// 类型转换
Object object = ConvertUtils.convert(source, paramType);
value = method.invoke(clazz, object);
}
if (value == null) {
return null;
}
return ConvertUtils.convert(value, targetClazz);
}
}
@@ -0,0 +1,22 @@
package com.aos.starter.core.enums;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: 字段填充策略枚举类 </p>
*
* @author dong4j
* @version 1.3.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.04.08 12:41
* @since 1.0.0
*/
public enum FieldFill {
/** 默认不处理 */
DEFAULT,
/** 插入时填充字段 */
INSERT,
/** 更新时填充字段 */
UPDATE,
/** 插入和更新时填充字段 */
INSERT_UPDATE
}
@@ -0,0 +1,154 @@
package com.aos.starter.core.jackson;
import com.aos.element.basic.basic.util.StringPool;
import com.aos.element.basic.basic.util.StringUtils;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.time.OffsetDateTime;
import java.time.temporal.TemporalAccessor;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: jackson 默认值为 null 时的处理, 主要是为了避免 app 端出现null导致闪退
* 规则:
* {@code
* number: 0
* string: null
* date: null
* boolean: false
* array: []
* Object: {}
* }
* todo-dong4j : (2020-07-10 14:5) [提供扩展接口, 可自定义 changeProperties ]
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.24 01:46
* @since 1.0.0
*/
public class DefaultBeanSerializerModifier extends com.fasterxml.jackson.databind.ser.BeanSerializerModifier {
/**
* Change properties list
*
* @param config config
* @param beanDesc bean desc
* @param beanProperties bean properties
* @return the list
* @see DefaultSerializerProvider#_serializeNull(JsonGenerator)
* @since 1.0.0
*/
@Override
@SuppressWarnings("all")
public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
BeanDescription beanDesc,
@NotNull List<BeanPropertyWriter> beanProperties) {
beanProperties.forEach(writer -> {
// 如果已经有 null 序列化处理如注解: @JsonSerialize(nullsUsing = xxx) 跳过
if (writer.hasNullSerializer()) {
return;
}
JavaType type = writer.getType();
Class<?> clazz = type.getRawClass();
if (type.isTypeOrSubTypeOf(Number.class)) {
// writer.assignNullSerializer(NullJsonSerializers.NUMBER_JSON_SERIALIZER);
} else if (type.isTypeOrSubTypeOf(Boolean.class)) {
writer.assignNullSerializer(NullJsonSerializers.BOOLEAN_JSON_SERIALIZER);
} else if (type.isTypeOrSubTypeOf(Character.class)) {
writer.assignNullSerializer(NullJsonSerializers.STRING_JSON_SERIALIZER);
} else if (type.isTypeOrSubTypeOf(String.class)) {
writer.assignNullSerializer(NullJsonSerializers.STRING_JSON_SERIALIZER);
} else if (type.isArrayType() || clazz.isArray() || type.isTypeOrSubTypeOf(Collection.class)) {
writer.assignNullSerializer(NullJsonSerializers.ARRAY_JSON_SERIALIZER);
} else if (type.isTypeOrSubTypeOf(OffsetDateTime.class)) {
writer.assignNullSerializer(NullJsonSerializers.STRING_JSON_SERIALIZER);
} else if (type.isTypeOrSubTypeOf(Date.class) || type.isTypeOrSubTypeOf(TemporalAccessor.class)) {
writer.assignNullSerializer(NullJsonSerializers.STRING_JSON_SERIALIZER);
} else {
writer.assignNullSerializer(NullJsonSerializers.OBJECT_JSON_SERIALIZER);
}
});
return super.changeProperties(config, beanDesc, beanProperties);
}
/**
* The interface Null json serializers.
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.24 01:46
* @since 1.0.0
*/
@SuppressWarnings("checkstyle:InterfaceIsType")
public interface NullJsonSerializers {
/**
* The constant STRING_JSON_SERIALIZER.
*/
JsonSerializer<Object> STRING_JSON_SERIALIZER = new JsonSerializer<Object>() {
@Override
public void serialize(Object value, @NotNull JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(StringPool.EMPTY);
}
};
/**
* The constant NUMBER_JSON_SERIALIZER.
*/
JsonSerializer<Object> NUMBER_JSON_SERIALIZER = new JsonSerializer<Object>() {
@Override
public void serialize(Object value, @NotNull JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeNumber(StringUtils.INDEX_NOT_FOUND);
}
};
/**
* The constant BOOLEAN_JSON_SERIALIZER.
*/
JsonSerializer<Object> BOOLEAN_JSON_SERIALIZER = new JsonSerializer<Object>() {
@Override
public void serialize(Object value, @NotNull JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeObject(Boolean.FALSE);
}
};
/**
* The constant ARRAY_JSON_SERIALIZER.
*/
JsonSerializer<Object> ARRAY_JSON_SERIALIZER = new JsonSerializer<Object>() {
@Override
public void serialize(Object value, @NotNull JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartArray();
gen.writeEndArray();
}
};
/**
* The constant OBJECT_JSON_SERIALIZER.
*/
JsonSerializer<Object> OBJECT_JSON_SERIALIZER = new JsonSerializer<Object>() {
@Override
public void serialize(Object value, @NotNull JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
gen.writeEndObject();
}
};
}
}
@@ -0,0 +1,39 @@
package com.aos.starter.core.node;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 森林节点类</p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.26 20:42
* @since 1.0.0
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class ForestNode extends BaseNode {
/**
* 节点内容
*/
private Object content;
/**
* Instantiates a new Forest node.
*
* @param id the id
* @param parentId the parent id
* @param content the content
* @since 1.0.0
*/
public ForestNode(Integer id, Integer parentId, Object content) {
this.id = id;
this.parentId = parentId;
this.content = content;
}
}
@@ -0,0 +1,81 @@
package com.aos.starter.core.node;
import java.util.ArrayList;
import java.util.List;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 森林管理类</p>
*
* @param <T> the type parameter
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 14:53
* @since 1.0.0
*/
public class ForestNodeManager<T extends INode> {
/**
* 森林的所有节点
*/
private final List<T> list;
/**
* 森林的父节点ID
*/
private final List<Integer> parentIds = new ArrayList<>();
/**
* Instantiates a new Forest node manager.
*
* @param items the items
* @since 1.0.0
*/
public ForestNodeManager(List<T> items) {
list = items;
}
/**
* 根据节点ID获取一个节点
*
* @param id 节点ID
* @return 对应的节点对象 tree node at
* @since 1.0.0
*/
public INode getTreeNodeAt(int id) {
for (INode forestNode : list) {
if (forestNode.getId() == id) {
return forestNode;
}
}
return null;
}
/**
* 增加父节点ID
*
* @param parentId 父节点ID
* @since 1.0.0
*/
public void addParentId(Integer parentId) {
parentIds.add(parentId);
}
/**
* 获取树的根节点(一个森林对应多颗树)
*
* @return 树的根节点集合 root
* @since 1.0.0
*/
public List<T> getRoot() {
List<T> roots = new ArrayList<>();
for (T forestNode : list) {
if (forestNode.getParentId() == 0 || parentIds.contains(forestNode.getId())) {
roots.add(forestNode);
}
}
return roots;
}
}
@@ -0,0 +1,41 @@
package com.aos.starter.core.node;
import java.util.List;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 森林节点归并类 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.26 20:42
* @since 1.0.0
*/
public class ForestNodeMerger {
/**
* 将节点数组归并为一个森林 (多棵树) (填充节点的children域)
* 时间复杂度为O(n^2)
*
* @param <T> T 泛型标记
* @param items 节点域
* @return 多棵树的根节点集合 list
* @since 1.0.0
*/
public static <T extends INode> List<T> merge(List<T> items) {
ForestNodeManager<T> forestNodeManager = new ForestNodeManager<>(items);
items.forEach(forestNode -> {
if (forestNode.getParentId() != 0) {
INode node = forestNodeManager.getTreeNodeAt(forestNode.getParentId());
if (node != null) {
node.getChildren().add(forestNode);
} else {
forestNodeManager.addParentId(forestNode.getId());
}
}
});
return forestNodeManager.getRoot();
}
}
@@ -0,0 +1,53 @@
package com.aos.starter.core.reflection;
import com.aos.starter.core.reflection.factory.DefaultObjectFactory;
import com.aos.starter.core.reflection.factory.ObjectFactory;
import com.aos.starter.core.reflection.wrapper.DefaultObjectWrapperFactory;
import com.aos.starter.core.reflection.wrapper.ObjectWrapperFactory;
import org.jetbrains.annotations.Contract;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: 默认的实体元数据包装对象, 使用 {@link DefaultMetaObject#forObject} 生成 {@link MetaObject}</p>
*
* @author dong4j
* @version 1.3.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.04.12 11:30
* @since 1.0.0
*/
public final class DefaultMetaObject {
/** DEFAULT_OBJECT_FACTORY */
public static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
/** DEFAULT_OBJECT_WRAPPER_FACTORY */
public static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
/** NULL_META_OBJECT */
public static final MetaObject NULL_META_OBJECT = MetaObject.forObject(Object.class,
DEFAULT_OBJECT_FACTORY,
DEFAULT_OBJECT_WRAPPER_FACTORY,
new DefaultReflectorFactory());
/**
* Default meta object
*
* @since 1.0.0
*/
@Contract(pure = true)
private DefaultMetaObject() {
}
/**
* For object meta object
*
* @param object object
* @return the meta object
* @since 1.0.0
*/
@Contract("!null -> new")
public static MetaObject forObject(Object object) {
return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
}
}
@@ -0,0 +1,61 @@
package com.aos.starter.core.reflection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.3.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.04.12 11:54
* @since 1.0.0
*/
public class DefaultReflectorFactory implements ReflectorFactory {
/** Reflector map */
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();
/** Class cache enabled */
private boolean classCacheEnabled = true;
/**
* Is class cache enabled boolean
*
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean isClassCacheEnabled() {
return this.classCacheEnabled;
}
/**
* Sets class cache enabled *
*
* @param classCacheEnabled class cache enabled
* @since 1.0.0
*/
@Override
public void setClassCacheEnabled(boolean classCacheEnabled) {
this.classCacheEnabled = classCacheEnabled;
}
/**
* Find for class reflector
*
* @param type type
* @return the reflector
* @since 1.0.0
*/
@Override
public Reflector findForClass(Class<?> type) {
if (this.classCacheEnabled) {
// synchronized (type) removed see issue #461
return this.reflectorMap.computeIfAbsent(type, Reflector::new);
} else {
return new Reflector(type);
}
}
}
@@ -0,0 +1,155 @@
package com.aos.starter.core.reflection.factory;
import com.aos.starter.core.reflection.ReflectionException;
import com.aos.starter.core.reflection.Reflector;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.3.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.04.12 11:46
* @since 1.0.0
*/
public class DefaultObjectFactory implements ObjectFactory, Serializable {
/** serialVersionUID */
private static final long serialVersionUID = -8855120656740914948L;
/**
* Create t
*
* @param <T> parameter
* @param type type
* @return the t
* @since 1.0.0
*/
@Override
public <T> T create(Class<T> type) {
return this.create(type, null, null);
}
/**
* Create t
*
* @param <T> parameter
* @param type type
* @param constructorArgTypes constructor arg types
* @param constructorArgs constructor args
* @return the t
* @since 1.0.0
*/
@SuppressWarnings("unchecked")
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
Class<?> classToCreate = this.resolveInterface(type);
// we know types are assignable
return (T) this.instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
}
/**
* Is collection boolean
*
* @param <T> parameter
* @param type type
* @return the boolean
* @since 1.0.0
*/
@Override
public <T> boolean isCollection(Class<T> type) {
return Collection.class.isAssignableFrom(type);
}
/**
* Resolve interface class
*
* @param type type
* @return the class
* @since 1.0.0
*/
protected Class<?> resolveInterface(Class<?> type) {
Class<?> classToCreate;
if (type == List.class || type == Collection.class || type == Iterable.class) {
classToCreate = ArrayList.class;
} else if (type == Map.class) {
classToCreate = HashMap.class;
} else if (type == SortedSet.class) {
classToCreate = TreeSet.class;
} else if (type == Set.class) {
classToCreate = HashSet.class;
} else {
classToCreate = type;
}
return classToCreate;
}
/**
* Instantiate class t
*
* @param <T> parameter
* @param type type
* @param constructorArgTypes constructor arg types
* @param constructorArgs constructor args
* @return the t
* @since 1.0.0
*/
@SuppressWarnings("all")
private <T> @NotNull T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
try {
Constructor<T> constructor;
if (constructorArgTypes == null || constructorArgs == null) {
constructor = type.getDeclaredConstructor();
try {
return constructor.newInstance();
} catch (IllegalAccessException e) {
if (Reflector.canControlMemberAccessible()) {
constructor.setAccessible(true);
return constructor.newInstance();
} else {
throw e;
}
}
}
constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[0]));
try {
return constructor.newInstance(constructorArgs.toArray(new Object[0]));
} catch (IllegalAccessException e) {
if (Reflector.canControlMemberAccessible()) {
constructor.setAccessible(true);
return constructor.newInstance(constructorArgs.toArray(new Object[0]));
} else {
throw e;
}
}
} catch (Exception e) {
String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList)
.stream().map(Class::getSimpleName).collect(Collectors.joining(","));
String argValues = Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList)
.stream().map(String::valueOf).collect(Collectors.joining(","));
throw new ReflectionException("Error instantiating {} with invalid types ({}) or values ({}). Cause: ",
type, argTypes, argValues, e, e);
}
}
}
@@ -0,0 +1,67 @@
package com.aos.starter.core.reflection.invoker;
import com.aos.starter.core.reflection.Reflector;
import org.jetbrains.annotations.Contract;
import java.lang.reflect.Field;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.3.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.04.12 11:46
* @since 1.0.0
*/
public class GetFieldInvoker implements Invoker {
/** Field */
private final Field field;
/**
* Get field invoker
*
* @param field field
* @since 1.0.0
*/
@Contract(pure = true)
public GetFieldInvoker(Field field) {
this.field = field;
}
/**
* Invoke object
*
* @param target target
* @param args args
* @return the object
* @throws IllegalAccessException illegal access exception
* @since 1.0.0
*/
@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException {
try {
return this.field.get(target);
} catch (IllegalAccessException e) {
if (Reflector.canControlMemberAccessible()) {
this.field.setAccessible(true);
return this.field.get(target);
} else {
throw e;
}
}
}
/**
* Gets type *
*
* @return the type
* @since 1.0.0
*/
@Override
public Class<?> getType() {
return this.field.getType();
}
}
@@ -0,0 +1,43 @@
package com.aos.starter.core.reflection.wrapper;
import com.aos.starter.core.reflection.MetaObject;
import com.aos.starter.core.reflection.ReflectionException;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.3.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.04.12 11:52
* @since 1.0.0
*/
public class DefaultObjectWrapperFactory implements ObjectWrapperFactory {
/**
* Has wrapper for boolean
*
* @param object object
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean hasWrapperFor(Object object) {
return false;
}
/**
* Gets wrapper for *
*
* @param metaObject meta object
* @param object object
* @return the wrapper for
* @since 1.0.0
*/
@Override
public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
throw new ReflectionException("The DefaultObjectWrapperFactory should never be called to provide an ObjectWrapper.");
}
}
@@ -0,0 +1,97 @@
package com.aos.starter.core.util;
import com.aos.starter.core.convert.CustomConversionService;
import org.jetbrains.annotations.Contract;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.lang.Nullable;
import lombok.experimental.UtilityClass;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 基于 spring ConversionService 类型转换 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 18:18
* @since 1.0.0
*/
@UtilityClass
@SuppressWarnings("unchecked")
public class ConvertUtils {
/**
* Convenience operation for converting a source object to the specified targetType.
* {@link TypeDescriptor#forObject(Object)}.
*
* @param <T> 泛型标记
* @param source the source object
* @param targetType the target type
* @return the converted value
* @throws IllegalArgumentException if targetType is {@code null}, or sourceType is {@code null} but source is not {@code null}
* @since 1.0.0
*/
@Contract("null, _ -> null")
@Nullable
public static <T> T convert(@Nullable Object source, Class<T> targetType) {
if (source == null) {
return null;
}
if (ClassUtils.isAssignableValue(targetType, source)) {
return (T) source;
}
GenericConversionService conversionService = CustomConversionService.getInstance();
return conversionService.convert(source, targetType);
}
/**
* Convenience operation for converting a source object to the specified targetType,
* where the target type is a descriptor that provides additional conversion context.
* {@link TypeDescriptor#forObject(Object)}.
*
* @param <T> 泛型标记
* @param source the source object
* @param sourceType the source type
* @param targetType the target type
* @return the converted value
* @throws IllegalArgumentException if targetType is {@code null}, or sourceType is {@code null} but source is not {@code null}
* @since 1.0.0
*/
@Contract("null, _, _ -> null")
@Nullable
public static <T> T convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
return null;
}
GenericConversionService conversionService = CustomConversionService.getInstance();
return (T) conversionService.convert(source, sourceType, targetType);
}
/**
* Convenience operation for converting a source object to the specified targetType,
* where the target type is a descriptor that provides additional conversion context.
* Simply delegates to {@link #convert(Object, TypeDescriptor, TypeDescriptor)} and
* encapsulates the construction of the source type descriptor using
* {@link TypeDescriptor#forObject(Object)}.
*
* @param <T> 泛型标记
* @param source the source object
* @param targetType the target type
* @return the converted value
* @throws IllegalArgumentException if targetType is {@code null}, or sourceType is {@code null} but source is not {@code null}
* @since 1.0.0
*/
@Contract("null, _ -> null")
@Nullable
public static <T> T convert(@Nullable Object source, TypeDescriptor targetType) {
if (source == null) {
return null;
}
GenericConversionService conversionService = CustomConversionService.getInstance();
return (T) conversionService.convert(source, targetType);
}
}
@@ -0,0 +1,136 @@
package com.aos.starter.core.util;
import org.jetbrains.annotations.NotNull;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import lombok.experimental.UtilityClass;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: DateTime 工具类 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 18:18
* @since 1.0.0
*/
@UtilityClass
public class DateTimeUtils {
/**
* The constant DATETIME_FORMAT.
*/
public static final DateTimeFormatter DATETIME_FORMAT = DateTimeFormatter.ofPattern(DateUtils.PATTERN_DATETIME);
/**
* The constant DATE_FORMAT.
*/
public static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern(DateUtils.PATTERN_DATE);
/**
* The constant TIME_FORMAT.
*/
public static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern(DateUtils.PATTERN_TIME);
/**
* 日期时间格式化
*
* @param temporal 时间
* @return 格式化后的时间 string
* @since 1.0.0
*/
@NotNull
public static String formatDateTime(TemporalAccessor temporal) {
return DATETIME_FORMAT.format(temporal);
}
/**
* 日期时间格式化
*
* @param temporal 时间
* @return 格式化后的时间 string
* @since 1.0.0
*/
@NotNull
public static String formatDate(TemporalAccessor temporal) {
return DATE_FORMAT.format(temporal);
}
/**
* 时间格式化
*
* @param temporal 时间
* @return 格式化后的时间 string
* @since 1.0.0
*/
@NotNull
public static String formatTime(TemporalAccessor temporal) {
return TIME_FORMAT.format(temporal);
}
/**
* 日期格式化
*
* @param temporal 时间
* @param pattern 表达式
* @return 格式化后的时间 string
* @since 1.0.0
*/
@NotNull
public static String format(TemporalAccessor temporal, String pattern) {
return DateTimeFormatter.ofPattern(pattern).format(temporal);
}
/**
* 将字符串转换为时间
*
* @param dateStr 时间字符串
* @param pattern 表达式
* @return 时间 temporal accessor
* @since 1.0.0
*/
@NotNull
public static TemporalAccessor parse(String dateStr, String pattern) {
DateTimeFormatter format = DateTimeFormatter.ofPattern(pattern);
return format.parse(dateStr);
}
/**
* 将字符串转换为时间
*
* @param dateStr 时间字符串
* @param formatter DateTimeFormatter
* @return 时间 temporal accessor
* @since 1.0.0
*/
@NotNull
public static TemporalAccessor parse(String dateStr, @NotNull DateTimeFormatter formatter) {
return formatter.parse(dateStr);
}
/**
* 时间转 Instant
*
* @param dateTime 时间
* @return Instant instant
* @since 1.0.0
*/
public static Instant toInstant(@NotNull LocalDateTime dateTime) {
return dateTime.atZone(ZoneId.systemDefault()).toInstant();
}
/**
* Instant 转 时间
*
* @param instant Instant
* @return Instant local date time
* @since 1.0.0
*/
@NotNull
public static LocalDateTime toDateTime(Instant instant) {
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
}
}
@@ -0,0 +1,827 @@
package com.aos.starter.core.util;
import com.aos.element.basic.basic.asserts.Assertions;
import com.aos.element.basic.basic.constant.ConfigDefaultValue;
import com.aos.element.basic.basic.util.ConcurrentDateFormat;
import com.aos.element.basic.basic.util.Exceptions;
import com.aos.element.basic.basic.util.StringPool;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.Assert;
import java.text.ParseException;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalQuery;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import lombok.experimental.UtilityClass;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 日期工具类 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2019.12.09 10:38
* @since 1.0.0
*/
@UtilityClass
@SuppressWarnings("checkstyle:MethodLimit")
public class DateUtils {
/** PATTERN_MS_DATETIME */
public static final String PATTERN_MS_DATETIME = ConfigDefaultValue.DEFAULT_DATE_FORMAT.concat(":SSS");
/** The constant PATTERN_DATETIME. */
public static final String PATTERN_DATETIME = ConfigDefaultValue.DEFAULT_DATE_FORMAT;
/** The constant PATTERN_DATE. */
public static final String PATTERN_DATE = "yyyy-MM-dd";
/** The constant PATTERN_DATE_HOUR. */
public static final String PATTERN_DATE_HOUR = "yyyy-MM-dd HH";
/** PATTERN_MONTH */
public static final String PATTERN_MONTH = "yyyyMM";
/** 时分秒 */
public static final String PATTERN_TIME = "HH:mm:ss";
/** PATTERN_DATE_NO_SEPARATOR */
public static final String PATTERN_DATE_NO_SEPARATOR = "yyyyMMdd";
/** PATTERN_TIME_NO_SEPARATOR */
public static final String PATTERN_TIME_NO_SEPARATOR = "HHmmss";
/** PATTERN_DATETIME_NO_SEPARATOR */
public static final String PATTERN_DATETIME_NO_SEPARATOR = PATTERN_DATE_NO_SEPARATOR + PATTERN_TIME_NO_SEPARATOR;
/** 老 date 格式化 */
public static final ConcurrentDateFormat DATETIME_FORMAT = ConcurrentDateFormat.of(PATTERN_DATETIME);
/** DATETIME_FORMAT_NO_SEPARATOR */
public static final ConcurrentDateFormat DATETIME_FORMAT_NO_SEPARATOR = ConcurrentDateFormat.of(PATTERN_DATETIME_NO_SEPARATOR);
/** The constant DATE_FORMAT. */
public static final ConcurrentDateFormat DATE_FORMAT = ConcurrentDateFormat.of(PATTERN_DATE);
/** DATE_FORMAT_NO_SEPARATOR */
public static final ConcurrentDateFormat DATE_FORMAT_NO_SEPARATOR = ConcurrentDateFormat.of(PATTERN_DATE_NO_SEPARATOR);
/** The constant TIME_FORMAT. */
public static final ConcurrentDateFormat TIME_FORMAT = ConcurrentDateFormat.of(PATTERN_TIME);
/** TIME_FORMAT_NO_SEPARATOR */
public static final ConcurrentDateFormat TIME_FORMAT_NO_SEPARATOR = ConcurrentDateFormat.of(PATTERN_TIME_NO_SEPARATOR);
/** java 8 时间格式化 */
public static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern(DateUtils.PATTERN_DATETIME);
/** DATETIME_FORMATTER_NO_SEPARATOR */
public static final DateTimeFormatter DATETIME_FORMATTER_NO_SEPARATOR =
DateTimeFormatter.ofPattern(DateUtils.PATTERN_DATETIME_NO_SEPARATOR);
/** The constant DATE_FORMATTER. */
public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(DateUtils.PATTERN_DATE);
/** DATE_FORMATTER_NO_SEPARATOR */
public static final DateTimeFormatter DATE_FORMATTER_NO_SEPARATOR = DateTimeFormatter.ofPattern(DateUtils.PATTERN_DATE_NO_SEPARATOR);
/** The constant TIME_FORMATTER. */
public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern(DateUtils.PATTERN_TIME);
/** TIME_FORMATTER_NO_SEPARATOR */
public static final DateTimeFormatter TIME_FORMATTER_NO_SEPARATOR = DateTimeFormatter.ofPattern(DateUtils.PATTERN_TIME_NO_SEPARATOR);
/**
* 添加年
*
* @param date 时间
* @param yearsToAdd 添加的年数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date plusYears(Date date, int yearsToAdd) {
return DateUtils.set(date, Calendar.YEAR, yearsToAdd);
}
/**
* 设置日期属性
*
* @param date 时间
* @param calendarField 更改的属性
* @param amount 更改数,-1表示减少
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
private static Date set(Date date, int calendarField, int amount) {
Assert.notNull(date, "The date must not be null");
Calendar c = Calendar.getInstance();
c.setLenient(false);
c.setTime(date);
c.add(calendarField, amount);
return c.getTime();
}
/**
* 添加月
*
* @param date 时间
* @param monthsToAdd 添加的月数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date plusMonths(Date date, int monthsToAdd) {
return DateUtils.set(date, Calendar.MONTH, monthsToAdd);
}
/**
* 添加周
*
* @param date 时间
* @param weeksToAdd 添加的周数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date plusWeeks(Date date, int weeksToAdd) {
return DateUtils.plus(date, Period.ofWeeks(weeksToAdd));
}
/**
* 日期添加时间量
*
* @param date 时间
* @param amount 时间量
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date plus(@NotNull Date date, TemporalAmount amount) {
Instant instant = date.toInstant();
return Date.from(instant.plus(amount));
}
/**
* 添加天
*
* @param date 时间
* @param daysToAdd 添加的天数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date plusDays(Date date, long daysToAdd) {
return DateUtils.plus(date, Duration.ofDays(daysToAdd));
}
/**
* 添加小时
*
* @param date 时间
* @param hoursToAdd 添加的小时数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date plusHours(Date date, long hoursToAdd) {
return DateUtils.plus(date, Duration.ofHours(hoursToAdd));
}
/**
* 添加分钟
*
* @param date 时间
* @param minutesToAdd 添加的分钟数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date plusMinutes(Date date, long minutesToAdd) {
return DateUtils.plus(date, Duration.ofMinutes(minutesToAdd));
}
/**
* 添加秒
*
* @param date 时间
* @param secondsToAdd 添加的秒数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date plusSeconds(Date date, long secondsToAdd) {
return DateUtils.plus(date, Duration.ofSeconds(secondsToAdd));
}
/**
* 添加毫秒
*
* @param date 时间
* @param millisToAdd 添加的毫秒数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date plusMillis(Date date, long millisToAdd) {
return DateUtils.plus(date, Duration.ofMillis(millisToAdd));
}
/**
* 添加纳秒
*
* @param date 时间
* @param nanosToAdd 添加的纳秒数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date plusNanos(Date date, long nanosToAdd) {
return DateUtils.plus(date, Duration.ofNanos(nanosToAdd));
}
/**
* 减少年
*
* @param date 时间
* @param years 减少的年数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date minusYears(Date date, int years) {
return DateUtils.set(date, Calendar.YEAR, -years);
}
/**
* 减少月
*
* @param date 时间
* @param months 减少的月数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date minusMonths(Date date, int months) {
return DateUtils.set(date, Calendar.MONTH, -months);
}
/**
* 减少周
*
* @param date 时间
* @param weeks 减少的周数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date minusWeeks(Date date, int weeks) {
return DateUtils.minus(date, Period.ofWeeks(weeks));
}
/**
* 日期减少时间量
*
* @param date 时间
* @param amount 时间量
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date minus(@NotNull Date date, TemporalAmount amount) {
Instant instant = date.toInstant();
return Date.from(instant.minus(amount));
}
/**
* 减少天
*
* @param date 时间
* @param days 减少的天数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date minusDays(Date date, long days) {
return DateUtils.minus(date, Duration.ofDays(days));
}
/**
* 减少小时
*
* @param date 时间
* @param hours 减少的小时数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date minusHours(Date date, long hours) {
return DateUtils.minus(date, Duration.ofHours(hours));
}
/**
* 减少分钟
*
* @param date 时间
* @param minutes 减少的分钟数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date minusMinutes(Date date, long minutes) {
return DateUtils.minus(date, Duration.ofMinutes(minutes));
}
/**
* 减少秒
*
* @param date 时间
* @param seconds 减少的秒数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date minusSeconds(Date date, long seconds) {
return DateUtils.minus(date, Duration.ofSeconds(seconds));
}
/**
* 减少毫秒
*
* @param date 时间
* @param millis 减少的毫秒数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date minusMillis(Date date, long millis) {
return DateUtils.minus(date, Duration.ofMillis(millis));
}
/**
* 减少纳秒
*
* @param date 时间
* @param nanos 减少的纳秒数
* @return 设置后的时间 date
* @since 1.0.0
*/
@NotNull
public static Date minusNanos(Date date, long nanos) {
return DateUtils.minus(date, Duration.ofNanos(nanos));
}
/**
* 日期时间格式化
*
* @param date 时间
* @return 格式化后的时间 string
* @since 1.0.0
*/
public static String formatDateTime(Date date) {
return DATETIME_FORMAT.format(date);
}
/**
* 日期格式化
*
* @param date 时间
* @return 格式化后的时间 string
* @since 1.0.0
*/
public static String formatDate(Date date) {
return DATE_FORMAT.format(date);
}
/**
* 时间格式化
*
* @param date 时间
* @return 格式化后的时间 string
* @since 1.0.0
*/
public static String formatTime(Date date) {
return TIME_FORMAT.format(date);
}
/**
* java8 日期时间格式化
*
* @param temporal 时间
* @return 格式化后的时间 string
* @since 1.0.0
*/
@NotNull
public static String formatDateTime(TemporalAccessor temporal) {
return DATETIME_FORMATTER.format(temporal);
}
/**
* java8 日期时间格式化
*
* @param temporal 时间
* @return 格式化后的时间 string
* @since 1.0.0
*/
@NotNull
public static String formatDate(TemporalAccessor temporal) {
return DATE_FORMATTER.format(temporal);
}
/**
* java8 时间格式化
*
* @param temporal 时间
* @return 格式化后的时间 string
* @since 1.0.0
*/
@NotNull
public static String formatTime(TemporalAccessor temporal) {
return TIME_FORMATTER.format(temporal);
}
/**
* java8 日期格式化
*
* @param temporal 时间
* @param pattern 表达式
* @return 格式化后的时间 string
* @since 1.0.0
*/
@NotNull
public static String format(TemporalAccessor temporal, String pattern) {
return DateTimeFormatter.ofPattern(pattern).format(temporal);
}
/**
* Parse date time
*
* @param dateStr date str
* @return the date
* @since 1.6.0
*/
public static Date parseDateTime(String dateStr) {
return parse(dateStr, PATTERN_DATETIME);
}
/**
* 将字符串转换为时间
*
* @param dateStr 时间字符串
* @param pattern 表达式
* @return 时间 date
* @since 1.0.0
*/
@NotNull
public static Date parse(String dateStr, String pattern) {
Assertions.notBlank(dateStr, "参数错误, 时间字符串不能为空");
ConcurrentDateFormat format = ConcurrentDateFormat.of(pattern);
try {
return format.parse(dateStr);
} catch (ParseException e) {
throw Exceptions.unchecked(StringUtils.format("不能将 {} 以 {} 格式转换为 Date 类型", dateStr, pattern), e);
}
}
/**
* 将字符串转换为时间
*
* @param dateStr 时间字符串
* @param format ConcurrentDateFormat
* @return 时间 date
* @since 1.0.0
*/
public static Date parse(String dateStr, @NotNull ConcurrentDateFormat format) {
try {
return format.parse(dateStr);
} catch (ParseException e) {
throw Exceptions.unchecked(StringUtils.format("不能将 {} 以 {} 格式转换为 Date 类型", dateStr, format.getFormat()), e);
}
}
/**
* 将字符串转换为时间
*
* @param <T> the type parameter
* @param dateStr 时间字符串
* @param pattern 表达式
* @param query the query
* @return 时间 t
* @since 1.0.0
*/
public static <T> T parse(String dateStr, String pattern, TemporalQuery<T> query) {
return DateTimeFormatter.ofPattern(pattern).parse(dateStr, query);
}
/**
* Instant 转 时间
*
* @param instant Instant
* @return Instant local date time
* @since 1.0.0
*/
@NotNull
public static LocalDateTime toDateTime(Instant instant) {
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
}
/**
* 转换成 date
*
* @param dateTime LocalDateTime
* @return Date date
* @since 1.0.0
*/
@NotNull
public static Date toDate(LocalDateTime dateTime) {
return Date.from(DateUtils.toInstant(dateTime));
}
/**
* 时间转 Instant
*
* @param dateTime 时间
* @return Instant instant
* @since 1.0.0
*/
public static Instant toInstant(@NotNull LocalDateTime dateTime) {
return dateTime.atZone(ZoneId.systemDefault()).toInstant();
}
/**
* 转换成 date
*
* @param localDate LocalDate
* @return Date date
* @since 1.0.0
*/
@NotNull
public static Date toDate(@NotNull LocalDate localDate) {
return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
}
/**
* Converts local date time to Calendar.
*
* @param localDateTime the local date time
* @return the calendar
* @since 1.0.0
*/
@NotNull
public static Calendar toCalendar(LocalDateTime localDateTime) {
return GregorianCalendar.from(ZonedDateTime.of(localDateTime, ZoneId.systemDefault()));
}
/**
* localDate 转换成毫秒数
*
* @param localDate LocalDate
* @return long long
* @since 1.0.0
*/
public static long toMilliseconds(@NotNull LocalDate localDate) {
return toMilliseconds(localDate.atStartOfDay());
}
/**
* localDateTime 转换成毫秒数
*
* @param localDateTime LocalDateTime
* @return long long
* @since 1.0.0
*/
public static long toMilliseconds(@NotNull LocalDateTime localDateTime) {
return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
/**
* 转换成java8 时间
*
* @param calendar 日历
* @return LocalDateTime local date time
* @since 1.0.0
*/
@NotNull
public static LocalDateTime fromCalendar(@NotNull Calendar calendar) {
TimeZone tz = calendar.getTimeZone();
ZoneId zid = tz == null ? ZoneId.systemDefault() : tz.toZoneId();
return LocalDateTime.ofInstant(calendar.toInstant(), zid);
}
/**
* 转换成java8 时间
*
* @param instant Instant
* @return LocalDateTime local date time
* @since 1.0.0
*/
@NotNull
public static LocalDateTime fromInstant(Instant instant) {
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
}
/**
* 转换成java8 时间
*
* @param date Date
* @return LocalDateTime local date time
* @since 1.0.0
*/
@NotNull
public static LocalDateTime fromDate(@NotNull Date date) {
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}
/**
* 转换成java8 时间
*
* @param milliseconds 毫秒数
* @return LocalDateTime local date time
* @since 1.0.0
*/
@NotNull
public static LocalDateTime fromMilliseconds(long milliseconds) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(milliseconds), ZoneId.systemDefault());
}
/**
* 比较2个时间差,跨度比较小
*
* @param startInclusive 开始时间
* @param endExclusive 结束时间
* @return 时间间隔 duration
* @since 1.0.0
*/
public static Duration between(Temporal startInclusive, Temporal endExclusive) {
return Duration.between(startInclusive, endExclusive);
}
/**
* 比较2个时间差,跨度比较大,年月日为单位
*
* @param startDate 开始时间
* @param endDate 结束时间
* @return 时间间隔 period
* @since 1.0.0
*/
public static Period between(LocalDate startDate, LocalDate endDate) {
return Period.between(startDate, endDate);
}
/**
* 比较2个 时间差
*
* @param startDate 开始时间
* @param endDate 结束时间
* @return 时间间隔 duration
* @since 1.0.0
*/
public static Duration between(@NotNull Date startDate, @NotNull Date endDate) {
return Duration.between(startDate.toInstant(), endDate.toInstant());
}
/**
* Between
*
* @param startTime start time
* @param targetDate target date
* @param endTime end time
* @return the boolean
* @since 1.6.0
*/
public static boolean between(Date startTime, Date targetDate, Date endTime) {
return startTime.getTime() <= targetDate.getTime()
&& endTime.getTime() >= targetDate.getTime();
}
/**
* 将秒数转换为日时分秒
*
* @param second 秒数
* @return 时间 string
* @since 1.0.0
*/
public static String secondToTime(Long second) {
// 判断是否为空
if (second == null || second == 0L) {
return StringPool.EMPTY;
}
//转换天数
long days = second / 86400;
//剩余秒数
second = second % 86400;
//转换小时
long hours = second / 3600;
//剩余秒数
second = second % 3600;
//转换分钟
long minutes = second / 60;
//剩余秒数
second = second % 60;
if (days > 0) {
return StringUtils.format("{}天{}小时{}分{}秒", days, hours, minutes, second);
} else {
return StringUtils.format("{}小时{}分{}秒", hours, minutes, second);
}
}
/**
* 将字符串格式的时间转换为 long
*
* @param dateString the date string
* @return the long
* @since 1.0.0
*/
@NotNull
@Contract(pure = true)
public static Long timeToSecond(String dateString) {
return parse(dateString, PATTERN_DATETIME).getTime();
}
/**
* Time to millisecond
*
* @param dateString date string
* @return the long
* @since 1.7.0
*/
@NotNull
@Contract(pure = true)
public static Long timeToMillisecond(String dateString) {
return parse(dateString, PATTERN_MS_DATETIME).getTime();
}
/**
* 获取今天的日期
*
* @return 时间 string
* @since 1.0.0
*/
public static String today() {
return format(new Date(), PATTERN_DATE_NO_SEPARATOR);
}
/**
* Now date
*
* @return the date
* @since 1.0.0
*/
@NotNull
@Contract(" -> new")
public static Date now() {
return new Date();
}
/**
* 日期格式化
*
* @param date 时间
* @param pattern 表达式
* @return 格式化后的时间 string
* @since 1.0.0
*/
public static String format(Date date, String pattern) {
return ConcurrentDateFormat.of(pattern).format(date);
}
/**
* 获取当前时间到当日最后时间相差的分钟数
*
* @param nowTime the now time
* @return int int
* @since 1.0.0
*/
public static int diffMinutesTime(Date nowTime) {
nowTime = null == nowTime ? now() : nowTime;
Calendar todayLastTime = DateUtils.getCurrentCalendar();
todayLastTime.set(Calendar.HOUR_OF_DAY, 23);
todayLastTime.set(Calendar.MINUTE, 59);
todayLastTime.set(Calendar.SECOND, 59);
return (int) ((todayLastTime.getTimeInMillis() - nowTime.getTime()) / 1000 / 60);
}
/**
* Diff minutes time int
*
* @return the int
* @since 1.0.0
*/
public static int diffMinutesTime() {
return diffMinutesTime(now());
}
/**
* Gets current calendar *
*
* @return the current calendar
* @since 1.0.0
*/
private static Calendar getCurrentCalendar() {
Calendar calendar = Calendar.getInstance();
TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
calendar.setTimeZone(timeZone);
return calendar;
}
}
@@ -0,0 +1,777 @@
package com.aos.starter.core.util;
import com.aos.element.basic.basic.util.Charsets;
import com.aos.element.basic.basic.util.Exceptions;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.springframework.lang.Nullable;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import lombok.experimental.UtilityClass;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 加密相关工具类 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 18:25
* @since 1.0.0
*/
@UtilityClass
@SuppressWarnings("all")
public class DigestUtils extends org.springframework.util.DigestUtils {
/**
* HEX_VALUE
*/
private static final String HEX_VALUE = "0123456789abcdef";
/**
* HEX_CODE
*/
private static final char[] HEX_CODE = HEX_VALUE.toCharArray();
/**
* Calculates the MD5 digest.
*
* @param data Data to digest
* @return MD5 digest as a hex array
* @since 1.0.0
*/
public static byte[] md5(byte[] data) {
return org.springframework.util.DigestUtils.md5Digest(data);
}
/**
* Calculates the MD5 digest.
*
* @param data Data to digest
* @return MD5 digest as a hex array
* @since 1.0.0
*/
public static byte[] md5(@NotNull String data) {
return org.springframework.util.DigestUtils.md5Digest(data.getBytes(Charsets.UTF_8));
}
/**
* Return a hexadecimal string representation of the MD5 digest of the given bytes.
*
* @param bytes the bytes to calculate the digest over
* @return a hexadecimal digest string
* @since 1.0.0
*/
@NotNull
public static String md5Hex(byte[] bytes) {
return org.springframework.util.DigestUtils.md5DigestAsHex(bytes);
}
/**
* sha1Hex
*
* @param data Data to digest
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String sha1Hex(@NotNull String data) {
return DigestUtils.encodeHex(sha1(data.getBytes(Charsets.UTF_8)));
}
/**
* encode Hex
*
* @param bytes Data to Hex
* @return bytes as a hex string
* @since 1.0.0
*/
@NotNull
public static String encodeHex(byte[] bytes) {
StringBuilder r = new StringBuilder(bytes.length * 2);
for (byte b : bytes) {
r.append(HEX_CODE[(b >> 4) & 0xF]);
r.append(HEX_CODE[(b & 0xF)]);
}
return r.toString();
}
/**
* sha1
*
* @param bytes Data to digest
* @return digest as a hex array
* @since 1.0.0
*/
public static byte[] sha1(byte[] bytes) {
return DigestUtils.digest("SHA-1", bytes);
}
/**
* digest
*
* @param algorithm 算法
* @param bytes Data to digest
* @return digest byte array
* @since 1.0.0
*/
public static byte[] digest(String algorithm, byte[] bytes) {
try {
MessageDigest md = MessageDigest.getInstance(algorithm);
return md.digest(bytes);
} catch (NoSuchAlgorithmException e) {
throw Exceptions.unchecked(e);
}
}
/**
* sha1Hex
*
* @param bytes Data to digest
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String sha1Hex(byte[] bytes) {
return DigestUtils.encodeHex(sha1(bytes));
}
/**
* SHA224
*
* @param data Data to digest
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] sha224(@NotNull String data) {
return DigestUtils.sha224(data.getBytes(Charsets.UTF_8));
}
/**
* SHA224
*
* @param bytes Data to digest
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] sha224(byte[] bytes) {
return DigestUtils.digest("SHA-224", bytes);
}
/**
* SHA224Hex
*
* @param data Data to digest
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String sha224Hex(@NotNull String data) {
return DigestUtils.encodeHex(sha224(data.getBytes(Charsets.UTF_8)));
}
/**
* SHA224Hex
*
* @param bytes Data to digest
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String sha224Hex(byte[] bytes) {
return DigestUtils.encodeHex(sha224(bytes));
}
/**
* sha256Hex
*
* @param data Data to digest
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] sha256(@NotNull String data) {
return DigestUtils.sha256(data.getBytes(Charsets.UTF_8));
}
/**
* sha256Hex
*
* @param bytes Data to digest
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] sha256(byte[] bytes) {
return DigestUtils.digest("SHA-256", bytes);
}
/**
* sha256Hex
*
* @param data Data to digest
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String sha256Hex(@NotNull String data) {
return DigestUtils.encodeHex(sha256(data.getBytes(Charsets.UTF_8)));
}
/**
* sha256Hex
*
* @param bytes Data to digest
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String sha256Hex(byte[] bytes) {
return DigestUtils.encodeHex(sha256(bytes));
}
/**
* sha384
*
* @param data Data to digest
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] sha384(@NotNull String data) {
return DigestUtils.sha384(data.getBytes(Charsets.UTF_8));
}
/**
* sha384
*
* @param bytes Data to digest
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] sha384(byte[] bytes) {
return DigestUtils.digest("SHA-384", bytes);
}
/**
* sha384Hex
*
* @param data Data to digest
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String sha384Hex(@NotNull String data) {
return DigestUtils.encodeHex(sha384(data.getBytes(Charsets.UTF_8)));
}
/**
* sha384Hex
*
* @param bytes Data to digest
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String sha384Hex(byte[] bytes) {
return DigestUtils.encodeHex(sha384(bytes));
}
/**
* sha512Hex
*
* @param data Data to digest
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] sha512(@NotNull String data) {
return DigestUtils.sha512(data.getBytes(Charsets.UTF_8));
}
/**
* sha512Hex
*
* @param bytes Data to digest
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] sha512(byte[] bytes) {
return DigestUtils.digest("SHA-512", bytes);
}
/**
* sha512Hex
*
* @param data Data to digest
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String sha512Hex(@NotNull String data) {
return DigestUtils.encodeHex(sha512(data.getBytes(Charsets.UTF_8)));
}
/**
* sha512Hex
*
* @param bytes Data to digest
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String sha512Hex(byte[] bytes) {
return DigestUtils.encodeHex(sha512(bytes));
}
/**
* digest Hex
*
* @param algorithm 算法
* @param bytes Data to digest
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String digestHex(String algorithm, byte[] bytes) {
return DigestUtils.encodeHex(digest(algorithm, bytes));
}
/**
* hmacMd5
*
* @param data Data to digest
* @param key key
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] hmacMd5(@NotNull String data, String key) {
return DigestUtils.hmacMd5(data.getBytes(Charsets.UTF_8), key);
}
/**
* hmacMd5
*
* @param bytes Data to digest
* @param key key
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] hmacMd5(byte[] bytes, String key) {
return DigestUtils.digestHmac("HmacMD5", bytes, key);
}
/**
* digest Hmac
*
* @param algorithm 算法
* @param bytes Data to digest
* @param key the key
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] digestHmac(String algorithm, byte[] bytes, @NotNull String key) {
SecretKey secretKey = new SecretKeySpec(key.getBytes(Charsets.UTF_8), algorithm);
try {
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
return mac.doFinal(bytes);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw Exceptions.unchecked(e);
}
}
/**
* hmacMd5 Hex
*
* @param data Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String hmacMd5Hex(@NotNull String data, String key) {
return DigestUtils.encodeHex(hmacMd5(data.getBytes(Charsets.UTF_8), key));
}
/**
* hmacMd5 Hex
*
* @param bytes Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String hmacMd5Hex(byte[] bytes, String key) {
return DigestUtils.encodeHex(hmacMd5(bytes, key));
}
/**
* hmacSha1
*
* @param data Data to digest
* @param key key
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] hmacSha1(@NotNull String data, String key) {
return DigestUtils.hmacSha1(data.getBytes(Charsets.UTF_8), key);
}
/**
* hmacSha1
*
* @param bytes Data to digest
* @param key key
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] hmacSha1(byte[] bytes, String key) {
return DigestUtils.digestHmac("HmacSHA1", bytes, key);
}
/**
* hmacSha1 Hex
*
* @param data Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String hmacSha1Hex(@NotNull String data, String key) {
return DigestUtils.encodeHex(hmacSha1(data.getBytes(Charsets.UTF_8), key));
}
/**
* hmacSha1 Hex
*
* @param bytes Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String hmacSha1Hex(byte[] bytes, String key) {
return DigestUtils.encodeHex(hmacSha1(bytes, key));
}
/**
* hmacSha224
*
* @param data Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
public static byte[] hmacSha224(@NotNull String data, String key) {
return DigestUtils.hmacSha224(data.getBytes(Charsets.UTF_8), key);
}
/**
* hmacSha224
*
* @param bytes Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
public static byte[] hmacSha224(byte[] bytes, String key) {
return DigestUtils.digestHmac("HmacSHA224", bytes, key);
}
/**
* hmacSha224 Hex
*
* @param data Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String hmacSha224Hex(@NotNull String data, String key) {
return DigestUtils.encodeHex(hmacSha224(data.getBytes(Charsets.UTF_8), key));
}
/**
* hmacSha224 Hex
*
* @param bytes Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String hmacSha224Hex(byte[] bytes, String key) {
return DigestUtils.encodeHex(hmacSha224(bytes, key));
}
/**
* hmacSha256
*
* @param data Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
public static byte[] hmacSha256(@NotNull String data, String key) {
return DigestUtils.hmacSha256(data.getBytes(Charsets.UTF_8), key);
}
/**
* hmacSha256
*
* @param bytes Data to digest
* @param key key
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] hmacSha256(byte[] bytes, String key) {
return DigestUtils.digestHmac("HmacSHA256", bytes, key);
}
/**
* hmacSha256 Hex
*
* @param data Data to digest
* @param key key
* @return digest as a byte array
* @since 1.0.0
*/
@NotNull
public static String hmacSha256Hex(@NotNull String data, String key) {
return DigestUtils.encodeHex(hmacSha256(data.getBytes(Charsets.UTF_8), key));
}
/**
* hmacSha256 Hex
*
* @param bytes Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String hmacSha256Hex(byte[] bytes, String key) {
return DigestUtils.encodeHex(hmacSha256(bytes, key));
}
/**
* hmacSha384
*
* @param data Data to digest
* @param key key
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] hmacSha384(@NotNull String data, String key) {
return DigestUtils.hmacSha384(data.getBytes(Charsets.UTF_8), key);
}
/**
* hmacSha384
*
* @param bytes Data to digest
* @param key key
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] hmacSha384(byte[] bytes, String key) {
return DigestUtils.digestHmac("HmacSHA384", bytes, key);
}
/**
* hmacSha384 Hex
*
* @param data Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String hmacSha384Hex(@NotNull String data, String key) {
return DigestUtils.encodeHex(hmacSha384(data.getBytes(Charsets.UTF_8), key));
}
/**
* hmacSha384 Hex
*
* @param bytes Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String hmacSha384Hex(byte[] bytes, String key) {
return DigestUtils.encodeHex(hmacSha384(bytes, key));
}
/**
* hmacSha512
*
* @param data Data to digest
* @param key key
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] hmacSha512(@NotNull String data, String key) {
return DigestUtils.hmacSha512(data.getBytes(Charsets.UTF_8), key);
}
/**
* hmacSha512
*
* @param bytes Data to digest
* @param key key
* @return digest as a byte array
* @since 1.0.0
*/
public static byte[] hmacSha512(byte[] bytes, String key) {
return DigestUtils.digestHmac("HmacSHA512", bytes, key);
}
/**
* hmacSha512 Hex
*
* @param data Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String hmacSha512Hex(@NotNull String data, String key) {
return DigestUtils.encodeHex(hmacSha512(data.getBytes(Charsets.UTF_8), key));
}
/**
* hmacSha512 Hex
*
* @param bytes Data to digest
* @param key key
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String hmacSha512Hex(byte[] bytes, String key) {
return DigestUtils.encodeHex(hmacSha512(bytes, key));
}
/**
* digest Hmac Hex
*
* @param algorithm 算法
* @param bytes Data to digest
* @param key the key
* @return digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String digestHmacHex(String algorithm, byte[] bytes, String key) {
return DigestUtils.encodeHex(DigestUtils.digestHmac(algorithm, bytes, key));
}
/**
* decode Hex
*
* @param hexStr Hex string
* @return decode hex to bytes
* @since 1.0.0
*/
@SuppressWarnings("PMD.UndefineMagicConstantRule")
public static byte[] decodeHex(@NotNull String hexStr) {
int len = hexStr.length();
if ((len & 0x01) != 0) {
throw new IllegalArgumentException("hexBinary needs to be even-length: " + hexStr);
}
String hexText = hexStr.toLowerCase();
byte[] out = new byte[len >> 1];
for (int i = 0; i < len; i += 2) {
int hn = HEX_VALUE.indexOf(hexText.charAt(i));
int ln = HEX_VALUE.indexOf(hexText.charAt(i + 1));
if (hn == -1 || ln == -1) {
throw new IllegalArgumentException("contains illegal character for hexBinary: " + hexStr);
}
out[i / 2] = (byte) ((hn << 4) | ln);
}
return out;
}
/**
* 比较字符串,避免字符串因为过长,产生耗时
*
* @param a String
* @param b String
* @return 是否相同 boolean
* @since 1.0.0
*/
@Contract("null, _ -> false; !null, null -> false")
public static boolean slowEquals(@Nullable String a, @Nullable String b) {
if (a == null || b == null) {
return false;
}
return DigestUtils.slowEquals(a.getBytes(Charsets.UTF_8), b.getBytes(Charsets.UTF_8));
}
/**
* 比较 byte 数组,避免字符串因为过长,产生耗时
*
* @param a byte array
* @param b byte array
* @return 是否相同 boolean
* @since 1.0.0
*/
@Contract(value = "null, _ -> false; !null, null -> false", pure = true)
public static boolean slowEquals(@Nullable byte[] a, @Nullable byte[] b) {
if (a == null || b == null) {
return false;
}
if (a.length != b.length) {
return false;
}
int diff = a.length ^ b.length;
for (int i = 0; i < a.length; i++) {
diff |= a[i] ^ b[i];
}
return diff == 0;
}
/**
* 自定义加密 先MD5再SHA1
*
* @param data 数据
* @return String string
* @since 1.0.0
*/
@NotNull
public static String encrypt(String data) {
return DigestUtils.encodeHex(sha1(md5Hex(data)));
}
/**
* sha1
*
* @param data Data to digest
* @return digest as a hex array
* @since 1.0.0
*/
public static byte[] sha1(@NotNull String data) {
return DigestUtils.sha1(data.getBytes(Charsets.UTF_8));
}
/**
* Calculates the MD5 digest and returns the value as a 32 character hex string.
*
* @param data Data to digest
* @return MD5 digest as a hex string
* @since 1.0.0
*/
@NotNull
public static String md5Hex(@NotNull String data) {
return org.springframework.util.DigestUtils.md5DigestAsHex(data.getBytes(Charsets.UTF_8));
}
}
@@ -0,0 +1,704 @@
package com.aos.starter.core.util;
import com.aos.element.basic.basic.asserts.Assertions;
import com.aos.element.basic.basic.constant.ConfigKey;
import com.aos.element.basic.basic.util.CharPool;
import com.aos.element.basic.basic.util.Charsets;
import com.aos.element.basic.basic.util.Exceptions;
import com.aos.element.basic.basic.util.IoUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.PatternMatchUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 文件工具类 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 18:26
* @since 1.0.0
*/
@Slf4j
@UtilityClass
@SuppressWarnings("checkstyle:MethodLimit")
public class FileUtils extends org.springframework.util.FileCopyUtils {
/**
* 扫描目录下的文件
*
* @param path 路径
* @return 文件集合 list
* @since 1.0.0
*/
public static List<File> list(String path) {
File file = new File(path);
return list(file, TrueFilter.TRUE);
}
/**
* 扫描目录下的文件
*
* @param path 路径
* @param fileNamePattern 文件名 * 号
* @return 文件集合 list
* @since 1.0.0
*/
public static List<File> list(String path, String fileNamePattern) {
File file = new File(path);
return list(file, pathname -> {
String fileName = pathname.getName();
return PatternMatchUtils.simpleMatch(fileNamePattern, fileName);
});
}
/**
* 扫描目录下的文件
*
* @param path 路径
* @param filter 文件过滤
* @return 文件集合 list
* @since 1.0.0
*/
public static List<File> list(String path, FileFilter filter) {
File file = new File(path);
return list(file, filter);
}
/**
* 扫描目录下的文件
*
* @param file 文件
* @return 文件集合 list
* @since 1.0.0
*/
public static List<File> list(File file) {
List<File> fileList = new ArrayList<>();
return list(file, fileList, TrueFilter.TRUE);
}
/**
* 扫描目录下的文件
*
* @param file 文件
* @param fileNamePattern Spring AntPathMatcher 规则
* @return 文件集合 list
* @since 1.0.0
*/
public static List<File> list(File file, String fileNamePattern) {
List<File> fileList = new ArrayList<>();
return list(file, fileList, pathname -> {
String fileName = pathname.getName();
return PatternMatchUtils.simpleMatch(fileNamePattern, fileName);
});
}
/**
* 扫描目录下的文件
*
* @param file 文件
* @param filter 文件过滤
* @return 文件集合 list
* @since 1.0.0
*/
public static List<File> list(File file, FileFilter filter) {
List<File> fileList = new ArrayList<>();
return list(file, fileList, filter);
}
/**
* 扫描目录下的文件
*
* @param file 文件
* @param fileList file list
* @param filter 文件过滤
* @return 文件集合 list
* @since 1.0.0
*/
@Contract("_, _, _ -> param2")
private static List<File> list(@NotNull File file, List<File> fileList, FileFilter filter) {
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (File f : files) {
list(f, fileList, filter);
}
}
} else {
// 过滤文件
boolean accept = filter.accept(file);
if (file.exists() && accept) {
fileList.add(file);
}
}
return fileList;
}
/**
* 获取文件后缀名
*
* @param fullName 文件全名
* @return {String}
* @since 1.0.0
*/
@NotNull
public static String getFileExtension(String fullName) {
Assertions.notNull(fullName, "file fullName is null.");
String fileName = new File(fullName).getName();
int dotIndex = fileName.lastIndexOf('.');
return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
}
/**
* 获取文件名,去除后缀名
*
* @param file 文件
* @return {String}
* @since 1.0.0
*/
public static @NotNull String getNameWithoutExtension(String file) {
Assertions.notNull(file, "file is null.");
String fileName = new File(file).getName();
int dotIndex = fileName.lastIndexOf(CharPool.DOT);
return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);
}
/**
* Returns a {@link File} representing the system temporary directory.
*
* @return the system temporary directory.
* @since 1.0.0
*/
@NotNull
@Contract(" -> new")
public static File getTempDir() {
return new File(getTempDirPath());
}
/**
* Returns the path to the system temporary directory.
*
* @return the path to the system temporary directory.
* @since 1.0.0
*/
public static String getTempDirPath() {
return System.getProperty(ConfigKey.JvmConfigKey.TMP_DIR);
}
/**
* 拼接临时文件目录.
*
* @param subDirFile sub dir file
* @return 临时文件目录. string
* @since 1.0.0
*/
@NotNull
public static String toTempDirPath(String subDirFile) {
return FileUtils.toTempDir(subDirFile).getAbsolutePath();
}
/**
* 拼接临时文件目录.
*
* @param subDirFile sub dir file
* @return the system temporary directory.
* @since 1.0.0
*/
public static @NotNull File toTempDir(@NotNull String subDirFile) {
String tempDirPath = FileUtils.getTempDirPath();
// 删除子目录目录分隔符
if (subDirFile.startsWith(File.separator)) {
subDirFile = subDirFile.substring(1);
}
// 为临时目录最后添加目录分隔符
if (!tempDirPath.endsWith(File.separator)) {
tempDirPath += File.separator;
}
String fullPath = tempDirPath.concat(subDirFile);
File fullFilePath = new File(fullPath);
File dir = fullFilePath.getParentFile();
if (!dir.exists() && dir.mkdirs()) {
log.debug("{} 不存在, 创建成功", dir);
}
return fullFilePath;
}
/**
* Reads the contents of a file into a String.
* The file is always closed.
*
* @param file the file to read, must not be {@code null}
* @return the file contents, never {@code null}
* @since 1.0.0
*/
@NotNull
public static String readToString(File file) {
return readToString(file, Charsets.UTF_8);
}
/**
* Reads the contents of a file into a String.
* The file is always closed.
*
* @param file the file to read, must not be {@code null}
* @param encoding the encoding to use, {@code null} means platform default
* @return the file contents, never {@code null}
* @since 1.0.0
*/
@NotNull
public static String readToString(File file, Charset encoding) {
try (InputStream in = Files.newInputStream(file.toPath())) {
return IoUtils.toString(in, encoding);
} catch (IOException e) {
throw Exceptions.unchecked(e);
}
}
/**
* Reads the contents of a file into a String.
* The file is always closed.
*
* @param file the file to read, must not be {@code null}
* @return the file contents, never {@code null}
* @since 1.0.0
*/
@NotNull
public static byte[] readToByteArray(File file) {
try (InputStream in = Files.newInputStream(file.toPath())) {
return IoUtils.toByteArray(in);
} catch (IOException e) {
throw Exceptions.unchecked(e);
}
}
/**
* Writes a String to a file creating the file if it does not exist.
*
* @param file the file to write
* @param data the content to write to the file
* @since 1.0.0
*/
public static void writeToFile(File file, String data) {
writeToFile(file, data, Charsets.UTF_8, false);
}
/**
* Writes a String to a file creating the file if it does not exist.
*
* @param file the file to write
* @param data the content to write to the file
* @param encoding the encoding to use, {@code null} means platform default
* @param append if {@code true}, then the String will be added to the end of the file rather than overwriting
* @since 1.0.0
*/
public static void writeToFile(File file, String data, Charset encoding, boolean append) {
try (OutputStream out = new FileOutputStream(file, append)) {
IoUtils.write(data, out, encoding);
} catch (IOException e) {
throw Exceptions.unchecked(e);
}
}
/**
* Writes a String to a file creating the file if it does not exist.
*
* @param file the file to write
* @param data the content to write to the file
* @param append if {@code true}, then the String will be added to the end of the file rather than overwriting
* @since 1.0.0
*/
public static void writeToFile(File file, String data, boolean append) {
writeToFile(file, data, Charsets.UTF_8, append);
}
/**
* Writes a String to a file creating the file if it does not exist.
*
* @param file the file to write
* @param data the content to write to the file
* @param encoding the encoding to use, {@code null} means platform default
* @since 1.0.0
*/
public static void writeToFile(File file, String data, Charset encoding) {
writeToFile(file, data, encoding, false);
}
/**
* 转成file
*
* @param multipartFile MultipartFile
* @param file File
* @since 1.0.0
*/
public static void toFile(@NotNull MultipartFile multipartFile, File file) {
try {
FileUtils.toFile(multipartFile.getInputStream(), file);
} catch (IOException e) {
throw Exceptions.unchecked(e);
}
}
/**
* 转成file
*
* @param in InputStream
* @param file File
* @since 1.0.0
*/
public static void toFile(InputStream in, File file) {
try (OutputStream out = new FileOutputStream(file)) {
FileUtils.copy(in, out);
} catch (IOException e) {
throw Exceptions.unchecked(e);
}
}
/**
* Moves a file.
* <p>
* When the destination file is on another file system, do a "copy and delete".
*
* @param srcFile the file to be moved
* @param destFile the destination file
* @throws IOException if source or destination is invalid
* @since 1.0.0
*/
public static void moveFile(File srcFile, File destFile) throws IOException {
Assert.notNull(srcFile, "Source must not be null");
Assert.notNull(destFile, "Destination must not be null");
if (!srcFile.exists()) {
throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
}
if (srcFile.isDirectory()) {
throw new IOException("Source '" + srcFile + "' is a directory");
}
if (destFile.exists()) {
throw new IOException("Destination '" + destFile + "' already exists");
}
if (destFile.isDirectory()) {
throw new IOException("Destination '" + destFile + "' is a directory");
}
boolean rename = srcFile.renameTo(destFile);
if (!rename) {
FileUtils.copy(srcFile, destFile);
if (!srcFile.delete()) {
FileUtils.deleteQuietly(destFile);
throw new IOException("Failed to delete original file '" + srcFile + "' after copy to '" + destFile + "'");
}
}
}
/**
* Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories.
* <p>
* The difference between File.delete() and this method are:
* <ul>
* <li>A directory to be deleted does not have to be empty.</li>
* <li>No exceptions are thrown when a file or directory cannot be deleted.</li>
* </ul>
*
* @param file file or directory to delete, can be {@code null}
* @return {@code true} if the file or directory was deleted, otherwise {@code false}
* @since 1.0.0
*/
@Contract("null -> false")
public static boolean deleteQuietly(@Nullable File file) {
if (file == null) {
return false;
}
try {
if (file.isDirectory()) {
FileSystemUtils.deleteRecursively(file);
}
} catch (Exception ignored) {
}
try {
return file.delete();
} catch (Exception ignored) {
return false;
}
}
/**
* NIO 按行读取文件
*
* @param path 文件路径
* @return 行列表 list
* @since 1.0.0
*/
public static List<String> readLines(String path) {
return readLines(Paths.get(path));
}
/**
* NIO 按行读取文件
*
* @param path 文件路径
* @return 行列表 list
* @since 1.0.0
*/
public static List<String> readLines(Path path) {
return readLines(path, Charsets.UTF_8);
}
/**
* NIO 按行读取文件
*
* @param path 文件路径
* @param cs 字符集
* @return 行列表 list
* @since 1.0.0
*/
public static List<String> readLines(Path path, Charset cs) {
try {
return Files.readAllLines(path, cs);
} catch (IOException e) {
throw Exceptions.unchecked(e);
}
}
/**
* NIO 按行读取文件
*
* @param file 文件
* @return 行列表 list
* @since 1.0.0
*/
public static List<String> readLines(@NotNull File file) {
return readLines(file.toPath());
}
/**
* NIO 按行读取文件
*
* @param path 文件路径
* @param cs 字符集
* @return 行列表 list
* @since 1.0.0
*/
public static List<String> readLines(String path, Charset cs) {
return readLines(Paths.get(path), cs);
}
/**
* NIO 按行读取文件
*
* @param file 文件
* @param cs 字符集
* @return 行列表 list
* @since 1.0.0
*/
public static List<String> readLines(@NotNull File file, Charset cs) {
return readLines(file.toPath(), cs);
}
/**
* 转换成不同平台的下的路径
*
* @param path the path
* @return the string
* @since 1.0.0
*/
@NotNull
public static String getRealFilePath(@NotNull String path) {
return path.replace("/", File.separator).replace("\\", File.separator);
}
/**
* 拼接不同平台下的文件路径, 末尾不含路径分隔符
*
* @param paths paths
* @return the string
* @since 1.0.0
*/
@NotNull
public static String appendPath(@NotNull String... paths) {
// 删除前缀后后缀
for (int i = 0; i < paths.length; i++) {
paths[i] = StringUtils.removeSuffix(paths[i], File.separator);
// 第一个路径不删除前缀
if (i == 0) {
continue;
}
paths[i] = StringUtils.removePrefix(paths[i], File.separator);
}
return String.join(File.separator, paths);
}
/**
* 递归删除指定目录及文件
*
* @param first first
* @param more more
* @return the boolean
* @since 1.0.0
*/
@SneakyThrows
public static boolean deleteFiles(String first, String... more) {
Path start = Paths.get(first, more);
if (start.toFile().exists()) {
Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
try {
Files.delete(file);
} catch (IOException ignored) {
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e) {
if (e == null) {
try {
Files.delete(dir);
} catch (IOException ignored) {
}
return FileVisitResult.CONTINUE;
}
// 如果存在异常, 则说明文件不存在
return FileVisitResult.SKIP_SUBTREE;
}
});
}
return true;
}
/**
* 创建文件路径且处理 path 最后一个路径分隔符
*
* @param path path
* @return the string
* @since 1.4.0
*/
public static @NotNull String toPath(String path) {
File logFile = new File(path);
if (!logFile.exists() && logFile.mkdirs()) {
log.info(String.format("创建日志目录: %s", logFile.getPath()));
}
return logFile.getPath();
}
/**
* 默认为true
*
* @author L.cm
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 18:26
* @since 1.0.0
*/
public static class TrueFilter implements FileFilter, Serializable {
/**
* The constant TRUE.
*/
public static final TrueFilter TRUE = new TrueFilter();
/** serialVersionUID */
private static final long serialVersionUID = -6420452043795072619L;
/**
* Accept boolean
*
* @param pathname pathname
* @return the boolean
* @since 1.0.0
*/
@Override
public boolean accept(File pathname) {
return true;
}
}
/**
* Touch
*
* @param file file
* @throws IOException io exception
* @since 1.5.0
*/
public static void touch(@NotNull File file) throws IOException {
if (!file.exists()) {
OutputStream out = openOutputStream(file);
IoUtils.closeQuietly(out);
}
boolean success = file.setLastModified(System.currentTimeMillis());
if (!success) {
throw new IOException("Unable to set the last modification time for " + file);
}
}
/**
* Open output stream
*
* @param file file
* @return the file output stream
* @throws IOException io exception
* @since 1.5.0
*/
public static @NotNull FileOutputStream openOutputStream(File file) throws IOException {
return openOutputStream(file, false);
}
/**
* Open output stream
*
* @param file file
* @param append append
* @return the file output stream
* @throws IOException io exception
* @since 1.5.0
*/
@Contract("_, _ -> new")
public static @NotNull FileOutputStream openOutputStream(@NotNull File file, boolean append) throws IOException {
if (file.exists()) {
if (file.isDirectory()) {
throw new IOException("File '" + file + "' exists but is a directory");
}
if (!file.canWrite()) {
throw new IOException("File '" + file + "' cannot be written to");
}
} else {
File parent = file.getParentFile();
if (parent != null && !parent.mkdirs() && !parent.isDirectory()) {
throw new IOException("Directory '" + parent + "' could not be created");
}
}
return new FileOutputStream(file, append);
}
}
@@ -0,0 +1,23 @@
package com.aos.starter.core.util;
import java.security.SecureRandom;
import java.util.Random;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: 一些常用的单例对象 </p>
*
* @author dong4j
* @version 1.2.3
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.01.27 18:17
* @since 1.0.0
*/
public final class Holder {
/** RANDOM */
public static final Random RANDOM = new Random();
/** SECURE_RANDOM */
public static final SecureRandom SECURE_RANDOM = new SecureRandom();
}
@@ -0,0 +1,297 @@
package com.aos.starter.core.util;
import com.aos.element.basic.basic.util.Charsets;
import com.aos.element.basic.basic.util.HttpsUtils;
import com.aos.element.basic.basic.util.JsonUtils;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import lombok.experimental.UtilityClass;
/**
* <p>Company: 成都返空汇网络技术有限公司 </p>
* <p>Description: </p>
*
* @author dong4j
* @version 1.3.0
* @email "mailto:dongshijie@fkhwl.com"
* @date 2020.03.04 14:02
* @since 1.0.0
*/
@UtilityClass
public class HttpClientUtils {
/** 最大连接数 */
private static final int MAX_CONNECTION_TOTAL = 300;
/** 路由并发数 */
private static final int ROUTE_MAX_COUNT = 200;
/** 重试次数 */
private static final int RETRY_COUNT = 3;
/** 连接超时 */
private static final int CONNECTION_TIME_OUT = 45000;
/** 数据超时 */
private static final int READ_TIME_OUT = 75000;
/** 连接等待 */
private static final int CONNECTION_REQUEST_TIME_OUT = 5000;
/** 编码 */
private static final String CHARSET = Charsets.UTF_8_NAME;
/**
* Post for object t
*
* @param <T> parameter
* @param url url
* @param requestBody request body
* @param contentType content type
* @param responseType response type
* @return the t
* @throws Exception exception
* @since 1.0.0
*/
public static <T> T postForObject(String url,
Object requestBody,
MediaType contentType,
Class<T> responseType) throws Exception {
return postForObjectWithHeader(url, requestBody, contentType, responseType, null);
}
/**
* Post for object with header t
*
* @param <T> parameter
* @param url url
* @param requestBody request body
* @param contentType content type
* @param responseType response type
* @param headers headers
* @return the t
* @throws Exception exception
* @since 1.0.0
*/
public static <T> T postForObjectWithHeader(String url,
Object requestBody,
MediaType contentType,
Class<T> responseType,
Map<String, String[]> headers) throws Exception {
try (CloseableHttpClient httpClient = acceptsUntrustedCertsHttpClient()) {
RestTemplate restTemplate = getRestTemplate(httpClient);
// headers
HttpHeaders httpHeaders = getDefaultHeader(contentType);
if (!Objects.isNull(headers)) {
fillHeaders(httpHeaders, headers);
}
HttpEntity<Object> httpEntity = new HttpEntity<>(requestBody, httpHeaders);
return restTemplate.postForObject(url, httpEntity, responseType);
} catch (Exception e) {
throw new Exception("网络异常或请求错误.", e);
}
}
/**
* Gets for object with header *
*
* @param <T> parameter
* @param url url
* @param responseType response type
* @param headerName header name
* @param headerValue header value
* @return the for object with header
* @throws Exception exception
* @since 1.0.0
*/
public static <T> T getForObjectWithHeader(String url,
Class<T> responseType,
String headerName,
String headerValue) throws Exception {
HttpHeaders httpHeaders = getDefaultHeader(MediaType.APPLICATION_JSON);
httpHeaders.add(headerName, headerValue);
return getForObject(url, responseType, httpHeaders);
}
/**
* Gets for object *
*
* @param <T> parameter
* @param url url
* @param responseType response type
* @return the for object
* @throws Exception exception
* @since 1.0.0
*/
public static <T> T getForObject(String url, Class<T> responseType) throws Exception {
return getForObject(url, responseType, getDefaultHeader(MediaType.APPLICATION_JSON));
}
/**
* Gets default header *
*
* @param contentType content type
* @return the default header
* @since 1.0.0
*/
private static HttpHeaders getDefaultHeader(MediaType contentType) {
HttpHeaders headers = new HttpHeaders();
List<MediaType> acceptableMediaTypes = new ArrayList<>();
acceptableMediaTypes.add(MediaType.ALL);
headers.setAccept(acceptableMediaTypes);
headers.setContentType(contentType);
headers.add("Connection", "Keep-Alive");
headers.add("Content-Encoding", "gzip");
headers.add("Vary", "Accept-Encoding");
headers.add("Transfer-Encoding", "chunked");
return headers;
}
/**
* Gets for object *
*
* @param <T> parameter
* @param url url
* @param responseType response type
* @param httpHeaders http headers
* @return the for object
* @throws Exception exception
* @since 1.0.0
*/
private static <T> T getForObject(String url, Class<T> responseType, HttpHeaders httpHeaders) throws Exception {
try (CloseableHttpClient httpClient = acceptsUntrustedCertsHttpClient()) {
RestTemplate restTemplate = getRestTemplate(httpClient);
HttpEntity<Object> httpEntity = new HttpEntity<>(null, httpHeaders);
URI uri = new URI(url);
String responseStr = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, String.class).getBody();
return JsonUtils.parse(responseStr, responseType);
} catch (Exception e) {
throw new Exception("网络异常或请求错误.", e);
}
}
/**
* Gets rest template *
*
* @param httpClient http client
* @return the rest template
* @since 1.0.0
*/
@NotNull
private static RestTemplate getRestTemplate(CloseableHttpClient httpClient) {
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
clientHttpRequestFactory.setConnectTimeout(CONNECTION_TIME_OUT);
clientHttpRequestFactory.setReadTimeout(READ_TIME_OUT);
clientHttpRequestFactory.setConnectionRequestTimeout(CONNECTION_REQUEST_TIME_OUT);
clientHttpRequestFactory.setBufferRequestBody(false);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
messageConverters.forEach(m -> {
if (m instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) m).setDefaultCharset(Charset.forName(CHARSET));
}
});
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
}
/**
* 接受未信任的请求
*
* @return closeable http client
* @throws KeyStoreException key store exception
* @throws NoSuchAlgorithmException no such algorithm exception
* @throws KeyManagementException key management exception
* @since 1.0.0
*/
public static CloseableHttpClient acceptsUntrustedCertsHttpClient()
throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
SSLContext sslContext = HttpsUtils.getSslContext();
httpClientBuilder.setSSLContext(sslContext);
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactory)
.build();
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connMgr.setMaxTotal(MAX_CONNECTION_TOTAL);
connMgr.setDefaultMaxPerRoute(ROUTE_MAX_COUNT);
httpClientBuilder.setConnectionManager(connMgr);
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(RETRY_COUNT, true));
httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
return httpClientBuilder.build();
}
/**
* Gets for object with header *
*
* @param <T> parameter
* @param url url
* @param headers headers
* @param responseType response type
* @return the for object with header
* @throws Exception exception
* @since 1.0.0
*/
public static <T> T getForObjectWithHeader(String url, Map<String, String[]> headers, Class<T> responseType) throws Exception {
HttpHeaders httpHeaders = getDefaultHeader(MediaType.APPLICATION_JSON);
fillHeaders(httpHeaders, headers);
return getForObject(url, responseType, httpHeaders);
}
/**
* Fill headers *
*
* @param httpHeaders http headers
* @param headers headers
* @since 1.0.0
*/
private static void fillHeaders(HttpHeaders httpHeaders, @NotNull Map<String, String[]> headers) {
headers.forEach((key, value1) -> Stream.of(value1).forEach(value -> httpHeaders.add(key, value)));
}
}
@@ -0,0 +1,16 @@
code.default.null.data=\u6682\u65E0\u6570\u636E
code.param.verify.error=\u53C2\u6570\u6821\u9A8C\u5931\u8D25: [{}]
code.data.error=\u6570\u636E\u4E0D\u5B58\u5728
code.option.failure=\u64CD\u4F5C\u5931\u8D25
code.config.error=\u914D\u7F6E\u9519\u8BEF
code.server.inner.error=\u670D\u52A1\u5185\u90E8\u9519\u8BEF
code.service.invoke.error=\u670D\u52A1\u4E0D\u53EF\u7528
code.client.invoke.error=Rest Client \u8C03\u7528\u5931\u8D25
code.agent.disable.error=Agent Service \u4E0D\u53EF\u7528
code.agent.not.found.error=\u672A\u627E\u5230\u6307\u5B9A\u670D\u52A1
code.rpc.invoke.error=\u8FDC\u7A0B\u670D\u52A1\u4E0D\u53EF\u7528
code.gateway.instances.error=\u7F51\u5173\u8DEF\u7531\u5931\u8D25, \u672A\u627E\u5230\u6307\u5B9A\u670D\u52A1
code.gateway.router.error=\u7F51\u5173\u8DEF\u7531\u914D\u7F6E\u9519\u8BEF: 1.\u8BF7\u68C0\u67E5\u8C03\u7528\u7AEF\u914D\u7F6E fkh.gateway.enable-router \u662F\u5426\u4E3A true; 2.\u68C0\u67E5\u8DEF\u7531\u914D\u7F6E\u662F\u5426\u6B63\u786E.
code.server.busy=\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528,\u8BF7\u7A0D\u540E\u91CD\u8BD5!
code.server.error=\u7F51\u7EDC\u5F02\u5E38
@@ -0,0 +1,34 @@
package ${cfg.package_dto};
import com.fkhwl.starter.common.base.BaseDTO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: $!{table.comment} 数据传输实体 (根据业务需求添加字段) </p>
*
* @author ${author}
* @version ${cfg.version}
* @email "mailto:${author}@fkhwl.com"
* @date ${cfg.date}
* @since ${cfg.version}
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class ${entity}DTO extends BaseDTO<Long> {
private static final long serialVersionUID = 1L;
/** todo: [自动生成的字段, 避免此实体没有字段导致启动失败的问题, 可删除] */
private String autoField;
}
@@ -0,0 +1,128 @@
package ${cfg.package_po};
#foreach($pkg in ${table.importPackages})
import ${pkg};
#end
#if(${entityLombokModel})
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
#end
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: $!{table.comment} 实体类 </p>
*
* @author ${author}
* @version ${cfg.version}
* @email "mailto:${author}@fkhwl.com"
* @date ${cfg.date}
* @since ${cfg.version}
*/
#if(${entityLombokModel})
@Data
@AllArgsConstructor
@NoArgsConstructor
#if(${superEntityClass})
@EqualsAndHashCode(callSuper = true)
#end
@Accessors(chain = true)
#end
#if(${table.convert})
@TableName("${table.name}")
#end
#if(${superEntityClass})
public class ${entity} extends ${superEntityClass}#if(${activeRecord})<Long, ${entity}>#end {
#elseif(${activeRecord})
public class ${entity} extends Model<${entity}> {
#else
public class ${entity} implements Serializable {
#end
#if(${entityColumnConstant})
#foreach($field in ${table.fields})
public static final String ${field.name.toUpperCase()} = "${field.name}";
#end
#end
private static final long serialVersionUID = 1L;
## ---------- BEGIN 字段循环遍历 ----------
#foreach($field in ${table.fields})
#if(${field.keyFlag})
#set($keyPropertyName=${field.propertyName})
#end
#if("$!field.comment" != "")
/** ${field.comment} */
#end
#if(${field.keyFlag})
## 主键
#if(${field.keyIdentityFlag})
@TableId(value = "${field.name}", type = IdType.AUTO)
#elseif(!$null.isNull(${idType}) && "$!idType" != "")
@TableId(value = "${field.name}", type = IdType.${idType})
#elseif(${field.convert})
@TableId("${field.name}")
#end
## 普通字段
#elseif(${field.fill})
## ----- 存在字段填充设置 -----
#if(${field.convert})
@TableField(value = "${field.name}", fill = FieldFill.${field.fill})
#else
@TableField(fill = FieldFill.${field.fill})
#end
#elseif(${field.convert})
@TableField("${field.name}")
#end
## 乐观锁注解
#if(${versionFieldName}==${field.name})
@Version
#end
## 逻辑删除注解
#if(${logicDeleteFieldName}==${field.name})
@TableLogic
#end
private ${field.propertyType} ${field.propertyName};
#end
## ---------- END 字段循环遍历 ----------
#if(!${entityLombokModel})
#foreach($field in ${table.fields})
#if(${field.propertyType.equals("boolean")})
#set($getprefix="is")
#else
#set($getprefix="get")
#end
public ${field.propertyType} ${getprefix}${field.capitalName}() {
return ${field.propertyName};
}
#if(${entityBuilderModel})
public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
#else
public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
#end
this.${field.propertyName} = ${field.propertyName};
#if(${entityBuilderModel})
return this;
#end
}
#end
#end
#if(!${entityLombokModel})
@Override
public String toString() {
return "${entity}{" +
#foreach($field in ${table.fields})
#if($!{velocityCount}==1)
"${field.propertyName}=" + ${field.propertyName} +
#else
", ${field.propertyName}=" + ${field.propertyName} +
#end
#end
"}";
}
#end
}
@@ -0,0 +1,34 @@
package ${cfg.package_form};
import com.fkhwl.starter.common.base.BaseForm;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
/**
* <p>Company: 成都返空汇网络技术有限公司</p>
* <p>Description: $!{table.comment} 入参实体 (根据业务需求添加字段) </p>
*
* @author ${author}
* @version ${cfg.version}
* @email "mailto:${author}@fkhwl.com"
* @date ${cfg.date}
* @since ${cfg.version}
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class ${entity}Form extends BaseForm<Long> {
private static final long serialVersionUID = 1L;
/** todo: [自动生成的字段, 避免此实体没有字段导致启动失败的问题, 可删除] */
private String autoField;
}