feat(network): 添加网络地址和端口相关工具类

- 新增 NetworkAddress 类用于表示网络地址,支持 IPv4 和 IPv6
- 新增 NetworkPort 类用于表示端口号
- 新增 NetworkEndpoint 类用于封装网络地址和端口信息
- 优化 AutoConfiguration 类,添加更多系统信息
- 更新 AesUtils、Base64Utils等类的版本信息
- 删除 Minecraft SLF 相关无用代码
- 更新项目版本号至 4.0.7
This commit is contained in:
Armamem0t 2025-09-15 22:32:56 +08:00
parent 7c3c13e28c
commit 541a8a82b4
Signed by: minglipro
GPG Key ID: 5F355A77B22AA93B
47 changed files with 1488 additions and 2080 deletions

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils
* CurrentFile build.gradle.kts
* LastUpdate 2025-09-15 11:20:04
* LastUpdate 2025-09-15 22:22:00
* UpdateUser MingLiPro
*/
@ -77,7 +77,6 @@ dependencies {
implementation("org.mindrot:jbcrypt:0.4")
implementation("org.jetbrains:annotations:24.0.0")
compileOnly("net.java.dev.jna:jna:5.17.0")
//implementation("jakarta.annotation:jakarta.annotation-api:2.1.1")
implementation("org.slf4j:slf4j-api:2.0.17")
implementation("com.mingliqiye.utils.jna:WinKernel32Api:1.0.1")
@ -179,7 +178,6 @@ tasks.processResources {
DateTimeFormatter.ofPattern(
"yyyy-MM-dd HH:mm:ss.SSSSSSS"
)
)
)
)

View File

@ -16,10 +16,10 @@
# ProjectName mingli-utils
# ModuleName mingli-utils
# CurrentFile gradle.properties
# LastUpdate 2025-09-15 18:03:04
# LastUpdate 2025-09-15 22:32:50
# UpdateUser MingLiPro
#
JDKVERSIONS=1.8
GROUPSID=com.mingliqiye.utils
ARTIFACTID=mingli-utils
VERSIONS=4.0.6
VERSIONS=4.0.7

View File

@ -16,7 +16,7 @@
# ProjectName mingli-utils
# ModuleName mingli-utils
# CurrentFile gradle-wrapper.properties
# LastUpdate 2025-09-15 12:01:36
# LastUpdate 2025-09-15 22:32:50
# UpdateUser MingLiPro
#
distributionBase=GRADLE_USER_HOME

2
gradlew vendored
View File

