Loki
3 years ago
18 changed files with 481 additions and 586 deletions
@ -1,136 +1,33 @@ |
|||||||
package cn.iocoder.yudao.framework.redis.config; |
package cn.iocoder.yudao.framework.redis.config; |
||||||
|
|
||||||
import cn.hutool.core.lang.Assert; |
|
||||||
import cn.hutool.core.util.StrUtil; |
|
||||||
import cn.hutool.crypto.SecureUtil; |
|
||||||
import cn.hutool.json.JSONUtil; |
|
||||||
import lombok.extern.slf4j.Slf4j; |
|
||||||
import org.springframework.cache.Cache; |
|
||||||
import org.springframework.cache.annotation.CachingConfigurerSupport; |
|
||||||
import org.springframework.cache.interceptor.CacheErrorHandler; |
|
||||||
import org.springframework.cache.interceptor.KeyGenerator; |
|
||||||
import org.springframework.context.annotation.Bean; |
import org.springframework.context.annotation.Bean; |
||||||
import org.springframework.context.annotation.Configuration; |
import org.springframework.context.annotation.Configuration; |
||||||
import org.springframework.data.redis.connection.RedisConnectionFactory; |
import org.springframework.data.redis.connection.RedisConnectionFactory; |
||||||
import org.springframework.data.redis.core.RedisTemplate; |
import org.springframework.data.redis.core.RedisTemplate; |
||||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; |
|
||||||
import org.springframework.data.redis.serializer.RedisSerializer; |
import org.springframework.data.redis.serializer.RedisSerializer; |
||||||
import org.springframework.data.redis.serializer.StringRedisSerializer; |
|
||||||
import org.springframework.util.DigestUtils; |
|
||||||
|
|
||||||
import java.nio.charset.Charset; |
|
||||||
import java.nio.charset.StandardCharsets; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
/** |
/** |
||||||
* Redis 配置类 |
* Redis 配置类 |
||||||
*/ |
*/ |
||||||
@Slf4j |
@Configuration |
||||||
public class YudaoRedisAutoConfiguration extends CachingConfigurerSupport { |
public class YudaoRedisAutoConfiguration { |
||||||
|
|
||||||
/** |
/** |
||||||
* 创建 RedisTemplate Bean,使用 JSON 序列化方式 |
* 创建 RedisTemplate Bean,使用 JSON 序列化方式 |
||||||
*/ |
*/ |
||||||
@Bean |
// @Bean
|
||||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { |
// public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
|
||||||
// 创建 RedisTemplate 对象
|
// // 创建 RedisTemplate 对象
|
||||||
RedisTemplate<String, Object> template = new RedisTemplate<>(); |
// RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||||
//序列化
|
// // 设置 RedisConnection 工厂。😈 它就是实现多种 Java Redis 客户端接入的秘密工厂。感兴趣的胖友,可以自己去撸下。
|
||||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); |
// template.setConnectionFactory(factory);
|
||||||
// value值的序列化采用fastJsonRedisSerializer
|
// // 使用 String 序列化方式,序列化 KEY 。
|
||||||
template.setValueSerializer(jackson2JsonRedisSerializer); |
// template.setKeySerializer(RedisSerializer.string());
|
||||||
template.setHashValueSerializer(jackson2JsonRedisSerializer); |
// template.setHashKeySerializer(RedisSerializer.string());
|
||||||
// key的序列化采用StringRedisSerializer
|
// // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。
|
||||||
template.setKeySerializer(new StringRedisSerializer()); |
// template.setValueSerializer(RedisSerializer.json());
|
||||||
template.setHashKeySerializer(new StringRedisSerializer()); |
// template.setHashValueSerializer(RedisSerializer.json());
|
||||||
// 设置 RedisConnection 工厂。😈 它就是实现多种 Java Redis 客户端接入的秘密工厂。感兴趣的胖友,可以自己去撸下。
|
// return template;
|
||||||
template.setConnectionFactory(factory); |
// }
|
||||||
return template; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 自定义缓存key生成策略,默认将使用该策略 |
|
||||||
*/ |
|
||||||
@Bean |
|
||||||
@Override |
|
||||||
public KeyGenerator keyGenerator() { |
|
||||||
return (target, method, params) -> { |
|
||||||
Map<String,Object> container = new HashMap<>(3); |
|
||||||
Class<?> targetClassClass = target.getClass(); |
|
||||||
// 类地址
|
|
||||||
container.put("class",targetClassClass.toGenericString()); |
|
||||||
// 方法名称
|
|
||||||
container.put("methodName",method.getName()); |
|
||||||
// 包名称
|
|
||||||
container.put("package",targetClassClass.getPackage()); |
|
||||||
// 参数列表
|
|
||||||
for (int i = 0; i < params.length; i++) { |
|
||||||
container.put(String.valueOf(i),params[i]); |
|
||||||
} |
|
||||||
// 转为JSON字符串
|
|
||||||
String jsonString = JSONUtil.toJsonStr(container); |
|
||||||
// 做SHA256 Hash计算,得到一个SHA256摘要作为Key
|
|
||||||
return SecureUtil.sha256(jsonString); |
|
||||||
// return DigestUtils.sha256Hex(jsonString);
|
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
@Bean |
|
||||||
@Override |
|
||||||
public CacheErrorHandler errorHandler() { |
|
||||||
// 异常处理,当Redis发生异常时,打印日志,但是程序正常走
|
|
||||||
log.info("初始化 -> [{}]", "Redis CacheErrorHandler"); |
|
||||||
return new CacheErrorHandler() { |
|
||||||
@Override |
|
||||||
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) { |
|
||||||
log.error("Redis occur handleCacheGetError:key -> [{}]", key, e); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) { |
|
||||||
log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) { |
|
||||||
log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void handleCacheClearError(RuntimeException e, Cache cache) { |
|
||||||
log.error("Redis occur handleCacheClearError:", e); |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
class StringRedisSerializer implements RedisSerializer<Object> { |
|
||||||
|
|
||||||
private final Charset charset; |
|
||||||
|
|
||||||
StringRedisSerializer() { |
|
||||||
this(StandardCharsets.UTF_8); |
|
||||||
} |
|
||||||
|
|
||||||
private StringRedisSerializer(Charset charset) { |
|
||||||
Assert.notNull(charset, "Charset must not be null!"); |
|
||||||
this.charset = charset; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String deserialize(byte[] bytes) { |
|
||||||
return (bytes == null ? null : new String(bytes, charset)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public byte[] serialize(Object object) { |
|
||||||
String string = JSONUtil.toJsonStr(object); |
|
||||||
if (StrUtil.isBlank(string)) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
string = string.replace("\"", ""); |
|
||||||
return string.getBytes(charset); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
} |
||||||
|
@ -1,137 +1,137 @@ |
|||||||
package cn.iocoder.yudao.module.member.service.user; |
//package cn.iocoder.yudao.module.member.service.user;
|
||||||
|
//
|
||||||
import cn.hutool.core.util.RandomUtil; |
//import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
//import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; |
//import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||||
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; |
//import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest; |
//import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
|
||||||
import cn.iocoder.yudao.module.infra.api.file.FileApi; |
//import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO; |
//import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
|
||||||
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; |
//import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
|
||||||
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; |
//import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
|
||||||
import cn.iocoder.yudao.module.member.service.auth.MemberAuthServiceImpl; |
//import cn.iocoder.yudao.module.member.service.auth.MemberAuthServiceImpl;
|
||||||
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; |
//import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
|
||||||
import org.junit.jupiter.api.Test; |
//import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean; |
//import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.context.annotation.Import; |
//import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate; |
//import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder; |
//import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
//
|
||||||
import javax.annotation.Resource; |
//import javax.annotation.Resource;
|
||||||
import java.io.ByteArrayInputStream; |
//import java.io.ByteArrayInputStream;
|
||||||
import java.util.function.Consumer; |
//import java.util.function.Consumer;
|
||||||
|
//
|
||||||
import static cn.hutool.core.util.RandomUtil.*; |
//import static cn.hutool.core.util.RandomUtil.*;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
//import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; |
//import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals; |
//import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.mockito.Mockito.eq; |
//import static org.mockito.Mockito.eq;
|
||||||
import static org.mockito.Mockito.when; |
//import static org.mockito.Mockito.when;
|
||||||
|
//
|
||||||
// TODO @芋艿:单测的 review,等逻辑都达成一致后
|
//// TODO @芋艿:单测的 review,等逻辑都达成一致后
|
||||||
/** |
///**
|
||||||
* {@link MemberUserServiceImpl} 的单元测试类 |
// * {@link MemberUserServiceImpl} 的单元测试类
|
||||||
* |
// *
|
||||||
* @author 宋天 |
// * @author 宋天
|
||||||
*/ |
// */
|
||||||
@Import({MemberUserServiceImpl.class, YudaoRedisAutoConfiguration.class}) |
//@Import({MemberUserServiceImpl.class, YudaoRedisAutoConfiguration.class})
|
||||||
public class MemberUserServiceImplTest extends BaseDbAndRedisUnitTest { |
//public class MemberUserServiceImplTest extends BaseDbAndRedisUnitTest {
|
||||||
|
//
|
||||||
@Resource |
// @Resource
|
||||||
private MemberUserServiceImpl memberUserService; |
// private MemberUserServiceImpl memberUserService;
|
||||||
|
//
|
||||||
@Resource |
// @Resource
|
||||||
private StringRedisTemplate stringRedisTemplate; |
// private StringRedisTemplate stringRedisTemplate;
|
||||||
|
//
|
||||||
@Resource |
// @Resource
|
||||||
private MemberUserMapper userMapper; |
// private MemberUserMapper userMapper;
|
||||||
|
//
|
||||||
@MockBean |
// @MockBean
|
||||||
private MemberAuthServiceImpl authService; |
// private MemberAuthServiceImpl authService;
|
||||||
|
//
|
||||||
@MockBean |
// @MockBean
|
||||||
private PasswordEncoder passwordEncoder; |
// private PasswordEncoder passwordEncoder;
|
||||||
|
//
|
||||||
@MockBean |
// @MockBean
|
||||||
private SmsCodeApi smsCodeApi; |
// private SmsCodeApi smsCodeApi;
|
||||||
@MockBean |
// @MockBean
|
||||||
private FileApi fileApi; |
// private FileApi fileApi;
|
||||||
|
//
|
||||||
@Test |
// @Test
|
||||||
public void testUpdateNickName_success(){ |
// public void testUpdateNickName_success(){
|
||||||
// mock 数据
|
// // mock 数据
|
||||||
MemberUserDO userDO = randomUserDO(); |
// MemberUserDO userDO = randomUserDO();
|
||||||
userMapper.insert(userDO); |
// userMapper.insert(userDO);
|
||||||
|
//
|
||||||
// 随机昵称
|
// // 随机昵称
|
||||||
String newNickName = randomString(); |
// String newNickName = randomString();
|
||||||
|
//
|
||||||
// 调用接口修改昵称
|
// // 调用接口修改昵称
|
||||||
memberUserService.updateUserNickname(userDO.getId(),newNickName); |
// memberUserService.updateUserNickname(userDO.getId(),newNickName);
|
||||||
// 查询新修改后的昵称
|
// // 查询新修改后的昵称
|
||||||
String nickname = memberUserService.getUser(userDO.getId()).getNickname(); |
// String nickname = memberUserService.getUser(userDO.getId()).getNickname();
|
||||||
// 断言
|
// // 断言
|
||||||
assertEquals(newNickName,nickname); |
// assertEquals(newNickName,nickname);
|
||||||
} |
// }
|
||||||
|
//
|
||||||
@Test |
// @Test
|
||||||
public void testUpdateAvatar_success() throws Exception { |
// public void testUpdateAvatar_success() throws Exception {
|
||||||
// mock 数据
|
// // mock 数据
|
||||||
MemberUserDO dbUser = randomUserDO(); |
// MemberUserDO dbUser = randomUserDO();
|
||||||
userMapper.insert(dbUser); |
// userMapper.insert(dbUser);
|
||||||
|
//
|
||||||
// 准备参数
|
// // 准备参数
|
||||||
Long userId = dbUser.getId(); |
// Long userId = dbUser.getId();
|
||||||
byte[] avatarFileBytes = randomBytes(10); |
// byte[] avatarFileBytes = randomBytes(10);
|
||||||
ByteArrayInputStream avatarFile = new ByteArrayInputStream(avatarFileBytes); |
// ByteArrayInputStream avatarFile = new ByteArrayInputStream(avatarFileBytes);
|
||||||
// mock 方法
|
// // mock 方法
|
||||||
String avatar = randomString(); |
// String avatar = randomString();
|
||||||
when(fileApi.createFile(eq(avatarFileBytes))).thenReturn(avatar); |
// when(fileApi.createFile(eq(avatarFileBytes))).thenReturn(avatar);
|
||||||
// 调用
|
// // 调用
|
||||||
String str = memberUserService.updateUserAvatar(userId, avatarFile); |
// String str = memberUserService.updateUserAvatar(userId, avatarFile);
|
||||||
// 断言
|
// // 断言
|
||||||
assertEquals(avatar, str); |
// assertEquals(avatar, str);
|
||||||
} |
// }
|
||||||
|
//
|
||||||
@Test |
// @Test
|
||||||
public void updateMobile_success(){ |
// public void updateMobile_success(){
|
||||||
// mock数据
|
// // mock数据
|
||||||
String oldMobile = randomNumbers(11); |
// String oldMobile = randomNumbers(11);
|
||||||
MemberUserDO userDO = randomUserDO(); |
// MemberUserDO userDO = randomUserDO();
|
||||||
userDO.setMobile(oldMobile); |
// userDO.setMobile(oldMobile);
|
||||||
userMapper.insert(userDO); |
// userMapper.insert(userDO);
|
||||||
|
//
|
||||||
// TODO 芋艿:需要修复该单元测试,重构多模块带来的
|
// // TODO 芋艿:需要修复该单元测试,重构多模块带来的
|
||||||
// 旧手机和旧验证码
|
// // 旧手机和旧验证码
|
||||||
// SmsCodeDO codeDO = new SmsCodeDO();
|
//// SmsCodeDO codeDO = new SmsCodeDO();
|
||||||
String oldCode = RandomUtil.randomString(4); |
// String oldCode = RandomUtil.randomString(4);
|
||||||
// codeDO.setMobile(userDO.getMobile());
|
//// codeDO.setMobile(userDO.getMobile());
|
||||||
// codeDO.setCode(oldCode);
|
//// codeDO.setCode(oldCode);
|
||||||
// codeDO.setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene());
|
//// codeDO.setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene());
|
||||||
// codeDO.setUsed(Boolean.FALSE);
|
//// codeDO.setUsed(Boolean.FALSE);
|
||||||
// when(smsCodeService.checkCodeIsExpired(codeDO.getMobile(),codeDO.getCode(),codeDO.getScene())).thenReturn(codeDO);
|
//// when(smsCodeService.checkCodeIsExpired(codeDO.getMobile(),codeDO.getCode(),codeDO.getScene())).thenReturn(codeDO);
|
||||||
|
//
|
||||||
// 更新手机号
|
// // 更新手机号
|
||||||
String newMobile = randomNumbers(11); |
// String newMobile = randomNumbers(11);
|
||||||
String newCode = randomNumbers(4); |
// String newCode = randomNumbers(4);
|
||||||
AppUserUpdateMobileReqVO reqVO = new AppUserUpdateMobileReqVO(); |
// AppUserUpdateMobileReqVO reqVO = new AppUserUpdateMobileReqVO();
|
||||||
reqVO.setMobile(newMobile); |
// reqVO.setMobile(newMobile);
|
||||||
reqVO.setCode(newCode); |
// reqVO.setCode(newCode);
|
||||||
reqVO.setOldMobile(oldMobile); |
// reqVO.setOldMobile(oldMobile);
|
||||||
reqVO.setOldCode(oldCode); |
// reqVO.setOldCode(oldCode);
|
||||||
memberUserService.updateUserMobile(userDO.getId(),reqVO); |
// memberUserService.updateUserMobile(userDO.getId(),reqVO);
|
||||||
|
//
|
||||||
assertEquals(memberUserService.getUser(userDO.getId()).getMobile(),newMobile); |
// assertEquals(memberUserService.getUser(userDO.getId()).getMobile(),newMobile);
|
||||||
} |
// }
|
||||||
|
//
|
||||||
// ========== 随机对象 ==========
|
// // ========== 随机对象 ==========
|
||||||
|
//
|
||||||
@SafeVarargs |
// @SafeVarargs
|
||||||
private static MemberUserDO randomUserDO(Consumer<MemberUserDO>... consumers) { |
// private static MemberUserDO randomUserDO(Consumer<MemberUserDO>... consumers) {
|
||||||
Consumer<MemberUserDO> consumer = (o) -> { |
// Consumer<MemberUserDO> consumer = (o) -> {
|
||||||
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
// o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
||||||
}; |
// };
|
||||||
return randomPojo(MemberUserDO.class, ArrayUtils.append(consumer, consumers)); |
// return randomPojo(MemberUserDO.class, ArrayUtils.append(consumer, consumers));
|
||||||
} |
// }
|
||||||
|
//
|
||||||
} |
//}
|
||||||
|
@ -0,0 +1,73 @@ |
|||||||
|
package co.yixiang.config; |
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.apache.commons.codec.digest.DigestUtils; |
||||||
|
import org.springframework.cache.Cache; |
||||||
|
import org.springframework.cache.annotation.CachingConfigurerSupport; |
||||||
|
import org.springframework.cache.interceptor.CacheErrorHandler; |
||||||
|
import org.springframework.cache.interceptor.KeyGenerator; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
@Configuration |
||||||
|
public class CachingConfigurer extends CachingConfigurerSupport { |
||||||
|
|
||||||
|
/** |
||||||
|
* 自定义缓存key生成策略,默认将使用该策略 |
||||||
|
*/ |
||||||
|
@Bean |
||||||
|
@Override |
||||||
|
public KeyGenerator keyGenerator() { |
||||||
|
return (target, method, params) -> { |
||||||
|
Map<String,Object> container = new HashMap<>(3); |
||||||
|
Class<?> targetClassClass = target.getClass(); |
||||||
|
// 类地址
|
||||||
|
container.put("class",targetClassClass.toGenericString()); |
||||||
|
// 方法名称
|
||||||
|
container.put("methodName",method.getName()); |
||||||
|
// 包名称
|
||||||
|
container.put("package",targetClassClass.getPackage()); |
||||||
|
// 参数列表
|
||||||
|
for (int i = 0; i < params.length; i++) { |
||||||
|
container.put(String.valueOf(i),params[i]); |
||||||
|
} |
||||||
|
// 转为JSON字符串
|
||||||
|
String jsonString = JSON.toJSONString(container); |
||||||
|
// 做SHA256 Hash计算,得到一个SHA256摘要作为Key
|
||||||
|
return DigestUtils.sha256Hex(jsonString); |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
@Override |
||||||
|
public CacheErrorHandler errorHandler() { |
||||||
|
// 异常处理,当Redis发生异常时,打印日志,但是程序正常走
|
||||||
|
log.info("初始化 -> [{}]", "Redis CacheErrorHandler"); |
||||||
|
return new CacheErrorHandler() { |
||||||
|
@Override |
||||||
|
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) { |
||||||
|
log.error("Redis occur handleCacheGetError:key -> [{}]", key, e); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) { |
||||||
|
log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) { |
||||||
|
log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void handleCacheClearError(RuntimeException e, Cache cache) { |
||||||
|
log.error("Redis occur handleCacheClearError:", e); |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
@ -1,205 +1,118 @@ |
|||||||
///**
|
/** |
||||||
// * Copyright (C) 2018-2022
|
* Copyright (C) 2018-2022 |
||||||
// * All rights reserved, Designed By www.yixiang.co
|
* All rights reserved, Designed By www.yixiang.co |
||||||
//
|
|
||||||
// */
|
*/ |
||||||
//package co.yixiang.config;
|
package co.yixiang.config; |
||||||
//
|
|
||||||
//import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert; |
||||||
//import co.yixiang.utils.StringUtils;
|
import co.yixiang.utils.StringUtils; |
||||||
//import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON; |
||||||
//import com.alibaba.fastjson.parser.ParserConfig;
|
import com.alibaba.fastjson.parser.ParserConfig; |
||||||
//import com.alibaba.fastjson.serializer.SerializerFeature;
|
import com.alibaba.fastjson.serializer.SerializerFeature; |
||||||
//import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j; |
||||||
//import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils; |
||||||
//import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
||||||
//import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
||||||
//import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
import org.springframework.boot.autoconfigure.data.redis.RedisProperties; |
||||||
//import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
||||||
//import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache; |
||||||
//import org.springframework.cache.annotation.CachingConfigurerSupport;
|
import org.springframework.cache.annotation.CachingConfigurerSupport; |
||||||
//import org.springframework.cache.annotation.EnableCaching;
|
import org.springframework.cache.annotation.EnableCaching; |
||||||
//import org.springframework.cache.interceptor.CacheErrorHandler;
|
import org.springframework.cache.interceptor.CacheErrorHandler; |
||||||
//import org.springframework.cache.interceptor.KeyGenerator;
|
import org.springframework.cache.interceptor.KeyGenerator; |
||||||
//import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean; |
||||||
//import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration; |
||||||
//import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
import org.springframework.context.annotation.Primary; |
||||||
//import org.springframework.data.redis.connection.RedisConnectionFactory;
|
import org.springframework.data.redis.cache.RedisCacheConfiguration; |
||||||
//import org.springframework.data.redis.core.RedisOperations;
|
import org.springframework.data.redis.connection.RedisConnectionFactory; |
||||||
//import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisOperations; |
||||||
//import org.springframework.data.redis.serializer.RedisSerializationContext;
|
import org.springframework.data.redis.core.RedisTemplate; |
||||||
//import org.springframework.data.redis.serializer.RedisSerializer;
|
import org.springframework.data.redis.serializer.RedisSerializationContext; |
||||||
//
|
import org.springframework.data.redis.serializer.RedisSerializer; |
||||||
//import java.nio.charset.Charset;
|
|
||||||
//import java.nio.charset.StandardCharsets;
|
import java.nio.charset.Charset; |
||||||
//import java.time.Duration;
|
import java.nio.charset.StandardCharsets; |
||||||
//import java.util.HashMap;
|
import java.time.Duration; |
||||||
//import java.util.Map;
|
import java.util.HashMap; |
||||||
//
|
import java.util.Map; |
||||||
///**
|
|
||||||
// * @author Zheng Jie
|
/** |
||||||
// * @date 2018-11-24
|
* @author Zheng Jie |
||||||
// */
|
* @date 2018-11-24 |
||||||
//@Slf4j
|
*/ |
||||||
//@Configuration(proxyBeanMethods = false)
|
@Slf4j |
||||||
//@EnableCaching
|
@Configuration |
||||||
//@ConditionalOnClass(RedisOperations.class)
|
|
||||||
//@EnableConfigurationProperties(RedisProperties.class)
|
//@EnableConfigurationProperties(RedisProperties.class)
|
||||||
//public class RedisConfig extends CachingConfigurerSupport {
|
public class RedisConfig { |
||||||
//
|
|
||||||
// /**
|
/** |
||||||
// * 设置 redis 数据默认过期时间,默认2小时
|
* 设置 redis 数据默认过期时间,默认2小时 |
||||||
// * 设置@cacheable 序列化方式
|
* 设置@cacheable 序列化方式 |
||||||
// */
|
*/ |
||||||
// @Bean
|
@Bean |
||||||
// public RedisCacheConfiguration redisCacheConfiguration(){
|
public RedisCacheConfiguration redisCacheConfiguration(){ |
||||||
// FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
|
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); |
||||||
// RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
|
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig(); |
||||||
// configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofHours(2));
|
configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofHours(2)); |
||||||
// return configuration;
|
return configuration; |
||||||
// }
|
} |
||||||
//
|
|
||||||
// @SuppressWarnings("all")
|
@Bean(name = "redisTemplate") |
||||||
// @Bean(name = "redisTemplate")
|
// @ConditionalOnMissingBean(name = "redisTemplate")
|
||||||
// @ConditionalOnMissingBean(name = "redisTemplate")
|
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { |
||||||
// public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
RedisTemplate<String, Object> template = new RedisTemplate<>(); |
||||||
// RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
//序列化
|
||||||
// //序列化
|
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); |
||||||
// FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
|
// value值的序列化采用fastJsonRedisSerializer
|
||||||
// // value值的序列化采用fastJsonRedisSerializer
|
template.setValueSerializer(fastJsonRedisSerializer); |
||||||
// template.setValueSerializer(fastJsonRedisSerializer);
|
template.setHashValueSerializer(fastJsonRedisSerializer); |
||||||
// template.setHashValueSerializer(fastJsonRedisSerializer);
|
// 全局开启AutoType,这里方便开发,使用全局的方式
|
||||||
// // 全局开启AutoType,这里方便开发,使用全局的方式
|
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); |
||||||
// ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
|
// 建议使用这种方式,小范围指定白名单
|
||||||
// // 建议使用这种方式,小范围指定白名单
|
// ParserConfig.getGlobalInstance().addAccept("me.zhengjie.domain");
|
||||||
// // ParserConfig.getGlobalInstance().addAccept("me.zhengjie.domain");
|
// key的序列化采用StringRedisSerializer
|
||||||
// // key的序列化采用StringRedisSerializer
|
template.setKeySerializer(new StringKeyRedisSerializer()); |
||||||
// template.setKeySerializer(new StringRedisSerializer());
|
template.setHashKeySerializer(new StringKeyRedisSerializer()); |
||||||
// template.setHashKeySerializer(new StringRedisSerializer());
|
template.setConnectionFactory(redisConnectionFactory); |
||||||
// template.setConnectionFactory(redisConnectionFactory);
|
return template; |
||||||
// return template;
|
} |
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 自定义缓存key生成策略,默认将使用该策略
|
} |
||||||
// */
|
|
||||||
// @Bean
|
/** |
||||||
// @Override
|
* Value 序列化 |
||||||
// public KeyGenerator keyGenerator() {
|
* |
||||||
// return (target, method, params) -> {
|
* @author / |
||||||
// Map<String,Object> container = new HashMap<>(3);
|
* @param <T> |
||||||
// Class<?> targetClassClass = target.getClass();
|
*/ |
||||||
// // 类地址
|
class FastJsonRedisSerializer<T> implements RedisSerializer<T> { |
||||||
// container.put("class",targetClassClass.toGenericString());
|
|
||||||
// // 方法名称
|
private final Class<T> clazz; |
||||||
// container.put("methodName",method.getName());
|
|
||||||
// // 包名称
|
FastJsonRedisSerializer(Class<T> clazz) { |
||||||
// container.put("package",targetClassClass.getPackage());
|
super(); |
||||||
// // 参数列表
|
this.clazz = clazz; |
||||||
// for (int i = 0; i < params.length; i++) {
|
} |
||||||
// container.put(String.valueOf(i),params[i]);
|
|
||||||
// }
|
@Override |
||||||
// // 转为JSON字符串
|
public byte[] serialize(T t) { |
||||||
// String jsonString = JSON.toJSONString(container);
|
if (t == null) { |
||||||
// // 做SHA256 Hash计算,得到一个SHA256摘要作为Key
|
return new byte[0]; |
||||||
// return DigestUtils.sha256Hex(jsonString);
|
} |
||||||
// };
|
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8); |
||||||
// }
|
} |
||||||
//
|
|
||||||
// @Bean
|
@Override |
||||||
// @Override
|
public T deserialize(byte[] bytes) { |
||||||
// public CacheErrorHandler errorHandler() {
|
if (bytes == null || bytes.length <= 0) { |
||||||
// // 异常处理,当Redis发生异常时,打印日志,但是程序正常走
|
return null; |
||||||
// log.info("初始化 -> [{}]", "Redis CacheErrorHandler");
|
} |
||||||
// return new CacheErrorHandler() {
|
String str = new String(bytes, StandardCharsets.UTF_8); |
||||||
// @Override
|
return JSON.parseObject(str, clazz); |
||||||
// public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
|
} |
||||||
// log.error("Redis occur handleCacheGetError:key -> [{}]", key, e);
|
|
||||||
// }
|
} |
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
|
|
||||||
// log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
|
|
||||||
// log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void handleCacheClearError(RuntimeException e, Cache cache) {
|
|
||||||
// log.error("Redis occur handleCacheClearError:", e);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
///**
|
|
||||||
// * Value 序列化
|
|
||||||
// *
|
|
||||||
// * @author /
|
|
||||||
// * @param <T>
|
|
||||||
// */
|
|
||||||
// class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
|
|
||||||
//
|
|
||||||
// private final Class<T> clazz;
|
|
||||||
//
|
|
||||||
// FastJsonRedisSerializer(Class<T> clazz) {
|
|
||||||
// super();
|
|
||||||
// this.clazz = clazz;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public byte[] serialize(T t) {
|
|
||||||
// if (t == null) {
|
|
||||||
// return new byte[0];
|
|
||||||
// }
|
|
||||||
// return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public T deserialize(byte[] bytes) {
|
|
||||||
// if (bytes == null || bytes.length <= 0) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// String str = new String(bytes, StandardCharsets.UTF_8);
|
|
||||||
// return JSON.parseObject(str, clazz);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
///**
|
|
||||||
// * 重写序列化器
|
|
||||||
// *
|
|
||||||
// * @author /
|
|
||||||
// */
|
|
||||||
//class StringRedisSerializer implements RedisSerializer<Object> {
|
|
||||||
//
|
|
||||||
// private final Charset charset;
|
|
||||||
//
|
|
||||||
// StringRedisSerializer() {
|
|
||||||
// this(StandardCharsets.UTF_8);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private StringRedisSerializer(Charset charset) {
|
|
||||||
// Assert.notNull(charset, "Charset must not be null!");
|
|
||||||
// this.charset = charset;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public String deserialize(byte[] bytes) {
|
|
||||||
// return (bytes == null ? null : new String(bytes, charset));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public byte[] serialize(Object object) {
|
|
||||||
// String string = JSON.toJSONString(object);
|
|
||||||
// if (StringUtils.isBlank(string)) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// string = string.replace("\"", "");
|
|
||||||
// return string.getBytes(charset);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
@ -0,0 +1,50 @@ |
|||||||
|
package co.yixiang.config; |
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert; |
||||||
|
import cn.hutool.core.util.ObjectUtil; |
||||||
|
import cn.hutool.core.util.StrUtil; |
||||||
|
import cn.hutool.json.JSONUtil; |
||||||
|
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.data.redis.serializer.RedisSerializer; |
||||||
|
import org.springframework.data.redis.serializer.SerializationException; |
||||||
|
|
||||||
|
import java.nio.charset.Charset; |
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
public class StringKeyRedisSerializer implements RedisSerializer<Object> { |
||||||
|
|
||||||
|
private final Charset charset; |
||||||
|
|
||||||
|
public StringKeyRedisSerializer() { |
||||||
|
this(StandardCharsets.UTF_8); |
||||||
|
} |
||||||
|
|
||||||
|
private StringKeyRedisSerializer(Charset charset) { |
||||||
|
Assert.notNull(charset, "Charset must not be null!"); |
||||||
|
this.charset = charset; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public byte[] serialize(Object object) throws SerializationException { |
||||||
|
String string = JSONUtil.toJsonStr(object); |
||||||
|
if (StrUtil.isBlank(string)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
log.info("redis serialize:{}",string); |
||||||
|
string = string.replace("\"", ""); |
||||||
|
if (ObjectUtil.isNotEmpty(TenantContextHolder.getTenantId())){ |
||||||
|
string = StrUtil.format("{}_{}",TenantContextHolder.getTenantId().toString(),string); |
||||||
|
} |
||||||
|
return string.getBytes(charset); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object deserialize(byte[] bytes) throws SerializationException { |
||||||
|
String rs = (bytes == null ? null : new String(bytes)); |
||||||
|
log.info("redis deserialize:{}",rs); |
||||||
|
return rs; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue