Java EXCEL 表格导入导出(带下拉选-带VLOOKUP函数封装)

Java EXCEL 表格导入导出(带下拉选-带VLOOKUP函数封装)

对于excel Java POI 使用
目前简单导出导入功能网上很多,但是对于有下拉选,样式等缺点却是最大硬伤,故此封装一个通用点的Excel 表格工具类,方便大家使用!

  • 模板数据填充
  • 下拉选数据规则
  • 导出实体类映射

本次工具类设计工作原理

1.你需要有一个模板 把样式设置好
2.需要有三个工作簿

2.1第一个是用户使用的添加数据的, 第二个是下拉选项,第三个是列对应后台实体类属性,只不过是第二个和第三个工作薄在代码中读取后会自动为您隐藏

直接上图
模板下载工作表

  • 一定要看下边俩个图哦.

额外说明注意哦
在这里插入图片描述

表格工具类

package com.techhero.base.exam.utils.excel;

import com.techhero.base.exam.model.abs.ExcelList;
import com.techhero.base.exam.model.abs.ExcelTemplateModel;
import com.techhero.base.exam.model.abs.OptionNode;
import com.techhero.base.exam.model.abs.SelectOption;
import com.techhero.common.utils.req.CMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidation;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STDataValidationErrorStyle;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STDataValidationType;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class ExcelUtils {
    
    /**
     * 导入数据
     * 根据传入的实体对象,将数据构建成一个List
     */
    public static <T> ExcelList<T> importData(MultipartFile multipartFile, Integer readFirstIndex, Class clazz, String... validName) {
        Workbook workBook = getWorkbook(multipartFile);
        
        /*列名工作区*/
        assert workBook != null;
        Sheet colNameSheet = workBook.getSheetAt(2);
        
        /*第一行*/
        Row row = colNameSheet.getRow(0);
        
        /*获取表格中定义的列名称(一般对应Class中的字段)*/
        List<String> excelColNames = new ArrayList<>(row.getLastCellNum());
        for (int i = 0; i < row.getLastCellNum(); i++) {
            Cell cell = row.getCell(i);
            excelColNames.add(cell.getStringCellValue());
        }
        
        /*数据工作薄*/
        Sheet dataSheet = workBook.getSheetAt(0);
        
        int           lastRowNum   = dataSheet.getLastRowNum();
        ExcelList<T>  list         = new ExcelList<>();
        List<Integer> errorRowNums = new ArrayList<>();
        validFor:
        for (int i = readFirstIndex - 1; i < lastRowNum; i++) {
            Row dataRow = dataSheet.getRow(i);
            
            /*Map对应一行数据*/
            Map<String, String> beanMap = new HashMap<>(excelColNames.size());
            for (int n = 0; n < excelColNames.size(); n++) {
                Cell   cell      = dataRow.getCell(n);
                String cellValue = getCellValue(cell);
                
                if (n == 0 && StringUtils.isBlank(cellValue)) {
                    break validFor;
                }
                
                beanMap.put(excelColNames.get(n), cellValue);
            }
            
            /*校验数据为空合法性*/
            if (validName != null) {
                for (int k = 0; k < validName.length; k++) {
                    if (beanMap.get(validName[k]) == null && StringUtils.isNotEmpty(beanMap.get(validName[k]))) {
                        errorRowNums.add(i);
                        continue validFor;
                    }
                }
            }
            
            try {
                T o = (T) clazz.newInstance();
                
                ConvertUtils.register(new Converter() {
                    public Object convert(Class type, Object value) {
                        if (value != null) {
                            try {
                                return DateUtils.parseDate(value.toString(),
                                        "yyyy-MM-dd HH:mm:ss",
                                        "yyyy-MM-dd HH:mm",
                                        "yyyy-MM-dd",
                                        "yyyy/MM/dd HH:mm:ss",
                                        "yyyy/MM/dd HH:mm",
                                        "yyyy/MM/dd",
                                        "yyyyMMdd HH:mm:ss",
                                        "yyyyMMdd HH:mm",
                                        "yyyyMMdd",
                                        "yyyy年MM月dd日 HH:mm:ss",
                                        "yyyy年MM月dd日 HH:mm",
                                        "yyyy年MM月dd日",
                                        "yyyyMMddHHmmss");
                            } catch (ParseException e) {
                                log.info("[时间转换失败]");
                                return null;
                            }
                        }
                        return null;
                    }
                }, Date.class);
                
                /*将Map中的属性拷贝到实体类中*/
                BeanUtils.populate(o, beanMap);
                list.add(o);
            } catch (Exception e) {
                log.info("[数据导入-{}条数据有问题]", i, e);
            }
        }
        
        list.setErrorRows(errorRowNums);
        
        Row    supperDataRow = dataSheet.getRow(1);
        Cell   cell          = supperDataRow.getCell(0);
        String supperData    = cell.getStringCellValue();
        
        list.setSupperData(supperData);
        return list;
    }
    
    public static String getCellValue(Cell cell) {
        String cellValue = "";
        if (cell == null) {
            return cellValue;
        }
        // 判断数据的类型
        switch (cell.getCellTypeEnum()) {
            case NUMERIC: // 数字
                //short s = cell.getCellStyle().getDataFormat();
                if (HSSFDateUtil.isCellDateFormatted(cell)) {// 处理日期格式、时间格式
                    SimpleDateFormat sdf;
                    // 验证short值
                    if (cell.getCellStyle().getDataFormat() == 14) {
                        sdf = new SimpleDateFormat("yyyy/MM/dd");
                    } else if (cell.getCellStyle().getDataFormat() == 21) {
                        sdf = new SimpleDateFormat("HH:mm:ss");
                    } else if (cell.getCellStyle().getDataFormat() == 22) {
                        sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                    } else {
                        sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    }
                    Date date = cell.getDateCellValue();
                    cellValue = sdf.format(date);
                } else if (cell.getCellStyle().getDataFormat() == 0) {//处理数值格式
                    cell.setCellType(CellType.STRING);
                    cellValue = String.valueOf(cell.getRichStringCellValue().getString());
                }
                break;
            case STRING: // 字符串
                cellValue = String.valueOf(cell.getStringCellValue());
                break;
            case BOOLEAN: // Boolean
                cellValue = String.valueOf(cell.getBooleanCellValue());
                break;
            case FORMULA: // 公式
                try {
                    cellValue = String.valueOf(cell.getStringCellValue());
                } catch (Exception exception) {
                    cellValue = String.valueOf(cell.getNumericCellValue());
                }
                break;
            case BLANK: // 空值
                cellValue = null;
                break;
            case ERROR: // 故障
                cellValue = "非法";
                break;
            default:
                cellValue = "未知";
                break;
        }
        return cellValue;
    }
    
    /*获取工作簿*/
    public static Workbook getWorkbook(MultipartFile multipartFile) {
        String originalFilename = multipartFile.getOriginalFilename();
        String fileType         = originalFilename.substring(originalFilename.lastIndexOf("."));
        try {
            return getWorkbook(multipartFile.getInputStream(), fileType);
        } catch (IOException e) {
            log.error("EXCEL 导入 操作失败!", e);
            return null;
        }
    }
    
    /*获取工作簿*/
    public static Workbook getWorkbook(InputStream inStr, String fileName) {
        String fileType = fileName.substring(fileName.lastIndexOf("."));
        try {
            if (".xls".equals(fileType)) {
                return new XSSFWorkbook(inStr);
            }
            return new XSSFWorkbook(inStr);
        } catch (IOException e) {
            return null;
        }
    }
    
    /*Excel模板下载*/
    public static void downLoadExcelTemplate(HttpServletResponse response, ExcelTemplateModel model) {
        log.info("[EXCEL TOOL BUILDER -- BUILDER PARAMS LOOK]\n{}", model);
        
        /*初始化模板行*/
        model.initTemplateInitRowSize();
        Workbook workbook = downLoadExcelTemplate(model);
        
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            response.setContentType("application/vnd.ms-excel");
            response.addHeader("Cache-Control", "no-cache, no-store, must-revalidate");
            response.addHeader("charset", "utf-8");
            response.addHeader("Pragma", "no-cache");
            String encodeName = URLEncoder.encode(model.getExcelName(), StandardCharsets.UTF_8.toString());
            response.setHeader("Content-Disposition", "attachment; filename=\"" + encodeName + "\"; filename*=utf-8''" + encodeName);
            
            assert workbook != null;
            workbook.write(outputStream);
        } catch (IOException e) {
            log.info("[下载Excel模板失败!]", e);
        }
    }
    
    /*获取下载Excel模板*/
    public static Workbook downLoadExcelTemplate(ExcelTemplateModel model) {
        /*创建工作薄*/
        try {
            XSSFWorkbook workBook = new XSSFWorkbook(model.getResourceTemplateFile());
            
            /*头部设置*/
            if (model.isHasHand()) {
                handHandler(workBook, model);
            }
            
            /*下拉设定*/
            if (model.isHasSelectOptions()) {
                /*列名称处理*/
                colNamesHandler(workBook, model);
                
                /*下拉选数据填充*/
                loadSelectOptionHandler(workBook, model);
                
                /*绑定下拉选*/
                bindSelectOptionHandler(workBook, model);
                
                /*绑定下拉选对应编码函数*/
                bindSelectOptionCodeHandler(workBook, model);
                
                /*编码列隐藏处理*/
                hiddenColHandler(workBook, model);
                
            }
            
            return workBook;
        } catch (Exception exception) {
            log.error("[下载模板-{}]==>异常", model.getFilePath(), exception);
        }
        
        return null;
        
    }
    
    /*编码列隐藏处理*/
    private static void hiddenColHandler(XSSFWorkbook workBook, ExcelTemplateModel model) {
        /*模板工作薄*/
        XSSFSheet templateSheet = workBook.getSheetAt(0);
        
        if (model.isHasSelectOptions()) {
            model.getSelectOptions().forEach(selectOption -> templateSheet.setColumnHidden(selectOption.getColNameCodeIndex(), selectOption.isCodeColHiddenFlag()));
        }
        
    }
    
    /*绑定下拉选对应编码函数*/
    private static void bindSelectOptionCodeHandler(XSSFWorkbook workBook, ExcelTemplateModel model) {
        
        final String[] colNames = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
        
        /*模板工作薄*/
        XSSFSheet templateSheet = workBook.getSheetAt(0);
        
        /*下拉选数据工作簿*/
        XSSFSheet optionDataSheet = workBook.getSheetAt(1);
        String    sheetName       = optionDataSheet.getSheetName();
        
        int                templateInitRowSize = model.getTemplateInitRowSize();
        List<SelectOption> selectOptions       = model.getSelectOptions();
        
        if (model.isHasSelectOptions()) {
            for (int i = model.getSelectOptionRowNum() - 1; i < templateInitRowSize; i++) {
                /*创建行*/
                XSSFRow row    = templateSheet.createRow(i);
                int     finalI = i + 1;
                selectOptions.forEach(selectOption -> {
                    
                    if (selectOption.isNeedBindCodeFunction()) {
                        /*创建对应的编码列*/
                        XSSFCell cell = row.createCell(selectOption.getColNameCodeIndex());
                        
                        String cellFormula = "VLOOKUP({0},{1},2,0)";
                        
                        /*当前模板工作薄名称对应列下标*/
                        int colNameIndex = selectOption.getColNameIndex();
                        
                        /*当前模板工作薄名称对应列下标字母*/
                        String colNameForTemplateSheet = colNames[colNameIndex];
                        
                        /*通过那个数据列的数据关联当前表格*/
                        String sourceDataCol = colNameForTemplateSheet + finalI;
                        
                        int    keyColIndex   = selectOption.getKeyColIndex();
                        String keyColName    = colNames[keyColIndex];
                        int    valueColIndex = selectOption.getValueColIndex();
                        String valueColName  = colNames[valueColIndex];
                        
                        String dataArea = sheetName + "!" + valueColName + ":" + keyColName;
                        
                        MessageFormat format = new MessageFormat(cellFormula);
                        cellFormula = format.format(new String[]{sourceDataCol, dataArea});
                        cell.setCellFormula(cellFormula);
                    }
                    
                });
            }
        }
        
    }
    
    /*绑定下拉选*/
    private static void bindSelectOptionHandler(XSSFWorkbook workBook, ExcelTemplateModel model) {
        
        /*模板工作薄*/
        XSSFSheet templateSheet = workBook.getSheetAt(0);
        
        /*下拉选数据工作簿*/
        XSSFSheet optionDataSheet = workBook.getSheetAt(1);
        String    sheetName       = optionDataSheet.getSheetName();
        
        List<SelectOption> selectOptions = model.getSelectOptions();
        
        selectOptions.forEach(selectOption -> templateSheet.addValidationData(getValidationData(sheetName, model, selectOption)));
        
    }
    
    /*设置有效性*/
    private static DataValidation getValidationData(String sheetName, ExcelTemplateModel model, SelectOption selectOption) {
        
        int firstRowNum         = model.getSelectOptionRowNum() - 1;
        int templateInitRowSize = model.getTemplateInitRowSize();
        
        /*对应模板工作薄列下标*/
        int colNameIndex = selectOption.getColNameIndex();
        
        /*唯一属性对应模板工作薄列*/
        int maxRowNum = selectOption.getMaxRowNum();
        
        /*值对应数据薄列*/
        int valueColIndex = selectOption.getValueColIndex();
        
        final String[] colNames = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
        String         colName  = colNames[valueColIndex];
        
        /*有效性表达式*/
        String strFormula = sheetName + "!$" + colName + "$1:$" + colName + "$" + maxRowNum;
        
        XSSFDataValidationConstraint xssfDataValidationConstraint = new XSSFDataValidationConstraint(0x03, strFormula);
        
        /*设置数据有效性加载在哪个单元格上。四个参数分别是:起始行、终止行、起始列、终止列*/
        CellRangeAddressList regions = new CellRangeAddressList(firstRowNum, templateInitRowSize, colNameIndex, colNameIndex);
        
        CTDataValidation   newDataValidation  = CTDataValidation.Factory.newInstance();
        CellRangeAddress[] cellRangeAddresses = regions.getCellRangeAddresses();
        List<String>       ref                = new ArrayList<String>();
        for (int i = 0; i < cellRangeAddresses.length; i++) {
            CellRangeAddress cellRangeAddress = cellRangeAddresses[i];
            ref.add(cellRangeAddress.formatAsString());
        }
        
        newDataValidation.setSqref(ref);
        
        newDataValidation.setType(STDataValidationType.LIST);
        newDataValidation.setFormula1(strFormula);
        newDataValidation.setAllowBlank(true);
        newDataValidation.setErrorStyle(STDataValidationErrorStyle.STOP);
        
        return new XSSFDataValidation(xssfDataValidationConstraint, regions, newDataValidation);
    }
    
    /*下拉选数据填充*/
    private static void loadSelectOptionHandler(XSSFWorkbook workBook, ExcelTemplateModel model) {
        /*下拉选数据工作簿*/
        XSSFSheet optionDataSheet = workBook.getSheetAt(1);
        
        /*设置工作簿名称*/
        workBook.setSheetName(1, "DATA");
        /*设置工作簿隐藏*/
        workBook.setSheetHidden(1, true);
        
        /*下拉选数据*/
        List<SelectOption> selectOptions = model.getSelectOptions();
        
        /*获取最大行号*/
        AtomicInteger maxRowNumAtomicInteger = new AtomicInteger();
        selectOptions.forEach(selectOption -> {
            List<OptionNode> options = selectOption.getOptions();
            if (selectOption.getMaxRowNum() > maxRowNumAtomicInteger.get()) {
                maxRowNumAtomicInteger.set(options.size());
            }
        });
        
        List<List<OptionNode>> rowOptions = new ArrayList<>();
        for (int i = 0; i < maxRowNumAtomicInteger.get(); i++) {
            List<OptionNode> rowOption = new ArrayList<>();
            int              finalI    = i;
            selectOptions.forEach(selectOption -> {
                List<OptionNode> options = selectOption.getOptions();
                if (finalI < options.size()) {
                    rowOption.add(options.get(finalI));
                } else {
                    rowOption.add(OptionNode.builder().build());
                }
            });
            rowOptions.add(rowOption);
        }
        
        log.info("[拼装表格下拉选数据]#{}", rowOptions);
        
        for (int i = 0; i < rowOptions.size(); i++) {
            XSSFRow          row         = optionDataSheet.createRow(i);
            List<OptionNode> optionNodes = rowOptions.get(i);
            for (int k = 0, x = 0; k < optionNodes.size() * 2; k = k + 2, x++) {
                OptionNode optionNode = optionNodes.get(x);
                
                if (optionNode.isAddCol()) {
                    XSSFCell valueCell = row.createCell(k);
                    valueCell.setCellType(CellType.STRING);
                    XSSFCell keyCell = row.createCell(k + 1);
                    keyCell.setCellType(CellType.STRING);
                    
                    keyCell.setCellValue(optionNode.getKey());
                    valueCell.setCellValue(optionNode.getValue());
                }
                
            }
        }
        
    }
    
    /*列名称处理*/
    private static void colNamesHandler(XSSFWorkbook workBook, ExcelTemplateModel model) {
        
        /*列名工作区*/
        XSSFSheet colNameSheet = workBook.getSheetAt(2);
        
        /*设置工作簿名称*/
        workBook.setSheetName(2, "COLNAMES");
        
        /*设置工作簿隐藏*/
        workBook.setSheetHidden(2, true);
        
        /*第一行*/
        XSSFRow row = colNameSheet.getRow(0);
        
        /*下拉选项*/
        List<SelectOption> selectOptions = model.getSelectOptions();
        
        /*数据薄角标标记*/
        int index = 0;
        
        for (SelectOption selectOption : selectOptions) {
            
            selectOption.setKeyAndValueIndex(index);
            
            String colName     = selectOption.getColName();
            String colNameCode = selectOption.getColNameCode();
            
            rowFor:
            for (int i = 0; i < row.getLastCellNum(); i++) {
                XSSFCell cell = row.getCell(i);
                if (StringUtils.isNotBlank(cell.getStringCellValue()) && cell.getStringCellValue().trim().equals(colName)) {
                    selectOption.setColNameIndex(i);
                    break rowFor;
                }
            }
            
            if (selectOption.isNeedBindCodeFunction()) {
                rowFor:
                for (int i = 0; i < row.getLastCellNum(); i++) {
                    XSSFCell cell = row.getCell(i);
                    if (StringUtils.isNotBlank(cell.getStringCellValue()) && cell.getStringCellValue().trim().equals(colNameCode)) {
                        selectOption.setColNameCodeIndex(i);
                        break rowFor;
                    }
                }
            }
            
            index += 2;
        }
    }
    
    /*头部数据处理*/
    private static void handHandler(XSSFWorkbook workBook, ExcelTemplateModel model) {
        /*第一个工作区*/
        XSSFSheet templateSheet = workBook.getSheetAt(0);
        /*标题行*/
        XSSFRow titleRow = templateSheet.getRow(0);
        /*标题行第一列*/
        XSSFCell titleRowCell = titleRow.getCell(0);
        /*头信息值*/
        String handValue = titleRowCell.getStringCellValue();
        /*替换占位符数据*/
        MessageFormat format = new MessageFormat(handValue);
        handValue = format.format(model.getHandData());
        
        /*将数据回填头部第一列中*/
        titleRowCell.setCellValue(handValue);
        
        /*回显数据设置*/
        if (model.isHasSupperData()) {
            Row  row  = templateSheet.getRow(1);
            Cell cell = row.getCell(0);
            
            cell.setCellValue(model.getSupperData());
        }
        
    }
    
    /*测试模板生成函数*/
    public static void downLoadExcelTemplateToLocal(ExcelTemplateModel model) {
        Workbook workbook = downLoadExcelTemplate(model);
        File     file     = new File("/Users/cnnoter/Data/TempData/CsTemplate2.xlsx"); //写文件
        try (FileOutputStream out = new FileOutputStream(file)) {
            out.flush();
            assert workbook != null;
            workbook.write(out);
        } catch (Exception e) {
            log.info("测试失败", e);
        }
        
    }
 
    /*数据导出*/
    public static void exportData(HttpServletResponse response, ExcelTemplateModel model) {
        try (InputStream in = new FileInputStream(model.getFilePath())) {
            
            Workbook workBook = getWorkbook(in, model.getFilePath());
            
            /*第一个工作区*/
            assert workBook != null;
            Sheet templateSheet = workBook.getSheetAt(0);
            /*标题行*/
            Row titleRow = templateSheet.getRow(0);
            /*标题行第一列*/
            Cell titleRowCell = titleRow.getCell(0);
            /*头信息值*/
            String handValue = titleRowCell.getStringCellValue();
            /*替换占位符数据*/
            MessageFormat format = new MessageFormat(handValue);
            handValue = format.format(model.getHandData());
            
            /*将数据回填头部第一列中*/
            titleRowCell.setCellValue(handValue);
            
            /*列名工作区*/
            Sheet colNameSheet = workBook.getSheetAt(1);
            
            /*设置工作簿名称*/
            workBook.setSheetName(1, "COLNAMES");
            
            /*设置工作簿隐藏*/
            workBook.setSheetHidden(1, true);
            
            /*第一行*/
            Row row = colNameSheet.getRow(0);
            
            short lastCellNum = row.getLastCellNum();
            
            /*列名*/
            Map<String, Integer> colNames = new HashMap<>();
            for (int i = 0; i < lastCellNum; i++) {
                Cell   cell    = row.getCell(i);
                String colName = cell.getStringCellValue();
                colNames.put(colName, i);
            }
            
            Set<String> colNameSet = colNames.keySet();
            
            List exportData = model.getExportData();
            
            for (int i = 0; i < exportData.size(); i++) {
                Object obj= exportData.get(i);
                
                CMap data = CMap.builderParamByBean(obj);
                
                Row exportRow = templateSheet.createRow(i + model.getExportFirstRowNum() - 1);
                
                /*序号列*/
                Cell cell = exportRow.createCell(0);
                cell.setCellValue(i + 1);
                
                /*数据列*/
                colNameSet.forEach(colName -> {
                    Integer indexCell = colNames.get(colName);
                    Cell    dataCell     = exportRow.createCell(indexCell+1);
                    dataCell.setCellValue(data.getValue(colName));
                });
            }
    
    
            log.info("[EXCEL TOOL BUILDER -- BUILDER PARAMS LOOK]\n{}", model);
    
            try (ServletOutputStream outputStream = response.getOutputStream()) {
                response.setContentType("application/vnd.ms-excel");
                response.addHeader("Cache-Control", "no-cache, no-store, must-revalidate");
                response.addHeader("charset", "utf-8");
                response.addHeader("Pragma", "no-cache");
                String encodeName = URLEncoder.encode(model.getExcelName(), StandardCharsets.UTF_8.toString());
                response.setHeader("Content-Disposition", "attachment; filename=\"" + encodeName + "\"; filename*=utf-8''" + encodeName);
        
                workBook.write(outputStream);
                outputStream.flush();
            } catch (IOException e) {
                log.info("[下载Excel模板失败!]", e);
            }
            
        } catch (Exception e) {
            log.info("导出模板失败", e);
        }
        
    }
}

