寫在前面
前後端分離:前端VUE+ELEMENT,後端springboot。
excel上傳至後端
設置後端接口
先不做處理,收到文件就回復一個導入成功。(RespBean是爲了規範,自己封裝的一個用於統一回復格式的類,這裏改成String也是一樣的)
@PostMapping("/import")
public RespBean importExcel(MultipartFile file){
System.out.println("收到文件");
return RespBean.ok("導入成功");
}
前端使用upload組件
上傳時採用的是element的upload組件,不僅僅是element,只要是成熟的Vue組件庫肯定都有upload組件,所以這個不所謂,使用對應upload組件即可。具體使用參照官網:element upload組件
<el-upload action="/api/order/import"
:show-file-list="false"
:on-success="hanleSuccess"
accept=".xls">
<el-button type="primary">導入訂單</el-button>
</el-upload>
action指定後端地址;accept指定允許的導入文件的格式;show-file-list置爲false,那麼成功導入後,頁面上不會顯示已導入的文件列表(跟代碼邏輯無關,只是修改一下視覺效果);hanleSuccess是成功時回調方法,我用來展示後端返回的信息。當然,這幾個屬性最重要的還是action,其它根據自己開發需要,參照一下官網,自定義就好了。
至此就導入成功了,接下來時excel的解析
解析excel
使用POI:Apache POI提供API給Java對Microsoft Office格式檔案讀和寫的功能。
導入依賴
<!--解析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>
創建一個解析excel的工具類,將前端得到的file作爲參數:
//controller
@PostMapping("/import")
public RespBean importExcel(MultipartFile file){
// System.out.println("收到文件");
List<Order> orders = ExcelUtils.excelToOrder(file);
return RespBean.ok("導入成功");
}
下面是工具類的代碼:(註釋寫裏面了,節省空間)
簡單來說就是:先拿到整個表的對象,再拿到單張sheet的對象,再拿到每一行的對象,再分別取出一行中每一個單元格的值。
public class ExcelUtils {
public static List<Order> excelToOrder(MultipartFile file){
// 新建一個list,用於存放解析結果
List<Order> list=new ArrayList<>();
try {
// 拿到對象
HSSFWorkbook workbook = new HSSFWorkbook(file.getInputStream());
// 一個excel可能有多個sheet,所以遍歷sheet
for (int i = 0; i <workbook.getNumberOfSheets() ; i++) {
// 拿到sheet對象
HSSFSheet sheet = workbook.getSheetAt(i);
// System.out.println("行數"+sheet.getPhysicalNumberOfRows());
// 遍歷每一行
for (int j = 0; j <sheet.getPhysicalNumberOfRows() ; j++) {
//略過首行,即標題行
if(j==0){
continue;
}
// 拿到行的對象
HSSFRow row = sheet.getRow(j);
// 即使你的表格中沒有空行,但也可能會被解析出一些空行,所以我們略過空行,否則會報錯
if (row==null){
continue;
}
// System.out.println("列數"+row.getPhysicalNumberOfCells());
// new一個自己的實體類的對象,方便一會兒將解析出來的值存放進去
Order order = new Order();
// 注意下面這種方法是最簡單但是也最死板的方法,就是固定excel的表頭
// 每一列只能是對應的字段。一旦excel的某兩列相互替換一下位置
// 那麼寫入order的值就亂了
// 遍歷一行中的每一個單元格
for (int k = 0; k <row.getPhysicalNumberOfCells() ; k++) {
// 寫固定了,每一列內容不能變
if(k==0){
//訂單號
order.setOrdernumber(row.getCell(k).getStringCellValue());
}
else if(k==1){
//產線
order.setLinename(row.getCell(k).getStringCellValue());
}
else if(k==2){
// 訂單時間
order.setSubmittime(row.getCell(k).getDateCellValue());
}
else if(k==3){
// 交貨時間
order.setDelivertime(row.getCell(k).getDateCellValue());
}
else if(k==4){
// 規格
order.setGuige(row.getCell(k).getStringCellValue());
}
else if(k==5){
// 備註
order.setSpecification(row.getCell(k).getStringCellValue());
}
else ;
}
// 將order對象添加到list中
list.add(order);
// System.out.println(order);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
}
至此,excel的解析就完成了,並且我們也得到了一個待存放入數據庫的list。下一步就是常規的入庫了。
寫入數據庫
這一步就常規了,就一個普通的insert操作,不詳細寫了。
@PostMapping("/import")
public RespBean importExcel(MultipartFile file){
List<Order> orders = ExcelUtils.excelToOrder(file);
// 遍歷list,導入數據庫。
for (Order order : orders) {
orderService.save(order);
}
return RespBean.ok("導入成功");
}
用的Mybatis。mapper、service什麼的根據自己的情況寫了就OK了。
寫在後面
上述的excel解析方法,較爲簡單,要求導入的excel格式要嚴格規範。
要想通用性強一點的話,可以考慮以下思路:判斷表頭;判斷單元格值的屬性再進行枚舉。
後續可能的問題:爲了防止重複導入,在解析結果入庫時,應該先判斷數據庫內是否已經有對應的數據了。可以根據某個唯一的字段進行查詢(比如:身份證號、用戶唯一id、訂單號等等),有的話就不插入,沒有的話則插入。
正在學習,歡迎交流,多多指教!