EasyExcel快速入门使用

详情查看easyExcel官方

一、Mavem配置

<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.6</version>
</dependency>

二、EasyExcel的写操作

1、写入方式一

javabean

/**
 * 这里使用了lombok和validation简化javabean代码
 */
@Data   /* setter/getter */
@NoArgsConstructor  /* 无参构造器 */
@AllArgsConstructor     /* 全参构造器 */
public class Student {
    
    
	//使用@ExcelProperty注解来为生成的Excel设置标头
    @ExcelProperty("姓名")
    private String name;
    @ExcelProperty("年龄")
    private Integer age;
    @ExcelProperty("详情")
    private String details;
    @ExcelProperty("学号")
    private Integer sno;
    @DateTimeFormat("yyyy-MM-dd")
    @ExcelProperty("创建时间")
    private Date createTime;

}

运行代码

    /**
     * 写入方式一
     */
    @Test
    public void test01(){
    
    
        //创建文件保存位置,以及文件名
        String filename = "src/main/resources/test01.xlsx";
		//添加模型数据
        List<Student> stus = new ArrayList<Student>();
        stus.add(new Student("zhangsan",11,"hahaha",202101,new Date()));
        stus.add(new Student("zhangsan",12,"saaa",202102,new Date()));
        stus.add(new Student("zhangsan",13,"hahaha",202103,new Date()));
        stus.add(new Student("zhangsan",14,"hahaha",202104,new Date()));
        stus.add(new Student("zhangsan",10,"hahaha",202105,new Date()));
        
        //将list中的数据写入excel中的第一个sheet中,这种方式文件流会自动关闭
        EasyExcel.write(filename,Student.class).sheet("学生信息").doWrite(stus);

    }

运行效果
在这里插入图片描述

2、写入方式二

运行代码

    /**
     * 写入方式二
     */
    @Test
    public void test02(){
    
    
        //创建文件保存位置,以及文件名
        String filename = "src/main/resources/test02.xlsx";

        List<Student> stus = new ArrayList<Student>();
        stus.add(new Student("zhangsan",11,"hahaha",202101,new Date()));
        stus.add(new Student("zhangsan",12,"saaa",202102,new Date()));
        stus.add(new Student("zhangsan",13,"hahaha",202103,new Date()));
        stus.add(new Student("zhangsan",14,"hahaha",202104,new Date()));
        stus.add(new Student("zhangsan",10,"hahaha",202105,new Date()));

        //创建Excel写入对象
        ExcelWriter writer = EasyExcel.write(filename,Student.class).build();
        //创建Sheet对象一个sheet对象就是一张sheet工作簿
        WriteSheet writeSheet = EasyExcel.writerSheet("学生信息").build();
        //将工作表写入到Excel中
        writer.write(stus,writeSheet);
        //关闭
        writer.finish();

    }

运行效果
在这里插入图片描述

3、排除属性字段

    /**
     * 排除字段
     */
    @Test
    public void test03(){
    
    
        //创建文件保存位置,以及文件名
        String filename = "src/main/resources/test03.xlsx";

        List<Student> stus = new ArrayList<Student>();
        stus.add(new Student("zhangsan",11,"hahaha",202101,new Date()));
        stus.add(new Student("zhangsan",12,"saaa",202102,new Date()));
        stus.add(new Student("zhangsan",13,"hahaha",202103,new Date()));
        stus.add(new Student("zhangsan",14,"hahaha",202104,new Date()));
        stus.add(new Student("zhangsan",10,"hahaha",202105,new Date()));
        //设置排除属性字段
        Set<String> set = new HashSet<String>();
        set.add("details");
        //排除属性字段
        EasyExcel.write(filename,Student.class).excludeColumnFiledNames(set)
                .sheet("用户信息").doWrite(stus);

    }

运行结果
在这里插入图片描述

4、包含属性字段

    /**
     * 排除字段
     */
    @Test
    public void test04(){
    
    
        //创建文件保存位置,以及文件名
        String filename = "src/main/resources/test04.xlsx";

        List<Student> stus = new ArrayList<Student>();
        stus.add(new Student("zhangsan",11,"hahaha",202101,new Date()));
        stus.add(new Student("zhangsan",12,"saaa",202102,new Date()));
        stus.add(new Student("zhangsan",13,"hahaha",202103,new Date()));
        stus.add(new Student("zhangsan",14,"hahaha",202104,new Date()));
        stus.add(new Student("zhangsan",10,"hahaha",202105,new Date()));

        //设置包含属性字段
        Set<String> set = new HashSet<String>();
        set.add("name");
        set.add("age");

        //包含属性字段
        EasyExcel.write(filename,Student.class).includeColumnFiledNames(set)
                .sheet("用户信息").doWrite(stus);
    }

