(原)SpringBoot+ @Aspect註解 實現一個管理端自建Log日誌管理功能

一、效果

二、技術應用:

JDK1.8+

SpringBoot2.0+   、@Aspect註解

MySql5.6+

三、上代碼---我的博客只上乾貨!!!!

Log實體對象類.java

package *****.***.***.modules.sys.log.entity;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import org.springframework.stereotype.Component;

import io.swagger.annotations.ApiModelProperty;

 
@Entity
@Table(name = "sys_log")
@Component
@org.hibernate.annotations.Table(comment="系統日誌信息", appliesTo = "sys_log")
public class SysLog implements Serializable{

    private static final long serialVersionUID = 42L;
	
	@Id
	@ApiModelProperty("主鍵")
	@Column(name="id",nullable = false,columnDefinition = "bigint(64)  comment '主鍵'")
	private Long id;// 主鍵Id

	@ApiModelProperty("日誌編號")
	@Column(name="log_id",columnDefinition = "varchar(255)  comment '日誌編號'" )
	private String logId;//日誌編號
	
	@ApiModelProperty("請求鏈接")
	@Column(name="url",columnDefinition = "text  comment '請求鏈接'" )
	private String url;//請求鏈接
	
	@ApiModelProperty("請求方法")
	@Column(name="method",columnDefinition = "text  comment '請求方法'" )
	private String method;//請求方法
	
	@ApiModelProperty("請求類名")
	@Column(name="class_name",columnDefinition = "text  comment '請求類名'" )
	private String className;//請求方法
	
	@ApiModelProperty("請求方法名")
	@Column(name="method_name",columnDefinition = "text  comment '請求方法名'" )
	private String methodName;//請求方法
	
	@ApiModelProperty("請求參數")
	@Column(name="params",columnDefinition = "text  comment '請求參數'" )
	private String params;//請求參數
	
	@ApiModelProperty("日誌類型:(1:系統日誌2:業務日誌)")
	@Column(name="lot_type",columnDefinition = "varchar(255)  comment '日誌類型:(1:系統日誌2:業務日誌)'" )
	private String logType;//請求方法
	
	@ApiModelProperty("請求方式:(GET/POST)")
	@Column(name="type",columnDefinition = "varchar(255)  comment '請求方式(GET/POST)'" )
	private String type;//請求方法
	
	@ApiModelProperty("請求IP")
	@Column(name="IP",columnDefinition = "text  comment '請求IP'" )
	private String ip;//請求方法
	
	@ApiModelProperty("操作的數據庫表")
	@Column(name="log_table",columnDefinition = "varchar(255)  comment '操作的數據庫表'" )
	private String table;//操作的數據庫表
	
	@ApiModelProperty("請求異常")
	@Column(name="log_error",columnDefinition = "text  comment '請求異常'" )
	private String logError;//請求異常
	
	@ApiModelProperty("運行時長")
	@Column(name="time",columnDefinition = "varchar(255) comment '運行時長'" )
	private long time;//
	
	@ApiModelProperty("備註")
	@Column(name="log_comment",columnDefinition = "text  comment '備註'" )
	private String logComment;//備註

	@ApiModelProperty("創建人")
	@Column(name="create_by" )
	private String createBy;//創建人

	@ApiModelProperty("創建時間")
	@Column(name="create_time"  )
	private Date createTime;//創建時間
	
 
	 
	 //setter()/getter();
	 
	

}

四、實現基本保存功能,基本的CRUD.java

package ****.****.****.modules.sys.log.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;


import *****.modules.sys.log.entity.SysLog;
import *******.modules.sys.log.service.SysLogService;

import io.swagger.annotations.ApiOperation;

@CrossOrigin//跨域
@RestController
@RequestMapping("/SysLog")
public class SysLogController{

	
	@Autowired
	public SysLogService sysLogService;
	
	
//	//添加AOP註解日誌管理
//	@SysLogAspectValue(
//			describtion = "獲取所有日誌列表信息",
//			logType = "1",
//			type="POST",
//			url="/SysLog/SelectAllSysLog",
//			table="sys_log",
//			params = "SysLog",
//			method = "POST"
//	)
	@ResponseBody
	@ApiOperation(value = "獲取所有日誌列表信息", notes = "/SysLog/SelectAllSysLog")
	@GetMapping(value = "/SelectAllSysLog")
	public List<SysLog> SelectAllSysLog(){
		return sysLogService.SelectAllSysLogList(page).getContent();
	}
	
	
}
package *******.*****.******modules.sys.log.service;

import org.springframework.data.domain.Page;

import ***.***.****t.modules.sys.log.entity.SysLog;

/***
 * 系統日誌接口
 * @ClassName: SysLogService
 * @Description: TODO(描述)
 * @author author
 * @date 2019-12-03 10:55:22
 */
public interface SysLogService {

	
	
	
	/***
	 * 日誌保存
	 * @Title: save
	 * @Description: TODO(描述)
	 * @param sysLog
	 * @author author
	 * @date 2019-12-10 09:56:28
	 */
	void save(SysLog sysLog);

	
}
package ***.****.****.modules.sys.log.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;


