SpringBoot最简单好用的导出导入功能,拿来即用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


拿来吧你

提示:粘贴即可用

SpringBoot 项目整合的导入导出接口。


一、接口说明

项目pom.xml 文件添加依赖,编写封装类即可。依赖、导入导出的封装类以及使用方法,以下文章都会一一列举,十分方便,已经经过测试,复制粘贴用起来吧。

二、依赖

提示:这里给的是关于导出导出的依赖。

代码如下(示例):


	 <!--实体类属性注解-->
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>javax.persistence-api</artifactId>
            <version>2.2</version>
        </dependency>

        <!--导出导入-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.1.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
        <!--JSON-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.21</version>
        </dependency>


三、导出工具类

提示: 复制即可用

exportData()方法有三个参数:

  1. response :请求接口浏览器直接新开窗口下载导出的文件
  2. List dataList : 用户数据,比如导出User表数据,那么将从数据库查询的用户数据作为这第二个参数
  3. Class EntityClass : 实体类字节码,导出工具类直接根据实体类的字段和数据库的字段一一映射,将User.class作为这第三个参数。

代码如下(示例):

import org.apache.poi.ss.usermodel.*;

import javax.persistence.Column;
import javax.persistence.Table;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

public class ExportUtils {

    public static <T> void exportData(HttpServletResponse response, List<T> dataList, Class<T> EntityClass) throws IOException {
        // 创建Excel工作簿
        Workbook workbook = WorkbookFactory.create(true);

        // 创建工作表
//        Sheet sheet = workbook.createSheet("数据表");
        Sheet sheet = workbook.createSheet(EntityClass.getSimpleName());

        // 设置标题行的字体样式
        Font font = workbook.createFont();
        font.setBold(true); // 将字体设置为加粗样式

        // 获取表名
        Table tableAnnotation = EntityClass.getAnnotation(Table.class);
//        String tableName = EntityClass.getSimpleName(); // 获取的是UserDO(类的名字)
        String tableName = "data";
        if (tableAnnotation != null) {
            tableName = tableAnnotation.name();
        }

        /**
         *    创建标题行
         * 1. 要根据实体类的 @Column(name = "姓名") 注解中的 name 值来设置标题行,
         * 2. 你可以通过反射获取实体类的字段名称。
         * 3. 可以使用 Class.getDeclaredFields() 方法来获取所有的字段,
         * 4. 然后使用 Field.getAnnotation() 方法获取 @Column 注解,最后通过 name() 方法获取注解中设置的名称。
         */
        Row headerRow = sheet.createRow(0);
        Field[] fields = EntityClass.getDeclaredFields();

        // 数据不为空,写数据,为空,下载模板,模板无序号
        int columnIndex = 0;
        for (Field field : fields) {
            Column columnAnnotation = field.getAnnotation(Column.class);
            if (columnAnnotation != null) {
                String columnName = columnAnnotation.name();
                
                // 排除id、createTime、updateTime、isDeleted等属性的导出
                if (Objects.isNull(dataList)) {
                    if (!("id".equals(field.getName()) || "createTime".equals(field.getName())
                            || "updateTime".equals(field.getName()) || "status".equals(field.getName())
                            || "isDeleted".equals(field.getName()) || "icon".equals(field.getName()) )) {
                        Cell headerCell = headerRow.createCell(columnIndex);
                        headerCell.setCellValue(columnName);

                        // 应用字体样式到标题单元格
                        CellStyle cellStyle = workbook.createCellStyle();
                        cellStyle.setFont(font);
                        headerCell.setCellStyle(cellStyle);

                        columnIndex++;
                    }
                } else {

                        Cell headerCell = headerRow.createCell(columnIndex);
                        headerCell.setCellValue(columnName);

                        // 应用字体样式到标题单元格
                        CellStyle cellStyle = workbook.createCellStyle();
                        cellStyle.setFont(font);
                        headerCell.setCellStyle(cellStyle);

                        columnIndex++;

                }
            }
        }
        /**
         * 1. 可以使用反射获取实体类的字段数量,
         * 2. 然后在循环中根据字段数来创建单元格
         */
        // 数据不为空-填充数据到Excel表格
        // 数据为空,下载模板
        if (Objects.nonNull(dataList)) {
            int rowNumber = 1;
            for (T data : dataList) {
                Row row = sheet.createRow(rowNumber);

                for (int i = 0; i < fields.length; i++) {
                    Field field = fields[i];
                    Column columnAnnotation = field.getAnnotation(Column.class);
                    if (columnAnnotation != null) {
                        Cell cell = row.createCell(i);
                        setCellValue(cell, data, field);
                    }
                }

                rowNumber++;
            }
        }

        // 设置响应头信息
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("UTF-8");

        String encodedTableName = URLEncoder.encode(tableName, "UTF-8");
        String filename = encodedTableName + ".xlsx";
        response.setHeader("Content-Disposition", "attachment; filename=" + filename);

        // 将Excel写入响应输出流
        workbook.write(response.getOutputStream());

        // 关闭工作簿
        workbook.close();
    }