运行效果
在这里插入图片描述

5、设置列的顺序

运行写入方式

通过设置@ExcelProperty的index来设置字段所在的列

/**
 * 这里使用了lombok简化javabean代码
 */
@Data   /* setter/getter */
@NoArgsConstructor  /* 无参构造器 */
@AllArgsConstructor     /* 全参构造器 */
public class Student {
    
    
    //通过设置index来设置字段所在的列
    @ExcelProperty(value = "姓名",index = 1)
    private String name;
    @ExcelProperty(value = "年龄",index = 2)
    private Integer age;
    @ExcelProperty(value = "详情",index = 4)
    private String details;
    @ExcelProperty(value = "学号",index = 3)
    private Integer sno;
    @DateTimeFormat("yyyy-MM-dd")
    @ExcelProperty(value = "创建时间",index = 5)
    private Date createTime;

}

运行效果
在这里插入图片描述

6、设置复杂头

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher {
    
    
	//复杂头设置
    @ExcelProperty({
    
    "教师汇总","姓名"})
    private String name;
    @ExcelProperty({
    
    "教师汇总","年龄"})
    private Integer age;
    @ExcelProperty({
    
    "教师汇总","详情"})
    private String details;
    @ExcelProperty({
    
    "教师汇总","课程"})
    private String course;
    @ExcelProperty({
    
    "教师汇总","日期"})
    @DateTimeFormat("yyyy-MM-dd")
    private Date date;
}

运行代码

    @Test
    public void test06(){
    
    
        //创建文件保存位置,以及文件名
        String filename = "src/main/resources/test06.xlsx";

        List<Teacher> teachers = new ArrayList<Teacher>();
        teachers.add(new Teacher("zhaoliu",34,"nihao","yuwen",new Date()));
        teachers.add(new Teacher("zhaoliu",34,"nihao","shuxue",new Date()));
        teachers.add(new Teacher("zhaoliu",24,"nihao","yingyu",new Date()));
        teachers.add(new Teacher("zhaoliu",66,"nihao","yingyue",new Date()));
        teachers.add(new Teacher("zhaoliu",53,"nihao","yuwen",new Date()));
        teachers.add(new Teacher("zhaoliu",54,"nihao","yuwen",new Date()));

        //将list中的数据写入excel中的第一个sheet中,这种方式文件流会自动关闭
        EasyExcel.write(filename,Teacher.class).sheet("老师信息").doWrite(teachers);
    }

运行效果
在这里插入图片描述

7、图片导入

5种方式

@Data
@NoArgsConstructor
public class ImageData {
    
    
    private File file;
    private InputStream inputStream;
    /**
     * 如果string类型 必须指定转换器,string默认转换成string
     */
    @ExcelProperty(converter = StringImageConverter.class)
    private String string;
    private byte[] byteArray;
    /**
     * 根据url导出
     */
    private URL url;
}

运行代码

    /**
     * 图片导出
     * 1. 创建excel对应的实体对象 参照{@link ImageData}
     * 2. 直接写即可
     */
    @Test
    public void imageWrite() throws Exception {
    
    
        String fileName = "src/main/resources/test07.xlsx";
        // 如果使用流 记得关闭
        InputStream inputStream = null;
        try {
    
    
            List<ImageData> list = new ArrayList<ImageData>();
            ImageData imageData = new ImageData();
            list.add(imageData);
            String imagePath = "src/main/resources/test.png";
            // 放入五种类型的图片 实际使用只要选一种即可
            //1、将图片以二进制数组的形式存入对象
            imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath)));
            //2、以文件的形式存入对象
            imageData.setFile(new File(imagePath));
            //3、以字符串的形式存入对象(会通过StringImageConverter将图片转换为字符串)
            imageData.setString(imagePath);
            //4、通过流的方式存入对象
            inputStream = FileUtils.openInputStream(new File(imagePath));
            imageData.setInputStream(inputStream);
            //5、通过URL的方式存入对象
            imageData.setUrl(new URL(
                    "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2853553659,1775735885&fm=26&gp=0.jpg"));
            EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list);
        } finally {
    
    
            if (inputStream != null) {
    
    
                inputStream.close();
            }
        }
    }

运行效果

