Jun 01, 2021 Article blog
This article was reproduced from the public number: Java Geek Technology Author: Duck Blood Fans
In recent days has been in the transformation project, the use of snowflake algorithm to generate the primary key ID, suddenly stepped on a pit, front
JavaScript
in taking
Long
type parameters, the parameter value is a bit wrong!
Recently in the transformation of the internal management system, found a huge pit, that is, the front-end
JavaScript
in the acquisition of back-end
Long
parameters, the accuracy of the loss!
At first, it was normal to simulate an interface request with
postman
but when you use a browser request, something goes wrong!
@RequestMapping("/queryUser")
public List<User> queryUser(){
List<User> resultList = new ArrayList<>();
User user = new User();
//赋予一个long型用户ID
user.setId(123456789012345678L);
resultList.add(user);
return resultList;
}
Open the browser and request the interface, the result is as follows!
Simulate interface requests with postman, and the results are as follows!
At the beginning, I really did not find this pit, the results of testing, only to find that the front end passed to the back end of the ID, and the ID stored in the database is not consistent, only to find JavaScript and this pit!
For its own
Number
type in
JavaScript
does not fully represent
Long
type of number, and there is a loss of precision when
Long
length is greater than
17
bits.
When we change the user ID above to 19 bits, let's look at the results returned by the browser request.
//设置用户ID,位数为19位
user.setId(1234567890123456789l);
Browser request results!
When the returned result exceeds 17 bits, the back all becomes 0!
What should I do if I encounter this situation?
long
type to
String
type in the background, but it's a bit expensive and needs to be changed wherever it's involved
long
type to
String
type, which enables global conversion (recommended)
Because the project involves a lot of code, it is not possible to change the
long
type to
String
type, and there are so many ways to use the
Long
type that it is very risky to change, so it is not recommended!
The ideal method is to use
aop代理
to intercept all methods, the return parameters for unified processing, the use of tools for conversion, the process is as follows!
We can use
Jackson
toolkit to serialize objects.
maven
<!--jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
JsonUtil
public class JsonUtil {
private static final Logger log = LoggerFactory.getLogger(JsonUtil.class);
private static ObjectMapper objectMapper = new ObjectMapper();
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
static {
// 对象的所有字段全部列入
objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
// 取消默认转换timestamps形式
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// 忽略空bean转json的错误
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
//设置为东八区
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
// 统一日期格式
objectMapper.setDateFormat(new SimpleDateFormat(DATE_FORMAT));
// 反序列化时,忽略在json字符串中存在, 但在java对象中不存在对应属性的情况, 防止错误
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 序列换成json时,将所有的long变成string
objectMapper.registerModule(new SimpleModule().addSerializer(Long.class, ToStringSerializer.instance).addSerializer(Long.TYPE, ToStringSerializer.instance));
}
/**
* 对象序列化成json字符串
* @param obj
* @param <T>
* @return
*/
public static <T> String objToStr(T obj) {
if (null == obj) {
return null;
}
try {
return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
} catch (Exception e) {
log.warn("objToStr error: ", e);
return null;
}
}
/**
* json字符串反序列化成对象
* @param str
* @param clazz
* @param <T>
* @return
*/
public static <T> T strToObj(String str, Class<T> clazz) {
if (StringUtils.isBlank(str) || null == clazz) {
return null;
}
try {
return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);
} catch (Exception e) {
log.warn("strToObj error: ", e);
return null;
}
}
/**
* json字符串反序列化成对象(数组)
* @param str
* @param typeReference
* @param <T>
* @return
*/
public static <T> T strToObj(String str, TypeReference<T> typeReference) {
if (StringUtils.isBlank(str) || null == typeReference) {
return null;
}
try {
return (T) (typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference));
} catch (Exception e) {
log.warn("strToObj error", e);
return null;
}
}
}
Person
for testing
@Data
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
//Long型参数
private Long uid;
private String name;
private String address;
private String mobile;
private Date createTime;
}
public static void main(String[] args) {
Person person = new Person();
person.setId(1);
person.setUid(1111L);
person.setName("hello");
person.setAddress("");
System.out.println(JsonUtil.objToStr(person));
}
The output is as follows:
One of the most critical lines of code is to register this conversion class to enable all
long
to be
string
// 序列换成json时,将所有的long变成string
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
If you want to format a date, you can set it globally.
//全局统一日期格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
Alternatively, set a property individually, such as formatting the
createTime
property to
yyyy-MM-dd
with just the following annotations.
@JsonFormat(pattern="yyyy-MM-dd", timezone="GMT+8")
private Date createTime;
Once the tool conversion class is written, it's very simple, and you only need to serialize the parameters returned by
aop
intercept method to automatically turn all
long
into
string
If it's a
SpringMVC
project, it's easy to do.
ObjectMapper
package com.example.util;
/**
* 继承ObjectMapper
*/
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
super();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
registerModule(simpleModule);
}
}
<mvc:annotation-driven >
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg index="0" value="utf-8" />
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
<value>text/plain;charset=UTF-8</value>
</list>
</property>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.example.util.CustomObjectMapper">
<property name="dateFormat">
<-对日期进行统一转化->
<bean class="java.text.SimpleDateFormat">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" />
</bean>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
In the case of a SpringBoot project, the operation is similar.
WebConfig
configuration class and implement the
configureMessageConverters
method from
WebMvcConfigurer
/**
* WebMvc配置
*/
@Configuration
@Slf4j
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
/**
*添加消息转化类
* @param list
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> list) {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = jsonConverter.getObjectMapper();
//序列换成json时,将所有的long变成string
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
list.add(jsonConverter);
}
}
In the actual project development, many services are pure microservices development, do not use
SpringMVC
in this case, using
JsonUtil
tool class to serialize objects, may be a very good choice.
If there is something wrong with understanding, welcome netizens to criticize and point out!
The above is
W3Cschool编程狮
about
the back end to receive long type parameters when the accuracy is lost, how to deal with this pit
related to the introduction, I hope to help you.