SpringBoot2+Jackson+RedisTempl

SpringBoot2+Jackson+RedisTemplate+RedisCache配置

版本

依赖 版本
spring boot 2.7.18

配置用途

  1. 拓展SpringBoot的Jackson配置
  2. 封装JacksonUtil方便使用,且使用Spring配置的Jackson单例
  3. Redis序列化使用基于Jackson基础上修改的配置,并用于Spring Cache

代码

需要依赖

1
2
3
4
5
6
7
8
xml复制代码<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>

Jackson配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
java复制代码/**
* Jackson ObjectMapper配置
* <p>使用此配置后别再定义其他 ObjectMapper 的 bean, 否则会导致该配置bean失效
*/
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
return builder -> builder
.serializationInclusion(JsonInclude.Include.NON_NULL)
.featuresToEnable(
JsonParser.Feature.ALLOW_SINGLE_QUOTES
)
.featuresToDisable(
SerializationFeature.FAIL_ON_EMPTY_BEANS,
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
)
.simpleDateFormat(BaseConsts.DATE_TIME_PT)
.serializerByType(Long.class, ToStringSerializer.instance)
.serializerByType(BigInteger.class, ToStringSerializer.instance)
.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(BaseConsts.DATE_TIME_FMT))
.serializerByType(LocalDate.class, new LocalDateSerializer(BaseConsts.DATE_FMT))
.serializerByType(LocalTime.class, new LocalTimeSerializer(BaseConsts.TIME_FMT))
.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(BaseConsts.DATE_TIME_FMT))
.deserializerByType(LocalDate.class, new LocalDateDeserializer(BaseConsts.DATE_FMT))
.deserializerByType(LocalTime.class, new LocalTimeDeserializer(BaseConsts.TIME_FMT))
;
}
}

public class BaseConsts {
public static final String DATE_TIME_PT = "yyyy-MM-dd HH:mm:ss";

public static final String DATE_PT = "yyyy-MM-dd";
public static final String TIME_PT = "HH:mm:ss";
public static final String DATE_COMPACT_PT = "yyyyMMdd";
public static final DateTimeFormatter DATE_TIME_FMT = DateTimeFormatter.ofPattern(DATE_TIME_PT);
public static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern(DATE_PT);
public static final DateTimeFormatter TIME_FMT = DateTimeFormatter.ofPattern(TIME_PT);
public static final DateTimeFormatter DATE_COMPACT_FMT = DateTimeFormatter.ofPattern(DATE_COMPACT_PT);

private BaseConsts() {
}
}

JacksonUtil封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
java复制代码import cn.hutool.extra.spring.SpringUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Optional;

/**
* 封装Jackson方便使用
*/
@Slf4j
public class JacksonUtil {

public static <T> Optional<T> executeWithExHandle(ThrowsExFunction<ObjectMapper, T> function, String exMsg) {
try {
return Optional.of(function.apply(getObjectMapper()));
} catch (Exception e) {
log.error(exMsg, e);
return Optional.empty();
}
}

public static String toJsonStr(Object object) {
return executeWithExHandle(om -> om.writeValueAsString(object), "toJsonStr Exception")
.orElse(null);
}

public static JsonNode parseJsonNode(String jsonStr) {
return executeWithExHandle(om -> om.readTree(jsonStr), "parseJsonNode Exception")
.orElse(null);
}

public static <T> T parseObject(String jsonStr, Class<T> clazz) {
return executeWithExHandle(om -> om.readValue(jsonStr, clazz), "parseObject Exception")
.orElse(null);
}

public static <T> List<T> parseList(String jsonStr, Class<T> clazz) {
return executeWithExHandle((ThrowsExFunction<ObjectMapper, List<T>>) om ->
om.readValue(jsonStr, om.getTypeFactory().constructCollectionType(List.class, clazz)), "parseList Exception")
.orElse(null);
}

public static <T> T parseByType(String jsonStr, TypeReference<T> typeReference) {
return executeWithExHandle(om -> om.readValue(jsonStr, typeReference), "parseByType Exception")
.orElse(null);
}

@FunctionalInterface
private interface ThrowsExFunction<T, R> {
R apply(T t) throws Exception;
}

public static ObjectMapper copyObjectMapper() {
return getObjectMapper().copy();
}

private volatile static ObjectMapper OBJECT_MAPPER;

private JacksonUtil() {
}

private static ObjectMapper getObjectMapper() {
if (OBJECT_MAPPER == null) {
synchronized (JacksonUtil.class) {
if (OBJECT_MAPPER == null) {
try {
OBJECT_MAPPER = SpringUtil.getBean(ObjectMapper.class);
} catch (Exception e) {
log.warn("Get Spring ObjectMapper Fail");
OBJECT_MAPPER = new ObjectMapper();
}
}
}
}
return OBJECT_MAPPER;
}
}

Redis配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
java复制代码@EnableCaching
@Configuration
@AutoConfigureAfter(JacksonAutoConfiguration.class) // Jackson配置后再配置Redis
public class RedisConfig {

@Bean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer(getRedisConfigObjectMapper());
redisTemplate.setValueSerializer(jsonSerializer);
redisTemplate.setHashValueSerializer(jsonSerializer);
StringRedisSerializer stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}

@Bean
public RedisCacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
RedisSerializationContext.SerializationPair<String> keyPair = RedisSerializationContext.SerializationPair
.fromSerializer((StringRedisSerializer) redisTemplate.getKeySerializer());
RedisSerializationContext.SerializationPair<?> valuePair = RedisSerializationContext.SerializationPair
.fromSerializer(redisTemplate.getValueSerializer());
return RedisCacheManager
.builder(Objects.requireNonNull(redisTemplate.getConnectionFactory()))
.cacheDefaults(RedisCacheConfiguration
// spring.cache.redis.xxx
.defaultCacheConfig()
.entryTtl(Duration.ZERO)
.disableCachingNullValues()
.serializeKeysWith(keyPair)
.serializeValuesWith(valuePair))
.transactionAware()
.build();
}

private static ObjectMapper getRedisConfigObjectMapper() {
ObjectMapper om = JacksonUtil.copyObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// NON_FINAL配置,让RedisTemplate反序列化时得到正确的对象类型,而不影响如@RequestBody之类的功能
om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
return om;
}
}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%