    // 调用方法 setCellValue() 在 setCellValue() 方法中根据字段的类型来设置单元格的值
    private static <T> void setCellValue(Cell cell, T data, Field field) {
        field.setAccessible(true);
        try {
            Object value = field.get(data);

            // 根据属性的类型来设置单元格的值
            if (value instanceof Integer) {
                cell.setCellValue((Integer) value);
            } else if (value instanceof String) {
                cell.setCellValue((String) value);
            } else if (value instanceof Boolean) {
                cell.setCellValue((Boolean) value);
            } else if (value instanceof Date) {
                DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH);
                DateTimeFormatter targetFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime dateTime = LocalDateTime.parse(value.toString(), sourceFormatter);
                String convertedTime = dateTime.format(targetFormatter);
                cell.setCellValue(convertedTime);

            } else if (value instanceof Double) {
                cell.setCellValue(value.toString());
            } else {
                // 处理其他类型的值
            }
        } catch (IllegalAccessException e) {
            // 处理异常情况
            e.printStackTrace();
        }
    }
}

四、导入工具类

提示:导入即是上传文件xlsx文件,根据导入的数据转为Java语言,再做其他的操作,比如插入数据库。

参数解析:

  1. MultipartFile file : 上传到导入接口的文件
  2. Class entityClass : 比如是导入User类,则传入 User.class 作为参数


import org.apache.poi.ss.usermodel.*;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.Column;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

public class ImportUtil {

    public static <T> List<T> importEntities(MultipartFile file, Class<T> entityClass) throws Exception {
        // 创建Excel工作簿
        Workbook workbook = WorkbookFactory.create(file.getInputStream());

        // 获取第一个工作表
        Sheet sheet = workbook.getSheetAt(0);

        // 获取标题行的列名
        Row titleRow = sheet.getRow(0);
        List<String> columnNames = getColumnNames(titleRow);

        // 创建实体对象列表
        List<T> entities = new ArrayList<>();

        // 迭代每一行(跳过标题行)
        Iterator<Row> iterator = sheet.iterator();
        iterator.next(); // 跳过标题行
        while (iterator.hasNext()) {
            Row row = iterator.next();

            // 读取单元格数据并创建实体对象
            T entity = createEntityFromRow(row, columnNames, entityClass);
            entities.add(entity);
        }

        // 关闭工作簿
        workbook.close();

        return entities;
    }

    // 获取列名
    private static List<String> getColumnNames(Row row) {
        List<String> columnNames = new ArrayList<>();
        for (Cell cell : row) {
            columnNames.add(getStringCellValue(cell));
        }
        return columnNames;
    }


    // 根据行数据创建实体对象
    // 对
    private static <T> T createEntityFromRow(Row row, List<String> columnNames, Class<T> entityClass) throws Exception {
        T entity = entityClass.getDeclaredConstructor().newInstance();
        Field[] fields = entityClass.getDeclaredFields();

        for (int i = 0; i < columnNames.size(); i++) {
            String columnName = columnNames.get(i);
            String cellValue = getStringCellValue(row.getCell(i));

            for (Field field : fields) {
                field.setAccessible(true);
                Column columnAnnotation = field.getAnnotation(Column.class);
                if (columnAnnotation != null && columnAnnotation.name().equals(columnName)) {
                    setFieldValue(entity, field, cellValue);
                    break;
                }
            }
        }

        return entity;
    }


