分布式新闻项目实战 - 10.Long类型精度丢失问题

news2025/3/14 0:34:43

怒发冲冠,凭阑处、潇潇雨歇。抬望眼,仰天长啸,壮怀激烈。三十功名尘与土,八千里路云和月。莫等闲、白了少年头,空悲切。
靖康耻,犹未雪。臣子恨,何时灭。驾长车,踏破贺兰山缺。壮志饥餐胡虏肉,笑谈渴饮匈奴血。待从头、收拾旧山河,朝天阙。
——《满江红》 岳飞

在这里插入图片描述


系列文章目录

  1. 项目搭建
  2. App登录及网关
  3. App文章
  4. 自媒体平台(博主后台)
  5. 内容审核(自动)
  6. Long类型精度丢失问题


一、存在的问题

前端的 Number 数据类型,能够表示的整数范围是从 -9007199254740992 ~ 9007199254740992(包含边界值)

如下图,后端返回的 id 超过 9007199254740992 范围时,会导致精度丢失(超过16位后的数字都是 0)
在这里插入图片描述


二、JacksonFilter

在这里插入图片描述

  • 当后端响应给前端的数据中包含了 id 或者 特殊标识(可自定义)的时候,把当前数据进行转换为 String 类型
  • 当前端传递后后端的 dto 中有 id 或者 特殊标识(可自定义)的时候,把当前数据转为 IntegerLong 类型

三、自定义注解

作用: 在需要转换类型的字段属性上,用于非id的属性上

新建 heima-leadnews-model\src\main\java\com\heima\model\common\annotation\IdEncrypt.java 文件:

@JacksonAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
public @interface IdEncrypt {
}

四、序列化和反序列化类

1. 用于序列化自增数字的混淆

新建 heima-leadnews-model\src\main\java\com\heima\model\common\annotation\IdEncrypt.java 文件:

@JacksonAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
public @interface IdEncrypt {
}

2. 用于反序列化自增数字的混淆解密

新建 heima-leadnews-common\src\main\java\com\heima\common\jackson\ConfusionDeserializer.java 文件:

public class ConfusionDeserializer extends JsonDeserializer<Object> {

    JsonDeserializer<Object>  deserializer = null;
    JavaType type =null;

    public  ConfusionDeserializer(JsonDeserializer<Object> deserializer, JavaType type){
        this.deserializer = deserializer;
        this.type = type;
    }

    @Override
    public  Object deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException{
        try {
            if(type!=null){
                if(type.getTypeName().contains("Long")){
                    return Long.valueOf(p.getValueAsString());
                }
                if(type.getTypeName().contains("Integer")){
                    return Integer.valueOf(p.getValueAsString());
                }
            }
            return IdsUtils.decryptLong(p.getValueAsString());
        }catch (Exception e){
            if(deserializer!=null){
                return deserializer.deserialize(p,ctxt);
            }else {
                return p.getCurrentValue();
            }
        }
    }
}

3. 用于过滤序列化时处理的字段

新建 heima-leadnews-common\src\main\java\com\heima\common\jackson\ConfusionSerializerModifier.java 文件:

public class ConfusionSerializerModifier extends BeanSerializerModifier {

    @Override
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
                                                     BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
        List<BeanPropertyWriter> newWriter = new ArrayList<>();
        for(BeanPropertyWriter writer : beanProperties){
            String name = writer.getType().getTypeName();
            if(null == writer.getAnnotation(IdEncrypt.class) && !writer.getName().equalsIgnoreCase("id")){
                newWriter.add(writer);
            } else {
                writer.assignSerializer(new ConfusionSerializer());
                newWriter.add(writer);
            }
        }
        return newWriter;
    }
}

4. 用于过滤反序列化时处理的字段

新建 heima-leadnews-common\src\main\java\com\heima\common\jackson\ConfusionDeserializerModifier.java 文件:

public class ConfusionDeserializerModifier extends BeanDeserializerModifier {

    @Override
    public BeanDeserializerBuilder updateBuilder(final DeserializationConfig config, final BeanDescription beanDescription, final BeanDeserializerBuilder builder) {
        Iterator it = builder.getProperties();

        while (it.hasNext()) {
            SettableBeanProperty p = (SettableBeanProperty) it.next();
            if ((null != p.getAnnotation(IdEncrypt.class)||p.getName().equalsIgnoreCase("id"))) {
                JsonDeserializer<Object> current = p.getValueDeserializer();
                builder.addOrReplaceProperty(p.withValueDeserializer(new ConfusionDeserializer(p.getValueDeserializer(),p.getType())), true);
            }
        }
        return builder;
    }
}

5. 用于注册模块和修改器

新建 heima-leadnews-common\src\main\java\com\heima\common\jackson\ConfusionModule.java 文件:

public class ConfusionModule extends Module {

    public final static String MODULE_NAME = "jackson-confusion-encryption";
    public final static Version VERSION = new Version(1,0,0,null,"heima",MODULE_NAME);

