poi實現excel級聯下拉框

poi功能很強大,這裏用來實現一個excel級聯的下拉框

package poiExcel;

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.junit.Test;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author : haojiangtao
 * @Description :
 * @Date : 14:20 2019/11/14
 * @Modify :
 **/
public class MyExcel {
    private static final String PRICE_SHEET_NAME = "PRICE_SHEET_NAME";

    private static final String MODEL_TYPE_SHEET_NAME = "MODEL_TYPE_SHEET_NAME";

    private static final int XLS_MAX_ROW = 65535; //0開始

    @Test
    public void cascadeExcel() {
        List<String> headers = Arrays.asList("耗材類型", "品牌型號", "數量", "價格");
        List<Integer> priceList = Arrays.asList(50, 100, 1000, 1200);
        List<String> typeList = Arrays.asList("鼠標", "鍵盤", "電腦");
        Map<String, List<String>> typeModelMap = new HashMap<>();
        typeModelMap.put("鼠標", Arrays.asList("雷蛇鼠標", "賽睿鼠標", "櫻桃鼠標"));
        typeModelMap.put("鍵盤", Arrays.asList("87鍵盤", "104鍵盤"));
        typeModelMap.put("電腦", Arrays.asList("惠普", "戴爾"));
        MyExcel.createStoreInExcelTemplate("f:/類型型號.xls", headers,
                priceList, typeList, typeModelMap);
    }

