Alibaba-Easyexcel 使用总结

简介

简介

EasyExcel 是一个基于 Java 的简单、省内存的读写 Excel 的开源项目,在尽可能节约内存的情况下支持读写百 M 的 Excel。

但注意,其不支持:

  • 单个文件的并发写入、读取
  • 读取图片

常见问题

Excel 术语

  • Sheet,工作薄。

    在这里插入图片描述

  • Row,行,第一行索引从 0 开始。

  • Column,列,第一列索引从 0 开始。

    在这里插入图片描述

  • Cell,单元格。

    在这里插入图片描述

项目准备

新建 Maven 项目,如下配置:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>easyexcel</artifactId>
        <version>3.1.1</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.22</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.47</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

读 Excel

简单读取

准备如下 excel 文件。

在这里插入图片描述

编写数据类,用来对从 Excel 文件读取到文件内容进行封装。

@Data
public class PersonData {
    private Long id;
    private Date birthday;
    private String name;
}

编写读取代码,使用 EasyExcel 提供 API 读取 Excel 文件内容。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

// 不要求:JDK8+
// 不用额外写一个 XxxListener,直接用内置 ReadListener
@Test
public void read() {
    String fileName = "Excel 文件路径";
    // 这里需要指定读用哪个 class 去读,然后读取第一个 sheet 文件流会自动关闭
    EasyExcel.read(fileName, PersonData.class, new ReadListener<PersonData>() {
        /**
        * 单次缓存的数据量
        */
        private static final int BATCH_COUNT = 100;
        /**
        * 临时存储
        */
        private List<PersonData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

        @Override
        public void invoke(PersonData data, AnalysisContext context) {
            cachedDataList.add(data);
            if (cachedDataList.size() >= BATCH_COUNT) {
                printData();
                // 存储完成清理 list
                cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            }
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            printData();
        }

        /**
        * 打印数据
        */
        private void printData() {
            for (PersonData personData : cachedDataList) {
                System.out.println(personData);
            }
        }
    }).sheet().doRead();
}


// 要求:JDK8+,EasyExcel since:3.0.0-beta1
// 不用额外写一个 XxxListener,直接用内置 PageReadListener
@Test
public void read() {
    String fileName = "Excel 文件路径";
    // 这里 需要指定读用哪个 class 去读,然后读取第一个 sheet 文件流会自动关闭
    // 这里每次会读取 100 条数据 然后返回过来 直接调用使用数据就行
    EasyExcel.read(fileName, PersonData.class, new PageReadListener<PersonData>(dataList -> {
        dataList.forEach(System.out::println);
    })).sheet().doRead();
}

指定列的下标或者列名

默认情况 EasyExcel 是根据两个规则封装数据:一个是根据 Excel 中列的顺序与对象字段的顺序一致;另一个是根据 Excel 列的的单元格式与对象字段类型匹配。但开发者可以使用注解 @ExcelProperty,指定封装规则。

@Data
public class PersonData {
    @ExcelProperty(index = 1) // 指定读取的下标,下标默认从 0 开始。这里不建议 index 和 name 同时用,要么一个对象只用 index,要么一个对象只用 name 去匹配
    private Long id;
    @ExcelProperty("出生日期") // 指定读取的列名
    private Date birthday;
    @ExcelProperty("姓名") // 指定读取的列名
    private String name;
}

数据转换等异常处理:onException

读取时抛出异常,则代码会停止。若在监听器中重写处理异常的方法,则代码还会正常执行,继续读取其他行的数据。

准备如下 excel 文件。

在这里插入图片描述

编写读取代码。

@Test
public void read() {
    String fileName = "Excel 文件路径";
    EasyExcel.read(fileName, PersonData.class, new ReadListener<PersonData>() {
        /**
        * 单次缓存的数据量
        */
        private static final int BATCH_COUNT = 100;
        /**
        * 临时存储
        */
        private List<PersonData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

        // 读取时出现异常会执行如下方法,并且不导致读取操作终止
        public void onException(Exception exception, AnalysisContext context) {
            // 打印异常
            System.out.println(exception.getMessage());
        }

        @Override
        public void invoke(PersonData data, AnalysisContext context) {
            cachedDataList.add(data);
            if (cachedDataList.size() >= BATCH_COUNT) {
                printData();
                // 存储完成清理 list
                cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            }
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            printData();
        }

        /**
        * 打印数据
        */
        private void printData() {
            for (PersonData personData : cachedDataList) {
                System.out.println(personData);
            }
        }
    })
    .sheet().doRead();
}