    @Override
    public String getModuleName() {
        return MODULE_NAME;
    }

    @Override
    public Version version() {
        return VERSION;
    }

    @Override
    public void setupModule(SetupContext context) {
        context.addBeanSerializerModifier(new ConfusionSerializerModifier());
        context.addBeanDeserializerModifier(new ConfusionDeserializerModifier());
    }

    /**
     * 注册当前模块
     * @return
     */
    public static ObjectMapper registerModule(ObjectMapper objectMapper){
        //CamelCase策略,Java对象属性:personId,序列化后属性:persionId
        //PascalCase策略,Java对象属性:personId,序列化后属性:PersonId
        //SnakeCase策略,Java对象属性:personId,序列化后属性:person_id
        //KebabCase策略,Java对象属性:personId,序列化后属性:person-id
        // 忽略多余字段,抛错
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//        objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
        return objectMapper.registerModule(new ConfusionModule());
    }

}

6. 自动化配置

提供自动化配置默认ObjectMapper,让整个框架自动处理id混淆

新建 heima-leadnews-common\src\main\java\com\heima\common\jackson\InitJacksonConfig.java 文件:

@Configuration
public class InitJacksonConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper = ConfusionModule.registerModule(objectMapper);
        return objectMapper;
    }

}

五、自动配置

新建 heima-leadnews-common\src\main\resources\META-INF\spring.factories 文件:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.heima.common.exception.ExceptionCatch,\
  com.heima.common.swagger.SwaggerConfiguration,\
  com.heima.common.swagger.Swagger2Configuration,\
  com.heima.common.aliyun.GreenImageScan,\
  com.heima.common.aliyun.GreenTextScan,\
  com.heima.common.tess4j.Tess4jClient,\
  com.heima.common.redis.CacheService,\
  com.heima.common.jackson.InitJacksonConfig

六、标识字段

在dto中传递参数的时候如果想要把数值类型转为json,可以使用@IdEncrypt标识字段进行转换,如下:

@Data
public class ArticleInfoDto {
    
