springboot自定義日志注解的實(shí)現(xiàn)
前言
在之前的日志記錄的寫法中,我們大多是寫一個(gè)工具類,在這個(gè)類里面定義日志保存的方法,然后再controller中執(zhí)行請求的時(shí)候調(diào)用即可,雖然調(diào)用僅僅一行代碼,但是不夠友好;所有可以寫一個(gè)類似于@Controller等的注解,在需要保存日志的方法上面加上一個(gè)注解,這樣不用在每個(gè)都寫一端代碼;話不多說上代碼
1、首先一個(gè)log的實(shí)體類,這個(gè)無關(guān)緊要
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 = "耗時(shí)(毫秒)") ?? ?private Long time; ? ?? ?@Column(name = "METHOD") ?? ?@ExportConfig(value = "操作方法") ?? ?private String method; ? ?? ?@Column(name = "PARAMS") ?? ?@ExportConfig(value = "參數(shù)") ?? ?private String params; ? ?? ?@Column(name = "IP") ?? ?@ExportConfig(value = "IP地址") ?? ?private String ip; ? ?? ?@Column(name = "CREATE_TIME") ?? ?@ExportConfig(value = "操作時(shí)間", convert = "c:com.sysmg.common.util.poi.convert.TimeConvert") ?? ?private Date createTime; ? ?? ?@Column(name = "LOCATION") ?? ?@ExportConfig(value = "地點(diǎn)") ?? ?private String location; ?? ? ?? ?// 用于搜索條件中的時(shí)間字段 ?? ?@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、定義一個(gè)注解接口
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)代表是方法上的注解,當(dāng)然也可以是類注解,字段注解等
@Target(ElementType.TYPE) //接口、類、枚舉、注解
@Target(ElementType.FIELD) //字段、枚舉的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法參數(shù)
@Target(ElementType.CONSTRUCTOR) //構(gòu)造函數(shù)
@Target(ElementType.LOCAL_VARIABLE)//局部變量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包
@Retention(RetentionPolicy.RUNTIME)代表注解會(huì)被jvm保留,這個(gè)參數(shù)有三種
RetentionPolicy.SOURCE —— 這種類型的Annotations只在源代碼級別保留,編譯時(shí)就會(huì)被忽略
RetentionPolicy.CLASS —— 這種類型的Annotations編譯時(shí)被保留,在class文件中存在,但JVM將會(huì)忽略
RetentionPolicy.RUNTIME —— 這種類型的Annotations將被JVM保留,所以他們能在運(yùn)行時(shí)被JVM或其他使用反射機(jī)制的代碼所讀取和使用。
一般默認(rèn)第三種
當(dāng)然也可以寫
@Documented和@Order(優(yōu)先級 數(shù)字越小優(yōu)先級越高)
@Documented 注解表明這個(gè)注解應(yīng)該被 javadoc工具記錄. 默認(rèn)情況下,javadoc是不包括注解的. 但如果聲明注解時(shí)指定了 @Documented,則它會(huì)被 javadoc 之類的工具處理, 所以注解類型信息也會(huì)被包括在生成的文檔中。
@Order標(biāo)記定義了組件的加載順序,這個(gè)標(biāo)記包含一個(gè)value屬性。屬性接受整形值。如:1,2 等等。值越小擁有越高的優(yōu)先級。Ordered.HIGHEST_PRECEDENCE這個(gè)屬性值是最高優(yōu)先級的屬性,它的值是-2147483648,對應(yīng)的最低屬性值是Ordered.LOWEST_PRECEDENCE,它的值是2147483647。
String value() default ""
這個(gè)代表是要傳遞的參數(shù),類似
@Autowired(required=true) ? ? public @interface Autowired { ? ?? ?/** ?? ? * Declares whether the annotated dependency is required. ?? ? * <p>Defaults to {@code true}. ?? ? */ ?? ?boolean required() default true; ? }
springmvc項(xiàng)目還需要開啟切面編程
<aop:aspectj-autoproxy proxy-target-class="true"/>
springboot默認(rèn)是開啟的
3、定義注解的實(shí)現(xiàn)類,也就是這個(gè)注解要做什么事
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); ?? ?} }
這里的實(shí)現(xiàn)類中日志添加的方法中使用的淘寶的獲取ip服務(wù),后續(xù)會(huì)加上去,其實(shí)這里面可以隨便寫一個(gè)實(shí)現(xiàn)方法,因?yàn)槲沂橇艄ぞ邆浞?,所以記錄的較多
具體的@Aspect、@Pointcut、@Around、@Before、@After等aop相關(guān)的注解和參數(shù)需要自己去鞏固一下知識(shí)
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相關(guān)知識(shí)的介紹以及獲取訪問ip的工具類,不過跟本課題關(guān)系不大,后續(xù)會(huì)更上去
到此這篇關(guān)于springboot自定義日志注解的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)springboot自定義日志注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
StringUtils中的isEmpty、isNotEmpty、isBlank和isNotBlank的區(qū)別詳解
這篇文章主要介紹了StringUtils中的isEmpty、isNotEmpty、isBlank和isNotBlank的區(qū)別詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06springboot整合apache ftpserver詳細(xì)教程(推薦)
這篇文章主要介紹了springboot整合apache ftpserver詳細(xì)教程,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01一文告訴你為什么要重寫hashCode()方法和equals()方法
本篇文章帶大家了解一下為什么重寫hashCode()方法和equals()方法,文中有非常詳細(xì)的說明以及代碼示例,對正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下2021-05-05Java同步框架AbstractQueuedSynchronizer詳解
本篇文章主要介紹了Java同步框架AbstractQueuedSynchronizer詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10