序列化和反序列化
序列化 (Serialization)
序列化是将对象转换为可以存储或传输的格式的过程。这个过程通常涉及将对象转换为字节流、JSON 字符串、XML 文档等格式。序列化的目的是将对象的状态保存下来,以便稍后可以恢复或在不同的系统之间传递数据。
典型应用场景
- 持久化存储:将对象保存到文件或数据库中。
- 网络传输:将对象通过网络传输到远程系统。
- 缓存:将对象存储到内存或分布式缓存系统中。
代码示例
对于一个简单的 Java 对象 Person
:
public class Person {
private String name;
private int age;
// Constructors, getters, and setters
}
ObjectMapper objectMapper = new ObjectMapper();
Person person = new Person("Alice", 30);
String json = objectMapper.writeValueAsString(person);
System.out.println(json); // 输出: {"name":"Alice","age":30}
反序列化 (Deserialization)
反序列化是将存储或传输格式的数据转换回对象的过程。这个过程的目的是恢复对象的状态,使其可以在应用程序中使用。反序列化通常是序列化的逆过程。
典型应用场景
- 数据加载:从文件或数据库中加载对象。
- 网络接收:从网络中接收到对象数据。
- 缓存读取:从缓存系统中读取对象。
代码示例
继续上面的示例,将 JSON 字符串反序列化回 Person
对象:
String json = "{\"name\":\"Alice\",\"age\":30}";
Person person = objectMapper.readValue(json, Person.class);
System.out.println(person.getName()); // 输出: Alice
System.out.println(person.getAge()); // 输出: 30
用于反序列化的JsonUtils
public final class JsonUtils {
// 定义JSON对象开始标记
private static final JsonToken JSON_OBJECT_START_TOKEN = JsonToken.START_OBJECT;
// 定义JSON数组开始标记
private static final JsonToken JSON_ARRAY_START_TOKEN = JsonToken.START_ARRAY;
// 配置默认的ObjectMapper,用于JSON序列化和反序列化
private static final ObjectMapper DEFAULT_MAPPER = Jackson2ObjectMapperBuilder.json()
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) // 禁用日期写为时间戳
.simpleDateFormat("yyyy-MM-dd HH:mm:ss") // 设置日期格式
.timeZone(TimeZone.getDefault()) // 设置时区
.serializationInclusion(JsonInclude.Include.NON_NULL) // 仅包含非空字段
.build()
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 禁用未知属性失败功能
// 私有构造方法,防止实例化工具类
private JsonUtils() {
}
// 检查字节数组是否为有效的JSON
public static boolean isValidJSON(byte[] jsonByte) {
return jsonByte.length > 0 &&
(JSON_OBJECT_START_TOKEN.asByteArray()[0] == jsonByte[0] || JSON_ARRAY_START_TOKEN.asByteArray()[0] == jsonByte[0]);
}
// 检查字符串是否为有效的JSON
public static boolean isValidJSON(String json) {
return json.startsWith(JSON_OBJECT_START_TOKEN.asString()) || json.startsWith(JSON_ARRAY_START_TOKEN.asString());
}
// 将对象序列化为JSON字符串
@SneakyThrows
public static String toJSON(Object obj) {
if (obj == null) {
return null;
}
if (String.class.equals(obj.getClass())) {
return obj.toString();
}
return DEFAULT_MAPPER.writeValueAsString(obj);
}
// 将JSON字符串反序列化为指定类型的对象
@SneakyThrows
public static <T> T fromJSON(String json, Class<T> clazz) {
return DEFAULT_MAPPER.readValue(json, clazz);
}
// 使用自定义的ObjectMapper将JSON字符串反序列化为指定类型的对象
@SneakyThrows
public static <T> T fromJSON(String json, Class<T> clazz, UnaryOperator<ObjectMapper> customMapper) {
return customMapper.apply(DEFAULT_MAPPER.copy()).readValue(json, clazz);
}
// 将JSON字符串反序列化为带有泛型类型的信息对象
@SneakyThrows
public static <T> T fromJSON(String json, TypeReference<T> type) {
if (StringUtils.isEmpty(json)) {
return null;
}
return DEFAULT_MAPPER.readValue(json, type);
}
// 将字节数组形式的JSON反序列化为带有泛型类型的信息对象
@SneakyThrows
public static <T> T fromJSON(byte[] json, TypeReference<T> type) {
return DEFAULT_MAPPER.readValue(json, type);
}
// 将JSON字符串反序列化为指定类型的对象列表
@SneakyThrows
public static <E> List<E> fromJSONList(String json, Class<E> clazz) {
return DEFAULT_MAPPER.readValue(json, DEFAULT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz));
}
// 将JSON字符串反序列化为指定键值类型的映射
@SneakyThrows
public static <K, V> Map<K, V> fromJSONMap(String json, Class<K> kClazz, Class<V> vClazz) {
return DEFAULT_MAPPER.readValue(json, DEFAULT_MAPPER.getTypeFactory().constructMapType(Map.class, kClazz, vClazz));
}
// 将JSON字符串反序列化为键类型为指定类,值类型为列表的映射
@SneakyThrows
public static <K, V> Map<K, V> fromListJSONMap(String json, Class<K> kClazz, Class<List> vClazz) {
return DEFAULT_MAPPER.readValue(json, DEFAULT_MAPPER.getTypeFactory().constructMapType(Map.class, kClazz, vClazz));
}
// 将JSON字符串反序列化为JsonNode
@SneakyThrows
public static JsonNode fromJSON(String json) {
return DEFAULT_MAPPER.readTree(json);
}
}
HTTP请求
Spring Framework中RestTemplate的简单使用
url
:请求的URL地址。method
:HTTP方法,例如GET、POST等。requestEntity
:包含请求头和请求体的HttpEntity
对象,可以为null。responseType
:响应体的类型,例如String.class
或自定义的类。uriVariables
:URL中的变量,使用一个Map
来表示。throws RestClientException
:声明这个方法可能会抛出RestClientException
。
自定义 HttpEntity 类
private HttpEntity createHttpEntity() {
HttpHeaders httpHeaders = new HttpHeaders();
if (this.httpMethod != null) {
httpHeaders.setContentType(this.contentType);
}
if (this.headers != null) {
headers.forEach(httpHeaders::add);
}
if (HttpMethod.POST == this.httpMethod && this.requestBody != null) {
if (this.requestBody instanceof Map) {
MultiValueMap httpBody = new LinkedMultiValueMap<>();
((Map) this.requestBody).forEach(httpBody::add);
return new HttpEntity<>(httpBody, httpHeaders);
} else {
return new HttpEntity<>(JsonUtils.toJSON(this.requestBody), httpHeaders);
}
}
return new HttpEntity<>(Collections.emptyMap(), httpHeaders);
}
自定义 RestTemplate 对于某一些外接服务,可能涉及到密匙认证,那么可在此处加入密匙相关内容。
private RestTemplate createRestTemplate() {
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setConnectionRequestTimeout(10000);
httpRequestFactory.setConnectTimeout(10000);
httpRequestFactory.setReadTimeout(10000);
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
if (!this.disableTraceLog) {
restTemplate.setInterceptors(Lists.newArrayList(new TraceHttpLogInterceptor()));
}
if (StringUtils.isNotEmpty(this.username) && StringUtils.isNotEmpty(this.password)) {
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(this.username, this.password));
restTemplate.setInterceptors(restTemplate.getInterceptors());
}
return restTemplate;
}
运行实例
Optional<List<UpmDimeNodeDTO>> resp = HttpRequests.post(getUpmRpcUrl(upmProps.getUserDimeNode()))
.json(new UserInfo(misNumber,true))
.doRequest()
.map(jsonStr -> {
try {
log.info(param,jsonStr);
JSONObject jsonObject = JSON.parseObject(jsonStr);
String data = jsonObject.getString("data");
List<ObjectDTO> upmDimeNodeDTOS = JSON.parseObject(data, new com.alibaba.fastjson.TypeReference<List<ObjectDTO>>() {
});
return ObjectDTO == null ? Lists.newArrayList() : ObjectDTO;
} catch (Exception e) {
log.info("Rpc-exception param[{}],resJson[{}]", param,
jsonStr);
return Lists.newArrayList();
}
});
Response构建
通常RPC远程调用时,返回的类型一般会有某一个实体类、List<实体类>、分页查询类型等,返回类型的封装可参考以下。
实体类
public class ObjBaseResp<T> {
private T data;
private Integer code;
private String msg;
}
List<实体类>
public class ListBaseResp<T> {
private List<T> data;
private Integer code;
private String msg;
}
分页查询
public class UpmPageBaseResp<T> {
/**
* 结果集
*/
private List<T> records;
/**
* 根据条件查询出的数据总数
*/
private Integer total;
/**
* 每页条数
*/
private Integer size;
/**
* 总页数
*/
private Integer pages;
/**
* 当前页
*/
private Integer current;
}