读多个 sheet

先准备好如下 Excel 文件。

在这里插入图片描述

编写读取代码。

// 读多个或者全部 sheet,这里注意一个 sheet 不能读取多次,多次读取需要重新读取文件

//----------------------------读取全部 sheet---------
@Test
public void read() {
    String fileName = "Excel 文件路径";
    // 读取全部 sheet
    // PageReadListener 的 doAfterAllAnalysed 会在每个 sheet 读取完毕后调用一次。
    EasyExcel.read(fileName, PersonData.class, new PageReadListener<PersonData>(dataList -> {
        dataList.forEach(System.out::println);
    })).doReadAll();


    
    
    // ---------------------读取指定或者所有 sheet----------------------------
    try (ExcelReader excelReader = EasyExcel.read(fileName).build()) {
        //创建读的工作簿对象
        ReadSheet readSheet1 = EasyExcel.readSheet(0)
                .head(PersonData.class)
                .registerReadListener(new PageReadListener<PersonData>(dataList -> {
                    dataList.forEach(System.out::println);
                }))
                .build();
        
        ReadSheet readSheet2 = EasyExcel.readSheet(1)
                .head(PersonData.class)
                .registerReadListener(new PageReadListener<PersonData>(dataList -> {
                    dataList.forEach(System.out::println);
                }))
                .build();
        // 这里注意 一定要把工作簿一起传进去,不然有个问题就是 03 版的 Excel 会读取多次,浪费性能
        excelReader.read(readSheet1, readSheet2);
    }
}



// --------------------指定读取某个 sheet------------------------------
@Test
public void read() {
    String fileName = "Excel 文件路径";

    EasyExcel.read(fileName, PersonData.class, new PageReadListener<PersonData>(dataList -> {
        dataList.forEach(System.out::println);
    })).sheet(0).doRead();
    EasyExcel.read(fileName, PersonData.class, new PageReadListener<PersonData>(dataList -> {
        dataList.forEach(System.out::println);
    })).sheet(1).doRead();
}

日期、数字或者自定义格式转换

先准备好如下 Excel 文件。

在这里插入图片描述

1、编写自定义转换器。

public class CustomStringStringConverter implements Converter<String> {

    // 支持 Java 的类型 
    @Override
    public Class<?> supportJavaTypeKey() {
        return String.class;
    }

    // 支持 Excel 单元格类型
    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 当读到的数据符合类型,封装的字段也符合类型,按照下面方法转换数据
     * 这么转换,是由开发者在方法中重写
     * @param context
     * @return
     */
    @Override
    public String convertToJavaData(ReadConverterContext<?> context) {
        //context.getReadCellData().getStringValue(): 是原本的数据 
        return "大神:" + context.getReadCellData().getStringValue();
    }

    /**
     * 这里是写的时候会调用
     *  当读到的数据符合类型,封装的字段也符合类型,按照下面方法转换数据
     *  这么转换,是由开发者在方法中重写
     * @return
     */
    @Override
    public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) {
        return new WriteCellData<>(context.getValue());
    }

}

2、通过注解

编写数据类。

@Data
public class PlayerData {
    @ExcelProperty(converter = CustomStringStringConverter.class)//----------->转换器
    private String name;
    @DateTimeFormat("yyyy年MM月dd日")
    private Date birthday;
    private BigDecimal bf;
}

在这里插入图片描述

编写读取代码。

在这里插入图片描述

@Test
public void read() {
    String fileName = "Excel 文件路径";
    // 这里需要指定读用哪个 class 去读,然后读取第一个 sheet 文件流会自动关闭
    // 这里每次会读取 100 条数据 然后返回过来 直接调用使用数据就行
    EasyExcel.read(fileName, PlayerData.class, new PageReadListener<PlayerData>(dataList -> {
        dataList.forEach(System.out::println);
    }))
    // 如果就想单个字段使用请使用 @ExcelProperty 指定 converter
    // .registerConverter(new CustomStringStringConverter())
    .sheet().doRead();
}

