• POI导出Excel


      前言

      数据报表是许多项目都有的模块,一般都是导出Excel或者PDF,这里记录下我在项目里用POI导出Excel。项目中,我需要根据页面jqgrid的机架查询条件导出对应的机架数据,jqgrid是分页的,但导出是要导出所有。

      POI

      Apache POI - the Java API for Microsoft Documents,官网:http://poi.apache.org/

      代码编写

      maven引如POI

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
    </dependency>

      或者

    <dependency><!--Excel工具类(Easy POI)-->
        <groupId>cn.afterturn</groupId>
        <artifactId>easypoi-base</artifactId>
        <version>3.2.0</version>
    </dependency>
    <dependency><!--Excel工具类(Easy POI)-->
        <groupId>cn.afterturn</groupId>
        <artifactId>easypoi-web</artifactId>
        <version>3.2.0</version>
    </dependency>
    <dependency><!--Excel工具类(Easy POI)-->
        <groupId>cn.afterturn</groupId>
        <artifactId>easypoi-annotation</artifactId>
        <version>3.2.0</version>
    </dependency>

      html、js调用

    <button type="button" class="btn btn-default fa table-download float-right" onclick="exportRackExcel();">导出</button>
    //导出excel
    function exportRackExcel() {
        //获取当前jqGrid分页参数
        var postData = $("#rack").jqGrid("getGridParam", "postData");
        postData.page = 1;
        postData.rows = 999999999;//设置每页9亿条记录(相当于无穷大,查询所有)
        //ajax不支持Excel类型,使用location.href或者表单提交
        //window.location.href,get提交,数据会暴露在URL,相对不安全
        //创建临时的、隐藏的form表单,post提交,数据在请求体里,相对安全
        var $form = $(document.createElement('form')).css({display: 'none'}).attr("method", "POST").attr("action", ctx + "/excel");
        for (var key in postData) {
            var $input = $(document.createElement('input')).attr('name', key).val(postData[key]);
            $form.append($input);
        }
        $("body").append($form);
        $form.submit();
        //过河拆桥,提交完成后remove掉
        $form.remove();
    }

      

      controller

        /**
         * 根据当前jqGrid分页情况,创建并导出Excel文件
         *
         * @param entity 机架实体,用来接收查询条件
         * @return ResponseEntity
         */
        @PostMapping("/excel")
        public ResponseEntity createExcel(RackVo entity) {
            //Excel对应的columnNames列名集合 { key,label }
            String[][] excelMap = {
                    {"no", "Rack Code"},
                    {"rackName", "Rack Name"},
                    {"roomName", "Room"},
                    {"idc", "IDC Center"},
                    {"clientName", "Customer"},
                    {"rackTypeName", "Type"},
                    {"existentialMode", "Existential Mode"},
                    {"maxPower", "Maximum Power(KVA)"},
                    {"status", "Status"},
                    {"administrate", "Administrate"},
            };
            return DownloadUtil.download(ExportExcelUtil.createExcel("Rack Management", excelMap, rackService.createExcel(entity).getData()).getData(), "机架数据报表");
        }

      两个工具类:导出Excel工具类 ExportExcelUtil,下载工具类 DownloadUtil

    /**
     * java POI 导出Excel表工具类
     */
    public class ExportExcelUtil {
    
        //禁止实例化
        private ExportExcelUtil() {
        }
    
        /**
         * 只支持一级表头
         *
         * @param titleName   表标题
         * @param columnNames 列名集合,key是用来设置填充数据时对应单元格的值,label就是对应的列名,生成Excel表时,
         *                    第一维数组下标0对应值为Excel表最左边的列的列名 例:{ { key,label },{ key,label } }
         * @param dataLists   数据集合,key对应的是列名集合的key,value是要填充到单元格的值 例:ArrayList<HashMap<String key, String vaule>>
         * @return ResultModel<Workbook>
         */
        public static ResultModel<Workbook> createExcel(String titleName, String[][] columnNames, ArrayList<HashMap<String, String>> dataLists) {
          
            //创建HSSFWorkbook对象(excel的文档对象)
            HSSFWorkbook wb = new HSSFWorkbook();
            //建立新的sheet对象(excel的表单)
            HSSFSheet sheet = wb.createSheet(titleName);//设置表单名
    
            //1、标题名
            //创建标题行,参数为行索引(excel的行),可以是0~65535之间的任何一个
            HSSFRow row1 = sheet.createRow(0);
    
            //标题的字体
            HSSFFont font1 = wb.createFont();
            font1.setFontHeightInPoints((short) 12);
            font1.setFontName("黑体");
    
            //标题的样式
            HSSFCellStyle style1 = wb.createCellStyle();
            style1.setAlignment(HSSFCellStyle.ALIGN_CENTER);//水平居中
            style1.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//垂直居中
    
            // 把字体 应用到当前样式
            style1.setFont(font1);
    
            //自动换行
            style1.setWrapText(true);
    
            //自定义填充颜色(天空蓝)
            style1.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            style1.setFillForegroundColor(IndexedColors.SKY_BLUE.getIndex());
    
            // 设置边框
            style1.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            style1.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            style1.setBorderRight(HSSFCellStyle.BORDER_THIN);
            style1.setBorderTop(HSSFCellStyle.BORDER_THIN);
    
            createCell(row1, 0, style1, titleName);
            //合并单元格CellRangeAddress构造参数依次表示起始行,截至行,起始列, 截至列
            sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, columnNames.length - 1));
    
            //2、列名
            //创建列名行
            //列名的字体
            HSSFFont font2 = wb.createFont();
            font2.setFontHeightInPoints((short) 12);
            font2.setFontName("新宋体");
    
            //列名的样式
            HSSFCellStyle style2 = wb.createCellStyle();
            style2.setAlignment(HSSFCellStyle.ALIGN_CENTER);//水平居中
            style2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//垂直居中
    
            // 把字体 应用到当前样式
            style2.setFont(font2);
    
            //自动换行
            style2.setWrapText(true);
    
            //自定义填充颜色(浅蓝色)
            style2.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            style2.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
    
            // 设置边框
            style2.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            style2.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            style2.setBorderRight(HSSFCellStyle.BORDER_THIN);
            style2.setBorderTop(HSSFCellStyle.BORDER_THIN);
    
            HSSFRow row2 = sheet.createRow(1);
            for (int i = 0; i < columnNames.length; i++) {
                //单元格宽度
                sheet.setColumnWidth(i, 20 * 256);
                createCell(row2, i, style2, columnNames[i][1]);//例:[[key,label],[key,label]] 取label
            }
    
            //3、填充数据
            //内容的字体
            HSSFFont font3 = wb.createFont();
            font3.setFontHeightInPoints((short) 12);
            font3.setFontName("新宋体");
    
            //内容的样式
            HSSFCellStyle style3 = wb.createCellStyle();
            style3.setAlignment(HSSFCellStyle.ALIGN_CENTER);//水平居中
            style3.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//垂直居中
    
            // 把字体 应用到当前样式
            style3.setFont(font3);
    
            //自动换行
            style3.setWrapText(true);
    
            //默认无填充
            style3.setFillPattern(FillPatternType.NO_FILL);
            style3.setFillForegroundColor(IndexedColors.RED.getIndex());
    
            // 设置边框
            style3.setBorderBottom(HSSFCellStyle.BORDER_THIN);
            style3.setBorderLeft(HSSFCellStyle.BORDER_THIN);
            style3.setBorderRight(HSSFCellStyle.BORDER_THIN);
            style3.setBorderTop(HSSFCellStyle.BORDER_THIN);
    
            int index = 2;//标题行、列名行,所以数据行默认从第三行开始
            for (HashMap<String, String> map : dataLists) {
                //创建内容行
                HSSFRow row3 = sheet.createRow(index);
                for (int i = 0; i < columnNames.length; i++) {
                    String val = map.get(columnNames[i][0]);
                    createCell(row3, i, style3, val == null ? "" : val);//例:[[key,label],[key,label]] 取key
                }
                index++;
            }
    
            return ResultModel.of(wb);
        }
    
        /**
         * 创建一个单元格
         *
         * @param row       行
         * @param column    列
         * @param cellStyle 单元格样式
         * @param text      值
         */
        private static void createCell(Row row, int column, CellStyle cellStyle, String text) {
            Cell cell = row.createCell(column);  // 创建单元格
            cell.setCellValue(text);  // 设置值
            cell.setCellStyle(cellStyle); // 设置单元格样式
        }
    }
    /**
     * 文件下载工具类
     */
    public class DownloadUtil{
    /**
         * 快速下载
         */
        public static ResponseEntity download(byte[] fileBytes, String fileName) {
            //设置文件
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentDispositionFormData("attachment", new String(fileName.getBytes(StandardCharsets.UTF_8),StandardCharsets.ISO_8859_1);
            //下载文件
            return new ResponseEntity<>(fileBytes, headers, HttpStatus.CREATED);
        }
    
        /**
         * 快速下载
         */
        public static ResponseEntity download(File file) {
    
            return download(getByteArray(file), file.getName());
        }
    
        /**
         * 快速下载
         */
        public static ResponseEntity download(Workbook workbook, String fileName) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            try {
                fileName = fileName + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".xls";
                workbook.write(outputStream);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return download(outputStream.toByteArray(), fileName);
        }
    
        //获取文件的字节数组
        private static byte[] getByteArray(File file) {
            if (!file.exists()) {
                throw new RuntimeException("File Not Found:" + file.getPath());
            }
            ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
            BufferedInputStream in = null;
            try {
                in = new BufferedInputStream(new FileInputStream(file));
                int buf_size = 1024;
                byte[] buffer = new byte[buf_size];
                int len;
                while (-1 != (len = in.read(buffer, 0, buf_size))) {
                    bos.write(buffer, 0, len);
                }
                return bos.toByteArray();
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            } finally {
                try {
                    assert in != null;
                    in.close();
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        //获取文件名后缀
        private static String getSuffix(String fileName) {
            int lastPointIndex = fileName.lastIndexOf(".");
            if (StringUtils.isEmpty(fileName) || lastPointIndex == -1) {
                return null;
            }
            return fileName.substring(lastPointIndex + 1);
        }
    }

      获取封装数据的service层 createExcel,直接到取page分页方法,遍历机架数据集合,设置Map<key,value>,add到list<Map>中,最后将封装好的数据return回controller,传入工具类,最后下载。

        /**
         * 根据当前jqGrid分页情况,创建并导出Excel文件
         *
         * @param entity 查询条件
         * @return 封装好的数据集合
         */
        @Override
        public ResultModel<ArrayList<HashMap<String, String>>> createExcel(RackVo entity) {
            ArrayList<HashMap<String, String>> dataLists = new ArrayList<HashMap<String, String>>();
            //直接调page分页方法,获取当前jqGrid分页条件对应的数据集合,
            ResultModel<PageInfo<RackVo>> rm = page(entity);
            if (rm.isFlag()) {
                List<RackVo> rackVoList = rm.getData().getRows();
                for (RackVo rackVo : rackVoList) {
                    HashMap<String, String> map = new HashMap<String, String>(16);
                    map.put("no", rackVo.getNo() != null ? rackVo.getNo() : "");
                    map.put("rackName", rackVo.getName() != null ? rackVo.getName() : "");
                    map.put("roomName", rackVo.getRoom() != null ? rackVo.getRoom().getRoomname() : "");
                    map.put("idc", rackVo.getOrg() != null ? rackVo.getOrg().getOrgName() : "");
                    map.put("clientName", rackVo.getCustomer() != null ? rackVo.getCustomer().getClientname() : "");
                    map.put("rackTypeName", rackVo.getRacktype() != null ? rackVo.getRacktype().getName() : "");
                    map.put("existentialMode", "1".equals(rackVo.getExistentialMode()) ? "Physical" : "Virtual");
                    map.put("maxPower", rackVo.getMaxpower() != null ? rackVo.getMaxpower() : "");
                    String status = rackVo.getServiceStatus();
                    switch (status != null ? status : "") {
                        case "1":
                            status = "Idle";
                            break;
                        case "2":
                            status = "Reserved";
                            break;
                        case "3":
                            status = "Occupied";
                            break;
                        default:
                            status = "";
                            break;
                    }
                    map.put("status", status);
                    String administrate = rackVo.getAdministrate();
                    switch (administrate != null ? administrate : "") {
                        case "R":
                            administrate = "Cust Own";
                            break;
                        case "U":
                            administrate = "CTG Own";
                            break;
                        default:
                            administrate = "";
                            break;
                    }
                    map.put("administrate", administrate);
                    dataLists.add(map);
                }
            }
            return ResultModel.of(dataLists);
        }

      效果

      从开发阶段到测试阶段,导了无数次,没毛病

      小升级

      excelMap,Excel对应的columnNames列名集合 { key,label },可以不用再controller设置了,直接从页面jqgrid抓取,传入controller就行(滑稽脸~)

    //获取jqgrid头部标题tr,有多少个tr就有多少级标题
    var thead_tr = $(".ui-jqgrid-htable").find("tr.ui-jqgrid-labels");
    
    //遍历thead_tr找出每一个标题,并保存到对象中
    var titles = [];
    thead_tr.each(function(index_tr,element_tr){
        titles.push([]);
        $(element_tr).find("th").each(function(index_th,element_th){
            //内容
            var label = $(element_th).text();        
            
            //所占行 rowspan 默认1
            var rowspan = $(element_th).attr("rowspan") || 1;
            
            //所占列 colspan 默认1
            var colspan = $(element_th).attr("colspan") || 1;
            
            //
            var key = $(element_th).attr("id");
            key = key.substring(key.lastIndexOf("_")+1,key.length);
            
            if(label){
                titles[index_tr].push({
                    label:label,
                    key:key,
                    rowspan:rowspan,
                    colspan:colspan,
                });
            }
        });
    });
    //JSON.stringify(titles)
    console.log(titles);

  • 相关阅读:
    构造方法中使用this的含义
    Android Bundle类
    Android中使用PULL方式解析XML文件
    Android 创建与解析XML(四)—— Pull方式
    File的getPath()和getAbsolutePath()和getCanonicalPath()的区别
    Android-取出SDcard卡下指定后缀名的文件
    page、request、session和application有什么区别?
    prepareStatement的用法和解释
    pageContext对象的用法
    使用JSP连接MySql数据库读取HTML表单数据进行存贮
  • 原文地址:https://www.cnblogs.com/huanzi-qch/p/9964231.html
Copyright © 2020-2023  润新知