企业网网站,营销团队建设与管理,莱芜做网站公司,网页设计教程详细步骤ppt目录 文章目录 一#xff0c;Fastjson到Jackson的替换方案方案代码序列化反序列化通过key获取某种类型的值类型替换 二#xff0c;Springboot工程中序列化的使用场景三#xff0c;SpringMVC框架中的Http消息转换器1#xff0c;原理#xff1a;2#xff0c;自定义消息转换…目录 文章目录 一Fastjson到Jackson的替换方案方案代码序列化反序列化通过key获取某种类型的值类型替换 二Springboot工程中序列化的使用场景三SpringMVC框架中的Http消息转换器1原理2自定义消息转换器Fastjson序列化消息转换器定义Jackson序列化消息转换器定义 3,Jackson常用注解自定义序列化规则 一Fastjson到Jackson的替换方案
方案代码
package main.java.solutions;import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;/*** json工具类* Date: 2023/7/4 14:38*/
Slf4j
NoArgsConstructor(access AccessLevel.PRIVATE)
public class JsonUtil {/*** 这个是提供给http接口使用的对象*/private static final ObjectMapper OBJECT_MAPPER new ObjectMapper();static {// 通过该方法对mapper对象进行设置所有序列化的对象都将按改规则进行系列化// Include.Include.ALWAYS 默认// Include.NON_DEFAULT 属性为默认值不序列化// Include.NON_EMPTY 属性为 空 或者为 NULL 都不序列化则返回的json是没有这个字段的。这样对移动端会更省流量// Include.NON_NULL 属性为NULL 不序列化OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);OBJECT_MAPPER.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, true);OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);OBJECT_MAPPER.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);SimpleModule module new SimpleModule();module.addSerializer(BigDecimal.class, ToStringSerializer.instance);module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());module.addSerializer(LocalDate.class, new LocalDateSerializer());module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeSerializer());module.addDeserializer(LocalDate.class, new LocalDateDeSerializer());OBJECT_MAPPER.registerModule(module);}/*** 直接获取ObjectMapper对象*/public static ObjectMapper getObjectMapper() {return OBJECT_MAPPER;}/*** 序列化一个对象序列化失败时仅仅打印日志并且返回null。** param object 对象* return String*/public static String toJsonOrNull(Object object) {if (object null) {return null;}try {return OBJECT_MAPPER.writeValueAsString(object);} catch (JsonProcessingException e) {log.error(Json serialize error :, e);}return null;}/*** 序列化一个对象序列化失败则抛异常** param object 对象* return String*/public static String toJsonString(Object object) throws Exception {if (object null) {return null;}try {return OBJECT_MAPPER.writeValueAsString(object);} catch (JsonProcessingException e) {log.error(Json serialize error :, e);throw new Exception(Json serialize error);}}/*** 反序列化失败则抛异常*/public static T T parseObject(String json, ClassT classType) throws Exception {if (StringUtils.isEmpty(json)) {return null;}try {return OBJECT_MAPPER.readValue(json, classType);} catch (Exception e) {log.error(Json de-serialize error :, e);throw new Exception(Json de-serialize error);}}/*** 自定义复杂的泛型对象反序列化失败则抛异常*/public static T T parseObject(String json, TypeReferenceT typeReference) throws Exception{if (StringUtils.isEmpty(json)) {return null;}try {return OBJECT_MAPPER.readValue(json, typeReference);} catch (Exception e) {log.error(Json de-serialize error :, e);throw new Exception(Json de-serialize error);}}/*** 反序列化为Map*/public static MapString, Object parseMap(String json) throws Exception{return parseObject(json, new TypeReferenceMapString, Object() {});}/*** 自定义 List 类型的反序列化** param json JSON 字符串* param classType List 中元素的类类型* param T List 中元素的泛型类型* return 反序列化后的 List 对象*/SuppressWarnings(unchecked)public static T ListT parseArray(String json, ClassT classType) throws Exception {if (StringUtils.isEmpty(json)) {return null;}try {return parseCollection(json, ArrayList.class, classType);} catch (Exception e) {log.error(Error occurred during json deserialization for List: , e);throw new Exception(Error occurred during json deserialization);}}/*** 通用的集合类型反序列化** param jsonStr JSON 字符串* param resultClass 结果集合的类类型* param classType 集合元素的类类型* param C 返回结果的泛型类型必须是 Collection 的子类* param T 集合元素的泛型类型* return 反序列化后的集合对象* throws IOException 如果反序列化过程中出现 I/O 错误*/public static C extends CollectionT, T C parseCollection(String jsonStr, ClassC resultClass, ClassT classType) throws IOException {return OBJECT_MAPPER.readValue(jsonStr, OBJECT_MAPPER.getTypeFactory().constructCollectionType(resultClass, classType));}public static Long getLong(MapString, Object map, String key) throws Exception {return TypeUtils.castToLong(map.get(key));}public static Integer getInteger(MapString, Object map, String key) throws Exception{return TypeUtils.castToInt(map.get(key));}public static String getString(MapString, Object map, String key) {return TypeUtils.castToString(map.get(key));}}package main.java.solutions;import java.math.BigDecimal;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** 类型转换类* Date: 2023/7/4 14:38*/
public class TypeUtils {private static final Pattern NUMBER_WITH_TRAILING_ZEROS_PATTERN Pattern.compile(\\.0*$);public static String castToString(Object value) {if (value null) {return null;}return value.toString();}public static Integer castToInt(Object value) throws Exception{if (value null) {return null;}if (value instanceof Integer) {return (Integer)value;}if (value instanceof BigDecimal) {return intValue((BigDecimal)value);}if (value instanceof Number) {return ((Number)value).intValue();}if (value instanceof String) {String strVal (String)value;if (strVal.length() 0 //|| null.equals(strVal) //|| NULL.equals(strVal)) {return null;}if (strVal.indexOf(,) ! -1) {strVal strVal.replaceAll(,, );}Matcher matcher NUMBER_WITH_TRAILING_ZEROS_PATTERN.matcher(strVal);if (matcher.find()) {strVal matcher.replaceAll();}return Integer.parseInt(strVal);}if (value instanceof Boolean) {return (Boolean)value ? 1 : 0;}if (value instanceof Map) {Map map (Map)value;if (map.size() 2 map.containsKey(andIncrement) map.containsKey(andDecrement)) {Iterator iter map.values().iterator();iter.next();Object value2 iter.next();return castToInt(value2);}}throw new Exception(Cast type error: value);}public static Long castToLong(Object value) throws Exception {if (value null) {return null;}if (value instanceof BigDecimal) {return longValue((BigDecimal)value);}if (value instanceof Number) {return ((Number)value).longValue();}if (value instanceof String) {String strVal (String)value;if (strVal.length() 0 //|| null.equals(strVal) //|| NULL.equals(strVal)) {return null;}if (strVal.indexOf(,) ! -1) {strVal strVal.replaceAll(,, );}try {return Long.parseLong(strVal);} catch (NumberFormatException ex) {//}}if (value instanceof Map) {Map map (Map)value;if (map.size() 2 map.containsKey(andIncrement) map.containsKey(andDecrement)) {Iterator iter map.values().iterator();iter.next();Object value2 iter.next();return castToLong(value2);}}if (value instanceof Boolean) {return (Boolean)value ? 1L : 0L;}throw new Exception(Cast type error: value);}public static int intValue(BigDecimal decimal) {if (decimal null) {return 0;}int scale decimal.scale();if (scale -100 scale 100) {return decimal.intValue();}return decimal.intValueExact();}public static long longValue(BigDecimal decimal) {if (decimal null) {return 0;}int scale decimal.scale();if (scale -100 scale 100) {return decimal.longValue();}return decimal.longValueExact();}
}
序列化
1JSON.toJSONString(this)和JSON.toJSON(this); if为null则返回null如果转换异常就抛异常。
如果是日志打印就使用JsonUtils.toJsonOrNull(this)替换否则使用JsonUtils.toJsonString(this)
反序列化
1JSON.parseObject(deviceInfoStr, DeviceInfo.class); if为null则返回null如果转换异常就抛异常
使用**JsonUtils.parseObject(deviceInfoStr, DeviceInfo.class)**替换
2JSON.parseObject(String text);if为null则返回null如果转换异常就抛异常
使用 **JsonUtils.parseMap(String json)**替换
3JSONObject.parseArray(String text, ClassT clazz)if为null则返回null如果转换异常就抛异常
使用 **JsonUtils.parseArray(String text, ClassT clazz)**替换;
通过key获取某种类型的值
1jsonObject.getLong(String key) if为null则返回null如果转换异常就抛异常
使用**JsonUtils.getLong(map, key)**替换;
2jsonObject.getInteger(String key) if为null则返回null如果转换异常就抛异常
使用 **JsonUtils.getInteger(map, key)**替换;
3jsonObject.getString(String key) if为null则返回null如果转换异常就抛异常
使用 **JsonUtils.getString(map, key)**替换;
类型替换
7返回给前端的是JSONObject使用**MapString, Object**替换
8返回给前端的是JSONArray使用**ListObject**替换
二Springboot工程中序列化的使用场景
控制器Controller控制器负责处理 HTTP 请求和响应其中涉及到请求参数的反序列化和响应结果的序列化。SpringMVC 使用消息转换器MessageConverter来处理请求和响应的序列化和反序列化常见的消息转换器包括 JSON、XML、Form 表单等。RESTful API如果您的 Spring Boot 项目是基于 RESTful API 架构的那么在请求和响应的过程中需要进行对象和 JSON/XML 数据之间的序列化和反序列化。Spring Boot 使用消息转换器来自动处理这些转换过程。数据库操作当使用对象关系映射ORM框架如 Hibernate、Spring Data JPA进行数据库操作时需要将 Java 对象与数据库记录之间进行序列化和反序列化。ORM 框架会自动将对象转换为数据库记录序列化或将数据库记录转换为对象反序列化。缓存操作在使用缓存如 Redis、Memcached时需要将对象存储到缓存中或从缓存中获取对象。这涉及到将对象进行序列化和反序列化以便在缓存中进行存储和检索。消息队列如果在 Spring Boot 项目中使用消息队列如 RabbitMQ、Kafka进行异步消息处理那么消息的生产者和消费者之间需要进行对象的序列化和反序列化以便在消息传递过程中正确地传递和处理对象数据。文件存储当将Java对象以文件形式存储时可能需要将其序列化为JSON或其他格式以便于读取和写入。
三SpringMVC框架中的Http消息转换器
1原理
利用SpringMVC框架可以使得我们在开发时只要在代码中使用**RequestBody和ResponseBody两个注解就可以分别完成从请求报文到对象和从对象到响应报文的转换。而在源码内部其实这种灵活的消息转换机制就是利用HttpMessageConverter**来实现的。
HttpMessageConverter的调用是在RequestResponseBodyMethodProcessor类的解析请求参数的方法resolveArgument()和处理返回值的方法handleReturnValue()中进行调用的。 Http消息转换器接口
org.springframework.http.converter.HttpMessageConverter 3
public interface HttpMessageConverterT {boolean canRead(Class? var1, Nullable MediaType var2);boolean canWrite(Class? var1, Nullable MediaType var2);ListMediaType getSupportedMediaTypes();T read(Class? extends T var1, HttpInputMessage var2) throws IOException, HttpMessageNotReadableException;void write(T var1, Nullable MediaType var2, HttpOutputMessage var3) throws IOException, HttpMessageNotWritableException;
}链路
http请求 -》 DispatcherServlet -》RequestMappingHandlerAdapter处理请求映射的适配器-》ArgumentResolver(参数解析器)/ReturnValueHandlers(返回值处理器)-》RequestResponseBodyMethodProcessor(处理请求和返回的参数)-》HttpMessageConverter的readwrite方法
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerAdapter 1
protected final ListHttpMessageConverter? getMessageConverters() {if (this.messageConverters null) {this.messageConverters new ArrayList();//这是一个抽象方法允许子类覆盖它来配置HTTP消息转换器。开发者可以在子类中实现这个方法来添加自定义的消息转换器。this.configureMessageConverters(this.messageConverters);if (this.messageConverters.isEmpty()) {//中添加一组默认的HTTP消息转换器。这些默认转换器是Spring MVC框架提供的用于支持常见的数据格式如JSON、XML等。this.addDefaultHttpMessageConverters(this.messageConverters);}//这是一个可选的方法允许子类进一步扩展或修改已经配置的HTTP消息转换器。开发者可以在子类中实现这个方法来对已有的消息转换器进行额外的定制。this.extendMessageConverters(this.messageConverters);}return this.messageConverters;}有几种类型的转换器: ByteArrayHttpMessageConverter负责读取二进制格式的数据和写出二进制格式的数据
StringHttpMessageConverter负责读取字符串格式的数据和写出二进制格式的数据(当返回值是或者接受值是String类型时是由这个处理)
ResourceHttpMessageConverter负责读取资源文件和写出资源文件数据
ResourceRegionHttpMessageConverter用于支持分块传输Chunked Transfer Encoding的响应。它允许将资源按照指定的区块大小进行切分分块传输响应给客户端。
SourceHttpMessageConverter用于处理以XML格式或其他文本格式表示的数据。它支持处理一些Java源数据Source类型如javax.xml.transform.SourceXML数据的源表示和org.springframework.core.io.Resource资源文件的源表示。
AllEncompassingFormHttpMessageConverter它是一个综合性的表单数据转换器用于处理表单数据的请求和响应。
Jaxb2RootElementHttpMessageConverter用于处理XML数据并支持Java对象与XML数据之间的转换。它主要依赖于Java Architecture for XML Binding (JAXB) API来实现XML数据的序列化和反序列化。
MappingJackson2HttpMessageConverter负责读取和写入json格式的数据(当返回值是对象或者List就由这个处理)
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor 2
2自定义消息转换器
一般默认的转换器不能满足我们的需求需要自定义消息转换器可以创建自己的转换器类FastjsonJackson消息转换器并在 Spring Boot 配置中进行注册。通常情况下只需要注册您的自定义转换器Spring Boot 将自动将其应用于适当的请求和响应。
Fastjson序列化消息转换器定义
Configuration
public class WebConfig implements WebMvcConfigurer {Overridepublic void configureMessageConverters(ListHttpMessageConverter? converters) {//使用fastjson converterFastJsonHttpMessageConverter converter new FastJsonHttpMessageConverter();FastJsonConfig config new FastJsonConfig();config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect,SerializerFeature.WriteNullListAsEmpty,SerializerFeature.WriteMapNullValue,SerializerFeature.WriteNullStringAsEmpty,SerializerFeature.WriteBigDecimalAsPlain);config.setSerializeFilters(ValueDesensitizeFilter.INSTANCE);// serialize configSerializeConfig serializeConfig SerializeConfig.getGlobalInstance();serializeConfig.put(BigDecimal.class, ToStringSerializer.instance);serializeConfig.put(LocalDateTime.class, LocalDateTimeSerializer.instance);serializeConfig.put(Long.class, ToStringSerializer.instance);serializeConfig.put(Long.TYPE, ToStringSerializer.instance);config.setSerializeConfig(serializeConfig);converter.setFastJsonConfig(config);converters.add(0, converter);}
}
Jackson序列化消息转换器定义
Configuration
public class JacksonConfig {BeanConditionalOnMissingBean(ObjectMapper.class)public ObjectMapper objectMapper() {ObjectMapper objectMapper new ObjectMapper();// 通过该方法对mapper对象进行设置所有序列化的对象都将按改规则进行序列化// Include.Include.ALWAYS 默认// Include.NON_DEFAULT 属性为默认值不序列化// Include.NON_EMPTY 属性为 空 或者为 NULL 都不序列化则返回的json是没有这个字段的。这样对移动端会更省流量// Include.NON_NULL 属性为NULL 不序列化objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);//解析数组集合、List对象 为[]objectMapper.setSerializerFactory(objectMapper.getSerializerFactory().withSerializerModifier(new SerializerModifier()));SimpleModule simpleModule new SimpleModule();simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);simpleModule.addSerializer(Long.class, ToStringSerializer.instance);simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeToTimestampSerializer());simpleModule.addSerializer(LocalDate.class, new LocalDateSerializer());simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeSerializer());simpleModule.addDeserializer(LocalDate.class, new LocalDateDeSerializer());objectMapper.registerModule(simpleModule);return objectMapper;}
}如何优雅地使用Jackson进行序列化和反序列化操作
定义一个通用的工具类对于属性特殊的规则可以在属性上加注解。
3,Jackson常用注解自定义序列化规则
JsonFormat 注解来自定义日期格式。
public class User {private String name;JsonFormat(pattern yyyy-MM-dd)private Date birthday;
}JsonIgnore 注解来排除不想序列化的字段。
public class User {private String name;JsonIgnoreprivate String password;
}JsonProperty 注解来自定义字段名称。
public class User {JsonProperty(username)private String name;
}JsonInclude 注解来指定字段的空值处理策略。
public class User {private String name;JsonInclude(JsonInclude.Include.NON_NULL)private String email;
}使用 JsonSerialize 和 JsonDeserialize 注解来指定自定义的序列化器和反序列化器。
public class User {private String name;JsonSerialize(using LocalDateTimeSerializer.class)JsonDeserialize(using LocalDateTimeDeSerializer.class)private LocalDateTime birthday;
}
自定义反序列化器
/*** 新建这个反序列化器的目的源String串中extendFieldJson属性是对象类型目标对象DeviceInfo中的extendFieldJson属性是String类型转换的时候会报类型不匹配的错误。** Date: 2023/9/19 18:00*/
public class ObjectToStringDeSerializer extends JsonDeserializerString {Overridepublic String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {// 从 JSON 中读取属性的对象值Object objectValue jsonParser.readValueAs(Object.class);// 将对象值转换为json字符串if (objectValue ! null) {return JsonUtil.toJsonString(objectValue);}return null;}
}