参数封装对象

package com.techhero.base.exam.model.abs;

import com.techhero.common.utils.StringUtil;
import lombok.*;

import java.io.File;
import java.io.Serializable;
import java.util.List;

/*Excel 创建模板数据封装对象*/
@Data
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ExcelTemplateModel implements Serializable {
    
    /*模板路径*/
    private String filePath;
    
    /*表格名称*/
    private String excelName;
    
    /*下拉选从第几行设置*/
    private int selectOptionRowNum;
    
    /*导出表格时从第几行开始添加数据*/
    private int exportFirstRowNum;
    
    /*初始化模板工作薄行数*/
    private int templateInitRowSize;
    
    /*头部数据-使用占位符代替*/
    private String[] handData;
    
    /*存放一些导入有关的数据*/
    private String supperData;
    
    /*选项*/
    private List<SelectOption> selectOptions;
    
    /*导出数据*/
    private List<?> exportData;
    
    /*获取文件路径*/
    public File getResourceTemplateFile(){
        return new File(this.filePath);
    }
    
    /*是否有头信息更换*/
    public boolean isHasHand(){
        return handData!=null&& handData.length>0;
    }
    
    /*是否有下拉选*/
    public boolean isHasSelectOptions(){
        return selectOptions!=null && !selectOptions.isEmpty();
    }
    
    /*是否需要填充回显数据*/
    public boolean isHasSupperData(){
        return StringUtil.isNotEmpty(supperData);
    }
    
    public void initTemplateInitRowSize(){
       if(this.templateInitRowSize==0){
           this.templateInitRowSize=5000;
       }
    }
    
}