指定行读取

默认情况下 EasyExcel 从第 1 行(0 行是列头)读取。把上面测试代码修改如下进行测试。

@Test
public void read() {
    String fileName = "Excel 文件路径";
    EasyExcel.read(fileName, PlayerData.class, new PageReadListener<PlayerData>(dataList -> {
        dataList.forEach(System.out::println);
    }))
    .sheet()
    .headRowNumber(2) // 手动指定从从第 2 行读取
    .doRead();
}

写 Excel

简单写入

修改数据类。

@Data
public class PersonData {
    private Long id;
    private Date birthday;
    private String name;
    private String ignore;
    
    public PersonData() {}

    public PersonData(Long id, Date birthday, String name) {
        this.id = id;
        this.birthday = birthday;
        this.name = name;
    }
}

编写模拟提供数据类。

public class PersonMock {
    public static List<PersonData> data() {
        return Arrays.asList(
            new PersonData(1L, new Date(), "刘备"),
            new PersonData(2L, new Date(), "关羽"),
            new PersonData(3L, new Date(), "张飞"),
            new PersonData(4L, new Date(), "赵云"),
            new PersonData(5L, new Date(), "诸葛亮"),
            new PersonData(6L, new Date(), "黄忠"),
            new PersonData(7L, new Date(), "魏延"),
            new PersonData(8L, new Date(), "庞统"),
            new PersonData(9L, new Date(), "法正"),
            new PersonData(10L, new Date(), "黄权")
        );
    }
}

编写写入代码。

// 注意在数据量不大的情况下可以使用(5000 以内,具体也要看实际情况),数据量大请参照后面重复多次写入
@Test
public void write() {
    // 写法 1,要求:JDK8+,EasyExcel since:3.0.0-beta1
    String fileName = "Excel 文件路径";
    // 这里需要指定写用哪个 class 去写,然后写到第一个 sheet,工作薄名字为模板,然后文件流会自动关闭
    EasyExcel.write(fileName, PersonData.class)
        .sheet("模板")
        .doWrite(PersonMock::data);//这才是真正的写入

    // 写法 2
    // 这里需要指定写用哪个 class 去写
    try (ExcelWriter excelWriter = EasyExcel.write(fileName, PersonData.class).build()) {
        WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
        excelWriter.write(PersonMock::data, writeSheet);
    }
}

效果如下:

在这里插入图片描述

指定写入的列(忽略某个列)

方式 1:修改数据类,使用注解 @ExcelIgnore。

@Data
public class PersonData {
    private Long id;
    private Date birthday;
    private String name;
    /**
     * 忽略这个字段
     */
    // @ExcelIgnore
    private String ignore;

    public PersonData() {}

    public PersonData(Long id, Date birthday, String name) {
        this.id = id;
        this.birthday = birthday;
        this.name = name;
    }
}

效果如下:

在这里插入图片描述

方式 2:修改测试代码。

@Test
public void write() {
    String fileName = "Excel 文件路径";

    Set<String> excludeColumnFieldNames = new HashSet<>();
    excludeColumnFieldNames.add("birthday");

    EasyExcel.write(fileName, PersonData.class)
        .excludeColumnFieldNames(excludeColumnFieldNames) // 指定写入时排除哪些列
        .sheet("模板")
        .doWrite(PersonMock::data);
}

效果如下:

在这里插入图片描述

指定写入时包含哪些列

@Test
public void write() {
    String fileName = "Excel 文件路径";

    Set<String> includeColumnFieldNames = new HashSet<>();
    includeColumnFieldNames.add("id");
    includeColumnFieldNames.add("name");

    EasyExcel.write(fileName, PersonData.class)
        .includeColumnFieldNames(includeColumnFieldNames) // 指定写入时包含哪些列
        .sheet("模板")
        .doWrite(PersonMock::data);
}

效果如下:
在这里插入图片描述

指定写入列名及顺序

修改数据类,使用 @ExcelProperty 注解指定写入时的列名和顺序。

@Data
public class PersonData {
    @ExcelProperty(value = "id", index = 1) // 这个注解可以指定读写时的列名及顺序
    private Long id;
    @ExcelProperty(value = "出生日期", index = 3)
    private Date birthday;
    @ExcelProperty(value = "姓名", index = 2)
    private String name;

