既然有切面编程,已经有Before,After-returning,After,After-throwing,Around这五种通知,已经非常完善了。但是为什么要自定义一个注解,配合拦截器使用呢?有一个问题,就只在切面编程中,我们是无法获取当前线程的HttpServletRequest、HttpServletResponse的,所以这个时候我们可以使用Handler结合@Interface的方式解决一些MVC层公用的代码的实现,例如访问限流。
0.pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>Cairo-SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.3.1.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration> <!--设置程序执行的主类 -->
<mainClass>com.jz.WebsocketApplication</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
<finalName>annotation-handler-demo</finalName>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
1.自定义注解(不需要写校验器类)
package com.xdl.annotation.handler.config.vali;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(METHOD)
/**
* @author liurui
* @date 2019年9月14日
*/
public @interface MyAnnotation {
boolean required();
int expireSeconds();
}
2.自定义拦截器
package com.xdl.annotation.handler.config.web;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.xdl.annotation.handler.config.vali.MyAnnotation;
/**
* @author liurui
* @date 2019年9月14日
*/
@Component
public class AnnotationHandler extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if(handler instanceof HandlerMethod) {
MyAnnotation myAnnotation = ((HandlerMethod) handler).getMethodAnnotation(MyAnnotation.class);
if(myAnnotation != null) {
boolean required = myAnnotation.required();
int expireSeconds = myAnnotation.expireSeconds();
System.out.println(required+"============"+expireSeconds);
MyThreadLocal.setStr(required+"_"+expireSeconds);
}
}
return true;
}
}
3.将Handler配置到Web中
package com.xdl.annotation.handler.config.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author liurui
* @date 2019年9月14日
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
AnnotationHandler annotationHandler;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(annotationHandler);
}
}
4.小技巧,将需要信息放入ThreadLocal中
package com.xdl.annotation.handler.config.web;
/**
* @author liurui
* @date 2019年9月14日
*/
public class MyThreadLocal {
public static ThreadLocal<String> localStr = new ThreadLocal<>();
public static void setStr(String str) {
localStr.set(str);
}
public static String getStr() {
return localStr.get();
}
}
5.启动类,访问测试
package com.xdl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xdl.annotation.handler.config.vali.MyAnnotation;
import com.xdl.annotation.handler.config.web.MyThreadLocal;
import com.xdl.annotation.handler.util.result.AllResult;
/**
* @author liurui
* @date 2019年9月14日
*/
@SpringBootApplication
@RestController
@RequestMapping("/validator")
public class AHApplication {
@GetMapping("/param")
@MyAnnotation(required=false,expireSeconds=10)
public AllResult vali(String param) {
String str = MyThreadLocal.getStr();
return AllResult.ok(param+"=="+str);
}
public static void main(String[] args) {
SpringApplication.run(AHApplication.class, args);
}
}
6.测试结果
在访问http://localhost:8080/validator/param?param=dkdk时候
这里提供一个思路上面说的访问限流;就是可以将每一个URI放入redis中,然后时间就是你需要限流的时间,能够访问的次数就是需要放入的值,可以使用incr操作增加,如果次数大于你限制的,那就直接利用response返回对应提醒的JSON结果,如果需要详细的限流demo可以下方留言。
本次demo源码:
链接:https://pan.baidu.com/s/17onWNRdhUpygGvWuALuZrA
提取码:876u