定义一个SpringBoot中间件

本文定义一个文本检测中间件,用于检测方法参数中的敏感词汇检测,如果存在敏感词汇则拦截方法,如果不存在敏感词汇则放行,敏感词汇在配置文件中定义

1.首先配置pom 

基础依赖配置

<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>cn.clearsky</groupId>
  <artifactId>whitelist2-spring-boot-starter</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>whitelist2-spring-boot-starter</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.5.RELEASE</version>
    <relativePath/>
  </parent>

<!--  依赖配置   -->
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
      <groupId>commons-beanutils</groupId>
      <artifactId>commons-beanutils</artifactId>
      <version>1.8.3</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.75</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

<!--  build 配置-->
  <build>
    <finalName>whitelist2-spring-boot-starter</finalName>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
        <includes>
          <include>**/**</include>
        </includes>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>src/test/resources</directory>
        <filtering>true</filtering>
        <includes>
          <include>**/**</include>
        </includes>
      </testResource>
    </testResources>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.12.4</version>
        <configuration>
          <skipTests>true</skipTests>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.5</version>
        <configuration>
          <encoding>${project.build.sourceEncoding}</encoding>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>${project.build.sourceEncoding}</encoding>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-source-plugin</artifactId>
        <version>2.1.2</version>
        <executions>
          <execution>
            <id>attach-sources</id>
            <goals>
              <goal>jar</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

2.定义SpringBoot扫描文件

根据SpringBoot自动装配原理可以知道需要定义一个Spring的 spring.factories 文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.bugstack.middleware.whitelist.config.WhiteListAutoConfigure

3.自定义一个注解作为切入点

package cn.clearsky.annotation;

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

/**
 * Retention(RetentionPolicy.RUNTIME) : 运行时保留
 * Target(ElementType.METHOD): 只能标记在方法上
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DoFilterKey {

    /**
     * 需要参与过滤的方法参数字段名称
     * @return
     */
    String filterFiled() default "";

    /**
     * 被拦截之后返回的信息
     * @return
     */
    String returnInterceptMsg() default "";
}

4.读取配置文件中的配置参数

这里有两块,一块是读取参数,另外一块是将参数实例化为Bean

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("clearsky.filterkey")
public class FilterKeyProperties {
    /**
     * 读取配置文件中的敏感词
     */
    private String keys;

    public String getKeys() {
        return keys;
    }
    public void setKeys(String keys) {
        this.keys = keys;
    }
}

实例化bean

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Configuration : 标志为配置类
 * ConditionalOnClass(FilterKeyProperties.class): WhiteListProperties 位于当前类路径上,才会实例化一个bean
 * EnableConfigurationProperties(FilterKeyProperties.class):加上这个注解配置文件才会自动配置进来
 */
@Configuration
@ConditionalOnClass(FilterKeyProperties.class)
@EnableConfigurationProperties(FilterKeyProperties.class)
public class FilterKeyAutoConfigure {

    /**
     * ConditionalOnMissingBean 如果不存在这个bean的时候就初始化bean 为了支持可拓展性 用户自定义bean
     * @param filterKeyProperties  配置参数bean
     * @return
     */
    @Bean("filterKeyConfig")
    @ConditionalOnMissingBean
    public String filterKeyConfig(FilterKeyProperties filterKeyProperties) {
        return filterKeyProperties.getKeys();
    }
}

4.定义切面逻辑

import cn.clearsky.annotation.DoFilterKey;
import org.apache.commons.beanutils.BeanUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Pointcut;
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.annotation.Resource;
import java.lang.reflect.Method;

/**
 * 定义切面
 */
@Aspect
@Component
public class DoFilterPoint {
    private Logger log = LoggerFactory.getLogger(DoFilterKey.class);

    /**
     * 注入敏感词汇
     */
    @Resource
    private String filterKeyConfig;

    @Pointcut("@annotation(cn.clearsky.annotation.DoFilterKey)")
    public void aopPoint2() {}

    @Around("aopPoint2()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("when the filterKeys:{}", filterKeyConfig);

        Method method = getMethod(joinPoint);
        log.info("method:{}", method);
        DoFilterKey doFilterKey = method.getAnnotation(DoFilterKey.class);
        // 校验字段值
        String filterFiledValue = getFiledKeyValue(doFilterKey.filterFiled(), joinPoint.getArgs());

        // 为空释放
        if (null == filterFiledValue || "".equals(filterFiledValue)) return joinPoint.proceed();

        String[] split = filterKeyConfig.split(",");

        // 敏感词过滤
        for (String str : split) {
            if (filterFiledValue.equals(str)) {
                // 拦截
                log.info("filterKey:{}", filterFiledValue);
                return returnRes(doFilterKey.returnInterceptMsg(), method);
            }
        }
        // 释放
        return joinPoint.proceed();
    }

    /**
     * 拦截返回
     * @param returnInterceptMsg
     * @param method
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    private Object returnRes(String returnInterceptMsg, Method method) throws InstantiationException, IllegalAccessException {
        Class<?> returnType = method.getReturnType();
        if (returnInterceptMsg == null || "".equals(returnInterceptMsg)) return returnType.newInstance();
        return returnInterceptMsg;
    }

    /**
     * 获取字段值 用于过滤操作
     * @param filterFiled
     * @param args
     * @return
     */
    private String getFiledKeyValue(String filterFiled, Object[] args) {
        String filedValue = null;
        for (Object arg : args) {
            try {
                if (null == filedValue || "".equals(filedValue)) {
                    filedValue = BeanUtils.getProperty(arg, filterFiled);
                } else {
                    break;
                }
            } catch (Exception e) {
                if (args.length == 1) {
                    return args[0].toString();
                }
            }
        }
        log.info("filedValue:{}", filedValue);
        return filedValue;
    }

    /**
     * 通过joinPoint获取方法信息
     * @param joinPoint
     * @return
     * @throws NoSuchMethodException
     */
    private Method getMethod(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        return joinPoint.getTarget().getClass().getMethod(methodSignature.getName(),methodSignature.getParameterTypes());
    }
}

5.install打包 

在需要使用的地方添加依赖,同时在配置文件中配置敏感词汇即可

remark

代码绝大多数逻辑都在注释中说明了

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值