例子还是之前的例子。仍然是对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(); }
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不能为空! */