This commit is contained in:
oneao committed 2025-06-10 22:05:11 +08:00
1 parent c570ec514c
commit a4827cb646
9 files changed
+479 -83

No files matched your search

@@ -1,5 +1,6 @@
package cn.g3soft;
import cn.g3soft.utils.SnowflakeIdUtils;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -11,6 +12,7 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
})
public class BaseApplication {
public static void main(String[] args) {
System.out.println(SnowflakeIdUtils.nextId());
SpringApplication.run(BaseApplication.class,args);
}
}
@@ -1,79 +0,0 @@
package cn.g3soft.common;
import cn.g3soft.enums.ResponseEnum;
import lombok.Data;
import lombok.NonNull;
@Data
public class Result<T> {
private final Integer code;
private final String message;
@NonNull
private final T data;
private final Boolean showExceptionDetail;
private Result(Integer code, String message, T data, Boolean showExceptionDetail) {
this.code = code;
this.message = message;
this.data = data;
this.showExceptionDetail = showExceptionDetail;
}
// 默认showDetail为false的构造
private Result(Integer code, String message, T data) {
this(code, message, data, false);
}
// ✅ 链式设置 showExceptionDetail:返回一个新对象
public Result<T> withShowExceptionDetail(boolean showExceptionDetail) {
return new Result<>(this.code, this.message, this.data, showExceptionDetail);
}
// 成功响应(无数据)
public static <T> Result<T> success() {
return new Result<>(ResponseEnum.SUCCESS.getCode(), ResponseEnum.SUCCESS.getMessage(), null);
}
public static <T> Result<T> success(String message) {
return new Result<>(ResponseEnum.SUCCESS.getCode(), message, null);
}
public static <T> Result<T> success(@NonNull T data) {
return new Result<>(ResponseEnum.SUCCESS.getCode(), ResponseEnum.SUCCESS.getMessage(), data);
}
public static <T> Result<T> success(@NonNull T data, String message) {
return new Result<>(ResponseEnum.SUCCESS.getCode(), message, data);
}
public static <T> Result<T> success(ResponseEnum responseEnum) {
return new Result<>(responseEnum.getCode(), responseEnum.getMessage(), null);
}
public static <T> Result<T> success(ResponseEnum responseEnum, @NonNull T data) {
return new Result<>(responseEnum.getCode(), responseEnum.getMessage(), data);
}
// 错误响应(默认不显示详细信息)
public static <T> Result<T> error(ResponseEnum responseEnum) {
return new Result<>(responseEnum.getCode(), responseEnum.getMessage(), null);
}
public static <T> Result<T> error(Integer code, String message) {
return new Result<>(code, message, null);
}
public static <T> Result<T> error(String message) {
return new Result<>(ResponseEnum.ERROR.getCode(), message, null);
}
public static <T> Result<T> error(T data) {
return new Result<>(ResponseEnum.ERROR.getCode(), ResponseEnum.ERROR.getMessage(), data);
}
public static <T> Result<T> error(T data,String message) {
return new Result<>(ResponseEnum.ERROR.getCode(),message, data);
}
public static <T> Result<T> error() {
return new Result<>(ResponseEnum.ERROR.getCode(), ResponseEnum.ERROR.getMessage(), null);
}
}
@@ -0,0 +1,45 @@
package cn.g3soft.common.model;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Builder;
import lombok.Data;
import java.util.Date;
@Data
@Builder
public class ExceptionEntity {
/** 异常记录的唯一ID */
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/** 异常发生时间 */
private Date time;
/** 请求的URI地址 */
private String uri;
/** HTTP请求方法,如GET、POST等 */
private String httpMethod;
/** 抛出异常的类名 */
private String className;
/** 抛出异常的方法名 */
private String methodName;
/** 抛出异常的文件名 */
private String fileName;
/** 抛出异常的代码行号 */
private Integer lineNumber;
/** 异常的简短信息 */
private String summary;
/** 异常的详细堆栈信息 */
private String detailMessage;
/** 请求参数(可能为JSON字符串等) */
private String params;
}
@@ -0,0 +1,126 @@
package cn.g3soft.common.model;
import cn.g3soft.enums.ResponseEnum;
import lombok.NonNull;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder(toBuilder = true)
public class Result<T> {
private final Integer code;
private final String message;
private final T data;
private final Boolean showExceptionDetail;
// 工厂方法建议保留,简化构造调用
public static <T> Result<T> success() {
return Result.<T>builder()
.code(ResponseEnum.SUCCESS.getCode())
.message(ResponseEnum.SUCCESS.getMessage())
.showExceptionDetail(false)
.build();
}
public static <T> Result<T> success(String message) {
return Result.<T>builder()
.code(ResponseEnum.SUCCESS.getCode())
.message(message)
.showExceptionDetail(false)
.build();
}
public static <T> Result<T> success(@NonNull T data) {
return Result.<T>builder()
.code(ResponseEnum.SUCCESS.getCode())
.message(ResponseEnum.SUCCESS.getMessage())
.data(data)
.showExceptionDetail(false)
.build();
}
public static <T> Result<T> success(@NonNull T data, String message) {
return Result.<T>builder()
.code(ResponseEnum.SUCCESS.getCode())
.message(message)
.data(data)
.showExceptionDetail(false)
.build();
}
public static <T> Result<T> success(ResponseEnum responseEnum) {
return Result.<T>builder()
.code(responseEnum.getCode())
.message(responseEnum.getMessage())
.showExceptionDetail(false)
.build();
}
public static <T> Result<T> success(ResponseEnum responseEnum, @NonNull T data) {
return Result.<T>builder()
.code(responseEnum.getCode())
.message(responseEnum.getMessage())
.data(data)
.showExceptionDetail(false)
.build();
}
public static <T> Result<T> error() {
return Result.<T>builder()
.code(ResponseEnum.ERROR.getCode())
.message(ResponseEnum.ERROR.getMessage())
.showExceptionDetail(false)
.build();
}
public static <T> Result<T> error(String message) {
return Result.<T>builder()
.code(ResponseEnum.ERROR.getCode())
.message(message)
.showExceptionDetail(false)
.build();
}
public static <T> Result<T> error(Integer code, String message) {
return Result.<T>builder()
.code(code)
.message(message)
.showExceptionDetail(false)
.build();
}
public static <T> Result<T> error(ResponseEnum responseEnum) {
return Result.<T>builder()
.code(responseEnum.getCode())
.message(responseEnum.getMessage())
.showExceptionDetail(false)
.build();
}
public static <T> Result<T> error(T data) {
return Result.<T>builder()
.code(ResponseEnum.ERROR.getCode())
.message(ResponseEnum.ERROR.getMessage())
.data(data)
.showExceptionDetail(false)
.build();
}
public static <T> Result<T> error(T data, String message) {
return Result.<T>builder()
.code(ResponseEnum.ERROR.getCode())
.message(message)
.data(data)
.showExceptionDetail(false)
.build();
}
public Result<T> withShowExceptionDetail(boolean show) {
return this.toBuilder().showExceptionDetail(show).build();
}
public boolean isSuccess() {
return ResponseEnum.SUCCESS.getCode().equals(this.code);
}
}
@@ -1,12 +1,11 @@
package cn.g3soft.exception;
import cn.g3soft.common.Result;
import cn.g3soft.common.model.Result;
import cn.g3soft.exception.auth.AuthException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
@@ -0,0 +1,98 @@
package cn.g3soft.utils;
import cn.g3soft.common.model.ExceptionEntity;
import cn.g3soft.exception.BaseException;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
public class ExceptionUtils {
private static final ObjectMapper objectMapper = new ObjectMapper();
/**
* 根据异常和请求信息,生成统一的异常信息对象 ExceptionDetailInfo
* @param ex 异常对象
* @param request HttpServletRequest,用来获取请求路径和方法等
* @param projectBasePackage 项目基础包名,如 "com.error",用来定位业务代码异常栈帧
* @return ExceptionDetailInfo 封装的异常信息
*/
public static ExceptionEntity extractExceptionInfo(Exception ex, HttpServletRequest request, String projectBasePackage) {
StackTraceElement[] stackTrace = ex.getStackTrace();
StackTraceElement source = null;
if (stackTrace != null) {
for (StackTraceElement element : stackTrace) {
if (element.getClassName().startsWith(projectBasePackage)) {
source = element;
break;
}
}
if (source == null && stackTrace.length > 0) {
source = stackTrace[0];
}
}
String briefMessage;
if (ex instanceof BaseException) {
BaseException be = (BaseException) ex;
briefMessage = be.getMessage();
} else {
if (ex.getMessage() != null) {
String[] lines = ex.getMessage().split("\n");
// 遍历每一行,找到第一行“非空、非符号”的有效信息
String usefulLine = null;
for (String line : lines) {
String trimmed = line.trim();
if (!trimmed.isEmpty()) {
usefulLine = trimmed;
break;
}
}
// 如果找到有效行,就用它;否则仅用异常类名
if (usefulLine != null) {
briefMessage = ex.getClass().getSimpleName() + ": " + usefulLine;
} else {
briefMessage = ex.getClass().getSimpleName();
}
} else {
briefMessage = ex.getClass().getSimpleName();
}
}
String paramJson = null;
if (request != null) {
Map<String, String> paramMap = new HashMap<>();
Enumeration<String> paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
paramMap.put(paramName, request.getParameter(paramName));
}
try {
paramJson = JsonUtils.toJson(paramMap);
} catch (Exception e) {
paramJson = "参数序列化失败: " + e.getMessage();
}
}
return ExceptionEntity.builder()
.id(SnowflakeIdUtils.nextId())
.uri(request != null ? request.getRequestURI() : null)
.httpMethod(request != null ? request.getMethod() : null)
.className(source != null ? source.getClassName() : null)
.methodName(source != null ? source.getMethodName() : null)
.fileName(source != null ? source.getFileName() : null)
.lineNumber(source != null ? source.getLineNumber() : null)
.summary(briefMessage)
.detailMessage(org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(ex))
.time(new Date())
.params(paramJson)
.build();
}
}
@@ -0,0 +1,40 @@
package cn.g3soft.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonUtils {
private static final ObjectMapper objectMapper = new ObjectMapper();
// 判断字符串是否为有效的 JSON 格式
public static boolean isTypeJSON(String msgText) {
try {
// 尝试将字符串解析为 JsonNode,如果能解析,说明是有效的 JSON
JsonNode node = objectMapper.readTree(msgText);
return node != null;
} catch (Exception e) {
return false; // 如果抛出异常,说明不是有效的 JSON
}
}
// 将 JSON 字符串转换为指定类型的 Java 对象
public static <T> T toBean(String json, Class<T> clazz) {
try {
// 使用 ObjectMapper 将 JSON 字符串转换为指定类型的对象
return objectMapper.readValue(json, clazz);
} catch (JsonProcessingException e) {
e.printStackTrace(); // 打印异常信息
return null; // 如果转换失败,返回 null
}
}
// 将对象转换为 JSON 字符串
public static String toJson(Object obj) {
try {
return objectMapper.writeValueAsString(obj); // 将对象转换为 JSON 字符串
} catch (JsonProcessingException e) {
System.out.println(e.getMessage());
return null; // 如果出现异常,返回 null
}
}
}
@@ -0,0 +1,165 @@
package cn.g3soft.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@Slf4j
public class SnowflakeIdUtils {
public static long MAX_START_INTERVAL_TIME = TimeUnit.SECONDS.toNanos(5L);
private static final long twepoch = 1288834974657L;
private static final long workerIdBits = 5L;
private static final long datacenterIdBits = 5L;
private static final long maxWorkerId = 31L;
private static final long maxDatacenterId = 31L;
private static final long sequenceBits = 12L;
private static final long workerIdShift = 12L;
private static final long datacenterIdShift = 17L;
private static final long timestampLeftShift = 22L;
private static final long sequenceMask = 4095L;
// 这两个必须初始化
private static long workerId;
private static long datacenterId;
private static long sequence = 0L;
private static long lastTimestamp = -1L;
private static InetAddress inetAddress;
// 初始化一次即可,线程安全调用
public static synchronized void init(InetAddress address) {
if (inetAddress == null) {
inetAddress = address;
datacenterId = getDatacenterId(maxDatacenterId);
workerId = getMaxWorkerId(datacenterId, maxWorkerId);
long start = System.nanoTime();
long end = System.nanoTime();
if (end - start > MAX_START_INTERVAL_TIME) {
log.warn("Initialization Sequence Very Slow! Get datacenterId:{} workerId:{}", datacenterId, workerId);
} else {
initLog();
}
}
}
public static synchronized void init(long fixedWorkerId, long fixedDatacenterId) {
Assert.isTrue(fixedWorkerId <= maxWorkerId && fixedWorkerId >= 0,
String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
Assert.isTrue(fixedDatacenterId <= maxDatacenterId && fixedDatacenterId >= 0,
String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
workerId = fixedWorkerId;
datacenterId = fixedDatacenterId;
initLog();
}
private static void initLog() {
if (log.isDebugEnabled()) {
log.debug("Initialization Sequence datacenterId:{} workerId:{}", datacenterId, workerId);
}
}
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuilder mpid = new StringBuilder();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (StringUtils.isNotBlank(name)) {
mpid.append(name.split("@")[0]);
}
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1L);
}
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
if (inetAddress == null) {
if (log.isDebugEnabled()) {
log.debug("Use localhost address");
}
inetAddress = InetAddress.getLocalHost();
}
if (log.isDebugEnabled()) {
log.debug("Get {} network interface", inetAddress);
}
NetworkInterface network = NetworkInterface.getByInetAddress(inetAddress);
if (log.isDebugEnabled()) {
log.debug("Get network interface info: {}", network);
}
if (network == null) {
log.warn("Unable to get network interface for {}", inetAddress);
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
if (mac != null && mac.length >= 2) {
id = ((0xffL & (long) mac[mac.length - 2]) | (0xff00L & ((long) mac[mac.length - 1] << 8))) >> 6;
id %= maxDatacenterId + 1L;
}
}
} catch (Exception e) {
log.warn("getDatacenterId error: {}", e.getMessage(), e);
}
return id;
}
public static synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
long offset = lastTimestamp - timestamp;
if (offset > 5L) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
}
try {
SnowflakeIdUtils.class.wait(offset << 1);
timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = ThreadLocalRandom.current().nextLong(1, 3);
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift)
| sequence;
}
protected static long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
protected static long timeGen() {
return System.currentTimeMillis();
}
public static long parseIdTimestamp(long id) {
return (id >> 22) + 1288834974657L;
}
}
@@ -1,11 +1,11 @@
datasource:
db1:
url: jdbc:jtds:sqlserver://192.168.1.176:1433;databaseName=G3-Email
url: jdbc:jtds:sqlserver://127.0.0.1:1433;databaseName=test1
username: sa
password: sa
driverClassName: net.sourceforge.jtds.jdbc.Driver
db2:
url: jdbc:jtds:sqlserver://192.168.1.176:1433;databaseName=Sllog
url: jdbc:jtds:sqlserver://127.0.0.1:1433;databaseName=test2
username: sa
password: sa
driverClassName: net.sourceforge.jtds.jdbc.Driver