SpringBoot解析Excel把資料儲存到資料庫,親測可用
阿新 • • 發佈:2021-12-01
轉載出處: https://www.cnblogs.com/liyhbk/p/13903528.html
一、建立一個spring boot專案
1.1 開發工具 idea
1.2 jdk 1.8
1.3 具體專案搭建流程可以閱讀我的另一篇部落格(建立spring boot專案)
1.4 整體結構
二、搭建spring boot開發環境
2.1 新增pom檔案
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.liyh</groupId> <artifactId>springboot_excel</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>springboot_excel</name> <description>study springboot_excel</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <!--mysql驅動--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--jdbc 資料庫連線--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- 引入阿里資料庫連線池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.6</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- mybatisPlus 核心庫 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>net.sourceforge.nekohtml</groupId> <artifactId>nekohtml</artifactId> <version>1.9.15</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <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.10</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> </resource> </resources> </build> </project>
2.2 配置application.yml檔案
# 配置埠 server: port: 8086 spring: # 配置資料來源 datasource: url: jdbc:mysql://localhost:3306/db1?useSSL=false&serverTimezone=UTC username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver thymeleaf: mode: LEGACYHTML5 # 取消模板檔案快取 cache: false #設定thymeleaf檔案路徑 預設為src/main/resources/templates freemarker: template-loader-path: classpath:/templates #設定靜態檔案路徑,js,css等 mvc: static-path-pattern: /static/** servlet: multipart: # 設定單個檔案大小 max-file-size: 200MB # 設定單次請求檔案的總大小 max-request-size: 200MB # mybatis-plus相關配置 mybatis-plus: # xml掃描,多個目錄用逗號或者分號分隔(告訴 Mapper 所對應的 XML 檔案位置) mapper-locations: classpath*:com/liyh/mapper/xml/*.xml configuration: # 是否開啟自動駝峰命名規則對映:從資料庫列名到Java屬性駝峰命名的類似對映 map-underscore-to-camel-case: true #列印sql,儲存到檔案 logging: level: com.liyh.mapper: debug
2.3 編寫摸板檔案
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <hr/> <p>摸板下載</p> <a href="/excel/download">下載摸板</a> <hr/> <p>檔案上傳</p> <form action="/excel/import" method="POST" enctype="multipart/form-data"> 檔案:<input type="file" name="file"/> <input type="submit"/> </form> <hr/> </body> </html>
2.4 建立IndexController,FileController
package com.liyh.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * @Author: liyh * @Date: 2020/10/23 17:33 */ @Controller public class IndexController { @RequestMapping("/") public String index() { return "index"; } }
package com.liyh.controller; import com.liyh.entity.Result; import com.liyh.service.ExcelService; import com.liyh.utils.ExcelTool; import com.liyh.utils.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 介面 * * @Author: liyh * @Date: 2020/10/23 17:05 */ @RestController @RequestMapping("/excel") public class ExcelController { Logger logger = LoggerFactory.getLogger(ExcelController.class); @Autowired private ExcelService excelService; @PostMapping("/import") public Result importProject(MultipartFile file) { String postfix = ExcelTool.getPostfix(file.getOriginalFilename()); if (!"xlsx".equals(postfix) && !"xls".equals(postfix)) { return Result.error("匯入失敗,請選擇正確的檔案格式支援xlsx或xls"); } return excelService.importProject(file); } @GetMapping("/download") public String downloadFile(HttpServletRequest request, HttpServletResponse response) { String fileName = "template.xlsx"; String result = FileUtils.downloadFiles(request, response, fileName); if (request == null) { return null; } return result; } }
2.4 檔案工具類
package com.liyh.utils; import org.springframework.core.io.ClassPathResource; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; /** * @Author: liyh * @Date: 2020/11/4 16:10 */ public class FileUtils { /** * 下載檔案 * @param request * @param response * @param fileName * @return * @throws IOException */ public static String downloadFiles(HttpServletRequest request, HttpServletResponse response, String fileName){ if (StringUtils.isEmpty(fileName)) { return "檔名稱為空"; } //設定檔案路徑 ClassPathResource classPathResource = new ClassPathResource("templates/" + fileName); File file = null; try { file = classPathResource.getFile(); } catch (IOException e) { e.printStackTrace(); return "檔案不存在"; } response.setHeader("content-type", "application/octet-stream"); // 設定強制下載不開啟 response.setContentType("application/force-download"); // 設定檔名 response.addHeader("Content-Disposition", "attachment;fileName=" + fileName); byte[] buffer = new byte[1024]; InputStream fis = null; BufferedInputStream bis = null; try { fis = new FileInputStream(file); bis = new BufferedInputStream(fis); OutputStream os = response.getOutputStream(); int i = bis.read(buffer); while (i != -1) { os.write(buffer, 0, i); i = bis.read(buffer); } } catch (Exception e) { e.printStackTrace(); } finally { if (bis != null) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } return "檔案下載成功"; } /** * 判斷檔案大小 * * @param file 檔案 * @param size 限制大小 * @param unit 限制單位(B,K,M,G) * @return */ public static boolean checkFileSize(MultipartFile file, int size, String unit) { if (file.isEmpty() || StringUtils.isEmpty(size) || StringUtils.isEmpty(unit)) { return false; } long len = file.getSize(); double fileSize = 0; if ("B".equals(unit.toUpperCase())) { fileSize = (double) len; } else if ("K".equals(unit.toUpperCase())) { fileSize = (double) len / 1024; } else if ("M".equals(unit.toUpperCase())) { fileSize = (double) len / 1048576; } else if ("G".equals(unit.toUpperCase())) { fileSize = (double) len / 1073741824; } if (fileSize > size) { return false; } return true; } }FileUtils
2.5 service
package com.liyh.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.liyh.entity.ProjectItem; import com.liyh.entity.Result; import com.liyh.mapper.ExcelMapper; import com.liyh.service.ExcelService; import com.liyh.utils.ExcelTool; import org.apache.commons.lang3.StringUtils; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * @Author: liyh * @Date: 2020/10/23 17:44 */ @Service public class ExcelServiceImpl extends ServiceImpl<ExcelMapper, ProjectItem> implements ExcelService { private NumberFormat numberFormat = null; @Override public Result importProject(MultipartFile file) { // 解析Excel資料 Result r = readDataFromExcel(file); List list = (List) r.getData(); List<ProjectItem> items = list; if (items == null || items.size() <= 0) { return Result.error("沒有資料!!!"); } //查詢之前是否存在專案清單項 QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("is_deleted", 0); List<ProjectItem> beforeItems = baseMapper.selectList(wrapper); //如果存在,判斷兩個集合中是否有相同的專案序號 if (beforeItems != null && beforeItems.size() > 0) { List<String> beforeOrderNumber = beforeItems.stream().map(ProjectItem::getOrderNumber).collect(Collectors.toList()); List<String> afterOrderNumber = items.stream().map(ProjectItem::getOrderNumber).collect(Collectors.toList()); for (String vo : beforeOrderNumber) { if (afterOrderNumber.contains(vo)) { return Result.error(vo + ":該專案序號已經存在"); } } } // 如果沒有序號相等,則插入資料表格中的資料,然後重新讀取 for (ProjectItem item : items) { // 儲存資料 int insert = baseMapper.insertProjectItem(item.getOrderNumber(), item.getName(), item.getContent(), item.getType(), item.getUnit(), item.getPrice(), item.getCount()); if (insert <= 0) { return Result.error("匯入失敗"); } } return Result.success("匯入成功"); } /** * 解析Excel資料 * * @param file 檔案 * @return */ public Result readDataFromExcel(MultipartFile file) { POIFSFileSystem pfs = null; Workbook workbook = null; try { // 解析xls和xlsx不相容問題 workbook = ExcelTool.getWorkBook(pfs, workbook, file); } catch (IOException e) { e.printStackTrace(); return Result.error("模板儲存異常。"); } if (workbook == null) { return Result.error("請使用模板上傳檔案"); } // 判斷有記錄的列數 if (workbook.getSheetAt(0).getRow(0).getPhysicalNumberOfCells() != 7) { return Result.error("請使用型別所對應的模板"); } numberFormat = NumberFormat.getNumberInstance(); List<ProjectItem> list = new ArrayList<>(); // 獲取表格第一個sheet的內容 Sheet sheetAt = workbook.getSheetAt(0); // 獲得sheet總行數 int lastRowNum = sheetAt.getLastRowNum(); if (lastRowNum < 1) { return Result.error("資料錯誤"); } // 開始讀取,不讀取表頭所以從第二行開始 for (int i = 1; i <= lastRowNum; i++) { // 獲取每一行 Row row = sheetAt.getRow(i); // 行為空不讀取 if (row == null) continue; Cell cell = row.getCell(0); //列為空不讀取 if (cell == null || StringUtils.isEmpty(convertData(cell))) continue; // 建立物件封裝行資料 ProjectItem projectItem = new ProjectItem(); // 建立一個集合根據下標來確定每個單元格對應物件的什麼屬性 List<String> rowList = new ArrayList<>(); //新增資料 for (int j = 0; j < 7; j++) { Cell cellOne = row.getCell(j); try { String item = convertData(cellOne); rowList.add(item); } catch (Exception e) { System.out.println("-------------------Err-----------------------"); System.out.println(i + "行" + j + "列資料轉換出現異常"); rowList.add(""); } } //規避行數資料後幾行為空 if (rowList.size() < 7) { for (int k = 0; k < 7 - rowList.size(); k++) { rowList.add(""); } } // 新增資料 projectItem.setOrderNumber(rowList.get(0).trim()); projectItem.setName(rowList.get(1).trim()); projectItem.setContent(rowList.get(2).trim()); if ("直接費".equals(rowList.get(3).trim())) { projectItem.setType(1); } else if ("間接費".equals(rowList.get(3).trim())) { projectItem.setType(2); } else if ("措施費".equals(rowList.get(3).trim())) { projectItem.setType(3); } else { projectItem.setType(null); } projectItem.setUnit(rowList.get(4).trim()); projectItem.setPrice(rowList.get(5).trim()); projectItem.setCount(rowList.get(6).trim()); list.add(projectItem); } return Result.success("解析成功", list); } /** * 表格資料轉換 * * @param cell * @return */ public String convertData(Cell cell) { String str = ""; switch (cell.getCellTypeEnum()) { case NUMERIC: //判斷是否是整數 str = numberFormat.format(cell.getNumericCellValue()); break; case STRING: str = cell.getStringCellValue(); break; case _NONE: str = ""; break; case BLANK: str = ""; break; case FORMULA: try { str = String.valueOf(cell.getNumericCellValue()); } catch (IllegalArgumentException e) { str = String.valueOf(cell.getRichStringCellValue()); } break; default: str = ""; } return str; } }
2.6 entity
package com.liyh.entity; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.io.Serializable; /** * 專案清單表實體類 * * @Author: liyh * @Date: 2020/10/23 17:05 */ @Data @TableName("project_item") public class ProjectItem implements Serializable { private static final long serialVersionUID = 1L; /** * 主鍵uuid */ private Integer id; /** * 專案序號 */ private String orderNumber; /** * 專案名稱 */ private String name; /** * 專案內容 */ private String content; /** * 費用型別(直接費等) */ private Integer type; /** * 單位 */ private String unit; /** * 單價 */ private String price; /** * 數量 */ private String count; /** * 是否已刪除[0-否、1-是] */ private String isDeleted; }
三、摸板檔案
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for project_item -- ---------------------------- DROP TABLE IF EXISTS `project_item`; CREATE TABLE `project_item` ( `id` int(11) NOT NULL AUTO_INCREMENT, `order_number` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL, `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL, `content` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL, `type` int(16) NULL DEFAULT NULL, `unit` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL, `price` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL, `count` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL, `is_deleted` int(1) UNSIGNED ZEROFILL NULL DEFAULT 0 COMMENT '是否已刪除[0-否、1-是]', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact; SET FOREIGN_KEY_CHECKS = 1;