package com.techhero.base.exam.model.abs;

import lombok.Data;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.util.List;

@Data
@ToString
public class SelectOption implements Serializable {
    
    /*列名称(对应英文名称)*/
    private String colName;
    
    /*列名称代码(对应英文名称代码)*/
    private String colNameCode;
    
    /*列隐藏标记*/
    private boolean codeColHiddenFlag;
    
    /*对应模板工作薄名称列下标*/
    private int colNameIndex;
    
    /*对应模板工作薄名称代码列下标*/
    private int colNameCodeIndex;
    
    /*唯一属性对应模板工作薄列*/
    private int keyColIndex;
    
    /*值对应数据薄列*/
    private int valueColIndex;
    
    /*选项*/
    private List<OptionNode> options;
    
    /*私有化全参构造函数*/
    private SelectOption(String colName, List<OptionNode> options) {
        this.colName = colName;
        this.options = options;
    }
    
    /*私有化全参构造函数*/
    private SelectOption(String colName,String colNameCode, List<OptionNode> options,boolean codeColHiddenFlag) {
        this.colName = colName;
        this.options = options;
        this.colNameCode= colNameCode;
        this.codeColHiddenFlag=codeColHiddenFlag;
    }
    
    public static SelectOption builder(String colName, List<OptionNode> options) {
        return new SelectOption(colName,options);
    }
    
