js精度丢失坑

简介: js精度丢失坑

飞蛾扑火时一定是极快乐幸福的。——三毛

我们在进行开发时可能会遇到这样一个坑,那就是js代码的精度丢失

可以看到16位以后就会出现精度丢失的问题

我们定义一个简单接口,这里用com.baomidou.mybatisplus.core.toolkit.IdWorker.getId()生成19位为Long类型的id

@GetMapping("json")
@ResponseBody
public Ruben json() {
    return new Ruben(IdWorker.getId());
}

返回的Ruben对象

/**
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/6 0006 21:37
 */
public class Ruben {
    private Long id;
    public Ruben(Long id) {
        this.id = id;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
}

请求一下

可以看到我们Response中是正常的

Preview中就出现了精度丢失的问题

当然,我们可以转换为string,这样就不会出现精度丢失问题

但是,我们在返回json格式数据的接口中如果要一个一个处理的话非常麻烦,我们可以配置一下WebMvcConfigurer

如果我们使用的Mvc默认的jackson,只需如下配置即可

package com.ruben.simplethymeleaf.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
 * MVC配置类
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/6 0006 20:20
 */
@Configuration
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 全局配置序列化返回 JSON 处理
        final ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setObjectMapper(objectMapper);
        converters.add(converter);
    }
}

然后我们配置完后重启项目

再次请求,可以看到默认将Long给我们转成了String

假设你用的是FastJson,则需要如下配置

package com.ruben.simplethymeleaf.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
/**
 * MVC配置类
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/7/6 0006 20:20
 */
@Configuration
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
    /**
     * Fastjson处理精度丢失问题
     *
     * @param converters 转换器
     */
    /**
     * @param converters 转换器
     * @author <achao1441470436@gmail.com>
     * @since 2021/5/21 0021 15:08
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter fastJsonConverter = new FastJsonHttpMessageConverter();
        // 设置允许ContentType
        List<MediaType> supportedMediaTypes = new ArrayList<>();
        supportedMediaTypes.add(MediaType.APPLICATION_JSON);
        supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML);
        supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
        supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
        supportedMediaTypes.add(MediaType.APPLICATION_PDF);
        supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML);
        supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML);
        supportedMediaTypes.add(MediaType.APPLICATION_XML);
        supportedMediaTypes.add(MediaType.IMAGE_GIF);
        supportedMediaTypes.add(MediaType.IMAGE_JPEG);
        supportedMediaTypes.add(MediaType.IMAGE_PNG);
        supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM);
        supportedMediaTypes.add(MediaType.TEXT_HTML);
        supportedMediaTypes.add(MediaType.TEXT_MARKDOWN);
        supportedMediaTypes.add(MediaType.TEXT_PLAIN);
        supportedMediaTypes.add(MediaType.TEXT_XML);
        fastJsonConverter.setSupportedMediaTypes(supportedMediaTypes);
        FastJsonConfig fjc = new FastJsonConfig();
        // 配置序列化策略
        // ID_WORKER 生成主键太长导致 js 精度丢失
        // JavaScript 无法处理 Java 的长整型 Long 导致精度丢失,具体表现为主键最后两位永远为 0,解决思路: Long 转为 String 返回
        fjc.setSerializerFeatures(SerializerFeature.BrowserCompatible);
        fastJsonConverter.setFastJsonConfig(fjc);
        converters.add(fastJsonConverter);
    }
}

同样的效果如下

当然,有种情况,是我们没有用ajax请求Json数据,而是直接使用thymeleaf进行渲染

在页面上当然没问题,但在js代码里就会出现精度丢失

我们写一个接口跳转到对应页面

@GetMapping
public String index() {
    request.setAttribute("id", IdWorker.getId());
    request.setAttribute("ruben", new Ruben(IdWorker.getId()));
    return "index";
}

然后在页面上渲染我们的idruben.id

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ruben</title>
</head>
<body>
<div>
    <div th:text="${id}"></div>
    <div>[[${ruben.id}]]</div>
</div>
</body>
</html>

可以看到页面是成功渲染

但如果我们在js里替换

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ruben</title>
</head>
<body>
<div>
    <div th:text="${id}"></div>
    <div>[[${ruben.id}]]</div>
</div>
<script th:inline="javascript">
    var id = [[${id}]]
    console.log(id)
</script>
<script th:inline="javascript">
    /*<![CDATA[*/
    var id = /*[[${id}]]*/ 'Achao';
    /*]]>*/
    console.log(id)
</script>
</body>
</html>

可以看到浏览器控制台里确实是替换成功了

但我们控制台输出的数据出现精度丢失了

所以我们可以如下解决,直接在外层套个引号即可

<script th:inline="javascript">
    var id = '[[${id}]]'
    console.log(id)
</script>

效果如下

打印出来可以看到第一个也正确

相关文章
|
8月前
|
JSON JavaScript 前端开发
解决js中Long类型数据在请求与响应过程精度丢失问题(springboot项目中)
解决js中Long类型数据在请求与响应过程精度丢失问题(springboot项目中)
686 0
|
8月前
|
存储 前端开发 JavaScript
【JavaScript】浮点数精度问题
浮点数精度问题是指在计算机中使用二进制表示浮点数时,由于二进制无法精确表示某些十进制小数,导致计算结果可能存在舍入误差或不精确的情况。 这个问题主要源于浮点数的存储方式。在计算机中,浮点数通常使用IEEE 754标准来表示。该标准将浮点数分为符号位、指数位和尾数位,使用科学计数法来表示一个浮点数。
112 0
|
6月前
|
JavaScript
js 精确计算(解决js四则运算精度缺失问题)
js 精确计算(解决js四则运算精度缺失问题)
165 0
|
JavaScript 前端开发 Java
如何避免和解决JavaScript中精度损失问题
如何避免和解决JavaScript中精度损失问题
141 0
|
8月前
|
存储 JavaScript 前端开发
浮点数不再神秘:JS浮点数精度详解
浮点数不再神秘:JS浮点数精度详解
|
8月前
|
存储 JavaScript 前端开发
说说JavaScript数字精度丢失的问题,如何解决?
在 JavaScript 中,数字精度丢失是一种普遍的问题。这是因为 JavaScript 内部的数字均以 IEEE 754 标准的双精度浮点数格式存储,这种格式只能精确表示有限个小数,而对于一些无限循环小数或无理数,无法精确表示,就会出现精度丢失的情况。
164 0
|
缓存 算法 JavaScript
雪花算法原理以及JS精度丢失问题
雪花算法原理以及JS精度丢失问题
574 0
|
JavaScript
js计算精确度丢失问题解决,js小数失精度的解决方法
js计算精确度丢失问题解决,js小数失精度的解决方法
288 0
|
JavaScript
js加减乘除运算出现精度丢失
js加减乘除运算出现精度丢失