1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        注解+反射優(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ái)系統(tǒng)的時(shí)候會(huì)很頻繁的遇到Excel導(dǎo)入導(dǎo)出的問題,正好這次在做一個(gè)后臺(tái)系統(tǒng),就想著寫一個(gè)公用工具來進(jìn)行Excel的導(dǎo)入導(dǎo)出。

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

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

        • 導(dǎo)出方法接收一個(gè)list集合,和一個(gè)Class類型,和HttpServletResponse 對(duì)象
        • 導(dǎo)出是可能會(huì)有下拉列表,所以需要一個(gè)map存儲(chǔ)下拉列表數(shù)據(jù)源,傳入?yún)?shù)后只需一行代碼即可導(dǎo)出
        • 導(dǎo)入方法需要傳入file文件,以及一個(gè)Class類型,導(dǎo)入之后將會(huì)返回一個(gè)list集合,里面的對(duì)象就是傳入類型的對(duì)象,傳入?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è)注解的字段才會(huì)導(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中的列對(duì)應(yīng)的序號(hào)

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

        }

        注解使用示例

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

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

        我們根據(jù)傳入的類型上面的字段注解的順序來分別為不同的字段賦值,然后存入集合中,再返回

        代碼如下:

        /**
         * 將Excel轉(zhuǎn)換為對(duì)象集合
         * @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è)方法是自定義方法,代碼會(huì)貼在后面

        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ù)(返回對(duì)象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版

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

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

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

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


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

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

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            女人18片毛片120分钟免费观看 | 亚洲AV成人片无码网站 | 伊人无码视频 | 午夜成人精品一区二区三区在线观看 | 含羞草实验室隐藏路径2023 | 操逼试频| 无遮挡免费观看 | 国产精品私拍pans大尺度在线 | 亚洲AV无码成人精品区 | 操逼黄色电影 |