NIO-01首篇

NIO简介


java NIO(New IO)从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,却提供了与标准IO不同的IO工作方式。

标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。

Java NIO 与 IO 的主要区别

IONIO
面向流(Stream Oriented)面向缓冲区(Buffer Oriented)
阻塞IO(Blocking IO)非阻塞IO(Non Blocking IO)
(无)选择器(Selectors)

传统IO示例图

NIO示意图

缓冲(Buffer)


Java NIO的核心就是Channel(通道)和Buffer(缓冲)。

一个用于特定基本数据类型的容器。由 java.nio 包定义的,所有缓冲区都是 Buffer 抽象类的子类,其本质是数组。

Java NIO 中的 Buffer 主要用于与 NIO 通道进行
交互,数据是从通道读入缓冲区,从缓冲区写
入通道中的。

Buffer的常用子类

为了可以保存多个相同类型的数据。NIO根据数据类型不同(boolean 除外) ,有多种子类
  •  ByteBuffer
  •  CharBuffer
  •  ShortBuffer
  •  IntBuffer
  •  LongBuffer
  •  FloatBuffer
  •  DoubleBuffer

Buffer的分类

缓冲分为直接缓冲区非直接缓冲区

他们两者最标志的区别是,非直接缓冲区是需要把缓冲区的内容复制到中间缓冲区的,而直接缓冲区没有复制这项,而是进行映射到物理内存来进行的。

如图,这就是非直接缓冲区,也是最常用的方式,一般所指的Buffer也就是这个。它有一个复制的动作,所以相对于直接缓冲区,它的速度并不是很快
这里写图片描述

这是直接缓冲区的,他针对于物理内存,会将缓冲区的数据映射到内存中,然后在另一边通过映射拿到数据,没有复制的动作。因为作用于内存,所以速度快,但成本较高,所占内存和CPU运速较高。
这里写图片描述

  • 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中
  • 直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率
  • 字节缓冲区是直接缓冲区还是非直接缓冲区可通过调用其 isDirect() 方法来确定。
  • static XxxBuffer allocate(int capacity) : 静态方法,创建一个容量为 capacity 的 XxxBuffer 对象。如:
ByteBuffer buf = ByteBuffer.allocate(1024);

Buffer的基本属性

Buffer有一些基本属性需要知道

  •  容量 (capacity) :表示 Buffer 最大数据容量,缓冲区容量不能为负,并且创建后不能更改。通过开始的allocate()或allocateDirect()来指定创建。

  •  限制 (limit):第一个不应该读取或写入的数据的索引,即位于 limit后的数据不可读写。缓冲区的限制不能为负,并且不能大于其容量。默认是容量的大小为限定,当使用flip()方法会将当前位置设为界限,也可以使用limit(int n)方法设置界限

  •  位置 (position):下一个要读取或写入的数据的索引。缓冲区的位置不能为负,并且不能大于其限制。可以通过position(int n)设置位置

  •  标记 (mark)与重置 (reset):标记是一个索引,通过 Buffer 中的 mark() 方法指定 Buffer 中一个特定的 position,之后可以通过调用 reset() 方法恢复到这个 position

    • 0 <= mark <= position <= limit <= capacity

示例图:
这里写图片描述

Buffer的常用方法

方 法描 述
Buffer clear()清空缓冲区并返回对缓冲区的引用
Buffer flip()将缓冲区的界限设置为当前位置,并将当前位置充值为 0。该方法一般用于将缓冲区从写模式切换到读模式,不使用该方法,将无法读取到数据
int capacity()返回 Buffer 的 capacity 大小
boolean hasRemaining()判断缓冲区中是否还有元素
int limit()返回 Buffer 的界限(limit) 的位置
Buffer limit(int n)将设置缓冲区界限为 n, 并返回一个具有新 limit 的缓冲区对象
Buffer mark()对缓冲区设置标记
int position()返回缓冲区的当前位置 position
Buffer position(int n)将设置缓冲区的当前位置为 n , 并返回修改后的 Buffer 对象
int remaining()返回 position 和 limit 之间的元素个数
Buffer reset()将位置 position 转到以前设置的 mark 所在的位置
Buffer rewind()将位置设为为 0, 取消设置的 mark