    public PersonData() {}

    public PersonData(Long id, Date birthday, String name) {
        this.id = id;
        this.birthday = birthday;
        this.name = name;
    }
}

编写写入代码。

@Test
public void write() {
    String fileName = "Excel 文件路径";
    EasyExcel.write(fileName, PersonData.class)
        .sheet("模板")
        .doWrite(PersonMock::data);
}

效果如下:

在这里插入图片描述

复杂头写入

修改数据类。

@Data
public class PersonData {

    @ExcelProperty({"蜀国", "id"}) // 第一个主列名,第二次级列名
    private Long id;
    @ExcelProperty({"蜀国", "出生日期"})
    private Date birthday;
    @ExcelProperty({"蜀国", "姓名"})
    private String name;

    public PersonData() {}

    public PersonData(Long id, Date birthday, String name) {
        this.id = id;
        this.birthday = birthday;
        this.name = name;
    }
}

编写写入代码。

@Test
public void write() {
    String fileName = "Excel 文件路径";
    EasyExcel.write(fileName, PersonData.class)
        .sheet("模板")
        .doWrite(PersonMock::data);
}

效果如下:

在这里插入图片描述

重复多次写入

支持单个 sheet 多次写入,或者支持写多个 sheet。

往一个 sheet 多次写入,写入代码如下:

@Test
public void write() {
    String fileName = "Excel 文件路径";
    try (ExcelWriter excelWriter = EasyExcel.write(fileName, PersonData.class).build()) {
        // 注意若同一个 sheet 只要创建一次
        WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
        // 调用 2 次写入,实际使用时根据数据库分页的总的页数来
        for (int i = 0; i < 2; i++) {
            // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
            List<PersonData> data = PersonMock.data();
            excelWriter.write(data, writeSheet);
        }
    }
}

效果如下:

在这里插入图片描述

往多个 sheet 写入相同数据

写入代码如下:

@Test
public void write() {
    String fileName = "Excel 文件路径";
    try (ExcelWriter excelWriter = EasyExcel.write(fileName, PersonData.class).build()) {
        for (int i = 0; i < 2; i++) {
            // 每次都要创建 writeSheet,需要指定 sheet 缩影,而且 sheet 名称必须不一样
            WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).build();
            // 写入数据
            excelWriter.write(PersonMock.data(), writeSheet);
        }
    }
}

效果如下:

在这里插入图片描述

往多个 sheet 写入不同数据

修改数据类。

@Data
public class PlayerData {
    private String name;
    private Date birthday;
    private BigDecimal bf;

    public PlayerData() { }

    public PlayerData(String name, Date birthday, BigDecimal bf) {
        this.name = name;
        this.birthday = birthday;
        this.bf = bf;
    }
}

编写模拟提供数据类。

public class PlayerMock {
    public static List<PlayerData> data() {
        return Arrays.asList(
            new PlayerData("C罗", new Date(), new BigDecimal("0.07")),
            new PlayerData("乔丹", new Date(), new BigDecimal("0.03"))
        );
    }
}

编写写入代码。

public void write5() {
    String fileName = "Excel 文件路径";
    try (ExcelWriter excelWriter = EasyExcel.write(fileName).build()) {
        
        // 向第一个 sheet 写入 PersonData 类型的数据
        WriteSheet writeSheet0 = EasyExcel.writerSheet(0, "蜀国")
            .head(PersonData.class) // 设置第一行列标题,列头
            .build();
        excelWriter.write(PersonMock.data(), writeSheet0);

        // 向第二个 sheet 写入 PlayerData 类型的数据
        WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "运动员")
            .head(PlayerData.class) // // 设置第一行列标题
            .build();
        excelWriter.write(PlayerMock.data(), writeSheet1);
    }
}

效果如下:

在这里插入图片描述

日期、数字或者自定义格式转换

编写自定义转换器。

public class CustomStringStringConverter implements Converter<String> {

    @Override
    public Class<?> supportJavaTypeKey() {
        return String.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 这里读的时候会调用:前面有
     *
     * @param context
     * @return
     */
    @Override
    public String convertToJavaData(ReadConverterContext<?> context) {
        return "大神:" + context.getReadCellData().getStringValue();
    }

    /**
     * 这里是写的时候会调用
     *  当读到的数据符合类型,封装的字段也符合类型,按照下面方法转换数据
     *  这么转换,是由开发者在方法中重写
     * @return
     */
    @Override
    public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) {
        return new WriteCellData<>("大神:" + context.getValue());
    }

}