    private static void createStoreInExcelTemplate(String filePath, List<String> headers, List<Integer> priceList,
                                                   List<String> typeList, Map<String, List<String>> typeModelMap) {
        FileOutputStream out = null;
        File file;
        try {
            //指定文件
            file = new File(filePath);
            //文件流
            out = new FileOutputStream(file);
            //工作簿
            HSSFWorkbook wb = new HSSFWorkbook();
            HSSFSheet mainSheet = wb.createSheet("sheet1");
            //將存儲下拉框數據的sheet隱藏
            //wb.setSheetHidden(2, true);
            HSSFSheet typeModelSheet = wb.createSheet("sheet2");
            HSSFSheet priceSheet = wb.createSheet("sheet3");
            //初始化表頭數據
            initHeaders(wb, mainSheet, headers);
            //價格下拉框,類型型號下拉框
            initPrice(wb, priceSheet, priceList);
            initTypeAndModel(wb, typeModelSheet, typeList, typeModelMap);
            //在主sheet裏面設置下拉框校驗
            initSheetNameMapping(mainSheet);
            //在主sheet裏面設置數量校驗
            initCount(mainSheet);
            out.flush();
            wb.write(out);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 初始化表頭
     *
     * @param wb
     * @param mainSheet
     * @param headers
     */
    private static void initHeaders(HSSFWorkbook wb, HSSFSheet mainSheet, List<String> headers) {
        //表頭樣式,居中加粗
        HSSFCellStyle style = wb.createCellStyle();
        boldStyle(wb, centerStyle(style));

        //生成sheet1內容,第一個sheet的第一行爲標題
        HSSFRow rowFirst = mainSheet.createRow(0);
        //凍結第一行
        mainSheet.createFreezePane(0, 1, 0, 1);
        //寫標題
        for (int i = 0; i < headers.size(); i++) {
            HSSFCell cell = rowFirst.createCell(i); //獲取第一行的每個單元格
            mainSheet.setColumnWidth(i, 4000); //設置每列的列寬
            cell.setCellStyle(style); //加樣式
            cell.setCellValue(headers.get(i)); //往單元格里寫數據
        }
    }

    /**
     * 居中
     *
     * @param cellStyle
     * @return
     */
    public static CellStyle centerStyle(CellStyle cellStyle) {
        // 創建一個居中格式
        cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        return cellStyle;
    }

    /**
     * 加粗
     *
     * @param workbook
     * @param cellStyle
     * @return
     */
    public static CellStyle boldStyle(Workbook workbook, CellStyle cellStyle) {
        Font fontStyle = workbook.createFont();
        fontStyle.setFontName("微軟雅黑");
        fontStyle.setFontHeightInPoints((short) 12);
        fontStyle.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        cellStyle.setFont(fontStyle);
        return cellStyle;
    }

    /**
     * 設置價格下拉框1.設置值 2.設置下拉框
     *
     * @param wb
     * @param priceSheet
     * @param priceList
     */
    private static void initPrice(HSSFWorkbook wb, HSSFSheet priceSheet, List<Integer> priceList) {
        writePrice(wb, priceSheet, priceList);
        initPriceNameMapping(wb, priceSheet.getSheetName(), priceList.size());
    }

    /**
     * 設置價格下拉框1.設置值
     *
     * @param wb
     * @param priceSheet
     * @param priceList
     */
    private static void writePrice(HSSFWorkbook wb, HSSFSheet priceSheet, List<Integer> priceList) {
        for (int i = 0; i < priceList.size(); i++) {
            HSSFRow row = priceSheet.createRow(i);
            HSSFCell cell = row.createCell(0);
            cell.setCellValue(priceList.get(i));
        }
    }

    /**
     * 設置價格下拉框2.設置下拉框
     *
     * @param workbook
     * @param sheetName
     * @param priceCount
     */
    private static void initPriceNameMapping(HSSFWorkbook workbook, String sheetName, int priceCount) {
        Name name = workbook.createName();
        name.setNameName(PRICE_SHEET_NAME);
        name.setRefersToFormula(sheetName + "!$A$1:$A$" + priceCount);
    }

    /**
     * 設置類型型號級聯下拉框 1.設置類型值 2.設置型號下拉框 3.設置類型級聯下拉框
     *
     * @param workbook
     * @param tmSheet
     * @param typeList
     * @param typeModelMap
     */
    private static void initTypeAndModel(HSSFWorkbook workbook, HSSFSheet tmSheet,
                                         List<String> typeList, Map<String, List<String>> typeModelMap) {
        writeTypes(workbook, tmSheet, typeList);
        writeModels(workbook, tmSheet, typeList, typeModelMap);
        initTypeNameMapping(workbook, tmSheet.getSheetName(), typeList.size());
    }

    /**
     * 設置類型型號級聯下拉框 1.設置類型值
     *
     * @param workbook
     * @param modelTypeSheet
     * @param typeList
     */
    private static void writeTypes(HSSFWorkbook workbook, HSSFSheet modelTypeSheet, List<String> typeList) {
        HSSFRow row = modelTypeSheet.getRow(0) == null ? modelTypeSheet.createRow(0)
                : modelTypeSheet.createRow(0);
        HSSFCellStyle cellStyle = workbook.createCellStyle();
        boldStyle(workbook, cellStyle);
        //if (CollectionUtils.isNotEmpty(modelList)) {
        if (null != typeList) {
            for (int i = 0; i < typeList.size(); i++) {
                HSSFCell cell = row.getCell(i) == null ? row.createCell(i) : row.getCell(i);
                cell.setCellValue(typeList.get(i));
                cell.setCellStyle(cellStyle);
            }
        }
    }

    /**
     * 設置類型型號級聯下拉框 2.設置型號下拉框
     *
     * @param workbook
     * @param tmSheet
     * @param typeList
     * @param typeModelMap
     */
    private static void writeModels(HSSFWorkbook workbook, HSSFSheet tmSheet,
                                    List<String> typeList, Map<String, List<String>> typeModelMap) {
        for (int i = 0; i < typeList.size(); i++) {
            String typeName = typeList.get(i);
            List<String> modelList = typeModelMap.get(typeName);
            //if (CollectionUtils.isNotEmpty(modelList)) {
            if (null != modelList) {
                for (int j = 0; j < modelList.size(); j++) {
                    HSSFRow row = tmSheet.getRow(j + 1) == null ? tmSheet.createRow(j + 1)
                            : tmSheet.getRow(j + 1);
                    HSSFCell cell = row.getCell(i) == null ? row.createCell(i) : row.getCell(i);
                    cell.setCellValue(modelList.get(j));
                }
            }
            initModelNameMapping(workbook, tmSheet.getSheetName(), typeName, i, modelList.size());
        }
    }


    private static void initModelNameMapping(HSSFWorkbook workbook, String tmSheetName,
                                             String typeName, int referCol, int modelCount) {
        Name name = workbook.createName();
        name.setNameName(typeName);
        //modelCount + 1 = modelCount + 2 -1
        name.setRefersToFormula(tmSheetName + "!$" + getColumnName(referCol) +
                "$2:$" + getColumnName(referCol) + "$" + (modelCount + 1));
    }

    /**
     * 3.設置類型級聯下拉框
     *
     * @param workbook
     * @param tmSheetName
     * @param typeCount
     */
    private static void initTypeNameMapping(HSSFWorkbook workbook, String tmSheetName, int typeCount) {
        Name name = workbook.createName();
        name.setNameName(MODEL_TYPE_SHEET_NAME);
        name.setRefersToFormula(tmSheetName + "!$A$1:$" + getColumnName(typeCount - 1) + "$1");
    }

    /**
     * 轉換爲A,B,C,D的列
     * @param index
     * @return
     */
    public static String getColumnName(int index) {
        StringBuilder s = new StringBuilder();
        while (index >= 26) {
            s.insert(0, (char) ('A' + index % 26));
            index = index / 26 - 1;
        }
        s.insert(0, (char) ('A' + index));
        return s.toString();
    }

    /**
     * 在主sheet裏面設置
     *
     * @param sheet
     */
    private static void initSheetNameMapping(HSSFSheet sheet) {
        DataValidation typeValidation = getDataValidationByFormula(MODEL_TYPE_SHEET_NAME, 0);

        DataValidation shelfValidation = getDataValidationByFormula("INDIRECT($A1)", 1);
        DataValidation priceValidation = getDataValidationByFormula(PRICE_SHEET_NAME, 3);
        // 主sheet添加驗證數據
        sheet.addValidationData(typeValidation);
        sheet.addValidationData(shelfValidation);
        sheet.addValidationData(priceValidation);
    }

    public static DataValidation getDataValidationByFormula(String formulaString, int columnIndex) {
        // 加載下拉列表內容
        DVConstraint constraint = DVConstraint.createFormulaListConstraint(formulaString);
        // 設置數據有效性加載在哪個單元格上。
        // 四個參數分別是:起始行、終止行、起始列、終止列
        CellRangeAddressList regions = new CellRangeAddressList(1, XLS_MAX_ROW, columnIndex, columnIndex);
        // 數據有效性對象
        DataValidation dataValidationList = new HSSFDataValidation(regions, constraint);
        dataValidationList.createErrorBox("Error", "請選擇或輸入有效的選項,或下載最新模版重試!");
        String promptText = initPromptText(columnIndex);
        dataValidationList.createPromptBox("", promptText);
        return dataValidationList;
    }

    private static DataValidation getDecimalValidation(int firstRow, int lastRow, int columnIndex) {
        // 創建一個規則:>0的整數
        DVConstraint constraint = DVConstraint.createNumericConstraint(DVConstraint.ValidationType.INTEGER, DVConstraint.OperatorType.GREATER_OR_EQUAL, "0", "0");
        // 設定在哪個單元格生效
        CellRangeAddressList regions = new CellRangeAddressList(firstRow, lastRow, columnIndex, columnIndex);
        // 創建規則對象
        HSSFDataValidation decimalVal = new HSSFDataValidation(regions, constraint);
        decimalVal.createPromptBox("", initPromptText(columnIndex));
        decimalVal.createErrorBox("輸入值類型或大小有誤!", "數值型,請輸入大於0 的整數。");
        return decimalVal;
    }

    private static String initPromptText(int columnIndex) {
        String promptText = "";
        switch (columnIndex) {
            case 1:
                promptText = "請下拉選擇或輸入有效項!且先選擇類型!";
                break;
            case 3:
                promptText = "請輸入大於0的整數!";
                break;
        }
        return promptText;
    }

    /**
     * 在主sheet中校驗數量
     * @param mainSheet
     */
    private static void initCount(HSSFSheet mainSheet) {
        DataValidation quantityValidation = getDecimalValidation(1, XLS_MAX_ROW, 2);
        mainSheet.addValidationData(quantityValidation);
    }

}

在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述

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