springboot自定义日志注解的实现

网友投稿 348 2022-08-22


springboot自定义日志注解的实现

前言

在之前的日志记录的写法中,我们大多是写一个工具类,在这个类里面定义日志保存的方法,然后再controller中执行请求的时候调用即可,虽然调用仅仅一行代码,但是不够友好;所有可以写一个类似于@Controller等的注解,在需要保存日志的方法上面加上一个注解,这样不用在每个都写一端代码;话不多说上代码

     1、首先一个log的实体类,这个无关紧要

package com.sysmg.system.domain;

import java.io.Serializable;

import java.util.Date;

import javax.persistence.Column;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import javax.persistence.Table;

import javax.persistence.Transient;

import com.sysmg.common.annotation.ExportConfig;

@Table(name = "t_log")

public class SysLog implements Serializable {

private static final long serialVersionUID = -8878596941954995444L;

@Id

@GeneratedValue(generator = "JDBC")

@Column(name = "ID")

private Long id;

@Column(name = "USERNAME")

@ExportConfig(value = "操作用户")

private String username;

@Column(name = "OPERATION")

@ExportConfig(value = "描述")

private String operation;

@Column(name = "TIME")

@ExportConfig(value = "耗时(毫秒)")

private Long time;

@Column(name = "METHOD")

@ExportConfig(value = "操作方法")

private String method;

@Column(name = "PARAMS")

@ExportConfig(value = "参数")

private String params;

@Column(name = "IP")

@ExportConfig(value = "IP地址")

private String ip;

@Column(name = "CREATE_TIME")

@ExportConfig(value = "操作时间", convert = "c:com.sysmg.common.util.poi.convert.TimeConvert")

private Date createTime;

@Column(name = "LOCATION")

@ExportConfig(value = "地点")

private String location;

// 用于搜索条件中的时间字段

@Transient

private String timeField;

/**

* @return ID

*/

public Long getId() {

return id;

}

/**

* @param id

*/

public void setId(Long id) {

this.id = id;

}

/**

* @return USERNAME

*/

public String getUsername() {

return username;

}

/**

* @param username

*/

public void setUsername(String username) {

this.username = username == null ? null : username.trim();

}

/**

* @return OPERATION

*/

public String getOperation() {

return operation;

}

/**

* @param operation

*/

public void setOperation(String operation) {

this.operation = operation == null ? null : operation.trim();

}

/**

* @return TIME

*/

public Long getTime() {

return time;

}

/**

* @param time

*/

public void setTime(Long time) {

this.time = time;

}

/**

* @return METHOD

*/

public String getMethod() {

return method;

}

/**

* @param method

*/

public void setMethod(String method) {

this.method = method == null ? null : method.trim();

}

/**

* @return PARAMS

*/

public String getParams() {

return params;

}

/**

* @param params

*/

public void setParams(String params) {

this.params = params == null ? null : params.trim();

}

/**

* @return IP

*/

public String getIp() {

return ip;

}

/**

* @param ip

*/

public void setIp(String ip) {

this.ip = ip == null ? null : ip.trim();

}

/**

* @return CREATE_TIME

*/

public Date getCreateTime() {

return createTime;

}

/**

* @param createTime

*/

public void setCreateTime(Date createTime) {

this.createTime = createTime;

}

public String getLocation() {

return location;

}

public void setLocation(String location) {

this.location = location;

}

public String getTimeField() {

return timeField;

}

public void setTimeField(String timeField) {

this.timeField = timeField;

}

}

2、定义一个注解接口

package com.sysmg.common.annotation;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Log {

String value() default "";

}

@Target(ElementType.METHOD)代表是方法上的注解,当然也可以是类注解,字段注解等

@Target(ElementType.TYPE) //接口、类、枚举、注解 @Target(ElementType.FIELD) //字段、枚举的常量 @Target(ElementType.METHOD) //方法 @Target(ElementType.PARAMETER) //方法参数 @Target(ElementType.CONSTRUCTOR) //构造函数 @Target(ElementType.LOCAL_VARIABLE)//局部变量 @Target(ElementType.ANNOTATION_TYPE)//注解 @Target(ElementType.PACKAGE) ///包

@Retention(RetentionPolicy.RUNTIME)代表注解会被jvm保留,这个参数有三种

RetentionPolicy.SOURCE —— 这种类型的Annotations只在源代码级别保留,编译时就会被忽略 RetentionPolicy.CLASS —— 这种类型的Annotations编译时被保留,在class文件中存在,但JVM将会忽略 RetentionPolicy.RUNTIME —— 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。一般默认第三种

