上一章节介绍了怎样使用 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));
}
}
}