[*] 日常优化

This commit is contained in:
acgist
2023-07-17 08:48:57 +08:00
parent b5a2ad06b4
commit 9f6fdd564d
14 changed files with 563 additions and 487 deletions

View File

@@ -134,7 +134,7 @@ const defaultRTCPeerConnectionConfig = {
// ICE代理服务器 // ICE代理服务器
iceServers : [ iceServers : [
{ {
// { "url": "stun:stun1.l.google.com:19302" }, // { "urls": "stun:stun1.l.google.com:19302" },
urls: [ urls: [
"stun:stun1.l.google.com:19302", "stun:stun1.l.google.com:19302",
"stun:stun2.l.google.com:19302", "stun:stun2.l.google.com:19302",

View File

@@ -12,37 +12,37 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public final class CloseableUtils { public final class CloseableUtils {
private CloseableUtils() { private CloseableUtils() {
} }
/** /**
* 关闭资源 * 关闭资源
* *
* @param closeable 资源 * @param closeable 资源
*/ */
public static final void close(Closeable closeable) { public static final void close(Closeable closeable) {
try { try {
if(closeable != null) { if(closeable != null) {
closeable.close(); closeable.close();
} }
} catch (Exception e) { } catch (Exception e) {
log.error("关闭资源异常", e); log.error("关闭资源异常", e);
} }
} }
/** /**
* 关闭资源 * 关闭资源
* *
* @param closeable 资源 * @param closeable 资源
*/ */
public static final void close(AutoCloseable closeable) { public static final void close(AutoCloseable closeable) {
try { try {
if(closeable != null) { if(closeable != null) {
closeable.close(); closeable.close();
} }
} catch (Exception e) { } catch (Exception e) {
log.error("关闭资源异常", e); log.error("关闭资源异常", e);
} }
} }
} }

View File

@@ -43,7 +43,7 @@ public final class DateUtils {
private final DateTimeFormatter dateTimeFormatter; private final DateTimeFormatter dateTimeFormatter;
private DateStyle(String format) { private DateStyle(String format) {
this.format = format; this.format = format;
this.dateTimeFormatter = DateTimeFormatter.ofPattern(format); this.dateTimeFormatter = DateTimeFormatter.ofPattern(format);
} }
@@ -75,7 +75,7 @@ public final class DateUtils {
private final DateTimeFormatter dateTimeFormatter; private final DateTimeFormatter dateTimeFormatter;
private TimeStyle(String format) { private TimeStyle(String format) {
this.format = format; this.format = format;
this.dateTimeFormatter = DateTimeFormatter.ofPattern(format); this.dateTimeFormatter = DateTimeFormatter.ofPattern(format);
} }
@@ -128,7 +128,7 @@ public final class DateUtils {
private final DateTimeFormatter dateTimeFormatter; private final DateTimeFormatter dateTimeFormatter;
private DateTimeStyle(String format) { private DateTimeStyle(String format) {
this.format = format; this.format = format;
this.dateTimeFormatter = DateTimeFormatter.ofPattern(format); this.dateTimeFormatter = DateTimeFormatter.ofPattern(format);
} }

View File

@@ -29,251 +29,251 @@ import lombok.extern.slf4j.Slf4j;
*/ */
@Slf4j @Slf4j
public final class ErrorUtils { public final class ErrorUtils {
private ErrorUtils() { private ErrorUtils() {
} }
/** /**
* 异常映射 * 异常映射
*/ */
private static final Map<Class<?>, MessageCode> CODE_MAPPING = new LinkedHashMap<>(); private static final Map<Class<?>, MessageCode> CODE_MAPPING = new LinkedHashMap<>();
/** /**
* 错误地址 * 错误地址
*/ */
public static final String ERROR_PATH = "/error"; public static final String ERROR_PATH = "/error";
/** /**
* Servlet错误编码 * Servlet错误编码
*/ */
public static final String SERVLET_STATUS_CODE = "javax.servlet.error.status_code"; public static final String SERVLET_STATUS_CODE = "javax.servlet.error.status_code";
/** /**
* Servlet错误地址 * Servlet错误地址
*/ */
public static final String SERVLET_REQUEST_URI = "javax.servlet.error.request_uri"; public static final String SERVLET_REQUEST_URI = "javax.servlet.error.request_uri";
/** /**
* Servlet错误异常 * Servlet错误异常
*/ */
public static final String EXCEPTION_SERVLET = "javax.servlet.error.exception"; public static final String EXCEPTION_SERVLET = "javax.servlet.error.exception";
/** /**
* SpringBoot异常 * SpringBoot异常
*/ */
public static final String EXCEPTION_SPRINGBOOT = "org.springframework.boot.web.servlet.error.DefaultErrorAttributes.ERROR"; public static final String EXCEPTION_SPRINGBOOT = "org.springframework.boot.web.servlet.error.DefaultErrorAttributes.ERROR";
/** /**
* 注册异常(注意继承顺序) * 注册异常(注意继承顺序)
* *
* @param messageCode 状态编码 * @param messageCode 状态编码
* @param clazz 异常类型 * @param clazz 异常类型
*/ */
public static final void register(MessageCode messageCode, Class<?> clazz) { public static final void register(MessageCode messageCode, Class<?> clazz) {
log.debug("注册状态编码异常映射:{} - {}", messageCode, clazz); log.debug("注册状态编码异常映射:{} - {}", messageCode, clazz);
synchronized (CODE_MAPPING) { synchronized (CODE_MAPPING) {
CODE_MAPPING.put(clazz, messageCode); CODE_MAPPING.put(clazz, messageCode);
} }
} }
/** /**
* @param request 请求 * @param request 请求
* @param response 响应 * @param response 响应
* *
* @return 错误消息 * @return 错误消息
*/ */
public static final Message message(HttpServletRequest request, HttpServletResponse response) { public static final Message message(HttpServletRequest request, HttpServletResponse response) {
return ErrorUtils.message(null, request, response); return ErrorUtils.message(null, request, response);
} }
/** /**
* @param t 异常 * @param t 异常
* @param request 请求 * @param request 请求
* @param response 响应 * @param response 响应
* *
* @return 错误消息 * @return 错误消息
*/ */
public static final Message message(Throwable t, HttpServletRequest request, HttpServletResponse response) { public static final Message message(Throwable t, HttpServletRequest request, HttpServletResponse response) {
final Message message; final Message message;
// 错误状态编码 // 状态编码
int status = ErrorUtils.globalStatus(request, response); int status = ErrorUtils.globalStatus(request, response);
// 全局异常 // 全局异常
final Object globalError = t == null ? ErrorUtils.globalError(request) : t; final Object globalError = t == null ? ErrorUtils.globalError(request) : t;
// 原始异常 // 原始异常
final Object rootError = ErrorUtils.rootException(globalError); final Object rootError = ErrorUtils.rootException(globalError);
if(rootError instanceof MessageCodeException messageCodeException) { if(rootError instanceof MessageCodeException messageCodeException) {
// 状态编码异常 // 状态编码异常
final MessageCode messageCode = messageCodeException.getMessageCode(); final MessageCode messageCode = messageCodeException.getMessageCode();
status = messageCode.getStatus(); status = messageCode.getStatus();
message = Message.fail(messageCode, messageCodeException.getMessage()); message = Message.fail(messageCode, messageCodeException.getMessage());
} else if(rootError instanceof Throwable throwable) { } else if(rootError instanceof Throwable throwable) {
// 未知异常:异常转换 // 未知异常:异常转换
final MessageCode messageCode = ErrorUtils.messageCode(status, throwable); final MessageCode messageCode = ErrorUtils.messageCode(status, throwable);
status = messageCode.getStatus(); status = messageCode.getStatus();
message = Message.fail(messageCode, ErrorUtils.message(messageCode, throwable)); message = Message.fail(messageCode, ErrorUtils.message(messageCode, throwable));
} else { } else {
// 没有异常 // 没有异常
final MessageCode messageCode = MessageCode.of(status); final MessageCode messageCode = MessageCode.of(status);
message = Message.fail(messageCode); message = Message.fail(messageCode);
} }
// 状态编码 // 状态编码
if(status == HttpServletResponse.SC_OK) { if(status == HttpServletResponse.SC_OK) {
status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR; status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
} }
response.setStatus(status); response.setStatus(status);
// 请求地址 // 请求地址
final String path = ErrorUtils.getFirstParams( final String path = ErrorUtils.getFirstParams(
request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI), request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI),
request.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH), request.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH),
request.getAttribute(SERVLET_REQUEST_URI), request.getAttribute(SERVLET_REQUEST_URI),
request.getServletPath() request.getServletPath()
); );
// 请求参数 // 请求参数
final String query = ErrorUtils.getFirstParams( final String query = ErrorUtils.getFirstParams(
request.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING), request.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING),
request.getQueryString() request.getQueryString()
); );
// 请求方法 // 请求方法
final String method = request.getMethod(); final String method = request.getMethod();
if(globalError instanceof Throwable) { if(globalError instanceof Throwable) {
log.error(""" log.error("""
请求异常 请求异常
请求地址:{} 请求地址:{}
请求参数:{} 请求参数:{}
请求方法:{} 请求方法:{}
错误信息:{} 错误信息:{}
响应状态:{} 响应状态:{}
""", path, query, method, message, status, globalError); """, path, query, method, message, status, globalError);
} else { } else {
log.warn(""" log.warn("""
请求错误 请求错误
请求地址:{} 请求地址:{}
请求参数:{} 请求参数:{}
请求方法:{} 请求方法:{}
错误信息:{} 错误信息:{}
响应状态:{} 响应状态:{}
原始信息:{} 原始信息:{}
""", path, query, method, message, status, globalError); """, path, query, method, message, status, globalError);
} }
final Map<String, String> body = new HashMap<>(); final Map<String, String> body = new HashMap<>();
body.put("path", path); body.put("path", path);
body.put("query", query); body.put("query", query);
body.put("method", method); body.put("method", method);
message.setBody(body); message.setBody(body);
return message; return message;
} }
/** /**
* @param request 请求 * @param request 请求
* @param response 响应 * @param response 响应
* *
* @return 状态编码 * @return 状态编码
*/ */
public static final int globalStatus(HttpServletRequest request, HttpServletResponse response) { public static final int globalStatus(HttpServletRequest request, HttpServletResponse response) {
final Object status = request.getAttribute(SERVLET_STATUS_CODE); final Object status = request.getAttribute(SERVLET_STATUS_CODE);
if(status instanceof Integer) { if(status instanceof Integer) {
return (Integer) status; return (Integer) status;
} }
return response.getStatus(); return response.getStatus();
} }
/** /**
* @param request 请求 * @param request 请求
* *
* @return 异常 * @return 异常
*/ */
public static final Object globalError(HttpServletRequest request) { public static final Object globalError(HttpServletRequest request) {
// Servlet错误异常 // Servlet错误异常
Object throwable = request.getAttribute(EXCEPTION_SERVLET); Object throwable = request.getAttribute(EXCEPTION_SERVLET);
if(throwable != null) { if(throwable != null) {
return throwable; return throwable;
} }
// SpringBoot异常 // SpringBoot异常
throwable = request.getAttribute(EXCEPTION_SPRINGBOOT); throwable = request.getAttribute(EXCEPTION_SPRINGBOOT);
if(throwable != null) { if(throwable != null) {
return throwable; return throwable;
} }
return throwable; return throwable;
} }
/** /**
* @param status 原始状态编码 * @param status 原始状态编码
* @param throwable 异常 * @param throwable 异常
* *
* @return 状态编码 * @return 状态编码
* *
* @see ResponseEntityExceptionHandler * @see ResponseEntityExceptionHandler
* @see DefaultHandlerExceptionResolver * @see DefaultHandlerExceptionResolver
*/ */
public static final MessageCode messageCode(int status, Throwable throwable) { public static final MessageCode messageCode(int status, Throwable throwable) {
final Class<?> clazz = throwable.getClass(); final Class<?> clazz = throwable.getClass();
return CODE_MAPPING.entrySet().stream() return CODE_MAPPING.entrySet().stream()
.filter(entry -> { .filter(entry -> {
final Class<?> mappingClazz = entry.getKey(); final Class<?> mappingClazz = entry.getKey();
return mappingClazz.equals(clazz) || mappingClazz.isAssignableFrom(clazz); return mappingClazz.equals(clazz) || mappingClazz.isAssignableFrom(clazz);
}) })
.map(Map.Entry::getValue) .map(Map.Entry::getValue)
.findFirst() .findFirst()
.orElse(MessageCode.of(status)); .orElse(MessageCode.of(status));
} }
/** /**
* @param messageCode 状态编码 * @param messageCode 状态编码
* @param throwable 异常 * @param throwable 异常
* *
* @return 异常信息 * @return 异常信息
*/ */
public static final String message(MessageCode messageCode, Throwable throwable) { public static final String message(MessageCode messageCode, Throwable throwable) {
if(throwable instanceof BindException bindException) { if(throwable instanceof BindException bindException) {
return bindException.getAllErrors().stream() return bindException.getAllErrors().stream()
.map(ObjectError::getDefaultMessage) .map(ObjectError::getDefaultMessage)
.collect(Collectors.joining(" && ")); .collect(Collectors.joining(" && "));
} }
if(throwable instanceof ConstraintViolationException violationException) { if(throwable instanceof ConstraintViolationException violationException) {
return violationException.getConstraintViolations().stream() return violationException.getConstraintViolations().stream()
.map(ConstraintViolation::getMessage) .map(ConstraintViolation::getMessage)
.collect(Collectors.joining(" && ")); .collect(Collectors.joining(" && "));
} }
final String message = throwable.getMessage(); final String message = throwable.getMessage();
// 不是未知系统异常 // 自定义的系统异常
if(StringUtils.isNotEmpty(message) && messageCode != MessageCode.CODE_9999) { if(StringUtils.isNotEmpty(message) && messageCode != MessageCode.CODE_9999) {
return message; return message;
} }
// 少量信息返回异常信息 // 少量信息直接返回
if(StringUtils.isNotEmpty(message) && message.length() <= Byte.MAX_VALUE) { if(StringUtils.isNotEmpty(message) && message.length() <= Byte.MAX_VALUE) {
return message; return message;
} }
// 其他情况不能直接返回异常信息 // 其他情况不能直接返回异常信息
return messageCode.getMessage(); return messageCode.getMessage();
} }
/** /**
* @param t 异常 * @param t 异常
* *
* @return 原始异常 * @return 原始异常
* *
* @see #rootException(Throwable) * @see #rootException(Throwable)
*/ */
public static final Object rootException(Object t) { public static final Object rootException(Object t) {
if(t instanceof Throwable throwable) { if(t instanceof Throwable throwable) {
return ErrorUtils.rootException(throwable); return ErrorUtils.rootException(throwable);
} }
return t; return t;
} }
/** /**
* @param t 异常 * @param t 异常
* *
* @return 原始异常 * @return 原始异常
*/ */
public static final Throwable rootException(Throwable t) { public static final Throwable rootException(Throwable t) {
Throwable cause = t; Throwable cause = t;
do { do {
// 直接返回状态编码异常 // 直接返回状态编码异常
if(cause instanceof MessageCodeException) { if(cause instanceof MessageCodeException) {
return cause; return cause;
} }
} while(cause != null && (cause = cause.getCause()) != null); } while(cause != null && (cause = cause.getCause()) != null);
// 返回原始异常 // 返回原始异常
return t; return t;
} }
/** /**
* @param params 参数列表 * @param params 参数列表
* *
@@ -287,5 +287,5 @@ public final class ErrorUtils {
} }
return null; return null;
} }
} }

View File

@@ -3,6 +3,7 @@ package com.acgist.taoyao.boot.utils;
import java.io.File; import java.io.File;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.nio.file.Paths;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
@@ -13,49 +14,49 @@ import org.apache.commons.lang3.ArrayUtils;
*/ */
public final class FileUtils { public final class FileUtils {
private FileUtils() { private FileUtils() {
} }
/** /**
* 数据进制 * 数据进制
*/ */
private static final int SCALE = 1024; private static final int SCALE = 1024;
/** /**
* 文件大小单位 * 文件大小单位
*/ */
private static final String[] UNITS = {"B", "KB", "MB", "GB", "TB", "PB"}; private static final String[] UNITS = { "B", "KB", "MB", "GB", "TB", "PB" };
/** /**
* @param size 文件大小 * @param size 文件大小
* *
* @return 文件大小 * @return 文件大小
*/ */
public static final String formatSize(Long size) { public static final String formatSize(Long size) {
return formatSize(size, "B"); return FileUtils.formatSize(size, "B");
} }
/** /**
* @param size 文件大小 * @param size 文件大小
* @param unit 当前单位 * @param unit 当前单位
* *
* @return 文件大小 * @return 文件大小
*/ */
public static final String formatSize(Long size, String unit) { public static final String formatSize(Long size, String unit) {
if(size == null || size <= 0L) { if(size == null || size <= 0L) {
return "0B"; return "0B";
} }
int index = ArrayUtils.indexOf(UNITS, unit); int index = ArrayUtils.indexOf(UNITS, unit);
double value = size; double value = size;
while(value >= SCALE) { while(value >= SCALE) {
if(++index >= UNITS.length) { if(++index >= UNITS.length) {
index = UNITS.length - 1; index = UNITS.length - 1;
break; break;
} }
value /= SCALE; value /= SCALE;
} }
return BigDecimal.valueOf(value).setScale(2, RoundingMode.HALF_EVEN) + UNITS[index]; return BigDecimal.valueOf(value).setScale(2, RoundingMode.HALF_EVEN) + UNITS[index];
} }
/** /**
* @return 是否Linux平台 * @return 是否Linux平台
*/ */
@@ -66,7 +67,7 @@ public final class FileUtils {
/** /**
* 创建目录 * 创建目录
* *
* @param path * @param path 目录
*/ */
public static final void mkdirs(String path) { public static final void mkdirs(String path) {
final File file = new File(path); final File file = new File(path);
@@ -75,5 +76,14 @@ public final class FileUtils {
} }
file.mkdirs(); file.mkdirs();
} }
/**
* 创建上级目录
*
* @param path 目录
*/
public static final void mkdirsParent(String path) {
FileUtils.mkdirs(Paths.get(path).getParent().toFile().getAbsolutePath());
}
} }

View File

@@ -38,13 +38,15 @@ public final class HTTPUtils {
/** /**
* 无效IP验证 * 无效IP验证
*/ */
private static final Function<String, Boolean> NEXT_IP = ip -> StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip); private static final Function<String, Boolean> NEXT_IP
=
ip -> StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip);
private HTTPUtils() { private HTTPUtils() {
} }
/** /**
* @param timeout 超时时间 * @param timeout 超时时间
* @param executor 线程池 * @param executor 线程池
*/ */
public static final void init(long timeout, Executor executor) { public static final void init(long timeout, Executor executor) {
@@ -71,7 +73,7 @@ public final class HTTPUtils {
* *
* @return IP地址 * @return IP地址
*/ */
public static final String httpIp(HttpServletRequest request) { public static final String clientIP(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For"); String ip = request.getHeader("X-Forwarded-For");
if (NEXT_IP.apply(ip)) { if (NEXT_IP.apply(ip)) {
ip = request.getHeader("X-Real-IP"); ip = request.getHeader("X-Real-IP");
@@ -91,7 +93,9 @@ public final class HTTPUtils {
final SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init( sslContext.init(
new KeyManager[0], new KeyManager[0],
new X509TrustManager[] { TaoyaoTrustManager.INSTANCE }, new X509TrustManager[] {
TaoyaoTrustManager.INSTANCE
},
new SecureRandom() new SecureRandom()
); );
return sslContext; return sslContext;
@@ -105,7 +109,7 @@ public final class HTTPUtils {
} }
return null; return null;
} }
/** /**
* 证书验证 * 证书验证
* *

View File

@@ -140,7 +140,30 @@ public final class JSONUtils {
throw MessageCodeException.of(e, "JSON转Map失败" + json); throw MessageCodeException.of(e, "JSON转Map失败" + json);
} }
} }
/**
* JSON转Map
*
* @param <K> K类型
* @param <V> V类型
* @param json JSON
* @param kClazz Java类型
* @param vClass Java类型
*
* @return Map
*/
public static final <K, V> Map<K, V> toMap(String json, Class<K> kClazz, Class<V> vClass) {
if (Objects.isNull(json)) {
return Map.of();
}
try {
return MAPPER.readValue(json, new TypeReference<Map<K, V>>() {
});
} catch (IOException e) {
throw MessageCodeException.of(e, "JSON转Map失败" + json);
}
}
/** /**
* JSON转List * JSON转List
* *
@@ -202,7 +225,7 @@ public final class JSONUtils {
private static final Module buildCustomModule() { private static final Module buildCustomModule() {
final SimpleModule customModule = new SimpleModule("CustomModule"); final SimpleModule customModule = new SimpleModule("CustomModule");
// 注意不能转换Long类型数据请求数据类型变化 // 注意不能转换Long类型数据请求数据类型变化
// customModule.addSerializer(Long.class, ToStringSerializer.instance); // customModule.addSerializer(Long.class, ToStringSerializer.instance);
return customModule; return customModule;
} }

View File

@@ -28,11 +28,11 @@ public final class NetUtils {
/** /**
* 本机IP * 本机IP
*/ */
private static String localIp; private static String localIP;
/** /**
* 环回IP * 环回IP
*/ */
private static String loopbackIp; private static String loopbackIP;
/** /**
* 地址重写 * 地址重写
*/ */
@@ -43,13 +43,13 @@ public final class NetUtils {
*/ */
public static final void init(RewriteProperties rewriteProperties) { public static final void init(RewriteProperties rewriteProperties) {
try { try {
NetUtils.rewriteProperties = rewriteProperties; NetUtils.rewriteProperties = rewriteProperties;
final InetAddress localHost = InetAddress.getLocalHost(); final InetAddress localHost = InetAddress.getLocalHost();
final InetAddress loopbackAddress = InetAddress.getLoopbackAddress(); final InetAddress loopbackAddress = InetAddress.getLoopbackAddress();
NetUtils.localIp = localHost.getHostAddress(); NetUtils.localIP = localHost.getHostAddress();
NetUtils.loopbackIp = loopbackAddress.getHostAddress(); NetUtils.loopbackIP = loopbackAddress.getHostAddress();
log.info("本机IP{}", NetUtils.localIp); log.info("本机IP{}", NetUtils.localIP);
log.info("环回IP{}", NetUtils.loopbackIp); log.info("环回IP{}", NetUtils.loopbackIP);
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
log.error("加载网络配置异常", e); log.error("加载网络配置异常", e);
} }
@@ -58,29 +58,29 @@ public final class NetUtils {
/** /**
* @return 本机IP * @return 本机IP
*/ */
public static final String localIp() { public static final String localIP() {
return NetUtils.localIp; return NetUtils.localIP;
} }
/** /**
* @return 环回IP * @return 环回IP
*/ */
public static final String loopbackIp() { public static final String loopbackIP() {
return NetUtils.loopbackIp; return NetUtils.loopbackIP;
} }
/** /**
* 内网是否相同网段 * 内网是否相同网段
* *
* @param sourceIp 原始IP * @param sourceIP 原始IP
* @param clientIp 终端IP * @param clientIP 终端IP
* *
* @return 是否匹配 * @return 是否匹配
*/ */
public static final boolean subnetIp(final String sourceIp, final String clientIp) { public static final boolean subnetIP(final String sourceIP, final String clientIP) {
try { try {
final InetAddress sourceAddress = NetUtils.realAddress(sourceIp); final InetAddress sourceAddress = NetUtils.realAddress(sourceIP);
final InetAddress clientAddress = NetUtils.realAddress(clientIp); final InetAddress clientAddress = NetUtils.realAddress(clientIP);
final boolean sourceLocal = NetUtils.localAddress(sourceAddress); final boolean sourceLocal = NetUtils.localAddress(sourceAddress);
final boolean clientLocal = NetUtils.localAddress(clientAddress); final boolean clientLocal = NetUtils.localAddress(clientAddress);
if(sourceLocal && clientLocal) { if(sourceLocal && clientLocal) {
@@ -96,37 +96,38 @@ public final class NetUtils {
return source.equals(client); return source.equals(client);
} }
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
log.error("IP地址转换异常{}-{}", sourceIp, clientIp, e); log.error("IP地址转换异常{} - {}", sourceIP, clientIP, e);
} }
return true; return false;
} }
/** /**
* 重写地址 * 重写地址
* *
* @param sourceIp 原始IP * @param sourceIP 原始IP
* @param clientIp 终端IP * @param clientIP 终端IP
* *
* @return 替换IP * @return 重写IP
*/ */
public static final String rewriteIp(final String sourceIp, final String clientIp) { public static final String rewriteIP(final String sourceIP, final String clientIP) {
if(Boolean.FALSE.equals(NetUtils.rewriteProperties.getEnabled())) { if(Boolean.FALSE.equals(NetUtils.rewriteProperties.getEnabled())) {
return sourceIp; return sourceIP;
} }
final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream()
.filter(v -> NetUtils.subnetIp(v.getNetwork(), clientIp))
.findFirst()
.orElse(null);
if(rule == null) {
return sourceIp;
}
log.debug("地址重写:{} - {} - {}", sourceIp, clientIp, rule.getNetwork());
try { try {
final InetAddress sourceAddress = NetUtils.realAddress(sourceIp); final InetAddress sourceAddress = NetUtils.realAddress(sourceIP);
final InetAddress clientAddress = NetUtils.realAddress(clientIp); final InetAddress clientAddress = NetUtils.realAddress(clientIP);
final boolean sourceLocal = NetUtils.localAddress(sourceAddress); final boolean sourceLocal = NetUtils.localAddress(sourceAddress);
final boolean clientLocal = NetUtils.localAddress(clientAddress); final boolean clientLocal = NetUtils.localAddress(clientAddress);
// 内网服务 && 内网设备
if(sourceLocal && clientLocal) { if(sourceLocal && clientLocal) {
final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream()
.filter(v -> NetUtils.subnetIP(v.getNetwork(), clientIP))
.findFirst()
.orElse(null);
if(rule == null) {
return sourceIP;
}
log.debug("地址重写:{} - {} - {}", sourceIP, clientIP, rule.getNetwork());
// 明确配置 // 明确配置
if(StringUtils.isNotEmpty(rule.getInnerHost())) { if(StringUtils.isNotEmpty(rule.getInnerHost())) {
return rule.getInnerHost(); return rule.getInnerHost();
@@ -150,18 +151,36 @@ public final class NetUtils {
return InetAddress.getByAddress(bytes).getHostAddress(); return InetAddress.getByAddress(bytes).getHostAddress();
} }
} }
// 公网服务 && 内网设备
if(sourceLocal && !clientLocal && StringUtils.isNotEmpty(rule.getInnerHost())) {
return rule.getInnerHost();
}
// 内网服务 && 公网设备 // 内网服务 && 公网设备
if(!sourceLocal && clientLocal && StringUtils.isNotEmpty(rule.getOuterHost())) { if(sourceLocal && !clientLocal) {
return rule.getOuterHost(); final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream()
.filter(v -> NetUtils.subnetIP(v.getNetwork(), sourceIP))
.findFirst()
.orElse(null);
if(rule == null) {
return sourceIP;
}
if(StringUtils.isNotEmpty(rule.getOuterHost())) {
return rule.getOuterHost();
}
}
// 公网服务 && 内网设备
if(!sourceLocal && clientLocal) {
final RewriteRuleProperties rule = NetUtils.rewriteProperties.getRule().stream()
.filter(v -> NetUtils.subnetIP(v.getNetwork(), clientIP))
.findFirst()
.orElse(null);
if(rule == null) {
return sourceIP;
}
if(StringUtils.isNotEmpty(rule.getInnerHost())) {
return rule.getInnerHost();
}
} }
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
log.error("地址重写异常:{}-{}", sourceIp, clientIp, e); log.error("地址重写异常:{} - {}", sourceIP, clientIP, e);
} }
return sourceIp; return sourceIP;
} }
/** /**
@@ -175,7 +194,7 @@ public final class NetUtils {
final InetAddress address = InetAddress.getByName(ip); final InetAddress address = InetAddress.getByName(ip);
if(NetUtils.localAnyOrLoopAddress(address)) { if(NetUtils.localAnyOrLoopAddress(address)) {
// 通配地址或者换回地址使用本机地址 // 通配地址或者换回地址使用本机地址
return InetAddress.getByName(NetUtils.localIp); return InetAddress.getByName(NetUtils.localIP);
} }
return address; return address;
} }

View File

@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" scanPeriod="60 seconds" debug="false"> <configuration scan="false" scanPeriod="60 seconds" debug="false">
<springProperty scope="context" name="log.name" source="spring.application.name" /> <springProperty scope="context" name="log.name" source="spring.application.name" />
<contextName>${log.name}</contextName> <contextName>${log.name}</contextName>
<property name="log.path" value="logs" /> <property name="log.path" value="logs" />
<property name="log.queue" value="2048" /> <property name="log.queue" value="2048" />
<property name="log.buffer" value="8192" /> <property name="log.buffer" value="8192" />
<property name="log.history" value="30" /> <property name="log.history" value="30" />
<property name="log.charset" value="UTF-8" /> <property name="log.charset" value="UTF-8" />
<property name="log.pattern" value="[${log.name}] %d{YYYY-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} %file:%line - %m%n" /> <property name="log.pattern" value="[${log.name}] %d{YYYY-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} %file:%line - %m%n" />
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder> <encoder>
@@ -22,90 +22,90 @@
</filter> </filter>
</appender> </appender>
<appender name="fileDebug" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="fileDebug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/${log.name}.debug.log</file> <file>${log.path}/${log.name}.debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<maxHistory>${log.history}</maxHistory> <maxHistory>${log.history}</maxHistory>
<fileNamePattern>${log.path}/%d{yyyy-MM, aux}/${log.name}.debug.%d{yyyy-MM-dd}.log.gz</fileNamePattern> <fileNamePattern>${log.path}/%d{yyyy-MM, aux}/${log.name}.debug.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
</rollingPolicy> </rollingPolicy>
<bufferSize>${log.buffer}</bufferSize> <bufferSize>${log.buffer}</bufferSize>
<immediateFlush>false</immediateFlush> <immediateFlush>false</immediateFlush>
<encoder> <encoder>
<charset>${log.charset}</charset> <charset>${log.charset}</charset>
<pattern>${log.pattern}</pattern> <pattern>${log.pattern}</pattern>
</encoder> </encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level> <level>DEBUG</level>
</filter> </filter>
</appender> </appender>
<appender name="fileDebugAsync" class="ch.qos.logback.classic.AsyncAppender"> <appender name="fileDebugAsync" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="fileDebug" /> <appender-ref ref="fileDebug" />
<queueSize>${log.queue}</queueSize> <queueSize>${log.queue}</queueSize>
<includeCallerData>true</includeCallerData> <includeCallerData>true</includeCallerData>
<discardingThreshold>0</discardingThreshold> <discardingThreshold>0</discardingThreshold>
</appender> </appender>
<appender name="fileInfo" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="fileInfo" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/${log.name}.info.log</file> <file>${log.path}/${log.name}.info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<maxHistory>${log.history}</maxHistory> <maxHistory>${log.history}</maxHistory>
<fileNamePattern>${log.path}/%d{yyyy-MM, aux}/${log.name}.info.%d{yyyy-MM-dd}.log.gz</fileNamePattern> <fileNamePattern>${log.path}/%d{yyyy-MM, aux}/${log.name}.info.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
</rollingPolicy> </rollingPolicy>
<bufferSize>${log.buffer}</bufferSize> <bufferSize>${log.buffer}</bufferSize>
<immediateFlush>false</immediateFlush> <immediateFlush>false</immediateFlush>
<encoder> <encoder>
<charset>${log.charset}</charset> <charset>${log.charset}</charset>
<pattern>${log.pattern}</pattern> <pattern>${log.pattern}</pattern>
</encoder> </encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level> <level>INFO</level>
</filter> </filter>
</appender> </appender>
<appender name="fileInfoAsync" class="ch.qos.logback.classic.AsyncAppender"> <appender name="fileInfoAsync" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="fileInfo" /> <appender-ref ref="fileInfo" />
<queueSize>${log.queue}</queueSize> <queueSize>${log.queue}</queueSize>
<includeCallerData>true</includeCallerData> <includeCallerData>true</includeCallerData>
<discardingThreshold>0</discardingThreshold> <discardingThreshold>0</discardingThreshold>
</appender> </appender>
<appender name="fileError" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="fileError" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/${log.name}.error.log</file> <file>${log.path}/${log.name}.error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<maxHistory>${log.history}</maxHistory> <maxHistory>${log.history}</maxHistory>
<fileNamePattern>${log.path}/%d{yyyy-MM, aux}/${log.name}.error.%d{yyyy-MM-dd}.log.gz</fileNamePattern> <fileNamePattern>${log.path}/%d{yyyy-MM, aux}/${log.name}.error.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
</rollingPolicy> </rollingPolicy>
<bufferSize>${log.buffer}</bufferSize> <bufferSize>${log.buffer}</bufferSize>
<immediateFlush>false</immediateFlush> <immediateFlush>false</immediateFlush>
<encoder> <encoder>
<charset>${log.charset}</charset> <charset>${log.charset}</charset>
<pattern>${log.pattern}</pattern> <pattern>${log.pattern}</pattern>
</encoder> </encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level> <level>ERROR</level>
</filter> </filter>
</appender> </appender>
<appender name="fileErrorAsync" class="ch.qos.logback.classic.AsyncAppender"> <appender name="fileErrorAsync" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="fileError" /> <appender-ref ref="fileError" />
<queueSize>${log.queue}</queueSize> <queueSize>${log.queue}</queueSize>
<includeCallerData>true</includeCallerData> <includeCallerData>true</includeCallerData>
<discardingThreshold>0</discardingThreshold> <discardingThreshold>0</discardingThreshold>
</appender> </appender>
<springProfile name="uat | prd"> <springProfile name="uat | prd">
<root level="DEBUG"> <root level="DEBUG">
<appender-ref ref="fileDebugAsync" /> <appender-ref ref="fileDebugAsync" />
<appender-ref ref="fileInfoAsync" /> <appender-ref ref="fileInfoAsync" />
<appender-ref ref="fileErrorAsync" /> <appender-ref ref="fileErrorAsync" />
</root> </root>
</springProfile> </springProfile>
<springProfile name="!(uat | prd)"> <springProfile name="!(uat | prd)">
<root level="DEBUG"> <root level="DEBUG">
<appender-ref ref="console" /> <appender-ref ref="console" />
<appender-ref ref="fileDebugAsync" /> <appender-ref ref="fileDebugAsync" />
<appender-ref ref="fileInfoAsync" /> <appender-ref ref="fileInfoAsync" />
<appender-ref ref="fileErrorAsync" /> <appender-ref ref="fileErrorAsync" />
</root> </root>
</springProfile> </springProfile>
</configuration> </configuration>

View File

@@ -1,5 +1,7 @@
package com.acgist.taoyao.boot.model; package com.acgist.taoyao.boot.model;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Map; import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -19,6 +21,7 @@ public class MessageTest {
.body(Map.of("1", "2")) .body(Map.of("1", "2"))
.build(); .build();
final String json = JSONUtils.toJSON(message); final String json = JSONUtils.toJSON(message);
assertEquals("{\"code\":\"0000\",\"message\":\"acgist\",\"body\":{\"1\":\"2\"}}", json);
log.info("{}", json); log.info("{}", json);
} }

View File

@@ -20,34 +20,43 @@ public class NetUtilsTest {
private void init() { private void init() {
final RewriteRuleProperties rewriteRuleProperties1 = new RewriteRuleProperties(); final RewriteRuleProperties rewriteRuleProperties1 = new RewriteRuleProperties();
rewriteRuleProperties1.setNetwork("192.168.1.0"); rewriteRuleProperties1.setNetwork("192.168.1.0");
final RewriteRuleProperties rewriteRuleProperties8 = new RewriteRuleProperties();
rewriteRuleProperties8.setNetwork("192.168.8.0");
rewriteRuleProperties8.setInnerHost("192.168.8.88");
rewriteRuleProperties8.setOuterHost("8.8.8.8");
final RewriteRuleProperties rewriteRuleProperties10 = new RewriteRuleProperties(); final RewriteRuleProperties rewriteRuleProperties10 = new RewriteRuleProperties();
rewriteRuleProperties10.setNetwork("192.168.10.0"); rewriteRuleProperties10.setNetwork("192.168.10.0");
final RewriteProperties rewriteProperties = new RewriteProperties(); final RewriteProperties rewriteProperties = new RewriteProperties();
rewriteProperties.setEnabled(true); rewriteProperties.setEnabled(true);
rewriteProperties.setPrefix(24); rewriteProperties.setPrefix(24);
rewriteProperties.setRule(List.of(rewriteRuleProperties1, rewriteRuleProperties10)); rewriteProperties.setRule(List.of(rewriteRuleProperties1, rewriteRuleProperties8, rewriteRuleProperties10));
NetUtils.init(rewriteProperties); NetUtils.init(rewriteProperties);
} }
@Test @Test
public void testSubnetIp() { public void testSubnetIp() {
this.init(); this.init();
assertTrue(NetUtils.subnetIp("192.168.8.1", "192.168.8.100")); assertFalse(NetUtils.subnetIP("192.168.1.1", "114.114.114.114"));
assertTrue(NetUtils.subnetIp("192.168.100.1", "192.168.100.100")); assertTrue(NetUtils.subnetIP("192.168.8.1", "192.168.8.100"));
assertFalse(NetUtils.subnetIp("192.168.1.1", "192.168.8.100")); assertTrue(NetUtils.subnetIP("192.168.100.1", "192.168.100.100"));
assertFalse(NetUtils.subnetIp("192.168.80.1", "192.168.8.100")); assertFalse(NetUtils.subnetIP("192.168.1.1", "192.168.8.100"));
assertTrue(NetUtils.subnetIp("fe80::9ff9:2da9:9759:17e9", "fe80::9ff9:2da9:9759:17e9")); assertFalse(NetUtils.subnetIP("192.168.80.1", "192.168.8.100"));
assertTrue(NetUtils.subnetIp("fe80::9ff9:2da9:9759:17ee", "fe80::9ff9:2da9:9759:17e9")); assertTrue(NetUtils.subnetIP("fe80::9ff9:2da9:9759:17e9", "fe80::9ff9:2da9:9759:17e9"));
assertFalse(NetUtils.subnetIp("fe81::9ff9:2da9:9759:17e9", "fe80::9ff9:2da9:9759:17e9")); assertTrue(NetUtils.subnetIP("fe80::9ff9:2da9:9759:17ee", "fe80::9ff9:2da9:9759:17e9"));
assertFalse(NetUtils.subnetIp("fe81::9ff9:2da9:9759:17ee", "fe80::9ff9:2da9:9759:17e9")); assertFalse(NetUtils.subnetIP("fe81::9ff9:2da9:9759:17e9", "fe80::9ff9:2da9:9759:17e9"));
assertFalse(NetUtils.subnetIP("fe81::9ff9:2da9:9759:17ee", "fe80::9ff9:2da9:9759:17e9"));
} }
@Test @Test
public void testRewriteIp() { public void testRewriteIp() {
this.init(); this.init();
assertNotEquals("192.168.1.0", NetUtils.rewriteIp("0.0.0.0", "192.168.1.1")); assertNotEquals("192.168.1.0", NetUtils.rewriteIP("0.0.0.0", "192.168.1.1"));
assertEquals("192.168.1.100", NetUtils.rewriteIp("192.168.8.100", "192.168.1.1")); assertEquals("192.168.1.100", NetUtils.rewriteIP("192.168.8.100", "192.168.1.1"));
assertEquals("192.168.10.100", NetUtils.rewriteIp("192.168.8.100", "192.168.10.1")); assertEquals("192.168.10.100", NetUtils.rewriteIP("192.168.8.100", "192.168.10.1"));
assertEquals("114.114.114.114", NetUtils.rewriteIP("114.114.114.114", "192.168.10.1"));
assertEquals("192.168.2.100", NetUtils.rewriteIP("192.168.2.100", "114.114.114.114"));
assertEquals("192.168.8.88", NetUtils.rewriteIP("114.114.114.114", "192.168.8.100"));
assertEquals("8.8.8.8", NetUtils.rewriteIP("192.168.8.100", "114.114.114.114"));
} }
@Test @Test
@@ -55,15 +64,15 @@ public class NetUtilsTest {
this.init(); this.init();
long a = System.currentTimeMillis(); long a = System.currentTimeMillis();
for (int index = 0; index < 100000; index++) { for (int index = 0; index < 100000; index++) {
assertTrue(NetUtils.subnetIp("192.168.100.1", "192.168.100.100")); assertTrue(NetUtils.subnetIP("192.168.100.1", "192.168.100.100"));
assertFalse(NetUtils.subnetIp("192.168.1.1", "192.168.8.100")); assertFalse(NetUtils.subnetIP("192.168.1.1", "192.168.8.100"));
} }
long z = System.currentTimeMillis(); long z = System.currentTimeMillis();
log.info("耗时:{}", z - a); log.info("耗时:{}", z - a);
a = System.currentTimeMillis(); a = System.currentTimeMillis();
for (int index = 0; index < 100000; index++) { for (int index = 0; index < 100000; index++) {
assertEquals("192.168.1.100", NetUtils.rewriteIp("192.168.8.100", "192.168.1.1")); assertEquals("192.168.1.100", NetUtils.rewriteIP("192.168.8.100", "192.168.1.1"));
assertEquals("192.168.10.100", NetUtils.rewriteIp("192.168.8.100", "192.168.10.1")); assertEquals("192.168.10.100", NetUtils.rewriteIP("192.168.8.100", "192.168.10.1"));
} }
z = System.currentTimeMillis(); z = System.currentTimeMillis();
log.info("耗时:{}", z - a); log.info("耗时:{}", z - a);

View File

@@ -1,13 +1,21 @@
package com.acgist.taoyao.boot.utils; package com.acgist.taoyao.boot.utils;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ScriptUtilsTest { public class ScriptUtilsTest {
@Test @Test
void test() { void test() throws InterruptedException {
ScriptUtils.execute("ls"); assertNotEquals(0, ScriptUtils.execute("ls").getCode());
ScriptUtils.execute("netstat -ano"); assertEquals(0, ScriptUtils.execute("netstat -ano").getCode());
log.info("{}", ScriptUtils.execute("ls").getResult());
log.info("{}", ScriptUtils.execute("netstat -ano").getResult());
} }
} }

View File

@@ -92,7 +92,7 @@ public class MediaTransportPlainProtocol extends ProtocolRoomAdapter {
// 媒体服务返回IP // 媒体服务返回IP
final String mediaIp = (String) body.get(Constant.IP); final String mediaIp = (String) body.get(Constant.IP);
if(StringUtils.isNotEmpty(mediaIp)) { if(StringUtils.isNotEmpty(mediaIp)) {
final String rewriteIp = NetUtils.rewriteIp(mediaIp, clientIp); final String rewriteIp = NetUtils.rewriteIP(mediaIp, clientIp);
log.debug("重写地址:{} + {} -> {}", mediaIp, clientIp, rewriteIp); log.debug("重写地址:{} + {} -> {}", mediaIp, clientIp, rewriteIp);
body.put(Constant.IP, rewriteIp); body.put(Constant.IP, rewriteIp);
} }

View File

@@ -116,7 +116,7 @@ public class MediaTransportWebRtcCreateProtocol extends ProtocolRoomAdapter {
// 媒体服务返回IP // 媒体服务返回IP
final String mediaIp = (String) map.get(Constant.IP); final String mediaIp = (String) map.get(Constant.IP);
if(StringUtils.isNotEmpty(mediaIp)) { if(StringUtils.isNotEmpty(mediaIp)) {
final String rewriteIp = NetUtils.rewriteIp(mediaIp, clientIp); final String rewriteIp = NetUtils.rewriteIP(mediaIp, clientIp);
log.debug("重写地址:{} + {} -> {}", mediaIp, clientIp, rewriteIp); log.debug("重写地址:{} + {} -> {}", mediaIp, clientIp, rewriteIp);
map.put(Constant.IP, rewriteIp); map.put(Constant.IP, rewriteIp);
} }