<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)雅的實(shí)現(xiàn)Excel導(dǎo)入導(dǎo)出(通用版),飄了!

          共 17078字,需瀏覽 35分鐘

           ·

          2022-04-24 19:57

          責(zé)編:架構(gòu)君 | 來源:blog.csdn.net/youzi1394046585/article/details/86670203



             大家好,我是程序汪。


          日常在做后臺系統(tǒng)的時(shí)候會很頻繁的遇到Excel導(dǎo)入導(dǎo)出的問題,正好這次在做一個(gè)后臺系統(tǒng),就想著寫一個(gè)公用工具來進(jìn)行Excel的導(dǎo)入導(dǎo)出。

          一般我們在導(dǎo)出的時(shí)候都是導(dǎo)出的前端表格,而前端表格同時(shí)也會對應(yīng)的在后臺有一個(gè)映射類。

          所以在寫這個(gè)工具時(shí)我們先理一下需要實(shí)現(xiàn)的效果:

          • 導(dǎo)出方法接收一個(gè)list集合,和一個(gè)Class類型,和HttpServletResponse 對象
          • 導(dǎo)出是可能會有下拉列表,所以需要一個(gè)map存儲下拉列表數(shù)據(jù)源,傳入?yún)?shù)后只需一行代碼即可導(dǎo)出
          • 導(dǎo)入方法需要傳入file文件,以及一個(gè)Class類型,導(dǎo)入之后將會返回一個(gè)list集合,里面的對象就是傳入類型的對象,傳入?yún)?shù)后只需一行代碼即可導(dǎo)入

          實(shí)現(xiàn)過程:

          首先需要?jiǎng)?chuàng)建三個(gè)注解

          一個(gè)是EnableExport ,必須有這個(gè)注解才能導(dǎo)出

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

          }

          然后就是EnableExportField,有這個(gè)注解的字段才會導(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í)候設(shè)置Excel中的列對應(yīng)的序號

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

          }

          注解使用示例

          三個(gè)注解創(chuàng)建好之后就需要開始操作Excel了

          首先,導(dǎo)入方法。在后臺接收到前端上傳的Excel文件之后,使用poi來讀取Excel文件。擴(kuò)展:接私活

          我們根據(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);
                      //默認(rèn)只獲取第一個(gè)工作表
                      sheet = workbook.getSheetAt(0);
                      if (sheet != null) {
                       //前兩行是標(biāo)題
                          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包里面的一個(gè)類型轉(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)出分為幾個(gè)步驟:

          1. 建立一個(gè)工作簿,也就是類型新建一個(gè)Excel文件
          1. 建立一張sheet表
          1. 設(shè)置標(biāo)的行高和列寬
          1. 繪制標(biāo)題和表頭

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

          1. 寫入數(shù)據(jù)到Excel
          1. 創(chuàng)建下拉列表
          1. 寫入文件到response

          到這里導(dǎo)出工作就完成了

          下面是一些自定義方法的代碼

          /**
           * 獲取一個(gè)基本的帶邊框的單元格
           * @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;
          }

          /**
           * 獲取帶有背景色的標(biāo)題單元格
           * @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)建一個(gè)跨列的標(biāo)題行
           * @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è)置表頭標(biāo)題欄以及表格高度
           * @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){
              //插入標(biāo)題行
              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ù)校驗(yàn)
           * @param sheet 哪個(gè) sheet 頁添加校驗(yàn)
           * @return
           */
          public static void createDataValidation(Sheet sheet,Map<Integer,String[]> selectListMap) {
              if(selectListMap!=null) {
                  selectListMap.forEach(
                          // 第幾列校驗(yàn)(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);
                              }
                          }
                  );
              }
          }

          使用實(shí)例

          導(dǎo)出數(shù)據(jù)


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


          源碼地址:

          https://github.com/xyz0101/excelutils


          PS:如果覺得我的分享不錯(cuò),歡迎大家隨手點(diǎn)贊、轉(zhuǎn)發(fā)、在看。

          程序汪資料鏈接

          程序汪接的7個(gè)私活都在這里,經(jīng)驗(yàn)整理

          Java項(xiàng)目分享  最新整理全集,找項(xiàng)目不累啦 07版

          堪稱神級的Spring Boot手冊,從基礎(chǔ)入門到實(shí)戰(zhàn)進(jìn)階

          臥槽!字節(jié)跳動《算法中文手冊》火了,完整版 PDF 開放下載!

          臥槽!阿里大佬總結(jié)的《圖解Java》火了,完整版PDF開放下載!

          字節(jié)跳動總結(jié)的設(shè)計(jì)模式 PDF 火了,完整版開放下載!


          歡迎添加程序汪個(gè)人微信 itwang009  進(jìn)粉絲群或圍觀朋友圈

          瀏覽 23
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  精品乱伦无码 | 欧美精品超级AAAAAA | chaopeng视频在线观看 | 亚洲字幕在线观看 | 黑人大香蕉伊人 |