修改数据类,使用注解指定转换格式。

@Data
public class PlayerData {
    @ExcelProperty(converter = CustomStringStringConverter.class)//------------>转换器
    private String name;
    @DateTimeFormat("yyyy年MM月dd日")
    private Date birthday;
    @NumberFormat("#.##%")
    private BigDecimal bf;

    public PlayerData() { }

    public PlayerData(String name, Date birthday, BigDecimal bf) {
        this.name = name;
        this.birthday = birthday;
        this.bf = bf;
    }
}

编写写入的代码。

@Test
public void write() {
    String fileName = "Excel 文件路径";
    EasyExcel.write(fileName, PlayerData.class)
        .sheet("模板")
        .doWrite(PlayerMock::data);
}

效果如下:

在这里插入图片描述

指定列宽行高

修改数据类,使用注解指定列宽、行高。

@Data
@HeadRowHeight(30) // 指定列头行高度
@ContentRowHeight(20) // 指定内容行高度
@ColumnWidth(25) // 指定列宽
public class PlayerData {
    private String name;
    private Date birthday;
    private BigDecimal bf;

    public PlayerData() { }

    public PlayerData(String name, Date birthday, BigDecimal bf) {
        this.name = name;
        this.birthday = birthday;
        this.bf = bf;
    }
}

编写写入的代码。

@Test
public void write() {
    String fileName = "Excel 文件路径";
    EasyExcel.write(fileName, PlayerData.class)
        .sheet("模板")
        .doWrite(PlayerMock::data);
}

效果如下:

在这里插入图片描述

Web 环境导入导出

项目准备

新建 Spring Boot 项目,添加如下依赖:

<properties>
    <java.version>1.8</java.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>easyexcel</artifactId>
        <version>3.1.1</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.47</version>
    </dependency>
</dependencies>

把上面项目的的数据类 PersonData 和提供模拟数据类 PersonMock 拷贝到这个项目。

导出

所谓导出,就把后端数据库中数据,通过网络已 Excel 文件形式下载到客户端。

@GetMapping("/export")
public void exportExcel(HttpServletResponse response) throws IOException {
    response.setHeader("Content-disposition", "attachment;filename=person.xlsx");
    EasyExcel.write(response.getOutputStream(), PersonData.class)
        .sheet("模板")
        .doWrite(PersonMock::data);
}

导入

所谓导入,就把客户端 Excel 文件上传到后端,后端通过代码读取 Excel 文件的数据存入到数据库中。

@PostMapping("/import")
@ResponseBody
public String importExcel(MultipartFile file) throws IOException {
    EasyExcel.read(file.getInputStream(), PersonData.class, new PageReadListener<PersonData>((dataList) -> {
        dataList.forEach(System.out::println);
    }))
    .sheet().doRead();
    return "success";
}

@PostMapping("/import")
@ResponseBody
public String importExcel(MultipartFile file) throws IOException {
    // 同步读取(适合数据量小)
    List<Object> objects = EasyExcel.read(file.getInputStream()).head(PersonData.class).sheet().doReadSync();
    for (Object object : objects) {
        System.out.println(object);
    }
    return "success";
}

其他

ExcelExcel 构建体系

在这里插入图片描述

  • EasyExcel 继承 EasyExcelFactory,只是为给开发者用更短的名字
  • EasyExcelFactory 工厂类,主要用来创建 ExcelReaderBuilder、ExcelReaderSheetBuilder 和 ExcelWriterBuilder、ExcelWriterSheetBuilder 对象。
  • ExcelReaderBuilder,应用了 Bulider Pattern 模式,用来按照步骤一步步构建 ExcelReader 对象,也可以用来创建 ExcelReaderSheetBuilder 对象。
  • ExcelReaderSheetBuilder,用来调用 ExcelReader 对象中方法。
  • ExcelReader,用来对 Excel 文件进行读取操作。
  • ExcelWriterBuilder,应用了 Bulider Pattern 模式,用来按照步骤一步步构建 ExcelWriter 对象,也可以用来创建 ExcelWriterSheetBuilder 对象。
  • ExcelWriterSheetBuilder,用来调用 ExcelWriter 对象中方法。
  • ExcelWriter,用来对 Excel 文件进行写入操作。

