做系统的关键操作的日志功能

xiaoxiao2021-02-28  62

问题:

项目系统需要记录用户的关键操作日志,以便后期的系统维护,方便的查看问题,及时排除等原因。

分析:

作为一个日志记录功能,首先数据库新建一张表保存用户的操作关键字段,用户名,ip,操作描述,时间,日志id

采用技术:

第一种:新建一个日志业务实现,在操作发生时进行联动同,缺点是耦合太紧密,无用代码增多,后期代码臃肿,改动时地方分散,不利于维护

第二种:使用spring 的 aop 技术进行切面切入由于本身系统结构不规范,参数,方法名没有一致的样式,使用正则匹配方法名不是很方便,本身日志记录也只是记录关键操作,api全部切入的话,就不需要这个功能了,必须有针对性的记录关键操作日志

第三种:使用spring 的 aop技术切到自定义注解上,针对不同注解标志进行参数解析,记录日志,缺点是要针对每个不同的注解标志进行分别取注解标志,获取参数进行日志记录输出

采用第三种方法

思路

1. 通过自定义注解,注解到需要aop切入的方法上 2. 声明一个aspect切入面,注入数据层dao, 将上面的注解类设成切入点, 通过反射获取到自定义注解上的某个属性,来区分是不同的记录日志需求。进行不同程度的封装Log实体对象。 3. 然后通过数据层,写入到日志表。

步骤

自定义方法注解类,注解到方法上,用于标识需要切入的点 /** * 日志切面注解 */ @Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MethodLog { /** * 该注解作用于方法上时需要备注信息 */ String remark() default ""; String operType() default "0"; } 切面的实现 /** * 日志切面实现 */ @Component @Aspect public class LogService { @Autowired private OptLogDao dao; public LogService() { System.out.println("Aop"); } /** * 切点 */ @Pointcut("@annotation(com.education.anno.MethodLog)") public void methodCachePointcut() { } /** * 切面 * * @param point * @return * @throws Throwable */ @Around("methodCachePointcut()") public Object around(ProceedingJoinPoint point) throws Throwable { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder .getRequestAttributes()).getRequest(); String ip = getIp(request); User user = UserUtil.getCurrentUser(); String methodRemark = getMthodRemark(point); Object[] method_param; Object object; try { method_param = point.getArgs(); //获取方法参数 // String param=(String) point.proceed(point.getArgs()); object = point.proceed(); } catch (Exception e) { // 异常处理记录日志..log.error(e); throw e; } LiveOptLog optLog = new LiveOptLog(); optLog.setUserId(user.getId().intValue()); optLog.setIp(ip); optLog.setUserName(user.getUsername()); /** * 课程操作 */ if ("新增课程".equals(methodRemark) || "修改课程".equals(methodRemark) || "删除课程".equals(methodRemark)) { if (method_param[0] instanceof LiveCourseInfo) { LiveCourseInfo courseInfo = (LiveCourseInfo) method_param[0]; optLog.setDescription("用户 " + user.getUsername() + " " + methodRemark + "id: " + courseInfo.getId()); } } /** * 课节操作 */ if ("新增课节".equals(methodRemark) || "修改课节".equals(methodRemark) || "删除课节".equals(methodRemark)) { if (method_param[0] instanceof LiveCourseLessonInfo) { LiveCourseLessonInfo lessonInfo = (LiveCourseLessonInfo) method_param[0]; optLog.setDescription("用户 " + user.getUsername() + " " + methodRemark + "id: " + lessonInfo.getId()); } } dao.insertSelective(optLog); return object; } /** * 获取请求ip * * @param request * @return */ public static String getIp(HttpServletRequest request) { String ip = request.getHeader("X-Forwarded-For"); if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) { int index = ip.indexOf(","); if (index != -1) { return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip.substring(0, index); } else { return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip; } } ip = request.getHeader("X-Real-IP"); if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) { return ip; } return request.getRemoteAddr().equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip; } /** * 获取方法中的中文备注 * * @param joinPoint * @return * @throws Exception */ public static String getMthodRemark(ProceedingJoinPoint joinPoint) throws Exception { String targetName = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs(); Class targetClass = Class.forName(targetName); Method[] method = targetClass.getMethods(); String methode = ""; for (Method m : method) { if (m.getName().equals(methodName)) { Class[] tmpCs = m.getParameterTypes(); if (tmpCs.length == arguments.length) { MethodLog methodCache = m.getAnnotation(MethodLog.class); if (methodCache != null) { methode = methodCache.remark(); } break; } } } return methode; } 日志实体, 根据需求自定义 @Table(name = "opt_log") @Data @NoArgsConstructor @AllArgsConstructor @ExcelTitles({"序号", "ID" ,"操作人","描述", "时间", "IP"}) public class LiveOptLog extends BaseModel { /** * 日志类型 */ private String type; /** * 用户id */ @Column(name = "user_id") private Integer userId; @Column(name = "user_name") private String userName; /** * 内容 */ private String description; private String ip; private Date createtime; } 日志切入, 添加注解 @PostMapping @ApiOperation(value = "保存") @MethodLog(remark = "新增课程") public CourseInfo save(@RequestBody CourseInfo courseInfo) { courseInfoServiceImpl.save(courseInfo); return courseInfo; } 加入springboot配置 <!--spring切面aop依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> 在application.properties文件里加这样一条配置 spring.aop.auto=true 在springboot项目里加这两条配置即可,就可以开启aop功能

ok, 这样每次执行想要拦截关键日志的操作都会被切面拦截

转载请注明原文地址: https://www.6miu.com/read-2612466.html

最新回复(0)