javaweb接口安全校验预备知识----spring AOP之注解方式

来源:互联网 发布:广场舞视频下载软件 编辑:程序博客网 时间:2024/05/11 15:01

关于接口安全校验的实现方案这里有两种:用拦截器或者aop对访问接口的请求先进性拦截,校验通过的才能走下面的方法。否者不处理或者返回异常。本节现说spring aop如何实现。国庆过后在更新拦截器方式的接口安全校验。

spring aop的方式有两种,注解或者配置。注解实际上也得依靠一点配置才行。下面我们先说注解方式。

测试aop的项目结构如下图:

这里写图片描述

1.引入依赖 pom.xml
我们用的是maven+jdk1.7+spring框架。这里只针对aop的实现。所以引入依赖也只是相关的jar.

<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/maven-v4_0_0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>com.echarts</groupId>    <artifactId>EchartsProject</artifactId>    <packaging>war</packaging>    <version>0.0.1-SNAPSHOT</version>    <name>EchartsProject Maven Webapp</name>    <url>http://maven.apache.org</url>    <properties>        <spring.version>4.0.2.RELEASE</spring.version>        <jdk.version>1.7</jdk.version>    </properties>    <dependencies>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-context</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>4.12</version>            <scope>test</scope>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-test</artifactId>            <version>${spring.version}</version>            <scope>test</scope>        </dependency>        <!-- Spring的面向切面编程,提供AOP(面向切面编程)实现 -->        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-aop</artifactId>            <version>${spring.version}</version>        </dependency>        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-aspects</artifactId>            <version>${spring.version}</version>        </dependency>    </dependencies>    <build>        <finalName>EchartsProject</finalName>        <plugins><!--        指定jdk版本 -->            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <version>3.3</version>                <configuration>                    <source>${jdk.version}</source>                    <target>${jdk.version}</target>                    <showWarnings>true</showWarnings>                    <encoding>UTF-8</encoding>                </configuration>            </plugin>        </plugins>    </build></project>

2.Spring默认不支持@Aspect风格的切面声明,通过<aop:aspectj-autoproxy/> 配置开启@Aspect支持。配置后,Spring就能发现用@Aspect注解的切面内并把它应用到目标对象上。spring-aop.xml即配置这个的文件,代码如下:

<?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:p="http://www.springframework.org/schema/p"    xmlns:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="            http://www.springframework.org/schema/beans             http://www.springframework.org/schema/beans/spring-beans-2.5.xsd            http://www.springframework.org/schema/aop             http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">            <aop:aspectj-autoproxy />           <!-- 声明自定义advice,读取@Aspect注解。-->            <bean  class="com.zhanglf.aop.advice.ValidSecureAdvice"></bean>            <!--声明以便注入实体类-->            <bean id="aa" class="com.zhanglf.service.ServiceTest"></bean></beans>

3.如果是启动项目,这要在web.xml中引入配置文件spring-aop.xml才行,这里也说一下。但是本项目用不到,因为我们是通过测试类加载这个配置文件的,不用让web.xml来读取配置文件。web.xml中的配置如下:

<?xml version="1.0" encoding="UTF-8"?>  <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xmlns="http://java.sun.com/xml/ns/javaee"      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"      version="3.0">      <display-name>Archetype Created Web Application</display-name>    <context-param>        <param-name>contextConfigLocation</param-name>        <param-value>classpath:META-INF/aop/spring-aop.xml</param-value>    </context-param></web-app>

4.到这里配置就完成了。下面就是aop的java实现部分。由于是实际应用中我们可能会有多个不同的切面,不同的切面针对不同的层有不同的逻辑。比如针对controller层的切面接口安全校验,针对service层的业务异常处理,针对dao层的事物处理等。所以我们把指向不同层的pointcut和处理逻辑advice分开成两个包,如下图所示。
这里写图片描述

