添加依赖
<dependencies>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
配置application.yml
spring:
redis:
host: 127.0.0.1
port: 6379
password:
database: 0
配置时间格式
package cn.maicaii.edu.common.core.jackson;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.PackageVersion;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
/**
* java 8 时间默认序列化
* @author zengmingyong
*/
public class JavaTimeModule extends SimpleModule {
public JavaTimeModule() {
super(PackageVersion.VERSION);
this.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
this.addSerializer(LocalDate.class,
new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
this.addSerializer(LocalTime.class,
new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
this.addDeserializer(LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
this.addDeserializer(LocalDate.class,
new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
this.addDeserializer(LocalTime.class,
new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
}
}
package cn.maicaii.edu.common.core.config;
import cn.hutool.core.date.DatePattern;
import cn.maicaii.edu.common.core.jackson.JavaTimeModule;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.ZoneId;
import java.util.Locale;
import java.util.TimeZone;
/**
* 时间格式配置
*/
@Configuration(proxyBeanMethods = false) //fell模式
@ConditionalOnClass(ObjectMapper.class) //加载ObjectMapper 为 Bean
@AutoConfigureBefore(JacksonAutoConfiguration.class) //在JacksonConfiguration之前执行
public class JacksonConfiguration {
@Bean
@ConditionalOnMissingBean // 保证只加载一个customizer Bean 多个的时候 用@Primary标识哪个是默认的bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return builder -> {
builder.locale(Locale.CHINA);//
builder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
builder.simpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
builder.serializerByType(Long.class, ToStringSerializer.instance);
builder.modules(new JavaTimeModule());
};
}
}
配置redis
package cn.maicaii.edu.common.core.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
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.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/** Redis 配置类
*/
@EnableCaching
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class RedisTemplateConfiguration {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}
@Bean
public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
return redisTemplate.opsForValue();
}
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}
这个配置存在数据库的时候数据是看不懂的 ;因为用了Java自带的序列化
例如:redisTemplate.opsForValue().set("name", 100);
获取的数据如下
修改成我们看得懂的数据格式
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
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.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/** Redis 配置类
*/
@EnableCaching
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class RedisTemplateConfiguration {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(objectMapper);
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}
@Bean
public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
return redisTemplate.opsForValue();
}
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}
发现 objectMapper.enableDefaultTyping过时
解决办法
1. 查看enableDefaultTyping内部实现
@Deprecated
public ObjectMapper enableDefaultTyping(DefaultTyping dti) {
return enableDefaultTyping(dti, JsonTypeInfo.As.WRAPPER_ARRAY);
}
2.查看查看enableDefaultTyping内部实现
public ObjectMapper activateDefaultTyping(PolymorphicTypeValidator ptv,
DefaultTyping applicability, JsonTypeInfo.As includeAs)
{
// 18-Sep-2014, tatu: Let's add explicit check to ensure no one tries to
// use "As.EXTERNAL_PROPERTY", since that will not work (with 2.5+)
if (includeAs == JsonTypeInfo.As.EXTERNAL_PROPERTY) {
throw new IllegalArgumentException("Cannot use includeAs of "+includeAs);
}
TypeResolverBuilder<?> typer = _constructDefaultTypeResolverBuilder(applicability, ptv);
// we'll always use full class name, when using defaulting
typer = typer.init(JsonTypeInfo.Id.CLASS, null);
typer = typer.inclusion(includeAs);
return setDefaultTyping(typer);
}
这里我们可以直接调用activateDefaultTyping方法了,从而不用调用过期的enableDefaultTyping方法。再看activateDefaultTyping的参数
看看下面的实现方法
所以我们第一个参数选择 LaissezFaireSubTypeValidator.instance
第二个参数 ObjectMapper.DefaultTyping.NON_FINAL,
第三个参数 JsonTypeInfo.As.WRAPPER_ARRAY
🆗 现在修改的配置文件如下:
/** Redis 配置类
*/
@EnableCaching
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class RedisTemplateConfiguration {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance ,
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.WRAPPER_ARRAY);
serializer.setObjectMapper(objectMapper);
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}
@Bean
public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
return redisTemplate.opsForValue();
}
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}
测试
redisTemplate.opsForValue().set("name", 100);