springboot 切面编程记录请求日志
开发过程中,对于非查询操作,需要做对应的日志记录,因此使用切面在接口上定义@SysLogService注解,方便日志记录。
数据库表创建:
/*==============================================================*/
/* Table: sys_log 系统日志表 */
/*==============================================================*/
CREATE TABLE public.sys_log (
id SERIAL NOT NULL PRIMARY KEY,
user_id VARCHAR ( 50 ) NULL,
user_name VARCHAR ( 50 ) NULL,
operation VARCHAR ( 100 ) NULL,
response_time INT4 NULL,
method VARCHAR ( 200 ) NULL,
params TEXT NULL,
ip VARCHAR ( 50 ) NULL,
gmt_create TIMESTAMP NULL
);
COMMENT ON TABLE public.sys_log IS '系统日志';
COMMENT ON COLUMN public.sys_log.id IS '主键id';
COMMENT ON COLUMN public.sys_log.user_id IS '用户id';
COMMENT ON COLUMN public.sys_log.user_name IS '用户名称';
COMMENT ON COLUMN public.sys_log.operation IS '用户操作';
COMMENT ON COLUMN public.sys_log.response_time IS '响应时间';
COMMENT ON COLUMN public.sys_log.method IS '请求方法';
COMMENT ON COLUMN public.sys_log.params IS '请求参数';
COMMENT ON COLUMN public.sys_log.ip IS 'IP地址';
COMMENT ON COLUMN public.sys_log.gmt_create IS '创建时间';
注解接口定义:
/**
* 系统日志注解
* @author xx
* @Date 2021-4-14 18:01:05
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLogService {
String value() default "";
}
参数解释:
@Target 定义该注解可以用于何处,包含:ElementType.PARAMETER;ElementType.METHOD;ElementType.TYPE等;
@Retention 是定义被它所注解的注解保留多久;有SOURCE(保留在源文件);CLASS(保留到class文件);RUNTIME(JVM加载后仍存在)三种;
@Documented 注解只是用来做标识,没什么实际作用
具体实现:
/**
* 系统日志,切面处理类
* @author xx
* @Date 2021-4-14 19:30:02
*/
@Aspect
@Component
@Slf4j
public class SysLogAspect {
@Autowired
private SysLogMapper sysLogMapper;
@Autowired
SysUserApplicationService sysUserApplicationService;
@Pointcut("@annotation(com.yoi.core.domain.repository.SysLogService)")
public void logPointCut() {
}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
//执行方法
Object result = point.proceed();
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
//保存日志
saveSysLog(point, time);
return result;
}
private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SysLog sysLog = new SysLog();
SysLogService syslog = method.getAnnotation(SysLogService.class);
if(syslog != null){
//注解上的描述
sysLog.setOperation(syslog.value());
}
//请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLog.setMethod(className + "." + methodName + "()");
//请求的参数
Object[] args = joinPoint.getArgs();
try{
String params = JSONUtils.beanToJson(args[0]);
sysLog.setParams(params);
}catch (Exception e){
}
//设置IP地址
sysLog.setIp(WebUtils.getIpAddr());
//用户名
String userId = WebUtils.getUserId();
sysLog.setUserId(userId);
if(ObjectUtils.isNotEmpty(userId)){
SysUserDto sysUserDto = sysUserApplicationService.getUserByUserId(userId);
sysLog.setUserName(sysUserDto.getUserName());
}
sysLog.setResponseTime(time);
sysLog.setGmtCreate(DateUtils.getCurrentDate());
if(ObjectUtils.isNotEmpty(syslog.value())){
//保存系统日志
int num = sysLogMapper.insert(sysLog);
if(num>0){
log.info("save log{} success!",sysLog.toString());
}else{
log.info("save log{} faild!",sysLog.toString());
}
}else{
log.debug(className + "." + methodName + "() :request log{}!",sysLog.toString());
}
}
}
接口定义的注解使用:
@ApiOperation(value = "保存测试接口", notes = "保存测试接口")
@SysLogService("保存测试接口")
@PostMapping("/test")
public boolean test(@ApiParam(value = "传入json格式", required = true) @RequestBody Test test) {
return faultApplicationService.save(test);
}