Spring笔记 #02# 利用切面和注解校验方法参数

例子还是之前的例子。仍然是对mage进行法术攻击时的咒语进行校验,不过略微提高了扩展性。

应用示例

1、在.properties文件中定义参数格式(正则):

sp1=^\\D*hello\\D*$
sp2=^\\D*world\\D*$

2、对需要检查格式的方法参数进行注解,注解中传入的参数需要与.properties文件中的定义相对应:

package sample.spring.iocbasis.hero;

import sample.spring.iocbasis.annotation.CheckFormat;

public interface Mage {
    
    void attack(@CheckFormat("sp1") String sp1, @CheckFormat("sp2")String sp2);
}
package sample.spring.iocbasis.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.PARAMETER)
public @interface CheckFormat {
    String value();
}
注解.java

3、定义切面:

package sample.spring.iocbasis.weapon;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import sample.spring.iocbasis.annotation.CheckFormat;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Parameter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;

public class MagicBook implements Weapon {

    private static final Logger LOGGER = LogManager.getLogger();

    private static int count = 0;

    private int no = ++count;

    private static Map<String, Pattern> map = new HashMap<>();

    static {
        // 把.properties文件里的键值对读到内存里
        Properties prop = new Properties();
        String filename = "\\easy-validator.properties";
        try (InputStream input = MagicBook.class.getClassLoader().getResourceAsStream(filename)){
            if (input == null) {
                throw new RuntimeException("Sorry, unable to find " + filename);
            }
            prop.load(input);
            Enumeration<?> e = prop.propertyNames();
            while (e.hasMoreElements()) {
                String key = (String) e.nextElement();
                String value = prop.getProperty(key);
                map.put(key, Pattern.compile(value));
            }
        } catch (IOException e) {
            throw new RuntimeException("An exception occurred while reading " + filename, e);
        }
    }

    public void magicLimit(ProceedingJoinPoint jp) {
        try {
            LOGGER.info("{}试图发动一次魔法攻击,正在检查咒语格式 ...", jp.getThis());
            // 获取参数对象以便获得注解值
            MethodSignature signature = (MethodSignature) jp.getSignature();
            Parameter[] parameters = signature.getMethod().getParameters();
            // 获取参数值
            Object[] args = jp.getArgs();
            // 逐个参数进行判断
            for (int i = 0; i != args.length; ++i) {
                if (args[i] instanceof String) {
                    // 获取参数对应格式名(默认即为参数名)
                    String formatName = parameters[i].getAnnotation(CheckFormat.class).value();
                    String arg = (String) args[i];
                    // 非空检查
                    if (StringUtils.isBlank(arg)) {
                        LOGGER.info("{}不能为空!", formatName);
                        return;
                    } else {
                        Pattern pattern = map.get(formatName);
                        // 程序员要确保格式已经定义
                        if (pattern == null) throw new RuntimeException(formatName + "格式未定义");
                        // 格式检查
                        if (!pattern.matcher(arg).matches()) {
                            LOGGER.info("{}格式不正确!", formatName);
                            return;
                        }
                    }
                }
            }
            // 所有字符串检查通过才放行
            jp.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    @Override
    public void attack() {

    }

    @Override
    public String toString() {
        return "MagicBook{" +
                "no=" + no +
                '}';
    }
}

4、在IOC容器的配置文件中应用切面:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="magicBook" class="sample.spring.iocbasis.weapon.MagicBook"/>

    <aop:config>
        <aop:aspect ref="magicBook">
            <aop:pointcut id="mageAttack"
                          expression="execution(* sample.spring.iocbasis.hero.Mage.*(..))" />
            <aop:around pointcut-ref="mageAttack" method="magicLimit" />
        </aop:aspect>
    </aop:config>
</beans>

5、测试切面:

package sample.spring.iocbasis;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import sample.spring.iocbasis.hero.Mage;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("\\spring\\config.xml");
        Mage mage = context.getBean("mage", Mage.class);
        mage.attack("hello", "world.");
        mage.attack("hlo", "worl.");
        mage.attack("hello", "        ");
    }
}
/*
output=
MageImpl{no=1}试图发动一次魔法攻击,正在检查咒语格式 ...
MageImpl{no=1}用MagicBook{no=1}发起了一次攻击
MageImpl{no=1}试图发动一次魔法攻击,正在检查咒语格式 ...
sp1格式不正确!
MageImpl{no=1}试图发动一次魔法攻击,正在检查咒语格式 ...
sp2不能为空!
 */

猜你喜欢

转载自www.cnblogs.com/xkxf/p/10340965.html