依赖
<!-- redis --> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- pool 对象池 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.43</version> </dependency>
配置yml
spring: # redis 配置 redis: # 地址 host: xxx.xxx.xxx.xxx # 端口,默认为6379 port: 6379 # 数据库索引 database: 3 # 密码 password: # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms
配置类
import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { @Bean @SuppressWarnings(value = { "unchecked", "rawtypes" }) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); // 使用StringRedisSerializer来序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(serializer); // Hash的key也采用StringRedisSerializer的序列化方式 template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template; } @Bean public DefaultRedisScript<Long> limitScript() { DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); redisScript.setScriptText(limitScriptText()); redisScript.setResultType(Long.class); return redisScript; } /** * 限流脚本 */ private String limitScriptText() { return "local key = KEYS[1]\n" + "local count = tonumber(ARGV[1])\n" + "local time = tonumber(ARGV[2])\n" + "local current = redis.call('get', key);\n" + "if current and tonumber(current) > count then\n" + " return tonumber(current);\n" + "end\n" + "current = redis.call('incr', key)\n" + "if tonumber(current) == 1 then\n" + " redis.call('expire', key, time)\n" + "end\n" + "return tonumber(current);"; } }
FastJson2JsonRedisSerializer
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONReader; import com.alibaba.fastjson2.JSONWriter; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; /** * Redis使用FastJson序列化 * * @author ruoyi */ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> { public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; private Class<T> clazz; public FastJson2JsonRedisSerializer(Class<T> clazz) { super(); this.clazz = clazz; } @Override public byte[] serialize(T t) throws SerializationException { if (t == null) { return new byte[0]; } return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET); } @Override public T deserialize(byte[] bytes) throws SerializationException { if (bytes == null || bytes.length <= 0) { return null; } String str = new String(bytes, DEFAULT_CHARSET); return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType); } }
RedisCache工具类
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.BoundSetOperations; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; import java.util.*; import java.util.concurrent.TimeUnit; /** * spring redis 工具类 **/ @SuppressWarnings(value = { "unchecked", "rawtypes" }) @Component public class RedisCache { @Autowired public RedisTemplate redisTemplate; public Long increment(final String key) { return redisTemplate.opsForValue().increment(key); } /** * 缓存基本的对象,Integer、String、实体类等 * * @param key 缓存的键值 * @param value 缓存的值 */ public <T> void setCacheObject(final String key, final T value) { redisTemplate.opsForValue().set(key, value); } /** * 缓存基本的对象,Integer、String、实体类等 * * @param key 缓存的键值 * @param value 缓存的值 * @param timeout 时间 * @param timeUnit 时间颗粒度 */ public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) { redisTemplate.opsForValue().set(key, value, timeout, timeUnit); } /** * 设置有效时间 * * @param key Redis键 * @param timeout 超时时间 * @return true=设置成功;false=设置失败 */ public boolean expire(final String key, final long timeout) { return expire(key, timeout, TimeUnit.SECONDS); } /** * 设置有效时间 * * @param key Redis键 * @param timeout 超时时间 * @param unit 时间单位 * @return true=设置成功;false=设置失败 */ public boolean expire(final String key, final long timeout, final TimeUnit unit) { return redisTemplate.expire(key, timeout, unit); } /** * 获取有效时间 * * @param key Redis键 * @return 有效时间 */ public long getExpire(final String key) { return redisTemplate.getExpire(key); } /** * 判断 key是否存在 * * @param key 键 * @return true 存在 false不存在 */ public Boolean hasKey(String key) { return redisTemplate.hasKey(key); } /** * 获得缓存的基本对象。 * * @param key 缓存键值 * @return 缓存键值对应的数据 */ public <T> T getCacheObject(final String key) { ValueOperations<String, T> operation = redisTemplate.opsForValue(); return operation.get(key); } /** * 删除单个对象 * * @param key */ public boolean deleteObject(final String key) { return redisTemplate.delete(key); } /** * 删除集合对象 * * @param collection 多个对象 * @return */ public boolean deleteObject(final Collection collection) { return redisTemplate.delete(collection) > 0; } /** * 缓存List数据 * * @param key 缓存的键值 * @param dataList 待缓存的List数据 * @return 缓存的对象 */ public <T> long setCacheList(final String key, final List<T> dataList) { Long count = redisTemplate.opsForList().rightPushAll(key, dataList); return count == null ? 0 : count; } /** * 获得缓存的list对象 * * @param key 缓存的键值 * @return 缓存键值对应的数据 */ public <T> List<T> getCacheList(final String key) { return redisTemplate.opsForList().range(key, 0, -1); } /** * 缓存Set * * @param key 缓存键值 * @param dataSet 缓存的数据 * @return 缓存数据的对象 */ public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) { BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key); Iterator<T> it = dataSet.iterator(); while (it.hasNext()) { setOperation.add(it.next()); } return setOperation; } /** * 获得缓存的set * * @param key * @return */ public <T> Set<T> getCacheSet(final String key) { return redisTemplate.opsForSet().members(key); } /** * 缓存Map * * @param key * @param dataMap */ public <T> void setCacheMap(final String key, final Map<String, T> dataMap) { if (dataMap != null) { redisTemplate.opsForHash().putAll(key, dataMap); } } /** * 获得缓存的Map * * @param key * @return */ public <T> Map<String, T> getCacheMap(final String key) { return redisTemplate.opsForHash().entries(key); } /** * 往Hash中存入数据 * * @param key Redis键 * @param hKey Hash键 * @param value 值 */ public <T> void setCacheMapValue(final String key, final String hKey, final T value) { redisTemplate.opsForHash().put(key, hKey, value); } /** * 获取Hash中的数据 * * @param key Redis键 * @param hKey Hash键 * @return Hash中的对象 */ public <T> T getCacheMapValue(final String key, final String hKey) { HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash(); return opsForHash.get(key, hKey); } /** * 获取多个Hash中的数据 * * @param key Redis键 * @param hKeys Hash键集合 * @return Hash对象集合 */ public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) { return redisTemplate.opsForHash().multiGet(key, hKeys); } /** * 删除Hash中的某条数据 * * @param key Redis键 * @param hKey Hash键 * @return 是否成功 */ public boolean deleteCacheMapValue(final String key, final String hKey) { return redisTemplate.opsForHash().delete(key, hKey) > 0; } /** * 获得缓存的基本对象列表 * * @param pattern 字符串前缀 * @return 对象列表 */ public Collection<String> keys(final String pattern) { return redisTemplate.keys(pattern); } }
使用工具类
@Api(tags = "上传数据") @RestController @Validated @RequestMapping("/data") public class DataController { @Resource private RedisCache redisCache; @ApiOperation(value = "缺陷数据上传",tags = "缺陷数据上传") @PostMapping("/defect") public AjaxResult defect(@RequestBody Defect defect ) { // 记录不同type类型的数量 if("漏插".equals(defect.getType())){ Integer lochaNum = redisCache.getCacheObject("lochaNum");//漏插数量 if(lochaNum == null){ redisCache.setCacheObject("lochaNum",1); }else { redisCache.deleteObject("lochaNum"); redisCache.setCacheObject("lochaNum",lochaNum+1); } } if("虚插".equals(defect.getType())){ Integer xuchaNum = redisCache.getCacheObject("xuchaNum");//虚插数量 if(xuchaNum == null){ redisCache.setCacheObject("xuchaNum",1); }else { redisCache.deleteObject("xuchaNum"); redisCache.setCacheObject("xuchaNum",xuchaNum+1); } } // 记录最近10条数据 List<Defect> defects = redisCache.getCacheList("defects"); if(CollectionUtils.isEmpty(defects)){ defects = new ArrayList<>(); } defects.add(defect); redisCache.deleteObject("defects"); if(defects.size()>10){ redisCache.setCacheList("defects",defects.subList(defects.size()-10,defects.size())); }else { redisCache.setCacheList("defects",defects); } return AjaxResult.success(); } @ApiOperation(value = "入侵数据上传",tags = "入侵数据上传") @PostMapping("/intrusion") public AjaxResult intrusion(@RequestBody Intrusion intrusion ) { List<Intrusion> intrusions = redisCache.getCacheList("intrusions"); if(CollectionUtils.isEmpty(intrusions)){ intrusions = new ArrayList<>(); } intrusions.add(intrusion); redisCache.deleteObject("intrusions"); if(intrusions.size()>10){ redisCache.setCacheList("intrusions",intrusions.subList(intrusions.size()-10,intrusions.size())); }else { redisCache.setCacheList("intrusions",intrusions); } return AjaxResult.success(); } @ApiOperation(value = "获取缺陷数据",tags = "获取缺陷数据") @PostMapping("/getDefect") public AjaxResult getDefect() { List<Defect> defects = redisCache.getCacheList("defects"); return AjaxResult.success(defects); } @ApiOperation(value = "获取入侵数据",tags = "获取入侵数据") @PostMapping("/getIntrusion") public AjaxResult getIntrusion() { List<Intrusion> intrusions = redisCache.getCacheList("intrusions"); return AjaxResult.success(intrusions); } @ApiOperation(value = "获取缺陷占比",tags = "获取缺陷占比") @PostMapping("/getDefectPer") public AjaxResult getDefectPer() { Integer lochaNum = redisCache.getCacheObject("lochaNum");//漏插数量 Integer xuchaNum = redisCache.getCacheObject("xuchaNum");//虚插数量 Integer total = lochaNum+xuchaNum; String lochaPer = percent(lochaNum, total); String xuchaPer = percent(xuchaNum, total); HashMap<String, Object> resultMap = new HashMap<>(); resultMap.put("lochaPer",lochaPer); resultMap.put("xuchaPer",xuchaPer); return AjaxResult.success(resultMap); } /** * 占比计算保留小数的位数方法 * 转成百分数 * 当前数除以总数 * @param num1 ,num2 num1/num2 * @return rate 保留2位小数的 */ public String percent(int num1,int num2){ String rate="0.00%"; //定义格式化起始位数 String format="0.00"; if(num2 != 0 && num1 != 0){ DecimalFormat dec = new DecimalFormat(format); rate = dec.format((double) num1 / num2*100)+"%"; while(true){ if(rate.equals(format+"%")){ format=format+"0"; DecimalFormat dec1 = new DecimalFormat(format); rate = dec1.format((double) num1 / num2*100)+"%"; }else { break; } } }else if(num1 != 0 && num2 == 0){ rate = "100%"; } return rate; } }