generated from mingliqiye/lib-tem
feat(network): 添加网络地址和端口相关工具类
- 新增 NetworkAddress 类用于表示网络地址,支持 IPv4 和 IPv6 - 新增 NetworkPort 类用于表示端口号 - 新增 NetworkEndpoint 类用于封装网络地址和端口信息 - 优化 AutoConfiguration 类,添加更多系统信息 - 更新 AesUtils、Base64Utils等类的版本信息 - 删除 Minecraft SLF 相关无用代码 - 更新项目版本号至 4.0.7
This commit is contained in:
parent
7c3c13e28c
commit
541a8a82b4
@ -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"
|
||||
)
|
||||
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -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
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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
2
gradlew
vendored
@ -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
|
||||
#
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -1 +0,0 @@
|
||||
lombok.addLombokGeneratedAnnotation = false
|
@ -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
|
||||
*/
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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字符串解析为复杂泛型结构的对象(如List、Map等)
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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 库(Jackson、Gson、Fastjson 等)
|
||||
*
|
||||
* @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());
|
||||
}
|
||||
}
|
@ -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())
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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 值截断为无符号 short(2 字节)并按大端序写入字节数组。
|
||||
*
|
||||
* @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); // 读取并解析服务器响应
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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 表示 IPv4,6 表示 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 表示IPv4,6 表示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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -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())
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
*/
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
|
||||
|
231
src/main/kotlin/com/mingliqiye/utils/json/GsonJsonApi.kt
Normal file
231
src/main/kotlin/com/mingliqiye/utils/json/GsonJsonApi.kt
Normal 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)
|
||||
}
|
||||
}
|
301
src/main/kotlin/com/mingliqiye/utils/json/JacksonJsonApi.kt
Normal file
301
src/main/kotlin/com/mingliqiye/utils/json/JacksonJsonApi.kt
Normal 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字符串解析为复杂泛型结构的对象(如List、Map等)
|
||||
*
|
||||
* @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)
|
||||
}
|
||||
}
|
@ -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字符串中指定路径节点的值
|
||||
|
@ -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)
|
||||
}
|
164
src/main/kotlin/com/mingliqiye/utils/json/JsonTypeReference.kt
Normal file
164
src/main/kotlin/com/mingliqiye/utils/json/JsonTypeReference.kt
Normal 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 库(Jackson、Gson、Fastjson 等)
|
||||
*
|
||||
* @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())
|
||||
}
|
||||
}
|
201
src/main/kotlin/com/mingliqiye/utils/json/JsonTypeUtils.kt
Normal file
201
src/main/kotlin/com/mingliqiye/utils/json/JsonTypeUtils.kt
Normal 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
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
*/
|
||||
|
||||
|
350
src/main/kotlin/com/mingliqiye/utils/network/AddressPort.kt
Normal file
350
src/main/kotlin/com/mingliqiye/utils/network/AddressPort.kt
Normal 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 表示IPv4,6 表示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 表示 IPv4,6 表示 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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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")
|
||||
|
@ -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版本号的整数形式(如:8、11、17等)
|
||||
* 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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
#
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user