如何向Buffer中写数据

有两种方式

  1. 读取Channel数据写到Buffer
  2. 通过put方法将数据写Buffer

读取Channel数据写到Buffer的例子

int bytesRead = inChannel.read(buf); //read into buffer.

通过put方法将数据写Buffer的例子:

buf.put(127);
put()方法有很多重载方法,常用的有
  • put(byte b):将给定单个字节写入缓冲区的当前位置

  • put(byte[] src):将 src 中的字节写入缓冲区的当前位置

  • put(int index, byte b):将指定字节写入缓冲区的索引位置(不会移动 position)

如何向Buffer中读取数据

有两种方式

  1. 读取Buffer的数据写入Channel。
  2. 使用get()方法从Buffer中读取数据。

读取Buffer的数据写入Channel的例子:

int bytesWritten = inChannel.write(buf);

使用get()方法从Buffer中读取数据的例子

byte aByte = buf.get();
get()方法有很多重载方法,常用的有
  • get() :读取单个字节

  • get(byte[] dst):批量读取多个字节到 dst 中

  • get(int index):读取指定索引位置的字节(不会移动 position)

代码示例方法

    @Test
    public void test1() {
        String str = "aaaaa";

        //1. 分配一个指定大小的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);
        System.out.println("----------------allocate()----------------");
        System.out.println(buf.capacity());//1024
        System.out.println(buf.limit());//1024
        System.out.println(buf.position());//0

        //2. 利用 put() 存入数据到缓冲区中
        buf.put(str.getBytes());
        System.out.println("----------------put()----------------");
        System.out.println(buf.capacity());//1024
        System.out.println(buf.limit());//1024
        System.out.println(buf.position());//5

        //3. 切换读取数据模式
        //4. 利用 get() 读取缓冲区中的数据
        buf.flip();
        byte[] dst = new byte[buf.limit()];
        buf.get(dst);
        System.out.println("----------------flip()----------------");
        System.out.println(new String(dst,0,dst.length));//aaaaa
        System.out.println(buf.capacity());//1024
        System.out.println(buf.limit());//5
        System.out.println(buf.position());//5

        //5. rewind() : 可重复读
        buf.rewind();
        System.out.println("----------------rewind()----------------");
        System.out.println(buf.capacity());//1024
        System.out.println(buf.limit());//5
        System.out.println(buf.position());//0


        //6. clear() : 清空缓冲区. 但是缓冲区中的数据依然存在,但是处于“被遗忘”状态
        buf.clear();
        System.out.println("----------------clear()----------------");
        System.out.println(buf.capacity());//1024
        System.out.println(buf.limit());//1024
        System.out.println(buf.position());//0

        System.out.println((char)buf.get());//a
    }
@Test
    public void test2(){ 
        String str = "abcdef";
        ByteBuffer buf = ByteBuffer.allocate(1024);

        buf.put(str.getBytes());

        buf.flip();

        byte[] dst = new byte[buf.limit()];
        buf.get(dst, 0, 2);
        System.out.println(new String(dst,0,2));//ab
        System.out.println(buf.position());//2

        //mark() : 标记
        buf.mark();

        buf.get(dst, 2, 2);
        System.out.println(new String(dst,2,2));//cd
        System.out.println(buf.position());//4

        //reset() : 恢复到 mark 的位置
        buf.reset();
        System.out.println(buf.position());//2

        //判断缓冲区中是否还有剩余数据
        if(buf.hasRemaining()){
            //获取缓冲区中可以操作的数量
            System.out.println(buf.remaining());//4
            System.out.println(buf.limit());//6
            int j = buf.remaining();
            for(int i=0;i<j;i++){
                System.out.println((char)buf.get());//c d e f
            }
        }
    }
    @Test
    public void test3(){
        ByteBuffer buf = ByteBuffer.allocateDirect(1024);
        System.out.println(buf.isDirect());//true
    }

通道(Channel)