import ***.***.***.***.****.modules.sys.log.entity.SysLog;
import ***.*.*.*.*.*.*.*.modules.sys.log.repository.SysLogRepository;
import *.*.*.*.*.*.*.*.*.*.modules.sys.log.service.SysLogService;

/**
 * 系統日誌實現類
 * @ClassName: SysLogServiceImpl
 * @Description: TODO(描述)
 * @author author
 * @date 2019-12-03 10:55:17
 */
@Service("SysLogService")
public class SysLogServiceImpl implements SysLogService{

	 
	@Autowired
	public SysLogRepository sysLogRepository;
	
	 
	@Override
	public Page<SysLog> SelectAllSysLogList(int page) {
		Sort sort = new Sort(Sort.Direction.DESC, "createTime");//創建時間正序排列
		Pageable pageable = PageRequest.of(page, this.size, sort);
        Page<SysLog> sysLog = sysLogRepository.findAll (new Specification<SysLog>() {
			@Override
			public Predicate toPredicate(Root<SysLog> root,
					CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
				List<Predicate> list = new ArrayList<Predicate>();
				//拼接 where條件-----------------
				 
				//---------------------------
				Predicate[] p = new Predicate[list.size()];
				return criteriaBuilder.and(list.toArray(p));
			}
		}, pageable);
		return sysLog;
	}


	@Override
	public void save(SysLog sysLog) {
		sysLogRepository.save(sysLog);
	}


}
package *.*.*.*.*.*.*.modules.sys.log.repository;


import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;

import *.*.*.*.*.*.*.*.modules.sys.log.entity.SysLog;


/**
 * 系統日誌管理類
 * @ClassName: SysLogRepository
 * @Description: TODO(描述)
 * @author author
 * @date 2019-12-03 10:55:09
 */
public interface SysLogRepository extends JpaRepository<SysLog, Long> {

	
	 

}

已上就是基本的業務功能中的CRUD的功能,下面就是重點的log的AOP切面功能,,,

五、AOP切面功能動態獲取log信息

1)、在每個需要用到的方法頭上增加註釋,附加案例【四中第一個截圖】

package *.*.*.*.*.*.*.*.modules.sys.log.controller;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/***
 * 系統日誌管理表
 * @ClassName: SysLogController
 * @Description: TODO(描述)
 * @author author
 * @date 2019-12-03 10:54:52
 */

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented//註釋文檔
public @interface SysLogAspectValue {

	 String describtion() default "";//日誌描述
	 String logType() default "1";//日誌種類-1:系統日誌2:業務日誌
	 String type()  default "GET";//請求方式:(GET/POST)
	 String url()  default "";//請求鏈接
	 String table()  default "";//操作的數據庫表
	 String params()  default "";//請求參數
	 String method()  default "";//請求方法
	 
}

製作切面內容

package *.*.*.*.*.*.*.modules.sys.log.controller;


import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
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.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.google.gson.Gson;
import *.*.*.*.*.*.common.utils.IdGenerate;
import *.*.*.*.*.*.modules.sys.log.entity.SysLog;
import *.*.*.*.*.*.modules.sys.log.service.SysLogService;
 
 

/***
 *  系統日誌切面
 * @ClassName: SysLogAspect
 * @Description: TODO(描述)
 * @author author
 * @date 2019-12-04 10:34:41
 */
@Aspect  // 使用@Aspect註解聲明一個切面
@Component
public class SystemLogAspect{
 
	 private final String POINT_CUT ="@annotation(*.*.*.*.*.modules.sys.log.entity)";
	 
