java進階解析Springboot上傳excel存入數(shù)據(jù)庫步驟
一、導入依賴
這里還是用了Apache的POI插件,現(xiàn)在一般的springboot解析excel基本都用它 。
<!-- 文件上傳,解析文件需要的依賴-->
<!--poi對excel2007以上版本的支持-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.0.0</version>
</dependency>
<!-- poi對excel2003以下版本的支持 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.0.0</version>
</dependency>
二、前端實現(xiàn)
<button type="button" class="layui-btn layui-btn-normal layui-btn-radius" id="bookFileUpload">
<i class="layui-icon"></i>文件導入
</button>
/**
* 文件上傳--批量導入
*/
layui.use('upload', function () {
var upload = layui.upload;
var layer = layui.layer;
// layer.msg('上傳中', {icon: 16, time: 0,shade: 0.3});
//執(zhí)行實例
var uploadInst = upload.render({
elem: '#bookFileUpload', //綁定元素
url: '/library/book/batchAddBooks/', //上傳接口
exts: 'xlsx|xls', //限制文件類型
done: function (res) {
//上傳完畢回調
if (res.code == '1') {
successMsg("導入成功");
} else {
errorMsg("導入失敗" + res);
}
},
error: function (res) {
//請求異常回調
errorMsg("系統(tǒng)異常" + res);
}
});
});
說明一下,這里還是用了layui的框架去實現(xiàn)的,layui是我用過的前端框架里邊坑相對較少的一個不錯的簡單并且很容易入門的框架。
三、后臺邏輯
1.首先寫一個用于導入數(shù)據(jù)的model實體類,對應數(shù)據(jù)庫的一張表。
/**
* 書籍實體
*/
@Data
public class Book {
//主鍵id
private int bid;
//書名
private String bookname;
//作者
private String author;
//書的類型 武俠、言情等
private String booktype;
//出版社
private String publisher;
//出版時間
private String publicationdate;
//發(fā)行價格
private int price;
//發(fā)行狀態(tài)
private String bookstate;
//備注
private String comment;
}
這里使用了lombok的插件工具,所以可以省去寫setget方法,只需要@Data即可。
lombok的依賴,可用可不用,看你自己:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2.接著寫一下前端上傳過來excel,后臺的解析處理邏輯。
下面是重點:
package com.example.library.utils.fileUtiles;
import com.example.library.model.Book;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
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.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
/**
* @Author Summer_DM
* @Summary TODO 操作Excel的工具類
* @Version 1.0
* @Date 2021/9/16 下午 03:44
**/
public class ExcelUtils {
private static final Logger logger = LoggerFactory.getLogger(ExcelUtils.class);
//Map<String,Object> map = new HashMap<String, Object>();
private static final String XLS = "xls";
private static final String XLSX = "xlsx";
private final static String DATE_FORMAT = "yyyy-MM-dd";
/**
* 根據(jù)文件后綴名類型獲取對應的工作簿對象
* @param inputStream 讀取文件的輸入流
* @param fileType 文件后綴名類型(xls或xlsx)
* @return 包含文件數(shù)據(jù)的工作簿對象
* @throws IOException
*/
public static Workbook getWorkbook(InputStream inputStream, String fileType) throws Exception {
Workbook workbook = null;
//根據(jù)文件后綴名不同(xls和xlsx)獲得不同的Workbook實現(xiàn)類對象
if (fileType.equalsIgnoreCase(XLS)) {
//2003
workbook = new HSSFWorkbook(inputStream);
} else if (fileType.equalsIgnoreCase(XLSX)) {
//2007及以上
workbook = new XSSFWorkbook(inputStream);
}else {
throw new Exception("請上傳excel文件!");
}
return workbook;
}
/**
* 讀取Excel文件內容
* @param fileName 要讀取的Excel文件所在路徑
* @return 讀取結果列表,讀取失敗時返回null
*/
public static List<Book> readExcel(String fileName) {
Workbook workbook = null;
FileInputStream inputStream = null;
try {
// 獲取Excel后綴名
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
// 獲取Excel文件
File excelFile = new File(fileName);
if (!excelFile.exists()) {
logger.warn("指定的Excel文件不存在!");
}
// 獲取Excel工作簿
inputStream = new FileInputStream(excelFile);
workbook = getWorkbook(inputStream, fileType);
// 讀取excel中的數(shù)據(jù)
List<Book> resultDataList = parseExcel(workbook);
return resultDataList;
} catch (Exception e) {
logger.warn("解析Excel失敗,文件名:" + fileName + " 錯誤信息:" + e.getMessage());
return null;
} finally {
try {
if (null != workbook) {
workbook.close();
}
if (null != inputStream) {
inputStream.close();
}
} catch (Exception e) {
logger.warn("關閉數(shù)據(jù)流出錯!錯誤信息:" + e.getMessage());
return null;
}
}
}
/**
* 讀取Excel文件內容
* @param file 上傳的Excel文件
* @return 讀取結果列表,讀取失敗時返回null
*/
public static List<Book> readExcel(MultipartFile file) {
Workbook workbook = null;
try {
//判斷文件是否存在
if(null == file){
logger.warn("解析Excel失敗,文件不存在!");
return null;
}
// 獲取Excel后綴名
String fileName = file.getOriginalFilename();
if (fileName == null || fileName.isEmpty() || fileName.lastIndexOf(".") < 0) {
logger.warn("解析Excel失敗,因為獲取到的Excel文件名非法!");
return null;
}
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
// 獲取Excel工作簿
workbook = getWorkbook(file.getInputStream(), fileType);
// 讀取excel中的數(shù)據(jù)
List<Book> resultDataList = parseExcel(workbook);
return resultDataList;
} catch (Exception e) {
logger.warn("解析Excel失敗,文件名:" + file.getOriginalFilename() + " 錯誤信息:" + e.getMessage());
return null;
} finally {
try {
if (null != workbook) {
workbook.close();
}
} catch (Exception e) {
logger.warn("關閉數(shù)據(jù)流出錯!錯誤信息:" + e.getMessage());
return null;
}
}
}
/**
* 解析Excel數(shù)據(jù)
* @param workbook Excel工作簿對象
* @return 解析結果
*/
private static List<Book> parseExcel(Workbook workbook) {
List<Book> resultDataList = new ArrayList<>();
//獲取所有的工作表的的數(shù)量
int numOfSheet = workbook.getNumberOfSheets();
System.out.println(numOfSheet+"--->numOfSheet");
// 解析sheet,此處會讀取所有腳頁的行數(shù)據(jù),若只想讀取指定頁,不要for循環(huán),直接給sheetNum賦值,
// 腳頁從0開始(通常情況Excel都只有一頁,所以此處未進行進一步處理)
for (int sheetNum = 0; sheetNum < numOfSheet; sheetNum++) {
//獲取一個sheet也就是一個工作本。
Sheet sheet = workbook.getSheetAt(sheetNum);
// 校驗sheet是否合法
if (sheet == null) {
continue;
}
//獲取一個sheet有多少Row
//int lastRowNum = sheet.getLastRowNum();
//if(lastRowNum == 0) {
// continue;
//}
// 獲取第一行數(shù)據(jù)
int firstRowNum = sheet.getFirstRowNum();
Row firstRow = sheet.getRow(firstRowNum);
if (null == firstRow) {
logger.warn("解析Excel失敗,在第一行沒有讀取到任何數(shù)據(jù)!");
}
// 解析每一行的數(shù)據(jù),構造數(shù)據(jù)對象
int rowStart = firstRowNum + 1; //獲取第幾行
//獲得當前行的列數(shù)
int rowEnd = sheet.getPhysicalNumberOfRows();
for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) {
Row row = sheet.getRow(rowNum);
if (null == row) {
continue;
}
Book resultData = convertRowToData(row);
if (null == resultData) {
logger.warn("第 " + row.getRowNum() + "行數(shù)據(jù)不合法,已忽略!");
continue;
}
resultDataList.add(resultData);
}
}
return resultDataList;
}
/**
* 將單元格內容轉換為字符串
* @param cell
* @return
*/
private static String convertCellValueToString(Cell cell) {
String returnValue = null;
if(cell==null){
return returnValue;
}
//如果當前單元格內容為日期類型,需要特殊處理
String dataFormatString = cell.getCellStyle().getDataFormatString();
if(dataFormatString.equals("m/d/yy")){
returnValue = new SimpleDateFormat(DATE_FORMAT).format(cell.getDateCellValue());
return returnValue;
}
switch (cell.getCellType()) {
case NUMERIC: //數(shù)字
Double doubleValue = cell.getNumericCellValue();
// 格式化科學計數(shù)法,取一位整數(shù)
DecimalFormat df = new DecimalFormat("0");
returnValue = df.format(doubleValue);
break;
case STRING: //字符串
returnValue = cell.getStringCellValue();
break;
case BOOLEAN: //布爾
Boolean booleanValue = cell.getBooleanCellValue();
returnValue = booleanValue.toString();
break;
case BLANK: // 空值
break;
case FORMULA: // 公式
returnValue = cell.getCellFormula();
break;
case ERROR: // 故障
break;
default:
break;
}
return returnValue;
}
/**
* 提取每一行中需要的數(shù)據(jù),構造成為一個結果數(shù)據(jù)對象
*將excel的內容賦給實體類model
* 當該行中有單元格的數(shù)據(jù)為空或不合法時,忽略該行的數(shù)據(jù)
*
* @param row 行數(shù)據(jù)
* @return 解析后的行數(shù)據(jù)對象,行數(shù)據(jù)錯誤時返回null
*/
private static Book convertRowToData(Row row) {
Book resultData = new Book();
Cell cell;
int cellNum = 0;
//獲取書籍名稱
cell = row.getCell(cellNum++);
String bookName = convertCellValueToString(cell);
if (null == bookName || "".equals(bookName)) {
// 書籍名稱為空
resultData.setBookname(bookName);
} else {
resultData.setBookname(bookName);
}
// 獲取書籍作者
cell = row.getCell(cellNum++);
String author = convertCellValueToString(cell);
if (null == author || "".equals(author)) {
// 書籍作者為空
resultData.setAuthor(author);
} else {
resultData.setAuthor(author);
}
// 獲取書籍類型
cell = row.getCell(cellNum++);
String type = convertCellValueToString(cell);
if (null == type || "".equals(type)) {
// 書籍類型為空
resultData.setBooktype(type);
} else {
resultData.setBooktype(type);
}
//獲取出版單位
cell = row.getCell(cellNum++);
String publisher = convertCellValueToString(cell);
if (null == publisher || "".equals(publisher)) {
// 出版單位為空
resultData.setPublisher(publisher);
} else {
resultData.setPublisher(publisher);
}
//獲取出版時間
cell = row.getCell(cellNum++);
String publicationdate = convertCellValueToString(cell);
if (null == publicationdate || "".equals(publicationdate)) {
// 出版時間為空
resultData.setPublicationdate(publicationdate);
} else {
resultData.setPublicationdate(publicationdate);
}
//獲取價格
cell = row.getCell(cellNum++);
String price = convertCellValueToString(cell);
if (null == price || "".equals(price)) {
// 價格為空
resultData.setPrice(Integer.parseInt(price));
} else {
resultData.setPrice(Integer.parseInt(price));
}
//獲取借閱狀態(tài)
cell = row.getCell(cellNum++);
String bookstate = convertCellValueToString(cell);
if (null == bookstate || "".equals(bookstate)) {
// 借閱狀態(tài)為空
resultData.setBookstate(bookstate);
} else {
resultData.setBookstate(bookstate);
}
//獲取備注
cell = row.getCell(cellNum++);
String comment = convertCellValueToString(cell);
if (null == comment || "".equals(comment)) {
// 備注為空
resultData.setComment(comment);
} else {
resultData.setComment(comment);
}
return resultData;
}
/**
* 生成Excel文件
* @param outputStream
*/
public void writeExcel(OutputStream outputStream){
/**
* 這個outputstream可以來自與文件的輸出流,
* 也可以直接輸出到response的getOutputStream()里面
* 然后用戶就可以直接解析到你生產的excel文件了
*/
Workbook wb = new SXSSFWorkbook(100);
//創(chuàng)建一個工作本
Sheet sheet = wb.createSheet("sheet");
//通過一個sheet創(chuàng)建一個Row
Row row = sheet.createRow(0);
for(int i =0;i<10;i++){
//通過row創(chuàng)建一個cell
Cell cell = row.createCell(i);
cell.setCellValue("這是第"+i+"個cell");
}
try {
wb.write(outputStream);
wb.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
3.最后寫一下解析完成,存入數(shù)據(jù)庫。
<insert id="insertUsers">
insert into user(username,sex,tel,institute,profession,classname,stuid,password,type)
values
<foreach collection="users" index="" item="item" separator=",">
(
#{item.username,jdbcType=VARCHAR}, #{item.sex,jdbcType=VARCHAR}, #{item.tel,jdbcType=VARCHAR},
#{item.institute,jdbcType=VARCHAR}, #{item.profession,jdbcType=VARCHAR},
#{item.classname,jdbcType=VARCHAR}, #{item.stuid,jdbcType=VARCHAR},
#{item.password,jdbcType=VARCHAR}, #{item.type,jdbcType=VARCHAR}
)
</foreach>
</insert>
三、頁面效果
點擊導入用戶,選擇excel文件即可。

四、可能會遇到的問題
因為springboot現(xiàn)在使用的poi的支持已經達到5.0以上版本了,但是他整合起來可能會出現(xiàn)一些小異常,雖然不影響我們正常使用,但是控制臺會一直出現(xiàn),也很煩,所以這里 給一個解決辦法。
/**
* @Author Summer_DM
* @Summary TODO 專門用來處理SpringBoot應用集成poi 5.0.0啟動報錯java.io.FileNotFoundException,
* TODO 因為使用poi 5.0.0解析excel,會有一些找不到jar包的問題,但是去maven倉庫查看發(fā)現(xiàn)jar包都在,所以可以不必理會
* TODO java.io.FileNotFoundException: E:\software\apache\maven\maven-repository\library_repo\org\apache\xmlgraphics\batik-ttf2svg\1.13\lib\batik-i18n-1.13.jar (系統(tǒng)找不到指定的路徑。)
* @Version 1.0
* @Date 2021/9/18 下午 09:29
**/
@Configuration
public class MyStandardJarScanner {
@Bean
public TomcatServletWebServerFactory tomcatFactory() {
return new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
}
};
}
}
比較簡單易學,網上也有很多教程,有需要的可以一起來交流一下,哈哈?。?!
以上就是java進階Springboot上傳excel存入數(shù)據(jù)庫步驟的詳細內容,更多關于Springboot上傳excel的資料請關注腳本之家其它相關文章!
相關文章
詳解Lombok安裝及Spring Boot集成Lombok
這篇文章主要介紹了詳解Lombok安裝及Spring Boot集成Lombok,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03
Java高性能新一代構建工具Maven-mvnd(實踐可行版)
這篇文章主要介紹了Java高性能新一代構建工具Maven-mvnd(實踐可行版),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06

