#IT明星不是梦#【从0开始Web开发实战】SpringBoot集成Redis,控制REST访问频率

目录:

1. SpringBoot集成Redis

2. 封装服务RedisService.java

3. 单元测试RedisServiceTest.java

4. Redis读写功能调用

5. Redis使用技巧:控制REST接口访问频率

6. 封装Annotation注解,灵活控制REST接口访问频率

7. 代码优化:ExceptionHandler全局处理异常


Redis是一个高性能的key-value数据库,常用于搭建缓存系统,提高并发响应速度。SpringBoot集成Redis只需简单配置,本文分享封装的RedisService服务,进一步介绍使用注解和Redis,灵活控制REST接口访问频率的实现方法。


典型的缓存系统数据读取流程:

image.png

项目代码:https://github.com/jextop/StarterApi/

示例代码:https://github.com/rickding/HelloJava/tree/master/HelloAnnotation


一,SpringBoot集成Redis


代码文件

功能要点

SpringBoot集成Redis

pom.xml

引入Redis依赖spring-boot-starter-data-redis

application.yml

配置Redis服务器host, port

封装RedisService服务

RedisService.java

封装Redis调用:RedisTemplate, ValueOperations, ListOperations, HashOperations, SetOperations

单元测试

RedisServiceTest.java

测试封装的Redis功能函数

Redis读写功能调用

CheckController.java

增加REST接口/chk/cache,调用Redis读写功能

1. 新建SpringBoot项目时,选中Redis,将自动添加Redis依赖。

image.png

2. 已有SpringBoot项目,可以在pom.xml中直接引用Redis Starter:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

3. application.yml中配置Redis服务器信息:

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    database: 0
    password:
    timeout: 100
    jedis:
      pool:
        max-active: 8
        max-wait: -1
        max-idle: 10
        min-idle: 0


二,封装服务RedisService.java,调用Redis功能函数

1. 使用StringRedisTemplate对String类型的key和value操作

2. 使用ValueOperations<String, String>对String操作

a) setStr()

b) getStr()

3. ValueOperations<Object, Object>对Object操作

a) set()

b) get()

4. ListOperations<Object, Object>对列表操作

a) lSet()

b) lGet()

5. HashOperations<Object, Object, Object>对哈希表操作

a) hSet()

b) hGet()

6. SetOperations<Object, Object>对集合操作

a) sSet()

b) sGet()


三,单元测试RedisServiceTest.java

image.png

四,Redis读写功能调用

1. 增加RestController:CheckController.java

2. 增加REST接口/chk/cache,调用Redis读写功能

@GetMapping(value = "/chk/cache")
public Object cache(@RequestAttribute(required = false) String ip) {
    // Get a unique key
    String key = String.format("cache_test_%s_%s_缓存", ip, CodeUtil.getCode());

    // Set cache
    redisService.setStr(key, key, 3);

    // Get cache
    String str = redisService.getStr(key);
 
    // Delete key
    redisService.delStr(key);

    return new HashMap<String, Object>() {{
        put("chk", "cache");
        put("msg", str);
        put("status", key.equals(str));
    }};
}

3. REST接口调用RedisService示例

image.png

五,Redis使用技巧:控制REST接口访问频率

1,功能设计:统计API在指定时间段内的访问次数,进行频率控制。

2,实现要点:将接口访问频率控制逻辑实现在解释器和注解中。

代码文件

功能

AccessInterceptor.java

定义解释器

AccessLimitException.java

声明访问频率异常

WebConfig.java

注册解释器

AccessLimited.java

定义注解@AccessLimited

ExceptionController.java

ExceptionHandler处理访问频率异常

代码下载:https://github.com/jextop/StarterApi/tree/master/src/main/java/com/starter/

├── interceptor/AccessInterceptor.java

├── exception/AccessLimitException.java

├── config/WebConfig.java

├── annotation/AccessLimited.java

├── controller/ExceptionController.java


3,处理流程:

- Redis统计指定时间段内的访问次数,根据HttpRequest生成key

- Interceptor解释器拦截,实现访问频率控制逻辑

- 抛出异常AccessLimitException

image.png

String key = String.format("%s_%s:%s",
        request.getSession().getId(),
        request.getMethod(),
        request.getRequestURI()
);
try {
    long count = redisService.incr(key);
    if (count <= 5)) {
        if (count == 1) {
            redisService.expire(key, 1);
        }
        return true;
    }
} catch (RedisConnectionFailureException e) {
    return true;
}
throw new AccessLimitException();


六,封装Annotation注解,实现灵活的控制规则

1. 增加注解@AccessLimited

声明REST接口期望的访问频率控制规则:多长时间内允许访问多少次。然后更新代码,判断时使用accessLimited.count()和accessLimited.seconds()

@Order(Ordered.HIGHEST_PRECEDENCE)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimited {
    int count() default 5;
    int seconds() default 1;
}


2. REST接口引用@AccessLimited,代码优雅的只需一个注解。

image.png

3. 调用示例:

image.png 

七,ExceptionHandler全局处理异常

异常发生时,返回给客户端不同的状态和信息。

处理AccessLimitException

处理Redis数据读取异常:PersistenceException, DataAccessException

@RestControllerAdvice
public class ExceptionController {
    @ResponseStatus(HttpStatus.TOO_MANY_REQUESTS)
    @ExceptionHandler(value = AccessLimitException.class)
    public Object accessLimitExceptionHandler(AccessLimitException e) {
        return new HashMap<String, Object>() {{
            put("msg", e.getMessage());
        }};
    }

    @ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)
    @ExceptionHandler(value = {PersistenceException.class, DataAccessException.class, MessagingException.class})
    public Object dataExceptionHandler(RuntimeException e) {
        return new HashMap<String, Object>() {{
            put("msg", e.getMessage());
        }};
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public Object exceptionHandler(Exception e) {
        return new HashMap<String, Object>() {{
            put("msg", e.getMessage());
        }};
    }
}


猜你喜欢

转载自blog.51cto.com/13851865/2470194