SSM框架基於poi實現excel文件的上傳以及導入mysql數據庫

最近正在完善以前和小夥伴假期作的一個項目的一些小功能,其中一個就是上傳excel文件而且將excel文件中的數據導入到指定數據庫中。在這其中有遇到一些很小的細節的問題,因此決定將這個實現過程記錄下來。前端

一.基本介紹

  (1)先後臺分離,前端使用form表單提交,直接將文件流傳遞給後臺,後臺經過poi進行解析。java

 (2)在Excel中,有幾個基礎的概念web

  • 一個Execl就是一個Workbook
  • 一個Sheet就是一張表格
  • 一個Workbook能夠包含多個Sheet
  • 一行爲一個Row
  • 每一行(Row)的每一列就是一個單元格(Cell)

  (3)實現思路:在讀取Excel文件的過程當中,咱們能夠首先構造一個Workbook實例,而後遍歷每個Sheet,對於每個sheet,咱們再遍歷每個row,基於預先設定好的列名,讀取每一個cell的值。將讀取到的每個cell值,放進預先建立好的對象實例中去。【每個row就至關於一個實例對象】,最後咱們將這些實例對象組成一個對象列表,批量插入到數據庫中。spring

二.代碼實現

1.導入依賴包以及基礎配置

<dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.8</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-codec</artifactId>
                    <groupId>commons-codec</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.8</version>
        </dependency>

        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>

在spring-mvc.xml中添加代碼數據庫

<bean id="multipartResolve" class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
    </bean>

在web.xml中央控制器中添加支持apache

 

2.Controller層代碼數組

後臺使用MultipartFile來獲取上傳的文件。須要注意的是其中的@RequestParam中的參數值須要與前端頁面表單中type="file"的name的屬性值相同。spring-mvc

//導入excel用戶信息
    @ResponseBody
    @RequestMapping(value = "/importUserInfo.do", method = RequestMethod.POST)
    public ResultModel importUserInfo(@RequestParam("file") MultipartFile file) throws Exception {
        if (!file.isEmpty()) {
            InputStream inputStream = file.getInputStream();
            return ResultModel.builder()
                    .data(userService.importUserInfo(inputStream, file.getOriginalFilename()))
                    .code(SUCCESS)
                    .build();
        } else
            return ResultModel.builder()
                    .data("File is empty!")
                    .code(SUCCESS)
                    .build();
    }

 

3.userService中的實現方法importUserInfomvc

@Override
    public Integer importUserInfo(InputStream filePath, String file) {
        List<User> list = new ArrayList<>();
        String[] s;
        if (!file.endsWith(".xls") && !file.endsWith(".xlsx")) {
            //文件上傳格式出錯
            return -2;
        }
        Workbook workbook = null;
        try {
            //獲取Workbook實例
            workbook = ExcelUtil.getWorkBook(file, filePath);
        } catch (Exception e) {
            e.printStackTrace();
        }

        Sheet sheet = workbook.getSheetAt(0);
        
        //去除sheet中的一些無效行,好比值爲空可是有格式的空白行
        sheet = ExcelUtil.resetSheet(sheet);
        int lastRowNum = sheet.getLastRowNum();
        for (int i = 1; i <= lastRowNum; i++) {
            Row row = sheet.getRow(i);
            int cells = sheet.getRow(i).getPhysicalNumberOfCells();
            
            //獲取每一行的數值,並將其填入一個字符串的數組
            s = ExcelUtil.getExcelRows(row, cells);
            User user = new User();
            for (int j = 0; j < s.length; j++) {
                if (j == 0 && !s[j].equals(""))
                    user.setInstitute(s[j]);
                else if (j == 1 && !s[j].equals(""))
                    user.setMajor(s[j]);
                else if (j == 2 && !s[j].equals(""))
                    user.setClassId(Integer.getInteger(s[j]));
                else if (j == 3 && !s[j].equals(""))
                    user.setUsername(s[j]);
                else if (j == 4 && !s[j].equals(""))
                    user.setRealName(s[j]);
                else if (j == 5 && !s[j].equals(""))
                    user.setBirthday(DateUtil.parseYYYYMMDDDate(s[j]));
                else if (j == 6 && !s[j].equals(""))
                    user.setQq(s[j]);
                else if (j == 7 && !s[j].equals(""))
                    user.setTieba(s[j]);
                else if (j == 8 && !s[j].equals(""))
                    user.setWeibo(s[j]);
                else if (j == 9 && !s[j].equals(""))
                    user.setBlog(s[j]);
                user.setPassword("huhugty7tgf6f");
            }
            list.add(user);
        }
        return userDao.insertList(list);
    }

 

