map = new HashMap<>();
+ for (Status element : Status.values()) {
+ map.put(element.getValue(), element);
+ }
+ ENUM_MAP = Collections.unmodifiableMap(map);
+ }
+
+ public static Status get(Integer value) {
+ if (value == null) {
+ return null;
+ }
+ return ENUM_MAP.get(value);
+ }
+
+}
\ No newline at end of file
diff --git a/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/enums/SystemCode.java b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/enums/SystemCode.java
new file mode 100644
index 0000000..458d32e
--- /dev/null
+++ b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/enums/SystemCode.java
@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) 2004-2024 All Rights Reserved.
+ */
+package electromagnetic.data.framework.share.enums;
+
+/**
+ * @author wsk
+ * @version $Id: SystemCode.java, v 0.1 2024-10-17 17:56 wsk
+ */
+public class SystemCode {
+
+ /** 默认版本 */
+ public static String VERSION = "1";
+
+ /** 默认事件码 */
+ public static String EVENTCODE = "00001001";
+}
diff --git a/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/BizRuntimeException.java b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/BizRuntimeException.java
new file mode 100644
index 0000000..f38ff88
--- /dev/null
+++ b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/BizRuntimeException.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright (c) 2004-2024 All Rights Reserved.
+ */
+package electromagnetic.data.framework.share.exception;
+
+/**
+ * @author wsk
+ * @version $Id: BizRuntimeException.java, v 0.1 2024-10-17 17:46 wsk
+ */
+/**
+ * Runtime业务异常
+ *
+ * @author cihun
+ */
+public class BizRuntimeException extends RuntimeException implements DigestLogException {
+
+ private static final long serialVersionUID = 4823673135679689193L;
+ /**
+ * 错误码
+ */
+ private String errorCode;
+
+ public String getErrorCode() {
+ return errorCode;
+ }
+
+ // ~~~ 构造方法
+
+ /**
+ * default
+ */
+ public BizRuntimeException() {
+ super();
+ }
+
+ /**
+ * 创建一个BizRuntimeException
+ *
+ * @param errorMessage 错误描述
+ */
+ public BizRuntimeException(final String errorMessage) {
+ super(errorMessage);
+ }
+
+ /**
+ * 创建一个BizRuntimeException
+ *
+ * @param errorMessage 错误描述
+ * @param cause 异常
+ */
+ public BizRuntimeException(final String errorMessage, final Throwable cause) {
+ super(errorMessage, cause);
+ }
+
+ /**
+ * 创建一个BizRuntimeException
+ *
+ * @param cause 异常
+ */
+ public BizRuntimeException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * 创建一个BizRuntimeException
+ *
+ * @param errorCode 错误码
+ * @param errorMessage 错误描述
+ */
+ public BizRuntimeException(final String errorCode, final String errorMessage) {
+ this(errorCode, errorMessage, null);
+ }
+
+// /**
+// * 创建一个BizRuntimeException
+// *
+// * @param errorCode 错误码
+// * @param errorMessage 错误描述
+// * @param errorContext 错误上下文
+// */
+// public BizRuntimeException(final String errorCode, final String errorMessage, final ErrorContext errorContext) {
+// super(errorMessage);
+// this.errorCode = errorCode;
+// this.errorContext = errorContext;
+// }
+
+ /**
+ * 创建一个BizRuntimeException
+ *
+ * @param errorCode 错误码
+ * @param errorMessage 错误描述
+ * @param cause 异常
+ */
+ public BizRuntimeException(final String errorCode, final String errorMessage, final Throwable cause) {
+ super(errorMessage, cause);
+ this.errorCode = errorCode;
+ }
+
+// // ~~~ 重写方法
+//
+// /**
+// * @see java.lang.Throwable#toString()
+// */
+// @Override
+// public final String toString() {
+// return String.format(" %s [errorCode=%s, errorMsg=%s, errorContext=%s]", getClass()
+// .getSimpleName(), errorCode, getLocalizedMessage());
+// }
+
+ // ~~~ 容器方法
+
+ /**
+ * Setter method for property errorCode.
+ *
+ * @param errorCode value to be assigned to property errorCode
+ */
+ public void setErrorCode(String errorCode) {
+ this.errorCode = errorCode;
+ }
+
+ @Override
+ public String getTagErrorCode() {
+ return this.errorCode;
+ }
+
+ @Override
+ public String getTagErrorMsg() {
+ return this.getMessage();
+ }
+}
\ No newline at end of file
diff --git a/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/DigestLogException.java b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/DigestLogException.java
new file mode 100644
index 0000000..b751002
--- /dev/null
+++ b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/DigestLogException.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2004-2024 All Rights Reserved.
+ */
+package electromagnetic.data.framework.share.exception;
+
+/**
+ * @author wsk
+ * @version $Id: DigestLogException.java, v 0.1 2024-10-17 17:47 wsk
+ */
+public interface DigestLogException {
+
+ /**
+ * 获取错误码
+ *
+ * @return
+ */
+ String getTagErrorCode();
+
+ /**
+ * 获取错误详情
+ *
+ * @return
+ */
+ String getTagErrorMsg();
+}
diff --git a/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/ElectromagneticBizRuntimeException.java b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/ElectromagneticBizRuntimeException.java
new file mode 100644
index 0000000..b13ec2e
--- /dev/null
+++ b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/ElectromagneticBizRuntimeException.java
@@ -0,0 +1,71 @@
+/**
+ * Alibaba.com Inc. Copyright (c) 2004-2021 All Rights Reserved.
+ */
+package electromagnetic.data.framework.share.exception;
+
+
+import electromagnetic.data.framework.share.constants.ElectromagneticConstants;
+import electromagnetic.data.framework.share.enums.ElectromagneticSceneIncidentEnum;
+import electromagnetic.data.framework.share.enums.ErrorEnum;
+import electromagnetic.data.framework.share.enums.ResultCodeEnum;
+
+/**
+ * @version v 0.1
+ */
+
+public class ElectromagneticBizRuntimeException extends BizRuntimeException {
+
+
+ private static final long serialVersionUID = -1395535251101232205L;
+
+ public static ElectromagneticBizRuntimeException of(ElectromagneticSceneIncidentEnum incident, ErrorEnum error){
+ String errorCode = ElectromagneticConstants.PREFIX_CODE+error.getCodeLevel()+error.getCodeType()+ ElectromagneticConstants.CODE +incident.getCode() + error.getCode();
+ String message = error.getErrorDesc();
+ return new ElectromagneticBizRuntimeException(errorCode, message);
+ }
+
+ public static ElectromagneticBizRuntimeException of(ElectromagneticSceneIncidentEnum incident, ErrorEnum error, Throwable cause){
+ String errorCode = ElectromagneticConstants.PREFIX_CODE+error.getCodeLevel()+error.getCodeType()+ ElectromagneticConstants.CODE +incident.getCode() + error.getCode();
+ String message = error.getErrorDesc();
+ return new ElectromagneticBizRuntimeException(errorCode, message, cause);
+ }
+
+
+ public static ElectromagneticBizRuntimeException of(ElectromagneticSceneIncidentEnum incident, ErrorEnum error, String extendMsg){
+ String errorCode = ElectromagneticConstants.PREFIX_CODE+error.getCodeLevel()+error.getCodeType()+ ElectromagneticConstants.CODE +incident.getCode() + error.getCode();
+ String message = error.getErrorDesc() +"@"+ extendMsg;
+ return new ElectromagneticBizRuntimeException(errorCode, message);
+ }
+
+
+
+ public static ElectromagneticBizRuntimeException of(ElectromagneticSceneIncidentEnum incident, ResultCodeEnum error){
+ String errorCode = error.getResultCode(ElectromagneticConstants.CODE +incident.getCode());
+ String message = error.getResultMsg();
+ return new ElectromagneticBizRuntimeException(errorCode, message);
+ }
+
+ public static ElectromagneticBizRuntimeException of(ElectromagneticSceneIncidentEnum incident, ResultCodeEnum error, Throwable cause){
+ String errorCode = error.getResultCode(ElectromagneticConstants.CODE +incident.getCode());
+ String message = error.getResultMsg();
+ return new ElectromagneticBizRuntimeException(errorCode, message, cause);
+ }
+
+
+ public static ElectromagneticBizRuntimeException of(ElectromagneticSceneIncidentEnum incident, ResultCodeEnum error, String extendMsg){
+ String errorCode = error.getResultCode(ElectromagneticConstants.CODE +incident.getCode());
+ String message = error.getResultMsg() +"@"+ extendMsg;
+ return new ElectromagneticBizRuntimeException(errorCode, message);
+ }
+
+
+
+ private ElectromagneticBizRuntimeException(String errorCode, String errorMsg){
+ super(errorCode, errorMsg);
+ }
+
+ private ElectromagneticBizRuntimeException(String errorCode, String message, Throwable cause) {
+ super(errorCode,message, cause);
+ }
+
+}
\ No newline at end of file
diff --git a/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/IllegalParameterException.java b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/IllegalParameterException.java
new file mode 100644
index 0000000..551f375
--- /dev/null
+++ b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/IllegalParameterException.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2004-2024 All Rights Reserved.
+ */
+package electromagnetic.data.framework.share.exception;
+
+/**
+ * 非法参数异常扩展
+ * @author wsk
+ * @version $Id: IllegalParameterException.java, v 0.1 2024-10-20 19:02 wsk
+ */
+public class IllegalParameterException extends BizRuntimeException {
+
+ private static final long serialVersionUID = -469578593324154948L;
+
+ public IllegalParameterException(String message) {
+ super("ILLEGAL_PARAM", message);
+ }
+
+ public IllegalParameterException(String message, Throwable cause) {
+ super("ILLEGAL_PARAM", message, cause);
+ }
+
+}
\ No newline at end of file
diff --git a/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/LoggerConstant.java b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/LoggerConstant.java
new file mode 100644
index 0000000..cb75565
--- /dev/null
+++ b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/exception/LoggerConstant.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2004-2024 All Rights Reserved.
+ */
+package electromagnetic.data.framework.share.exception;
+
+/**
+ * @author wsk
+ * @version $Id: LoggerConstant.java, v 0.1 2024-10-18 18:04 wsk
+ */
+public class LoggerConstant {
+
+ /**
+ * 异步任务日志
+ */
+ public static final String TASK_SCHEDULER_LOG = "TASK-SCHEDULER";
+
+ /**
+ * 消息监听日志
+ */
+ public static final String MSG_LISTEN = "MSG-LISTEN";
+
+ /**
+ * 严重告警日志
+ */
+ public static final String SERIOUS_ALERT = "SERIOUS-ALERT";
+
+ /**
+ * 业务日志
+ */
+ public static final String DOMAIN_SERVICE = "DOMAIN-SERVICE";
+
+ /**
+ * 业务失败日志
+ */
+ public static final String DOMAIN_ERROR = "DOMAIN-ERROR";
+
+ /**
+ * 业务摘要日志
+ */
+ public static final String DOMAIN_DIGEST = "DOMAIN-DIGEST";
+
+ /**
+ * 调用外部系统日志
+ */
+ public static final String INTEGRATION = "INTEGRATION";
+}
\ No newline at end of file
diff --git a/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/id/IdWorker.java b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/id/IdWorker.java
new file mode 100644
index 0000000..ac842ca
--- /dev/null
+++ b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/id/IdWorker.java
@@ -0,0 +1,161 @@
+/**
+ * Copyright (c) 2004-2022 All Rights Reserved.
+ */
+package electromagnetic.data.framework.share.id;
+
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+
+/**
+ * @author wsk
+ * @version $Id: IdWorker.java, v 0.1 2022-06-20 16:41 wsk.pt Exp $$
+ */
+public class IdWorker {
+
+ private static IdWorker idWorker=new IdWorker();
+
+ // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
+ private final static long twepoch = 1288834974657L;
+ // 机器标识位数
+ private final static long workerIdBits = 5L;
+ // 数据中心标识位数
+ private final static long datacenterIdBits = 5L;
+ // 机器ID最大值
+ private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
+ // 数据中心ID最大值
+ private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
+ // 毫秒内自增位
+ private final static long sequenceBits = 12L;
+ // 机器ID偏左移12位
+ private final static long workerIdShift = sequenceBits;
+ // 数据中心ID左移17位
+ private final static long datacenterIdShift = sequenceBits + workerIdBits;
+ // 时间毫秒左移22位
+ private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
+
+ private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
+ /* 上次生产id时间戳 */
+ private static long lastTimestamp = -1L;
+ // 0,并发控制
+ private long sequence = 0L;
+
+ private final long workerId;
+ // 数据标识id部分
+ private final long datacenterId;
+
+ public IdWorker(){
+ this.datacenterId = getDatacenterId(maxDatacenterId);
+ this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
+ }
+ /**
+ * @param workerId
+ * 工作机器ID
+ * @param datacenterId
+ * 序列号
+ */
+ public IdWorker(long workerId, long datacenterId) {
+ if (workerId > maxWorkerId || workerId < 0) {
+ throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
+ }
+ if (datacenterId > maxDatacenterId || datacenterId < 0) {
+ throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
+ }
+ this.workerId = workerId;
+ this.datacenterId = datacenterId;
+ }
+ /**
+ * 获取下一个ID
+ *
+ * @return
+ */
+ public synchronized long nextId() {
+ long timestamp = timeGen();
+ if (timestamp < lastTimestamp) {
+ throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
+ }
+
+ if (lastTimestamp == timestamp) {
+ // 当前毫秒内,则+1
+ sequence = (sequence + 1) & sequenceMask;
+ if (sequence == 0) {
+ // 当前毫秒内计数满了,则等待下一秒
+ timestamp = tilNextMillis(lastTimestamp);
+ }
+ } else {
+ sequence = 0L;
+ }
+ lastTimestamp = timestamp;
+ // ID偏移组合生成最终的ID,并返回ID
+ long nextId = ((timestamp - twepoch) << timestampLeftShift)
+ | (datacenterId << datacenterIdShift)
+ | (workerId << workerIdShift) | sequence;
+
+ return nextId;
+ }
+
+ private long tilNextMillis(final long lastTimestamp) {
+ long timestamp = this.timeGen();
+ while (timestamp <= lastTimestamp) {
+ timestamp = this.timeGen();
+ }
+ return timestamp;
+ }
+
+ private long timeGen() {
+ return System.currentTimeMillis();
+ }
+
+ /**
+ *
+ * 获取 maxWorkerId
+ *
+ */
+ protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
+ StringBuffer mpid = new StringBuffer();
+ mpid.append(datacenterId);
+ String name = ManagementFactory.getRuntimeMXBean().getName();
+ if (!name.isEmpty()) {
+ /*
+ * GET jvmPid
+ */
+ mpid.append(name.split("@")[0]);
+ }
+ /*
+ * MAC + PID 的 hashcode 获取16个低位
+ */
+ return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
+ }
+
+ /**
+ *
+ * 数据标识id部分
+ *
+ */
+ protected static long getDatacenterId(long maxDatacenterId) {
+ long id = 0L;
+ try {
+ InetAddress ip = InetAddress.getLocalHost();
+ NetworkInterface network = NetworkInterface.getByInetAddress(ip);
+ if (network == null) {
+ id = 1L;
+ } else {
+ byte[] mac = network.getHardwareAddress();
+ id = ((0x000000FF & (long) mac[mac.length - 1])
+ | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
+ id = id % (maxDatacenterId + 1);
+ }
+ } catch (Exception e) {
+ System.out.println(" getDatacenterId: " + e.getMessage());
+ }
+ return id;
+ }
+ public static long getSnowFlakeId(){
+ return idWorker.nextId();
+ }
+
+ public static String getSnowFlakeIdString(){
+ return String.valueOf(getSnowFlakeId());
+ }
+
+}
\ No newline at end of file
diff --git a/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/log/DateUtil.java b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/log/DateUtil.java
new file mode 100644
index 0000000..3dfb6a9
--- /dev/null
+++ b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/log/DateUtil.java
@@ -0,0 +1,330 @@
+/**
+ * Copyright (c) 2004-2024 All Rights Reserved.
+ */
+package electromagnetic.data.framework.share.log;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * @author wsk
+ * @version $Id: DateUtil.java, v 0.1 2024-10-20 18:45 wsk
+ */
+public class DateUtil {
+ /** 日志 */
+ private final static Logger logger = LoggerFactory.getLogger(DateUtil.class);
+
+ /** yyyy-MM-dd */
+ public static String DATE_FORMAT_001 = "yyyy-MM-dd";
+
+ /** yyyyMMdd */
+ public static String DATE_FORMAT_002 = "yyyyMMdd";
+
+ /** yyyy-MM-dd HH:mm:ss */
+ public static String DATE_FORMAT_003 = "yyyy-MM-dd HH:mm:ss";
+
+ /** yyyy-MM-dd HH:mm:ss.S */
+ public static String DATE_FORMAT_004 = "yyyy-MM-dd HH:mm:ss.S";
+
+ /** yyyy-MM-dd'T'HH:mm:ssZ */
+ public static String DATE_FORMAT_005 = "yyyy-MM-dd'T'HH:mm:ssZ";
+
+ /** yyyy-MM-dd'T'HH:mm:ss */
+ public static String DATE_FORMAT_006 = "yyyy-MM-dd'T'HH:mm:ss";
+
+ /** yyyy-MM-dd'T'HH:mm:ss */
+ public static String DATE_FORMAT_007 = "HHmmss";
+
+ /** yyyy-MM-dd'T'HH:mm:ss */
+ public static String DATE_FORMAT_008 = "HHmm";
+
+ /**
+ * 不允许实例化
+ */
+ private DateUtil() {
+ //forbidden
+ }
+
+ /**
+ * 按照指定的格式,格式化时间
+ *
+ * @param srcDate 需要转换的date
+ * @param format 指定的格式
+ * @return 具有format格式的date,是一个new Date
+ * @throws ParseException 转换出错
+ */
+ public static Date format(Date srcDate, String format) {
+
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
+
+ //格式化
+ String dateStr = simpleDateFormat.format(srcDate);
+
+ return parse(dateStr, format);
+
+ }
+
+ /**
+ * 返回yyyyMMdd
+ * @param srcDate
+ * @return
+ */
+ public static String formatDate(Date srcDate) {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT_002);
+ return simpleDateFormat.format(srcDate);
+ }
+
+ /**
+ * 获取日期 指定格式的字符串
+ *
+ * @param date 日期
+ * @param format 格式
+ * @return
+ */
+ public static String getFormatDate(Date date, String format) {
+ SimpleDateFormat formate = null;
+ if (null == format) {
+ formate = new SimpleDateFormat(DATE_FORMAT_003);
+ } else {
+ formate = new SimpleDateFormat(format);
+ }
+ return formate.format(date);
+ }
+
+ /**
+ * 返回
+ * @param srcDate
+ * @return
+ */
+ public static String formatTime(Date srcDate) {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT_007);
+ return simpleDateFormat.format(srcDate);
+ }
+
+ /**
+ * 根据字符串和指定的格式,返回期望格式的时间
+ *
+ * @param dateStr 日期字符串
+ * @param format 输入的格式
+ * @return 具有format格式的date,是一个new Date
+ * @throws RuntimeException 格式转换出错
+ */
+ public static Date parse(String dateStr, String format) {
+
+ SimpleDateFormat formater = new SimpleDateFormat(format);
+
+ try {
+ return formater.parse(dateStr);
+ } catch (ParseException e) {
+ LogUtils.error(logger,"日期string转换Date失败,日期={0},format={1}",dateStr,format);
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * 按分钟偏移,根据{@code source}得到{@code minute}分钟之后的日期
+ *
+ * @param source
+ * , 要求非空
+ * @param minute
+ * , 分钟数,可以为负
+ * @return 新创建的Date对象
+ * @throws 如果source为null, 会抛出IllegalArgumentException异常
+ * @author xueye.duanxy
+ */
+ public static Date addMinutes(Date source, int minute) {
+ return addDate(source, Calendar.MINUTE, minute);
+ }
+
+ /**
+ * 在指定时间后,加上指定的秒数
+ *
+ * @param srcDate
+ * @param secs
+ * @return
+ */
+ public static Date addSeconds(Date srcDate, long secs) {
+ return new Date(srcDate.getTime() + (secs * 1000));
+ }
+
+ /**
+ * 获取第period天凌晨时间
+ * @return
+ */
+ public static Date getTheNextMorningTime(int period) {
+ return getTime(Calendar.DATE, period);
+ }
+
+ /**
+ * 根据calendarUnit获取凌晨时间
+ * @param calendarUnit
+ * @param period
+ * @return
+ */
+ private static Date getTime(int calendarUnit, int period) {
+ if (period <= 0) {
+ throw new RuntimeException("period <= 0");
+ }
+ Calendar calendar = Calendar.getInstance();
+ calendar.add(calendarUnit, period);
+
+ Date date = calendar.getTime();
+ SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT_001);
+ String dateString = formatter.format(date);
+
+ Date ret = null;
+ try {
+ ret = formatter.parse(dateString);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+
+ return ret;
+ }
+
+ /**
+ * 比较字符串时间
+ *
+ * @param date1
+ * @param date2
+ * @param format
+ * @return
+ */
+ public static int compareDate(String date1, String date2, String format) {
+ return parse(date1, format).compareTo(parse(date2, format));
+ }
+
+ /**
+ * 获取本周指定星期天数
+ * 如获取本周星期一:getDateOfThisWeek(new Date(), Calendar.MONDAY)
+ *
+ * @param date
+ * @param dayOfWeek {@link Calendar#DAY_OF_WEEK}
+ * @return
+ */
+ public static Date getDateOfThisWeek(Date date, int dayOfWeek) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+
+ // 获得当前日期是一个星期的第几天
+ int currentDayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
+
+ // 查找日期等于当前日期,直接返回
+ if (currentDayOfWeek == dayOfWeek) {
+ return cal.getTime();
+ }
+
+ // 临界点,如果当前时间为星期天,先跳到本周六,然后减去 (7-dayOfWeek) 天
+ if (Calendar.SUNDAY == currentDayOfWeek) {
+ cal.add(Calendar.DAY_OF_MONTH, -1);
+ currentDayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
+ }
+
+ // 临界点,如果要查找的时间为星期天,先跳到下周这个时刻,然后减去 (7-dayOfWeek) 天
+ if (Calendar.SUNDAY == dayOfWeek) {
+ cal.add(Calendar.DAY_OF_MONTH, 7);
+ currentDayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
+ }
+
+ // 根据要获取的星期值 - 当前星期值的差值计算需要获取的日期
+ cal.add(Calendar.DATE, dayOfWeek - currentDayOfWeek);
+ return cal.getTime();
+ }
+
+ /**
+ * 获取下周指定星期天数
+ *
+ * @param date
+ * @param dayOfWeek
+ * @return
+ */
+ public static Date getDateOfNextWeek(Date date, int dayOfWeek) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(getDateOfThisWeek(date, dayOfWeek));
+ cal.add(Calendar.DATE, 7);
+ return cal.getTime();
+ }
+
+ /**
+ * 获取上周指定星期天数
+ *
+ * @param date
+ * @param dayOfWeek
+ * @return
+ */
+ public static Date getDateOfLastWeek(Date date, int dayOfWeek) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(getDateOfThisWeek(date, dayOfWeek));
+ cal.add(Calendar.DATE, -7);
+ return cal.getTime();
+ }
+
+ /**
+ * 获取指定时区的凌晨零点
+ * @param timeZoneId
+ * @return
+ */
+ public static Date getDayBegin(Date date, String timeZoneId) {
+ SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_001);
+ sdf.setLenient(false);
+ sdf.setTimeZone(TimeZone.getTimeZone(timeZoneId));
+ String dateString = sdf.format(date);
+ try {
+ return sdf.parse(dateString);
+ } catch (ParseException e) {
+ return null;
+ }
+ }
+
+ /**
+ * 获取n天前
+ * @param days
+ * @return
+ */
+ public static Date getDaysBefore(Date date, int days) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ cal.add(Calendar.DATE, - days);
+ return cal.getTime();
+ }
+
+ /**
+ * 带时区解析日期 结果为服务器时区时间
+ * @param date yyyy-MM-dd
+ * @param zoneId
+ * @return
+ */
+ public static Date parserWithZone(String date, String zoneId) {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT_001);
+ simpleDateFormat.setLenient(false);
+ simpleDateFormat.setTimeZone(TimeZone.getTimeZone(zoneId));
+ try {
+ return simpleDateFormat.parse(date);
+ } catch (ParseException e) {
+ return null;
+ }
+ }
+
+
+ // ---------------------------------------- Private 函数 ------------------------------------------
+
+ /**
+ * Add Date并且返回一个新的日历对象
+ */
+ private static Date addDate(Date date, int calendarField, int amount) {
+ if (date == null) {
+ throw new IllegalArgumentException("The date must not be null");
+ }
+
+ Calendar c = Calendar.getInstance();
+ c.setTime(date);
+ c.add(calendarField, amount);
+ return c.getTime();
+ }
+}
\ No newline at end of file
diff --git a/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/log/DigestValue.java b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/log/DigestValue.java
new file mode 100644
index 0000000..8e31fce
--- /dev/null
+++ b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/log/DigestValue.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2004-2024 All Rights Reserved.
+ */
+package electromagnetic.data.framework.share.log;
+
+import java.lang.annotation.*;
+
+/**
+ * @author wsk
+ * @version $Id: DigestValue.java, v 0.1 2024-10-20 18:47 wsk
+ */
+@Documented
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DigestValue {
+
+ /**
+ * 顺序号(默认0,表示不指定顺序,按字段顺序排序)
+ *
+ * @return
+ */
+ int value() default 0;
+
+ /**
+ * 脱敏类型
+ *
+ * @return
+ */
+ Class extends Shield> shieldType() default Shield.class;
+}
\ No newline at end of file
diff --git a/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/log/LogDigestBaseInfo.java b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/log/LogDigestBaseInfo.java
new file mode 100644
index 0000000..21c299b
--- /dev/null
+++ b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/log/LogDigestBaseInfo.java
@@ -0,0 +1,157 @@
+/**
+ * Copyright (c) 2004-2024 All Rights Reserved.
+ */
+package electromagnetic.data.framework.share.log;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.Date;
+
+/**
+ * @author wsk
+ * @version $Id: LogDigestBaseInfo.java, v 0.1 2024-10-20 18:45 wsk
+ */
+public class LogDigestBaseInfo {
+
+ /** 服务门面 */
+ private String facadeName;
+
+ /** 服务方法 */
+ private String methodName;
+
+ /** 调用方应用名 */
+ private String appName;
+
+ /** 调用方主机ip */
+ private String hostIp;
+
+ /** traceId */
+ private String traceId;
+
+ /** 服务开始时间 */
+ private final long startTime;
+
+ /**
+ * 默认构造函数
+ */
+ public LogDigestBaseInfo() {
+ this.startTime = System.currentTimeMillis();
+ }
+
+ /**
+ * @see Object#toString()
+ */
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+
+ /**
+ * 获取yyyyMMddHHmmssSSS格式的开始时间字符串
+ *
+ * @return
+ */
+ public String getStartDateFormat() {
+ return DateUtil.getFormatDate(new Date(startTime), "yyyyMMddHHmmssSSS");
+ }
+
+ /**
+ * Getter method for property facadeName.
+ *
+ * @return property value of facadeName
+ */
+ public String getFacadeName() {
+ return facadeName;
+ }
+
+ /**
+ * Setter method for property facadeName.
+ *
+ * @param facadeName value to be assigned to property facadeName
+ */
+ public void setFacadeName(String facadeName) {
+ this.facadeName = facadeName;
+ }
+
+ /**
+ * Getter method for property methodName.
+ *
+ * @return property value of methodName
+ */
+ public String getMethodName() {
+ return methodName;
+ }
+
+ /**
+ * Setter method for property methodName.
+ *
+ * @param methodName value to be assigned to property methodName
+ */
+ public void setMethodName(String methodName) {
+ this.methodName = methodName;
+ }
+
+ /**
+ * Getter method for property appName.
+ *
+ * @return property value of appName
+ */
+ public String getAppName() {
+ return appName;
+ }
+
+ /**
+ * Setter method for property appName.
+ *
+ * @param appName value to be assigned to property appName
+ */
+ public void setAppName(String appName) {
+ this.appName = appName;
+ }
+
+ /**
+ * Getter method for property hostIp.
+ *
+ * @return property value of hostIp
+ */
+ public String getHostIp() {
+ return hostIp;
+ }
+
+ /**
+ * Setter method for property hostIp.
+ *
+ * @param hostIp value to be assigned to property hostIp
+ */
+ public void setHostIp(String hostIp) {
+ this.hostIp = hostIp;
+ }
+
+ /**
+ * Getter method for property traceId.
+ *
+ * @return property value of traceId
+ */
+ public String getTraceId() {
+ return traceId;
+ }
+
+ /**
+ * Setter method for property traceId.
+ *
+ * @param traceId value to be assigned to property traceId
+ */
+ public void setTraceId(String traceId) {
+ this.traceId = traceId;
+ }
+
+ /**
+ * Getter method for property startTime.
+ *
+ * @return property value of startTime
+ */
+ public long getStartTime() {
+ return startTime;
+ }
+}
\ No newline at end of file
diff --git a/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/log/LogUtils.java b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/log/LogUtils.java
new file mode 100644
index 0000000..bd3f1e4
--- /dev/null
+++ b/electromagnetic-framework/src/main/java/electromagnetic/data/framework/share/log/LogUtils.java
@@ -0,0 +1,455 @@
+/**
+ * Copyright (c) 2004-2024 All Rights Reserved.
+ */
+package electromagnetic.data.framework.share.log;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Field;
+import java.text.DateFormat;
+import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * @author wsk
+ * @version $Id: LogUtils.java, v 0.1 2024-10-20 18:37 wsk
+ */
+@Slf4j
+public class LogUtils {
+
+ /** 资产交换报文日志 */
+ private static final Logger LOGGER = LoggerFactory.getLogger(LogUtils.class);
+
+ /** 摘要日志的内容分隔符 */
+ public static final String SEP = ",";
+
+ /** 修饰符 */
+ private static final char RIGHT_TAG = ']';
+
+ /** 修饰符 */
+ private static final char LEFT_TAG = '[';
+
+
+ /** 全日志模式 */
+ private static boolean printAllMode = false;
+
+ /** 格式化开始符号 */
+ public static final String FMT_BEGIN = "[(";
+
+ /** 格式化中间符号 */
+ public static final String FMT_MIDDLE = ")(";
+
+ /** 格式化结束符号 */
+ public static final String FMT_END = ")]";
+
+ /** 数组开始符号 */
+ public static final String ARR_BEGIN = "[";
+
+ /** 数组结束符号 */
+ public static final String ARR_END = "]";
+
+ /** 毫秒 */
+ public static final String MS = "ms";
+
+ /** 没有值时日志上以-替代 */
+ public static final String NONE = "-";
+
+ /** 逗号 */
+ public static final String COMMA = ",";
+
+ /** 点号 */
+ public static final String DOT = ".";
+
+ /** 业务成功标识 */
+ public static final String YES = "Y";
+
+ /** 业务失败标识 */
+ public static final String NO = "N";
+
+ /** 下划线 */
+ public static final String UNDERLINE = "_";
+
+ /** 未知错误 */
+ public static final String UNKNOW_ERROR = "UNKNOW_ERROR";
+
+ /** 完整日期格式 */
+ private final static String FULL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
+
+ /**
+ * 屏蔽构造函数
+ */
+ private LogUtils() {}
+
+ /**
+ *
+ * 生成通知级别日志
+ *
+ *
+ * 根据带参数的日志模板和参数集合,生成info级别日志
+ * 带参数的日志模板中以{数字}表示待替换为变量的日志点,如a={0},表示用参数集合中index为0的参数替换{0}处
+ *
+ *
+ * @param logger logger引用
+ * @param model 带参数的日志模板
+ * @param parameters 参数集合
+ */
+ public static void info(Logger logger, String model, Object... parameters) {
+ if (logger.isInfoEnabled()) {
+ logger.info(MessageFormat.format(model,parameters));
+ }
+ }
+
+ /**
+ * 打印info级别日志信息(适用于没有参数场景下)
+ *
+ * @param logger logger引用
+ * @param message 日志信息
+ */
+ public static void info(Logger logger, String message) {
+ logger.info(message);
+ }
+
+ /**
+ *
+ * 生成调试级别日志
+ *
+ *
+ * 根据带参数的日志模板和参数集合,生成debug级别日志
+ * 带参数的日志模板中以{数字}表示待替换为变量的日志点,如a={0},表示用参数集合中index为0的参数替换{0}处
+ *
+ *
+ * @param logger logger引用
+ * @param model 带参数的日志模板
+ * @param parameters 参数集合
+ */
+ public static void debug(Logger logger, String model, Object... parameters) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(MessageFormat.format(model,parameters));
+ }
+ }
+
+ /**
+ *
+ * 生成警告级别日志
+ *
+ *
+ * 根据带参数的日志模板和参数集合,生成warn级别日志
+ * 带参数的日志模板中以{数字}表示待替换为变量的日志点,如a={0},表示用参数集合中index为0的参数替换{0}处
+ *
+ *
+ * @param logger logger引用
+ * @param model 带参数的日志模板
+ * @param parameters 参数集合
+ */
+ public static void warn(Logger logger, String model, Object... parameters) {
+ if (logger.isWarnEnabled()) {
+ logger.warn(MessageFormat.format(model,parameters));
+ }
+ }
+
+ /**
+ *
+ * 生成警告级别日志
+ *
+ *
+ * 带异常堆栈
+ *
+ *
+ * @param e
+ * @param logger
+ * @param template
+ * @param parameters
+ */
+ public static void warn(Throwable e, Logger logger, String template, Object... parameters) {
+ if (logger.isWarnEnabled()) {
+ logger.warn(MessageFormat.format(template,parameters),e);
+ }
+ }
+
+ /**
+ *
+ * 生成错误级别日志
+ *
+ *
+ * 根据带参数的日志模板和参数集合,生成error级别日志
+ * 带参数的日志模板中以{数字}表示待替换为变量的日志点,如a={0},表示用参数集合中index为0的参数替换{0}处
+ *
+ *
+ * @param e 错误异常堆栈
+ * @param logger logger引用
+ * @param template 带参数的日志模板
+ * @param parameters 参数集合
+ */
+ public static void error(Throwable e, Logger logger, String template, Object... parameters) {
+ if (logger.isErrorEnabled()) {
+ logger.error(MessageFormat.format(template,parameters),e);
+ }
+ }
+
+ /**
+ *
+ * 生成错误级别日志
+ *
+ *
+ * 根据带参数的日志模板和参数集合,生成error级别日志
+ * 带参数的日志模板中以{数字}表示待替换为变量的日志点,如a={0},表示用参数集合中index为0的参数替换{0}处
+ *
+ *
+ * @param logger logger引用
+ * @param model 带参数的日志模板
+ * @param parameters 参数集合
+ */
+ public static void error(Logger logger, String model, Object... parameters) {
+ if (logger.isErrorEnabled()) {
+ logger.error(MessageFormat.format(model,parameters));
+ }
+ }
+
+ /**
+ * 打印error日志。
+ *
+ * ERROR日志记录尽量使用{@link },避免日志的重复记录
+ *
+ * @param logger 日志对象
+ * @param e 异常信息
+ * @param objs 任意个要输出到日志的参数
+ */
+ public static void error(Logger logger, Throwable e, Object... objs) {
+ logger.error(getLogString(objs), e);
+ }
+
+ /**
+ * 生成输出到日志的字符串
+ *
+ * @param objs 任意个要输出到日志的参数
+ * @return 日志字符串
+ */
+ public static String getLogString(Object... objs) {
+ StringBuilder log = new StringBuilder();
+ log.append(LEFT_TAG);
+// log.append(fetchInvokeId()).append(SEP);
+// log.append(fetchLoadTestStamp()).append(SEP);
+// log.append(fetchTntInstId()).append(SEP);
+ // 预留扩展位
+ log.append(SEP).append(RIGHT_TAG);
+
+ if (objs != null) {
+ for (Object o : objs) {
+ log.append(o);
+ }
+ }
+ return log.toString();
+ }
+
+ /**
+ * 全日志模式日志输出
+ *
+ * @param object 待输出日志对象
+ * @return 输出日志
+ */
+ public static String objectToLog(Object object) {
+ if (object == null) {
+ return null;
+ }
+
+ if (printAllMode) {
+ return ReflectionToStringBuilder.toString(object, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+
+ return object.toString();
+ }
+
+ /**
+ * 生成用于唯一标识一次业务调用流程的uuid
+ *
+ * 调用场景只有两处:
+ * 外部接口入口处
+ * 异步任务入口处
+ *
+ *
+ * @param pdSeqNo 业务流水号
+ * @return uuid
+ */
+ public static String generateBusinessFlowUUID(String pdSeqNo) {
+ return String.format("%s-%s", pdSeqNo, UUID.randomUUID().toString());
+ }
+
+
+ /**
+ * 对dal-digest日志进行格式化: [(tracerId)(dsId,call.method,Y,1ms)]
+ * @param dsId 数据源id
+ * @param method 方法
+ * @param hasError 是否有异常
+ * @param elapseTimeInMillis 时间in ms
+ * @return 格式化串
+ */
+ public static void logDALDigest(Logger logger, String dsId, String method, boolean hasError,
+ long elapseTimeInMillis, long dataSize) {
+ if (logger.isInfoEnabled()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(FMT_BEGIN);
+
+ sb.append(ifBlank(dsId)).append(COMMA).append(method).append(COMMA)
+ .append(hasError ? NO : YES).append(COMMA).append(elapseTimeInMillis).append(MS)
+ .append(COMMA).append(dataSize).append(COMMA).append(FMT_END);
+ logger.info(sb.toString());
+ }
+ }
+
+ /**
+ * 对第三方调用日志进行格式化: [(tracerId)(dsId,call.method,Y,1ms)]
+ *
+ * @param classMethod 方法
+ * @param success 是否处理成功
+ * @param errorCode 错误码
+ * @param spendTime 时间in ms
+ * @return 格式化串
+ */
+ public static void logSalDigest(Logger logger, String classMethod, boolean success, String errorCode,
+ long spendTime, String request, String result) {
+ if (logger.isInfoEnabled()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(FMT_BEGIN);
+ sb.append(ifBlank(classMethod)).append(COMMA).append(success ? "Y" : "N").append(COMMA)
+ .append(ifBlank(errorCode)).append(COMMA).append(String.valueOf(spendTime))
+ .append(COMMA).append(FMT_MIDDLE);
+
+ sb.append(ifBlank(request)).append(COMMA).append(FMT_MIDDLE);
+
+ sb.append(ifBlank(result)).append(COMMA).append(FMT_END);
+
+ logger.info(sb.toString());
+ }
+ }
+
+ /**
+ * 打印API-DIGEST日志
+ *
+ * @param baseInfo
+ * @param success
+ * @param errorCode
+ * @param spendTime
+ * @param request
+ * @param result
+ */
+ public static void logApiDigest(LogDigestBaseInfo baseInfo, boolean success, String errorCode,
+ long spendTime, String request, String result) {
+ if (LOGGER.isInfoEnabled()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(FMT_BEGIN);
+ sb.append(ifBlank(baseInfo.getTraceId())).append(FMT_MIDDLE);
+ sb.append(ifBlank(baseInfo.getFacadeName())).append(DOT)
+ .append(ifBlank(baseInfo.getMethodName()));
+ sb.append(COMMA).append(success ? "Y" : "N").append(COMMA).append(ifBlank(errorCode))
+ .append(COMMA).append(String.valueOf(spendTime));
+ sb.append(COMMA).append(ifBlank(baseInfo.getStartDateFormat())).append(COMMA)
+ .append(ifBlank(baseInfo.getAppName())).append(COMMA)
+ .append(ifBlank(baseInfo.getHostIp())).append(COMMA).append(FMT_MIDDLE);
+
+ sb.append(ifBlank(request)).append(COMMA).append(FMT_MIDDLE);
+
+ sb.append(ifBlank(result)).append(COMMA).append(FMT_END);
+
+ LOGGER.info(sb.toString());
+ }
+ }
+
+ /**
+ * 入参为null或者空串时,返回"-",否则返回自身
+ *
+ * @param value 入参字符串
+ * @return 入参为null或者空串时, 返回"-",否则返回自身
+ */
+ private static String ifBlank(String value) {
+ return StringUtils.isBlank(value) ? NONE : value;
+ }
+
+ /**
+ * 获取摘要日志
+ *
+ * @return
+ */
+ public static String getDigestLog(Object obj) {
+ if (null == obj) {
+ return NONE;
+ }
+
+ List> digestValueList = Lists.newArrayList();
+
+ Collections.sort(retrieveDigestValues(obj, obj.getClass(), digestValueList), DIGEST_VALUE_SORTER);
+
+ Object[] digestValues = new Object[digestValueList.size()];
+ int i = 0;
+ for (Map.Entry