在这里插入图片描述

8、设置标题内容列宽

使用以下三个注解来设置

//注解在类或方法上都可
@HeadRowHeight(30) //设置标题高度
@ContentRowHeight(100) //设置内容高度
@ColumnWidth(50) //设置列宽

用7的案例

运行效果(注释在类上)

在这里插入图片描述

9、设置样式

方式一:用注解

使用写入方式一运行

在Studnet类上使用这些注解
类和方法都可以注释

//类和方法都可以注释
//标题样式设置                字体样式                           背景样式 LEMON_CHIFFON(26),
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND,fillForegroundColor = 26)
//设置标题字体 大小
@HeadFontStyle(fontHeightInPoints = 40)
//内容样式设置                字体样式                           背景样式 IndexedColors SKY_BLUE(40)
@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND,fillForegroundColor = 40)
//设置内容字体        大小
@ContentFontStyle(fontHeightInPoints = 20)

运行效果

在这里插入图片描述

方式二

运行方法

    /**
     * 自定义样式
     * <p>1. 创建excel对应的实体对象 参照{@link DemoData}
     * <p>2. 创建一个style策略 并注册
     * <p>3. 直接写即可
     */
    @Test
    public void styleWrite() {
    
    
        String fileName = "src/main/resources/test08.xlsx";
        // 头的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 背景设置为红色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
        //字体默认设置
        WriteFont headWriteFont = new WriteFont();
        //设置头部字体大小
        headWriteFont.setFontHeightInPoints((short)20);
        //通过字体的其他默认设置来设置头部字体
        headWriteCellStyle.setWriteFont(headWriteFont);
        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
        contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
        // 背景绿色
        contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());
        WriteFont contentWriteFont = new WriteFont();
        // 字体大小
        contentWriteFont.setFontHeightInPoints((short)20);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
        HorizontalCellStyleStrategy horizontalCellStyleStrategy =
                new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

        List<Teacher> teachers = new ArrayList<Teacher>();
        teachers.add(new Teacher("zhaoliu",34,"nihao","yuwen",new Date()));
        teachers.add(new Teacher("zhaoliu",34,"nihao","shuxue",new Date()));
        teachers.add(new Teacher("zhaoliu",24,"nihao","yingyu",new Date()));
        teachers.add(new Teacher("zhaoliu",66,"nihao","yingyue",new Date()));
        teachers.add(new Teacher("zhaoliu",53,"nihao","yuwen",new Date()));
        teachers.add(new Teacher("zhaoliu",54,"nihao","yuwen",new Date()));

        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        EasyExcel.write(fileName, Teacher.class).registerWriteHandler(horizontalCellStyleStrategy).sheet("模板")
                .doWrite(teachers);
    }

运行效果
在这里插入图片描述

10、合并单元格

javabean

@Data
@NoArgsConstructor
@AllArgsConstructor
//合并行索引为1-3列索引为1-3的单元格
@OnceAbsoluteMerge(firstRowIndex = 1,lastRowIndex = 3,firstColumnIndex = 1,lastColumnIndex = 3)
public class MergeCell {
    
    
    @ExcelProperty("单元格名字")
    @ContentLoopMerge(eachRow = 2) //合并列
    private String cellName;
    @ExcelProperty("长")
    private Integer width;
    @ExcelProperty("宽")
    private Integer heigth;
}

运行代码

    @Test
    public void test09(){
    
    
        //创建文件保存位置,以及文件名
        String filename = "src/main/resources/test09.xlsx";

        List<MergeCell> mergeCells = new ArrayList<MergeCell>();
        mergeCells.add(new MergeCell("cell1",17,15));
        mergeCells.add(new MergeCell("cell2",16,16));
        mergeCells.add(new MergeCell("cell3",15,17));
        mergeCells.add(new MergeCell("cell4",14,18));
        mergeCells.add(new MergeCell("cell5",13,19));
        mergeCells.add(new MergeCell("cell6",12,20));

        EasyExcel.write(filename,MergeCell.class).sheet("test01").doWrite(mergeCells);

    }

运行效果

在这里插入图片描述

三、EasyExcel的写操作

1、简单读取操作

运行代码

    @Test
    public void testRead01(){
    
    
        String fileName = "src/main/resources/test11.xlsx";
        //实现AnalysisEventListener监听器
        EasyExcel.read(fileName, new AnalysisEventListener<User>() {
    
    
            //每读取一行,执行一次
            public void invoke(User user, AnalysisContext analysisContext) {
    
    
                System.out.println("读取到的数据:"+user);
            }
            //读取完后运行
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    
    
                System.out.println("执行完毕");
            }
        }).sheet("用户表").doRead();
    }