	  private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SystemLogAspect.class);
	 
	@Autowired
	public SysLogService sysLogService;
    /**
     * 這裏我們使用註解的形式
     * 當然,我們也可以通過切點表達式直接指定需要攔截的package,需要攔截的class 以及 method
     * 切點表達式:   execution(...)
     */
    @Pointcut(POINT_CUT)
    public void PointCut() {}

    
    /**
     * 環繞通知 @Around  , 當然也可以使用 @Before (前置通知)  @After (後置通知)
     * @param point
     * @return
     * @throws Throwable
     */
    //@Around(POINT_CUT)
    @Around("@annotation(SysLogAspectValue)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        Object result = point.proceed();
        try {
        	//正常保存日誌
            saveLog(point, System.currentTimeMillis() - beginTime);
        } catch (Exception e) {
        	//異常保存日誌
        	//afterReturningMethod(point, e);
        }
        return result;
    }
 
    /***
     * 捕獲異常
     * 
     * @Title: afterReturningMethod
     * @Description: TODO(描述)
     * @param joinPoint
     * @param e
     * @author author
     * @throws Throwable 
     * @date 2019-12-10 01:40:37
     */ 
    @AfterThrowing(throwing = "exception",value = "@annotation(SysLogAspectValue)",argNames="exception")
    public void afterReturningMethod(JoinPoint joinPoint, Exception e) throws Throwable{
    	if(e!=null){
    		SysLog sysLog =  new SysLog();
        	long beginTime = System.currentTimeMillis();
        	long time = System.currentTimeMillis() - beginTime;

        	MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
    	
            // 接收到請求,記錄請求內容
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
    		sysLog.setId(IdGenerate.longUUIDId());//主鍵
            sysLog.setLogId(sysLog.getId().toString());//日誌編號
            
            sysLog.setTime(time);//時長
            sysLog.setIp(request.getRemoteAddr());//請求的IP
            sysLog.setCreateBy(sysLog.getIp());//請求人
            sysLog.setCreateTime( new Date() );//創建時間
            SysLogAspectValue sysLogAspectValue = method.getAnnotation(SysLogAspectValue.class);
            if(sysLogAspectValue != null){
                //註解上的描述
            	sysLog.setLogComment(sysLogAspectValue.describtion());//備註
            	sysLog.setLogType(sysLogAspectValue.logType());//日誌類型
            	sysLog.setType(sysLogAspectValue.type());//請求類型
            	sysLog.setUrl(sysLogAspectValue.url());//請求鏈接
            	sysLog.setTable(sysLogAspectValue.table());//操作的數據表
            	sysLog.setMethod(sysLogAspectValue.method());//操作請求方法
            }
            //請求的 類名、方法名
            sysLog.setClassName(joinPoint.getTarget().getClass().getName());//類名
            sysLog.setMethodName(signature.getName());//方法名
        	
            //請求的參數
            Object[] args = joinPoint.getArgs();
            List<String> list = new ArrayList<String>();
            for (Object o : args) {
                list.add(new Gson().toJson(o));
            }
            sysLog.setParams("Params:[ " + list.toString()+" ]:Aspectj @AfterThrowing");
            sysLog.setLogError(joinPoint.getSignature().getName()+ "[ message:" + e.getMessage() + "]:Aspectj @AfterThrowing");
            System.out.println("=====異常保存日誌成功==============================");
            sysLogService.save(sysLog);
            log.trace(POINT_CUT, sysLog);
            System.out.println("=====異常保存日誌  結束=========================");
    	}
    }
    
    /**
     * 正常保存日誌
     * @param joinPoint
     * @param time
     * @throws Throwable 
     */
    public void saveLog(ProceedingJoinPoint joinPoint, long time) {
        SysLog sysLog =  new SysLog();
        sysLog = this.addSysLog(joinPoint,sysLog , time );
        //請求的參數
        Object[] args = joinPoint.getArgs();
        List<String> list = new ArrayList<String>();
        for (Object o : args) {
            list.add(new Gson().toJson(o));
        }
        sysLog.setParams("Params:[ " + list.toString()+" ]:Aspectj @Around");
        sysLog.setLogError( "[ message: 無 ]:Aspectj @Around");
        System.out.println("=====正常保存日誌成功==============================");
        sysLogService.save(sysLog);
        log.trace(POINT_CUT, sysLog);
        System.out.println("=====正常保存日誌  結束=========================");
    }

    /**
     * 組裝日誌model
     * @Title: addSysLog
     * @Description: TODO(描述)
     * @param sysLog
     * @return
     * @author author
     * @date 2019-12-10 02:09:04
     */
	public SysLog addSysLog(ProceedingJoinPoint joinPoint, SysLog sysLog , long time) {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
	
        // 接收到請求,記錄請求內容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
		sysLog.setId(IdGenerate.longUUIDId());//主鍵
        sysLog.setLogId(sysLog.getId().toString());//日誌編號
        
        sysLog.setTime(time);//時長
        sysLog.setIp(request.getRemoteAddr());//請求的IP
        sysLog.setCreateBy(sysLog.getIp());//請求人
        sysLog.setCreateTime( new Date() );//創建時間
        SysLogAspectValue sysLogAspectValue = method.getAnnotation(SysLogAspectValue.class);
        if(sysLogAspectValue != null){
            //註解上的描述
        	sysLog.setLogComment(sysLogAspectValue.describtion());//備註
        	sysLog.setLogType(sysLogAspectValue.logType());//日誌類型
        	sysLog.setType(sysLogAspectValue.type());//請求類型
        	sysLog.setUrl(sysLogAspectValue.url());//請求鏈接
        	sysLog.setTable(sysLogAspectValue.table());//操作的數據表
        	sysLog.setMethod(sysLogAspectValue.method());//操作請求方法
        }
        //請求的 類名、方法名
        sysLog.setClassName(joinPoint.getTarget().getClass().getName());//類名
        sysLog.setMethodName(signature.getName());//方法名
		return sysLog;
	}
    
    
    
    
    
}

生成這個Log切面日誌的用法:

 

 

 

以上是自己整理的,並測試過,可以直接用

-------------------------------------------------- -------------------------------------------------- ------------

文章中,有問題,可以在評論區評論,一起探討編程中奧祕!

-------------------------------------------------- -------------------------------------------------- ------------

來都來了,代碼看都看了,那就留個言唄,可以互動下!

-------------------------------------------------- ------------------------------------------------- ------------

如果我的文章有幫助到您,歡迎打賞一下鼓勵博主,


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章