springboot自定義日志注解的實現
前言
在之前的日志記錄的寫法中,我們大多是寫一個工具類,在這個類里面定義日志保存的方法,然后再controller中執(zhí)行請求的時候調用即可,雖然調用僅僅一行代碼,但是不夠友好;所有可以寫一個類似于@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(優(yōu)先級 數字越小優(yōu)先級越高)
@Documented 注解表明這個注解應該被 javadoc工具記錄. 默認情況下,javadoc是不包括注解的. 但如果聲明注解時指定了 @Documented,則它會被 javadoc 之類的工具處理, 所以注解類型信息也會被包括在生成的文檔中。
@Order標記定義了組件的加載順序,這個標記包含一個value屬性。屬性接受整形值。如:1,2 等等。值越小擁有越高的優(yōu)先級。Ordered.HIGHEST_PRECEDENCE這個屬性值是最高優(yōu)先級的屬性,它的值是-2147483648,對應的最低屬性值是Ordered.LOWEST_PRECEDENCE,它的值是2147483647。
String value() default ""
這個代表是要傳遞的參數,類似
@Autowired(required=true) ? ? public @interface Autowired { ? ?? ?/** ?? ? * Declares whether the annotated dependency is required. ?? ? * <p>Defaults to {@code true}. ?? ? */ ?? ?boolean required() default true; ? }
springmvc項目還需要開啟切面編程
<aop:aspectj-autoproxy proxy-target-class="true"/>
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服務,后續(xù)會加上去,其實這里面可以隨便寫一個實現方法,因為我是留工具備份,所以記錄的較多
具體的@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("規(guī)則") ?? ?@RequestMapping("test") ?? ?public String index() { ?? ??? ?return "test"; ?? ?} }?? ?
大概這樣就可以使用了,目前里面缺少aop相關知識的介紹以及獲取訪問ip的工具類,不過跟本課題關系不大,后續(xù)會更上去
到此這篇關于springboot自定義日志注解的實現的文章就介紹到這了,更多相關springboot自定義日志注解內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
StringUtils中的isEmpty、isNotEmpty、isBlank和isNotBlank的區(qū)別詳解
這篇文章主要介紹了StringUtils中的isEmpty、isNotEmpty、isBlank和isNotBlank的區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-06-06springboot整合apache ftpserver詳細教程(推薦)
這篇文章主要介紹了springboot整合apache ftpserver詳細教程,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2020-01-01一文告訴你為什么要重寫hashCode()方法和equals()方法
本篇文章帶大家了解一下為什么重寫hashCode()方法和equals()方法,文中有非常詳細的說明以及代碼示例,對正在學習java的小伙伴們很有幫助,需要的朋友可以參考下2021-05-05Java同步框架AbstractQueuedSynchronizer詳解
本篇文章主要介紹了Java同步框架AbstractQueuedSynchronizer詳解,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10