1)定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
}
2)定义entity 这里我用的jpa
/**
* @author Lee
* @description 行为日志类
* @date 2020-03-06 11:10
**/
@Entity
@Data
@Table(name = "log")
@NoArgsConstructor
public class Log implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", columnDefinition = "VARCHAR(128) comment '用户名'")
private String username;
@Column(name = "userid", columnDefinition = "INT(22) comment '用户id'")
private Long userId;
@Lob
@Column(name = "description", columnDefinition = "TEXT comment '描述'")
private String description;
@Column(name = "method", columnDefinition = "VARCHAR(128) comment '方法名'")
private String method;
@Lob
@Column(name = "params", columnDefinition = "TEXT comment '参数'")
private String params;
@Column(name = "log_type", columnDefinition = "VARCHAR(10) comment '日志类型'")
private String logType;
@Column(name = "request_ip", columnDefinition = "VARCHAR(55) comment '请求ip'")
private String requestIp;
@Column(name = "address", columnDefinition = "VARCHAR(255) comment '地址'")
private String address;
@Column(name = "browser", columnDefinition = "VARCHAR(55) comment '浏览器'")
private String browser;
@Column(name = "time", columnDefinition = "INT(24) comment '耗时'")
private Long time;
@Column(name = "exception_detail", columnDefinition = "TEXT comment '异常详情'")
private byte[] exceptionDetail;
/**
* 创建日期
*/
@CreationTimestamp
@Column(name = "create_time", columnDefinition = "DATETIME comment '创建日期'")
private Timestamp createTime;
public Log(String logType, Long time) {
this.logType = logType;
this.time = time;
}
}
3)定义repository
@Repository
public interface LogRepository extends JpaRepository<Log,Long>, JpaSpecificationExecutor<Log> {
/**
* 获取一个时间段的IP记录
* @param date1 startTime
* @param date2 entTime
* @return IP数目
*/
@Query(value = "select count(*) FROM (select request_ip FROM log where create_time between ?1 and ?2 GROUP BY request_ip) as s",nativeQuery = true)
Long findIp(String date1, String date2);
/**
* 根据日志类型删除信息
* @param logType 日志类型
*/
@Query(nativeQuery = true,value = "delete from log where log_type = ?1")
@Modifying
void deleteByLogType(String logType);
}
4)编写logService的save方法
@Transactional(rollbackFor = Exception.class)
public void save(String browser, String ip, ProceedingJoinPoint joinPoint, Log log) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
cn.city.common.anon.Log aopLog = method.getAnnotation(cn.city.common.anon.Log.class);
// 方法路径
String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
StringBuilder params = new StringBuilder("{");
//参数值
Object[] argValues = joinPoint.getArgs();
//参数名称
String[] argNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
if (argValues != null) {
for (int i = 0; i < argValues.length; i++) {
params.append(" ").append(argNames[i]).append(": ").append(argValues[i]);
}
}
// 描述
if (log != null) {
log.setDescription(aopLog.value());
}
assert log != null;
log.setRequestIp(ip);
log.setAddress(StringUtils.getCityInfo(log.getRequestIp()));
log.setMethod(methodName);
final TUser curUserEntity = super.getCurUserEntity();
log.setUsername(curUserEntity.getMobile());
log.setUserId(curUserEntity.getId());
log.setParams(params.toString() + " }");
log.setBrowser(browser);
logRepository.save(log);
}
5)定义切面
@Component
@Aspect
@Slf4j
public class LogAspect {
private final LogService logService;
ThreadLocal<Long> currentTime = new ThreadLocal<>();
public LogAspect(LogService logService) {
this.logService = logService;
}
/**
* 配置切入点
*/
@Pointcut("@annotation(cn.city.common.anon.Log)")
public void logPointcut() {
// 该方法无方法体,主要为了让同类中其他方法使用此切入点
}
/**
* 配置环绕通知,使用在方法logPointcut()上注册的切入点
*
* @param joinPoint join point for advice
*/
@Around("logPointcut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object result;
currentTime.set(System.currentTimeMillis());
result = joinPoint.proceed();
Log log = new Log("INFO", System.currentTimeMillis() - currentTime.get());
currentTime.remove();
HttpServletRequest request = RequestHolder.getHttpServletRequest();
logService.save( StringUtils.getBrowser(request), StringUtils.getIp(request), joinPoint, log);
return result;
}
/**
* 配置异常通知
*
* @param joinPoint join point for advice
* @param e exception
*/
@AfterThrowing(pointcut = "logPointcut()", throwing = "e")
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
Log log = new Log("ERROR", System.currentTimeMillis() - currentTime.get());
currentTime.remove();
StringWriter sw = new StringWriter();
try (PrintWriter pw = new PrintWriter(sw)) {
e.printStackTrace(pw);
log.setExceptionDetail(sw.toString().getBytes());
}
HttpServletRequest request = RequestHolder.getHttpServletRequest();
logService.save(StringUtils.getBrowser(request), StringUtils.getIp(request), (ProceedingJoinPoint) joinPoint, log);
}
}
6)在控制器使用
效果: