目录:
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接口访问频率的实现方法。
典型的缓存系统数据读取流程:
项目代码: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依赖。
2. 已有SpringBoot项目,可以在pom.xml中直接引用Redis Starter:
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
a) setStr()
b) getStr()
3. ValueOperations
a) set()
b) get()
4. ListOperations
a) lSet()
b) lGet()
5. HashOperations
a) hSet()
b) hGet()
6. SetOperations
a) sSet()
b) sGet()
三,单元测试RedisServiceTest.java
四,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
put("chk", "cache");
put("msg", str);
put("status", key.equals(str));
}};
}
3. REST接口调用RedisService示例
五,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
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,代码优雅的只需一个注解。
3. 调用示例:
七,ExceptionHandler全局处理异常
异常发生时,返回给客户端不同的状态和信息。
l 处理AccessLimitException
l 处理Redis数据读取异常:PersistenceException, DataAccessException
@RestControllerAdvice
public class ExceptionController {
@ResponseStatus(HttpStatus.TOO_MANY_REQUESTS)
@ExceptionHandler(value = AccessLimitException.class)
public Object accessLimitExceptionHandler(AccessLimitException e) {
return new HashMap
put("msg", e.getMessage());
}};
}
@ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)
@ExceptionHandler(value = {PersistenceException.class, DataAccessException.class, MessagingException.class})
public Object dataExceptionHandler(RuntimeException e) {
return new HashMap
put("msg", e.getMessage());
}};
}
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(value = Exception.class)
public Object exceptionHandler(Exception e) {
return new HashMap
put("msg", e.getMessage());
}};
}
}