spring boot如何使用POI讀取Excel文件
spring boot 使用POI讀取Excel文件
Excel文件目錄
Excel模板文件存了resourse目錄下,如下圖:

<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.16</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.16</version>
</dependency>
重要說明
如果是xls格式,使用HSSFWorkbook,HSSFSheet,HSSFRow來進行相關(guān)操作
如果是xlsx格式,使用XSSFWorkbook,XSSFSheet,XSSFRow來進行相關(guān)操作
讀取Excel文件
// 定義一個數(shù)據(jù)格式化對象
XSSFWorkbook wb = null;
try {
//excel模板路徑
File cfgFile = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + "static/ExcelTemplate/ContradictionMatrix.xlsx");
InputStream in = new FileInputStream(cfgFile);
//讀取excel模板
wb = new XSSFWorkbook(in);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
獲取sheet表格及讀寫單元格內(nèi)容
//獲取sheet表格,及讀取單元格內(nèi)容
XSSFSheet sheet = null;
try{
sheet = wb.getSheetAt(0);
//先將獲取的單元格設(shè)置為String類型,下面使用getStringCellValue獲取單元格內(nèi)容
//如果不設(shè)置為String類型,如果單元格是數(shù)字,則報如下異常
//java.lang.IllegalStateException: Cannot get a STRING value from a NUMERIC cell
sheet.getRow(2).getCell(2).setCellType(CellType.STRING);
//讀取單元格內(nèi)容
String cellValue = sheet.getRow(2).getCell(2).getStringCellValue();
//添加一行
XSSFRow row = sheet.createRow(1); //第2行開始寫數(shù)據(jù)
row.setHeight((short)400); //設(shè)置行高
//向單元格寫數(shù)據(jù)
row.createCell(1).setCellValue("名稱");
}
catch (Exception e){
e.printStackTrace();
}
合并單元格
使用下面的語句合并單元格:
sheet.addMergedRegion(new CellRangeAddress(0,2,15,18));
看一下CellRangeAddress的構(gòu)造函數(shù):
/**
* Creates new cell range. Indexes are zero-based.
*
* @param firstRow Index of first row
* @param lastRow Index of last row (inclusive), must be equal to or larger than {@code firstRow}
* @param firstCol Index of first column
* @param lastCol Index of last column (inclusive), must be equal to or larger than {@code firstCol}
*/
public CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) {
super(firstRow, lastRow, firstCol, lastCol);
if (lastRow < firstRow || lastCol < firstCol)
throw new IllegalArgumentException("lastRow < firstRow || lastCol < firstCol");
}
SpringBoot解析Excel
現(xiàn)在很多web應(yīng)用中,導(dǎo)入excel導(dǎo)出excel很常見,這篇文章就講講導(dǎo)入excel文件。
以批量導(dǎo)入課程為例
首先加入需要的jar包
<!--解析excel--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>RELEASE</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>RELEASE</version> </dependency>
數(shù)據(jù)庫中創(chuàng)建一個表course
DROP TABLE IF EXISTS `course`; CREATE TABLE `course` ( `course_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '課程id', `course_code` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '課程代碼', `course_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '課程名稱', `teacher_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '教師id', `course_time` date NOT NULL DEFAULT '1996-01-01' COMMENT '開課時間', `class_room` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '開課地點', `course_week` int(5) UNSIGNED NOT NULL DEFAULT 0 COMMENT '課程學(xué)時', `course_type` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '必修課' COMMENT '課程類型', `college_id` int(11) UNSIGNED NOT NULL COMMENT '所屬院系id', `score` int(5) UNSIGNED NOT NULL DEFAULT 0 COMMENT '學(xué)分', `is_on` tinyint(2) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否開啟了選課,默認(rèn)0未開啟', PRIMARY KEY (`course_id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '課程表' ROW_FORMAT = Dynamic;
新建一個ExcelUtil.java
/**
* excel工具類
*/
public class ExcelUtils {
private static Logger logger = LoggerFactory.getLogger(ExcelUtils.class);
/**
* 課程excel
* @param in
* @param fileName
* @return
* @throws Exception
*/
public static List getCourseListByExcel(InputStream in, String fileName) throws Exception {
List list = new ArrayList<>();
// 創(chuàng)建excel工作簿
Workbook work = getWorkbook(in, fileName);
if (null == work) {
throw new Exception("創(chuàng)建Excel工作薄為空!");
}
Sheet sheet = null;
Row row = null;
Cell cell = null;
for (int i = 0; i < work.getNumberOfSheets(); i++) {
sheet = work.getSheetAt(i);
if(sheet == null) {
continue;
}
// 濾過第一行標(biāo)題
for (int j = sheet.getFirstRowNum(); j <= sheet.getLastRowNum(); j++) {
row = sheet.getRow(j);
if (row == null || row.getFirstCellNum() == j) {
continue;
}
List<Object> li = new ArrayList<>();
for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) {
cell = row.getCell(y);
// 日期類型轉(zhuǎn)換
if(y == 3) {
//cell.setCellType(CellType.STRING);
double s1 = cell.getNumericCellValue();
Date date = HSSFDateUtil.getJavaDate(s1);
li.add(date);
continue;
}
li.add(cell);
}
list.add(li);
}
}
work.close();
return list;
}
/**
* 判斷文件格式
* @param in
* @param fileName
* @return
*/
private static Workbook getWorkbook(InputStream in, String fileName) throws Exception {
Workbook book = null;
String filetype = fileName.substring(fileName.lastIndexOf("."));
if(".xls".equals(filetype)) {
book = new HSSFWorkbook(in);
} else if (".xlsx".equals(filetype)) {
book = new XSSFWorkbook(in);
} else {
throw new Exception("請上傳excel文件!");
}
return book;
}
}
這里主要注意一下上面的日期轉(zhuǎn)換,在excel中的日期,通過Java讀出來之后,變成了26 四月 2019這樣的形式,而數(shù)據(jù)庫中我們的字段類型為date,所以總是插入失敗。
上面我的寫法直接是知道那個字段是Date類型,所以直接使用y==3,這樣寫可復(fù)用性很差。
接下來直接看和數(shù)據(jù)庫交互的邏輯代碼
/**
* 通過excel文件,批量增加課程
* @param request
* @return
* @throws Exception
*/
@PostMapping("/upload/course")
public String uploadCourseExcel(HttpServletRequest request) {
MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
MultipartFile file = multipartHttpServletRequest.getFile("courseFile");
if(file.isEmpty()) {
return "redirect:/admin/course/list";
}
try {
InputStream inputStream = file.getInputStream();
List<List<Object>> list = ExcelUtils.getCourseListByExcel(inputStream, file.getOriginalFilename());
inputStream.close();
for (int i = 0; i < list.size(); i++) {
List<Object> courseList = list.get(i);
Course course = new Course();
course.setCourseCode(courseList.get(0).toString());
course.setCourseName(courseList.get(1).toString());
// 通過教師姓名查教師id
String teacherId = teacherService.getTeacByName(courseList.get(2).toString());
// 教師信息錯誤,直接跳過這條記錄
if(teacherId == null) {
continue;
}
course.setTeacherId(teacherId);
// 格式化時間
Date date = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US).parse(courseList.get(3).toString());
course.setCourseTime(new SimpleDateFormat("yyyy-MM-dd").parse(new SimpleDateFormat("yyyy-MM-dd").format(date)));
course.setClassRoom(courseList.get(4).toString());
course.setCourseWeek(Integer.parseInt(new DecimalFormat("0").format(Double.parseDouble(courseList.get(5).toString()))));
course.setCourseType(courseList.get(6).toString());
// 通過院系名稱查詢院系id
Integer collegeId = collegeService.getCollegeByName(courseList.get(7).toString());
// 院系有誤,直接跳過這條記錄
if(collegeId == null || collegeId == 0) {
continue;
}
course.setCollegeId(collegeId);
course.setScore(Integer.parseInt(new DecimalFormat("0").format(Double.parseDouble(courseList.get(8).toString()))));
// 默認(rèn)不開啟選課
course.setIsOn(0);
logger.error("course = " + course);
// 判斷課程是否重復(fù)(同一門課程可以有多個教師教師course_code, course_name, teacher_id聯(lián)合)
Integer courseId = null;
courseId = courseService.getCourseByThree(course);
// 存在重復(fù)的
if(courseId != null) {
// 跳過不添加
continue;
}
// 執(zhí)行插入操作
courseService.addCourse(course);
}
} catch (Exception e) {
return "redirect:/admin/course/list";
}
return "redirect:/admin/course/list";
}
可以看到,我又對時間類型進行了處理,才能最終插入數(shù)據(jù)庫
// 格式化時間
Date date = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US).parse(courseList.get(3).toString());
course.setCourseTime(new SimpleDateFormat("yyyy-MM-dd").parse(new SimpleDateFormat("yyyy-MM-dd").format(date)));
同時,在excel中的整數(shù)類型,取出來之后就會變成Double類型比如5變成5.0,所以我對此也進行了處理
course.setCourseWeek(Integer.parseInt(new DecimalFormat("0").format(Double.parseDouble(courseList.get(5).toString()))));
最后調(diào)用代碼進行插入操作。
看看前端代碼
<button class="btn btn-default col-md-2" style="margin-top: 20px">
<a data-toggle="modal" href="#uploadExcel" rel="external nofollow" role="button" style="color: black; text-decoration: none">
批量添加<sapn class="glyphicon glyphicon-plus"/>
</a>
</button>
<!--批量添加模態(tài)框-->
<div class="modal fade" tabindex="-1" role="dialog" id="uploadExcel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form class="form-horizontal" role="form" th:action="@{/admin/upload/course}"
enctype="multipart/form-data" method="post">
<div class="modal-body">
請選擇文件:<input type="file" name="courseFile">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">關(guān)閉</button>
<button type="submit" class="btn btn-success">添加</button>
</div>
</form>
</div>
</div>
</div>
這里我通過button喚醒一個模態(tài)框來添加
最后測試結(jié)果


