提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
提示:粘贴即可用
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()方法有三个参数:
代码如下(示例):
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 staticvoid 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语言,再做其他的操作,比如插入数据库。
参数解析:
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 staticList 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类为例,看我操作。
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; }
继承这个类之后,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 ListuserDOList = 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 + " 失败!"); } } } }
接下来用下载的模板进行写入数据,然后调用导入接口,获取数据。
数据这样测试,测试在后端接口是否能够正确接收空值,是否有错位。
清空控制台:方便查看打印的数据,无意义,只是表演需要
我这里使用 postman 工具请求:注意我框起来的点即可
铛铛铛铛:看这么几条,空的值都为空,对应的值都对应上
再看数据库:完美!!!扣 666
![在这里插入图片描述](https://img-blog.csdnimg.cn/602c547646c04d7a9d66013738ce7362.png
提示:觉得🐂B的扣个 666
惊不惊喜,意不意外!!!!