JAVA 实现动态Excel模板生成

参考博客:https://www.cnblogs.com/codecat/p/10948120.html

1、
package com.ainemo.console.util;

import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;

/**
 * @author jiangwentao
 * @date 2019/9/26
 */
public class ExcelTemplateUtil {

    private static final Logger log = LoggerFactory.getLogger(ExcelTemplateUtil.class);

    /**
     * 生成Excel导入模板
     *
     * @param filePath Excel文件路径
     * @param fileName 文件名
     * @param headers  Excel列标题(数组)
     * @param downData 下拉框数据(数组)
     * @param downRows 下拉列的序号(数组,序号从0开始)
     * @param notes 注意事项 第二行
     * @param title 标题
     */
    public static void createExcelTemplate(String filePath, String fileName, String[] headers,
                                            List<String[]> downData, String[] downRows, String notes, String title) {

        //创建工作薄
        HSSFWorkbook wb = new HSSFWorkbook();

        //表头样式
        HSSFCellStyle style = wb.createCellStyle();
        //创建一个居中格式
        style.setAlignment(HSSFCellStyle.ALIGN_LEFT);
        //字体样式
        HSSFFont fontStyle = wb.createFont();
        fontStyle.setFontName("宋体");
        fontStyle.setFontHeightInPoints((short) 11);
        fontStyle.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        style.setFont(fontStyle);

        //新建sheet
        HSSFSheet sheet1 = wb.createSheet("Sheet1");
        HSSFSheet sheet2 = wb.createSheet("Sheet2");

        //生成sheet1内容 第一个sheet的第一行内容(填写须知)
        HSSFRow rowFirst = sheet1.createRow(0);
        HSSFCell cellRemark =  rowFirst.createCell(0);
        sheet1.setColumnWidth(0, 8000);
        cellRemark.setCellStyle(style);
        cellRemark.setCellValue("填写须知:");
        //生成sheet1内容 第一个sheet的第二行内容(注意事项)
        HSSFRow rowNotes = sheet1.createRow(1);
        HSSFCell cellNotes =  rowNotes.createCell(0);
        sheet1.setColumnWidth(0, 8000);
        cellNotes.setCellStyle(style);
        cellNotes.setCellValue(notes);
        //生成sheet1内容 第一个sheet的第五行内容(标题)
        HSSFRow rowTitle = sheet1.createRow(4);
        HSSFCell cellTitle =  rowTitle.createCell(0);
        sheet1.setColumnWidth(0, 8000);
        cellTitle.setCellStyle(style);
        cellTitle.setCellValue(title);

        //生成sheet1内容 第一个sheet的第五行内容(设置字段名称及属性)
        HSSFRow rowHeader = sheet1.createRow(5);
        for (int i = 0; i < headers.length; i++) {
            //获取第一行的每个单元格
            HSSFCell cell = rowHeader.createCell(i);
            //设置每列的列宽
            sheet1.setColumnWidth(i, 8000);
            //加样式
            cell.setCellStyle(style);
            //往单元格里写数据
            cell.setCellValue(headers[i]);
        }

        //设置下拉框数据
        String[] arr = {"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"};
        int index = 0;
        HSSFRow row;
        for (int r = 0; r < downRows.length; r++) {
            //获取下拉对象
            String[] dlData = downData.get(r);
            int rowNum = Integer.parseInt(downRows[r]);

            //255以内的下拉
            if (dlData.length < 255) {
                //255以内的下拉,参数分别是:作用的sheet、下拉内容数组、起始行、终止行、起始列、终止列
                //超过255个报错
                sheet1.addValidationData(setDataValidation(sheet1, dlData, 1, 50000, rowNum, rowNum+1));
            } else {
                //255以上的下拉,即下拉列表元素很多的情况
                //1、设置有效性
                //String strFormula = "Sheet2!$A$1:$A$5000" ; //Sheet2第A1到A5000作为下拉列表来源数据
                //Sheet2第A1到A5000作为下拉列表来源数据
                String strFormula = "Sheet2!$" + arr[index] + "$1:$" + arr[index] + "$5000";
                //设置每列的列宽
                sheet2.setColumnWidth(r, 8000);
                //设置数据有效性加载在哪个单元格上,参数分别是:从sheet2获取A1到A5000作为一个下拉的数据、起始行、终止行、起始列、终止列
                //下拉列表元素很多的情况
                sheet1.addValidationData(setDataValidation(strFormula, 1, 50000, rowNum, rowNum));

                //2、生成sheet2内容
                for (int j = 0; j < dlData.length; j++) {
                    //第1个下拉选项,直接创建行、列
                    if (index == 0) {
                        //创建数据行
                        row = sheet2.createRow(j);
                        //设置每列的列宽
                        sheet2.setColumnWidth(j, 8000);
                        //设置对应单元格的值
                        row.createCell(0).setCellValue(dlData[j]);

                    } else {
                        //非第1个下拉选项
                        int rowCount = sheet2.getLastRowNum();
                        //前面创建过的行,直接获取行,创建列
                        if (j <= rowCount) {
                            //获取行,创建列,设置对应单元格的值
                            sheet2.getRow(j).createCell(index).setCellValue(dlData[j]);

                        } else {
                            //未创建过的行,直接创建行、创建列,设置每列的列宽
                            sheet2.setColumnWidth(j, 8000);
                            //创建行、创建列,设置对应单元格的值
                            sheet2.createRow(j).createCell(index).setCellValue(dlData[j]);
                        }
                    }
                }
                index++;
            }
        }
                //设置某一列为正整数
        if (!Objects.isNull(createExcelTemplate.getPositiveIntRows())) {
            for (Integer rowNum : createExcelTemplate.getPositiveIntRows()) {
                sheet1.addValidationData(setValidate(firstRow, endRow, rowNum, rowNum));
            }
        }
        try {
            //写文件
            File f = new File(filePath + "/" + fileName);

            //不存在则新增
            if (!f.getParentFile().exists()) {
                f.getParentFile().mkdirs();
            }
            if (!f.exists()) {
                f.createNewFile();
            }

            FileOutputStream out = new FileOutputStream(f);
            out.flush();
            wb.write(out);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

     /**
     * 设置单元格为正整数
     * @param firstRow 开始行
     * @param lastRow 结束行
     * @param firstCol 开始字段列
     * @param lastCol 结束字段列
     */
    private static HSSFDataValidation setValidate(int firstRow, int lastRow, int firstCol, int lastCol) {
        // 创建一个规则:1-100的数字 
        //OperatorType.GREATER_THAN 大于的意思 数据有效性为正整数 ValidationType.INTEGER(整数)
        DVConstraint constraint = DVConstraint.createNumericConstraint(DVConstraint.ValidationType.INTEGER,
                DVConstraint.OperatorType.GREATER_THAN, "0", null); 
        // 设定在哪个单元格生效
        CellRangeAddressList regions = new CellRangeAddressList(firstRow, lastRow, firstCol, lastCol);
        // 创建规则对象
        return new HSSFDataValidation(regions, constraint);
    }
    /**
     *
     * @param strFormula 下拉列表来源数据
     * @param firstRow 起始行
     * @param endRow 终止行
     * @param firstCol 起始列
     * @param endCol 终止列
     */
    private static HSSFDataValidation setDataValidation(String strFormula,
                                                        int firstRow, int endRow, int firstCol, int endCol) {

        // 设置数据有效性加载在哪个单元格上。四个参数分别是:起始行、终止行、起始列、终止列
        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
        DVConstraint constraint = DVConstraint.createFormulaListConstraint(strFormula);
        HSSFDataValidation dataValidation = new HSSFDataValidation(regions, constraint);

        dataValidation.createErrorBox("Error", "Error");
        dataValidation.createPromptBox("", null);

        return dataValidation;
    }


    /**
     * 下拉列表元素不多的情况(255以内的下拉)
     * @param sheet sheet
     * @param textList 下拉对象
     * @param firstRow 起始行
     * @param endRow 终止行
     * @param firstCol 起始列
     * @param endCol 终止列
     */
    private static DataValidation setDataValidation(Sheet sheet, String[] textList, int firstRow, int endRow, int firstCol, int endCol) {

        DataValidationHelper helper = sheet.getDataValidationHelper();
        //加载下拉列表内容
        DataValidationConstraint constraint = helper.createExplicitListConstraint(textList);
        //DVConstraint constraint = new DVConstraint();
        constraint.setExplicitListValues(textList);

        //设置数据有效性加载在哪个单元格上。四个参数分别是:起始行、终止行、起始列、终止列
        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);

        //数据有效性对象
        //DataValidation data_validation = new DataValidation(regions, constraint);

        return helper.createValidation(constraint, regions);
    }

    /**
     * 下载指定路径的Excel文件
     * @param filePath 文件路径
     * @param fileName  文件名
     */
    public static void getExcel(String filePath, String fileName, HttpServletResponse response, HttpServletRequest request) {

        try {

            //1.设置文件ContentType类型,这样设置,会自动判断下载文件类型
            response.setContentType("multipart/form-data");

            //2.设置文件头:最后一个参数是设置下载文件名
            response.setHeader("Content-disposition", "attachment; filename=\""
                    + encodeChineseDownloadFileName(request, fileName) + "\"");
//            response.setHeader("Content-Disposition", "attachment;filename="
//                    + new String(fileName.getBytes("UTF-8"), "ISO-8859-1") + ".xls"); //中文文件名

            //通过文件路径获得File对象
            File file = new File(filePath + "/" + fileName);

            FileInputStream in = new FileInputStream(file);
            //3.通过response获取OutputStream对象(out)
            OutputStream out = new BufferedOutputStream(response.getOutputStream());

            int b = 0;
            byte[] buffer = new byte[2048];
            while ((b = in.read(buffer)) != -1) {
                //4.写到输出流(out)中
                out.write(buffer, 0, b);
            }

            in.close();
            out.flush();
            out.close();

        } catch (IOException e) {
            log.error("下载Excel模板异常", e);
        }
    }

    /**
     * 设置中文文件名
     * @param  pFileName 文件名
     */
    private static String encodeChineseDownloadFileName(HttpServletRequest request, String pFileName)
            throws UnsupportedEncodingException {

        String filename = null;
        String agent = request.getHeader("USER-AGENT");
        //System.out.println("agent==========》"+agent);

        if (null != agent) {
            //Firefox
            if (-1 != agent.indexOf("Firefox")) {
                filename = "=?UTF-8?B?" + (new String(org.apache.commons.codec.binary.Base64.encodeBase64(pFileName.getBytes("UTF-8")))) + "?=";
            } else if (-1 != agent.indexOf("Chrome")) {
                //Chrome
                filename = new String(pFileName.getBytes(), "ISO8859-1");
            } else {//IE7+
                filename = java.net.URLEncoder.encode(pFileName, "UTF-8");
                //替换空格
                filename = StringUtils.replace(filename, "+", "%20");
            }
        } else {
            filename = pFileName;
        }

        return filename;
    }

    /**
     * 删除文件
     * @param filePath  文件路径
     */
    public static void delFile(String filePath, String fileName) {
        File delFile = new File(filePath + "/" + fileName);
        delFile.delete();
    }
}

 

 

2、

/**
 * 生成Excel模板并导出
 */
@RequestMapping("/getExcelTemplate")
public void getExcelTemplate(HttpServletRequest request, HttpServletResponse response){

    //模板名称
    String fileName = "excel_template_voucherWallet.xlsx";
    String filePath = request.getSession().getServletContext().getRealPath("/temp/");
    //列字段标题
    String[] headers = {"姓名","代理商","国家码","手机号","代金券类型","代金券张数"};
    //设置填Excel的注意事项
    String notes = "1、手机号不能为空; 2、国家码默认为+86(中国)";
    //设置Excel标题
    String title = "代金券钱包";    //设置数据有效性(第几列为正整数)
    Integer [] positiveIntRows = {5};    //下拉框数据
    List<String[]> downData = new ArrayList<>();
    List<VoucherType> voucherTypeList;
    try {
        voucherTypeList = crmVoucherWalletService.getAllVoucherTypes();
    } catch (Exception e) {
        LOGGER.error("fail to get voucherType list", e);
        voucherTypeList = null;
    }
    if (CollectionUtils.isEmpty(voucherTypeList)) {
        downData.add(null);
    } else {
        List<String> typeList = voucherTypeList.stream().map(VoucherType::getTypeName).collect(Collectors.toList());
        String[] types = new String[typeList.size()];
        downData.add(typeList.toArray(types));
    }
    //下拉的列序号数组(序号从0开始)
    String [] downRows = {"4"};
    try {
        ExcelTemplateUtil.createExcelTemplate(filePath, fileName, headers, downData, downRows, notes, title, positiveIntRows);        ExcelTemplateUtil.getExcel(filePath, fileName, response, request);
        ExcelTemplateUtil.delFile(filePath, fileName);
    } catch (Exception e) {
        LOGGER.error("fail to get excel template");
    }
}

 

 

数据有效性参考

参考链接:https://blog.csdn.net/nihaoqiulinhe/article/details/56017450

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值