要读取的内容
在这里插入图片描述
运行结果
在这里插入图片描述

2、指定列名和下标

同写入下标指定方式点击既达

3、自定义格式转换

自定义格式转换器

/**
 * 配置自定义转换器实现 Converter接口
 */
public class CustomStringStringConverter implements Converter<String> {
    
    
    public Class supportJavaTypeKey() {
    
    
        return String.class;
    }
    public CellDataTypeEnum supportExcelTypeKey() {
    
    
        return CellDataTypeEnum.STRING;
    }
    /**
     * 这里读的时候会调用
     */
    public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
                                    GlobalConfiguration globalConfiguration) {
    
    
        return "自定义:" + cellData.getStringValue();
    }
    /**
     * 这里是写的时候会调用 不用管
     */
    public CellData convertToExcelData(String value, ExcelContentProperty contentProperty,
                                       GlobalConfiguration globalConfiguration) {
    
    
        return new CellData(value);
    }
}

java对象

@Data
public class ConverterData {
    
    
    /**
     * 可以通过converter属性设置自定义转换器。为该属性值前加上”自定义“
     */
    @ExcelProperty(converter = CustomStringStringConverter.class)
    private String string;
    /**
     * 这里用string 去接日期才能格式化。我想接收年月日格式
     */
    @DateTimeFormat("yyyy年MM月dd日")
    private String date;
    /**
     * 我想接收百分比的数字
     */
    @NumberFormat("#.##%")
    private String doubleData;
}

运行方法

    /**
     * 日期、数字或者自定义格式转换
     * <p>
     * 默认读的转换器{@link DefaultConverterLoader#loadDefaultReadConverter()}
     * <p>1. 创建excel对应的实体对象 参照{@link ConverterData}.里面可以使用注解{@link DateTimeFormat}、{@link NumberFormat}或者自定义注解
     * <p>2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link ConverterDataListener}
     * <p>3. 直接读即可
     */
    @Test
    public void converterRead() {
    
    
        String fileName = "src/main/resources/test12.xlsx";
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet
        EasyExcel.read(fileName, ConverterData.class, new AnalysisEventListener<ConverterData>() {
    
    
            public void invoke(ConverterData data, AnalysisContext context) {
    
    
                System.out.println("获取数据:"+data);
            }

            public void doAfterAllAnalysed(AnalysisContext context) {
    
    
                System.out.println("数据获取完毕");
            }
        })
                // 这里注意 我们也可以registerConverter来指定自定义转换器, 但是这个转换变成全局了, 所有java为string,excel为string的都会用这个转换器。
                // 如果就想单个字段使用请使用@ExcelProperty 指定converter
                // .registerConverter(new CustomStringStringConverter())
                // 读取sheet
                .sheet().doRead();
    }

读取内容
在这里插入图片描述

运行效果
在这里插入图片描述

4、多头行读取

.headRowNumber(2)
运行方法

    @Test
    public void test12(){
    
    
        String fileName = "src/main/resources/test06.xlsx";
        EasyExcel.read(fileName, Teacher.class, new AnalysisEventListener<Teacher>() {
    
    
            public void invoke(Teacher teacher, AnalysisContext context) {
    
    
                System.out.println("获取数据:"+teacher);
            }

            public void doAfterAllAnalysed(AnalysisContext context) {
    
    
                System.out.println("数据获取完毕");
            }
        }).sheet("老师信息")
                // 这里可以设置1,因为头就是一行。如果多行头,可以设置其他值。不传入也可以,因为默认会根据DemoData 来解析,他没有指定头,也就是默认1行
                .headRowNumber(2).doRead();
    }

读取内容
在这里插入图片描述
运行效果
在这里插入图片描述

四、模板填充

1、单个填充

javabean

@Data
public class FillData {
    
    
    @ExcelProperty("姓名")
    private String name;
    @ExcelProperty("数字")
    private double number;
}

