shiro继承redis进行session的管理:
package com.maobc.common.core.redis;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
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.StringRedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableCaching
@Data
public class RedisConfiguration extends CachingConfigurerSupport {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 配置redis 连接
*/
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
// 1.创建 redisTemplate 模版
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 2.关联 redisConnectionFactory
template.setConnectionFactory(factory);
// 3.创建 自定义序列化类
MyRedisSerializer myRedisSerializer = new MyRedisSerializer();
// 7.设置 value 的转化格式和 key 的转化格式 默认使用的是JdkSerializationRedisSerializer
template.setValueSerializer(myRedisSerializer);
template.setHashValueSerializer(myRedisSerializer);
// 设置键(key)的序列化采用StringRedisSerializer。
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setDefaultSerializer(myRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public RedisTemplate<String, String> stringRedisTemplate(RedisConnectionFactory factory) {
return new StringRedisTemplate(factory);
}
}
默认使用JdkSerializationRedisSerializer
,这个序列化模式会将value序列化成字节码
,这样缓存shiro的session就没有什么问题,当是redis数据库的数据将是字节码,不方便观察。
如果改用GenericJackson2JsonRedisSerializer或者Jackson2JsonRedisSerializer,项目启动运行没有任何问题,但是在在访问过程中,突然性的报错:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "valid" (class org.apache.shiro.session.mgt.SimpleSession), not marked as ignorable (10 known properties: "attributeKeys", "timeout", "startTimestamp", "expired", "lastAccessTime", "host", "id", "stopTimestamp", "attributes", "attributesLazy"])
这是由于是反序列化报错的原因。无法反序列化接口的动态代理类,原因应该是动态代理类没有缺省构造函数。
处理方式:
- 解决session序列化问题方法也很简单,
setValueSerializer
不配置就可以了。
如果想要redis数据库的数据为json字符串,那么可以在其他用到缓存的地方使用StringRedisTemplate
,或者再定义一个template。
2. 自定义序列化和反序列化方法。
MyRedisSerializer 序列化成字节数组
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.io.*;
/**
* 重写序列化 序列化为字节码
* zhw
*/
public class MyRedisSerializer implements RedisSerializer {
@Override
public byte[] serialize(Object o) throws SerializationException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream objOut;
try {
objOut = new ObjectOutputStream(byteOut);
objOut.writeObject(o);
} catch (IOException e) {
e.printStackTrace();
}
return byteOut.toByteArray();
}
@Override
public Object deserialize(byte[] bytes) throws SerializationException {
if(bytes == null) return null;
ByteArrayInputStream byteIn = new ByteArrayInputStream(bytes);
ObjectInputStream objIn;
Object obj;
try {
objIn = new ObjectInputStream(byteIn);
obj =objIn.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
return obj;
}
}
FastJsonRedisSerializer:序列化成json字符串
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.Charset;
/**
* 重写序列化 序列化为json字符串
* zhw
*/
public class FastJsonRedisSerializer implements RedisSerializer {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class<T> clazz;
public FastJsonRedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(Object o) throws SerializationException {
if (o == null) {
return new byte[0];
}
return JSON.toJSONString(o, SerializerFeature.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);
}
}
多个项目彼此之间需使用同一个redis,一个项目往redis存入数据,另一个项目从redis中获取数据,如果使用的不是同一个redis的序列化方式,这样导致,另一个项目是无法从redis中获取到该key所对应的数据。