zoukankan      html  css  js  c++  java
  • springboot-aop面向切面编程

    需求:

        项目中需要记录用户操作信息,例如用户登陆系统后做了那些操作,需要有具体的日志记录。

    解决办法:

    1、编写操作记录日志业务类,在使用的方法中调用(一般记录方式)。

    2、使用面向切面方式记录日志,例如针对某些业务处理方法进行日志记录。

    3、通过注解方式,在调用的业务方法上增加日志类注解。

    推荐使用第二、第三中方式,使用灵活,如果不需要日志记录,将切面取消即可,第一种不够灵活。一些介绍使用注解方式编写日志记录。

    项目结构如下:

    在pom.xml导入依赖包

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.springboot</groupId>
    <artifactId>springboot-aop</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springboot-aop</name>
    <description>Demo project for Spring Boot</description>

    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.12.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.7</java.version>
    </properties>

    <dependencies>

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    </dependency>
    <!-- log4j 日志记录 -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j</artifactId>
    <version>1.3.5.RELEASE</version>
    </dependency>
    <!--aop依赖包-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <!-- 引入mybatis 数据库操作包 -->
    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.1</version>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <!-- 引入mybatis 分页插件 -->
    <dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.1.0</version>
    </dependency>
    </dependencies>

    <build>
    <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    </plugins>
    </build>


    </project>
    在application.properties配置文件中增加数据库连接
    #server.port=8090

    #标示使用的是mysql/oracle/sqlserver
    datasource.type=mysql
    #mysql数据连接
    spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.username=root
    spring.datasource.password=root
    #spring.datasource.max-active=20
    #spring.datasource.max-idle=8
    #spring.datasource.min-idle=8
    #spring.datasource.initial-size=20

    #mybatis 配置
    # 配置映射文件加载
    mybatis.mapper-locations=classpath*:mapper/**/*.xml
    # 实体类通过别名使用
    #mybatis.type-aliases-package=


    自定义注解类

    package com.example.springboot.aop.annotation;

    import java.lang.annotation.*;

    /**
    *自定义注解 拦截Controller
    */

    @Target({ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SystemControllerLog {
    String LogAction() default "";
    String LogContent() default "";
    int ModuleID() default 0;
    }
    实体类

    package com.example.springboot.aop.entity;

    public class SystemLogModel {
    private String LogAction;
    private String LogContent;
    private String FlagID;
    private String FlagName;
    private String LogIP;
    private String TimeFlag;
    private int ModuleID;

    自定义切面类

    package com.example.springboot.aop.aspect;

    import com.example.springboot.aop.annotation.SystemControllerLog;
    import com.example.springboot.aop.dao.SystemLogMapper;
    import com.example.springboot.aop.entity.SystemLogModel;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;

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

    /**
    * 切点类
    */
    @Aspect
    @Component
    public class SystemLogAspect {

    // 本地异常日志记录对象
    private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);

    @Autowired
    private SystemLogMapper systemLogMapper;

    // Controller层切点,针对在业务模块标注SystemControllerLog注解记录日志
    @Pointcut("@annotation( com.example.springboot.aop.annotation.SystemControllerLog )")
    public void controllerAspect() {
    }

    /**
    * 前置通知 用于拦截Controller层记录用户的操作
    *
    * @param joinPoint 切点
    */
    @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint) {

    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
    .getRequestAttributes()).getRequest();
    try {
    // 请求的IP
    String logIP = request.getHeader("X-Real-IP");
    // if (StringUtils.isEmpty(logIP)) {
    // logIP = request.getRemoteAddr();
    // }
    String userID = request.getParameter("UserID");
    String userName = request.getParameter("UserName");
    // if (StringUtils.isEmpty(userID) || StringUtils.isEmpty(userName)) {
    // logger.debug("操作日志-->日志添加:用户名或用户ID为空,返回不添加日志!");
    // return;
    // }

    SystemLogModel slm = getControllerMethodDescription(joinPoint);
    slm.setLogIP(logIP);
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:MM:ss");
    String date = dateFormat.format(new Date());
    slm.setTimeFlag(date);
    slm.setFlagID(userID);
    slm.setFlagName(userName);

    // *========控制台输出=========*//
    logger.debug("=====注解参数获取开始=====");
    logger.debug("请求方法:"
    + (joinPoint.getTarget().getClass().getName() + "."
    + joinPoint.getSignature().getName() + "()"));
    logger.debug("操作模块:" + slm.getModuleID());
    logger.debug("操作方法:" + slm.getLogAction());
    logger.debug("操作内容:" + slm.getLogContent());
    logger.debug("请求IP:" + slm.getLogIP());
    logger.debug("FlagID:" + slm.getFlagID());
    logger.debug("FlagName:" + slm.getFlagName());
    // *========数据库日志=========*//
    int res = systemLogMapper.saveOrUpdate(slm);
    if (res > 0) {
    logger.info(">>>>>>>>保存日志成功");
    }
    } catch (Exception e) {
    // 记录本地异常日志
    logger.error("前置通知异常,保存日志异常信息:{}", e.getMessage());
    }
    }

    /**
    * 获取注解中对方法的描述信息 用于Controller层注解
    *
    * @param joinPoint 切点
    * @return 方法描述
    * @throws Exception
    */
    public static SystemLogModel getControllerMethodDescription(
    JoinPoint joinPoint) throws Exception {
    String targetName = joinPoint.getTarget().getClass().getName();
    String methodName = joinPoint.getSignature().getName();
    Object[] arguments = joinPoint.getArgs();
    Class targetClass = Class.forName(targetName);
    Method[] methods = targetClass.getMethods();
    String description = "";
    SystemControllerLog log;
    SystemLogModel logM = new SystemLogModel();
    for (Method method : methods) {
    if (method.getName().equals(methodName)) {
    Class[] clazzs = method.getParameterTypes();
    if (clazzs.length == arguments.length) {
    log = method.getAnnotation(SystemControllerLog.class);
    logM.setModuleID(log.ModuleID());
    logM.setLogAction(log.LogAction());
    logM.setLogContent(log.LogContent());
    break;
    }
    }
    }
    return logM;
    }
    }

    mapper接口

    package com.example.springboot.aop.dao;

    import com.example.springboot.aop.entity.SystemLogModel;
    import org.apache.ibatis.annotations.Mapper;

    @Mapper
    public interface SystemLogMapper {

    //保存日志
    public int saveOrUpdate(SystemLogModel systemLogModel);
    }
    mapper配置文件
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.example.springboot.aop.dao.SystemLogMapper">

    <insert id="saveOrUpdate" parameterType="com.example.springboot.aop.entity.SystemLogModel">
    insert into test_system_Operation_log(FlagID,FlagName,LogAction,LogContent,LogIP,ModuleID,TimeFlag)
    values(#{FlagID},#{FlagName},#{LogAction},#{LogContent},#{LogIP},#{ModuleID},#{TimeFlag})
    </insert>

    </mapper>
    创建controller类

    package com.example.springboot.aop.controller;

    import com.example.springboot.aop.annotation.SystemControllerLog;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;

    /**
    * @desc aop测试日志记录
    * @Author wangsh
    * @date 2018/5/7 20:57
    */
    @RestController
    @RequestMapping("/aop")
    public class AopController {

    @SystemControllerLog(LogAction = "查询", ModuleID = 12, LogContent = "测试aop示例")
    @ResponseBody
    @RequestMapping("/hello")
    public String hello() {

    return "hello";
    }
    }

    创建启动服务类

    package com.example.springboot.aop;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.ComponentScan;

    //配置扫描指定的包及包下的所以子集
    @ComponentScan("com.example.springboot.aop")
    @SpringBootApplication
    public class SpringbootAopApplication {

    public static void main(String[] args) {
    SpringApplication.run(SpringbootAopApplication.class, args);
    }
    }
    启动服务测试
    浏览器访问: http://localhost:8080//aop/hello 

    查看数据库记录:

    以上就是aop切面及注解的使用。
    ---------------------
    作者:1057718341_h
    来源:CSDN
    原文:https://blog.csdn.net/seashouwang/article/details/80232811
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    树-1
    javaSE 2
    (蓝桥杯)蛇形矩阵的求法
    年轻母牛的故事
    互质环(序列)与最小公倍数的几种求法
    算法的复杂度
    Halo开源博客项目配置
    IDEA报错稀有语法问题
    带你跑ELADMIN后台管理系统开源项目
    相比c++,Java在基础语法的改变
  • 原文地址:https://www.cnblogs.com/sjqq/p/10241811.html
Copyright © 2011-2022 走看看