当然也可以写

@Documented和@Order(优先级  数字越小优先级越高)

@Documented 注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中。

@Order标记定义了组件的加载顺序,这个标记包含一个value属性。属性接受整形值。如:1,2 等等。值越小拥有越高的优先级。Ordered.HIGHEST_PRECEDENCE这个属性值是最高优先级的属性,它的值是-2147483648,对应的最低属性值是Ordered.LOWEST_PRECEDENCE,它的值是2147483647。

String value() default ""

这个代表是要传递的参数,类似

@Autowired(required=true)

public @interface Autowired {

/**

* Declares whether the annotated dependency is required.

*

Defaults to {@code true}.

*/

boolean required() default true;

}

springmvc项目还需要开启切面编程

springboot默认是开启的

3、定义注解的实现类,也就是这个注解要做什么事

package com.sysmg.common.aspect;

import java.lang.reflect.Method;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.SecurityUtils;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Pointcut;

import org.aspectj.lang.reflect.MethodSignature;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.core.LocalVariableTableParameterNameDiscoverer;

import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.ObjectMapper;

import com.sysmg.common.annotation.Log;

import com.sysmg.common.util.AddressUtilsBak;

import com.sysmg.common.util.HttpContextUtils;

import com.sysmg.common.util.IPUtils;

import com.sysmg.system.domain.SysLog;

import com.sysmg.system.domain.User;

import com.sysmg.system.service.LogService;

@Aspect

@Component

public class LogAspect {

@Autowired

private LogService logService;

@Autowired

ObjectMapper mapper;

@Pointcut("@annotation(com.sysmg.common.annotation.Log)")

public void pointcut() {

}

@Around("pointcut()")

public Object around(ProceedingJoinPoint point) {

Object result = null;

long beginTime = System.currentTimeMillis();

try {

result = point.proceed();

} catch (Throwable e) {

e.printStackTrace();

}

long time = System.currentTimeMillis() - beginTime;

saveLog(point, time);

return result;

}

private void saveLog(ProceedingJoinPoint joinPoint, long time) {

User user = (User) SecurityUtils.getSubject().getPrincipal();

MethodSignature signature = (MethodSignature) joinPoint.getSignature();

Method method = signature.getMethod();

SysLog log = new SysLog();

Log logAnnotation = method.getAnnotation(Log.class);

if (logAnnotation != null) {

log.setOperation(logAnnotation.value());

}

String className = joinPoint.getTarget().getClass().getName();

String methodName = signature.getName();

log.setMethod(className + "." + methodName + "()");

Object[] args = joinPoint.getArgs();

LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();

String[] paramNames = u.getParameterNames(method);

if (args != null && paramNames != null) {

String params = "";

for (int i = 0; i < args.length; i++) {

params += " " + paramNames[i] + ": " + args[i];

}

log.setParams(params);

}

HttpServletRequest request = HttpContextUtils.getHttpServletRequest();

log.setIp(IPUtils.getIpAddr(request));

log.setUsername(user.getUsername());

log.setTime(time);

log.setCreateTime(new Date());

log.setLocation(AddressUtilsBak.getRealAddressByIP(log.getIp(), mapper));

this.logService.save(log);

}

}

这里的实现类中日志添加的方法中使用的淘宝的获取ip服务,后续会加上去,其实这里面可以随便写一个实现方法,因为我是留工具备份,所以记录的较多

具体的@Aspect、@Pointcut、@Around、@Before、@After等aop相关的注解和参数需要自己去巩固一下知识

4、然后就可以在你想要记录日志的地方使用即可

package com.sysmg.controller;

import java.util.List;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.ResponseBody;

import com.github.pagehelper.PageHelper;

import com.github.pagehelper.PageInfo;

import com.sysmg.common.annotation.Log;

import com.sysmg.common.domain.QueryRequest;

import com.sysmg.common.domain.ResponseBo;

import com.sysmg.common.util.FileUtils;

@Controller

public class TestController{

@Log("规则")

@RequestMapping("test")

public String index() {

return "test";

}

}

大概这样就可以使用了,目前里面缺少aop相关知识的介绍以及获取访问ip的工具类,不过跟本课题关系不大,后续会更上去


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Python环境搭建与输入输出(如何安装和配置Python编程环境)
下一篇:#yyds干货盘点#python pass和match
相关文章

 发表评论

暂时没有评论,来抢沙发吧~