zoukankan      html  css  js  c++  java
  • java动态导出Excle模板

    实际开发中很多时候都需要导出Excle模板文件,而且是根据不同的需求需要导出不同的模板,在这里简单记录一下使用java实现普通的动态Excle模板导出功能。

    1.添加maven依赖:

    		<dependency>
    			<groupId>org.apache.poi</groupId>
    			<artifactId>poi</artifactId>
    			<version>3.8</version>
    		</dependency>
    		<dependency>
    			<groupId>org.apache.poi</groupId>
    			<artifactId>poi-ooxml</artifactId>
    			<version>3.8</version>
    		</dependency>
    		<dependency>
    			<groupId>org.apache.poi</groupId>
    			<artifactId>poi-ooxml-schemas</artifactId>
    			<version>3.8</version>
    		</dependency>
    
    1. 编写导出工具类:
    import java.io.OutputStream;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.lang3.StringUtils;
    import org.apache.poi.hssf.usermodel.HSSFCell;
    import org.apache.poi.hssf.util.HSSFColor;
    import org.apache.poi.ss.usermodel.Cell;
    import org.apache.poi.ss.usermodel.CellStyle;
    import org.apache.poi.ss.usermodel.Font;
    import org.apache.poi.ss.usermodel.RichTextString;
    import org.apache.poi.ss.usermodel.Row;
    import org.apache.poi.ss.usermodel.Sheet;
    import org.apache.poi.ss.usermodel.Workbook;
    import org.apache.poi.ss.util.CellRangeAddress;
    import org.apache.poi.ss.util.CellRangeAddressList;
    import org.apache.poi.xssf.usermodel.XSSFCellStyle;
    import org.apache.poi.xssf.usermodel.XSSFDataValidation;
    import org.apache.poi.xssf.usermodel.XSSFDataValidationConstraint;
    import org.apache.poi.xssf.usermodel.XSSFDataValidationHelper;
    import org.apache.poi.xssf.usermodel.XSSFFont;
    import org.apache.poi.xssf.usermodel.XSSFRichTextString;
    import org.apache.poi.xssf.usermodel.XSSFSheet;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    
    public class ExcelDownloadUtil {
    
        /**
         * 标题单元格默认长度
         */
        private static final int DEFAULT_COLUMN_SIZE = 20;
    
        /**
         * EXCEL含有下拉列表默认受影响行数
         */
        private static final int SELECT_HEIGHT = 300;
    
        /**
         * 用于动态生成导出模板
         * 
         * @param response 用于下载
         * @param sheetName 工作表空间名称
         * @param columnNames
         * @param title Excle模板标题,不需要则传null
         * @throws Exception
         */
        public static void getExcelTitleTemplate(HttpServletResponse response, String sheetName,
            List<Map<String, Object>> columnNames, String title) throws Exception {
            Workbook workBook = new XSSFWorkbook();
            // 生成一个表格
            Sheet sheet = workBook.getSheet(sheetName);
            if (sheet == null) {
                sheet = workBook.createSheet(sheetName);
            }
            // 最新Excel列索引,从0开始
            int lastRowIndex = sheet.getLastRowNum();
            if (lastRowIndex > 0) {
                lastRowIndex++;// 如果已经存在了工作表空间则从下一行开始
            }
            if (!StringUtils.isBlank(title)) {
                // 如果需要合并单元格显示一个大的title
                Row titleRow = sheet.createRow(lastRowIndex);
                //参数说明:1.起始行号 2.终止行号 3.起始列号 4.终止列号
                //这个需要实际情况自定义,我这里测试就写死0 0 0 4 了
                CellRangeAddress region = new CellRangeAddress(0, 0, 0, 4);
                sheet.addMergedRegion(region);// 合并单元格
                Cell cellTiltle = titleRow.createCell(0);
                // 设置样式
                cellTiltle.setCellStyle(createCellHeadStyle(workBook, false));
                // 单元格设置值
                cellTiltle.setCellValue(title);
                lastRowIndex++;
            }
    
            // 设置表格默认列宽度
            sheet.setDefaultColumnWidth(DEFAULT_COLUMN_SIZE);
            // 产生表格表头列标题行
            Row row = sheet.createRow(lastRowIndex);
            for (int i = 0; i < columnNames.size(); i++) {
                Map<String, Object> map = columnNames.get(i);
                Cell cell = row.createCell(i);
                // 设置单元格类型
                cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                // 设置单元格样式
                cell.setCellStyle(createCellHeadStyle(workBook, (boolean)map.get("isSpecial")));
                // 填充表头文本
                RichTextString text = new XSSFRichTextString((String)map.get("columnname"));
                cell.setCellValue(text);
                String[] selectValue = (String[])map.get("selectValue");
                // 如果需要有下拉列表则显示
                if (selectValue != null && selectValue.length != 0) {
                    // 准备下拉列表数据
                    CellRangeAddressList regions = new CellRangeAddressList(1, SELECT_HEIGHT, i, i);
                    // 创建下拉列表数据
                    XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper((XSSFSheet)sheet);
                    XSSFDataValidationConstraint dvConstraint =
                        (XSSFDataValidationConstraint)dvHelper.createExplicitListConstraint(selectValue);
                    XSSFDataValidation validation = (XSSFDataValidation)dvHelper.createValidation(dvConstraint, regions);
                    validation.setSuppressDropDownArrow(true);
                    validation.setShowErrorBox(true);
                    sheet.addValidationData(validation);
                }
            }
            OutputStream outputStream = response.getOutputStream();
            workBook.write(outputStream);// HSSFWorkbook写入流,下载
            outputStream.flush();// 刷新流
            outputStream.close();// 关闭流
    
        }
    
        /**
         * 创建单元格表头样式
         *
         * @param workbook 工作薄
         * @param bgColorYellow true-背景使用黄色
         * @return
         */
        private static CellStyle createCellHeadStyle(Workbook workbook, boolean bgColorYellow) {
            CellStyle style = workbook.createCellStyle();
            // 设置边框样式
            style.setBorderBottom(XSSFCellStyle.BORDER_THIN);
            style.setBorderLeft(XSSFCellStyle.BORDER_THIN);
            style.setBorderRight(XSSFCellStyle.BORDER_THIN);
            style.setBorderTop(XSSFCellStyle.BORDER_THIN);
            // 设置对齐样式
            style.setAlignment(XSSFCellStyle.ALIGN_CENTER);
            // 生成字体
            Font font = workbook.createFont();
            // 表头样式
            style.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
            // 如果是true,则显示黄色背景色
            style.setFillForegroundColor(bgColorYellow ? HSSFColor.YELLOW.index : HSSFColor.GREY_25_PERCENT.index);
            font.setFontHeightInPoints((short)12);
            font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
            // 把字体应用到当前的样式
            style.setFont(font);
            return style;
        }
    
        /**
         * 得到有效的Excel文件列有效数据
         * 
         * @param xianShiList
         * @param biTianList
         * @param jiGouId
         * @return
         */
        public static List<Map<String, Object>> getColumnNames(List<String> xianShiList, List<String> biTianList,
            String condition) {
            List<Map<String, Object>> columnNames = new ArrayList<Map<String, Object>>();
            Map<String, Object> resultMap = null;
            List<String> selectValues = null;
            boolean validaBiTianList = biTianList != null && !biTianList.isEmpty();
            for (int i = 0, len = xianShiList.size(); i < len; i++) {
                resultMap = new HashMap<String, Object>();
                // 得到下载的字段名称
                String columnName = xianShiList.get(i);
                // 判断该字段是否是字典类型,如果是字典类型的字段则需要显示下拉列表
                // 我这里用了一个枚举类涵盖所有的可能涉及的下载字段,每次判断一下是否需要获取字典值
                FieldEnum field = FieldEnum.getFieldEnum(columnName);
                if (field != null) {
                    resultMap.put("columnname", columnName);
                    // 判断字段是否是必填字段
                    if (validaBiTianList && biTianList.contains(columnName)) {
                        resultMap.put("isSpecial", true);// 如果是必填则标识为true
                    } else {
                        resultMap.put("isSpecial", false);
                    }
                    if (field.isZiDian()) {// 如果是字典值
                        // 获取字典内容
                        // ZiDianEntity ziDian = ZiDianUtil.getZiDian(columnName, condition);
                        // List<ZiDianZhiEntity> ziDianZhiEntityList = ziDian.getZiDianZhiList();
                        selectValues = new ArrayList<>();
                        // 添加字典值到下拉列表
                        /*for (int j = 0, lenx = ziDianZhiEntityList.size(); j < lenx; j++) {
                            selectValues.add(ziDianZhiEntityList.get(j).getZiDianZhi());
                        }*/
                        // 这里为了测试直接写死了
                        selectValues.add("男");
                        selectValues.add("女");
                        selectValues.add("未知");
                        resultMap.put("selectValue", selectValues.toArray(new String[selectValues.size()]));
                    }
                    columnNames.add(resultMap);
                }
            }
    
            return columnNames;
        }
    
        /**
         * 得到EXCEL模板下载时的显示字段
         * 
         * @param condition
         * @return
         * @throws Exception
         */
        public static List<String> listXianShiField(String condition) throws Exception {
            List<String> resultList = listExcelField("EXCEL下载时显示字段", condition);
            resultList = resultList != null && resultList.size() != 0 ? resultList
                : Arrays.asList(new String[] {"姓名", "身份证号", "性别", "联系电话", "联系地址"});
            return resultList;
        }
    
        /**
         * 得到EXCEL模板下载时的必填字段
         * 
         * @param jiGouId
         * @return
         * @throws Exception
         */
        public static List<String> listBiTianField(String jiGouId) throws Exception {
            List<String> resultList = listExcelField("EXCEL必填字段", jiGouId);
            resultList =
                resultList != null && resultList.size() != 0 ? resultList : Arrays.asList(new String[] {"姓名", "性别"});
            return resultList;
        }
    
        /**
         * 通过设置名称获取显示list集合
         * 
         * @param sheZhiMingCheng
         * @param condition
         * @return
         * @throws Exception
         */
        public static List<String> listExcelField(String sheZhiMingCheng, String condition) throws Exception {
            List<String> list = null;
            // 可以从数据库中动态获取,或者从程序中动态拼接出想要导出的字段
            //do something
            return list;
        }
    }
    

    枚举类补充:

    public enum FieldEnum {
        /**
         * 姓名
         */
        XING_MING("姓名", false),
        /**
         * 身份证号
         */
        SHEN_FEN_ZHENG_HAO("身份证号", false),
    
        /**
         * 性别
         */
        XING_BIE("性别", true),
    
        /**
         * 婚姻状况
         */
        HUN_YING_ZHUANG_KUANG("婚姻状况", true),
    
        /**
         * 联系人
         */
        LIAN_XI_REN("联系人", false),
        /**
         * 联系电话
         */
        LIAN_XI_DIAN_HUA("联系电话", false),
        /**
         * 联系地址
         */
        LIAN_XI_DI_ZHI("联系地址", false);
    
        /* 省略其他可能的属性 */
    
        private String name;
    
        private boolean isZiDian;
    
        private FieldEnum(String name, boolean isZiDian) {
            this.name = name;
            this.isZiDian = isZiDian;
        }
    
        /**
         * 通过name获取枚举类
         * 
         * @param name
         * @return
         */
        public static FieldEnum getFieldEnum(String name) {
            FieldEnum[] values = FieldEnum.values();
            for (int i = 0; i < values.length; i++) {
                if (values[i].getName().equals(name)) {
                    return values[i];
                }
            }
            return null;
        }
    
        public String getName() {
            return name;
        }
    
        public boolean isZiDian() {
            return isZiDian;
        }
    
    }
    

    3.实现下载:

    /**
         * 下载动态模板
         * 
         * @param request
         * @param response
         */
        @RequestMapping(value = "/downloadDongTaiMuBan.do")
        public void downloadDongTaiMuBan(HttpServletRequest request, HttpServletResponse response) {
            try {
                // 这里只是模仿一种条件,真正的条件需要根据实际情况传入
                String condition = request.getRequestURL().toString();
                System.out.println(condition);
                // 根据条件从数据库动态获取需要导出的EXCEL字段
                List<String> xianShiList = ExcelDownloadUtil.listXianShiField(condition);
                if (xianShiList != null && !xianShiList.isEmpty()) {
                    // 根据条件从数据库动态获取必填的EXCEL字段
                    List<String> biTianList = ExcelDownloadUtil.listBiTianField(condition);
                    // 文件名编码,解决乱码问题
                    String fileName = "登记.xlsx";
                    String userAgentString = request.getHeader("User-Agent");
                    String browser = UserAgent.parseUserAgentString(userAgentString).getBrowser().getGroup().getName();
                    if (browser.equals("Chrome") || browser.equals("Internet Exploer") || browser.equals("Safari")) {
                        fileName = URLEncoder.encode(fileName, "utf-8").replaceAll("\+", "%20");
                    } else {
                        fileName = MimeUtility.decodeText(fileName);
                    }
                    // 设置请求
                    response.setCharacterEncoding("UTF-8");
                    response.setContentType("application/x-download");
                    response.addHeader("Content-Disposition", String.format("attachment; filename="%s"", fileName));
                    response.addHeader("Cache-Control", "no-cache, no-store, must-revalidate");
                    response.addHeader("Pragma", "no-cache");
                    response.addHeader("Expires", "0");
    
                    final String sheetName = "第一分组";// 设置EXCEL默认工作表空间名称
                    // 处理EXCEL字段,标识出需要必填的字段,有下拉列表的字段,获取下拉列表的值
                    List<Map<String, Object>> columnNames =
                        ExcelDownloadUtil.getColumnNames(xianShiList, biTianList, condition);
                    if (columnNames != null && !columnNames.isEmpty()) {
                        ExcelDownloadUtil.getExcelTitleTemplate(response, sheetName, columnNames, "登记信息");
                    }
    
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("生成下载动态模板异常!", e);
            }
    
        }
    

    4.效果预览:
    在这里插入图片描述
    通过以上代码就简单实现Excle模板动态导出功能啦。

    一颗安安静静的小韭菜。文中如果有什么错误,欢迎指出。
  • 相关阅读:
    洛谷单元最短路标准版——spfa优化
    airline
    有依赖的背包
    挖地雷
    带分数问题
    子集和问题
    循环比赛日程表
    传纸条
    机器分配
    分组背包
  • 原文地址:https://www.cnblogs.com/c-Ajing/p/13448381.html
Copyright © 2011-2022 走看看