总结一下redis的使用。
我这里是有一个redisTemplate操作缓存数据, 和一个使用缓存管理器,对方法缓存的注解。两种方式缓存。
第一步引包:
<!--redis依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
第二步配置redis:
package com.xnpool.common.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.xnpool.common.service.RedisService;
import com.xnpool.common.service.impl.RedisServiceImpl;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.Duration;
/**
* Redis基础配置
* Created by heqiwen on 2020/6/19.
*/
public class BaseRedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisSerializer<Object> serializer = redisSerializer();
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public RedisSerializer<Object> redisSerializer() {
//创建JSON序列化器
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//必须设置,否则无法将JSON转化为对象,会转化成Map类型
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(objectMapper);
return serializer;
}
/**
* 有cachemanager(redis缓存管理器使用):配置+注解 可以对 方法进行缓存。带有注解@Cacheable、@CachePut、@CacheEvict 注解
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
//设置Redis缓存有效期为1天
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer())).entryTtl(Duration.ofDays(1));
return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
}
/**
* 对方法进行缓存时,注解的属性。 生成redis的key用的。
* @return
*/
@Bean
public KeyGenerator simpleKeyGenerator() {
return (o, method, objects) -> {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(method.getName());
stringBuilder.append(":");
for (Object obj : objects) {
stringBuilder.append(getAttributes(obj));
}
return stringBuilder.toString();
};
}
/**
* 对方法进行缓存时,注解的属性。 生成redis的key用的。
* @return
*/
@Bean
public KeyGenerator tokenKeyGenerator() {
return (oobj, method, objects) -> {
StringBuilder stringBuilder = new StringBuilder();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Long userId=(Long) request.getAttribute("currentUserId");
Long appId=(Long) request.getAttribute("currentApp");
stringBuilder.append("appid"+appId);
stringBuilder.append("userid"+userId+"_");
stringBuilder.append(method.getName());
stringBuilder.append(":");
for (Object obj : objects) {
stringBuilder.append(getAttributes(obj));
}
return stringBuilder.toString();
};
}
/**
* 用于清除当前用户自己的数据(redis的key)
* @return
*/
@Bean
public KeyGenerator evictoKeyGenerator() {
return (obj, method, objects) -> {
StringBuilder stringBuilder = new StringBuilder();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Long userId=(Long) request.getAttribute("currentUserId");
Long appId=(Long) request.getAttribute("currentApp");
stringBuilder.append("appid"+appId);
stringBuilder.append("userid"+userId+"_*");
return stringBuilder.toString();
};
}
@Bean
public RedisService redisService(){
return new RedisServiceImpl();
}
//获取对象的所有属性,如果是基础数据类型就直接返回tostring
private String getAttributes(Object obj){
Class<?> aClass = obj.getClass();
if(aClass.getName().startsWith("java.lang.")||aClass.getName().startsWith("java.util.")){
return obj.toString();
}else if(aClass.getName().startsWith("javax.servlet.http")){
return "";
}else {
try {
StringBuilder sb = new StringBuilder();
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field:declaredFields){
String fname=field.getName();
String fristLetter=fname.substring(0,1).toUpperCase();
String methodName="get"+fristLetter+fname.substring(1);
Method getMethod=aClass.getMethod(methodName,new Class[]{});
Object value=getMethod.invoke(obj,new Object[]{});
if(value==null){
continue;
}else {
sb.append(fname);
sb.append(String.valueOf(value));
}
}
Class<?> superclass = aClass.getSuperclass();
if(!superclass.getName().startsWith("java.lang.")){
Field[] fields = superclass.getDeclaredFields();
for (Field field:fields){
String fname=field.getName();
String fristLetter=fname.substring(0,1).toUpperCase();
String methodName="get"+fristLetter+fname.substring(1);
Method getMethod=aClass.getMethod(methodName,new Class[]{});
Object value=getMethod.invoke(obj,new Object[]{});
if(value==null){
continue;
}else {
sb.append(fname);
sb.append(String.valueOf(value));
}
}
}
return sb.toString();
}catch (Exception e){
return obj.toString();
}
}
}
}
这是一个springboot项目,redis属性会自动注入的。
spring:
redis:
host: localhost # Redis服务器地址
database: 0 # Redis数据库索引(默认为0)
port: 6379 # Redis服务器连接端口
password: # Redis服务器连接密码(默认为空)
timeout: 3000ms # 连接超时时间(毫秒)
第三步使用redisTemplate
package com.xnpool.common.service.impl;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.xnpool.common.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* redis操作实现类
* Created by heqiwen on 2020/3/3.
*/
public class RedisServiceImpl implements RedisService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public void set(String key, Object value, long time) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
}
@Override
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
@Override
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
@Override
public Boolean del(String key) {
return redisTemplate.delete(key);
}
@Override
public Boolean delPrex(String prex){
try{
Set<String> keys = redisTemplate.keys(prex);
if (CollectionUtils.isNotEmpty(keys)) {
redisTemplate.delete(keys);
}
}catch (Exception e){
return false;
}
return true;
}
@Override
public Long del(List<String> keys) {
return redisTemplate.delete(keys);
}
@Override
public Boolean expire(String key, long time) {
return redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
@Override
public Long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
@Override
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
@Override
public Long incr(String key, long delta) {
return redisTemplate.opsForValue().increment(key, delta);
}
@Override
public Long decr(String key, long delta) {
return redisTemplate.opsForValue().increment(key, -delta);
}
@Override
public Object hGet(String key, String hashKey) {
return redisTemplate.opsForHash().get(key, hashKey);
}
@Override
public Boolean hSet(String key, String hashKey, Object value, long time) {
redisTemplate.opsForHash().put(key, hashKey, value);
return expire(key, time);
}
@Override
public void hSet(String key, String hashKey, Object value) {
redisTemplate.opsForHash().put(key, hashKey, value);
}
@Override
public Map<Object, Object> hGetAll(String key) {
return redisTemplate.opsForHash().entries(key);
}
@Override
public Boolean hSetAll(String key, Map<String, Object> map, long time) {
redisTemplate.opsForHash().putAll(key, map);
return expire(key, time);
}
@Override
public void hSetAll(String key, Map<String, ?> map) {
redisTemplate.opsForHash().putAll(key, map);
}
@Override
public void hDel(String key, Object... hashKey) {
redisTemplate.opsForHash().delete(key, hashKey);
}
@Override
public Boolean hHasKey(String key, String hashKey) {
return redisTemplate.opsForHash().hasKey(key, hashKey);
}
@Override
public Long hIncr(String key, String hashKey, Long delta) {
return redisTemplate.opsForHash().increment(key, hashKey, delta);
}
@Override
public Long hDecr(String key, String hashKey, Long delta) {
return redisTemplate.opsForHash().increment(key, hashKey, -delta);
}
@Override
public Set<Object> sMembers(String key) {
return redisTemplate.opsForSet().members(key);
}
@Override
public Long sAdd(String key, Object... values) {
return redisTemplate.opsForSet().add(key, values);
}
@Override
public Long sAdd(String key, long time, Object... values) {
Long count = redisTemplate.opsForSet().add(key, values);
expire(key, time);
return count;
}
@Override
public Boolean sIsMember(String key, Object value) {
return redisTemplate.opsForSet().isMember(key, value);
}
@Override
public Long sSize(String key) {
return redisTemplate.opsForSet().size(key);
}
@Override
public Long sRemove(String key, Object... values) {
return redisTemplate.opsForSet().remove(key, values);
}
@Override
public List<Object> lRange(String key, long start, long end) {
return redisTemplate.opsForList().range(key, start, end);
}
@Override
public Long lSize(String key) {
return redisTemplate.opsForList().size(key);
}
@Override
public Object lIndex(String key, long index) {
return redisTemplate.opsForList().index(key, index);
}
@Override
public Long lPush(String key, Object value) {
return redisTemplate.opsForList().rightPush(key, value);
}
@Override
public Long lPush(String key, Object value, long time) {
Long index = redisTemplate.opsForList().rightPush(key, value);
expire(key, time);
return index;
}
@Override
public Long lPushAll(String key, Object... values) {
return redisTemplate.opsForList().rightPushAll(key, values);
}
@Override
public Long lPushAll(String key, Long time, Object... values) {
Long count = redisTemplate.opsForList().rightPushAll(key, values);
expire(key, time);
return count;
}
@Override
public Long lRemove(String key, long count, Object value) {
return redisTemplate.opsForList().remove(key, count, value);
}
/**
* 获得锁
*
* @param lock
* @return
*/
public boolean lock(String lock,Long LOCK_EXPIRE) {
return (boolean) redisTemplate.execute((RedisCallback) connection -> {
//获取时间毫秒值
long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;
//获取锁
Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());
if (acquire) {
return true;
} else {
byte[] bytes = connection.get(lock.getBytes());
//非空判断
if (Objects.nonNull(bytes) && bytes.length > 0) {
long expireTime = Long.parseLong(new String(bytes));
// 如果锁已经过期
if (expireTime < System.currentTimeMillis()) {
// 重新加锁,防止死锁
byte[] set = connection.getSet(lock.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
return Long.parseLong(new String(set)) < System.currentTimeMillis();
}
}
}
return false;
});
}
}
第四步使用缓存管理器cacheManage:
package com.xnpool.enterprise.modules.appmanage.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.xnpool.common.api.CommonResult;
import com.xnpool.enterprise.modules.appmanage.dto.SubUserQuery;
import com.xnpool.enterprise.modules.appmanage.model.TApplicationWhiteList;
import com.xnpool.enterprise.modules.appmanage.model.TSubuser;
import com.xnpool.enterprise.modules.appmanage.service.TSubuserService;
import com.xnpool.enterprise.security.annotation.TradeApiTokenCheck;
import com.xnpool.enterprise.security.util.CurrentUserUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* <p>
* 前端控制器
* </p>
*
* @author heqiwen
* @since 2021-01-14
*/
@Api(tags = "用户的子账户维护", description = "用户的子账户维护")
@Slf4j
@RestController
@RequestMapping("/subuser")
public class TSubuserController {
@Autowired
private TSubuserService subuserService;
@ApiOperation("增加子账户")
@RequestMapping(value = "/add", method = RequestMethod.POST)
@Caching(evict={@CacheEvict(value = "subuser_m",keyGenerator = "evictoKeyGenerator",allEntries = true),
@CacheEvict(value = "useraddress_m",keyGenerator = "evictoKeyGenerator",allEntries = true)})
public CommonResult<TSubuser> add(@RequestBody TSubuser subuser) {
CommonResult<TSubuser> result=subuserService.addSubuser(subuser);
return result;
}
@ApiOperation("修改子账户")
@RequestMapping(value = "/update", method = RequestMethod.POST)
@Caching(evict={@CacheEvict(value = "subuser_m",keyGenerator = "evictoKeyGenerator",allEntries = true),
@CacheEvict(value = "useraddress_m",keyGenerator = "evictoKeyGenerator",allEntries = true)})
public CommonResult<String> update(@RequestBody TSubuser subuser) {
subuser.setUpdateTime(new Date());
if(subuser.getParentId()==null || subuser.getParentId()==0){
Long currentUserId = CurrentUserUtil.getCurrentUserId();//取当前登录人
subuser.setParentId(currentUserId);
}
subuserService.updateById(subuser);
return CommonResult.success(String.valueOf(subuser.getId()));
}
@ApiOperation("根据ID删除子账户")
@RequestMapping(value = "/delete/{id}", method = RequestMethod.POST)
@Caching(evict={@CacheEvict(value = "subuser_m",keyGenerator = "evictoKeyGenerator",allEntries = true),
@CacheEvict(value = "useraddress_m",keyGenerator = "evictoKeyGenerator",allEntries = true)})
public CommonResult<String> delete(@PathVariable Long id) {
CommonResult<String> result=subuserService.deleteSubuser(id);
return result;
}
@ApiOperation("根据ID查看子账户")
@RequestMapping(value = "/detail/{id}", method = RequestMethod.POST)
public CommonResult<TSubuser> detail(@PathVariable Long id) {
TSubuser subuser=subuserService.getById(id);
return CommonResult.success(subuser);
}
@ApiOperation("查询子账户")
@RequestMapping(value = "/list", method = RequestMethod.POST)
@Cacheable(value = "subuser_m",keyGenerator = "tokenKeyGenerator",unless = "#result.data==null || #result.data.size()==0")
public CommonResult<List<TSubuser>> list(@RequestBody SubUserQuery subuser) {
Long currentUserId = CurrentUserUtil.getCurrentUserId();//取当前登录人
if(currentUserId==null){
return CommonResult.failed("token中用户数据为空");
}
subuser.setParentId(currentUserId);
log.info("查询子账号列表,userid:"+currentUserId);
List<TSubuser> list = subuserService.list(new QueryWrapper<TSubuser>().lambda().eq(TSubuser::getParentId, subuser.getParentId()).eq(TSubuser::getArtived,1).orderByDesc(TSubuser::getCreateTime));
return CommonResult.success(list);
}
}