Listener 体系

在这里插入图片描述

  • Listener 接口,里面没有任何方法。
  • ReadListener 接口,我们在使用 EasyExcel API 读取 excel 文件内容时,需要使用到这个类型的对象,并根据需求重写其中两个方法:
    • void invoke(T data, AnalysisContext context),每一条数据解析都会来调用这个方法;
    • void doAfterAllAnalysed(AnalysisContext context),所有数据解析完成了会来调用这个方法。
  • PageReadListener 接口,是对上面接口改造成 lambda 风格,让开发者使用便捷。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C# WPF ListBox 动态显示图片

前言 最近在和其他软件联合做一个本地图片选择传输功能&#xff0c;为此希望图片能够有序的呈现在客户端&#xff0c;简单的实现了一下功能&#xff0c;通过Mvvm模式进行呈现&#xff0c;过程简单通俗&#xff0c;话不多说直接上图。 处理过程 前台代码 你只需要粘贴到你的前台…

SQL - 开窗(窗口)函数

什么是开窗函数&#xff1f; 开窗函数对一组值进行操作&#xff0c;它不像普通聚合函数那样需要使用GROUP BY子句对数据进行分组&#xff0c;能够在同一行中同时返回基础行的列和聚合列 开窗函数的语法形式为&#xff1a;函数 over(partition by <分组用列> order by …

数据结构与算法:计算机科学的基石

文章目录 数据结构&#xff1a;构建数据的框架算法&#xff1a;问题的解决方案编程语言&#xff1a;实现数据结构的工具结论 &#x1f389;欢迎来到数据结构学习专栏~数据结构与算法&#xff1a;计算机科学的基石 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&…

Linux的基础指令

目录 1、ls指令 .和..意义 2、pwd指令 3、cd指令 ①cd ~ ②cd - 关于cd ..的用法 绝对路径和相对路径 4、touch指令 5、mkdir指令 tree指令 6、rmdir指令 7、rm指令 * 8、man指令 9、cp指令 nano&#xff1a; 10、mv指令 11、cat指令 12、more指令 13、less…

PCL 三维点云边界提取(C++详细过程版)

边界提取 一、概述二、代码实现三、结果展示本文由CSDN点云侠原创,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、概述 点云边界提取在PCL里有现成的调用函数,具体算法原理和实现代码见:PCL 点云边界提取。为充分了解pcl::BoundaryEsti…

最新ai系统ChatGPT程序源码+详细搭建教程+mj以图生图+Dall-E2绘画+支持GPT4+AI绘画+H5端+Prompt知识库

目录 一、前言 二、系统演示 三、功能模块 3.1 GPT模型提问 3.2 应用工作台 3.3 Midjourney专业绘画 3.4 mind思维导图 四、源码系统 4.1 前台演示站点 4.2 SparkAi源码下载 4.3 SparkAi系统文档 五、详细搭建教程 5.1 基础env环境配置 5.2 env.env文件配置 六、环境…

欧拉计划45题

Triangular, pentagonal, and hexagonal Triangle, pentagonal, and hexagonal numbers are generated by the following formulae: Triangle 1,3,6,10,15,… Pentagonal 1,5,12,22,35,… Hexagonal 1,6,15,28,45,… It can be verified…

性能比较 - Spring Boot 应用程序中的线程池与虚拟线程 (Project Loom)

本文比较了 Spring Boot 应用程序中的不同请求处理方法&#xff1a;ThreadPool、WebFlux、协程和虚拟线程 (Project Loom)。 在本文中&#xff0c;我们将简要描述并粗略比较可在 Spring Boot 应用程序中使用的各种请求处理方法的性能。 高效的请求处理在开发高性能后端…

镜像底层原理详解和基于Docker file创建镜像

目录 一、镜像底层原理 1.联合文件系统(UnionFS) 2.镜像加载原理 3.为什么Docker里的centos的大小才200M? 二、Dockerfile 1.简介 2.Dockerfile操作常用命令 &#xff08;1&#xff09;FORM 镜像 &#xff08;2&#xff09;MAINTAINER 维护人信息 &#xff08;3&…

