一、效果
二、技術應用:
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切面日誌的用法:
以上是自己整理的,並測試過,可以直接用
-------------------------------------------------- -------------------------------------------------- ------------
文章中,有問題,可以在評論區評論,一起探討編程中奧祕!
-------------------------------------------------- -------------------------------------------------- ------------
來都來了,代碼看都看了,那就留個言唄,可以互動下!
-------------------------------------------------- ------------------------------------------------- ------------
如果我的文章有幫助到您,歡迎打賞一下鼓勵博主,