Article catalog
catalogue
Custom facet (RequestLimitContract)
preface
The user-defined annotation implements the interface anti brush case, which is mainly implemented through AOP and user-defined annotation. In the actual development, we can implement some complex and repeated operations in the way of annotation + AOP. Today we mainly talk about interface anti brushing, and others will be implemented later.
preparation
First of all, before doing this case, I hope you have a certain understanding of user-defined annotations. At the same time, we should also have a certain understanding of Aop.
If you are not familiar with custom annotations, you can take a look at an article I sent earlier.
Ah ah, I finally understand that annotation is such a thing. 6000 + word understanding notes [i]
Here I use Spring boot+Redis for implementation. In fact, Redis may not be applicable. You can explore it yourself.
The construction of the environment will not be repeated here. It should be able to build projects.
AOP
Aspect oriented programming is generally to do some other operations on the existing code. For example, functions such as adding logs can be implemented using AOP.
Using AOP in springBoot requires introducing dependencies
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> <version>2.5.7</version> </dependency>
Let's briefly describe the following notes of AOP:
Annotation function:
@An aspect is usually a class in which pointcuts and notifications can be defined
@Jointpoint (connection point) a specific point in the execution of a program, usually a method call
@Advice: AOP performs enhanced processing on specific pointcuts, including @ before,@after,@afterReturning,@afterThrowing,@around
@Pointcut (pointcut) is the connection point with notification, which is mainly reflected in writing pointcut expression in the program
Here, I will not repeat the knowledge of AOP. If you have the opportunity to talk about AOP alone.
Write custom annotations
Here we create an annotation class named RequestLimit
package com.onlyqi.upup01.annotation; import org.springframework.core.annotation.Order; import java.lang.annotation.*; /** * Custom annotations restrict access */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented //Highest priority @Order(1) public @interface RequestLimit { /* * The number of accesses allowed. The default value is max_value * */ int count() default Integer.MAX_VALUE; /* * Subject to the first request to back off * For example, the first request is at 12:00, and the request time is set to one minute * If the number of accesses exceeds count in the time period of 12:01, an error will be reported, but the counting will be restarted after 12:01 instead of being inaccessible in the future * Time period, in milliseconds. The default value is one minute * Considering the above factors, in order to avoid attacks, it is recommended to set the time a little larger, such as 20 times a minute * If you want to avoid repeated submission, you need to and can only set Count to 1 and time to a smaller value, such as once a second * * */ int time() default 1; }
Custom facet (RequestLimitContract)
Redis needs to be used here, so you need to configure the relevant configurations of redis by yourself.
package com.onlyqi.upup01.aspect; import com.onlyqi.upup01.annotation.RequestLimit; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.Modifier; import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; @Aspect @Scope @Component public class RequestLimitContract { @Autowired private HttpServletResponse response; @Autowired private RedisTemplate redisTemplate; @Before("within(@org.springframework.web.bind.annotation.RestController *) && @annotation(limit)") public void requestLimit(final JoinPoint joinPoint, RequestLimit limit) throws IOException { // System.out.println("1111111111111111111111111111111111111start"); // System.out.println("target method name:" + joinpoint. Getsignature() getName()); // System.out.println("simple class name of the class to which the target method belongs:" + joinpoint. Getsignature() getDeclaringType(). getSimpleName()); // System.out.println("class name of the class to which the target method belongs:" + joinpoint. Getsignature() getDeclaringTypeName()); // System.out.println("target method declaration type:" + modifier. ToString (joinpoint. Getsignature() getModifiers())); Object[] args = joinPoint.getArgs(); System.out.println(args+"1111111111111111111111111111111111111end"); HttpServletRequest request = null; for (int i = 0; i < args.length; i++) { if (args[i] instanceof HttpServletRequest) { request = (HttpServletRequest) args[i]; break; } } if (request == null) { return; } String ip = request.getRemoteHost(); String url = request.getRequestURL().toString(); String key = "req_limit_".concat(url).concat(ip); // redisTemplate.opsForValue().set("1","111111"); Long increment = redisTemplate.opsForValue().increment(key); if (increment <= 1) { redisTemplate.expire(key, limit.time(), TimeUnit.SECONDS); } if (increment > limit.count()) { //throw new RuntimeException("access is too fast, please pass" + limit.time() + "access in seconds"); output(response,"Access frequency is too fast, please pass" + limit.time() + "Access in seconds"); } } private void output(HttpServletResponse response, String msg) throws IOException { response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); ServletOutputStream os = null; try { os = response.getOutputStream(); os.write(msg.getBytes(StandardCharsets.UTF_8)); } finally { if (os != null) { os.flush(); os.close(); } } } }
@scope: the annotation is used for value. After the class is managed by Spring, it is single instance.
@within: used to match all methods holding the specified annotation type;
@annotation(limit): is the method that matches the annotation containing the limit.
@@Before ("within (@org.springframework.web.bind.annotation.RestController *) & & @ annotation (limit)"): indicates that it is valid for methods containing @ RestController annotation class and methods containing limit
Get HttpServletRequest from jointPoint and add it if necessary.
For those unfamiliar to Redis, only two methods can be used: incr means the key value plus one. If the key value does not exist, create a key value and the initial value is 1 Expire means that the key will disappear as long as time elapses.
Create Controller for testing
package com.onlyqi.upup01.controller; import com.onlyqi.upup01.annotation.RequestLimit; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; @RestController public class TestController { public int count=0; @RequestLimit(count = 5,time = 2) @RequestMapping("/test") public String test(HttpServletRequest request ){ System.out.println("============================"+count); count++; return "Test page"; } }
Use custom annotations on the interface corresponding to the test.
yml configuration:
server: port: 8089 spring: redis: # redis database index (0 by default). We use the database with index 3 to avoid conflicts with other databases database: 3 # redis server address (loaclhost by default) host: 8.196.265.98 # redis port (6379 by default) port: 6379
Start project: access the corresponding interface
Normal speed access, normal access.
In case of quick access, it will be intercepted.
Here, the case is over. Although the function is simple, the main thing to learn is thought. Other functions can be realized in this way. It depends on your imagination.
Risby~~~~
--------
I reprinted it:
Original link: https://blog.csdn.net/weixin_46897073/article/details/122000190