【Springboot+mybatis】 解析Excel並批量導入到數據庫

【Springboot+mybatis】 解析Excel並批量導入到數據庫
置頂 2018年01月16日 20:05:52 冉野丶 閱讀數:4060 標籤: excel導入數據庫 文件上傳 excel解析  更多
個人分類: POI 工作問題歸納
版權聲明:本文爲博主原創文章,未經博主允許不得轉載。	https://blog.csdn.net/hanerer1314/article/details/79077663
      一個很簡單的需求,從後臺中選取一個的Excel文件,並直接導入到數據庫,然後根據導入的表查詢個人信息,由於表的數據內容還挺多,有好幾萬條,所幸是單表。

     一個很愚蠢的做法是每解析一個Row,然後構建一個新的對象,再把每個cell的值賦給該對象,直到循環結束,再通過mabatis的insert語句入庫,這樣很low,有沒有???但是數據也能跑的過去,能完成入庫,不過兩萬條數據,連解析帶入庫一共花了將近20分鐘,天啦嚕,這樣客戶會炸毛的。沒辦法,還得修改,看了很多辦法,一種最直接的就是把解析和入庫分開,然後重新構建sql批量插入,因爲mybatis用的是generator插件自動生成的代碼,想把自己構建的mapper接口內容放在mybatis自己的目錄下,但是每次重新執行插件時候,自己新寫的接口文件就會被清除掉,無奈之舉,只能重新構建一個文件夾(excelmapper)來存儲我的查詢接口,這才逃過一劫,當我進行測試時候又報錯了,無法掃描到excelmapper下面的接口內容,嘗試在單元測試類上面配置@componentScan("com.net.excelmapper")註解,如果啓動類在根包下面,則你可以在該類上添加@ComponentScan註解而不需要添加任何參數,Spring Boot會在根包下面搜索注有@Component, @Service, @Repository, @Controller註解的所有類,並將他們註冊爲Spring Beans,否則,你需要在@ComponentScan註解上定義basePackages或者其他屬性。最後的解決辦法是在啓動類上添加了對應excelmapper文件夾下的掃描路徑,@MapperScan({"com.neo.mapper","com.neo.excelmapper"}),合法化測試終於通過了,可是還有一個問題,上傳超過了限制的默認值,只好在配置文件添加了配置項:

spring.http.multipart.max-file-size = 2048KB //支持文件上傳最大的限制

spring.http.multipart.max-request-size = 10240kB //最大支持請求

spring.http.multipart.enabled = true#默認支持文件上傳。

spring.http.multipart.file-size-threshold = 0#支持文件寫入磁盤。
spring.http.multipart.location =#上傳文件的臨時目錄

因爲用的是表單進行提交,<input type =“file”>這種情況下在form標籤下需要特殊的指定屬性文件爲formdata文件,例如:<form role =“form”action =“/ importExcel”method =“post” enctype =“multipart / form-data”>,這下終於可以完成數據導入了,不料,兩萬條數據果然還是花了20分鐘,修改意見也就上面提到的,分開操作,先把解析的數據封裝到一個對象上,並且存儲到列表集合中,在從幾何中批量插入。