模板
在这里插入图片描述
运行方法

    /**
     * 最简单的填充
     *
     */
    @Test
    public void simpleFill() {
    
    
        // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
        // 模板中的变量要与javabean中的一致
        String templateFileName = "src/main/resources/model.xlsx";

        // 方案1 根据对象填充
        String fileName = "src/main/resources/test13.xlsx";
        // 这里 会填充到第一个sheet, 然后文件流会自动关闭
        FillData fillData = new FillData();
        fillData.setName("张三");
        fillData.setNumber(5.2);
        // doFill方法中传入填充数据
        EasyExcel.write(fileName,FillData.class).withTemplate(templateFileName).sheet().doFill(fillData);

        // 方案2 根据Map填充
        fileName = "src/main/resources/test14.xlsx";
        // 这里 会填充到第一个sheet, 然后文件流会自动关闭
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("name", "张三");
        map.put("number", 5.2);
        EasyExcel.write(fileName,FillData.class).withTemplate(templateFileName).sheet().doFill(map);
    }

运行结果
在这里插入图片描述

2、列表填充

运行方法

    /**
     * 填充列表
     *
     * @since 2.1.1
     */
    @Test
    public void listFill() {
    
    
        // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
        // 填充list 的时候还要注意 模板中{.} 多了个点 表示list
        String templateFileName = "src/main/resources/model2.xlsx";

        // 方案1 一下子全部放到内存里面 并填充
        String fileName = "src/main/resources/test15.xlsx";

        List<FillData> data = new ArrayList<FillData>();
        data.add(new FillData("zhangsan",11));
        data.add(new FillData("zhangsan",12));
        data.add(new FillData("zhangsan",13));
        data.add(new FillData("zhangsan",14));
        data.add(new FillData("zhangsan",15));
        // 这里 会填充到第一个sheet, 然后文件流会自动关闭
        EasyExcel.write(fileName,FillData.class).withTemplate(templateFileName).sheet().doFill(data);

        // 方案2 分多次 填充 会使用文件缓存(省内存)
        fileName = "src/main/resources/test13.xlsx";
        ExcelWriter excelWriter = EasyExcel.write(fileName,FillData.class).withTemplate(templateFileName).build();
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        excelWriter.fill(data, writeSheet);
        excelWriter.fill(data, writeSheet);
        // 千万别忘记关闭流
        excelWriter.finish();
    }

模板

在这里插入图片描述

运行结果

在这里插入图片描述

3、复杂填充

运行方法

    /**
     * 复杂的填充
     *
     * @since 2.1.1
     */
    @Test
    public void complexFill() {
    
    
        // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
        // {} 代表普通变量 {.} 代表是list的变量
        String templateFileName = "src/main/resources/model3.xlsx";

        String fileName = "src/main/resources/test16.xlsx";
        ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build();
        WriteSheet writeSheet = EasyExcel.writerSheet().build();

        List<FillData> data = new ArrayList<FillData>();
        data.add(new FillData("zhangsan",11));
        data.add(new FillData("zhangsan",12));
        data.add(new FillData("zhangsan",13));
        data.add(new FillData("zhangsan",14));
        data.add(new FillData("zhangsan",15));

        // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行,然后下面的数据往后移动。默认 是false,会直接使用下一行,如果没有则创建。
        // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了,所以慎用
        // 简单的说 如果你的模板有list,且list不是最后一行,下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存
        // 如果数据量大 list不是最后一行 参照下一个
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        excelWriter.fill(data, fillConfig, writeSheet);
        excelWriter.fill(data, fillConfig, writeSheet);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("date", "2019年10月9日13:28:28");
        map.put("total", 1000);
        excelWriter.fill(map, writeSheet);
        excelWriter.finish();
    }

模板

在这里插入图片描述

运行结果

在这里插入图片描述

4、横向填充

运行方法

    /**
     * 横向的填充
     *
     * @since 2.1.1
     */
    @Test
    public void horizontalFill() {
    
    
        // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
        // {} 代表普通变量 {.} 代表是list的变量
        String templateFileName = "src/main/resources/model4.xlsx";

        String fileName = "src/main/resources/test17.xlsx";
        ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build();
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        //通过FillConfig配置横向填充
        FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();

        List<FillData> data = new ArrayList<FillData>();
        data.add(new FillData("zhangsan",11));
        data.add(new FillData("zhangsan",12));
        data.add(new FillData("zhangsan",13));
        data.add(new FillData("zhangsan",14));
        data.add(new FillData("zhangsan",15));

        excelWriter.fill(data, fillConfig, writeSheet);
        excelWriter.fill(data, fillConfig, writeSheet);

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("date", "2019年10月9日13:28:28");
        excelWriter.fill(map, writeSheet);

        // 别忘记关闭流
        excelWriter.finish();
    }

模板

在这里插入图片描述
运行效果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/magicproblem/article/details/112798820