上一章节介绍了怎样使用 HashMapper 映射 Java 对象,本章将介绍怎样通过 Jackson2HashMapper 实现 Java 对象映射。
Jackson2HashMapper 通过使用 FasterXML Jackson 为 Java 对象提供 Redis Hash 映射。Jackson2HashMapper 可以将顶级属性映射为 Hash 字段名,还可以选择将结构扁平化。
扁平化指为所有嵌套属性创建单独的 Hash 项,并尽可能将复杂类型解析为简单类型。
考虑以下类及其包含的数据结构:
public class Person { private String firstname; private String lastname; private Address address; private Date date; private LocalDateTime localDateTime; //... } public class Address { private String city; private String country; //... }
下表显示了前面类中的数据在非扁平化映射中的显示方式:
Hash字段 | 值 |
firstname | Jon |
lastname | Snow |
address | { "city" : "Castle Black", "country" : "The North" } |
date | 1561543964015 |
localDateTime | 2018-01-02T12:13:14 |
下表显示了前面类中的数据在扁平化映射中的显示方式:
Hash字段 | 值 |
firstname | Jon |
lastname | Snow |
address.city | Castle Black |
address.country | The North |
date | 1561543964015 |
localDateTime | 2018-01-02T12:13:14 |
使用订单示例来学习怎样通过 Jackson2HashMapper 将对象映射为 Map,并且保存到 Redis。
使用 Jackson2JsonRedisSerializer 作为 RedisTemplate 的序列化器。如下:
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.serializer.*; @Configuration public class RedisConfigJackson2JsonRedisSerializer { @Bean public RedisTemplate<String,Object> jsonSerialRedisTemplate(RedisConnectionFactory factory) { RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(factory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class)); redisTemplate.setHashKeySerializer(new Jackson2JsonRedisSerializer<Object>(Object.class)); redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class)); redisTemplate.afterPropertiesSet(); return redisTemplate; } }
// Order.java import java.util.ArrayList; import java.util.List; /** * 订单实体 * @author hxstrive.com 2022/10/9 */ public class Order { /** 订单编号 */ private String orderNumber; /** 订单总金额 */ private double amount; /** 订单所属用户 */ private User user; /** 订单商品列表 */ private List<Goods> goodsList; public Order() { this.orderNumber = ""; this.amount = 0.0D; this.user = null; this.goodsList = new ArrayList<>(); } /** * 添加商品到订单 * @param goods */ public void addGoods(Goods goods) { this.goodsList.add(goods); this.amount += goods.getPrice(); } //... } // User.java /** * 用户实体 * @author hxstrive.com 2022/7/5 */ public class User { /** 用户ID */ private int id; /** 用户名 */ private String name; public User() {} public User(int id, String name) { this.id = id; this.name = name; } //... } // Goods.java /** * 商品实体 * @author hxstrive.com 2022/10/9 */ public class Goods { /** 商品编号 */ private String number; /** 商品名称 */ private String name; /** 商品价格 */ private double price; /** 商品数量 */ private int quantity; //... }
使用 @RunWith(SpringRunner.class) 和 @SpringBootTest 注解创建一个测试类,代码如下:
import com.alibaba.fastjson.JSONObject; import com.hxstrive.redis.entity.Goods; import com.hxstrive.redis.entity.Order; import com.hxstrive.redis.entity.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.hash.HashMapper; import org.springframework.data.redis.hash.Jackson2HashMapper; import org.springframework.test.context.junit4.SpringRunner; import java.util.Map; /** * 测试验证 Jackson2HashMapper 的用法 * @author hxstrive.com 2022/10/9 */ @RunWith(SpringRunner.class) @SpringBootTest public class Jackson2HashMapperTest { @Autowired @Qualifier("jsonSerialRedisTemplate") private RedisTemplate<String,Object> redisTemplate; private Order getOrder() { Order order = new Order(); order.setOrderNumber("BH20221009125434"); User user = new User(); user.setId(100); user.setName("张三"); order.setUser(user); Goods goodsJava = new Goods(); goodsJava.setNumber("9787111213826"); goodsJava.setName("《Java编程思想》"); goodsJava.setQuantity(2); goodsJava.setPrice(54.0D); order.addGoods(goodsJava); Goods goodsPhp = new Goods(); goodsPhp.setNumber("9787302596462"); goodsPhp.setName("《PHP从入门到精通》(第6版)"); goodsPhp.setQuantity(1); goodsPhp.setPrice(90.70D); order.addGoods(goodsPhp); return order; } @Test public void toHash() { HashMapper<Object, String, Object> hashMapper = new Jackson2HashMapper(true); Order order = getOrder(); Map<String,Object> map = hashMapper.toHash(order); for(Map.Entry<String,Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); System.out.println(key + "=" + value); } } @Test public void toHashFlatten() { HashMapper<Object, String, Object> hashMapper = new Jackson2HashMapper(false); Order order = getOrder(); Map<String,Object> map = hashMapper.toHash(order); for(Map.Entry<String,Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); System.out.println(key + "=" + value); } } @Test public void save() { Order order = getOrder(); HashMapper<Object, String, Object> hashMapper = new Jackson2HashMapper(false); Map<String,Object> map = hashMapper.toHash(order); for(Map.Entry<String,Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); System.out.println(key + "=" + value); } HashOperations<String,String,Object> ops = redisTemplate.opsForHash(); ops.putAll("jackson", map); } @Test public void find() { HashOperations<String,String,Object> ops = redisTemplate.opsForHash(); Map<String,Object> map = ops.entries("jackson"); HashMapper<Object, String, Object> hashMapper = new Jackson2HashMapper(false); Order order = (Order)hashMapper.fromHash(map); if(null != order) { System.out.println(JSONObject.toJSONString(order, true)); } } @Test public void saveFlatten() { Order order = getOrder(); HashMapper<Object, String, Object> hashMapper = new Jackson2HashMapper(true); Map<String,Object> map = hashMapper.toHash(order); for(Map.Entry<String,Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); System.out.println(key + "=" + value); } HashOperations<String,String,Object> ops = redisTemplate.opsForHash(); ops.putAll("jackson", map); } @Test public void findFlatten() { HashOperations<String,String,Object> ops = redisTemplate.opsForHash(); Map<String,Object> map = ops.entries("jackson"); HashMapper<Object, String, Object> hashMapper = new Jackson2HashMapper(true); Order order = (Order)hashMapper.fromHash(map); if(null != order) { System.out.println(JSONObject.toJSONString(order, true)); } } }