背景:服务端返回信息,其中某ID字段是long型,值是16位。前端拿到后再传给服务端,某ID值发生了改变。
这是因为,JS 中能精准表示的最大整数是:
Math.pow(2, 53),十进制即 9007199254740992
所以我们需要服务端返回给前端时对这种情况进行处理,本文是在springboot环境下使用fastJsonHttpMessageConverter引申介绍。
【1】自定义MyLongSerializerAndDeserializer
我们自定义MyLongSerializerAndDeserializer实现对long型的序列化、反序列化。
import com.alibaba.fastjson.parser.DefaultJSONParser; import com.alibaba.fastjson.parser.JSONLexer; import com.alibaba.fastjson.parser.JSONToken; import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; import com.alibaba.fastjson.serializer.JSONSerializer; import com.alibaba.fastjson.serializer.ObjectSerializer; import com.alibaba.fastjson.serializer.SerializeWriter; import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.util.TypeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.lang.reflect.Type; import java.util.concurrent.atomic.AtomicLong; /** * Created by jianggc at 2021/12/6. */ public class MyLongSerializerAndDeserializer implements ObjectSerializer , ObjectDeserializer { private static final Logger LOGGER= LoggerFactory.getLogger(MyLongSerializerAndDeserializer.class); // 反序列化 @Override public <T> T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) { final JSONLexer lexer = parser.lexer; Long longObject; if (lexer.token() == JSONToken.LITERAL_INT) { long longValue = lexer.longValue(); lexer.nextToken(JSONToken.COMMA); longObject = Long.valueOf(longValue); } else { Object value = parser.parse(); if (value == null) { return null; } longObject = TypeUtils.castToLong(value); } return clazz == AtomicLong.class // ? (T) new AtomicLong(longObject.longValue()) // : (T) longObject; } @Override public int getFastMatchToken() { return JSONToken.LITERAL_INT; } //序列化 @Override public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { SerializeWriter out = serializer.getWriter(); if (object == null) { out.writeNull(SerializerFeature.WriteNullNumberAsZero); } else if (fieldType == java.lang.Long.class){ // 这里,如果是long,我们就返回"实际值"这样的字符串格式 LOGGER.debug("对long进行处理"); out.write("\""+object+"\""); return; } } }
那么我们如何使用MyLongSerializerAndDeserializer
呢?两张方式:
- ① 某个bean的某个字段单独指定;
- ② 设置在SerializeConfig中
① 某个bean字段单独指定
如下所致,在ID字段上指定@JSONField(serializeUsing = MyLongSerializerAndDeserializer.class)
,那么只会对该bean该字段处理。
@Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @TableName("tb_sys_course") @ApiModel(value="SysCourse对象", description="课程表") public class SysCourse implements Serializable { private static final long serialVersionUID = 1L; @JSONField(serializeUsing = MyLongSerializerAndDeserializer.class) @TableId(value = "id", type = IdType.AUTO) private Long id; @ApiModelProperty(value = "课程名称") private String name; //... }
② 全局配置
如下所示,在配置类中注入如下bean,设置MyLongSerializerAndDeserializer。
@Bean FastJsonHttpMessageConverter fastJsonHttpMessageConverter(){ // 添加支持的MediaTypes;不添加时默认为*/*,也就是默认支持全部 // 但是MappingJackson2HttpMessageConverter里面支持的MediaTypes为application/json List<MediaType> fastMediaTypes = new ArrayList<>(); fastMediaTypes.add(MediaType.APPLICATION_JSON); fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); FastJsonConfig config = new FastJsonConfig(); // 设置日期转换格式 config.setDateFormat("yyyy-MM-dd HH:mm:ss"); //设置字符集 config.setCharset(Charset.forName("UTF-8")); // 设置SerializerFeature config.setSerializerFeatures( //输出类名 SerializerFeature.WriteClassName, //输出map中value为null的数据 SerializerFeature.WriteMapNullValue, //json格式化 SerializerFeature.PrettyFormat, //输出空list为[],而不是null SerializerFeature.WriteNullListAsEmpty, //输出空string为"",而不是null SerializerFeature.WriteNullStringAsEmpty ); // 设置自定义序列化器 config.getSerializeConfig().put(java.lang.Long.class,new MyLongSerializerAndDeserializer()); converter.setFastJsonConfig(config); converter.setSupportedMediaTypes(fastMediaTypes); return converter; }
【2】关于JSON
① 什么是JSON
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
- JSON 是轻量级的文本数据交换格式
- JSON 独立于语言
- JSON 具有自我描述性,更易理解
- JSON 文件的文件类型是 “.json”
- JSON 文本的 MIME 类型是 “application/json”
- JSON 使用 Javascript语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。 目前非常多的动态(PHP,JSP,.NET)编程语言都支持JSON。
② JSON实例
创建JSON对象,键为employees,值为含有三个JSON对象的对象数组;
var JSONObject= { "employees": [ { "firstName":"Bill" , "lastName":"Gates" }, { "firstName":"George" , "lastName":"Bush" }, { "firstName":"Thomas" , "lastName":"Carter" } ] }
创建JSON数组对象,也是数组对象;该数组对象是由三个JSON对象组成。
var employees = [ { "firstName":"Bill" , "lastName":"Gates" }, { "firstName":"George" , "lastName":"Bush" }, { "firstName":"Thomas" , "lastName": "Carter" } ];
可以像这样访问数组对象中的第一项:
employees[1].firstName //返回的值是: George
可以像这样修改数据:
employees[1].firstName = "Jobs";
③ JSON对象转JavaScript对象
eval( )函数
由于 JSON 语法是 JavaScript 语法的子集,JavaScript 函数 eval() 可用于将 JSON 文本转换为 JavaScript 对象。
eval() 函数使用的是 JavaScript 编译器,可解析 JSON 文本,然后生成 JavaScript 对象。必须把文本包围在括号中,这样才能避免语法错误:
var JSONObject = '{ "employees" : [' + '{ "firstName":"Bill" , "lastName":"Gates" },' + '{ "firstName":"George" , "lastName":"Bush" },' + '{ "firstName":"Thomas" , "lastName":"Carter" } ]}';
转JS对象:
var obj = eval("("+JSONObject+")");
JSON.parse( )
eval() 函数可编译并执行任何 JavaScript 代码。
这隐藏了一个潜在的安全问题。
使用 JSON 解析器将 JSON 转换为 JavaScript 对象是更安全的做法。
JSON 解析器只能识别 JSON 文本,而不会编译脚本。
在浏览器中,这提供了原生的 JSON 支持,而且 JSON 解析器的速度更快
var obj = JSON.parse(JSONObject);
JSON对象转为string对象
var jsonStr = JSON.stringify(jsonObject)
将表单转为JSON Object
var jsonObject = $('#editform').serializeArray();//JSON Object