电商系统架构设计系列(九):如何规划和设计分库分表?

上篇文章中&#xff0c;我给你留了一个思考题&#xff1a;分库分表该如何设计&#xff1f; 今天这篇文章&#xff0c;我们来聊一下如何规划和设计分库分表&#xff0c;以及要考虑哪些问题。 引言 当要解决海量数据的问题&#xff0c;就必须要用到分布式的存储集群了&#xff…

2023.8 - java - 泛型

泛型问题的引出&#xff1a; jdk 1.5 引出泛型 // package 泛型; public class index {public static void main (String[] args){test t new test();t.setContent("aaa");int a (int) t.getContent();System.out.println(a);} }class test{Object content;publi…

RNN+LSTM正弦sin信号预测 完整代码数据视频教程

视频讲解:RNN+LSTM正弦sin信号预测_哔哩哔哩_bilibili 效果演示: 数据展示: 完整代码: import torch import torch.nn as nn import torch.optim as optim import numpy as np import matplotlib.pyplot as plt import pandas as pd from sklearn.preprocessing import…

1.jvm和java体系结构

jvm简介 JVM&#xff1a;跨语言的平台 Java是目前应用最为广泛的软件开发平台之一。随着Java以及Java社区的不断壮大Java 也早已不再是简简单单的一门计算机语言了&#xff0c;它更是一个平台、一种文化、一个社区。 ● 作为一个平台&#xff0c;Java虚拟机扮演着举足轻重的…

无涯教程-Perl - use函数

描述 此函数将MODULE导出的所有功能(或仅LIST引用的功能)导入当前包的名称空间。有效等效于- BEGIN { require "Module.pm"; Module->import(); }也用于在当前脚本上强加编译器指令(编译指示),尽管从本质上讲它们只是模块。 请注意,use语句在编译时进行判断。在…

SpringBoot 模板模式实现优惠券逻辑

一、计算逻辑的类结构图 在这张图里&#xff0c;顶层接口 RuleTemplate 定义了 calculate 方法&#xff0c;抽象模板类 AbstractRuleTemplate 将通用的模板计算逻辑在 calculate 方法中实现&#xff0c;同时它还定义了一个抽象方法 calculateNewPrice 作为子类的扩展点。各个具…

三子棋游戏

目录 主函数test.c 菜单函数 选择实现 游戏函数 &#xff08;函数调用&#xff09; 打印棋盘数据 打印展示棋盘 玩家下棋 电脑下棋 判断输赢 循环 test.c总代码 头文件&函数声明game.h 头文件的包含 游戏符号声明 游戏函数声明 game.h总代码 游戏函数ga…

spring异步框架使用教程

背景 在需求开发过程中&#xff0c;为了提升效率&#xff0c;很容易就会遇到需要使用多线程的场景。这个时候一般都会选择建一个线程池去专门用来进行某一类动作&#xff0c;这种任务到来的时候往往伴随着大量的线程被创建调用。而还有另外一种场景是整个任务的执行耗时比较长…

Sui第四轮资助:16个团队瓜分

近日&#xff0c;Sui基金会公布了第四轮开发者资助名单&#xff0c;受助项目均是集中在DeFi、支付、基础设施、游戏、预言机等领域的Sui生态项目&#xff0c;他们是从2023年7月1日之前提交的申请中选出的。在此时间之后提交的任何项目目前正在审查中。 在前三轮资助中累积发放…

Linux Kernel 4.12 或将新增优化分析工具

到 7 月初&#xff0c;Linux Kernel 4.12 预计将为修复所有安全漏洞而奠定基础&#xff0c;另外新增的是一个分析工具&#xff0c;对于开发者优化启动时间时会有所帮助。 新的「个别任务统一模型」&#xff08;Per-Task Consistency Model&#xff09;为主要核心实时修补&#…

LinkedList

LinkedList的模拟实现&#xff08;底层是一个双向链表&#xff09;LinkedList使用 LinkedList的模拟实现&#xff08;底层是一个双向链表&#xff09; 无头双向链表&#xff1a;有两个指针&#xff1b;一个指向前一个节点的地址&#xff1b;一个指向后一个节点的地址。 节点定…