    // 获取单元格的字符串值
    private static String getStringCellValue(Cell cell) {
        if (cell == null) {
            return null;
        }

        String cellValue;
        // 根据单元格类型进行值转换
        switch (cell.getCellType()) {
            case STRING:
                cellValue = cell.getStringCellValue();
                break;
            case NUMERIC:
                // 判断是否为日期类型
                if (DateUtil.isCellDateFormatted(cell)) {
                    DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    cellValue = sdf.format(cell.getDateCellValue());
                } else {
                    // 将数字类型转换为字符串类型
                    cell.setCellType(CellType.STRING);
                    cellValue = cell.getStringCellValue();
                }
                break;
            case BOOLEAN:
                cellValue = String.valueOf(cell.getBooleanCellValue());
                break;
            case FORMULA:
                // 如果公式计算结果为字符串类型,则获取字符串值
                if (cell.getCachedFormulaResultType() == CellType.STRING) {
                    cellValue = cell.getRichStringCellValue().getString();
                }
                // 如果公式计算结果为数字类型,则获取数字值并转换为字符串
                else if (cell.getCachedFormulaResultType() == CellType.NUMERIC) {
                    cellValue = String.valueOf(cell.getNumericCellValue());
                }
                // 如果公式计算结果为布尔类型,则获取布尔值并转换为字符串
                else if (cell.getCachedFormulaResultType() == CellType.BOOLEAN) {
                    cellValue = String.valueOf(cell.getBooleanCellValue());
                } else {
                    cellValue = "";
                }
                break;
            default:
                cellValue = "";
                break;
        }

        return cellValue;
    }


    // 设置实体类属性的值
    private static <T> void setFieldValue(T entity, Field field, String cellValue) throws Exception {
        field.setAccessible(true);
        Class<?> fieldType = field.getType();

        // 根据属性的类型进行赋值
        if (fieldType == String.class) {
            field.set(entity, cellValue);
        } else if (fieldType == Integer.class) {
            field.set(entity, Integer.valueOf(cellValue));
        } else if (fieldType == Double.class) {
//            field.set(entity, Double.valueOf(cellValue));
            field.set(entity, cellValue);

        }
        // 在此处可以根据需要添加其他类型的赋值判断
        else {
            field.set(entity, null);
        }
    }
}


五、实体类的改造

这一步和导入导出息息相关,因为得根据实体类属性的注解来决定导出的列名是什么,表名是什么。以User类为例,看我操作。

  • 主要看@Table(name = “用户信息表”)和@Column(name = “姓名”)
  • @Data是lombok的,@TableName(“tb_user”)是mybatisplus指定数据库表的,这里只是解释一下,与导出导入无关,避免不知道的博友。
  • 还有细心的朋友看见我实体类继承 BaseEntity.java,这是我写的一个公共实体类,主要写表中公共有的字段,避免在多张表重复写相同的属性。可以在下面了解一下。


import javax.persistence.Column;
import javax.persistence.Table;

@Data
@TableName("tb_user")
@Table(name = "用户信息表")
public class UserDO extends BaseEntity {

    @Column(name = "姓名")
    private String username;

    @Column(name = "性别")
    private String sex;

    @Column(name = "密码")
    private String password;

    @Column(name = "邮箱")
    private String email;

    @Column(name = "地址")
    private String address;

}

BaseEntity.java

继承这个类之后,User实体类就有id 的属性了,也有其他的字段,比如status, create_time等。这个类也要用@Column(name = “序号”) 标注。



import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;

import javax.persistence.Column;
import java.io.Serializable;


@Data
public class BaseEntity implements Serializable {

    @TableId(type = IdType.AUTO)
    @Column(name = "序号")
    private Integer id;

}


六、控制层使用

准备工作做好之后,就是调用接口了,还是以User实体类为例,看我操作。

@RestController
@RequestMapping("/api/users")
@ResponseBody
public class UserController {

	/**
     * 下载数据模板
     * 模块的原因是根据模板填写数据,上传的数据才不会出差错
     * 为什么这样?具体原因你懂的
     */

    @Transactional
    @GetMapping("/download/template")
    public void downloadTemplate(HttpServletResponse response) throws IOException {
    	// 调用接口,并传入空数据,在导出已经做出判断,
    	// 说明这个接口是下载模板,不会往表格里面写数据
        ExportUtils.exportData(response, null , UserDO.class);
    }



    /**
     * 导出
     */

    @Transactional
    @GetMapping("/export")
    public void exportRole(HttpServletResponse response) throws IOException {
    	// 数据库获取数据,Mybatis-plus的方法,不知道的可以学习学习MP
        List<UserDO> userDOList = userService.list();
		// 调用导出工具类的方法,传入对应的参数,简单吧
        ExportUtils.exportData(response, userDOList , UserDO.class);
    }

