3.项目中通用的系统日志

  在实际项目中,我们通常会基于注解和AOP实现系统日志功能,即记载用户调用标有日志注解的方法的一些使用信息。使用注解完成该功能还是走注解三板斧流程,链接可查看2.基础加强版面试题 - 求知律己 - 博客园 (cnblogs.com)中第四节中的注解

1.定义注解

  定义注解其实就是创建一个注解,定义其是否被Javadoc工具编译成文档(@Document),注解可以使用的地方(@Target),注解的有效期(@Retention),注解是否可被子类继承(@Inherit)。

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OperateLog {

    //信息
    String message() default "";

    //模块名
    String modular() default "";

    //业务类型(0:其他 1:新增 2:修改 3:删除)
    public BusinessType businessType() default BusinessType.OTHER;

    //操作类型(0 成功、1失败)
    String operateType() default "";

    //操作明细
    String operateDetailsType() default "";


}
系统日志的注解定义

2.使用注解

  使用注解其实就是将注解标注在哪些地方使用。 

   上述图片中,箭头指向的地方表示注解使用在方法上,其实在定义注解的代码中已经通过@Target(ElementType.Method)标识注解使用在方法上。

3.为注解注入灵魂

   为注解注入灵魂,即通过反射、注解、AOP思想对我们执行的方法提供额外的逻辑操作。如本节是为方法提供日志记载功能,也就是在方法执行前,将用户调用方法执行某操作的信息持久化到数据库中,方便信息监控和分析。

import com.ku.owo.common.aspectj.annotations.OperateLog;
import com.ku.owo.common.domain.SystemThreadLocal;
import com.ku.owo.entity.OwoOperateLog;
import com.ku.owo.entity.UserInfo;
import com.ku.owo.service.IOwoOperateLogService;


import com.ku.owo.utils.ip.IPUtils;
import com.ku.owo.utils.RequestUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * 系统日志,切面处理类
 */
@Aspect
@Component
public class LogAspect {
    @Autowired
    private IOwoOperateLogService operateLogService;

    private static Logger logger = LoggerFactory.getLogger(LogAspect.class);

    public LogAspect() {
        logger.info("************SysLogAspect********************");
    }

    //切入点注解:execution():方法执行的切入点。
    // *表示通配符表示匹配任意的返回类型。
    //com.ku.owo.controller表示包路径,指定匹配该包以该包底下的子类。
    //..通配符表示匹配包下或子包所有类和方法
    //*通配符表示匹配任意的类名
    //.通配符表示包路径分隔符
    //*通配符表示匹配任意的方法名
    //(..)参数列表:表示匹配任意参数类型和数量的方法。
    @Pointcut("execution(* com.ku.owo.controller..*.*(..))")
    public void controllerAspect() {

    }

    @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint) {
        logger.info("=====SysLogAspect前置通知开始=====");
    }

    @AfterThrowing(value = "controllerAspect()", throwing = "e")
    public void doAfter(JoinPoint joinPoint, Exception e) {
        logger.info("=====SysLogAspect异常通知开始=====");
    }

    @Around("controllerAspect()")
    public Object interceptorApplogicA(ProceedingJoinPoint point) throws Throwable {
        logger.info("=====SysLogAspect 环绕通知开始=====");

        long beginTime = System.currentTimeMillis();
        // 执行方法
        Object result = point.proceed();
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;

        // 保存日志
        saveSysLog(point, time);

        return result;
    }

    @Before("controllerAspect()")
    public void doAfter(JoinPoint joinPoint) {
        logger.info("=====SysLogAspect后置通知开始=====");
    }

    private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
        //通过连接点获取签证
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();//再通过签证调用反射的方法
        OwoOperateLog owoOperateLog = new OwoOperateLog();

        //获取方法上的注解
        OperateLog operateLog = method.getAnnotation(OperateLog.class);
        try {
            if (operateLog != null) {
                // 注解上的描述
                // 请求的方法名
                String className = joinPoint.getTarget().getClass().getName();
                String methodName = signature.getName();
                owoOperateLog.setDetails(className + "." + methodName + "()");
                // 请求的参数
                Object[] args = joinPoint.getArgs();
                // 获取request
                HttpServletRequest request = RequestUtil.getRequest();
                owoOperateLog.setIp(IPUtils.getIpAddr(request));
                owoOperateLog.setState(0);
                owoOperateLog.setModular(operateLog.modular());
                owoOperateLog.setMessage(operateLog.message());
                owoOperateLog.setBusinessType(operateLog.businessType().ordinal());
                UserInfo user = SystemThreadLocal.get();
                if (null != user) {
                    String userId = user.getUserId();
                    owoOperateLog.setCreateUser(userId);
                }
                owoOperateLog.setCreateTime(new Date());
                operateLogService.save(owoOperateLog);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
        }
        logger.info("owoOperateLog=======>" + owoOperateLog.toString());
    }
}
系统日志切面类

4.数据表、实体类

  由于我们的系统日志需要持久化到数据库中,因此需要创建表来存储系统日志,实体类来完成系统日志的对象映射。

DROP TABLE IF EXISTS `owo_operate_log`;
CREATE TABLE `owo_operate_log`  (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `ip` VARCHAR(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作主机id',
  `modular` VARCHAR(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '模块',
  `message` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作信息',
  `business_type` TINYINT(4) NULL DEFAULT NULL COMMENT '业务类型(0其它 1新增 2修改 3删除)',
  `state` INT(11) NULL DEFAULT NULL COMMENT '操作状态(1:失败,0成功)',
  `details` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '详情',
  `create_user` VARCHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建者',
  `create_time` DATETIME NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = INNODB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '操作日志表' ROW_FORMAT = DYNAMIC;
数据表
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("owo_operate_log")
@ApiModel(value="OwoOperateLog对象", description="操作日志表")
public class OwoOperateLog implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @ApiModelProperty(value = "操作主机id")
    private String ip;

    @ApiModelProperty(value = "模块")
    private String modular;

    @ApiModelProperty(value = "操作信息")
    private String message;

    @ApiModelProperty(value = "业务类型(0其它 1新增 2修改 3删除)")
    private Integer businessType;

    @ApiModelProperty(value = "操作状态(1:失败,0成功)")
    private Integer state;

    @ApiModelProperty(value = "详情")
    private String details;

    @ApiModelProperty(value = "创建者")
    private String createUser;

    @ApiModelProperty(value = "创建时间")
    private Date createTime;


}
实体类

 

posted @ 2023-11-28 16:44  求知律己  阅读(9)  评论(0编辑  收藏  举报