diff --git a/business/src/main/java/com/fizz/business/anno/MyLog.java b/business/src/main/java/com/fizz/business/anno/MyLog.java new file mode 100644 index 0000000..6355495 --- /dev/null +++ b/business/src/main/java/com/fizz/business/anno/MyLog.java @@ -0,0 +1,27 @@ +package com.fizz.business.anno; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义注解记录系统操作日志 + */ +//Target注解决定 MyLog 注解可以加在哪些成分上,如加在类身上,或者属性身上,或者方法身上等成分 +@Target({ ElementType.PARAMETER, ElementType.METHOD }) +//Retention注解括号中的"RetentionPolicy.RUNTIME"意思是让 MyLog 这个注解的生命周期一直程序运行时都存在 +@Retention(value = RetentionPolicy.RUNTIME) +public @interface MyLog { + /** + * 模块标题 + */ + String title() default ""; + + /** + * 日志内容 + */ + String content() default ""; +} + diff --git a/business/src/main/java/com/fizz/business/aop/OperLogAspect.java b/business/src/main/java/com/fizz/business/aop/OperLogAspect.java new file mode 100644 index 0000000..5bf09a6 --- /dev/null +++ b/business/src/main/java/com/fizz/business/aop/OperLogAspect.java @@ -0,0 +1,245 @@ +package com.fizz.business.aop; + +import com.alibaba.fastjson2.JSON; +import com.fizz.business.anno.MyLog; +import com.fizz.business.domain.LogData; +import com.fizz.business.service.LogDataService; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.*; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; + +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +@Aspect +@Component +public class OperLogAspect { + @Autowired + private LogDataService operLogService; + //为了记录方法的执行时间 + ThreadLocal startTime = new ThreadLocal<>(); + /** + * 设置操作日志切入点,这里介绍两种方式: + * 1、基于注解切入(也就是打了自定义注解的方法才会切入) + * @Pointcut("@annotation(org.wujiangbo.annotation.MyLog)") + * 2、基于包扫描切入 + * @Pointcut("execution(public * org.wujiangbo.controller..*.*(..))") + */ + @Pointcut("@annotation(com.fizz.business.anno.MyLog)")//在注解的位置切入代码 + //@Pointcut("execution(public * org.wujiangbo.controller..*.*(..))")//从controller切入 + public void operLogPoinCut() { + } + @Before("operLogPoinCut()") + public void beforMethod(JoinPoint point){ + startTime.set(System.currentTimeMillis()); + } + /** + * 设置操作异常切入点记录异常日志 扫描所有controller包下操作 + */ + @Pointcut("execution(* com.fizz.business.controller..*.*(..))") + public void operExceptionLogPoinCut() { + } + /** + * 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行 + * + * @param joinPoint 切入点 + * @param result 返回结果 + */ + @AfterReturning(value = "operLogPoinCut()", returning = "result") + public void saveOperLog(JoinPoint joinPoint, Object result) { + // 获取RequestAttributes + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + // 从获取RequestAttributes中获取HttpServletRequest的信息 + HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST); + try { + // 从切面织入点处通过反射机制获取织入点处的方法 + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + // 获取切入点所在的方法 + Method method = signature.getMethod(); + // 获取操作 + MyLog myLog = method.getAnnotation(MyLog.class); + LogData logData = new LogData(); + if (myLog != null) { + logData.setModule(myLog.title());//设置模块名称 + logData.setLogtext(myLog.content());//设置日志内容 + } + // 将入参转换成json + String params = argsArrayToString(joinPoint.getArgs()); + // 获取请求的类名 + String className = joinPoint.getTarget().getClass().getName(); + // 获取请求的方法名 + String methodName = method.getName(); + methodName = className + "." + methodName + "()"; + + logData.setTimestamp(LocalDateTime.now()); + logData.setLogtype("INFORMATION"); + logData.setStatus(0); + logData.setConfirmTime(LocalDateTime.now()); + +// operlog.setMethod(methodName); //设置请求方法 +// operlog.setRequestMethod(request.getMethod());//设置请求方式 +// operlog.setRequestParam(params); // 请求参数 +// operlog.setResponseResult(JSON.toJSONString(result)); // 返回结果 +// operlog.setOperName("张三"); // 获取用户名(真实环境中,肯定有工具类获取当前登录者的账号或ID的,或者从token中解析而来) +// operlog.setIp(getIp(request)); // IP地址 +// operlog.setIpLocation("湖北武汉"); // IP归属地(真是环境中可以调用第三方API根据IP地址,查询归属地) +// operlog.setRequestUrl(request.getRequestURI()); // 请求URI +// operlog.setOperTime(new Date()); // 时间 +// operlog.setStatus(0);//操作状态(0正常 1异常) +// Long takeTime = System.currentTimeMillis() - startTime.get();//记录方法执行耗时时间(单位:毫秒) +// operlog.setTakeTime(takeTime); + //插入数据库 + operLogService.save(logData); + } catch (Exception e) { + e.printStackTrace(); + } + } + /** + * 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行 + */ + @AfterThrowing(pointcut = "operExceptionLogPoinCut()", throwing = "e") + public void saveExceptionLog(JoinPoint joinPoint, Throwable e) { + // 获取RequestAttributes +// RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); +// // 从获取RequestAttributes中获取HttpServletRequest的信息 +// HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST); +// LogData logData = new LogData(); +// try { +// // 从切面织入点处通过反射机制获取织入点处的方法 +// MethodSignature signature = (MethodSignature) joinPoint.getSignature(); +// // 获取切入点所在的方法 +// Method method = signature.getMethod(); +// // 获取请求的类名 +// String className = joinPoint.getTarget().getClass().getName(); +// // 获取请求的方法名 +// String methodName = method.getName(); +// methodName = className + "." + methodName + "()"; +// // 获取操作 +// MyLog myLog = method.getAnnotation(MyLog.class); +// if (myLog != null) { +// logData.setModule(myLog.title());//设置模块名称 +// logData.setLogtext(myLog.content());//设置日志内容 +// } +// // 将入参转换成json +// String params = argsArrayToString(joinPoint.getArgs()); +// operlog.setMethod(methodName); //设置请求方法 +// operlog.setRequestMethod(request.getMethod());//设置请求方式 +// operlog.setRequestParam(params); // 请求参数 +// operlog.setOperName("张三"); // 获取用户名(真实环境中,肯定有工具类获取当前登录者的账号或ID的,或者从token中解析而来) +// operlog.setIp(getIp(request)); // IP地址 +// operlog.setIpLocation("湖北武汉"); // IP归属地(真是环境中可以调用第三方API根据IP地址,查询归属地) +// operlog.setRequestUrl(request.getRequestURI()); // 请求URI +// operlog.setOperTime(new Date()); // 时间 +// operlog.setStatus(1);//操作状态(0正常 1异常) +// operlog.setErrorMsg(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));//记录异常信息 +// //插入数据库 +// operLogService.insert(operlog); +// } catch (Exception e2) { +// e2.printStackTrace(); +// } + } + /** + * 转换异常信息为字符串 + */ + public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) { + StringBuffer strbuff = new StringBuffer(); + for (StackTraceElement stet : elements) { + strbuff.append(stet + "\n"); + } + String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString(); + message = substring(message,0 ,2000); + return message; + } + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray) + { + String params = ""; + if (paramsArray != null && paramsArray.length > 0) + { + for (Object o : paramsArray) + { + if (o != null) + { + try + { + Object jsonObj = JSON.toJSON(o); + params += jsonObj.toString() + " "; + } + catch (Exception e) + { + e.printStackTrace(); + } + } + } + } + return params.trim(); + } + //字符串截取 + public static String substring(String str, int start, int end) { + if (str == null) { + return null; + } else { + if (end < 0) { + end += str.length(); + } + if (start < 0) { + start += str.length(); + } + if (end > str.length()) { + end = str.length(); + } + if (start > end) { + return ""; + } else { + if (start < 0) { + start = 0; + } + if (end < 0) { + end = 0; + } + return str.substring(start, end); + } + } + } + /** + * 转换request 请求参数 + * @param paramMap request获取的参数数组 + */ + public Map converMap(Map paramMap) { + Map returnMap = new HashMap<>(); + for (String key : paramMap.keySet()) { + returnMap.put(key, paramMap.get(key)[0]); + } + return returnMap; + } + + //根据HttpServletRequest获取访问者的IP地址 + public static String getIp(HttpServletRequest request) { + String ip = request.getHeader("x-forwarded-for"); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + return ip; + } +} diff --git a/business/src/main/java/com/fizz/business/comm/OPC/MessageSubscriptionRunner.java b/business/src/main/java/com/fizz/business/comm/OPC/MessageSubscriptionRunner.java index 9a5dfa6..6c4b86d 100644 --- a/business/src/main/java/com/fizz/business/comm/OPC/MessageSubscriptionRunner.java +++ b/business/src/main/java/com/fizz/business/comm/OPC/MessageSubscriptionRunner.java @@ -1,8 +1,10 @@ package com.fizz.business.comm.OPC; +import com.fizz.business.anno.MyLog; import com.fizz.business.constants.enums.ExitCutTypeEnum; import com.fizz.business.constants.enums.OpcMessageType; import com.fizz.business.domain.msg.*; +import com.fizz.business.service.LogDataService; import com.fizz.business.service.hanle.OpcReceiverHandler; import com.kangaroohy.milo.model.ReadWriteEntity; import com.kangaroohy.milo.service.MiloService; @@ -24,7 +26,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import static com.fizz.business.service.manager.OpcMessageIdsManager.*; -//@Component +@Component @Slf4j public class MessageSubscriptionRunner implements ApplicationRunner { @@ -33,6 +35,9 @@ public class MessageSubscriptionRunner implements ApplicationRunner { @Resource private OpcReceiverHandler opcReceiverHandler; + @Resource + private LogDataService logDataService; + @Override public void run(ApplicationArguments args) { sub(); @@ -81,6 +86,7 @@ public class MessageSubscriptionRunner implements ApplicationRunner { EntryMovementMessage msg =new EntryMovementMessage(); writeMessage( msg,entryMoveIds); log.info("接收入口移动信号:从 {} 移动到 {} ", msg.getMaterialPlaceSource(), msg.getMaterialPlaceDestination()); + logDataService.logInfo("TRACK","接收入口移动信号:从 {} 移动到 {} ", msg.getMaterialPlaceSource(), msg.getMaterialPlaceDestination()); //opcReceiverHandler.onMessageReceived(OpcMessageType.ENTRY_MOVEMENT,msg); } catch (Exception e) { } @@ -92,6 +98,7 @@ public class MessageSubscriptionRunner implements ApplicationRunner { ExitCutMessage msg = new ExitCutMessage(); writeMessage( msg,exitCutIds); log.info("接收到出口剪切信号:剪切类型 {},剪切长度{} ", msg.getCutType().toString(), msg.getCutLength()); + logDataService.logInfo("TRACK","接收到出口剪切信号:剪切类型 {},剪切长度{} ", msg.getCutType().toString(), msg.getCutLength()); // opcReceiverHandler.onMessageReceived(OpcMessageType.EXIT_CUT,msg); } catch (Exception e) { } @@ -103,6 +110,7 @@ public class MessageSubscriptionRunner implements ApplicationRunner { ExitMovementMessage msg = new ExitMovementMessage(); writeMessage( msg,exitMoveIds); log.info("接收出口移动信号:从 {} 移动到 {} ", msg.getExSrc(), msg.getExDesc()); + logDataService.logInfo("TRACK","接收出口移动信号:从 {} 移动到 {} ", msg.getExSrc(), msg.getExDesc()); // opcReceiverHandler.onMessageReceived(OpcMessageType.EXIT_MOVEMENT,msg); } catch (Exception e) { } @@ -114,6 +122,7 @@ public class MessageSubscriptionRunner implements ApplicationRunner { ExitMeasureMessage msg = new ExitMeasureMessage(); writeMessage(msg,exitMoveIds); log.info("接收出口称重信号:重量 {} ", msg.getWeight()); + logDataService.logInfo("TRACK","接收出口称重信号:重量 {} ", msg.getWeight()); // opcReceiverHandler.onMessageReceived(OpcMessageType.EXIT_MEASURE,msg); } catch (Exception e) { } diff --git a/business/src/main/java/com/fizz/business/domain/LogData.java b/business/src/main/java/com/fizz/business/domain/LogData.java index 8a8f654..d864999 100644 --- a/business/src/main/java/com/fizz/business/domain/LogData.java +++ b/business/src/main/java/com/fizz/business/domain/LogData.java @@ -61,7 +61,7 @@ public class LogData { @Schema(description ="confirmTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") - private Date confirmTime; + private LocalDateTime confirmTime; } \ No newline at end of file diff --git a/business/src/main/java/com/fizz/business/service/LogDataService.java b/business/src/main/java/com/fizz/business/service/LogDataService.java index 513f27d..65e89b0 100644 --- a/business/src/main/java/com/fizz/business/service/LogDataService.java +++ b/business/src/main/java/com/fizz/business/service/LogDataService.java @@ -23,4 +23,18 @@ public interface LogDataService extends IService { * @param seqid */ void alarmAck(Integer seqid); + + /** + * 记录日志 + * @param module + * @param content + */ + void logInfo(String module,String content, Object... args); + + /** + * 记录日志 + * @param module + * @param content + */ + void logWarn(String module,String content, Object... args); } diff --git a/business/src/main/java/com/fizz/business/service/impl/LogDataServiceImpl.java b/business/src/main/java/com/fizz/business/service/impl/LogDataServiceImpl.java index 946cb9d..0423a02 100644 --- a/business/src/main/java/com/fizz/business/service/impl/LogDataServiceImpl.java +++ b/business/src/main/java/com/fizz/business/service/impl/LogDataServiceImpl.java @@ -73,4 +73,61 @@ public class LogDataServiceImpl extends ServiceImpl impl .eq(LogData::getSeqid, seqid) .update(); } + + @Override + public void logInfo(String module, String content, Object... args) { + if (args.length > 0) { + content = formatMessage(content, args); + } + saveLogData("INFORMATION",module, content); + } + + @Override + public void logWarn(String module, String content, Object... args) { + if (args.length > 0) { + content = formatMessage(content, args); + } + saveLogData("WARN",module, content); + } + private void saveLogData(String logType,String module, String content){ + LogData logData = new LogData(); + logData.setModule(module);//设置模块名称 + logData.setLogtext(content);//设置日志内容 + logData.setTimestamp(LocalDateTime.now()); + logData.setLogtype(logType); + logData.setStatus(0); + logData.setConfirmTime(LocalDateTime.now()); + save(logData); + } + + private String formatMessage(String pattern, Object[] arguments) { + if (pattern == null) { + return null; + } + if (arguments == null || arguments.length == 0) { + return pattern; + } + + StringBuilder sb = new StringBuilder(); + int argIndex = 0; + int i = 0; + + while (i < pattern.length()) { + char c = pattern.charAt(i); + if (c == '{' && i + 1 < pattern.length() && pattern.charAt(i + 1) == '}') { + if (argIndex < arguments.length) { + sb.append(String.valueOf(arguments[argIndex++])); + } else { + sb.append("{}"); + } + i += 2; + } else { + sb.append(c); + i++; + } + } + + return sb.toString(); + } + } \ No newline at end of file