    /**
     * 导入
     */

    @Transactional
    @PostMapping("/import")
    public void importsEntity(@RequestParam("file") MultipartFile file) throws Exception {
        // 调用ImportUtil工具类来获取实体对象列表
        // 传入接口获取的文件和实体类,就可以获取到数据,简单吧
        List<UserDO> entities = ImportUtil.importEntities(file, UserDO.class);
        // 在这里处理导入数据的逻辑
        for (UserDO entity : entities) {
            // 执行对数据的操作,例如保存到数据库等
            System.out.println("导入的数据:" + entity);
            boolean save = userService.save(entity);
            if (save) {
               System.out.println("插入  " + entity + "   成功!");
           } else {
               System.out.println("插入  " + entity + "   失败!");
           }
        }
    }



}


七、效果

数据库表

在这里插入图片描述

1. 下载模板

  • 浏览器 URL 输入地址并回车

在这里插入图片描述
在这里插入图片描述

  • 查看模板并没有id的属性打印,导出工具类判断了。测试正确。

在这里插入图片描述


2. 导出

  • URL输入地址并回车

在这里插入图片描述

在这里插入图片描述

  • 查看内容:数据正确,且与数据库表字段对应。而且注意一点,id只是在下载模板的时候不打印,导出我并没有设置不打印,看个人需求,你也可以自己改一下。

