实现自定义注解存储操作日志功能

1.自定义注解

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

/**
 * @author LWL
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {

    String value() default "";

    int type() default 0;
}
package com.guangyi.project.entity.system_set;

import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Id;
import java.io.Serializable;
import java.util.Date;


/**
 * {@code 功能描述 Log实体}
 * @author LWL
 * @since 2021-07-06 14:12:15
 * @version 1.0
 */
@Data
@NoArgsConstructor
public class Log implements Serializable {
	private static final long serialVersionUID = 1L;
	
	/**
	 * {@code 功能描述: id}
	 */
		@Id
		private Long id;
	/**
	 * {@code 功能描述: 用户id}
	 */
		private Long userId;
	/**
	 * {@code 功能描述: 描述}
	 */
		private String description;
	/**
	 * {@code 功能描述: 异常详细}
	 */
		private String exceptionDetail;
	/**
	 * {@code 功能描述: 日志类型}
	 */
		private String logType;
	/**
	 * {@code 功能描述: 方法名}
	 */
		private String method;
	/**
	 * {@code 功能描述: 参数}
	 */
		private String params;
	/**
	 * {@code 功能描述: 请求ip}
	 */
		private String requestIp;
	/**
	 * {@code 功能描述: 请求耗时}
	 */
		private Long time;
	/**
	 * {@code 功能描述: 用户名}
	 */
		private String username;
	/**
	 * {@code 功能描述: 地址}
	 */
		private String address;
	/**
	 * {@code 功能描述: 浏览器}
	 */
		private String browser;
	/**
	 * {@code 功能描述: }
	 */
		private Integer type;
	/**
	 * {@code 功能描述: 是否删除}
	 */
		private Integer isDel;
	/**
	 * {@code 功能描述: }
	 */
		private Date createdate;
	/**
	 * {@code 功能描述: }
	 */
		private String createuser;
	/**
	 * {@code 功能描述: }
	 */
		private Date changedate;
	/**
	 * {@code 功能描述: }
	 */
		private String changeuser;

	public Log(String logType, Long time) {
		this.logType = logType;
		this.time = time;
	}
}

2.配置环绕通知和异常通知

package com.guangyi.project.aspect;

import com.guangyi.project.entity.system_set.Log;
import com.guangyi.project.security.SecurityUserDetails;
import com.guangyi.project.service.LogService;
import com.guangyi.project.utils.RequestHolder;
import com.guangyi.project.utils.StringUtils;
import com.guangyi.project.utils.ThrowableUtil;
import com.guangyi.project.utils.UserUtil;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * @author LWL
 */
@Component
@Aspect
@Slf4j
public class LogAspect {

    @Autowired
    private LogService logService;

    ThreadLocal<Long> currentTime = new ThreadLocal<>();

    /**
     * 配置切入点
     */
    @Pointcut("@annotation(com.guangyi.project.config.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();
        //获取当前登录用户信息
        SecurityUserDetails loginUser = UserUtil.getLoginUser(request);
        //获取浏览器信息
        String ua = request.getHeader("User-Agent");
        //转成UserAgent对象
        UserAgent userAgent = UserAgent.parseUserAgentString(ua);
        //获取浏览器信息
        Browser browser = userAgent.getBrowser();
        //浏览器名称
        String browserName = browser.getName();
        log.setBrowser(browserName);
        logService.save(loginUser.getUsername(),
                StringUtils.getIp(request), joinPoint,
                log, loginUser.getId());
        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();
        log.setExceptionDetail(ThrowableUtil.getStackTrace(e));
        HttpServletRequest request = RequestHolder.getHttpServletRequest();
        SecurityUserDetails loginUser = UserUtil.getLoginUser(request);
        //获取浏览器信息
        String ua = request.getHeader("User-Agent");
        //转成UserAgent对象
        UserAgent userAgent = UserAgent.parseUserAgentString(ua);
        //获取浏览器信息
        Browser browser = userAgent.getBrowser();
        //浏览器名称
        String browserName = browser.getName();
        log.setBrowser(browserName);
        logService.save(loginUser.getUsername(),
                StringUtils.getIp(request),
                (ProceedingJoinPoint) joinPoint, log, loginUser.getId());
    }
}

RequestHolder

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * 获取 HttpServletRequest
 * @author LWL
 * @date 2018-11-24
 */
public class RequestHolder {

    public static HttpServletRequest getHttpServletRequest() {
        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
    }
}
import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * 异常工具 2021-07-06
 * @author LWL
 */
public class ThrowableUtil {

    /**
     * 获取堆栈信息
     */
    public static String getStackTrace(Throwable throwable) {
        StringWriter sw = new StringWriter();
        try (PrintWriter pw = new PrintWriter(sw)) {
            throwable.printStackTrace(pw);
            return sw.toString();
        }
    }
}

3.service

package com.guangyi.project.service;

import com.guangyi.project.entity.system_set.Log;
import com.guangyi.project.model.system.MessageBean;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.scheduling.annotation.Async;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * {@code 功能描述: Log的service层}
 * @author LWL
 * @since 2021-07-02 11:35:38
 * @version 1.0
 */
public interface LogService {

