365平台-beat365下载地址-BET体育365投注官网

BET体育365投注官网

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

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

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

文章目录

拿来吧你一、接口说明二、依赖三、导出工具类四、导入工具类五、实体类的改造BaseEntity.java

六、控制层使用七、效果数据库表1. 下载模板2. 导出3. 导入

总结

拿来吧你

提示:粘贴即可用

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

一、接口说明

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

二、依赖

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

代码如下(示例):

javax.persistence

javax.persistence-api

2.2

org.apache.poi

poi

4.1.2

org.apache.poi

poi-ooxml

4.1.2

org.apache.commons

commons-lang3

3.12.0

com.alibaba

fastjson

2.0.21

三、导出工具类

提示: 复制即可用

exportData()方法有三个参数:

response :请求接口浏览器直接新开窗口下载导出的文件List dataList : 用户数据,比如导出User表数据,那么将从数据库查询的用户数据作为这第二个参数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 void exportData(HttpServletResponse response, List dataList, Class 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 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语言,再做其他的操作,比如插入数据库。

参数解析:

MultipartFile file : 上传到导入接口的文件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 List importEntities(MultipartFile file, Class entityClass) throws Exception {

// 创建Excel工作簿

Workbook workbook = WorkbookFactory.create(file.getInputStream());

// 获取第一个工作表

Sheet sheet = workbook.getSheetAt(0);

// 获取标题行的列名

Row titleRow = sheet.getRow(0);

List columnNames = getColumnNames(titleRow);

// 创建实体对象列表

List entities = new ArrayList<>();

// 迭代每一行(跳过标题行)

Iterator 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 getColumnNames(Row row) {

List columnNames = new ArrayList<>();

for (Cell cell : row) {

columnNames.add(getStringCellValue(cell));

}

return columnNames;

}

// 根据行数据创建实体对象

// 对

private static T createEntityFromRow(Row row, List columnNames, Class 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 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 userDOList = userService.list();

// 调用导出工具类的方法,传入对应的参数,简单吧

ExportUtils.exportData(response, userDOList , UserDO.class);

}

/**

* 导入

*/

@Transactional

@PostMapping("/import")

public void importsEntity(@RequestParam("file") MultipartFile file) throws Exception {

// 调用ImportUtil工具类来获取实体对象列表

// 传入接口获取的文件和实体类,就可以获取到数据,简单吧

List 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只是在下载模板的时候不打印,导出我并没有设置不打印,看个人需求,你也可以自己改一下。

3. 导入

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

数据这样测试,测试在后端接口是否能够正确接收空值,是否有错位。

清空控制台:方便查看打印的数据,无意义,只是表演需要

我这里使用 postman 工具请求:注意我框起来的点即可

铛铛铛铛:看这么几条,空的值都为空,对应的值都对应上

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

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

总结

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

← 蛋白粉选择什么样的好?蛋白粉排行榜最新五大款式测评 热血传奇手游额度是多少?如何查询和提升? →

相关阅读

那些终将消亡和被取代的科技产品

点击上方“CSDN”,选择“置顶公众号” 关键时刻,第一时间送达! 作者简介:互扯程序,某互联网公司 P8 级专家攻城狮,曾参与过央视全台网

📅 07-07 🌿 BET体育365投注官网