现在凡是企业级的或者稍微大点项目,基本都需要日志管理. 我这边在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;
}
}
最后添加一个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配置,现在都是几个注解搞定的事.