以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- SpringBoot+easypoi實現(xiàn)數(shù)據(jù)的Excel導(dǎo)出
- 使用Springboot+poi上傳并處理百萬級數(shù)據(jù)EXCEL
- Springboot+Poi導(dǎo)入Excel表格實現(xiàn)過程詳解
- SpringBoot中使用JeecgBoot的Autopoi導(dǎo)出Excel的方法步驟
- SpringBoot整合POI導(dǎo)出通用Excel的方法示例
- Springboot POI導(dǎo)出Excel(瀏覽器)
- java springboot poi 從controller 接收不同類型excel 文件處理
- SpringBoot使用POI進行Excel下載
- Springboot使用POI實現(xiàn)導(dǎo)出Excel文件示例
相關(guān)文章
深入探究Java?@MapperScan實現(xiàn)原理
之前是直接在Mapper類上面添加注解@Mapper,這種方式要求每一個mapper類都需要添加此注解,麻煩。通過使用@MapperScan可以指定要掃描的Mapper類的包的路徑,這篇文章深入探究Java?@MapperScan的實現(xiàn)原理2023-01-01
SpringMVC?Restful風(fēng)格與中文亂碼問題解決方案介紹
Restful就是一個資源定位及資源操作的風(fēng)格,不是標(biāo)準(zhǔn)也不是協(xié)議,只是一種風(fēng)格,是對http協(xié)議的詮釋,下面這篇文章主要給大家介紹了關(guān)于SpringMVC對Restful風(fēng)格支持的相關(guān)資料,需要的朋友可以參考下2022-10-10
Spring?Boot中的max-http-header-size配置方式
這篇文章主要介紹了Spring?Boot中的max-http-header-size配置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
Springboot使用POI實現(xiàn)導(dǎo)出Excel文件示例
本篇文章主要介紹了Springboot使用POI實現(xiàn)導(dǎo)出Excel文件示例,非常具有實用價值,需要的朋友可以參考下。2017-02-02
java利用遞歸調(diào)用實現(xiàn)樹形菜單的樣式
這篇文章主要給大家介紹了關(guān)于java利用遞歸調(diào)用實現(xiàn)樹形菜單樣式的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09
SpringBoot快速實現(xiàn)接口消息加密的過程詳解
在項目中,為了保證數(shù)據(jù)的安全,我們常常會對傳遞的數(shù)據(jù)進行加密,常用的加密算法包括對稱加密(AES)和非對稱加密(RSA),博主選取碼云上最簡單的API加密項目進行下面的講解,需要的朋友可以參考下2023-11-11