@ -18,7 +18,7 @@
# ProjectName mingli-utils
# ModuleName mingli-utils
# CurrentFile gradlew
# LastUpdate 2025-09-15 12:01:36
# LastUpdate 2025-09-15 22:32:50
# UpdateUser MingLiPro
#

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.jdk8
* CurrentFile build.gradle.kts
* LastUpdate 2025-09-14 18:19:04
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/
plugins {

View File

@ -1 +0,0 @@
lombok.addLombokGeneratedAnnotation = false

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils
* CurrentFile settings.gradle.kts
* LastUpdate 2025-09-13 02:37:04
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/

View File

@ -1,30 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Main.java
* LastUpdate 2025-09-15 11:18:12
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils;
public class Main {
public static void main(String[] args) {
MainKt.main();
}
}

View File

@ -1,249 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile GsonJsonApi.java
* LastUpdate 2025-09-15 11:20:04
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json;
import com.google.gson.*;
import com.mingliqiye.utils.json.converters.JsonConverter;
import com.mingliqiye.utils.json.converters.JsonStringConverter;
import org.jetbrains.annotations.NotNull;
public class GsonJsonApi implements JsonApi {
private Gson gsonUnicode;
private Gson gsonPretty;
private Gson gsonPrettyUnicode;
private Gson gson;
public GsonJsonApi() {
gson = new GsonBuilder()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
gsonUnicode = new GsonBuilder()
.disableHtmlEscaping()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
gsonPretty = new GsonBuilder()
.setPrettyPrinting()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
gsonPrettyUnicode = new GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
}
public GsonJsonApi(Gson gson) {
this.gson = gson
.newBuilder()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
this.gsonUnicode = gson
.newBuilder()
.disableHtmlEscaping()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
this.gsonPretty = gson
.newBuilder()
.setPrettyPrinting()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
this.gsonPrettyUnicode = gson
.newBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
}
@Override
public <T> T parse(String json, Class<T> clazz) {
return gson.fromJson(json, clazz);
}
@Override
public <T> T parse(String json, JsonTypeReference<T> type) {
return gson.fromJson(json, type.getType());
}
@Override
public String format(Object object) {
return gson.toJson(object);
}
@Override
public String formatUnicode(Object object) {
return gsonUnicode.toJson(object);
}
@Override
public String formatPretty(Object object) {
return gsonPretty.toJson(object);
}
@Override
public String formatPrettyUnicode(Object object) {
return gsonPrettyUnicode.toJson(object);
}
@Override
public boolean isValidJson(String json) {
try {
JsonElement element = JsonParser.parseString(json);
return true;
} catch (JsonSyntaxException e) {
return false;
} catch (Exception e) {
return false;
}
}
@Override
public String merge(String... jsons) {
JsonObject merged = new JsonObject();
for (String json : jsons) {
if (json == null || json.isEmpty()) {
continue;
}
try {
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
for (String key : obj.keySet()) {
merged.add(key, obj.get(key));
}
} catch (Exception e) {
// 忽略无效的 JSON 字符串
}
}
return gson.toJson(merged);
}
@Override
public String getNodeValue(String json, String path) {
try {
JsonElement element = JsonParser.parseString(json);
String[] paths = path.split("\\.");
JsonElement current = element;
for (String p : paths) {
if (current.isJsonObject()) {
current = current.getAsJsonObject().get(p);
} else {
return null;
}
if (current == null) {
return null;
}
}
return current.isJsonPrimitive()
? current.getAsString()
: current.toString();
} catch (Exception e) {
return null;
}
}
@Override
public String updateNodeValue(String json, String path, Object newValue) {
try {
JsonObject obj = JsonParser.parseString(json).getAsJsonObject();
String[] paths = path.split("\\.");
JsonObject current = obj;
// 导航到倒数第二层
for (int i = 0; i < paths.length - 1; i++) {
String p = paths[i];
if (!current.has(p) || !current.get(p).isJsonObject()) {
current.add(p, new JsonObject());
}
current = current.getAsJsonObject(p);
}
// 设置最后一层的值
String lastPath = paths[paths.length - 1];
if (newValue == null) {
current.remove(lastPath);
} else {
JsonElement element = gson.toJsonTree(newValue);
current.add(lastPath, element);
}
return gson.toJson(obj);
} catch (Exception e) {
return json;
}
}
@Override
public <T, D> D convert(T source, Class<D> destinationClass) {
String json = gson.toJson(source);
return gson.fromJson(json, destinationClass);
}
@Override
public <T, D> D convert(T source, JsonTypeReference<D> destinationType) {
String json = gson.toJson(source);
return gson.fromJson(json, destinationType.getType());
}
@Override
public void addJsonConverter(@NotNull JsonConverter<?, ?> c) {
gson = gson
.newBuilder()
.registerTypeAdapter(
c.getTClass(),
c.getStringConverter().getGsonJsonStringConverterAdapter()
)
.create();
gsonUnicode = gsonUnicode
.newBuilder()
.registerTypeAdapter(
c.getTClass(),
c.getStringConverter().getGsonJsonStringConverterAdapter()
)
.create();
gsonPretty = gsonPretty
.newBuilder()
.registerTypeAdapter(
c.getTClass(),
c.getStringConverter().getGsonJsonStringConverterAdapter()
)
.create();
gsonPrettyUnicode = gsonPrettyUnicode
.newBuilder()
.registerTypeAdapter(
c.getTClass(),
c.getStringConverter().getGsonJsonStringConverterAdapter()
)
.create();
}
@Override
public void addJsonStringConverter(@NotNull JsonStringConverter<?> c) {
addJsonConverter(c);
}
}

View File

@ -1,355 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile JacksonJsonApi.java
* LastUpdate 2025-09-15 11:16:53
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.mingliqiye.utils.json.converters.JsonConverter;
import com.mingliqiye.utils.json.converters.JsonStringConverter;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* 基于Jackson的JSON处理实现类提供JSON字符串解析格式化合并节点操作等功能
*/
public class JacksonJsonApi implements JsonApi {
private final ObjectMapper objectMapper;
/**
* 使用默认的ObjectMapper构造实例
*/
public JacksonJsonApi() {
this.objectMapper = new ObjectMapper();
}
/**
* 使用指定的ObjectMapper构造实例
*
* @param objectMapper 自定义的ObjectMapper实例
*/
public JacksonJsonApi(ObjectMapper objectMapper) {
this.objectMapper = objectMapper.copy();
}
/**
* 将JSON字符串解析为指定类型的对象
*
* @param json 待解析的JSON字符串
* @param clazz 目标对象类型
* @param <T> 泛型参数表示目标对象类型
* @return 解析后的对象
* @throws JsonException 当解析失败时抛出异常
*/
@Override
public <T> T parse(String json, Class<T> clazz) {
try {
return objectMapper.readValue(json, clazz);
} catch (IOException e) {
throw new JsonException("Failed to parse JSON string", e);
}
}
/**
* 将JSON字符串解析为复杂泛型结构的对象如ListMap等
*
* @param json JSON字符串
* @param type 泛型类型引用
* @param <T> 泛型参数表示目标对象类型
* @return 解析后的对象
* @throws JsonException 当解析失败时抛出异常
*/
@Override
public <T> T parse(String json, JsonTypeReference<T> type) {
try {
ObjectReader reader = objectMapper.readerFor(
objectMapper.constructType(type.getType())
);
return reader.readValue(json);
} catch (IOException e) {
throw new JsonException("Failed to parse JSON string", e);
}
}
/**
* 将对象格式化为JSON字符串
*
* @param object 待格式化的对象
* @return 格式化后的JSON字符串
* @throws JsonException 当格式化失败时抛出异常
*/
@Override
public String format(Object object) {
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new JsonException(
"Failed to format object to JSON string",
e
);
}
}
@Override
public String formatUnicode(Object object) {
try {
return objectMapper
.writer()
.with(JsonGenerator.Feature.ESCAPE_NON_ASCII)
.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new JsonException(e);
}
}
/**
* 将对象格式化为美化带缩进的JSON字符串
*
* @param object 待格式化的对象
* @return 美化后的JSON字符串
* @throws JsonException 当格式化失败时抛出异常
*/
@Override
public String formatPretty(Object object) {
try {
return objectMapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new JsonException(
"Failed to format object to pretty JSON string",
e
);
}
}
@Override
public String formatPrettyUnicode(Object object) {
try {
return objectMapper
.writerWithDefaultPrettyPrinter()
.with(JsonGenerator.Feature.ESCAPE_NON_ASCII)
.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new JsonException(
"Failed to format object to pretty JSON string",
e
);
}
}
/**
* 将JSON字符串解析为指定元素类型的List
*
* @param json JSON字符串
* @param elementType List中元素的类型
* @param <T> 泛型参数表示List中元素的类型
* @return 解析后的List对象
*/
@Override
public <T> List<T> parseList(String json, Class<T> elementType) {
return parse(json, JsonTypeUtils.listType(elementType));
}
/**
* 将JSON字符串解析为指定键值类型的Map
*
* @param json JSON字符串
* @param keyType Map中键的类型
* @param valueType Map中值的类型
* @param <K> 泛型参数表示Map中键的类型
* @param <V> 泛型参数表示Map中值的类型
* @return 解析后的Map对象
*/
@Override
public <K, V> Map<K, V> parseMap(
String json,
Class<K> keyType,
Class<V> valueType
) {
return parse(json, JsonTypeUtils.MapType(keyType, valueType));
}
/**
* 判断给定字符串是否是有效的JSON格式
*
* @param json 待验证的字符串
* @return 如果是有效JSON返回true否则返回false
*/
@Override
public boolean isValidJson(String json) {
try {
objectMapper.readTree(json);
return true;
} catch (Exception e) {
return false;
}
}
/**
* 合并多个JSON字符串为一个JSON对象
*
* @param jsons 多个JSON字符串
* @return 合并后的JSON字符串
* @throws JsonException 当合并失败时抛出异常
*/
@Override
public String merge(String... jsons) {
ObjectNode result = objectMapper.createObjectNode();
for (String json : jsons) {
try {
JsonNode node = objectMapper.readTree(json);
if (node.isObject()) {
result.setAll((ObjectNode) node);
}
} catch (IOException e) {
// 忽略无效的JSON字符串
}
}
try {
return objectMapper.writeValueAsString(result);
} catch (JsonProcessingException e) {
throw new JsonException("Failed to merge JSON strings", e);
}
}
/**
* 获取JSON字符串中指定路径的节点值
*
* @param json JSON字符串
* @param path 节点路径使用"."分隔
* @return 节点值的文本表示如果路径不存在则返回null
* @throws JsonException 当获取节点值失败时抛出异常
*/
@Override
public String getNodeValue(String json, String path) {
try {
JsonNode node = objectMapper.readTree(json);
String[] paths = path.split("\\.");
for (String p : paths) {
node = node.get(p);
if (node == null) {
return null;
}
}
return node.asText();
} catch (IOException e) {
throw new JsonException("Failed to get node value", e);
}
}
/**
* 更新JSON字符串中指定路径的节点值
*
* @param json JSON字符串
* @param path 节点路径使用"."分隔
* @param newValue 新的节点值
* @return 更新后的JSON字符串
* @throws JsonException 当更新节点值失败时抛出异常
*/
@Override
public String updateNodeValue(String json, String path, Object newValue) {
try {
JsonNode node = objectMapper.readTree(json);
if (node instanceof ObjectNode) {
ObjectNode objectNode = (ObjectNode) node;
String[] paths = path.split("\\.");
JsonNode current = objectNode;
// 导航到目标节点的父节点
for (int i = 0; i < paths.length - 1; i++) {
current = current.get(paths[i]);
if (current == null || !(current instanceof ObjectNode)) {
return json; // 路径不存在或无效
}
}
// 更新值
if (current instanceof ObjectNode) {
ObjectNode parent = (ObjectNode) current;
if (newValue == null) {
parent.remove(paths[paths.length - 1]);
} else {
parent.set(
paths[paths.length - 1],
objectMapper.valueToTree(newValue)
);
}
}
return objectMapper.writeValueAsString(objectNode);
}
return json;
} catch (IOException e) {
throw new JsonException("Failed to update node value", e);
}
}
/**
* 在不同对象类型之间进行转换
*
* @param source 源对象
* @param destinationClass 目标对象类型
* @param <T> 源对象类型
* @param <D> 目标对象类型
* @return 转换后的对象
*/
@Override
public <T, D> D convert(T source, Class<D> destinationClass) {
return objectMapper.convertValue(source, destinationClass);
}
/**
* 在不同泛型对象类型之间进行转换
*
* @param source 源对象
* @param destinationType 目标对象的泛型类型引用
* @param <T> 源对象类型
* @param <D> 目标对象类型
* @return 转换后的对象
*/
@Override
public <T, D> D convert(T source, JsonTypeReference<D> destinationType) {
return objectMapper.convertValue(
source,
objectMapper.constructType(destinationType.getType())
);
}
@Override
public void addJsonConverter(@NotNull JsonConverter<?, ?> c) {
objectMapper.registerModule(c.getStringConverter().getJacksonJsonStringConverterAdapter().getJacksonModule());
}
@Override
public void addJsonStringConverter(@NotNull JsonStringConverter<?> c) {
addJsonConverter(c);
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile JsonException.java
* LastUpdate 2025-09-09 09:25:08
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json;
public class JsonException extends RuntimeException {
public JsonException(String message) {
super(message);
}
public JsonException(String message, Throwable cause) {
super(message, cause);
}
public JsonException(Throwable cause) {
this(cause.getMessage(), cause);
}
}

View File

@ -1,175 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile JsonTypeReference.java
* LastUpdate 2025-09-09 09:20:05
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Objects;
import lombok.Getter;
/**
* 通用的 JSON 类型引用类用于在运行时保留泛型类型信息
* 适用于所有 JSON JacksonGsonFastjson
*
* @param <T> 引用的泛型类型
*/
@Getter
public abstract class JsonTypeReference<T>
implements Comparable<JsonTypeReference<T>> {
protected final Type type;
/**
* 构造函数通过反射获取泛型类型信息
* 仅供内部匿名子类使用
*/
protected JsonTypeReference() {
Type superClass = getClass().getGenericSuperclass();
// 检查是否为匿名子类防止直接实例化导致无法获取泛型信息
if (superClass instanceof Class) {
throw new IllegalArgumentException(
"必须使用匿名子类方式创建 JsonTypeReference" +
"例如: new JsonTypeReference<List<String>>() {}"
);
}
this.type =
((ParameterizedType) superClass).getActualTypeArguments()[0];
}
/**
* 构造函数直接指定类型
* @param type 具体的类型信息
*/
protected JsonTypeReference(Type type) {
this.type = Objects.requireNonNull(type, "Type cannot be null");
}
/**
* 创建类型引用实例
* @param <T> 目标类型
* @return 类型引用实例
*/
public static <T> JsonTypeReference<T> of() {
return new JsonTypeReference<T>() {};
}
/**
* 根据 Class 创建类型引用
* @param clazz 目标类
* @param <T> 目标类型
* @return 类型引用实例
*/
public static <T> JsonTypeReference<T> of(Class<T> clazz) {
return new JsonTypeReference<T>(clazz) {};
}
/**
* 根据 Type 创建类型引用
* @param type 目标类型
* @param <T> 目标类型
* @return 类型引用实例
*/
public static <T> JsonTypeReference<T> of(Type type) {
return new JsonTypeReference<T>(type) {};
}
/**
* 获取原始类型去掉泛型参数的类型
* @return 原始类型 Class
*/
@SuppressWarnings("unchecked")
public Class<T> getRawType() {
Type rawType = type;
// 如果是参数化类型则提取原始类型部分
if (type instanceof ParameterizedType) {
rawType = ((ParameterizedType) type).getRawType();
}
if (rawType instanceof Class) {
return (Class<T>) rawType;
}
throw new IllegalStateException("无法获取原始类型: " + type);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
JsonTypeReference<?> that = (JsonTypeReference<?>) o;
// 对于 ParameterizedType需要更完整的比较
if (
this.type instanceof ParameterizedType &&
that.type instanceof ParameterizedType
) {
ParameterizedType thisParamType = (ParameterizedType) this.type;
ParameterizedType thatParamType = (ParameterizedType) that.type;
return (
Objects.equals(
thisParamType.getRawType(),
thatParamType.getRawType()
) &&
Arrays.equals(
thisParamType.getActualTypeArguments(),
thatParamType.getActualTypeArguments()
) &&
Objects.equals(
thisParamType.getOwnerType(),
thatParamType.getOwnerType()
)
);
}
return Objects.equals(type, that.type);
}
@Override
public int hashCode() {
// 针对 ParameterizedType 进行完整哈希计算
if (type instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) type;
return Objects.hash(
paramType.getRawType(),
Arrays.hashCode(paramType.getActualTypeArguments()),
paramType.getOwnerType()
);
}
return Objects.hash(type);
}
@Override
public String toString() {
return "JsonTypeReference{" + type + '}';
}
@Override
public int compareTo(JsonTypeReference<T> o) {
return this.type.toString().compareTo(o.type.toString());
}
}

View File

@ -1,253 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile JsonTypeUtils.java
* LastUpdate 2025-09-09 09:18:08
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* JSON 类型工具类提供类型相关的工具方法
*/
public class JsonTypeUtils {
private JsonTypeUtils() {
// 工具类防止实例化
}
/**
* 检查给定的类型是否是指定类或其子类/实现类
*
* @param type 要检查的类型
* @param expectedClass 期望匹配的类
* @return 如果类型匹配则返回 true否则返回 false
*/
public static boolean isTypeOf(Type type, Class<?> expectedClass) {
if (type instanceof Class) {
return expectedClass.isAssignableFrom((Class<?>) type);
} else if (type instanceof ParameterizedType) {
return isTypeOf(
((ParameterizedType) type).getRawType(),
expectedClass
);
}
return false;
}
/**
* 获取泛型类型的参数类型
*
* @param type 泛型类型
* @param index 参数索引从0开始
* @return 指定位置的泛型参数类型
* @throws IllegalArgumentException 当无法获取指定索引的泛型参数时抛出异常
*/
public static Type getGenericParameter(Type type, int index) {
if (type instanceof ParameterizedType) {
Type[] typeArgs =
((ParameterizedType) type).getActualTypeArguments();
if (index >= 0 && index < typeArgs.length) {
return typeArgs[index];
}
}
throw new IllegalArgumentException(
"无法获取泛型参数: " + type + " at index " + index
);
}
/**
* 获取类型名称支持普通类和泛型类型
*
* @param type 类型对象
* @return 类型名称字符串
*/
public static String getTypeName(Type type) {
if (type instanceof Class) {
return ((Class<?>) type).getSimpleName();
} else if (type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) type;
Class<?> rawType = (Class<?>) pType.getRawType();
Type[] typeArgs = pType.getActualTypeArguments();
StringBuilder sb = new StringBuilder(rawType.getSimpleName());
sb.append("<");
for (int i = 0; i < typeArgs.length; i++) {
if (i > 0) sb.append(", ");
sb.append(getTypeName(typeArgs[i]));
}
sb.append(">");
return sb.toString();
}
return type.getTypeName();
}
/**
* 创建一个表示数组类型的引用对象
*
* @param componentType 数组元素的类型
* @param <T> 元素类型
* @return 表示数组类型的 JsonTypeReference 对象
*/
public static <T> JsonTypeReference<T[]> arrayType(Class<T> componentType) {
return new JsonTypeReference<T[]>() {
private final Type arrayType = java.lang.reflect.Array.newInstance(
componentType,
0
).getClass();
@Override
public Type getType() {
return new ParameterizedType() {
private final Type[] actualTypeArguments = new Type[] {
componentType,
};
@Override
public Type[] getActualTypeArguments() {
return actualTypeArguments;
}
@Override
public Type getRawType() {
return arrayType;
}
@Override
public Type getOwnerType() {
return null;
}
};
}
};
}
/**
* 创建一个表示 List 类型的引用对象
*
* @param componentType List 中元素的类型
* @param <T> 元素类型
* @return 表示 List 类型的 JsonTypeReference 对象
* @throws IllegalArgumentException 如果 componentType null则抛出异常
*/
public static <T> JsonTypeReference<List<T>> listType(
Class<T> componentType
) {
if (componentType == null) {
throw new IllegalArgumentException("componentType cannot be null");
}
return new JsonTypeReference<List<T>>() {
@Override
public Type getType() {
return new ParameterizedType() {
@Override
public Type[] getActualTypeArguments() {
return new Type[] { componentType };
}
@Override
public Type getRawType() {
return List.class;
}
@Override
public Type getOwnerType() {
return null;
}
};
}
};
}
/**
* 创建一个表示 Map 类型的引用对象
*
* @param keyType Map 键的类型
* @param valueType Map 值的类型
* @param <K> 键类型
* @param <V> 值类型
* @return 表示 Map 类型的 JsonTypeReference 对象
* @throws IllegalArgumentException 如果 keyType valueType null则抛出异常
*/
public static <K, V> JsonTypeReference<Map<K, V>> MapType(
Class<K> keyType,
Class<V> valueType
) {
if (keyType == null) {
throw new IllegalArgumentException("keyType cannot be null");
}
if (valueType == null) {
throw new IllegalArgumentException("valueType cannot be null");
}
return new JsonTypeReference<Map<K, V>>() {
@Override
public Type getType() {
return new ParameterizedType() {
@Override
public Type[] getActualTypeArguments() {
return new Type[] { keyType, valueType };
}
@Override
public Type getRawType() {
return Map.class;
}
@Override
public Type getOwnerType() {
return null;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof ParameterizedType)) return false;
ParameterizedType that = (ParameterizedType) obj;
return (
Objects.equals(getRawType(), that.getRawType()) &&
Arrays.equals(
getActualTypeArguments(),
that.getActualTypeArguments()
) &&
Objects.equals(getOwnerType(), that.getOwnerType())
);
}
@Override
public int hashCode() {
return (
Arrays.hashCode(getActualTypeArguments()) ^
Objects.hashCode(getRawType()) ^
Objects.hashCode(getOwnerType())
);
}
};
}
};
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Description.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import lombok.Data;
@Data
public class Description {
private String text;
private Extra[] extra;
}

