现在凡是企业级的或者稍微大点项目,基本都需要日志管理. 我这边在springboot基础上做了个日志信息记录到数据库的功能,在这里备份一下,以后有需要就省的再重写了.
首先我们得准备好所需要的jar,当然了这里是pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
这里的web是最基本的,后面也会用到的.
其实日志管理实现的方式有很多种,拦截器,aop切面等等,我这边用的就是aop切面实现的.既然要用到切面实现,那就必须要有切点,我这边是以自定义注解为切点(当然也可以切到指定路径下的文件夹哦)
下面为自定义切点:
package com.jshh.busness.LogAOP; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) // 这个注解是用来规定注解的作用范围的,这里定义为method方法级别. @Retention(RetentionPolicy.RUNTIME) // 这个注解可以理解为定义注解的生命周期,这里标识一直存在(编译和运行之后) public @interface LogAnnotation { // 定义注解参数 public String operateContent() default ""; public String operateType() default ""; }
这边简单的介绍下@Target和@Retention注解吧.
@Target 用来取值 注解使用范围:
METHOD 可用于方法上 TYPE 可用于类或者接口上 ANNOTATION_TYPE 可用于注解类型上(被@interface修饰的类型) CONSTRUCTOR 可用于构造方法上 FIELD 可用于域上 LOCAL_VARIABLE 可用于局部变量上 PACKAGE 用于记录java文件的package信息 PARAMETER 可用于参数上
@Retention
1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
回到正题,注解弄完了,现在要弄一个实体类来封装所需要的日志信息:
import com.jshh.entity.CommenEntity; import lombok.Getter; import lombok.Setter; @Setter @Getter public class LogEntity implements CommenEntity { private String uuid; private String userid; private String username; private String ip; private String status; private String operatetype; private String detail; private String operatetime; private String operatecontent; private String subsystemid; }
基础准备都弄完了,现在就要去做切面的实现类了.废话不多说代码附上:
package com.jshh.busness.LogAOP; import com.alibaba.fastjson.JSON; import com.jshh.client.DataCommenServerClient; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.CodeSignature; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.UUID; /** * @author 一只会飞的猪 * @desc 日志录入aop实现类 * @time 2018/8/28 * */ @Component @Aspect public class LogAspectClass { @Autowired LogAddService logAddService; // 这里定义下切点的位置,也就是刚才我们自定义的注解. @Pointcut("@annotation(com.jshh.busness.LogAOP.LogAnnotation)") public void mypointcut(){} //消息通知 @AfterReturning,在切点方法运行之后触发returning 为目标函数返回值 @AfterReturning(returning = "result",value = "mypointcut()") public void addlog(JoinPoint joinPoint,Object result){ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //从切面织入点处通过反射机制获取织入点处的方法 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //获取切入点所在的方法 Method method = signature.getMethod(); String operatetype =""; // 定义操作方式 String operatecontent=""; // 定义操作内容 // 获取注解中的操作方式 if(method!=null&&!"".equals(method)){ // 获取自定义注解操作 LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class); // 获取用户操作方式 operatetype = logAnnotation.operateType(); // 获取用户操作内容 operatecontent = logAnnotation.operateContent(); } // 获取请求的类名 String classname = joinPoint.getTarget().getClass().getName(); // 获取请求的方法名 String methodname = classname+"."+method.getName(); // 获取请求方式 String Method = request.getMethod(); // 获取请求url String URL = request.getRequestURI().toString(); // 获取请求的ip地址 String IP = request.getRemoteAddr(); // 获取userid String userid = request.getParameter("userid"); // 获取子系统id String subsystemid = request.getParameter("subsystemid"); // 生成uuid String uuid = UUID.randomUUID().toString(); // 获取请求的参数 String argsname[] = ((CodeSignature) joinPoint.getSignature()).getParameterNames(); Map<String,Object> parammap = new HashMap<>(); if(argsname.length>0){ parammap= getParam(joinPoint,argsname,methodname); } String detail = JSON.toJSONString(parammap); // 获取操作状态 Map<String,Object> statusmap = new HashMap<>(); String status=""; statusmap = (Map<String, Object>) result; Integer code= (Integer)statusmap.get("code"); if(code==0){ status = "失败"; }else{ status = "成功"; } // 日志实体类封装 LogEntity logEntity = new LogEntity(); logEntity.setUserid(userid); logEntity.setUuid(uuid); logEntity.setIp(IP); logEntity.setStatus(status); logEntity.setOperatetype(operatetype); logEntity.setOperatecontent(operatecontent); logEntity.setDetail(detail); logEntity.setSubsystemid(subsystemid); logAddService.addLogInfo(logEntity); System.out.println("aop+++++++++++++++++++++切面++++++++++++++++++++"); System.out.println("用户操作方式:----------"+operatetype); System.out.println("用户操作内容:----------"+operatecontent); System.out.println("请求方式:-------------"+Method); System.out.println("请求地址url:----------"+IP+URL); System.out.println("请求ip地址:------------"+IP); System.out.println("请求参数:------------"+request.getParameterNames().toString()); System.out.println("请求参数:============"+request.getQueryString()); System.out.println("请求方法名:============"+methodname); System.out.println("请求userid:============"+userid); System.out.println("返回参数:============"+detail); System.out.println("返回结果状态:============"+status); System.out.println("返回结果:============"+logEntity.toString()); } // 处理参数格式,并返回需要的参数 public static Map<String, Object> getParam(JoinPoint joinPoint,String argsname[],String methodname) { Map<String,Object> detailmap = new HashMap<>(); Map<String, Object> map = new HashMap<>(); Map<String, Object> mapCODE = new HashMap<>(); // 获取参数值 Object args[] = joinPoint.getArgs(); // 获取参数名 argsname = ((CodeSignature) joinPoint.getSignature()).getParameterNames(); String paramsString = ""; for(int i=0; i < argsname.length; i++) { if (!argsname[i].equals("model")) { map.put(argsname[i], args[i]); } } detailmap.put("method",methodname); detailmap.put("params",map); System.out.println("detail:====="+detailmap.toString()); return detailmap; } }
至于保存数据的方法这个就不用多说了吧,该咋保存就咋保存,除了这个方法,其他代码拷贝就能用的哦.
整个操作,不需要编写什么配置文件的,以前的ssm的xml配置,现在都是几个注解搞定的事.
最后添加一个controller:
@GetMapping("queryRoleByUserid") @LogAnnotation(operateType = "角色",operateContent = "根据用户id查询角色相关信息") public Model queryRoleByUserid(Model model, @RequestParam("userid") String userid) throws Exception { boolean ret = true; String msg = ""; Object result = null; try { result = userService.queryRoleByUserid(userid); } catch (Exception e) { ret = false; msg = e.getMessage(); e.printStackTrace(); } model = buildModel(model, ret, result, msg); return model; }
至于保存数据的方法这个就不用多说了吧,该咋保存就咋保存,除了这个方法,其他代码拷贝就能用的哦.
整个操作,不需要编写什么配置文件的,以前的ssm的xml配置,现在都是几个注解搞定的事.
最新评论
mat插件可以检测内存数据
标识接口?
序列化serializabel就是一个标识
就差一个MAC了
mark
除了预置sql查询字段,其他我竟然都没用过
可以,这个问题遇到过
mybatis多个参数: 1. 注解(最常用) 2. 转化为对象或MAP 3. 按顺序(这个最蠢,写的代码看得费劲) 单个参数需要注意得: 1.基本数据类型随便写 2.数组用array,l