4.Excel讀取類ExcelUtilapp

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.InputStream;

public class ExcelUtil {

    //判斷文件類型是否知足要求
    public static Workbook getWorkBook(String file, InputStream fis)throws Exception{
        Workbook workbook = null;
        if(!file.endsWith(".xls") && !file.endsWith(".xlsx")){
            throw new Exception("上傳表格的格式錯誤!");
        }
        if(file.endsWith(".xls")){
            workbook = new HSSFWorkbook(fis,true);
        }
        if(file.endsWith(".xlsx")){
            workbook = new XSSFWorkbook(fis);
        }
        return workbook;
    }

    //獲取每一行的數據,而且返回一個字符串數組
    public static String[] getExcelRows(Row row , int columuNum){
        String[] s ;
        StringBuilder builder = new StringBuilder();
        for(int x = 0;x<columuNum;x++){
            Cell cell = row.getCell(x);
            builder.append(getStringCellValue(cell)+",");
        }
        s = builder.toString().split(",");
        return s;
    }

    //獲取單元內的有效數據
    public static String getStringCellValue(Cell cell){
        StringBuilder sb = new StringBuilder();
        switch (cell.getCellType()){
            //數字
            case Cell.CELL_TYPE_NUMERIC:
                if(DateUtil.isCellDateFormatted(cell)){
                    sb.append(cell.getDateCellValue());
                }else {
                    //將該數字強制轉化爲字符串類型獲取
                    cell.setCellType(Cell.CELL_TYPE_STRING);
                    sb.append(cell.getStringCellValue());
                }
                break;

            //字符串
            case Cell.CELL_TYPE_STRING:
                sb.append(cell.getStringCellValue());
                break;

            //布爾
            case Cell.CELL_TYPE_BOOLEAN:
                sb.append(cell.getBooleanCellValue());
                break;

            //公式
            case Cell.CELL_TYPE_FORMULA:
                sb.append(cell.getCellFormula());
                break;

            //空值
            case Cell.CELL_TYPE_BLANK:
                sb.append("");
                break;

            //故障
            case Cell.CELL_TYPE_ERROR:
                sb.append("");
                break;

            default:
                sb.append("");
                break;
        }
        return sb.toString();
    }

    //過濾掉表中的無心義空白行,由於getLastRowNum()在獲取Row行數時,對於表中沒有值但卻有格式的無心義空白行也將計入
    public static Sheet resetSheet(Sheet sheet){
        CellReference cellReference = new CellReference("A4");
        boolean flag;
        for(int i=cellReference.getRow();i<=sheet.getLastRowNum();){
            Row r = sheet.getRow(i);
            if(r == null){
                sheet.shiftRows(i+1,sheet.getLastRowNum(),-1);
                continue;
            }
            flag = false;
            for(Cell c : r){
                if(c.getCellType()!=Cell.CELL_TYPE_BLANK){
                    flag = true;
                    break;
                }
            }
            if(flag){
                i++;
                continue;
            }
            else{   //若是是空白行,沒有數據,可是有格式
                if(i == sheet.getLastRowNum())
                    sheet.removeRow(r);
                else
                    sheet.shiftRows(i+1,sheet.getLastRowNum(),-1);
            }
        }
        return sheet;
    }
}

 

三.測試

這裏我使用postman來測試後臺接口:

測試結果:

相關文章
相關標籤/搜索