    /**
     * 保存日志数据
     * @param username 用户
     * @param browser 浏览器
     * @param ip 请求IP
     * @param joinPoint /
     * @param log 日志实体
     */
    @Async
    void save(String username, String ip, ProceedingJoinPoint joinPoint, Log log, Long uid);
    /**
     * @description: 操作日志
     * @param httpServletRequest
     * @param map
     * @return: com.guangyi.project.model.system.MessageBean
     * @author: LWL
     * @time: 2021/7/6 16:25
     */
    MessageBean operateLog(HttpServletRequest httpServletRequest, Map<String, Object> map);
}
package com.guangyi.project.service.impl;

import cn.hutool.json.JSONObject;
import com.guangyi.project.config.ErrorEnum;
import com.guangyi.project.entity.system_set.Admin;
import com.guangyi.project.entity.system_set.Log;
import com.guangyi.project.entity.user.Baseuser;
import com.guangyi.project.mapper.system_set.AdminMapper;
import com.guangyi.project.mapper.system_set.LogMapper;
import com.guangyi.project.mapper.user.BaseuserMapper;
import com.guangyi.project.model.querydo.LogDO;
import com.guangyi.project.model.system.MessageBean;
import com.guangyi.project.security.SecurityUserDetails;
import com.guangyi.project.service.LogService;
import com.guangyi.project.service.PkSequenceService;
import com.guangyi.project.utils.ErrorInfoUtil;
import com.guangyi.project.utils.ExceptionFormatUtil;
import com.guangyi.project.utils.StringUtils;
import com.guangyi.project.utils.UserUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class LogServiceImpl extends BaseService implements LogService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private LogMapper logMapper;
    @Resource
    private PkSequenceService pkSequenceService;
    @Resource
    private AdminMapper adminMapper;
    @Resource
    private BaseuserMapper baseuserMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(String username, String ip, ProceedingJoinPoint joinPoint, Log log, Long uid) {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        com.guangyi.project.config.Log aopLog = method.getAnnotation(com.guangyi.project.config.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 && argValues.length>1) {
            for (int i = 1; i < argValues.length; i++) {
                params.append(" ").append(argNames[i]).append(": ").append(argValues[i]);
            }
        }else {
            params.append("无参数");
        }
        // 描述
        if (log != null) {
            log.setDescription(aopLog.value());
        }
        //类型 0-后台 1-APP
        log.setType(aopLog.type());
        if (uid != null) {
            log.setUserId(uid);
        }
        assert log != null;
        log.setRequestIp(ip);

        String loginPath = "login";
        if (loginPath.equals(signature.getName())) {
            try {
                assert argValues != null;
                username = new JSONObject(argValues[0]).get("username").toString();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        log.setAddress(StringUtils.getCityInfo(log.getRequestIp()));
        log.setMethod(methodName);
        log.setUsername(username);
        log.setParams(params.toString() + " }");
        Long maxId = pkSequenceService.getMaxIdByTableName("log");
        log.setId(maxId);
        log.setChangedate(new Date());
        log.setCreatedate(new Date());
        log.setChangeuser(username);
        log.setCreateuser(username);
        log.setIsDel(0);
        logMapper.save(log);
    }

    @Override
    public MessageBean operateLog(HttpServletRequest httpServletRequest, Map<String, Object> map) {
        MessageBean result = new MessageBean();
        SecurityUserDetails loginUser = UserUtil.getLoginUser(httpServletRequest);
        try {
            long count = logMapper.count(map);
            List<LogDO> list = logMapper.list(map);
            if (!CollectionUtils.isEmpty(list)){
                list.forEach(x->{
                    if (x.getType()==0){
                        Admin admin = adminMapper.selectByPrimaryKey(x.getUserId());
                        x.setRealName(admin.getRealName());
                        x.setUsername(admin.getMobile());
                    }else {
                        Baseuser baseuser = baseuserMapper.selectByPrimaryKey(x.getUserId());
                        x.setRealName(baseuser.getNickname());
                        x.setUsername(baseuser.getMobile());
                    }
                });
            }
            result.setData(list);
            result.setTotal(count);
            result.setToken(loginUser.getToken());
        }catch (Exception e){
            logger.error(ErrorInfoUtil.getErrorInfo(e));
            throw ExceptionFormatUtil.formatException(e, ErrorEnum.GETINFO_ERROR);
        }
        return result;
    }
}

4.在接口上使用定义的注解

在这里插入图片描述

5.表结构

在这里插入图片描述

CREATE TABLE `log` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `user_id` bigint(20) DEFAULT NULL COMMENT '用户id',
  `description` varchar(255) DEFAULT NULL COMMENT '描述',
  `exception_detail` text COMMENT '异常详细',
  `log_type` varchar(255) DEFAULT '' COMMENT '日志类型',
  `method` varchar(255) DEFAULT NULL COMMENT '方法名',
  `params` text COMMENT '参数',
  `request_ip` varchar(255) DEFAULT NULL COMMENT '请求ip',
  `time` bigint(20) DEFAULT NULL COMMENT '请求耗时',
  `username` varchar(255) DEFAULT NULL COMMENT '用户名',
  `address` varchar(255) DEFAULT NULL COMMENT '地址',
  `browser` varchar(255) DEFAULT NULL COMMENT '浏览器',
  `type` smallint(6) DEFAULT '0',
  `is_del` smallint(1) DEFAULT '0' COMMENT '是否删除',
  `createdate` datetime NOT NULL,
  `createuser` varchar(100) NOT NULL,
  `changedate` datetime NOT NULL,
  `changeuser` varchar(100) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

查看操作日志
在这里插入图片描述
查看异常日志
在这里插入图片描述
查看报错信息
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值