java程式碼實現excel檔案資料匯入

lin_Lobster_發表於2020-11-11

因業務需求要實現資料的批量匯入,給了指定的excel模板上傳檔案,用java程式碼實現匯入excel檔案。

重新複習下。

下面是原始碼,僅供參考。

controller層程式碼,建立臨時目錄後,使用DiskFileItemFactory類來實現檔案上傳,List parseRequest(HttpServletRequest request)方法來解析request物件,並把表單中的每一個輸入項包裝成一個fileItem 物件,並返回一個儲存了所有FileItem的list集合。

 @RequestMapping("/doImport")
    @ResponseBody
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
    public Map<String, Object> doImport(HttpServletRequest request, HttpSession session) throws Exception{
        Map<String, Object> map = new HashMap<>();
        String path = System.getProperty("web.root");
        //建立臨時檔案目錄
        String tempPath = path + File.separator + "attach" + File.separator;
        //建立File類例項
        File tempFile = new File(tempPath + "temp");
        int userId = PubFunc.parseInt(session.getAttribute("user_id"));
        try {
            //建立FileItem 物件的工廠
            DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
            //指定臨時檔案目錄
            diskFileItemFactory.setRepository(tempFile);
            //負責處理上傳的檔案資料,並將表單中每個輸入項封裝成一個FileItem 物件中
            ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
            //解析request物件,把表單中的每一個輸入項包裝成一個fileItem 物件
            List<FileItem> lists = servletFileUpload.parseRequest(request);

            int len = lists.size();
            for (int n = 0; n < len; n++) {
                FileItem item = lists.get(n);
                if (!item.isFormField()) {
                    if (item.getName().length() > 0) {
                        InputStream inputStream = item.getInputStream();
                        unabledService.doImportExl(item.getName(), inputStream, userId);
                        map.put("code",0);
                        map.put("msg", "檔案上傳中,稍後自動跳轉" );
                    }
                }
            }
        }catch (FileNotFoundException e) {
            map.put("code",1);
            map.put("msg", "檔案未找到或檔案格式錯誤!");
        } catch (IOException e) {
            map.put("code",2);
            map.put("msg", "檔案內容讀取失敗");
        } catch (IllegalAccessException e) {
            map.put("code",3);
            map.put("msg", "使用者資訊寫入失敗");
        } catch (NoSuchFieldException e) {
            map.put("code",4);
            map.put("msg", "找不到該屬性值");
        } catch (NullPointerException e) {
            map.put("code",5);
            map.put("msg", "檔案未上傳");
        } catch (InvalidFormatException e) {
            map.put("code",6);
            map.put("msg", "檔案格式錯誤");
        } catch (Exception e) {
            e.printStackTrace();
            map.put("code",7);
            map.put("msg", e.getMessage());
        }
        return map;
    }

