<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          利用注解+反射優(yōu)雅的實現(xiàn)通用Excel導(dǎo)入導(dǎo)出

          共 20853字,需瀏覽 42分鐘

           ·

          2021-07-30 22:50

          點擊上方藍色字體,選擇“標星公眾號”

          優(yōu)質(zhì)文章,第一時間送達

          日常在做后臺系統(tǒng)的時候會很頻繁的遇到Excel導(dǎo)入導(dǎo)出的問題,正好這次在做一個后臺系統(tǒng),就想著寫一個公用工具來進行Excel的導(dǎo)入導(dǎo)出。
          一般我們在導(dǎo)出的時候都是導(dǎo)出的前端表格,而前端表格同時也會對應(yīng)的在后臺有一個映射類。
          所以在寫這個工具的時候我們先理一下我們需要實現(xiàn)的效果:

          1. 導(dǎo)出方法接收一個list集合,和一個Class類型,和HttpServletResponse 對象

          2. 導(dǎo)出是可能會有下拉列表,所以需要一個map存儲下拉列表數(shù)據(jù)源,傳入?yún)?shù)后只需一行代碼即可導(dǎo)出

          3. 導(dǎo)入方法需要傳入file文件,以及一個Class類型,導(dǎo)入之后將會返回一個list集合,里面的對象就是傳入類型的對象,傳入?yún)?shù)后只需一行代碼即可導(dǎo)入

          實現(xiàn)過程:
          首先需要創(chuàng)建三個注解
          一個是EnableExport ,必須有這個注解才能導(dǎo)出

          /**
           * 設(shè)置允許導(dǎo)出
           */
          @Target(ElementType.TYPE)
          @Retention(RetentionPolicy.RUNTIME)
          public @interface EnableExport {
               String fileName();

          }


          然后就是EnableExportField,有這個注解的字段才會導(dǎo)出到Excel里面,并且可以設(shè)置列寬

          /**
           * 設(shè)置該字段允許導(dǎo)出
           * 并且可以設(shè)置寬度
           */
          @Target(ElementType.FIELD)
          @Retention(RetentionPolicy.RUNTIME)
          public @interface EnableExportField {
               int colWidth() default  100;
               String colName();
          }


          再就是ImportIndex,導(dǎo)入的時候設(shè)置Excel中的列對應(yīng)的序號

          /**
           * 導(dǎo)入時索引
           */
          @Target(ElementType.FIELD)
          @Retention(RetentionPolicy.RUNTIME)
          public @interface ImportIndex {
               int index() ;


          }

          注解使用示例

          三個注解創(chuàng)建好之后就需要開始操作Excel了
          首先,導(dǎo)入方法。在后臺接收到前端上傳的Excel文件之后,使用poi來讀取Excel文件
          我們根據(jù)傳入的類型上面的字段注解的順序來分別為不同的字段賦值,然后存入集合中,再返回
          代碼如下:


          /**
               * 將Excel轉(zhuǎn)換為對象集合
               * @param excel Excel 文件
               * @param clazz pojo類型
               * @return
               */
              public static List<Object> parseExcelToList(File excel,Class clazz){
                  List<Object> res = new ArrayList<>();
                  // 創(chuàng)建輸入流,讀取Excel
                  InputStream is = null;
                  Sheet sheet = null;
                  try {
                      is = new FileInputStream(excel.getAbsolutePath());
                      if (is != null) {
                          Workbook workbook = WorkbookFactory.create(is);
                          //默認只獲取第一個工作表
                          sheet = workbook.getSheetAt(0);
                          if (sheet != null) {
                           //前兩行是標題
                              int i = 2;
                              String values[] ;
                              Row row = sheet.getRow(i);
                              while (row != null) {
                                  //獲取單元格數(shù)目
                                  int cellNum = row.getPhysicalNumberOfCells();
                                  values = new String[cellNum];
                                  for (int j = 0; j <= cellNum; j++) {
                                      Cell cell =   row.getCell(j);
                                      if (cell != null) {
                                          //設(shè)置單元格內(nèi)容類型
                                          cell.setCellType(Cell.CELL_TYPE_STRING );
                                          //獲取單元格值
                                          String value = cell.getStringCellValue() == null ? null : cell.getStringCellValue();
                                          values[j]=value;
                                      }
                                  }
                                  Field[] fields = clazz.getDeclaredFields();
                                  Object obj = clazz.newInstance();
                                  for(Field f : fields){
                                      if(f.isAnnotationPresent(ImportIndex.class)){
                                          ImportIndex annotation = f.getDeclaredAnnotation(ImportIndex.class);
                                          int index = annotation.index();
                                          f.setAccessible(true);
                                          //此處使用了阿里巴巴的fastjson包里面的一個類型轉(zhuǎn)換工具類
                                          Object val =TypeUtils.cast(values[index],f.getType(),null);
                                          f.set(obj,val);
                                      }
                                  }
                                  res.add(obj);
                                  i++;
                                  row=sheet.getRow(i);
                              }

                          }
                      }
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
                  return res;
              }


          接下來就是導(dǎo)出方法
          導(dǎo)出分為幾個步驟:

          1. 建立一個工作簿,也就是類型新建一個Excel文件

          2. 建立一張sheet表

          3. 設(shè)置標的行高和列寬

          4. 繪制標題和表頭

            這兩個方法是自定義方法,代碼會貼在后面

          5. 寫入數(shù)據(jù)到Excel

          6. 創(chuàng)建下拉列表

          7. 寫入文件到response

            到這里導(dǎo)出工作就完成了
            下面是一些自定義方法的代碼

            /**
               * 獲取一個基本的帶邊框的單元格
               * @param workbook
               * @return
               */
              private static HSSFCellStyle getBasicCellStyle(HSSFWorkbook workbook){
                  HSSFCellStyle hssfcellstyle = workbook.createCellStyle();
                  hssfcellstyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
                  hssfcellstyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
                  hssfcellstyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
                  hssfcellstyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
                  hssfcellstyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
                  hssfcellstyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
                  hssfcellstyle.setWrapText(true);
                  return hssfcellstyle;
              }

              /**
               * 獲取帶有背景色的標題單元格
               * @param workbook
               * @return
               */
              private static HSSFCellStyle getTitleCellStyle(HSSFWorkbook workbook){
                  HSSFCellStyle hssfcellstyle =  getBasicCellStyle(workbook);
                  hssfcellstyle.setFillForegroundColor((short) HSSFColor.CORNFLOWER_BLUE.index); // 設(shè)置背景色
                  hssfcellstyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
                  return hssfcellstyle;
              }

              /**
               * 創(chuàng)建一個跨列的標題行
               * @param workbook
               * @param hssfRow
               * @param hssfcell
               * @param hssfsheet
               * @param allColNum
               * @param title
               */
              private static void createTitle(HSSFWorkbook workbook, HSSFRow hssfRow , HSSFCell hssfcell, HSSFSheet hssfsheet,int allColNum,String title){
                  //在sheet里增加合并單元格
                  CellRangeAddress cra = new CellRangeAddress(0, 0, 0, allColNum);
                  hssfsheet.addMergedRegion(cra);
                  // 使用RegionUtil類為合并后的單元格添加邊框
                  RegionUtil.setBorderBottom(1, cra, hssfsheet, workbook); // 下邊框
                  RegionUtil.setBorderLeft(1, cra, hssfsheet, workbook); // 左邊框
                  RegionUtil.setBorderRight(1, cra, hssfsheet, workbook); // 有邊框
                  RegionUtil.setBorderTop(1, cra, hssfsheet, workbook); // 上邊框

                  //設(shè)置表頭
                  hssfRow = hssfsheet.getRow(0);
                  hssfcell = hssfRow.getCell(0);
                  hssfcell.setCellStyle( getTitleCellStyle(workbook));
                  hssfcell.setCellType(HSSFCell.CELL_TYPE_STRING);
                  hssfcell.setCellValue(title);
              }

              /**
               * 設(shè)置表頭標題欄以及表格高度
               * @param workbook
               * @param hssfRow
               * @param hssfcell
               * @param hssfsheet
               * @param colNames
               */
              private static void createHeadRow(HSSFWorkbook workbook,HSSFRow hssfRow , HSSFCell hssfcell,HSSFSheet hssfsheet,List<String> colNames){
                  //插入標題行
                  hssfRow = hssfsheet.createRow(1);
                  for (int i = 0; i < colNames.size(); i++) {
                      hssfcell = hssfRow.createCell(i);
                      hssfcell.setCellStyle(getTitleCellStyle(workbook));
                      hssfcell.setCellType(HSSFCell.CELL_TYPE_STRING);
                      hssfcell.setCellValue(colNames.get(i));
                  }
              }
              /**
               * excel添加下拉數(shù)據(jù)校驗
               * @param sheet 哪個 sheet 頁添加校驗
               * @return
               */
              public static void createDataValidation(Sheet sheet,Map<Integer,String[]> selectListMap) {
                  if(selectListMap!=null) {
                      selectListMap.forEach(
                              // 第幾列校驗(0開始)key 數(shù)據(jù)源數(shù)組value
                              (key, value) -> {
                                  if(value.length>0) {
                                      CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(2, 65535, key, key);
                                      DataValidationHelper helper = sheet.getDataValidationHelper();
                                      DataValidationConstraint constraint = helper.createExplicitListConstraint(value);
                                      DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
                                      //處理Excel兼容性問題
                                      if (dataValidation instanceof XSSFDataValidation) {
                                          dataValidation.setSuppressDropDownArrow(true);
                                          dataValidation.setShowErrorBox(true);
                                      } else {
                                          dataValidation.setSuppressDropDownArrow(false);
                                      }
                                      dataValidation.setEmptyCellAllowed(true);
                                      dataValidation.setShowPromptBox(true);
                                      dataValidation.createPromptBox("提示""只能選擇下拉框里面的數(shù)據(jù)");
                                      sheet.addValidationData(dataValidation);
                                  }
                              }
                      );
                  }
              }


          使用實例
          導(dǎo)出數(shù)據(jù)

          導(dǎo)入數(shù)據(jù)(返回對象List)

            作者 |  _JenKin

          來源 |  csdn.net/youzi1394046585/article/details/86670203


          加鋒哥微信: java3459  
          圍觀鋒哥朋友圈,天天推送Java干貨!

          瀏覽 78
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天干天天草 | 成人日日夜夜av 成人三级电影久久 | 国产黄色中文字幕 | 仓井空一区二区三区 | 日韩精品人妻一区二区 |