table of Contents:
1. SpringBoot integrated Redis
2. Packaging Services RedisService.java
3. Unit testing RedisServiceTest.java
4. the Redis function calls to read and write
5. The the Redis tips: a control interface to the access frequency REST
6. The package Annotation annotation, flexible control of the access frequency REST interface
7. code optimization: the ExceptionHandler global process exception
Redis is a key-value high-performance database structures commonly used in the cache system, the response speed increasing concurrency. SpringBoot Redis simply integrated configuration, this share package RedisService service, further information on the use of annotations and Redis, flexible interface to access control method to achieve frequency REST.
A typical cache system reads process data:
Item code: https://github.com/jextop/StarterApi/
Sample Code: https://github.com/rickding/HelloJava/tree/master/HelloAnnotation
A, SpringBoot integrated Redis
Code file |
Function Points |
|
SpringBoot integrated 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:
<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
四,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示例
五,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<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());
}};
}
}