![在这里插入图片描述](https://img-blog.csdnimg.cn/befd7234c6bb4999a84d0c200faffa2d.pn


3. 导入

  • 接下来用下载的模板进行写入数据,然后调用导入接口,获取数据。

  • 数据这样测试,测试在后端接口是否能够正确接收空值,是否有错位。
    在这里插入图片描述

  • 清空控制台:方便查看打印的数据,无意义,只是表演需要
    在这里插入图片描述

  • 我这里使用 postman 工具请求:注意我框起来的点即可
    在这里插入图片描述

  • 铛铛铛铛:看这么几条,空的值都为空,对应的值都对应上
    在这里插入图片描述

  • 再看数据库:完美!!!扣 666

在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/602c547646c04d7a9d66013738ce7362.png

总结

提示:觉得🐂B的扣个 666
惊不惊喜,意不意外!!!!

  • 10
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
### 回答1: Spring Boot 是一个用于创建基于 Spring 框架的独立、生产级别的应用程序的框架。EasyExcel 是一个基于 Java 的开源框架,可以方便地读写 Excel 文件。使用 EasyExcel 可以轻松地进行 Excel 文件的导入导出,非常适合在 Spring Boot 项目中使用。 下面是在 Spring Boot 项目中使用 EasyExcel 进行 Excel 文件导入导出的基本步骤: 1. 添加 EasyExcel 依赖 在项目的 pom.xml 文件中添加 EasyExcel 依赖: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.10</version> </dependency> ``` 2. 编写 Excel 导出代码 使用 EasyExcel 可以非常方便地进行 Excel 文件的导出。例如,以下代码可以将一个 List 对象导出为 Excel 文件: ```java // 定义 Excel 表头 List<List<String>> head = new ArrayList<>(); head.add(Arrays.asList("姓名", "年龄")); // 定义 Excel 数据 List<List<Object>> data = new ArrayList<>(); data.add(Arrays.asList("张三", 18)); data.add(Arrays.asList("李四", 20)); data.add(Arrays.asList("王五", 22)); // 导出 Excel 文件 String fileName = "example.xlsx"; String sheetName = "Sheet1"; EasyExcel.write(fileName).sheet(sheetName).head(head).sheet().doWrite(data); ``` 3. 编写 Excel 导入代码 使用 EasyExcel 进行 Excel 文件的导入也非常方便。例如,以下代码可以从 Excel 文件中读取数据并转换为一个 List 对象: ```java // 定义读取 Excel 文件的监听器 public class ExcelListener extends AnalysisEventListener<Object> { private List<Object> data = new ArrayList<>(); @Override public void invoke(Object object, AnalysisContext context) { data.add(object); } @Override public void doAfterAllAnalysed(AnalysisContext context) {} public List<Object> getData() { return data; } } // 读取 Excel 文件 String fileName = "example.xlsx"; ExcelListener listener = new ExcelListener(); EasyExcel.read(fileName, listener).sheet().doRead(); List<Object> data = listener.getData(); ``` 4. 将 Excel 文件导入到数据库 读取 Excel 文件之后,可以将数据存入数据库中。以下代码演示了将读取的 Excel 文件中的数据存入 MySQL 数据库的过程: ```java // 定义实体类 @Data public class Person { private String name; private Integer age; } // 保存数据到数据库 List<Person> persons = new ArrayList<>(); for (Object obj : data) { List<Object> row = (List<Object>) obj; Person person = new Person(); person.setName((String) row.get(0)); person.setAge((Integer) row.get(1)); persons.add(person); } personRepository.saveAll(persons); ``` 以上就是使用 EasyExcel 进行 Excel 文件导入导出的基本步骤。根据实际需求,可以对以上代码进行相应的修改和扩展。 ### 回答2: Spring Boot 是一个开源的Java开发框架,可以帮助开发人员快速构建基于Spring的应用程序。EasyExcel 是一种基于Java的Excel读写工具,它提供了简单便捷的API,可以方便地实现Excel的导入导出功能。 在Spring Boot中使用EasyExcel进行导入导出操作非常简单。首先,我们需要在pom.xml文件中添加EasyExcel的依赖项,以便可以使用它的功能。然后,我们可以创建一个Controller类来处理导入导出的请求。 对于导入操作,我们可以使用EasyExcel提供的@ExcelProperty注解来标记实体类的字段与Excel的列的映射关系。然后,我们可以使用EasyExcel的read方法来读取Excel文件,并将数据转换为实体类对象。最后,我们可以对读取到的数据进行相应的业务操作,比如存储到数据库中。 对于导出操作,我们可以使用EasyExcel的@ExcelProperty注解标记实体类的字段,并使用EasyExcel的write方法来将实体类列表写入Excel文件。我们可以通过指定文件路径或输出流的方式进行导出。 除了基本的导入导出功能,EasyExcel还提供了一些高级特性,比如读取大文件、多sheet处理、自定义读写处理器等。这些特性可以帮助我们更好地应对复杂的Excel导入导出需求。 总而言之,Spring Boot结合EasyExcel提供了一种简单快捷的方式来实现Excel的导入导出功能。无论是处理简单的Excel文件还是应对复杂的导入导出需求,Spring Boot和EasyExcel都能够提供强大的支持。 ### 回答3: Spring Boot 是一种简化了开发过程的Java框架,而EasyExcel是一种用于操作Excel文件的开源库。通过结合使用Spring Boot和EasyExcel,我们可以方便地实现Excel文件的导入导出功能。下面将详细介绍如何使用Spring Boot和EasyExcel来实现导入导出功能。 首先,我们需要在Spring Boot的项目中引入EasyExcel的依赖。在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.6</version> </dependency> ``` 接着,我们可以创建一个Controller类来处理导入导出的请求。在该类中,我们可以定义两个方法,一个用于导入Excel文件,另一个用于导出Excel文件。 对于导入功能,我们可以使用EasyExcel提供的`read()`方法来读取Excel文件,并将读取到的数据转换为一个List对象。以下是一个简单导入方法的示例代码: ```java @PostMapping("/import") public void importExcel(@RequestParam("file") MultipartFile file) throws IOException { List<DataDTO> dataList = EasyExcel.read(file.getInputStream()).head(DataDTO.class).sheet().doReadSync(); // 处理导入的数据 } ``` 对于导出功能,我们可以使用EasyExcel提供的`write()`方法来创建一个Excel文件,并将数据写入到该文件中。以下是一个简单导出方法的示例代码: ```java @GetMapping("/export") public void exportExcel(HttpServletResponse response) throws IOException { List<DataDTO> dataList = getDataList(); // 获取导出的数据 response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("data.xlsx", "utf-8")); EasyExcel.write(response.getOutputStream()).sheet("Data").doWrite(dataList); } ``` 在上述代码中,我们首先获取需要导出的数据(getDataList()方法需要根据实际情况实现),然后设置响应头信息,最后使用`write()`方法将数据写入到响应的输出流中。 通过以上步骤,我们在Spring Boot项目中成功实现了使用EasyExcel进行Excel文件的导入导出功能。我们可以根据具体需求对导入的数据进行处理,也可以根据实际情况设置导出文件的格式和名称。同时,EasyExcel还提供了更多的功能和选项,如设置表头、导入数据校验等,可以根据具体需求进行使用。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ItHeiMa小飞机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值