4.1 aop也叫面向切面编程,主要分为切面指向哪里——pointcut,切面做何动作——advice。这两者都要用@Aspect注解,这里先看且向哪里ValidSecurePointCut.java,由于我们为了接口的安全校验,起名字采用ValidSecure XXX的方式。

package com.zhanglf.aop.poincut;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;/** * 明确Pointcut职责: 对于ValidSecurePointCut来说,其主要职责是定义Pointcut, 可以在此类中同时定义多个Pointcuts * 要用@Aspect注解 * @author Administrator *         Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,如第18行;二是方法签名 *         ,如第19行。方法签名必须是 *         public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观 *          */@Aspectpublic class ValidSecurePointCut {//  这句话是方法切入点,execution为执行的意思,*代表任意返回值,注意星号后面有个空格,然后是包名,.*意思是包下面的所有子包。(..)代表各种方法.    @Pointcut("execution(* com.zhanglf.service..*.*(..))")//  @Pointcut("within(com.zhanglf.service..*)"),这种表达式同上面这种是一样的效果。    public void ValidSecure() {//因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。    }}

4.2 切面做何动作?——ValidSecureAdvice.java

package com.zhanglf.aop.advice;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;/** * 对于Advice,也只能使用@Aspect来注解。 * 由于定义的有pointcut方法签名,所以不直接使用Pointcut的表达式,而是使用了Pointcut中的方法签名。 * @author Administrator * *单独定义Pointcut的好处是,一是通过使用有意义的方法名,而不是难读的Pointcut表达式,使代码更加直观;二是Pointcut可以实现共 享,被多个Advice直接调用。 *若有多个Advice调用某个Pointcut,而这个Pointcut的表达式在将来有改变时,只需修改一个地方,维 护更加方便。 */@Aspectpublic class ValidSecureAdvice {//特别注意,只有环绕通知才有入参:ProceedingJoinPoint joinPoint,其它类型的注解的方法入参可以是基本类型等,但不能是ProceedingJoinPoint,只能是JoinPoint。至于方法的返回值则是自己随便给个数据类型都行。不一定时Object类型。    @Around("com.zhanglf.aop.poincut.ValidSecurePointCut.ValidSecure()")    public Object interceptor(ProceedingJoinPoint joinPoint) throws Throwable{          System.out.println("进入环绕通知,执行的是接口校验的逻辑代码。。。");              Object object = joinPoint.proceed();//执行该方法              System.out.println("退出方法");              return object;      }      @Before("com.zhanglf.aop.poincut.ValidSecurePointCut.ValidSecure() && args(name)")          public void doAccessCheck(String name){              System.out.println(name);              System.out.println("前置通知");          } }

4.3 切面指向谁呢?我们定义好了切面,从pointcut的表达式@Pointcut("within(com.zhanglf.service..*)")知道切面指向service层的所有类的所有方法。所以我们在service层下给了个测试用的类:ServiceTest.java。

package com.zhanglf.service;public class ServiceTest {    public String show(String a){        System.out.println("进入业务方法");        return null;    }}

这样就完成了aop的代码部分。重点部分就是ValidSecureAdvice类中的这几个方法的处理逻辑,我们这里简略为控制台打印。实际项目中接口安全校验我们只用@Around或者@Before注解的方法里的处理逻辑就可以了。下面开始测试部分。
5.aop测试

package com;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.zhanglf.service.ServiceTest;public class TestAOP {     @Test      public void inteceptorTest(){          ApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/aop/spring-aop.xml");        //通过spring配置文件中声明的aa 获取  ServiceTest 的实体类,并调用类下面的方法。        ServiceTest bean = (ServiceTest)ctx.getBean("aa");        bean.show(null);     }  }

运行结果如下:
这里写图片描述
这样就把aop注解的逻辑搞明白了。这里感谢一下博主的博文!

1 使用Spring的注解方式实现AOP
2 基于@Aspect的AOP配置
3 Spring AOP 的@Aspect
4 利用Spring AOP自定义注解解决日志和签名校验