View File

@ -1,34 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Extra.java
* LastUpdate 2025-09-09 08:37:34
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import lombok.Data;
@Data
public class Extra {
private String text;
private String color;
private Boolean bold;
private Boolean italic;
}

View File

@ -1,37 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile MinecraftServerStatus.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import lombok.Data;
@Data
public class MinecraftServerStatus {
private Description description;
private Players players;
private Version version;
private String favicon;
private boolean enforcesSecureChat;
private boolean previewsChat;
private String jsonData;
}

View File

@ -1,33 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Players.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import lombok.Data;
@Data
public class Players {
private int max;
private int online;
private PlayerSample[] sample;
}

View File

@ -1,219 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile SLP.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mingliqiye.utils.network.NetworkEndpoint;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Minecraft 服务器列表协议Server List Ping, SLP工具类
* 提供了与 Minecraft 服务器通信以获取其状态信息的功能
*/
public class SLP {
private static final ObjectMapper objectMapper = new ObjectMapper();
/**
* int32 值截断为无符号 short2 字节并按大端序写入字节数组
*
* @param value 需要转换的整数int32
* @return 包含两个字节的数组表示无符号 short
*/
public static byte[] toUnsignedShort(int value) {
byte[] array = new byte[2];
ByteBuffer.wrap(array, 0, 2)
.order(ByteOrder.BIG_ENDIAN)
.putShort((short) (value & 0xFFFF));
return array;
}
/**
* 构造 Minecraft 握手包数据
* 握手包用于初始化客户端与服务器之间的连接
*
* @param serverIP 服务器 IP 地址或域名
* @param serverPort 服务器端口号
* @param type 连接类型通常为 1 表示获取状态
* @return 握手包的完整字节数组
* @throws IOException 如果构造过程中发生 IO 错误
*/
public static byte[] getHandshakePack(
String serverIP,
int serverPort,
int type
) throws IOException {
ByteArrayOutputStream pack = new ByteArrayOutputStream();
ByteArrayOutputStream byteArrayOutputStream =
new ByteArrayOutputStream();
pack.write(0x00); // 握手包标识符
pack.write(toVarInt(1156)); // 协议版本号示例值
byte[] sip = serverIP.getBytes();
pack.write(toVarInt(sip.length)); // 服务器地址长度
pack.write(sip); // 服务器地址
pack.write(toUnsignedShort(serverPort)); // 服务器端口
pack.write(toVarInt(type)); // 下一阶段类型1 表示状态请求
byteArrayOutputStream.write(toVarInt(pack.size())); // 包长度前缀
byteArrayOutputStream.write(pack.toByteArray());
return byteArrayOutputStream.toByteArray();
}
/**
* 获取状态请求包的固定字节表示
* 此包用于向服务器请求当前状态信息
*
* @return 状态请求包的字节数组
*/
public static byte[] getStatusPack() {
return new byte[] { 0x01, 0x00 };
}
/**
* 从输入流中读取服务器返回的状态 JSON 数据并解析为 MinecraftServerStatus 实体对象
*
* @param inputStream 输入流包含服务器响应的数据
* @return 解析后的 MinecraftServerStatus 对象
* @throws IOException 如果读取过程中发生 IO 错误
*/
public static MinecraftServerStatus getStatusJsonEntity(
DataInputStream inputStream
) throws IOException {
readVarInt(inputStream); // 忽略第一个 VarInt包长度
inputStream.readByte(); // 忽略包标识符
int lengthjson = readVarInt(inputStream); // 读取 JSON 数据长度
byte[] data = new byte[lengthjson];
inputStream.readFully(data); // 读取完整的 JSON 数据
MinecraftServerStatus serverStatus = objectMapper.readValue(
data,
MinecraftServerStatus.class
);
serverStatus.setJsonData(new String(data)); // 设置原始 JSON 字符串
return serverStatus;
}
/**
* 从输入流中读取一个 VarInt 类型的整数最多 5 个字节
*
* @param in 输入流
* @return 解码后的整数值
* @throws IOException 如果读取过程中发生 IO 错误
*/
public static int readVarInt(DataInputStream in) throws IOException {
int value = 0;
int length = 0;
byte currentByte;
do {
currentByte = in.readByte();
value |= (currentByte & 0x7F) << (length * 7);
length += 1;
if (length > 5) {
throw new RuntimeException("VarInt too long");
}
} while ((currentByte & 0x80) != 0);
return value;
}
/**
* 将一个 int32 整数编码为 VarInt 格式的字节数组1 5 个字节
*
* @param value 需要编码的整数
* @return 编码后的 VarInt 字节数组
*/
public static byte[] toVarInt(int value) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
while (true) {
if ((value & 0xFFFFFF80) == 0) {
buffer.write(value); // 最后一个字节
break;
}
buffer.write((value & 0x7F) | 0x80); // 写入带继续位的字节
value >>>= 7; // 右移 7 位继续处理
}
return buffer.toByteArray();
}
/**
* 创建一个新的 Socket 连接到指定的网络端点并设置超时时间
*
* @param networkEndpoint 目标网络端点包括主机和端口
* @return 已连接的 Socket 实例
* @throws IOException 如果连接失败或发生 IO 错误
*/
public static Socket getNewConnect(NetworkEndpoint networkEndpoint)
throws IOException {
Socket socket = new Socket();
socket.setSoTimeout(5000); // 设置读取超时时间为 5
socket.connect(networkEndpoint.toInetSocketAddress()); // 执行连接操作
return socket;
}
/**
* 使用 "host:port" 格式的字符串连接到 Minecraft 服务器并获取其状态信息
*
* @param s 域名或 IP 地址加端口号组成的字符串例如 "127.0.0.1:25565"
* @return 服务器状态实体对象
* @throws IOException 如果连接失败或发生 IO 错误
*/
public static MinecraftServerStatus getServerStatus(String s)
throws IOException {
return getServerStatus(NetworkEndpoint.of(s));
}
/**
* 使用指定的主机名和端口号连接到 Minecraft 服务器并获取其状态信息
*
* @param s 主机名或 IP 地址
* @param i 端口号
* @return 服务器状态实体对象
* @throws IOException 如果连接失败或发生 IO 错误
*/
public static MinecraftServerStatus getServerStatus(String s, Integer i)
throws IOException {
return getServerStatus(NetworkEndpoint.of(s, i));
}
/**
* 使用 NetworkEndpoint 实例连接到 Minecraft 服务器并获取其状态信息
*
* @param e 网络端点实例包含主机和端口信息
* @return 服务器状态实体对象
* @throws IOException 如果连接失败或发生 IO 错误
* @see NetworkEndpoint
*/
public static MinecraftServerStatus getServerStatus(NetworkEndpoint e)
throws IOException {
Socket socket = getNewConnect(e); // 建立 TCP 连接
OutputStream out = socket.getOutputStream(); // 获取输出流发送数据
DataInputStream in = new DataInputStream(socket.getInputStream()); // 获取输入流接收数据
out.write(getHandshakePack(e.getHost(), e.getPort(), 1)); // 发送握手包
out.write(getStatusPack()); // 发送状态请求包
return getStatusJsonEntity(in); // 读取并解析服务器响应
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Version.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
import lombok.Data;
@Data
public class Version {
private String name;
private int protocol;
}

View File

@ -1,218 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile NetworkAddress.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.network;
import com.mingliqiye.utils.string.StringUtils;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Pattern;
/**
* 网络地址类用于表示一个网络地址IP或域名并提供相关操作
* 支持IPv4和IPv6地址的解析与验证
*
* @author MingLiPro
*/
public class NetworkAddress implements Serializable {
/**
* IPv6标识
*/
public static int IPV6 = 6;
/**
* IPv4标识
*/
public static int IPV4 = 4;
/**
* IPv4地址正则表达式
*/
static String IPV4REG =
"^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2" +
"(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$";
/**
* 编译后的IPv4地址匹配模式
*/
private static final Pattern IPV4_PATTERN = Pattern.compile(IPV4REG);
/**
* IPv6地址正则表达式
*/
static String IPV6REG =
"^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|" +
"^(::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4})$" +
"|" +
"^(::)$|" +
"^([0-9a-fA-F]{1,4}::([0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4})$|" +
"^(([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4})$|" +
"^(([0-9a-fA-F]{1,4}:){6}(([0-9]{1,3}\\.){3}[0-9]{1,3}))$|" +
"^::([fF]{4}:)?(([0-9]{1,3}\\.){3}[0-9]{1,3})$";
/**
* 编译后的IPv6地址匹配模式
*/
private static final Pattern IPV6_PATTERN = Pattern.compile(IPV6REG);
/**
* IP地址类型4 表示 IPv46 表示 IPv6
*/
@Getter
private int IPv;
/**
* IP地址字符串
*/
@Getter
private String ip;
/**
* 域名如果输入的是域名
*/
private String domain;
/**
* 标识是否是域名解析来的IP
*/
private boolean isdom;
/**
* 构造方法根据传入的字符串判断是IP地址还是域名并进行相应处理
*
* @param domip 可能是IP地址或域名的字符串
*/
NetworkAddress(String domip) {
try {
// 尝试将输入识别为IP地址
IPv = testIp(domip);
ip = domip;
} catch (NetworkException e) {
try {
// 如果不是有效IP则尝试作为域名解析
String ips = getHostIp(domip);
IPv = testIp(ips);
ip = ips;
isdom = true;
domain = domip;
} catch (UnknownHostException ex) {
throw new NetworkException(ex);
}
}
}
/**
* 静态工厂方法创建 NetworkAddress 实例
*
* @param domip 可能是IP地址或域名的字符串
* @return 新建的 NetworkAddress 实例
*/
public static NetworkAddress of(String domip) {
return new NetworkAddress(domip);
}
/**
* 静态工厂方法通过 InetAddress 创建 NetworkAddress 实例
*
* @param inetAddress InetAddress 对象
* @return 新建的 NetworkAddress 实例
*/
public static NetworkAddress of(InetAddress inetAddress) {
return new NetworkAddress(inetAddress.getHostAddress());
}
/**
* 从DNS服务器解析域名获取对应的IP地址
*
* @param domain 域名
* @return 解析出的第一个IP地址
* @throws UnknownHostException 如果域名无法解析
*/
public static String getHostIp(@NotNull String domain)
throws UnknownHostException {
InetAddress[] addresses = InetAddress.getAllByName(domain.trim());
return addresses[0].getHostAddress();
}
/**
* 检测给定字符串是否为有效的IPv4或IPv6地址
*
* @param ip 要检测的IP地址字符串
* @return 4 表示IPv46 表示IPv6
* @throws NetworkException 如果IP格式无效
*/
public static int testIp(String ip) {
if (ip == null) {
throw new NetworkException("IP地址不能为null");
}
String trimmedIp = ip.trim();
// 判断是否匹配IPv4格式
if (IPV4_PATTERN.matcher(trimmedIp).matches()) {
return IPV4;
}
// 判断是否匹配IPv6格式
if (IPV6_PATTERN.matcher(trimmedIp).matches()) {
return IPV6;
}
// 不符合任一格式时抛出异常
throw new NetworkException(
StringUtils.format("[{}] 不是有效的IPv4或IPv6地址", ip)
);
}
/**
* 将当前 NetworkAddress 转换为 InetAddress 对象
*
* @return InetAddress 对象
*/
public InetAddress toInetAddress() {
try {
return InetAddress.getByName(ip != null ? ip : domain);
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
/**
* 返回 NetworkAddress 的字符串表示形式
*
* @return 字符串表示
*/
public String toString() {
return isdom
? StringUtils.format(
"NetworkAddress(IP='{}',type='{}'," + "domain='{}')",
ip,
IPv,
domain
)
: StringUtils.format("NetworkAddress(IP='{}',type='{}')", ip, IPv);
}
}

View File

@ -1,164 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile NetworkEndpoint.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.network;
import com.mingliqiye.utils.string.StringUtils;
import lombok.Getter;
import java.io.Serializable;
import java.net.InetSocketAddress;
/**
* IP和端口聚集类用于封装网络地址与端口信息
* 该类提供了与InetSocketAddress之间的相互转换功能
*
* @author MingLiPro
* @see InetSocketAddress
*/
public class NetworkEndpoint implements Serializable {
@Getter
private final NetworkAddress networkAddress;
@Getter
private final NetworkPort networkPort;
/**
* 构造函数使用指定的网络地址和端口创建NetworkEndpoint实例
*
* @param networkAddress 网络地址对象
* @param networkPort 网络端口对象
* @see NetworkAddress
* @see NetworkPort
*/
private NetworkEndpoint(
NetworkAddress networkAddress,
NetworkPort networkPort
) {
this.networkAddress = networkAddress;
this.networkPort = networkPort;
}
/**
* 根据给定的InetSocketAddress对象创建NetworkEndpoint实例
*
* @param address InetSocketAddress对象
* @return 新建的NetworkEndpoint实例
* @see InetSocketAddress
*/
public static NetworkEndpoint of(InetSocketAddress address) {
return new NetworkEndpoint(
new NetworkAddress(address.getHostString()),
new NetworkPort(address.getPort())
);
}
/**
* 根据主机名或IP字符串和端口号创建NetworkEndpoint实例
*
* @param s 主机名或IP地址字符串
* @param i 端口号
* @return 新建的NetworkEndpoint实例
*/
public static NetworkEndpoint of(String s, Integer i) {
NetworkAddress networkAddress = new NetworkAddress(s);
NetworkPort networkPort = new NetworkPort(i);
return new NetworkEndpoint(networkAddress, networkPort);
}
/**
* 根据"host:port"格式的字符串创建NetworkEndpoint实例
* 例如"127.0.0.1:8080"
*
* @param s "host:port"格式的字符串
* @return 新建的NetworkEndpoint实例
*/
public static NetworkEndpoint of(String s) {
// 查找最后一个冒号的位置以支持IPv6地址中的冒号
int lastColonIndex = s.lastIndexOf(':');
return of(
s.substring(0, lastColonIndex),
Integer.parseInt(s.substring(lastColonIndex + 1))
);
}
/**
* 将当前NetworkEndpoint转换为InetSocketAddress对象
*
* @return 对应的InetSocketAddress对象
* @see InetSocketAddress
*/
public InetSocketAddress toInetSocketAddress() {
return new InetSocketAddress(
networkAddress.toInetAddress(),
networkPort.getPort()
);
}
/**
* 将当前NetworkEndpoint转换为"host:port"格式的字符串
* 例如"127.0.0.1:25563"
*
* @return 格式化后的字符串
*/
public String toHostPortString() {
return StringUtils.format(
"{}:{}",
networkAddress.getIp(),
networkPort.getPort()
);
}
/**
* 返回NetworkEndpoint的详细字符串表示形式
* 格式NetworkEndpoint(IP=...,Port=...,Endpoint=...)
*
* @return 包含详细信息的字符串
*/
public String toString() {
return StringUtils.format(
"NetworkEndpoint(IP={},Port={},Endpoint={})",
networkAddress.getIp(),
networkPort.getPort(),
toHostPortString()
);
}
/**
* 获取主机名或IP地址字符串
*
* @return 主机名或IP地址
*/
public String getHost() {
return networkAddress.getIp();
}
/**
* 获取端口号
*
* @return 端口号
*/
public Integer getPort() {
return networkPort.getPort();
}
}

View File

@ -1,49 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile NetworkException.java
* LastUpdate 2025-09-09 08:37:33
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.network;
/**
* 网络异常类用于处理网络相关的运行时异常
*
* @author MingLiPro
*/
public class NetworkException extends RuntimeException {
/**
* 构造一个带有指定详细消息的网络异常
*
* @param message 异常的详细消息
*/
public NetworkException(String message) {
super(message);
}
/**
* 构造一个网络异常指定原因异常
*
* @param e 导致此异常的原因异常
*/
public NetworkException(Exception e) {
super(e);
}
}

View File

@ -1,64 +0,0 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile NetworkPort.java
* LastUpdate 2025-09-14 22:12:16
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.network;
import com.mingliqiye.utils.string.StringUtils;
import lombok.Getter;
import java.io.Serializable;
/**
* 网络端口类
*
* @author MingLiPro
*/
public class NetworkPort implements Serializable {
@Getter
private final int port;
/**
* 构造函数创建一个网络端口对象
*
* @param port 端口号必须在0-65535范围内
*/
public NetworkPort(int port) {
testPort(port);
this.port = port;
}
/**
* 验证端口号是否合法
*
* @param port 待验证的端口号
* @throws NetworkException 当端口号不在合法范围(0-65535)内时抛出异常
*/
public static void testPort(int port) {
// 验证端口号范围是否在0-65535之间
if (!(0 <= port && 65535 >= port)) {
throw new NetworkException(
StringUtils.format("{} 不是正确的端口号", port)
);
}
}
}

View File

@ -16,17 +16,16 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Main.kt
* LastUpdate 2025-09-15 18:02:00
* LastUpdate 2025-09-15 22:31:33
* UpdateUser MingLiPro
*/
@file:JvmName("Main")
package com.mingliqiye.utils
import com.mingliqiye.utils.springboot.autoconfigure.AutoConfiguration
import com.mingliqiye.utils.uuid.UUID
fun main() {
AutoConfiguration.printBanner()
println(UUID.of("b5c4579e-921a-11f0-ad12-d7949d0c61b8").equals(UUID.of("b5c4579e-921a-11f0-ad12-d7949d0c61b8")))
println(UUID.getV1())
}

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile AesUtils.kt
* LastUpdate 2025-09-14 18:43:04
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Base64Utils.kt
* LastUpdate 2025-09-14 18:44:22
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/
@file:JvmName("Base64Utils")

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Factory.kt
* LastUpdate 2025-09-14 19:09:28
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/
@file:JvmName("Factory")

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile ComponentBean.kt
* LastUpdate 2025-09-14 18:48:59
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile SpringBeanUtils.kt
* LastUpdate 2025-09-14 22:10:45
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile FieldStructure.kt
* LastUpdate 2025-09-14 18:19:29
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/

View File

@ -0,0 +1,231 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile GsonJsonApi.kt
* LastUpdate 2025-09-15 22:07:43
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json
import com.google.gson.*
import com.mingliqiye.utils.json.converters.JsonConverter
import com.mingliqiye.utils.json.converters.JsonStringConverter
class GsonJsonApi : JsonApi {
private var gsonUnicode: Gson
private var gsonPretty: Gson
private var gsonPrettyUnicode: Gson
private var gson: Gson
constructor() {
gson = GsonBuilder()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create()
gsonUnicode = GsonBuilder()
.disableHtmlEscaping()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create()
gsonPretty = GsonBuilder()
.setPrettyPrinting()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create()
gsonPrettyUnicode = GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create()
}
constructor(gson: Gson) {
this.gson = gson
.newBuilder()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create()
this.gsonUnicode = gson
.newBuilder()
.disableHtmlEscaping()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create()
this.gsonPretty = gson
.newBuilder()
.setPrettyPrinting()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create()
this.gsonPrettyUnicode = gson
.newBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create()
}
override fun <T> parse(json: String, clazz: Class<T>): T {
return gson.fromJson(json, clazz)
}
override fun <T> parse(json: String, type: JsonTypeReference<T>): T {
return gson.fromJson(json, type.type)
}
override fun format(obj: Any): String {
return gson.toJson(obj)
}
override fun formatUnicode(obj: Any): String {
return gsonUnicode.toJson(obj)
}
override fun formatPretty(obj: Any): String {
return gsonPretty.toJson(obj)
}
override fun formatPrettyUnicode(obj: Any): String {
return gsonPrettyUnicode.toJson(obj)
}
override fun isValidJson(json: String): Boolean {
return try {
JsonParser.parseString(json)
true
} catch (e: JsonSyntaxException) {
false
} catch (e: Exception) {
false
}
}
override fun merge(vararg jsons: String): String {
val merged = JsonObject()
for (json in jsons) {
if (json.isNullOrEmpty()) {
continue
}
try {
val obj = JsonParser.parseString(json).asJsonObject
for (key in obj.keySet()) {
merged.add(key, obj.get(key))
}
} catch (e: Exception) {
// 忽略无效的 JSON 字符串
}
}
return gson.toJson(merged)
}
override fun getNodeValue(json: String, path: String): String? {
return try {
var element = JsonParser.parseString(json)
val paths = path.split("\\.".toRegex()).toTypedArray()
var current = element
for (p in paths) {
if (current.isJsonObject) {
current = current.asJsonObject.get(p)
} else {
return null
}
if (current == null) {
return null
}
}
if (current.isJsonPrimitive) current.asString else current.toString()
} catch (e: Exception) {
null
}
}
override fun updateNodeValue(json: String, path: String, newValue: Any): String {
return try {
val obj = JsonParser.parseString(json).asJsonObject
val paths = path.split("\\.".toRegex()).toTypedArray()
var current = obj
// 导航到倒数第二层
for (i in 0 until paths.size - 1) {
val p = paths[i]
if (!current.has(p) || !current.get(p).isJsonObject) {
current.add(p, JsonObject())
}
current = current.getAsJsonObject(p)
}
// 设置最后一层的值
val lastPath = paths[paths.size - 1]
val element = gson.toJsonTree(newValue)
current.add(lastPath, element)
gson.toJson(obj)
} catch (e: Exception) {
json
}
}
override fun <T, D> convert(source: T, destinationClass: Class<D>): D {
val json = gson.toJson(source)
return gson.fromJson(json, destinationClass)
}
override fun <T, D> convert(source: T, destinationType: JsonTypeReference<D>): D {
val json = gson.toJson(source)
return gson.fromJson(json, destinationType.type)
}
override fun addJsonConverter(c: JsonConverter<*, *>) {
c.getStringConverter()?.let {
gson = gson
.newBuilder()
.registerTypeAdapter(
it.tClass,
it.gsonJsonStringConverterAdapter
)
.create()
gsonUnicode = gsonUnicode
.newBuilder()
.registerTypeAdapter(
it.tClass,
it.gsonJsonStringConverterAdapter
)
.create()
gsonPretty = gsonPretty
.newBuilder()
.registerTypeAdapter(
it.tClass,
it.gsonJsonStringConverterAdapter
)
.create()
gsonPrettyUnicode = gsonPrettyUnicode
.newBuilder()
.registerTypeAdapter(
it.tClass,
it.gsonJsonStringConverterAdapter
)
.create()
}
}
override fun addJsonStringConverter(c: JsonStringConverter<*>) {
addJsonConverter(c)
}
}

View File

@ -0,0 +1,301 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile JacksonJsonApi.kt
* LastUpdate 2025-09-15 22:07:43
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.ObjectReader
import com.fasterxml.jackson.databind.node.ObjectNode
import com.mingliqiye.utils.json.converters.JsonConverter
import com.mingliqiye.utils.json.converters.JsonStringConverter
import java.io.IOException
/**
* 基于Jackson的JSON处理实现类提供JSON字符串解析格式化合并节点操作等功能
*/
class JacksonJsonApi : JsonApi {
private val objectMapper: ObjectMapper
/**
* 使用默认的ObjectMapper构造实例
*/
constructor() {
this.objectMapper = ObjectMapper()
}
/**
* 使用指定的ObjectMapper构造实例
*
* @param objectMapper 自定义的ObjectMapper实例
*/
constructor(objectMapper: ObjectMapper) {
this.objectMapper = objectMapper.copy()
}
/**
* 将JSON字符串解析为指定类型的对象
*
* @param json 待解析的JSON字符串
* @param clazz 目标对象类型
* @param <T> 泛型参数表示目标对象类型
* @return 解析后的对象
* @throws JsonException 当解析失败时抛出异常
*/
override fun <T> parse(json: String, clazz: Class<T>): T {
return try {
objectMapper.readValue(json, clazz)
} catch (e: IOException) {
throw JsonException("Failed to parse JSON string", e)
}
}
/**
* 将JSON字符串解析为复杂泛型结构的对象如ListMap等
*
* @param json JSON字符串
* @param type 泛型类型引用
* @param <T> 泛型参数表示目标对象类型
* @return 解析后的对象
* @throws JsonException 当解析失败时抛出异常
*/
override fun <T> parse(json: String, type: JsonTypeReference<T>): T {
return try {
val reader: ObjectReader = objectMapper.readerFor(
objectMapper.constructType(type.type)
)
reader.readValue(json)
} catch (e: IOException) {
throw JsonException("Failed to parse JSON string", e)
}
}
/**
* 将对象格式化为JSON字符串
*
* @param `object` 待格式化的对象
* @return 格式化后的JSON字符串
* @throws JsonException 当格式化失败时抛出异常
*/
override fun format(obj: Any): String {
return try {
objectMapper.writeValueAsString(obj)
} catch (e: JsonProcessingException) {
throw JsonException(
"Failed to format object to JSON string",
e
)
}
}
override fun formatUnicode(obj: Any): String {
return try {
objectMapper
.writer()
.with(JsonGenerator.Feature.ESCAPE_NON_ASCII)
.writeValueAsString(obj)
} catch (e: JsonProcessingException) {
throw JsonException(e)
}
}
/**
* 将对象格式化为美化带缩进的JSON字符串
*
* @param `object` 待格式化的对象
* @return 美化后的JSON字符串
* @throws JsonException 当格式化失败时抛出异常
*/
override fun formatPretty(obj: Any): String {
return try {
objectMapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(obj)
} catch (e: JsonProcessingException) {
throw JsonException(
"Failed to format object to pretty JSON string",
e
)
}
}
override fun formatPrettyUnicode(obj: Any): String {
return try {
objectMapper
.writerWithDefaultPrettyPrinter()
.with(JsonGenerator.Feature.ESCAPE_NON_ASCII)
.writeValueAsString(obj)
} catch (e: JsonProcessingException) {
throw JsonException(
"Failed to format object to pretty JSON string",
e
)
}
}
/**
* 判断给定字符串是否是有效的JSON格式
*
* @param json 待验证的字符串
* @return 如果是有效JSON返回true否则返回false
*/
override fun isValidJson(json: String): Boolean {
return try {
objectMapper.readTree(json)
true
} catch (e: Exception) {
false
}
}
/**
* 合并多个JSON字符串为一个JSON对象
*
* @param jsons 多个JSON字符串
* @return 合并后的JSON字符串
* @throws JsonException 当合并失败时抛出异常
*/
override fun merge(vararg jsons: String): String {
val result: ObjectNode = objectMapper.createObjectNode()
for (json in jsons) {
try {
val node: JsonNode = objectMapper.readTree(json)
if (node.isObject) {
result.setAll<JsonNode>(node as ObjectNode)
}
} catch (e: IOException) {
// 忽略无效的JSON字符串
}
}
return try {
objectMapper.writeValueAsString(result)
} catch (e: JsonProcessingException) {
throw JsonException("Failed to merge JSON strings", e)
}
}
/**
* 获取JSON字符串中指定路径的节点值
*
* @param json JSON字符串
* @param path 节点路径使用"."分隔
* @return 节点值的文本表示如果路径不存在则返回null
* @throws JsonException 当获取节点值失败时抛出异常
*/
override fun getNodeValue(json: String, path: String): String? {
return try {
var node: JsonNode = objectMapper.readTree(json)
val paths: Array<String> = path.split("\\.".toRegex()).toTypedArray()
for (p in paths) {
node = node.get(p)
}
node.asText()
} catch (e: IOException) {
throw JsonException("Failed to get node value", e)
}
}
/**
* 更新JSON字符串中指定路径的节点值
*
* @param json JSON字符串
* @param path 节点路径使用"."分隔
* @param newValue 新的节点值
* @return 更新后的JSON字符串
* @throws JsonException 当更新节点值失败时抛出异常
*/
override fun updateNodeValue(json: String, path: String, newValue: Any): String {
return try {
val node: JsonNode = objectMapper.readTree(json)
if (node is ObjectNode) {
val objectNode: ObjectNode = node
val paths: Array<String> = path.split("\\.".toRegex()).toTypedArray()
var current: JsonNode = objectNode
// 导航到目标节点的父节点
for (i in 0 until paths.size - 1) {
current = current.get(paths[i])
if (current !is ObjectNode) {
return json // 路径不存在或无效
}
}
// 更新值
if (current is ObjectNode) {
val parent: ObjectNode = current
parent.set<JsonNode>(
paths[paths.size - 1],
objectMapper.valueToTree(newValue)
)
}
objectMapper.writeValueAsString(objectNode)
}
json
} catch (e: IOException) {
throw JsonException("Failed to update node value", e)
}
}
/**
* 在不同对象类型之间进行转换
*
* @param source 源对象
* @param destinationClass 目标对象类型
* @param <T> 源对象类型
* @param <D> 目标对象类型
* @return 转换后的对象
*/
override fun <T, D> convert(source: T, destinationClass: Class<D>): D {
return objectMapper.convertValue(source, destinationClass)
}
/**
* 在不同泛型对象类型之间进行转换
*
* @param source 源对象
* @param destinationType 目标对象的泛型类型引用
* @param <T> 源对象类型
* @param <D> 目标对象类型
* @return 转换后的对象
*/
override fun <T, D> convert(source: T, destinationType: JsonTypeReference<D>): D {
return objectMapper.convertValue(
source,
objectMapper.constructType(destinationType.type)
)
}
override fun addJsonConverter(c: JsonConverter<*, *>) {
c.getStringConverter()?.let {
objectMapper.registerModule(it.jacksonJsonStringConverterAdapter.jacksonModule)
}
}
override fun addJsonStringConverter(c: JsonStringConverter<*>) {
addJsonConverter(c)
}
}

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile JsonApi.kt
* LastUpdate 2025-09-15 11:10:59
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/
@ -306,8 +306,8 @@ interface JsonApi {
* @param <T> 泛型参数表示List中元素的类型
* @return 解析后的List集合
</T> */
fun <T> parseList(json: String, elementType: Class<T>): MutableList<T> {
return parse<MutableList<T>>(json, JsonTypeUtils.listType<T>(elementType))
fun <T> parseList(json: String, elementType: Class<T>): List<T> {
return parse(json, type = listType(elementType))
}
/**
@ -372,7 +372,7 @@ interface JsonApi {
* @param path 节点路径"user.name"
* @return 节点值的字符串表示
*/
fun getNodeValue(json: String, path: String): String
fun getNodeValue(json: String, path: String): String?
/**
* 更新JSON字符串中指定路径节点的值

View File

@ -15,18 +15,18 @@
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile PlayerSample.java
* LastUpdate 2025-09-09 08:37:33
* CurrentFile JsonException.kt
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.minecraft.slp;
package com.mingliqiye.utils.json
import lombok.Data;
class JsonException : RuntimeException {
@Data
public class PlayerSample {
constructor(message: String) : super(message)
private String name;
private String id;
constructor(message: String, cause: Throwable) : super(message, cause)
constructor(cause: Throwable) : this(cause.message ?: "", cause)
}

View File

@ -0,0 +1,164 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile JsonTypeReference.kt
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.json
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.util.*
/**
* 通用的 JSON 类型引用类用于在运行时保留泛型类型信息
* 适用于所有 JSON JacksonGsonFastjson
*
* @param <T> 引用的泛型类型
*/
abstract class JsonTypeReference<T> : Comparable<JsonTypeReference<T>> {
open var type: Type = Any::class.java
/**
* 构造函数通过反射获取泛型类型信息
* 仅供内部匿名子类使用
*/
protected constructor() {
val superClass: Type = this.javaClass.genericSuperclass
// 检查是否为匿名子类,防止直接实例化导致无法获取泛型信息
if (superClass is Class<*>) {
throw IllegalArgumentException(
"必须使用匿名子类方式创建 JsonTypeReference" +
"例如: new JsonTypeReference<List<String>>() {}"
)
}
this.type = (superClass as ParameterizedType).actualTypeArguments[0]
}
/**
* 构造函数直接指定类型
* @param type 具体的类型信息
*/
protected constructor(type: Type) {
this.type = Objects.requireNonNull(type, "Type cannot be null")
}
/**
* 创建类型引用实例
* @param <T> 目标类型
* @return 类型引用实例
*/
companion object {
@JvmStatic
fun <T> of(): JsonTypeReference<T> {
return object : JsonTypeReference<T>() {}
}
/**
* 根据 Class 创建类型引用
* @param clazz 目标类
* @param <T> 目标类型
* @return 类型引用实例
*/
@JvmStatic
fun <T> of(clazz: Class<T>): JsonTypeReference<T> {
return object : JsonTypeReference<T>(clazz) {}
}
/**
* 根据 Type 创建类型引用
* @param type 目标类型
* @param <T> 目标类型
* @return 类型引用实例
*/
@JvmStatic
fun <T> of(type: Type): JsonTypeReference<T> {
return object : JsonTypeReference<T>(type) {}
}
}
/**
* 获取原始类型去掉泛型参数的类型
* @return 原始类型 Class
*/
@Suppress("UNCHECKED_CAST")
fun getRawType(): Class<T> {
var rawType: Type = type
// 如果是参数化类型,则提取原始类型部分
if (type is ParameterizedType) {
rawType = (type as ParameterizedType).rawType
}
if (rawType is Class<*>) {
return rawType as Class<T>
}
throw IllegalStateException("无法获取原始类型: $type")
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this.javaClass != other.javaClass) return false
val that = other as JsonTypeReference<*>
// 对于 ParameterizedType需要更完整的比较
if (this.type is ParameterizedType && that.type is ParameterizedType) {
val thisParamType = this.type as ParameterizedType
val thatParamType = that.type as ParameterizedType
return (
Objects.equals(
thisParamType.rawType,
thatParamType.rawType
) &&
thisParamType.actualTypeArguments.contentEquals(thatParamType.actualTypeArguments) &&
Objects.equals(
thisParamType.ownerType,
thatParamType.ownerType
)
)
}
return Objects.equals(type, that.type)
}
override fun hashCode(): Int {
if (type is ParameterizedType) {
val paramType = type as ParameterizedType
return Objects.hash(
paramType.rawType,
paramType.actualTypeArguments.contentHashCode(),
paramType.ownerType
)
}
return Objects.hash(type)
}
override fun toString(): String {
return "JsonTypeReference{$type}"
}
override fun compareTo(other: JsonTypeReference<T>): Int {
return this.type.toString().compareTo(other.type.toString())
}
}

View File

@ -0,0 +1,201 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile JsonTypeUtils.kt
* LastUpdate 2025-09-15 22:04:54
* UpdateUser MingLiPro
*/
@file:JvmName("JsonTypeUtils")
package com.mingliqiye.utils.json
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import java.util.*
/**
* 检查给定的类型是否是指定类或其子类/实现类
*
* @param type 要检查的类型
* @param expectedClass 期望匹配的类
* @return 如果类型匹配则返回 true否则返回 false
*/
fun isTypeOf(type: Type, expectedClass: Class<*>): Boolean {
return when (type) {
is Class<*> -> expectedClass.isAssignableFrom(type)
is ParameterizedType -> isTypeOf(type.rawType, expectedClass)
else -> false
}
}
/**
* 获取泛型类型的参数类型
*
* @param type 泛型类型
* @param index 参数索引从0开始
* @return 指定位置的泛型参数类型
* @throws IllegalArgumentException 当无法获取指定索引的泛型参数时抛出异常
*/
fun getGenericParameter(type: Type, index: Int): Type {
if (type is ParameterizedType) {
val typeArgs = type.actualTypeArguments
if (index >= 0 && index < typeArgs.size) {
return typeArgs[index]
}
}
throw IllegalArgumentException(
"无法获取泛型参数: $type at index $index"
)
}
/**
* 获取类型名称支持普通类和泛型类型
*
* @param type 类型对象
* @return 类型名称字符串
*/
fun getTypeName(type: Type): String {
return when (type) {
is Class<*> -> type.simpleName
is ParameterizedType -> {
val rawType = type.rawType as Class<*>
val typeArgs = type.actualTypeArguments
val sb = StringBuilder(rawType.simpleName)
sb.append("<")
for (i in typeArgs.indices) {
if (i > 0) sb.append(", ")
sb.append(getTypeName(typeArgs[i]))
}
sb.append(">")
sb.toString()
}
else -> type.typeName
}
}
/**
* 创建一个表示数组类型的引用对象
*
* @param componentType 数组元素的类型
* @param <T> 元素类型
* @return 表示数组类型的 JsonTypeReference 对象
*/
fun <T> arrayType(componentType: Class<T>): JsonTypeReference<Array<T>> {
return object : JsonTypeReference<Array<T>>() {
private val arrayType: Type = java.lang.reflect.Array.newInstance(
componentType, 0
).javaClass
override var type: Type = Any::class.java
get() = object : ParameterizedType {
private val actualTypeArguments = arrayOf<Type>(componentType)
override fun getActualTypeArguments(): Array<Type> {
return actualTypeArguments
}
override fun getRawType(): Type {
return arrayType
}
override fun getOwnerType(): Type? {
return null
}
}
}
}
/**
* 创建一个表示 List 类型的引用对象
*
* @param componentType List 中元素的类型
* @param <T> 元素类型
* @return 表示 List 类型的 JsonTypeReference 对象
* @throws IllegalArgumentException 如果 componentType null则抛出异常
*/
fun <T> listType(componentType: Class<T>): JsonTypeReference<List<T>> {
return object : JsonTypeReference<List<T>>() {
override var type: Type = Any::class.java
get() = object : ParameterizedType {
override fun getActualTypeArguments(): Array<Type> {
return arrayOf(componentType)
}
override fun getRawType(): Type {
return List::class.java
}
override fun getOwnerType(): Type? {
return null
}
}
}
}
/**
* 创建一个表示 Map 类型的引用对象
*
* @param keyType Map 键的类型
* @param valueType Map 值的类型
* @param <K> 键类型
* @param <V> 值类型
* @return 表示 Map 类型的 JsonTypeReference 对象
* @throws IllegalArgumentException 如果 keyType valueType null则抛出异常
*/
fun <K, V> MapType(keyType: Class<K>, valueType: Class<V>): JsonTypeReference<Map<K, V>> {
return object : JsonTypeReference<Map<K, V>>() {
override var type: Type = Any::class.java
get() = object : ParameterizedType {
override fun getActualTypeArguments(): Array<Type> {
return arrayOf(keyType, valueType)
}
override fun getRawType(): Type {
return Map::class.java
}
override fun getOwnerType(): Type? {
return null
}
override fun equals(obj: Any?): Boolean {
if (this === obj) return true
if (obj !is ParameterizedType) return false
val that = obj
return (Objects.equals(
rawType,
that.rawType
) && actualTypeArguments.contentEquals(that.actualTypeArguments) && Objects.equals(
ownerType,
that.ownerType
))
}
override fun hashCode(): Int {
return (actualTypeArguments.contentHashCode() xor Objects.hashCode(rawType) xor Objects.hashCode(
ownerType
))
}
}
}
}

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile Loggers.kt
* LastUpdate 2025-09-14 18:19:29
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/

View File

@ -0,0 +1,350 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile AddressPort.kt
* LastUpdate 2025-09-15 22:01:27
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.network
import java.io.Serializable
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.UnknownHostException
import java.util.regex.Pattern
/**
* 网络地址类用于表示一个网络地址IP或域名并提供相关操作
* 支持IPv4和IPv6地址的解析与验证
*
* @author MingLiPro
*/
class NetworkAddress private constructor(domip: String) : Serializable {
/**
* IPv6标识
*/
companion object {
const val IPV6 = 6
/**
* IPv4标识
*/
const val IPV4 = 4
/**
* IPv4地址正则表达式
*/
private const val IPV4REG =
"^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2" + "(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$"
/**
* 编译后的IPv4地址匹配模式
*/
private val IPV4_PATTERN = Pattern.compile(IPV4REG)
/**
* IPv6地址正则表达式
*/
private const val IPV6REG =
"^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|" + "^(::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4})$" + "|" + "^(::)$|" + "^([0-9a-fA-F]{1,4}::([0-9a-fA-F]{1,4}:){0,5}[0-9a-fA-F]{1,4})$|" + "^(([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4})$|" + "^(([0-9a-fA-F]{1,4}:){6}(([0-9]{1,3}\\.){3}[0-9]{1,3}))$|" + "^::([fF]{4}:)?(([0-9]{1,3}\\.){3}[0-9]{1,3})$"
/**
* 编译后的IPv6地址匹配模式
*/
private val IPV6_PATTERN = Pattern.compile(IPV6REG)
/**
* 静态工厂方法创建 NetworkAddress 实例
*
* @param domip 可能是IP地址或域名的字符串
* @return 新建的 NetworkAddress 实例
*/
@JvmStatic
fun of(domip: String): NetworkAddress {
return NetworkAddress(domip)
}
/**
* 静态工厂方法通过 InetAddress 创建 NetworkAddress 实例
*
* @param inetAddress InetAddress 对象
* @return 新建的 NetworkAddress 实例
*/
@JvmStatic
fun of(inetAddress: InetAddress): NetworkAddress {
return NetworkAddress(inetAddress.hostAddress)
}
/**
* 从DNS服务器解析域名获取对应的IP地址
*
* @param domain 域名
* @return 解析出的第一个IP地址
* @throws UnknownHostException 如果域名无法解析
*/
@JvmStatic
@Throws(UnknownHostException::class)
fun getHostIp(domain: String): String {
val addresses = InetAddress.getAllByName(domain.trim())
return addresses[0].hostAddress
}
/**
* 检测给定字符串是否为有效的IPv4或IPv6地址
*
* @param ip 要检测的IP地址字符串
* @return 4 表示IPv46 表示IPv6
* @throws NetworkException 如果IP格式无效
*/
@JvmStatic
fun testIp(ip: String?): Int {
if (ip == null) {
throw NetworkException("IP地址不能为null")
}
val trimmedIp = ip.trim()
// 判断是否匹配IPv4格式
if (IPV4_PATTERN.matcher(trimmedIp).matches()) {
return IPV4
}
// 判断是否匹配IPv6格式
if (IPV6_PATTERN.matcher(trimmedIp).matches()) {
return IPV6
}
// 不符合任一格式时抛出异常
throw NetworkException(
"[$ip] 不是有效的IPv4或IPv6地址"
)
}
}
/**
* IP地址类型4 表示 IPv46 表示 IPv6
*/
var iPv: Int = 0
private set
/**
* IP地址字符串
*/
var ip: String? = null
private set
/**
* 域名如果输入的是域名
*/
private var domain: String? = null
/**
* 标识是否是域名解析来的IP
*/
private var isdom = false
/**
* 构造方法根据传入的字符串判断是IP地址还是域名并进行相应处理
*
* @param domip 可能是IP地址或域名的字符串
*/
init {
try {
// 尝试将输入识别为IP地址
this.iPv = testIp(domip)
this.ip = domip
} catch (e: NetworkException) {
try {
// 如果不是有效IP则尝试作为域名解析
val ips = getHostIp(domip)
this.iPv = testIp(ips)
this.ip = ips
this.isdom = true
this.domain = domip
} catch (ex: UnknownHostException) {
throw NetworkException(ex)
}
}
}
/**
* 将当前 NetworkAddress 转换为 InetAddress 对象
*
* @return InetAddress 对象
*/
fun toInetAddress(): InetAddress {
try {
return InetAddress.getByName(if (ip != null) ip else domain)
} catch (e: UnknownHostException) {
throw RuntimeException(e)
}
}
/**
* 返回 NetworkAddress 的字符串表示形式
*
* @return 字符串表示
*/
override fun toString(): String {
return if (isdom) "NetworkAddress(IP='$ip',type='$iPv',domain='$domain')"
else "NetworkAddress(IP='$ip',type='$iPv')"
}
}
class NetworkPort : Serializable {
val port: Int
constructor(port: Int) {
testPort(port)
this.port = port
}
companion object {
fun testPort(port: Int) {
// 验证端口号范围是否在0-65535之间
if (port !in 0..65535) {
throw NetworkException("$port 不是正确的端口号")
}
}
}
}
class NetworkException : RuntimeException {
/**
* 构造一个带有指定详细消息的网络异常
*
* @param message 异常的详细消息
*/
constructor(message: String?) : super(message)
/**
* 构造一个网络异常指定原因异常
*
* @param e 导致此异常的原因异常
*/
constructor(e: Exception?) : super(e)
}
/**
* IP和端口聚集类用于封装网络地址与端口信息
* 该类提供了与InetSocketAddress之间的相互转换功能
*
* @author MingLiPro
* @see java.net.InetSocketAddress
*/
class NetworkEndpoint private constructor(
val networkAddress: NetworkAddress, val networkPort: NetworkPort
) : Serializable {
companion object {
/**
* 根据给定的InetSocketAddress对象创建NetworkEndpoint实例
*
* @param address InetSocketAddress对象
* @return 新建的NetworkEndpoint实例
* @see java.net.InetSocketAddress
*/
@JvmStatic
fun of(address: InetSocketAddress): NetworkEndpoint {
return NetworkEndpoint(
NetworkAddress.of(address.hostString), NetworkPort(address.port)
)
}
/**
* 根据主机名或IP字符串和端口号创建NetworkEndpoint实例
*
* @param s 主机名或IP地址字符串
* @param i 端口号
* @return 新建的NetworkEndpoint实例
*/
@JvmStatic
fun of(s: String, i: Int): NetworkEndpoint {
val networkAddress = NetworkAddress.of(s)
val networkPort = NetworkPort(i)
return NetworkEndpoint(networkAddress, networkPort)
}
/**
* 根据"host:port"格式的字符串创建NetworkEndpoint实例
* 例如"127.0.0.1:8080"
*
* @param s "host:port"格式的字符串
* @return 新建的NetworkEndpoint实例
*/
@JvmStatic
fun of(s: String): NetworkEndpoint {
val lastColonIndex = s.lastIndexOf(':')
return of(
s.take(lastColonIndex), s.substring(lastColonIndex + 1).toInt()
)
}
}
/**
* 将当前NetworkEndpoint转换为InetSocketAddress对象
*
* @return 对应的InetSocketAddress对象
* @see InetSocketAddress
*/
fun toInetSocketAddress(): InetSocketAddress {
return InetSocketAddress(
networkAddress.toInetAddress(), networkPort.port
)
}
/**
* 将当前NetworkEndpoint转换为"host:port"格式的字符串
* 例如"127.0.0.1:25563"
*
* @return 格式化后的字符串
*/
fun toHostPortString(): String {
return "${networkAddress.ip}:${networkPort.port}"
}
/**
* 返回NetworkEndpoint的详细字符串表示形式
* 格式NetworkEndpoint(IP=...,Port=...,Endpoint=...)
*
* @return 包含详细信息的字符串
*/
override fun toString(): String {
return "NetworkEndpoint(IP=${networkAddress.ip},Port=${networkPort.port},Endpoint=${toHostPortString()})"
}
/**
* 获取主机名或IP地址字符串
*
* @return 主机名或IP地址
*/
fun host(): String {
return networkAddress.ip ?: ""
}
/**
* 获取端口号
*
* @return 端口号
*/
fun port(): Int {
return networkPort.port
}
}

View File

@ -16,13 +16,15 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile RandomBytes.kt
* LastUpdate 2025-09-15 09:54:33
* LastUpdate 2025-09-15 22:27:36
* UpdateUser MingLiPro
*/
@file:JvmName("RandomBytes")
package com.mingliqiye.utils.random
import java.security.SecureRandom
/**
* 生成指定长度的随机字节数组
* @param length 数组长度
@ -78,3 +80,13 @@ fun randomByteNoHave(from: Byte, to: Byte): Byte {
val randomValue = randomIntNoHave(fromInt, toInt)
return (randomValue and 0xFF).toByte()
}
val secureRandom: SecureRandom by lazy {
SecureRandom()
}
fun randomByteSecure(size: Int): ByteArray {
val bytes = ByteArray(size)
secureRandom.nextBytes(bytes)
return bytes
}

View File

@ -1,6 +1,29 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile AesUtils.kt
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/
@file:JvmName("AesUtils")
package com.mingliqiye.utils.security
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
@ -9,8 +32,8 @@ const val AES_GCM_NO_PADDING = "AES/GCM/NoPadding"
const val AES_GCM_NO_PADDING_IV_LENGTH = 12
const val AES_GCM_NO_PADDING_TAG_LENGTH = 16
fun encryptAesGcmNoPadding(src: ByteArray, key: ByteArray,iv: ByteArray): ByteArray {
val secretKeySpec = createSecretKeySpec(ALGORITHM,key)
fun encryptAesGcmNoPadding(src: ByteArray, key: ByteArray, iv: ByteArray): ByteArray {
val secretKeySpec = createSecretKeySpec(ALGORITHM, key)
val cipher = Cipher.getInstance(AES_GCM_NO_PADDING)
val gcmParameterSpec = GCMParameterSpec(
AES_GCM_NO_PADDING_TAG_LENGTH * 8,
@ -19,16 +42,18 @@ fun encryptAesGcmNoPadding(src: ByteArray, key: ByteArray,iv: ByteArray): ByteAr
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmParameterSpec)
return cipher.doFinal(src)
}
fun encryptAesGcmNoPadding(src: ByteArray, key: String,iv: ByteArray): ByteArray {
fun encryptAesGcmNoPadding(src: ByteArray, key: String, iv: ByteArray): ByteArray {
return encryptAesGcmNoPadding(src, key.toByteArray(), iv)
}
fun encryptAesGcmNoPadding(src: String, key: String,iv: ByteArray): ByteArray {
fun encryptAesGcmNoPadding(src: String, key: String, iv: ByteArray): ByteArray {
return encryptAesGcmNoPadding(src.toByteArray(), key.toByteArray(), iv)
}
fun main() {
val iv = getRandomBytes(16)
println(encryptAesGcmNoPadding("mingliqiye","key", iv))
println(encryptAesGcmNoPadding("mingliqiye", "key", iv))
}

View File

@ -1,3 +1,25 @@
/*
* Copyright 2025 mingliqiye
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile SecureUtils.kt
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/
@file:JvmName("SecureUtils")
package com.mingliqiye.utils.security
@ -25,9 +47,9 @@ fun createSecretKey(algorithm: String, data: String): ByteArray {
}
fun createSecretKeySpec(algorithm: String, data: String): SecretKey {
return SecretKeySpec( createSecretKey(algorithm,data), algorithm)
return SecretKeySpec(createSecretKey(algorithm, data), algorithm)
}
fun createSecretKeySpec(algorithm: String, data: ByteArray): SecretKey {
return SecretKeySpec( createSecretKey(algorithm,data), algorithm)
}
return SecretKeySpec(createSecretKey(algorithm, data), algorithm)
}

View File

@ -16,14 +16,17 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile AutoConfiguration.kt
* LastUpdate 2025-09-15 08:51:52
* LastUpdate 2025-09-15 22:20:25
* UpdateUser MingLiPro
*/
package com.mingliqiye.utils.springboot.autoconfigure
import com.mingliqiye.utils.logger.mingLiLoggerFactory
import com.mingliqiye.utils.system.getJdkVersion
import com.mingliqiye.utils.system.computerName
import com.mingliqiye.utils.system.getPid
import com.mingliqiye.utils.system.jdkVersion
import com.mingliqiye.utils.system.userName
import com.mingliqiye.utils.time.DateTime
import com.mingliqiye.utils.time.Formatter
import org.springframework.context.annotation.ComponentScan
@ -63,8 +66,11 @@ open class AutoConfiguration {
metaData.append(String(buffer, 0, readlen))
}
val da = metaData.toString().split("\n").toMutableList()
da.add("time=" + DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7))
da.add("jdkRuntime=" + getJdkVersion())
da.add("jdkRuntime=$jdkVersion")
da.add("pid=$getPid")
da.add("computerName=$computerName")
da.add("userName=$userName")
da.add("time=" + DateTime.now().format(Formatter.STANDARD_DATETIME_MILLISECOUND7, true))
da.forEach { s: String ->
val d = s.trim { it <= ' ' }.split("=".toRegex(), 2).toTypedArray()
if (d.size >= 2) {

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile StringUtils.kt
* LastUpdate 2025-09-14 21:46:14
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/
@file:JvmName("StringUtils")

View File

@ -16,26 +16,33 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile SystemUtil.kt
* LastUpdate 2025-09-15 11:18:34
* LastUpdate 2025-09-15 22:19:57
* UpdateUser MingLiPro
*/
@file:JvmName("SystemUtils")
package com.mingliqiye.utils.system
import java.lang.management.ManagementFactory
import java.net.Inet4Address
import java.net.InetAddress
import java.net.NetworkInterface
import java.net.SocketException
private val osName: String? = System.getProperties().getProperty("os.name")
/**
* 操作系统名称属性延迟初始化
*/
val osName: String? by lazy {
System.getProperties().getProperty("os.name")
}
/**
* 判断当前操作系统是否为Windows系统
*
* @return 如果是Windows系统返回true否则返回false
*/
fun isWindows(): Boolean {
return osName != null && osName.startsWith("Windows")
val isWindows: Boolean by lazy {
osName != null && osName!!.startsWith("Windows")
}
/**
@ -43,8 +50,8 @@ fun isWindows(): Boolean {
*
* @return 如果是Mac系统返回true否则返回false
*/
fun isMac(): Boolean {
return osName != null && osName.startsWith("Mac")
val isMac: Boolean by lazy {
osName != null && osName!!.startsWith("Mac")
}
/**
@ -52,31 +59,30 @@ fun isMac(): Boolean {
*
* @return 如果是Unix/Linux系统返回true否则返回false
*/
fun isUnix(): Boolean {
val isUnix: Boolean by lazy {
if (osName == null) {
return false
false
} else {
(osName!!.startsWith("Linux") || osName!!.startsWith("AIX") || osName!!.startsWith("SunOS") || osName!!.startsWith(
"Mac OS X"
) || osName!!.startsWith(
"FreeBSD"
))
}
return (osName.startsWith("Linux") || osName.startsWith("AIX") || osName.startsWith("SunOS") || osName.startsWith("Mac OS X") || osName.startsWith(
"FreeBSD"
))
}
/**
* 获取JDK版本号
*
* @return JDK版本号字符串
* JDK版本号属性延迟初始化
*/
fun getJdkVersion(): String? {
return System.getProperty("java.specification.version")
val jdkVersion: String? by lazy {
System.getProperty("java.specification.version")
}
/**
* 获取Java版本号的整数形式
*
* @return Java版本号的整数形式81117
* Java版本号的整数形式属性延迟初始化
*/
fun getJavaVersionAsInteger(): Int {
val version = getJdkVersion()
val javaVersionAsInteger: Int by lazy {
val version = jdkVersion
if (version == null || version.isEmpty()) {
throw IllegalStateException(
"Unable to determine Java version from property 'java.specification.version'"
@ -98,7 +104,7 @@ fun getJavaVersionAsInteger(): Int {
}
version.take(2)
}
return uversion.toInt()
uversion.toInt()
}
/**
@ -106,18 +112,17 @@ fun getJavaVersionAsInteger(): Int {
*
* @return 如果JDK版本大于8返回true否则返回false
*/
fun isJdk8Plus(): Boolean {
return getJavaVersionAsInteger() > 8
val isJdk8Plus: Boolean by lazy {
javaVersionAsInteger > 8
}
/**
* 获取本地IP地址数组
* 本地IP地址数组延迟初始化
*
* @return 本地IP地址字符串数组
* @throws RuntimeException 当获取网络接口信息失败时抛出
*/
fun getLocalIps(): Array<String> {
return try {
val localIps: Array<String> by lazy {
try {
val ipList: MutableList<String> = ArrayList()
val interfaces = NetworkInterface.getNetworkInterfaces()
@ -145,22 +150,18 @@ fun getLocalIps(): Array<String> {
}
/**
* 获取本地IP地址列表
*
* @return 本地IP地址的字符串列表
* 本地IP地址列表延迟初始化
*/
fun getLocalIpsByList(): List<String> {
return getLocalIps().toList()
val localIpsByList: List<String> by lazy {
localIps.toList()
}
/**
* 获取本地回环地址
*
* @return 回环地址字符串通常为"127.0.0.1"
* 本地回环地址数组延迟初始化
*/
fun getLoopbackIps(): Array<String> {
val loopbackIps: Array<String> by lazy {
val strings: MutableList<String> = ArrayList(3)
return try {
return@lazy try {
val interfaces = NetworkInterface.getNetworkInterfaces()
while (interfaces.hasMoreElements()) {
@ -183,11 +184,92 @@ fun getLoopbackIps(): Array<String> {
}
/**
* 获取本地回环地址IP列表
*
* @return 本地回环地址IP字符串列表的副本
* 本地回环地址IP列表延迟初始化
*/
fun getLoopbackIpsByList(): List<String> {
// 将本地回环地址IP数组转换为列表并返回
return getLoopbackIps().toList()
val loopbackIpsByList: List<String> by lazy {
loopbackIps.toList()
}
/**
* 获取当前进程的PID
*
* @return 进程ID如果无法获取则返回-1
*/
val getPid: Long by lazy {
try {
val name = ManagementFactory.getRuntimeMXBean().name
val index = name.indexOf('@')
if (index > 0) {
name.take(index).toLong()
} else {
-1L
}
} catch (e: Exception) {
-1L
}
}
/**
* 获取当前进程的PID字符串形式
*
* @return 进程ID字符串如果无法获取则返回"-1"
*/
val pidAsString: String by lazy {
try {
val name = ManagementFactory.getRuntimeMXBean().name
val index = name.indexOf('@')
if (index > 0) {
name.take(index)
} else {
"-1"
}
} catch (e: Exception) {
"-1"
}
}
/**
* 获取计算机名
*
* @return 计算机名如果无法获取则返回"unknown"
*/
val computerName: String by lazy {
try {
var name = System.getenv("COMPUTERNAME")
if (name.isNullOrBlank()) {
name = System.getenv("HOSTNAME")
}
if (name.isNullOrBlank()) {
name = InetAddress.getLocalHost().hostName
}
name ?: "unknown"
} catch (e: Exception) {
"unknown"
}
}
/**
* 获取当前用户名
*
* @return 当前用户名如果无法获取则返回"unknown"
*/
val userName: String by lazy {
try {
getEnvVar("USERNAME")
?: getEnvVar("USER")
?: System.getProperty("user.name")
?: "unknown"
} catch (e: SecurityException) {
"unknown"
} catch (e: Exception) {
"unknown"
}
}
private fun getEnvVar(name: String): String? {
return try {
System.getenv(name)?.takeIf { it.isNotBlank() }
} catch (e: SecurityException) {
null
}
}

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile DateTime.kt
* LastUpdate 2025-09-15 09:57:50
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/
@ -27,8 +27,8 @@ import com.mingliqiye.utils.jna.NANOS_PER_100NS
import com.mingliqiye.utils.jna.WinKernel32Api
import com.mingliqiye.utils.jna.getWinKernel32Apis
import com.mingliqiye.utils.logger.mingLiLoggerFactory
import com.mingliqiye.utils.system.getJavaVersionAsInteger
import com.mingliqiye.utils.system.isWindows
import com.mingliqiye.utils.system.javaVersionAsInteger
import org.slf4j.Logger
import java.io.Serializable
import java.time.LocalDateTime
@ -185,8 +185,8 @@ class DateTime private constructor(
companion object {
private val WIN_KERNEL_32_API: WinKernel32Api? = if (
getJavaVersionAsInteger() == 8 &&
isWindows()
javaVersionAsInteger == 8 &&
isWindows
) {
val log: Logger = mingLiLoggerFactory.getLogger("mingli-utils DateTime")
val a = getWinKernel32Apis()

View File

@ -16,7 +16,7 @@
* ProjectName mingli-utils
* ModuleName mingli-utils.main
* CurrentFile MysqlUUIDv1.kt
* LastUpdate 2025-09-14 18:19:29
* LastUpdate 2025-09-15 22:32:50
* UpdateUser MingLiPro
*/
@file:JvmName("MysqlUUIDv1")

View File

@ -16,7 +16,7 @@
# ProjectName mingli-utils
# ModuleName mingli-utils.main
# CurrentFile org.springframework.boot.autoconfigure.AutoConfiguration.imports
# LastUpdate 2025-09-09 08:37:33
# LastUpdate 2025-09-15 22:32:50
# UpdateUser MingLiPro
#