1、前言
在前后端进行数据交互时,对于日期往往是通过时间戳进行交互,或者是doule、bigdecimal等格式进行格式化保留固定小数点。
比如:double与string、bigdecimal与string、long与date、long与localdatetime
主要通过jsonserializer与jsondeserializer进行实现:
- jsonserializer:用于后端数据返回前端时的序列化转换;
- jsondeserializer:用于前端数据请求后端时的反序列化转换;
- 只有请求或者响应的实体中存定义好的转换的类型才会进入自定义转换器中,比如:转换的字段类型为bigdecimal,如果请求/响应的实体中不包含bigdecimal类型,那么就不会进行到转换器中
在springboot中可以通过配置实现全局参数的字段转换,或者使用注解标注进行指定字段的转换生效或者转换失效;
2、配置类型全局转换器
代码以实现后端格式化bigdecimal数据和前后端交互localdatetime转long两种形式进行演示,实际中可以根据情况进行修改转换方式,实现任意类型的序列化转换;
2.1、定义类型全局转换器
该类中的反序列,对get请求无效,会出现类型转换失败的情况,对于get请求需要单独根据定义反序列化转换器;
dataconverterconfig:
import com.fasterxml.jackson.core.jsongenerator;
import com.fasterxml.jackson.core.jsonparser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.simplemodule;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.format.formatterregistry;
import org.springframework.http.converter.httpmessageconverter;
import org.springframework.http.converter.json.mappingjackson2httpmessageconverter;
import org.springframework.web.servlet.config.annotation.webmvcconfigurer;
import java.io.ioexception;
import java.math.bigdecimal;
import java.text.decimalformat;
import java.time.instant;
import java.time.localdatetime;
import java.time.zoneid;
import java.util.list;
@configuration
public class dataconverterconfig {
/**
* 配置消息转换器
*
* @return
*/
@bean
public webmvcconfigurer webmvcconfigurer() {
return new webmvcconfigurer() {
/**
* 添加自定义消息转换器
*/
@override
public void addformatters(formatterregistry registry) {
// 对于get请求的数据转换
registry.addconverter(new timestamptolocaldateconverter());
}
@override
public void extendmessageconverters(list<httpmessageconverter<?>> converters) {
mappingjackson2httpmessageconverter converter = new mappingjackson2httpmessageconverter();
converter.setobjectmapper(serializingobjectmapper());
converters.add(0, converter);
}
};
}
/**
* serializer配置
*
* @return
*/
public objectmapper serializingobjectmapper() {
objectmapper objectmapper = new objectmapper();
simplemodule module = new simplemodule();
// 禁止null值字段进行序列化
// 如果有需要则进行使用
// objectmapper.setserializationinclusion(jsoninclude.include.non_null);
// 添加默认序列化,将字段转化为转换string,支持各种可以直接使用tostring()方法的类型
// 如果有需要则进行开启
// module.addserializer(biginteger.class, new tostringserializer());
// module.addserializer(long.class, new tostringserializer());
// module.addserializer(integer.class, new tostringserializer());
// module.addserializer(biginteger.class, new tostringserializer());
// 添加自定义序列化 serializer
module.addserializer(bigdecimal.class, new bigdecimalserializer());
module.addserializer(localdatetime.class, new localdatetimeserializer());
// 添加自定义反序列化 deserializer
module.adddeserializer(localdatetime.class, new localdatetimedeserializer());
objectmapper.registermodule(module);
return objectmapper;
}
/**
* 序列化实现bigdecimal转化为string
*/
public static class bigdecimalserializer extends jsonserializer<bigdecimal> {
@override
public void serialize(bigdecimal value, jsongenerator gen, serializerprovider serializers)
throws ioexception {
string res = null;
if (value != null) {
int scale = value.scale();
if (scale > 2) {
res = value.tostring();
} else {
decimalformat df = new decimalformat("#0.00");
res = df.format(value);
}
gen.writestring(res);
}
}
}
/**
* 序列化实现 localdatetime转化为long
*/
public static class localdatetimeserializer extends jsonserializer<localdatetime> {
@override
public void serialize(localdatetime value, jsongenerator gen, serializerprovider serializers)
throws ioexception {
if (value != null) {
long timestamp = value.atzone(zoneid.systemdefault()).toinstant().toepochmilli();
gen.writenumber(timestamp);
}
}
}
/**
* 反序列化实现 long转化为为localdatetime(只对get请求无效)
*/
public static class localdatetimedeserializer extends jsondeserializer<localdatetime> {
@override
public localdatetime deserialize(jsonparser p, deserializationcontext deserializationcontext)
throws ioexception {
long timestamp = p.getvalueaslong();
if (timestamp > 0) {
return localdatetime.ofinstant(instant.ofepochmilli(timestamp), zoneid.systemdefault());
} else {
return null;
}
}
}
}
2.2、定义get请求反序列化转换器
在dataconverterconfig 类中的定义的反序列化转换器,对get请求无效,会出现类型转换失败的情况,对于get请求需要单独根据定义反序列化转换器,比如:此处用到的long转localdatetime反序列化转换,如果有其他类型就需要定义其他的反序列化转换器;
timestamptolocaldateconverter:
import org.springframework.core.convert.converter.converter;
import org.springframework.util.stringutils;
import java.time.instant;
import java.time.localdatetime;
import java.time.zoneid;
/**
* 时间戳字符串转时间类型转换器
*
*/
public class timestamptolocaldateconverter implements converter<string, localdatetime> {
@override
public localdatetime convert(string text) {
if (!stringutils.isempty(text)) {
long timestamp = long.parselong(text);
if (timestamp > 0) {
return localdatetime.ofinstant(instant.ofepochmilli(timestamp), zoneid.systemdefault());
} else {
return null;
}
}
return null;
}
}
2.3、定义实体
@data
public class product {
private long id;
private integer num;
private biginteger count;
private string name;
private bigdecimal price;
private bigdecimal realprice;
private localdatetime createtime;
private date time;
}
2.4、测试controller
@restcontroller
@requestmapping("/test")
@slf4j
public class testcontroller {
@apioperation(value = "测试get请求参数", notes = "测试post请求参数")
@apioperationsupport(order = 5)
@getmapping("/testget")
public object testget(product vo) {
system.out.println("请求参数时间:" + vo.getcreatetime());
product res = new product();
res.setid(system.currenttimemillis());
res.setnum(12);
res.setcount(new biginteger("10"));
res.setname("测试名称");
res.setcreatetime(localdatetime.now());
res.setprice(new bigdecimal("12.1"));
res.setrealprice(new bigdecimal("12.124"));
res.settime(new date());
return res;
}
@apioperation(value = "测试post请求参数", notes = "测试post请求参数")
@apioperationsupport(order = 10)
@postmapping("/testpost")
public product testpost(@requestbody product vo) {
system.out.println("请求参数时间:" + vo.getcreatetime());
product res = new product();
res.setid(system.currenttimemillis());
res.setnum(12);
res.setcount(new biginteger("10"));
res.setname("测试名称");
res.setcreatetime(localdatetime.now());
res.setprice(new bigdecimal("12.1"));
res.setrealprice(new bigdecimal("12.124"));
return res;
}
}
2.5、测试结果
1、反序列化测试
请求时对于createtime参数,传入long类型的时间戳