    public static SelectOption builder(String colName,String colNameCode, List<OptionNode> options,boolean codeColHiddenFlag) {
        return new SelectOption(colName,colNameCode,options, codeColHiddenFlag);
    }
    
    public static SelectOption builder(String colName,String colNameCode, List<OptionNode> options) {
        return new SelectOption(colName,colNameCode,options, true);
    }
    
    /*设置数据薄列对应管理*/
    public void setKeyAndValueIndex(int index){
        this.valueColIndex=index;
        this.keyColIndex=index+1;
    }
    
    /*是否需要绑定编码函数*/
    public boolean isNeedBindCodeFunction(){
        return StringUtils.isNotBlank(this.colNameCode);
    }
    
    /*获取最大行号*/
    public int getMaxRowNum(){
        if(this.options!=null){
            return this.options.size();
        }
        return 0;
    }
    
}
package com.techhero.base.exam.model.abs;

import lombok.*;
// 使用map有点不方便,还不如自己封装一个key-value 对象
@Data
@AllArgsConstructor
@ToString
@NoArgsConstructor
@Builder
public class OptionNode {
    
    /*唯一数据*/
    private String key;
    
    /*唯一值*/
    private String value;
 
    public boolean isAddCol(){
        return key!=null&&value!=null;
    }
    
}