    // 文章ID
    @IdEncrypt
    Long articleId;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/335107.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot——Banner介绍

一、什么是BannerBanner即横幅标语&#xff0c;我们在启动SpringBoot项目时会将Banner信息打印至控制台。我们可以输出一些图形、SpringBoot版本信息等内容。默认情况下是通过实现类SpringBootBanner输出的Banner内容&#xff0c;默认的输出内容如下。二、自定义Banner如果不想…

肠道微生态失调了?可以这样调回来

我们的肠道寄生着大概10万亿个细菌&#xff0c;它们可以合成维生素、必需氨基酸&#xff0c;并参与糖类和蛋白质的代谢&#xff0c;同时还能促进铁、镁、锌等矿物元素的吸收&#xff0c;一直与人体保持着动态平衡。肠道微生态平衡时&#xff0c;人体可以保持正常的生理功能&…

PyQt5编程扩展 3.2 资源文件的使用

目录 本例运行效果&#xff1a; 设计Qt窗体 建立项目 放一个Group Box 放三个Label 放一个Horizontal Slider 放两个Line Edit 层次结构 布局 放一个Group Box 放两个Label 放两个Line Edit 放一个Push Button 层次结构 布局 放一个frame 层次结构 布局 窗体…

Python语言零基础入门教程(十二)

Python 元组 Python 的元组与列表类似&#xff0c;不同之处在于元组的元素不能修改。 元组使用小括号&#xff0c;列表使用方括号。 元组创建很简单&#xff0c;只需要在括号中添加元素&#xff0c;并使用逗号隔开即可。 如下实例&#xff1a; tup1 (physics, chemistry,…

【Unity VR开发】结合VRTK4.0:将浮点操作转换为布尔操作

语录&#xff1a; 奈何桥上奈何愁&#xff0c;奈何桥下浣溪流&#xff0c;奈何人人奈何泪&#xff0c;奈何奈何洗春秋。 前言&#xff1a; 有时&#xff0c;您可能希望使用 一个值来激活或停用操作类型。例如&#xff0c;按下控制器上的扳机轴会导致在完全按下扳机时发生操作。…

西瓜数据集读取的详细解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。喜欢通过博客创作的方式对所学的知识进行总结与归纳,不仅形成深入且独到的理…

php mysql美食网站Dreamweaver

目 录 1 绪论 5 1.1 开发背景 5 1.2 开发意义 6 1.3 本文所做的工作及组织结构 7 2 开发环境介绍 7 2.1 Apache 7 2.2 Mysql 8 2.3 Php 8 2.4 Dreamweaver 9 2.5 WAMP 10 2.6 系统对软硬件要求 11 3 系统分析 11 3.1 需求分析 12 3.…

设计模式之命令模式,以C++为例。

命令模式一般叫&#xff1a;command模式&#xff0c;它将请求的发送者和接受者独立开。命令模式的目的是使得请求的发送者与请求的接收者解耦&#xff0c;并且使得请求的发送者可以控制请求的接收者。 目录 一、命令模式能干什么&#xff1f; 二、多级命令 三、进阶写法 一…

HTTP重定向和转发

1&#xff09;重定向会产生2次请求 2&#xff09;重定向后url地址变化 3&#xff09;重定有三种方法实现 // 重定向方式一 // resp.setStatus(resp.SC_MOVED_TEMPORARILY); // resp.setHeader("Location","http://www.baidu.com"…

JavaEE 初阶 — 确认应答机制

文章目录确认应答机制&#xff08;安全机制&#xff09;1 什么是后发先至问题1 如何解决后发先至问题确认应答机制&#xff08;安全机制&#xff09; 确认应答 是实现可靠传输的最核心机制。 这里指的 可靠传输 不是说 100% 可以把消息发给接收方&#xff0c;而是尽力而为&…

【Linux】进程优先级 | 进程的切换 | 环境变量详解

&#x1f923; 爆笑教程 &#x1f449; 《看表情包学Linux》&#x1f448; 猛戳订阅 &#x1f525; ​ &#x1f4ad; 写在前面&#xff1a;我们先讲解进程的优先级&#xff0c;探讨为什么会存在优先级&#xff0c;以及如何查看系统进程、进程优先级的修改。然后讲解进程的切…

基于SpringBoot的器材管理系统

介绍有一家实验室&#xff0c;里面有100台实验设备&#xff0c;5个实验员。每个设备使用之前需要对设备进行检查&#xff0c;现在存在以下痛点&#xff1a; 实验员检查器材的时候&#xff0c;发现器材不见了&#xff0c;他们都不知道器材是坏了还是其他实验员用到其他器材。非常…

传奇GOM引擎配置PAK密码补丁教程

因为我很少接触GOM引擎&#xff0c;所有很晚才知道PAK密码的事情&#xff0c;以前经常在群里或者QQ上有人问站长&#xff0c;说补丁有PAK密码怎么办&#xff0c;我起初不在意&#xff0c;限制发现是一个大问题&#xff0c;好吧&#xff0c;今天借助这篇文章&#xff0c;分享一下…

Python获取公众号(pc客户端)数据,使用Fiddler抓包工具

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 今天来教大家如何使用Fiddler抓包工具&#xff0c;获取公众号&#xff08;PC客户端&#xff09;的数据。 Fiddler是一个http协议调试代理工具&#xff0c;它能够记录并检查所有你的电脑和互联网之间的http通讯&#xff0c;…

Spring JdbcTemplate 和 事务

JdbcTemplate概述 JdbcTemplate是spring框架中提供的一个对象&#xff0c;是对原始繁琐的Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。例如&#xff1a;操作关系型数据的JdbcTemplate和&#xff0c;操作nosql数据库的RedisTemplate&#xff0c;操作消息…

UDP协议

文章目录一、前沿知识应用层传输层二、UDP协议一、前沿知识 应用层 应用层&#xff1a;描述了应用程序如何理解和使用网络中的通信数据。 我们程序员在应用层的主要工作是自定义协议&#xff0c;因为下面四层都在系统内核/驱动程序/硬件中已经实现好了&#xff0c;不能去修改…

【数据集】中国各类水文专业常用数据集合集

1 水文气象数据 1.1 中国站点尺度天然径流量估算数据集&#xff08;1961&#xff5e;2018年&#xff09; 论文&#xff1a; J2022-High-quality reconstruction of China’s natural streamflow-缪驰远&#xff08;北京师范大学地理科学学部&#xff09; 研究内容&#xff1a…

TLV73312PQDRVRQ1稳压器TPS622314TDRYRQ1应用原理图

一、TLV73312PQDRVRQ1低压差稳压器 1.2V 300MATLV733 300mA 低压差稳压器是有 300mA 拉电流能力的超小型、低静态电流 LDO&#xff0c;具有良好的线路和负载瞬态性能。这些器件具有 1% 的典型精度。TLV733 系列设计具有先进的无电容器结构&#xff0c;确保无需输入或输出电容器…

thinkPHP6接入workman

上篇介绍了workman实现websocket功能&#xff08;链接&#xff1a;https://blog.csdn.net/weixin_38155824/article/details/128952037&#xff09; 这篇就介绍如何在thinkPHP6项目中接入workman。 利用TP6的自定义命令开启websocket服务 查看TP6手册&#xff1a;命令行>自…

Oracle Dataguard(主库为 Oracle rac 集群)配置教程(01)—— dataguard 服务器安装 Oracle 软件

Oracle Dataguard&#xff08;主库为 Oracle rac 集群&#xff09;配置教程&#xff08;01&#xff09;—— dataguard 服务器安装 Oracle 软件 / 本专栏详细讲解 Oracle Dataguard&#xff08;Oracle 版本为11g&#xff0c;主库为双节点 Oracle rac 集群&#xff09;的配置过程…