mirror of https://github.com/elunez/eladmin
218 lines
7.7 KiB
Java
218 lines
7.7 KiB
Java
/*
|
||
* Copyright 2019-2020 Zheng Jie
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
package me.zhengjie.config;
|
||
|
||
import cn.hutool.core.lang.Assert;
|
||
import com.alibaba.fastjson.JSON;
|
||
import com.alibaba.fastjson.parser.ParserConfig;
|
||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.apache.commons.codec.digest.DigestUtils;
|
||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||
import org.springframework.cache.Cache;
|
||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||
import org.springframework.cache.annotation.EnableCaching;
|
||
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 org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||
import org.springframework.data.redis.core.RedisOperations;
|
||
import org.springframework.data.redis.core.RedisTemplate;
|
||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||
import reactor.util.annotation.Nullable;
|
||
import java.nio.charset.Charset;
|
||
import java.nio.charset.StandardCharsets;
|
||
import java.time.Duration;
|
||
import java.util.HashMap;
|
||
import java.util.Map;
|
||
|
||
|
||
/**
|
||
* @author Zheng Jie
|
||
* @date 2018-11-24
|
||
*/
|
||
@Slf4j
|
||
@Configuration
|
||
@EnableCaching
|
||
@ConditionalOnClass(RedisOperations.class)
|
||
@EnableConfigurationProperties(RedisProperties.class)
|
||
public class RedisConfig extends CachingConfigurerSupport {
|
||
|
||
/**
|
||
* 设置 redis 数据默认过期时间,默认2小时
|
||
* 设置@cacheable 序列化方式
|
||
*/
|
||
@Bean
|
||
public RedisCacheConfiguration redisCacheConfiguration(){
|
||
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
|
||
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
|
||
configuration = configuration.serializeValuesWith(RedisSerializationContext.
|
||
SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofHours(2));
|
||
return configuration;
|
||
}
|
||
|
||
@SuppressWarnings("all")
|
||
@Bean(name = "redisTemplate")
|
||
@ConditionalOnMissingBean(name = "redisTemplate")
|
||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||
//序列化
|
||
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
|
||
// value值的序列化采用fastJsonRedisSerializer
|
||
template.setValueSerializer(fastJsonRedisSerializer);
|
||
template.setHashValueSerializer(fastJsonRedisSerializer);
|
||
// 全局开启AutoType,这里方便开发,使用全局的方式
|
||
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
|
||
// 建议使用这种方式,小范围指定白名单
|
||
// ParserConfig.getGlobalInstance().addAccept("me.zhengjie.domain");
|
||
// key的序列化采用StringRedisSerializer
|
||
template.setKeySerializer(new StringRedisSerializer());
|
||
template.setHashKeySerializer(new StringRedisSerializer());
|
||
template.setConnectionFactory(redisConnectionFactory);
|
||
return template;
|
||
}
|
||
|
||
/**
|
||
* 自定义缓存key生成策略,默认将使用该策略
|
||
*/
|
||
@Bean
|
||
@Override
|
||
public KeyGenerator keyGenerator() {
|
||
return (target, method, params) -> {
|
||
Map<String,Object> container = new HashMap<>();
|
||
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);
|
||
}
|
||
};
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 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 @Nullable byte[] serialize(Object object) {
|
||
String string = JSON.toJSONString(object);
|
||
|
||
if (org.apache.commons.lang3.StringUtils.isBlank(string)) {
|
||
return null;
|
||
}
|
||
string = string.replace("\"", "");
|
||
return string.getBytes(charset);
|
||
}
|
||
}
|