springboot-aop面向切面编程

需求:

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

解决办法:

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

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

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

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

项目结构如下:

springboot-aop面向切面编程_第1张图片

在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.0modelVersion>

    <groupId>com.example.springbootgroupId>
    <artifactId>springboot-aopartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <packaging>jarpackaging>

    <name>springboot-aopname>
    <description>Demo project for Spring Bootdescription>

    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>1.5.12.RELEASEversion>
        <relativePath/> 
    parent>

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

    <dependencies>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-log4jartifactId>
            <version>1.3.5.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-aopartifactId>
        dependency>
        
        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>1.3.1version>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>

        
        <dependency>
            <groupId>com.github.pagehelpergroupId>
            <artifactId>pagehelperartifactId>
            <version>4.1.0version>
        dependency>
    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            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" ?>
 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 

springboot-aop面向切面编程_第2张图片

查看数据库记录:

springboot-aop面向切面编程_第3张图片

以上就是aop切面及注解的使用。


你可能感兴趣的:(springboot,spring-boot开发教程)