excelmapper接口:
公共接口ExcelMapper {
    void batchInsert(List <Tbagent> tbagentList);
}
excelmapper.xml中主要的SQL語句,也就是執行批量操作的SQL,
<insert id =“batchInsert”parameterType =“java.util.List”>
    INSERT INTO代理(job_number,部門,地區,用戶名,idcard,company_rankings,department_rankings,region_rankings,
    distance_first_company,distance_first_department,distance_first_region)
    VALUES
    <foreach collection =“list”item =“item”index =“index”separator =“,”>
        (#{item.job_number},{#} item.department,#{item.region},{#} item.username,#{item.idcard},{#} item.company_rankings,
        #{item.department_rankings},{#} item.region_rankings,#{item.distance_first_company},{#} item.distance_first_department,#{item.distance_first_region})
    </的foreach>
</插入>
主要的服務層:
/ **
 *由管理員於2018/1/11創建。
 * /
@服務
公共類IimportServiceImpl實現IimportService {
  private final static String XLS =“xls”;
  public static final String XLSX =“xlsx”;
    私人最終靜態記錄器記錄器= LoggerFactory.getLogger(IimportServiceImpl.class);
    @Autowired私人TbagentMapper tbagentMapper;
    @Autowired私人SqlSessionTemplate sqlSessionTemplate;
    @Autowired私有ExcelMapper excelMapper;
    @覆蓋
    public Integer importExcel(MultipartFile myFile){
        // 1。使用HSSFWorkbook打開或者創建“Excel對象”
        // 2。用HSSFWorkbook返回對象或者創建片對象
        // 3。用片材返回行對象,用行對象得到細胞對象
        // 4。對細胞對象進行讀寫
        List <Tbagent> tbagents = new ArrayList <>();
        工作簿工作簿=空;
        String fileName = myFile.getOriginalFilename(); //獲取文件名
        logger.info( “【文件名】{}”,文件名);
        if(fileName.endsWith(XLS))
        {
            嘗試{
                workbook = new HSSFWorkbook(myFile.getInputStream()); // 2003版本
            } catch(IOException e){
                e.printStackTrace();
            }
        } else if(fileName.endsWith(XLSX)){
            嘗試{
                workbook = new XSSFWorkbook(myFile.getInputStream()); // 2007版本
            } catch(IOException e){
                e.printStackTrace();
            }
        }其他{
            拋出新的LianjiaException(ResultEnum.FILE_IS_NOT_EXCEL); //文件不是Excel文件
        }
        工作表=工作簿.getSheet(“sheet1”);
        int rows = sheet.getLastRowNum();
        logger.info( “【行】{}”,行);
        if(rows == 0){
            拋出new LianjiaException(ResultEnum.DATA_IS_NULL); //數據爲空請填寫數據
        }
        long startTime = System.currentTimeMillis();
        for(int i = 1; i <= rows + 1; i ++){
            行排= sheet.getRow(i);
            if(row!= null){
                Tbagent tbagent = new Tbagent();
                //部門
                String department = getCellValue(row.getCell(0));
                tbagent.setDepartment(部門);
                //用戶姓名
                String username = getCellValue(row.getCell(1));
                tbagent.setUsername(用戶名);
                //工號
                String jobNumer = getCellValue(row.getCell(2));
                如果(!StringUtils.isEmpty(jobNumer)){
                    Integer job_number = Integer.parseInt(jobNumer);
                    tbagent.setJob_number(Integer.valueOf(jobNumer));
                }
                //身份證後六位
                String idcard = getCellValue(row.getCell(3));
                tbagent.setIdcard(idcard);
                //公司排名
                String companyRankings = getCellValue(row.getCell(4));
                如果(!StringUtils.isEmpty(companyRankings)){
                    整數new_companyRankings = Integer.parseInt(companyRankings);
                    tbagent.setCompany_rankings(new_companyRankings);
                }
                //事業部排名
                String departmenRanks = getCellValue(row.getCell(5));
                如果(!StringUtils.isEmpty(departmenRanks)){
                    整數new_departmentRanks = Integer.parseInt(departmenRanks);
                    tbagent.setDepartment_rankings(new_departmentRanks);
                }
                //大區排名
                String region_Ranks = getCellValue(row.getCell(6));
                如果(!StringUtils.isEmpty(region_Ranks)){
                    整數new_region_Rankings = Integer.parseInt(region_Ranks);
                    //logger.info( “【大區排名】{}”,new_region_Rankings);
                    tbagent.setRegion_rankings(new_region_Rankings);
                } //距離公司第一名差距
                String distance_first_company = getCellValue(row.getCell(7));
                如果(!StringUtils.isEmpty(distance_first_company)){
                    long new_distance_first_company = Long.parseLong(distance_first_company);
                    tbagent.setDistance_first_company(new_distance_first_company);
                }
                //距離事業部第一名差距
                String distance_first_deparment = getCellValue(row.getCell(8));
                如果(!StringUtils.isEmpty(distance_first_deparment)){
                    Long new_distance_first_deparment = Long.parseLong(distance_first_deparment);
                    tbagent.setDistance_first_department(new_distance_first_deparment);
                }
                //距離大區第一名差距
                String distance_first_region = getCellValue(row.getCell(9));
                如果(!StringUtils.isEmpty(distance_first_region)){
                    Long new_distance_first_region = Long.parseLong(distance_first_region);
                    tbagent.setDistance_first_region(new_distance_first_region);
                }
                //System.out.println(JSON.toJSON(tbagent));
                //tbagentMapper.insert(tbagent);
                tbagents.add(tbagent);
                //logger.info( “插入數據完成”);
            }
        }
        excelMapper.batchInsert(tbagents); //批量插入五秒完成
        long endTime = System.currentTimeMillis();
        long totaltime = endTime  -  startTime;
        logger.info( “【消耗時間爲】{}”,TOTALTIME); //將近兩萬條數據3秒解析完成
        logger.info( “【第一條數據爲】{}”,JSON.toJSON(tbagents.get(0)));
        返回行;
    }
    public String getCellValue(Cell cell){
        String value =“”;
        if(cell!= null){
            開關(cell.getCellType()){
                case HSSFCell.CELL_TYPE_NUMERIC://數字
                     value = cell.getNumericCellValue()+“”;
                    如果(HSSFDateUtil.isCellDateFormatted(小區)){
                        Date date = cell.getDateCellValue();
                        if(date!= null){
                            value = new SimpleDateFormat(“yyyy-MM-dd”)。format(date); //日期格式化
                        }其他{
                           value =“”;
                        }
                    } else {
                        //解析cell時候數字類型默認是double類型的但是想要獲取整數類型需要格式化很重要很重要
                        value = new DecimalFormat(“0”)。format(cell.getNumericCellValue());
                    }
                    打破;
                大小寫HSSFCell.CELL_TYPE_STRING://字符串
                    value = cell.getStringCellValue();
                    打破;
                大小寫HSSFCell.CELL_TYPE_BOOLEAN://布爾類型
                    value = cell.getBooleanCellValue()+“”;
                    打破;
                大小寫HSSFCell.CELL_TYPE_BLANK://空值
                    value =“”;
                    打破;
                case HSSFCell.CELL_TYPE_ERROR://錯誤類型
                    value =“非法字符”;
                    打破;
                默認:
                    value =“未知類型”;
                    打破;
            }
        }
        返回value.trim();
    }
}
部分效果圖:


登錄效果圖如上。



不太完美的地方就是沒有一個進度條給客戶看,後期需要做處理。清空數據用的是MySQL的的截斷語句,直接清空所有的數據。然後讓用戶在導入到數據庫。

源碼地址 importexcel 分支

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章