package com.techhero.common.utils.req;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.techhero.common.model.base.ToDate;
import com.techhero.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
//其实就是一个HashMap 但是里边有很多工具方法,方便使用
@Slf4j
public class CMap extends HashMap<String, Object> implements Serializable {
    
    /*分页页码标记*/
    public static final String PAGE_NUM = "pageNum";
    
    /*分页步长*/
    public static final String PAGE_SIZE = "pageSize";
    
    /* 当前时间 */
    public static final String CURRENT_DATE = "CURRENT_DATE";
    
    /*获取分页页码*/
    public Integer getPageNum() {
        return getPageParam(PAGE_NUM);
    }
    
    /*获取分页步长*/
    public Integer getPageSize() {
        return getPageParam(PAGE_SIZE);
    }
    
    private Integer getPageParam(String pageParamType) {
        try {
            Object v = this.get(pageParamType);
            if (v == null)
                return -1;
            return Integer.valueOf(v.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }
    
    /**
     * 获取字符串值
     */
    public String getValue(String key) {
        Object v = this.get(key);
        if (v == null) return null;
        return v.toString();
    }
    
    /*获取Integer数据*/
    public Integer getIntegerValue(String key) {
        try {
            Object v = this.get(key);
            if (v == null)
                return null;
            return Integer.valueOf(v.toString());
        } catch (Exception e) {
            log.info("cMap数据转换Integer 错误");
        }
        return null;
    }
    
    /*带默认值获取Integer数据*/
    public Integer getIntegerValue(String key, Integer defaultValue) {
        Integer value = getIntegerValue(key);
        return value == null ? defaultValue : value;
    }
    
    /*获取Short数据*/
    public Short getShortValue(String key) {
        try {
            Object v = this.get(key);
            if (v == null)
                return null;
            return Short.valueOf(v.toString());
        } catch (Exception e) {
            log.info("cMap数据转换Short 错误");
        }
        return null;
    }
    
    /*获取带默认值Short数据*/
    public Short getShortValue(String key, Short defaultValue) {
        Short value = getShortValue(key);
        return defaultValue == null ? value : defaultValue;
    }
    
    /*获取Date类型数据*/
    public Date getDateValue(String key) {
        Object value = get(key);
        if (value == null) return null;
        
        String dateStr = value.toString();
        
        long ltime;
        Date date  = null;
        if (StringUtils.isNotEmpty(dateStr)) {
            try {
                ltime = Long.parseLong(dateStr);
                date = new Date(ltime);
            } catch (Exception e) {
                try {
                    date = DateUtils.parseDate(dateStr);
                } catch (Exception ex) {
                    log.error("DATE 类型转换失败", ex);
                }
            }
        }
        return date;
    }
    
    /**
     * 获取Double数据
     */
    public Double getDoubleValue(String key) {
        try {
            Object v = this.get(key);
            if (v == null)
                return null;
            return Double.valueOf(v.toString());
        } catch (Exception e) {
            log.info("cMap数据转换Double 错误");
        }
        return null;
    }
    
    /**
     * 获取当前时间,前端使用获取本人写的获取请求参数时候回自动在该map中放入一个时间. 此时间是为了全程统一
     */
    public Date getCurrentDate() {
        try {
            Object v = this.get(CURRENT_DATE);
            if (v == null) {
                Date date = new Date();
                super.put(CURRENT_DATE, date);
                return date;
            }
            return (Date) v;
        } catch (Exception e) {
            log.info("cMap数据转换Date 错误");
        }
        return null;
    }
    
    /*换PUT方法可以连缀*/
    public CMap putValue(String key, Object value) {
        super.put(key, value);
        return this;
    }
    
    /*换PUT方法可以连缀*/
    public CMap putDateValue(String key, Object value) {
        if (value instanceof java.sql.Timestamp) {
            java.sql.Timestamp o       = (java.sql.Timestamp) value;
            String             dateStr = com.techhero.common.utils.DateUtils.formatDate(new Date(o.getTime()));
            super.put(key, dateStr);
            return this;
        } else if (value instanceof Date) {
            Date   date    = (Date) value;
            String dateStr = com.techhero.common.utils.DateUtils.formatDate(date);
            super.put(key, dateStr);
            return this;
        }
        
        log.info("日期数据保存失败");
        return this;
    }
    
    /*换PUT方法可以连缀*/
    public CMap putDateTimeValue(String key, Object value) {
        if (value instanceof java.sql.Timestamp) {
            java.sql.Timestamp o       = (java.sql.Timestamp) value;
            String             dateStr = com.techhero.common.utils.DateUtils.formatDateTime(new Date(o.getTime()));
            super.put(key, dateStr);
            return this;
        } else if (value instanceof Date) {
            Date   date    = (Date) value;
            String dateStr = com.techhero.common.utils.DateUtils.formatDateTime(date);
            super.put(key, dateStr);
            return this;
        }
        
        log.info("日期数据保存失败");
        return this;
    }
    
    /**
     * 主要针对数据MYBATIS返回数据,对类型java.sql.Timestamp进行转换为String类型
     * 如果你想要保存一个原生类型,你可以选择CMap.putValue(String key, Object value);
     * 作者: 吴 波
     * 时间: 2020-03-06 13:43
     * 笔名: 那年秋天的茄子^^
     */
    @Override
    public Object put(String key, Object value) {
        if (value instanceof java.sql.Timestamp) {
            java.sql.Timestamp o       = (java.sql.Timestamp) value;
            String             dateStr = DateUtils.formatDateTime(new Date(o.getTime()));
            super.put(key, dateStr);
            return dateStr;
        }
        return super.put(key, value);
    }
    
    /*通过一个Map构建为当前类*/
    public static CMap builder(Map<? extends String, ?> map) {
        CMap param = new CMap();
        param.putAll(map);
        return param;
    }
    
    /*通过一个Bean对象转换为Param对象*/
    public static CMap builderParamByBean(Object bean) {
        if (bean == null) return null;
        CMap param = new CMap();
        try {
            BeanInfo             beanInfo            = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                /*过滤class属性*/
                if (!key.equals("class")) {
                    /*得到property对应的getter方法*/
                    Method getter = property.getReadMethod();
                    Object value  = getter.invoke(bean);
                    if(value!=null&&value instanceof Date){
                        Field declaredField = bean.getClass().getDeclaredField(key);
                        log.debug("[当前为日期类型-反射获取是否有ToDate注解]");
                        if(declaredField.isAnnotationPresent(ToDate.class)){
                            ToDate annotation = declaredField.getAnnotation(ToDate.class);
                            String format = annotation.value();
                            value= DateUtils.formatDate((Date) value, format);
                        }
                    }
                    
                    param.put(key, value);
                }
            }
        } catch (Exception e) {
            log.error("转换数据错误!",e);
        }
        return param;
    }
    
    /**
     * 如果你在其中放入的是一个实例自定义对象,
     * 则你可以通过这个方法获取那个bean对象
     */
    public <T> T getBean(String key, Class<T> t) {
        Object v = this.get(key);
        if (v != null) {
            if (t.isAssignableFrom(v.getClass())) {
                try {
                    @SuppressWarnings("unchecked")
                    T newInstance = (T) v;
                    return newInstance;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
    
    /**
     * 获取某前缀开始的数据集
     */
    public CMap getComMapByPre(String pre) {
        CMap        param  = new CMap();
        Set<String> keySet = this.keySet();
        for (String key : keySet) {
            if (key.startsWith(pre)) {
                Object v      = super.get(key);
                String newKey = key.substring(pre.length());
                param.put(newKey, v);
            }
        }
        return param;
    }
    
    /*获取布尔值数据默认为False*/
    public Boolean getBooleanValue(String key) {
        Object v = this.get(key);
        if (v == null)
            return false;
        if (v instanceof Boolean) {
            return (Boolean) v;
        }
        return false;
    }
    
    /*获取BigDecimal数据*/
    public BigDecimal getBigDecimalValue(String key) {
        Double doubleValue = this.getDoubleValue(key);
        if (doubleValue != null) return new BigDecimal(doubleValue);
        return null;
    }
    
    /**
     * 获取对象
     */
    public <T> T getMapBean(Class<T> t) {
        return transMapToBean(this, t);
    }
    
    /**
     * 利用org.apache.commons.beanutils
     */
    public static <T> T transMapToBean(Map<?, ?> map, Class<T> clazz) {
        T object = null;
        try {
            object = clazz.newInstance();
            if (map == null || map.size() < 1) {
                return object;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(clazz); // 获取类属性
            
            /*给 JavaBean 对象的属性赋值*/
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            
            StringBuffer sb = new StringBuffer(clazz.getName());
            sb.append("\n");
            
            for (PropertyDescriptor descriptor : propertyDescriptors) {
                String propertyName = descriptor.getName();
                
                sb.append(propertyName);
                sb.append("=");
                
                if (map.containsKey(propertyName)) {
                    // 下面一句可以 try 起来,这样当一个属性赋值失败的时候就不会影响其他属性赋值。
                    Object   value        = map.get(propertyName);
                    Class<?> propertyType = descriptor.getPropertyType();
                    Object[] args         = new Object[1];
                    try {
                        if (value != null) {
                            if (propertyType.equals(Integer.class)) {
                                value = Integer.valueOf(value.toString());
                            } else if (propertyType.equals(Short.class)) {
                                value = Short.valueOf(value.toString());
                            } else if (propertyType.equals(Long.class)) {
                                value = Long.valueOf(value.toString());
                            } else if (propertyType.equals(BigDecimal.class)) {
                                value = new BigDecimal(value.toString());
                            } else if (propertyType.equals(Double.class)) {
                                value = Double.valueOf(value.toString());
                            } else if (propertyType.equals(Float.class)) {
                                value = Float.valueOf(value.toString());
                            } else if (propertyType.equals(Date.class)) {
                                if (value.getClass().equals(String.class)) {
                                    try {
                                        value = DateUtils.parseDate(value.toString());
                                    } catch (Exception e) {
                                        log.info("转换失败",e);
                                    }
                                }
                            }
                        }
                        args[0] = value;
                        sb.append(value);
                        sb.append("\n");
                        Method writeMethod = descriptor.getWriteMethod();
                        if (writeMethod == null) {
                            continue;
                        }
                        writeMethod.invoke(object, args);
                    } catch (Exception e) {
                        log.info("[CMap 转换异常]\n{}",sb, e);
                    }
                }
            }
            return object;
            
        } catch (Exception e) {
            log.info("转换失败",e);
        }
        return object;
    }
    
    /*构造函数*/
    public CMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
    }
    
    public CMap(int initialCapacity) {
        super(initialCapacity, 1);
    }
    
    public CMap() {
    }
    
    public CMap(Map<? extends String, ?> m) {
        super(m);
    }
    
    @Override
    public String toString() {
        return JSONObject.toJSONString(this);
    }
    
}

使用方式如下:

public static void main(String[] args) {
       /*岗位*/
        List<OptionNode> gwOptions = new ArrayList<>();
        gwOptions.add(OptionNode.builder().key("1").value("考区负责人").build());
        gwOptions.add(OptionNode.builder().key("2").value("考点负责人").build());
        gwOptions.add(OptionNode.builder().key("3").value("考场负责人").build());
        gwOptions.add(OptionNode.builder().key("4").value("钥匙保管员").build());
        gwOptions.add(OptionNode.builder().key("5").value("武警").build());
        
        /*没有编码列*/
         SelectOption gw = SelectOption.builder("GW", gwOptions);
        
       /* 性别类型*/
        List<OptionNode> xbOptions = new ArrayList<>();
        xbOptions.add(OptionNode.builder().key("A").value("男").build());
        xbOptions.add(OptionNode.builder().key("B").value("女").build());
        xbOptions.add(OptionNode.builder().key("C").value("未知").build());
        
        /*有编码列-且隐藏编码列*/
        SelectOption xb = SelectOption.builder("XB", "XBBM", xbOptions, true);
        
        /*证件类型*/
        List<OptionNode> typeOptions = new ArrayList<>();
        typeOptions.add(OptionNode.builder().key("A1").value("身份证").build());
        typeOptions.add(OptionNode.builder().key("B2").value("军官证").build());
        typeOptions.add(OptionNode.builder().key("C3").value("驾驶证").build());
        
        /*有编码列-且不隐藏编码列*/
        SelectOption type = SelectOption.builder("ZJLX", "ZJLXBM", typeOptions, false);
        
        List<SelectOption> selectOptions = new ArrayList<>();
        selectOptions.add(xb);
        selectOptions.add(type);
        selectOptions.add(gw);
        
        ExcelTemplateModel build = ExcelTemplateModel.builder()
                /*文件路劲*/
                .filePath("/Users/cnnoter/Data/TempData/CsTempldate.xlsx")
                /*默认初始化行数*/
                .templateInitRowSize(5000)
                /*头部信息渲染*/
                .handData(new String[]{"湖北省考试院", "KS1X03"})
                /*下拉选项*/
                .selectOptions(selectOptions)
                /*其实行未知*/
                .selectOptionRowNum(3)
                .build();
        
        downLoadExcelTemplateToLocal(build);

下边是service中直接调用的一个函数(参考)

/*考点工作人员模板下载*/
    private void examPointWorkPersonTemplateDownLoad(String code,String examPlanCode, HttpServletResponse response) {
        
        /*考试管理机构*/
        ZhJgKsgljgxxb examMngOrg = zhJgKsgljgxxbMapper.selectOne(ZhJgKsgljgxxb.builder().ksgljgid(code).build());
        
        /*头部替换[考试管理机构名称/管理机构标识]*/
        String[] handData = new String[]{examMngOrg.getKsgljgmc(), examMngOrg.getKsgljgid()};
        
        /*下拉选数据*/
        List<SelectOption> selectOptions = new ArrayList<>();
        
        
        /*性别*/
        List<Dict>       xbDicts       = dictMapper.select(Dict.builder().sjlx("zd_xbdm").build());
        List<OptionNode> xbOptionNodes = xbDicts.stream().map(dict -> OptionNode.builder().key(dict.getDm()).value(dict.getDmmc()).build()).collect(Collectors.toList());
        selectOptions.add(SelectOption.builder("xb", "xbm", xbOptionNodes));
        
        /*获取岗位*/
        List<Job>        jobs           = jobMapper.select(Job.builder().gwflDm(JobTypeEnum.KS_JOB.getOrgCode()).build());
        List<OptionNode> jobOptionNodes = jobs.stream().map(job -> OptionNode.builder().key(job.getGwDm()).value(job.getGwmc()).build()).collect(Collectors.toList());
        selectOptions.add(SelectOption.builder("gwzz", "gwzzm", jobOptionNodes));
        
        /*是否在编*/
        List<OptionNode> isOpenList = new ArrayList<>();
        isOpenList.add(OptionNode.builder().key("0").value("否").build());
        isOpenList.add(OptionNode.builder().key("1").value("是").build());
        selectOptions.add(SelectOption.builder("sfzb", isOpenList));
        
        /*学历*/
        List<Dict>       xlDicts       = dictMapper.select(Dict.builder().sjlx("xl").build());
        List<OptionNode> xlOptionNodes = xlDicts.stream().map(dict -> OptionNode.builder().key(dict.getDm()).value(dict.getDmmc()).build()).collect(Collectors.toList());
        selectOptions.add(SelectOption.builder("xl", "xlbm", xlOptionNodes));
        
        /*职称*/
        List<Dict>       zcDicts       = dictMapper.select(Dict.builder().sjlx("zc").build());
        List<OptionNode> zcOptionNodes = zcDicts.stream().map(dict -> OptionNode.builder().key(dict.getDm()).value(dict.getDmmc()).build()).collect(Collectors.toList());
        selectOptions.add(SelectOption.builder("zc", "zcbm", zcOptionNodes));
        
        /*考点*/
        List<DcKdxxb>    examPoints           = dcKdxxbMapper.select(DcKdxxb.builder().kdxzqhm(code).ksjhbm(examPlanCode).build());
        List<OptionNode> examPointOptionNodes = examPoints.stream().filter(dcKdxxb -> StringUtil.isNotBlank(dcKdxxb.getBzhkdid())&&StringUtil.isNotBlank(dcKdxxb.getKdmc())).map(dcKdxxb -> OptionNode.builder().key(dcKdxxb.getId()).value(dcKdxxb.getKdmc()).build()).collect(Collectors.toList());
        selectOptions.add(SelectOption.builder("bzhkdmc", "bzhkdid", examPointOptionNodes));
        
        /*培训考核情况*/
        List<Dict>       pxkhqkDicts       = dictMapper.select(Dict.builder().sjlx("pxkhqk").build());
        List<OptionNode> pxkhqkOptionNodes = pxkhqkDicts.stream().map(dict -> OptionNode.builder().key(dict.getDm()).value(dict.getDmmc()).build()).collect(Collectors.toList());
        selectOptions.add(SelectOption.builder("pxkhqk", "pxkhqkbm", pxkhqkOptionNodes));
        
        String supperData = handData[1] + ",1,身份证," + code;
        
        ExcelUtils.downLoadExcelTemplate(response,
                ExcelTemplateModel.builder()
                        .handData(handData)
                        .supperData(supperData)
                        .selectOptionRowNum(4)
                        .templateInitRowSize(5000)
                        .selectOptions(selectOptions)
                        .filePath(templatePath.getExamPointWorkPersonPath())
                        .excelName(examMngOrg.getKsgljgmc() + "考点工作人员.xlsx")
                        .build());
        
    }

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值