Java NIO的通道表示打开到 IO 设备(例如:文件、套接字)的连接,类似流,但又有些不同:

  1. 通道是双向的,可以向通道读取数据,也可以向通道写数据。但是流的读写是单向。
  2. 通道的数据是不负责存储,而是先读取或者写入一个Buffer中,只负责负责缓冲区中数据的传输

Java 为 Channel 接口提供的最主要实现类如下:

由 java.nio.channels 包定义的。

  • FileChannel:用于读取、写入、映射和操作文件的通道。
  • DatagramChannel:通过 UDP 读写网络中的数据通道。
  • SocketChannel:通过 TCP 读写网络中的数据。
  • ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个SocketChannel。

示意图
这里写图片描述

获取通道

  1. Java 针对支持通道的类提供了 getChannel() 方法

    • 本地 IO:

      • FileInputStream/FileOutputStream
      • RandomAccessFile
    • 网络IO:

      • Socket
      • ServerSocket
      • DatagramSocket
  2. 在 JDK 1.7 中的 NIO.2 针对各个通道提供了静态方法 open()

  3. 在 JDK 1.7 中的 NIO.2 的 Files 工具类的 newByteChannel()

非直接缓冲区–通道–文件复制

//利用通道完成文件的复制(非直接缓冲区)
    @Test
    public void test1(){
        long start = System.currentTimeMillis();

        //获取文件
        FileInputStream in = null;
        FileOutputStream out = null;
        //获取通道
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            in = new FileInputStream("1.jpg");
            out = new FileOutputStream("2.jpg");

            inChannel = in.getChannel();
            outChannel = out.getChannel();

            //分配指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);

            //读取通道中的数据存入缓冲区中
            while(inChannel.read(buf)!=-1){
                buf.flip();//切换读取数据的模式

                //将缓冲区中的数据写入通道中
                outChannel.write(buf);
                buf.clear();//清空缓冲区
            }
        } catch (Exception e) {
            e.printStackTrace();
        //关闭通道和文件
        }finally{
            if(outChannel != null){
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(inChannel != null){
                try {
                    inChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(in != null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        long end = System.currentTimeMillis();

        System.out.println(end-start);
    }

直接缓冲区–通道–文件复制

    @Test
    //使用直接缓冲区完成文件的复制(内存映射文件)
    public void test2() throws IOException{
        long start = System.currentTimeMillis();

        //只读
        FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
        //读,写,创建
        FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);

        //内存映射文件
        MappedByteBuffer inMapperedBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
        MappedByteBuffer outMapperedBuf = outChannel.map(MapMode.READ_WRITE,0, inChannel.size());

        //直接对缓冲区进行数据的读写操作
        byte[] dst = new byte[inMapperedBuf.limit()];
        inMapperedBuf.get(dst);
        outMapperedBuf.put(dst);

        inChannel.close();
        outChannel.close();

        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }

通道间进行数据传输


如何在通道间进行数据传输呢?主要是依靠

  • transferFrom()

  • transferTo()

这两个方法。

public abstract long transferFrom(ReadableByteChannel src,long position,long count)
                           throws IOException
将数据从源通道(方法内的通道)传输到其他 Channel(对象的通道) 中

如   outChannel.transferFrom(inChannel, 0, inChannel.size());为将inChannel通道的数据传输到outChannel。
public abstract long transferTo(long position,
                                long count,
                                WritableByteChannel target)
                         throws IOException
将数据从源通道(对象的通道)传输到目标Channel(方法的通道) 中

如   inChannel.transferTo(0, inChannel.size(), outChannel);为将inChannel通道的数据传输到outChannel

例子

    @Test
    public void test03() throws IOException{
        //只读
        FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
        //读,写,创建
        FileChannel outChannel = FileChannel.open(Paths.get("4.jpg"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);

        //inChannel.transferTo(0, inChannel.size(), outChannel);
        outChannel.transferFrom(inChannel, 0, inChannel.size());

        inChannel.close();
        outChannel.close();
    }

分散(Scatter)和聚集(Gather)


分散读取(Scattering Reads)是指从 Channel 中读取的数据“分散”到多个 Buffer 中。

这里写图片描述
注意:按照缓冲区的顺序,从 Channel 中读取的数据依次将 Buffer 填满。

聚集写入(Gathering Writes)是指将多个 Buffer 中的数据“聚集”到 Channel。

这里写图片描述
注意:按照缓冲区的顺序,写入 position 和 limit 之间的数据到 Channel 。

示例代码

    @Test
    public void test04() throws Exception{
        RandomAccessFile raf1 = new RandomAccessFile("1.txt","rw");

        //获取通道
        FileChannel channel1 = raf1.getChannel();

        //分配指定大小的缓冲区
        ByteBuffer buf1 = ByteBuffer.allocate(1024);
        ByteBuffer buf2 = ByteBuffer.allocate(1024);

        //分散读取
        ByteBuffer[] bufs = {buf1,buf2};
        channel1.read(bufs);

        for(ByteBuffer byteBuffer:bufs){
            byteBuffer.flip();
        }

        System.out.println(new String(bufs[0].array(),0,bufs[0].limit()));
        System.out.println("------------------------------------------------");
        System.out.println(new String(bufs[1].array(),0,bufs[1].limit()));

        //聚集写入
        RandomAccessFile raf2 = new RandomAccessFile("2.txt","rw");
        FileChannel channel2 = raf2.getChannel();
        channel2.write(bufs);
    }   

字符集


数据在传输的过程中可能出现乱码情况,这是因为数据在编码和解码阶段并没有达成统一的字符集

  • 编码:字符串 -> 字节数组
  • 解码:字节数组 -> 字符串

这是所有支持的字符集

    @Test
    public void test05(){
        Map<String,Charset> map = Charset.availableCharsets();

        Set<Entry<String,Charset>> set = map.entrySet();

        for(Entry<String,Charset> entry:set){
            System.out.println(entry.getKey()+"------"+entry.getValue());
        }
    }

编码解码示例

    @Test
    public void test06() throws CharacterCodingException{
        Charset cs1 = Charset.forName("GBK");

        //获取编码器
        CharsetEncoder ce = cs1.newEncoder();

        //获取解码器
        CharsetDecoder cd = cs1.newDecoder();

        CharBuffer cBuf = CharBuffer.allocate(1024);
        cBuf.put("大唐帝国");
        cBuf.flip();

        //编码
        ByteBuffer bBuf = ce.encode(cBuf);

        for(int i = 0;i < bBuf.limit();i++){
            System.out.println(bBuf.get());
        }

        //解码
        bBuf.flip();
        CharBuffer cBuf2 = cd.decode(bBuf);
        System.out.println(cBuf2.toString());

        //错误解码,造成乱码
        Charset cs2 = Charset.forName("UTF-8");
        bBuf.flip();
        CharBuffer cBuf3 = cs2.decode(bBuf);
        System.out.println(cBuf3.toString());
    }
下载方式:https://pan.quark.cn/s/a4b39357ea24 布线问题(分支限界算法)是计算机科学和电子工程领域中一个广为人知的议题,它主要探讨如何在印刷电路板上定位两个节点间最短的连接路径。 在这一议题中,电路板被构建为一个包含 n×m 个方格的矩阵,每个方格能够被界定为可通行或不可通行,其核心任务是定位从初始点到最终点的最短路径。 分支限界算法是处理布线问题的一种常用策略。 该算法与回溯法有相似之处,但存在差异,分支限界法仅需获取满足约束条件的一个最优路径,并按照广度优先或最小成本优先的原则来探索解空间树。 树 T 被构建为子集树或排列树,在探索过程中,每个节点仅被赋予一次成为扩展节点的机会,且会一次性生成其全部子节点。 针对布线问题的解决,队列式分支限界法可以被采用。 从起始位置 a 出发,将其设定为首个扩展节点,并将与该扩展节点相邻且可通行的方格加入至活跃节点队列中,将这些方格标记为 1,即从起始方格 a 到这些方格的距离为 1。 随后,从活跃节点队列中提取队首节点作为下一个扩展节点,并将与当前扩展节点相邻且未标记的方格标记为 2,随后将这些方格存入活跃节点队列。 这一过程将持续进行,直至算法探测到目标方格 b 或活跃节点队列为空。 在实现上述算法时,必须定义一个类 Position 来表征电路板上方格的位置,其成员 row 和 col 分别指示方格所在的行和列。 在方格位置上,布线能够沿右、下、左、上四个方向展开。 这四个方向的移动分别被记为 0、1、2、3。 下述表格中,offset[i].row 和 offset[i].col(i=0,1,2,3)分别提供了沿这四个方向前进 1 步相对于当前方格的相对位移。 在 Java 编程语言中,可以使用二维数组...
源码来自:https://pan.quark.cn/s/a4b39357ea24 在VC++开发过程中,对话框(CDialog)作为典型的用户界面组件,承担着与用户进行信息交互的重要角色。 在VS2008SP1的开发环境中,常常需要满足为对话框配置个性化背景图片的需求,以此来优化用户的操作体验。 本案例将系统性地阐述在CDialog框架下如何达成这一功能。 首先,需要在资源设计工具中构建一个新的对话框资源。 具体操作是在Visual Studio平台中,进入资源视图(Resource View)界面,定位到对话框(Dialog)分支,通过右键选择“插入对话框”(Insert Dialog)选项。 完成对话框内控件的布局设计后,对对话框资源进行保存。 随后,将着手进行背景图片的载入工作。 通常有两种主要的技术路径:1. **运用位图控件(CStatic)**:在对话框界面中嵌入一个CStatic控件,并将其属性设置为BST_OWNERDRAW,从而具备自主控制绘制过程的权限。 在对话框的类定义中,需要重写OnPaint()函数,负责调用图片资源并借助CDC对象将其渲染到对话框表面。 此外,必须合理处理WM_CTLCOLORSTATIC消息,确保背景图片的展示不会受到其他界面元素的干扰。 ```cppvoid CMyDialog::OnPaint(){ CPaintDC dc(this); // 生成设备上下文对象 CBitmap bitmap; bitmap.LoadBitmap(IDC_BITMAP_BACKGROUND); // 获取背景图片资源 CDC memDC; memDC.CreateCompatibleDC(&dc); CBitmap* pOldBitmap = m...
2025-08-01 08:30:16.004 INFO 2300 --- [nio-8080-exec-8] c.s.interceptor.JwtTokenUserInterceptor : jwt校验:eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3NTQwMTUzNzMsInVzZXJJZCI6Nn0.II1ESkLT1fSvgN_8vLeiUlDRdLvJDC-53dBOijaBl8o 2025-08-01 08:30:16.005 INFO 2300 --- [nio-8080-exec-8] c.s.interceptor.JwtTokenUserInterceptor : 当前员工id:6 2025-08-01 08:30:16.006 INFO 2300 --- [nio-8080-exec-8] c.sky.controller.user.OrdersController : 历史订单查询:page=1,pageSize=10,status=null 2025-08-01 08:30:16.007 DEBUG 2300 --- [nio-8080-exec-8] c.s.mapper.OrdersMapper.pageQuery_COUNT : ==> Preparing: SELECT count(0) FROM orders WHERE user_id = ? 2025-08-01 08:30:16.007 DEBUG 2300 --- [nio-8080-exec-8] c.s.mapper.OrdersMapper.pageQuery_COUNT : ==> Parameters: 6(Long) 2025-08-01 08:30:16.008 DEBUG 2300 --- [nio-8080-exec-8] c.s.mapper.OrdersMapper.pageQuery_COUNT : <== Total: 1 2025-08-01 08:30:16.009 DEBUG 2300 --- [nio-8080-exec-8] com.sky.mapper.OrdersMapper.pageQuery : ==> Preparing: select * from orders WHERE user_id = ? order by order_time desc LIMIT ? 2025-08-01 08:30:16.009 DEBUG 2300 --- [nio-8080-exec-8] com.sky.mapper.OrdersMapper.pageQuery : ==> Parameters: 6(Long), 10(Integer) 2025-08-01 08:30:16.012 DEBUG 2300 --- [nio-8080-exec-8] com.sky.mapper.OrdersMapper.pageQuery : <== Total: 7 2025-08-01 08:30:16.013 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:30:16.013 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 10(Long) 2025-08-01 08:30:16.014 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 1 2025-08-01 08:30:16.015 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:30:16.015 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 9(Long) 2025-08-01 08:30:16.017 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 1 2025-08-01 08:30:16.017 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:30:16.018 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 8(Long) 2025-08-01 08:30:16.019 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 3 2025-08-01 08:30:16.020 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:30:16.020 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 7(Long) 2025-08-01 08:30:16.021 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 1 2025-08-01 08:30:16.022 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:30:16.022 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 6(Long) 2025-08-01 08:30:16.023 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 1 2025-08-01 08:30:16.024 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:30:16.024 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 5(Long) 2025-08-01 08:30:16.027 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 1 2025-08-01 08:30:16.027 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:30:16.027 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 4(Long) 2025-08-01 08:30:16.028 DEBUG 2300 --- [nio-8080-exec-8] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 1 2025-08-01 08:31:11.975 INFO 2300 --- [nio-8080-exec-9] c.s.interceptor.JwtTokenUserInterceptor : jwt校验:eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3NTQwMTUzNzMsInVzZXJJZCI6Nn0.II1ESkLT1fSvgN_8vLeiUlDRdLvJDC-53dBOijaBl8o 2025-08-01 08:31:11.976 INFO 2300 --- [nio-8080-exec-9] c.s.interceptor.JwtTokenUserInterceptor : 当前员工id:6 2025-08-01 08:31:11.976 INFO 2300 --- [nio-8080-exec-9] c.sky.controller.user.OrdersController : 历史订单查询:page=1,pageSize=10,status=null 2025-08-01 08:31:11.977 DEBUG 2300 --- [nio-8080-exec-9] c.s.mapper.OrdersMapper.pageQuery_COUNT : ==> Preparing: SELECT count(0) FROM orders WHERE user_id = ? 2025-08-01 08:31:11.978 DEBUG 2300 --- [nio-8080-exec-9] c.s.mapper.OrdersMapper.pageQuery_COUNT : ==> Parameters: 6(Long) 2025-08-01 08:31:11.978 DEBUG 2300 --- [nio-8080-exec-9] c.s.mapper.OrdersMapper.pageQuery_COUNT : <== Total: 1 2025-08-01 08:31:11.980 DEBUG 2300 --- [nio-8080-exec-9] com.sky.mapper.OrdersMapper.pageQuery : ==> Preparing: select * from orders WHERE user_id = ? order by order_time desc LIMIT ? 2025-08-01 08:31:11.980 DEBUG 2300 --- [nio-8080-exec-9] com.sky.mapper.OrdersMapper.pageQuery : ==> Parameters: 6(Long), 10(Integer) 2025-08-01 08:31:11.982 DEBUG 2300 --- [nio-8080-exec-9] com.sky.mapper.OrdersMapper.pageQuery : <== Total: 7 2025-08-01 08:31:11.982 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:31:11.982 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 10(Long) 2025-08-01 08:31:11.983 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 1 2025-08-01 08:31:11.984 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:31:11.984 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 9(Long) 2025-08-01 08:31:11.985 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 1 2025-08-01 08:31:11.985 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:31:11.985 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 8(Long) 2025-08-01 08:31:11.986 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 3 2025-08-01 08:31:11.987 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:31:11.987 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 7(Long) 2025-08-01 08:31:11.989 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 1 2025-08-01 08:31:11.989 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:31:11.989 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 6(Long) 2025-08-01 08:31:11.990 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 1 2025-08-01 08:31:11.991 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:31:11.991 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 5(Long) 2025-08-01 08:31:11.992 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 1 2025-08-01 08:31:11.993 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Preparing: select * from order_detail where order_id = ? 2025-08-01 08:31:11.993 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : ==> Parameters: 4(Long) 2025-08-01 08:31:11.996 DEBUG 2300 --- [nio-8080-exec-9] c.s.m.OrderDetailMapper.getByOrderId : <== Total: 1 后端返回的这样
08-02
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值