service層程式碼,裡面有兩個方法需要注意,一個是readExcel(fileName,inputStream)方法,通過流來讀取excel資料,並對excel裡面的資料做重複校驗。另一個是insert_batch(unableds,userId)方法,用來將資料批量插入,

  /**
     * 執行匯入資料操作
     *
     * @param fileName    檔名
     * @param inputStream 資料流
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    @Override
    public int doImportExl(String fileName, InputStream inputStream, int userId) throws Exception {
        //讀取資料
        List<Map<String, Object>> list = readExcel(fileName, inputStream);
        if (list == null || list.isEmpty()) {
            throw new Exception("匯入資料存在相同手機號");
        }
        //插入資料條數記錄
        int i = 0;
        //迭代器
        Iterator<Map<String, Object>> iterator = list.iterator();
        Map<String, Object> fieldMap = getFieldsMap(122);
        List<Unabled> unableds = new ArrayList<>();
        while (iterator.hasNext()) {
            Map<String, Object> map = iterator.next();
            Unabled unabled = new Unabled();
            //反射獲取所有屬性
            Class<? extends Unabled> clazz = unabled.getClass();
            for (String key : fieldMap.keySet()) {
                String value = PubFunc.toString(map.get(PubFunc.toString(fieldMap.get(key))));
                if (!PubFunc.isNullStr(value)) {
                    Field field = clazz.getDeclaredField(key);
                    //設定私有屬性允許更改
                    field.setAccessible(true);
                    field.set(unabled, value);
                }

            }
            unableds.add(unabled);

        }
        int res = insert_batch(unableds, userId);

        return res;
    }

readExcel(fileName,inputStream)方法程式碼

 private List<Map<String, Object>> readExcel(String fileName, InputStream inputStream) throws IOException, InvalidFormatException {
        //校驗檔案
        boolean ret = isXls(fileName);

        Workbook wb = null;

        //根據字尾新建對應的工作簿
        if (ret) {
            wb = new HSSFWorkbook(inputStream);
        } else {
            wb = WorkbookFactory.create(inputStream);
        }
        //獲取第一個sheet
        Sheet sheet = wb.getSheetAt(0);
        //標題行
        Row titleRow = sheet.getRow(0);

        //獲取最大行數及列數
        int max_row = sheet.getLastRowNum();
        int max_cell = titleRow.getLastCellNum() - 1;
        //存放資料
        List<Map<String, Object>> list = new ArrayList<>();
        //存放手機號做重複校驗

        for (int i = 1; i <= max_row; i++) {
            Map<String, Object> map = new HashMap<>();
            Row row = sheet.getRow(i);
            if (row == null) {
                break;
            }
            for (int j = 0; j < max_cell; j++) {
                String cellTitle = titleRow.getCell(j).getStringCellValue();
                Cell cell = row.getCell(j);
                String cellValue;
                //對空值進行處理
                if (cell == null) {
                    cellValue = "";
                } else {
                    cell.setCellType(Cell.CELL_TYPE_STRING);
                    cellValue = cell.getStringCellValue();
                }
               
                map.put(cellTitle, cellValue);
            }
            list.add(map);
        }
        wb.close();
       
        return list;
    }

insert_batch(unableds,userId)方法程式碼,newCachedThreadPool建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒。

   @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, isolation = Isolation.DEFAULT)
    public int insert_batch(List<Unabled> unableds, int userId) throws Exception {
      //建立一個執行緒安全的ConcurrentHashMap集合
        ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
       //建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒
        ExecutorService threadPoolExecutor = Executors.newCachedThreadPool();
          // 主執行緒等待子執行緒執行完成再執行
        final CountDownLatch countDownLatch = new CountDownLatch(unableds.size() / 500 == 0 ? 1 : unableds.size() / 500);
        for (int i = 0; i < unableds.size(); i += 500) {
            if (i > unableds.size()) {
                break;
            }
            int j = i + 500;
            List<Unabled> list = j > unableds.size() ? unableds.subList(i, unableds.size()) : unableds.subList(i, j);
            threadPoolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + ":" + System.currentTimeMillis());
                    for (int k = 0; k < list.size(); k++) {
                        Unabled unabled = list.get(k);
                        int res = 0;
                        try {
                            //插入資料
                            res = insert(unabled, userId);
                            System.out.println("使用者新增/更新成功:" + unabled.getF_1402() + ":" + unabled.getF_1403());
                        } catch (Exception e) {
                            System.out.println("使用者新增失敗:" + unabled.getF_1402() + ":" + unabled.getF_1403());
                        }
                        if (res == 0) {
                            map.put(unabled.getF_1402(), unabled);
                        }
                    }
                   //如果計數到達零,則釋放所有等待的執行緒
                    countDownLatch.countDown();
                    System.out.println(Thread.currentThread().getName() + ":" + System.currentTimeMillis());
                }
            });
        }

        countDownLatch.await();
        threadPoolExecutor.shutdown();
        for (String key : map.keySet()) {
            log.info("匯入失敗:" + key);
            System.out.println("匯入失敗:" + key);
            throw new Exception("匯入失敗: " + key+",該使用者手機號可能被佔用");
        }
        return 0;
    }

 

相關文章