diff --git a/ruoyi-common/hwmom-common-mom/pom.xml b/ruoyi-common/hwmom-common-mom/pom.xml new file mode 100644 index 00000000..ca5a8a7b --- /dev/null +++ b/ruoyi-common/hwmom-common-mom/pom.xml @@ -0,0 +1,37 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + hwmom-common-mom + + + hwmom-common-mom 通用功能 + + + + + org.dromara + ruoyi-common-satoken + + + + org.dromara + ruoyi-common-json + + + + org.apache.dubbo + dubbo-spring-boot-starter + provided + + + + + diff --git a/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/annotation/DataSyncPublish.java b/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/annotation/DataSyncPublish.java new file mode 100644 index 00000000..c7f8cdc5 --- /dev/null +++ b/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/annotation/DataSyncPublish.java @@ -0,0 +1,43 @@ +package org.dromara.common.annotation; + +import org.dromara.common.enums.OperatorType; + +import java.lang.annotation.*; + +/** + * 自定义数据同步记录注解 + * + * @author xins + */ +@Target({ElementType.PARAMETER, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataSyncPublish { + /** + * 数据库表名称 + */ + String tableName() default ""; + + + /** + * 操作类型 + */ + OperatorType operatorType() default OperatorType.INSERT; + +// /** +// * 是否保存请求的参数 +// */ +// boolean isSaveRequestData() default true; +// +// /** +// * 是否保存响应的参数 +// */ +// boolean isSaveResponseData() default true; +// +// +// /** +// * 排除指定的请求参数 +// */ +// String[] excludeParamNames() default {}; + +} diff --git a/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/aspect/DataSyncPublishAspect.java b/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/aspect/DataSyncPublishAspect.java new file mode 100644 index 00000000..61a925ef --- /dev/null +++ b/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/aspect/DataSyncPublishAspect.java @@ -0,0 +1,215 @@ +package org.dromara.common.aspect; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.time.StopWatch; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.dromara.common.annotation.DataSyncPublish; +import org.dromara.common.json.utils.JsonUtils; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Collection; +import java.util.Map; +import java.util.StringJoiner; + +/** + * 数据同步记录处理 + * + * @author xins + */ +@Slf4j +@Aspect +@AutoConfiguration +public class DataSyncPublishAspect { + + /** + * 排除敏感属性字段 + */ + public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; + + + /** + * 计时 key + */ + private static final ThreadLocal KEY_CACHE = new ThreadLocal<>(); + + /** + * 处理请求前执行 + */ + @Before(value = "@annotation(dataSyncPublish)") + public void doBefore(JoinPoint joinPoint, DataSyncPublish dataSyncPublish) { + StopWatch stopWatch = new StopWatch(); + KEY_CACHE.set(stopWatch); + stopWatch.start(); + } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(dataSyncPublish)", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, DataSyncPublish dataSyncPublish, Object jsonResult) { + handleDataSyncPublish(joinPoint, dataSyncPublish, null, jsonResult); + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(dataSyncPublish)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, DataSyncPublish dataSyncPublish, Exception e) { + handleDataSyncPublish(joinPoint, dataSyncPublish, e, null); + } + + protected void handleDataSyncPublish(final JoinPoint joinPoint, DataSyncPublish dataSyncPublish, final Exception e, Object jsonResult) { + try { + + System.out.println("dbname:"+dataSyncPublish.tableName()); + System.out.println("operationType:"+dataSyncPublish.operatorType().ordinal()); + String params = this.argsArrayToString(joinPoint.getArgs()); + System.out.println("params:"+params); +// // *========数据库日志=========*// +// OperLogEvent operLog = new OperLogEvent(); +// operLog.setTenantId(LoginHelper.getTenantId()); +// operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); +// // 请求的地址 +// String ip = ServletUtils.getClientIP(); +// operLog.setOperIp(ip); +// operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); +// LoginUser loginUser = LoginHelper.getLoginUser(); +// operLog.setOperName(loginUser.getUsername()); +// operLog.setDeptName(loginUser.getDeptName()); +// +// if (e != null) { +// operLog.setStatus(BusinessStatus.FAIL.ordinal()); +// operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); +// } +// // 设置方法名称 +// String className = joinPoint.getTarget().getClass().getName(); +// String methodName = joinPoint.getSignature().getName(); +// operLog.setMethod(className + "." + methodName + "()"); +// // 设置请求方式 +// operLog.setRequestMethod(ServletUtils.getRequest().getMethod()); +// // 处理设置注解上的参数 +// getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); +// // 设置消耗时间 +// StopWatch stopWatch = KEY_CACHE.get(); +// stopWatch.stop(); +// operLog.setCostTime(stopWatch.getTime()); +// // 发布事件保存数据库 +// SpringUtils.context().publishEvent(operLog); + } catch (Exception exp) { + // 记录本地异常日志 + log.error("异常信息:{}", exp.getMessage()); + exp.printStackTrace(); + } finally { + KEY_CACHE.remove(); + } + } + + /** + * 获取注解中对方法的描述信息 用于Controller层注解 + * + * @param log 日志 + * @param operLog 操作日志 + * @throws Exception + */ +// public void getControllerMethodDescription(JoinPoint joinPoint, DataSyncPublish dataSyncPublish, Object jsonResult) throws Exception { +// // 设置action动作 +// operLog.setBusinessType(log.businessType().ordinal()); +// // 设置标题 +// operLog.setTitle(log.title()); +// // 设置操作人类别 +// operLog.setOperatorType(log.operatorType().ordinal()); +// // 是否需要保存request,参数和值 +// if (log.isSaveRequestData()) { +// // 获取参数的信息,传入到数据库中。 +// setRequestValue(joinPoint, operLog, log.excludeParamNames()); +// } +// // 是否需要保存response,参数和值 +// if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) { +// operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 2000)); +// } +// } + + /** + * 获取请求的参数,放到log中 + * + * @param operLog 操作日志 + * @throws Exception 异常 + */ +// private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception { +// Map paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); +// String requestMethod = operLog.getRequestMethod(); +// if (MapUtil.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name())) { +// String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); +// operLog.setOperParam(StringUtils.substring(params, 0, 2000)); +// } else { +// MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES); +// MapUtil.removeAny(paramsMap, excludeParamNames); +// operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 2000)); +// } +// } + + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray) { + StringJoiner params = new StringJoiner(" "); + if (ArrayUtil.isEmpty(paramsArray)) { + return params.toString(); + } + for (Object o : paramsArray) { + if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { + String str = JsonUtils.toJsonString(o); + Dict dict = JsonUtils.parseMap(str); + if (MapUtil.isNotEmpty(dict)) { + MapUtil.removeAny(dict, EXCLUDE_PROPERTIES); + str = JsonUtils.toJsonString(dict); + } + params.add(str); + } + } + return params.toString(); + } + + /** + * 判断是否需要过滤的对象。 + * + * @param o 对象信息。 + * @return 如果是需要过滤的对象,则返回true;否则返回false。 + */ + @SuppressWarnings("rawtypes") + public boolean isFilterObject(final Object o) { + Class clazz = o.getClass(); + if (clazz.isArray()) { + return MultipartFile.class.isAssignableFrom(clazz.getComponentType()); + } else if (Collection.class.isAssignableFrom(clazz)) { + Collection collection = (Collection) o; + for (Object value : collection) { + return value instanceof MultipartFile; + } + } else if (Map.class.isAssignableFrom(clazz)) { + Map map = (Map) o; + for (Object value : map.values()) { + return value instanceof MultipartFile; + } + } + return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse + || o instanceof BindingResult; + } +} diff --git a/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/enums/OperatorType.java b/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/enums/OperatorType.java new file mode 100644 index 00000000..c000f9a7 --- /dev/null +++ b/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/enums/OperatorType.java @@ -0,0 +1,23 @@ +package org.dromara.common.enums; + +/** + * 操作类型 + * + * @author xins + */ +public enum OperatorType { + /** + * 插入 + */ + INSERT, + + /** + * 更新 + */ + UPDATE, + + /** + * 删除 + */ + DELETE +} diff --git a/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/event/DataSyncPublishEvent.java b/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/event/DataSyncPublishEvent.java new file mode 100644 index 00000000..9246cf04 --- /dev/null +++ b/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/event/DataSyncPublishEvent.java @@ -0,0 +1,34 @@ +package org.dromara.common.event; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 数据同步记录发布事件 + * + * @author xins + */ + +@Data +public class DataSyncPublishEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 数据库表名称 + */ + private String tableName; + + /** + * 操作类型 + */ + private String operationType; + + /** + * 过滤时间(如果是创建,则createtime大于此时间,如果是更新,则updatetime大于此时间) + */ + private String filterTime; +} diff --git a/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/event/DataSyncPublishListener.java b/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/event/DataSyncPublishListener.java new file mode 100644 index 00000000..f32cbbb6 --- /dev/null +++ b/ruoyi-common/hwmom-common-mom/src/main/java/org/dromara/common/event/DataSyncPublishListener.java @@ -0,0 +1,29 @@ +package org.dromara.common.event; + +import cn.hutool.core.bean.BeanUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.dubbo.config.annotation.DubboReference; +import org.dromara.system.api.RemoteLogService; +import org.dromara.system.api.domain.bo.RemoteOperLogBo; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class DataSyncPublishListener { + + @DubboReference + private RemoteLogService remoteLogService; + + /** + * 保存系统日志记录 + */ + @EventListener + public void dataSyncPublish(DataSyncPublishEvent dataSyncPublishEvent) { +// tableName,类型,时间,删除的id; + + } + + + +} diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 48e00955..0feb19b4 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -45,6 +45,7 @@ ruoyi-common-nacos ruoyi-common-bus ruoyi-common-sse + hwmom-common-mom ruoyi-common