结果:
虽然前端传入时参数为long类型的时间戳,但是后端打印出的数据格式为localdatetime,表示反序列化是转换成功;

2、序列化测试
响应参数定义如下:

前端结果:
可以看出,在后端定义的实体中createtime字段的类型为localdatetime,price字段的值是12.1只有一位小数;
当响应到前端时createtime字段的值时long类型的时间戳,price字段的值为12.10并且是保留两位小数的string类型值。

3、webmvcconfigurationsupport踩坑说明
如果项目中存在继承webmvcconfigurationsupport的配置类,那么在定义dataconverterconfig(全局转换器)时的配置就需要做出调整,调整如下:
1、dataconverterconfig修改处理
dataconverterconfig中删除webmvcconfigurer webmvcconfigurer()方法,对objectmapper serializingobjectmapper()方法加上@bean注解,更改后代码如下:
@configuration
public class dataconverterconfig {
/**
* serializer配置
*
* @return
*/
@bean
public objectmapper serializingobjectmapper() {
objectmapper objectmapper = new objectmapper();
simplemodule module = new simplemodule();
// 添加自定义序列化 serializer
module.addserializer(bigdecimal.class, new bigdecimalserializer());
module.addserializer(localdatetime.class, new localdatetimeserializer());
// 添加自定义反序列化 deserializer
module.adddeserializer(localdatetime.class, new localdatetimedeserializer());
objectmapper.registermodule(module);
return objectmapper;
}
/**
* 序列化实现bigdecimal转化为string
*/
public static class bigdecimalserializer extends jsonserializer<bigdecimal> {
@override
public void serialize(bigdecimal value, jsongenerator gen, serializerprovider serializers)
throws ioexception {
string res = null;
if (value != null) {
int scale = value.scale();
if (scale > 2) {
res = value.tostring();
} else {
decimalformat df = new decimalformat("#0.00");
res = df.format(value);
}
gen.writestring(res);
}
}
}
/**
* 序列化实现 localdatetime转化为long
*/
public static class localdatetimeserializer extends jsonserializer<localdatetime> {
@override
public void serialize(localdatetime value, jsongenerator gen, serializerprovider serializers)
throws ioexception {
if (value != null) {
long timestamp = value.atzone(zoneid.systemdefault()).toinstant().toepochmilli();
gen.writenumber(timestamp);
}
}
}
/**
* 反序列化实现 long转化为为localdatetime(只对get请求无效),对于get请求需要单独订单转换器,比如:timestamptolocaldateconverter
*/
public static class localdatetimedeserializer extends jsondeserializer<localdatetime> {
@override
public localdatetime deserialize(jsonparser p, deserializationcontext deserializationcontext)
throws ioexception {
long timestamp = p.getvalueaslong();
if (timestamp > 0) {
return localdatetime.ofinstant(instant.ofepochmilli(timestamp), zoneid.systemdefault());
} else {
return null;
}
}
}
}
2、webmvcconfigurationsupport继承类中处理
webmvcconfigurationsupport继承类中新增addformatters()方法与extendmessageconverters方法以及注入objectmapper,更改后代码如下:
@configuration
public class webmvcregistrationsconfig extends webmvcconfigurationsupport {
@resource
private objectmapper serializingobjectmapper;
/**
* 添加自定义消息转换器
*/
@override
protected void addformatters(formatterregistry registry) {
// 添加时间戳转日期类型消息转换器
registry.addconverter(new timestamptolocaldateconverter());
}
@override
public void extendmessageconverters(list<httpmessageconverter<?>> converters) {
mappingjackson2httpmessageconverter converter = new mappingjackson2httpmessageconverter();
converter.setobjectmapper(serializingobjectmapper);
converters.add(0, converter);
}
}
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论