目录:

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接口访问频率的实现方法。


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

【从0开始Web开发实战】SpringBoot集成Redis,控制REST访问频率_第1张图片

项目代码: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依赖。

【从0开始Web开发实战】SpringBoot集成Redis,控制REST访问频率_第2张图片

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


   org.springframework.boot
   spring-boot-starter-data-redis

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操作

a) setStr()

b) getStr()

3. ValueOperations对Object操作

a) set()

b) get()

4. ListOperations对列表操作

a) lSet()

b) lGet()

5. HashOperations对哈希表操作

a) hSet()

b) hGet()

6. SetOperations对集合操作

a) sSet()

b) sGet()


三,单元测试RedisServiceTest.java

【从0开始Web开发实战】SpringBoot集成Redis,控制REST访问频率_第3张图片

四,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, Object>() {{
        put("chk", "cache");
        put("msg", str);
        put("status", key.equals(str));
    }};
}

3. REST接口调用RedisService示例

【从0开始Web开发实战】SpringBoot集成Redis,控制REST访问频率_第4张图片

五,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

【从0开始Web开发实战】SpringBoot集成Redis,控制REST访问频率_第5张图片

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,代码优雅的只需一个注解。

【从0开始Web开发实战】SpringBoot集成Redis,控制REST访问频率_第6张图片

3. 调用示例:

【从0开始Web开发实战】SpringBoot集成Redis,控制REST访问频率_第7张图片 

七,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, 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, Object>() {{
            put("msg", e.getMessage());
        }};
    }

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