POI3级以及3级以下表头的报表处理

来源:互联网 发布:cyberghost for mac 编辑:程序博客网 时间:2024/06/03 07:09

POI3级以及3级以下表头的报表处理

最近做Excel导出,本来好好的,直接用模板导出就好了,结果需求一句话,就来句要动态导出,所以迫不得已得自己写表头啦。。。
开发人员的悲催啊。。。,需求要啥咱得给啊。。
哈哈,说笑啦,不过也确实是因为这个才弄啦这个表头处理,也是这个东西让我有感觉想写BLOG啦,算是谢谢咱家需求啦~

简单说一下这个实现的功能,其实就是通过POI导出数据,不过可以通过固定格式的字符串来定义表头,之后填写数据,然后导出,不过是WEB端的导出。

3级表头字符串如下(使用 , : _ = @ 来进行分级处理,用List太麻烦,用数组没办法处理,只能这么做啦)例如: TA:TA1=TA11@TA12_TA2,TB
2级表头字符串如下(使用 , : _ 来进行分级处理)例如: TA:TA1_TA2,TB
1级表头就没啥说啦,逗号分隔

下面干脆点,直接代码啦

import java.io.IOException;import java.io.OutputStream;import java.util.*;import javax.servlet.http.HttpServletResponse;import org.apache.poi.hssf.usermodel.*;import org.apache.poi.hssf.util.Region; /**  * 文件名称:PoiUtilDetailTile.java  * 模块名称:poi导出同时进行多重表头处理,以及相关的数据插入和导出  * 完成日期:  *   * 文件调用:  * 修改记录:  * 修改时间:  * 修  改  人:  * 修改内容:  * 关联BUG:  * 修改方法:   */@SuppressWarnings("deprecation")public class PoiUtilDetailTitle {        private HSSFCellStyle titleStyle = null;        private HSSFCellStyle bodyStyle = null;          /**           * 初始化样式           */        private void init(HSSFWorkbook wb) {                  titleFont(wb);                  bodyFont(wb);        }        /**         * 设置body样式         *          */        private void bodyFont(HSSFWorkbook wb) {                  HSSFFont bodyFont = wb.createFont();                  bodyFont.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);                  bodyFont.setFontName("宋体");                  bodyFont.setFontHeightInPoints((short) 9);                  bodyStyle = wb.createCellStyle();                  bodyStyle.setFont(bodyFont);                  bodyStyle.setBorderTop((short)1);                  bodyStyle.setBorderRight((short)1);                  bodyStyle.setBorderBottom((short)1);                  bodyStyle.setBorderLeft((short)1);                  bodyStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);                  bodyStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);        }          /**          * 设置标题样式          *           */         private void titleFont(HSSFWorkbook wb) {                   HSSFFont titleFont = wb.createFont();                   titleFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);                   titleFont.setFontName("宋体");                   titleFont.setFontHeightInPoints((short) 12);                   titleStyle = wb.createCellStyle();                   titleStyle.setFont(titleFont);                   titleStyle.setBorderBottom((short)1);                   titleStyle.setBorderTop((short)1);                   titleStyle.setBorderRight((short)1);                   titleStyle.setBorderLeft((short)1);                   titleStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);                   titleStyle.setVerticalAlignment(HSSFCellStyle.ALIGN_CENTER);         }        /**         * createAndExportWb         * 创建并导出wb         * @param filename 导出文件名称         * @param itsheets         * 是一个Maplist 内容有         * namesheet的名称         * titleTypesheettitle的类型,值有 3(3级表头),2(2级表头),他同时也对应表头的级别         * titleStringsheettitle的串(没处理1级,有功夫再写,1级的也简单)         * 3级表头字符串如下(使用 ,  :  _  =   @ 来进行分级处理,用List太麻烦,用数组没办法处理,只能这么做啦)         * 例如:  TA:TA1=TA11@TA12_TA2,TB         * 2级表头字符串如下(使用 ,  :  _ 来进行分级处理)例如: TA:TA1_TA2,TB         *          * datalist : 对应的数据,要求数据中不会出现null,或者少值,因为这样会出现串列的问题  List<List<Object>>         * @param response          * void         * @exception          * @since  1.0.0         */        @SuppressWarnings({ "unchecked" })        public void createAndExportWb(String filename,List<Map<String,Object>> itsheets,HttpServletResponse response){            HSSFWorkbook wb=new HSSFWorkbook();             init(wb);             for(Map<String,Object> stmap :itsheets){//循环处理sheet                 String name=(String) stmap.get("name");                 int titleType=(int) stmap.get("titleType");                 String titleString=(String) stmap.get("titleString");                 List<List<Object>> datalist=(List<List<Object>>) stmap.get("datalist");                 HSSFSheet sheet=wb.createSheet(name);//创建sheet                 doSheetFillIn(sheet,titleType,titleString,datalist);//处理sheet的主方法             }             doExportExcel(response,filename,wb);         }        /**         * doSheetFillIn         * 处理sheet         * @param sheet         * @param titleType         * @param titleString         * @param datalist          * void         * @exception          * @since  1.0.0         */        private void doSheetFillIn(HSSFSheet sheet, int titleType, String titleString,                List<List<Object>> datalist) {            if(3==titleType){                doSheetFillIn_Three(sheet,titleString);//处理3级表头            }else if(2==titleType){                doSheetFillIn_Two(sheet,titleString);//处理2级表头            }else if(1==titleType){                doSheetFillIn_One(sheet,titleString);//处理1级表头            }            doFillInSheetData(sheet,titleType,datalist);//填写数据        }        /**         * doSheetFillIn_One         * 处理1级表头         * @param sheet         * @param titleString          * void         * @exception          * @since  1.0.0         */        private void doSheetFillIn_One(HSSFSheet sheet, String titleString) {            HSSFRow row1 = sheet.createRow(0);            String[]  headers=titleString.split(",");            for(short i = 0; i < headers.length; i++){//i是headers的索引,也是Excel的索引                HSSFCell cellT = row1.createCell(i);                cellT.setCellStyle(titleStyle);                HSSFRichTextString text = new HSSFRichTextString(headers[i]);                cellT.setCellValue(text);            }        }        /**         * doSheetFillIn_Two         * 2级表头处理         * @param sheet         * @param titleString          * 字符串样例     2级表头字符串如下(使用 ,  :  _ 来进行分级处理)例如: TA:TA1_TA2,TB          * void         * @exception          * @since  1.0.0         */        private void doSheetFillIn_Two(HSSFSheet sheet, String titleString) {            HSSFRow row1 = sheet.createRow(0);            HSSFRow row2 = sheet.createRow(1);            String[]  headers=titleString.split(",");            for(short i = 0, n = 0; i < headers.length; i++){//i是headers的索引,n是Excel的索引                HSSFCell cellT = row1.createCell(n);                cellT.setCellStyle(titleStyle);                HSSFRichTextString text = null;                if(headers[i].contains(":")){//2级标题                    String[] temp = headers[i].split(":");//子标题的分割                    text = new HSSFRichTextString(temp[0]);                    String[] childlv1 = temp[1].split("_");                    sheet.addMergedRegion(new Region(0, n, 0, (short) (n + childlv1.length -1)));//2级标题的时候可以直接根据2子标题的个数来合并                    short tempI = n;                    for(int j = 0; j < childlv1.length -1; j++){//循环补充父标题的空格                        HSSFCell cellTitleBlank = row1.createCell(++tempI);                        cellTitleBlank.setCellStyle(titleStyle);                    }                    for(int j = 0; j < childlv1.length; j++){//循环插入自标题的内容                        HSSFCell cellChild = row2.createCell(n++);                        cellChild.setCellStyle(titleStyle);                        cellChild.setCellValue(new HSSFRichTextString(childlv1[j]));                        }                }else{//1级标题                    HSSFCell cell2 = row2.createCell(n);                    cell2.setCellStyle(bodyStyle);                    text = new HSSFRichTextString(headers[i]);                    sheet.addMergedRegion(new Region(0, n, 1, n));//没有子标题的时候自己独占两行                    n++;                }                cellT.setCellValue(text);            }        }        /**         * doSheetFillIn_Three         * 3级表头处理         * @param sheet         * @param titleString          * * 3级表头字符串如下(使用 ,  :  _  =   @ 来进行分级处理,用List太麻烦,用数组没办法处理,只能这么做啦)         * 例如:  TA:TA1=TA11@TA12_TA2,TB         * void         * @exception          * @since  1.0.0         */        private void doSheetFillIn_Three(HSSFSheet sheet, String titleString) {            HSSFRow row1 = sheet.createRow(0);            HSSFRow row2 = sheet.createRow(1);            HSSFRow row3 = sheet.createRow(2);            String[]  headers=titleString.split(",");            for(short i = 0, n = 0; i < headers.length; i++){//i是headers的索引,n是Excel的索引                HSSFCell cellT = row1.createCell(n);                cellT.setCellStyle(titleStyle);                HSSFRichTextString text = null;                if(headers[i].contains(":")){//有2级标题                    if(headers[i].contains("=")){//有3级标题    TA:TA1=TA11@TA12_TA2                        //确定3级标题的个数,确定1级标题的总长度,同时也是把各级标题分解开                        String[] temp = headers[i].split(":");                      //分级1级标题temp[0]是标题文字,temp[1]是子标题                        text = new HSSFRichTextString(temp[0]);                        String[] childlv2=temp[1].split("_");                       //获取temp2级标题的数组                        int ttlength=0;                        short row2index=n;                        short row3index=n;                        for(int k=0;k<childlv2.length;k++){                         //循环计算全部的2级标题对应的子标题总数                            String childlv2_1=childlv2[k];                          //取到2级标题的第一个                            HSSFRichTextString textLV2 = null;                            HSSFCell cellChildlv2 = row2.createCell(row2index++);   //根据row2的index进行循环                            cellChildlv2.setCellStyle(titleStyle);                            //一层层的向下取,取到3级,并向下进行补充                            if(childlv2_1.contains("=")){//2级子节点,有3级子节点                                String[] childlv2_all=childlv2_1.split("=");                                textLV2=new HSSFRichTextString(childlv2_all[0]);                                String childlv3_1=childlv2_all[1];                                if(childlv3_1.contains("@")){//这里说明2级子节点有多个3级子节点,那么2级子节点就需要合并,同时为                                    String[] childlv3_all=childlv3_1.split("@");                                    ttlength=ttlength+childlv3_all.length;                                    //开始写3级节点                                    for(String childlv3Text : childlv3_all){                                        HSSFCell cellChildlv3 = row3.createCell(row3index++);                                        cellChildlv3.setCellStyle(titleStyle);                                        cellChildlv3.setCellValue(new HSSFRichTextString(childlv3Text));                                        n++;//进行EXCEL索引叠加                                    }                                    //这里进行2级节点的合并,因为有多个                                    sheet.addMergedRegion(new Region(1, row2index, 1, (short)(row2index+childlv3_all.length-1)));                                    //补充2级节点的空cell                                    for(int x=0;x<childlv3_all.length-1;x++){                                        HSSFCell cellChildlv2Blank = row2.createCell(++row2index);                                        cellChildlv2Blank.setCellStyle(titleStyle);                                    }                                }else{//这里说明2级子节点只有一个3级子节点,那么就不用合并和补充空格啦                                    ttlength=ttlength+1;                                    //写入3级节点的cell                                    HSSFCell cellChildlv3 = row3.createCell(row3index++);                                    cellChildlv3.setCellStyle(titleStyle);                                    cellChildlv3.setCellValue(new HSSFRichTextString(childlv3_1));                                    n++;//Excel索引节点的递增                                }                            }else{//2级子几点没有3及子节点                                textLV2=new HSSFRichTextString(childlv2_1);                                ttlength=ttlength+1;                                //这个2级节点没有子节点,那么就要合并3row                                sheet.addMergedRegion(new Region(1, row3index, 2, row3index));                                //补充3row的cell空格                                HSSFCell cellChildlv3Blank = row3.createCell(row3index++);                                cellChildlv3Blank.setCellStyle(titleStyle);                                n++;//进行Excel的索引递增,避免写到一个格子里面去                            }                            cellChildlv2.setCellValue(textLV2);                        }                        //进行3层总长度的cell合并                        sheet.addMergedRegion(new Region(0, (short)(n-ttlength), 0, (short) (n-1)));                        //插入第一行的补充的空格                        short tr1 = n;                        for(int j = 0; j < ttlength -1; j++){//循环补充父标题的空格,因为已经定义啦一个cell所以要减1                            HSSFCell cellTitleBlank = row1.createCell(++tr1);//因为开始已经定义啦一个cell所以就是 ++tr1                            cellTitleBlank.setCellStyle(titleStyle);                        }                    }else{//只有2级标题                        String[] temp = headers[i].split(":");//子标题的分割                        text = new HSSFRichTextString(temp[0]);                        String[] childlv2 = temp[1].split("_");                        //只有2及标题,那么1级标题要占2行,2级标题占1行                        sheet.addMergedRegion(new Region(0, n, 1, (short) (n + childlv2.length -1)));                        short tr1 = n;                        short tr2 = n;                        short tr3 = n;                        //对对应的空行进行补充,第一行                        for(int j = 0; j < childlv2.length -1; j++){//循环补充父标题的空格,因为已经定义啦一个cell所以要减1                            HSSFCell cellTitleBlank = row1.createCell(++tr1);//因为开始已经定义啦一个cell所以就是 ++tr1                            cellTitleBlank.setCellStyle(titleStyle);                        }                        //对第二行进行补充空格,从头开始                        for(int k=0;k < childlv2.length; k++){//未定义cell,所以不减1                            HSSFCell cellTitleBlank = row2.createCell(tr2++);//之前未进行定义,所以是tr2++                            cellTitleBlank.setCellStyle(titleStyle);                        }                        //插入子行信息                        for(int j = 0; j < childlv2.length; j++){//循环插入子标题的内容                            HSSFCell cellChild = row3.createCell(tr3++);                            cellChild.setCellStyle(titleStyle);                            cellChild.setCellValue(new HSSFRichTextString(childlv2[j]));                                n++;//这里进行啦EXCEL的索引递增,不然会都写到一个格子里面去                        }                    }                }else{//只有1级标题                    HSSFCell cell2 = row2.createCell(n);                    cell2.setCellStyle(titleStyle);                    HSSFCell cell3 = row3.createCell(n);                    cell3.setCellStyle(titleStyle);                    text = new HSSFRichTextString(headers[i]);                    sheet.addMergedRegion(new Region(0, n, 2, n));//没有子标题的时候自己独占两行                    n++;                }                cellT.setCellValue(text);            }        }        /**         * doFillInSheetData         * 填写数据         * @param sheet          * @param beginRow  开始行数         * @param datalist  数据列表,进行循环写入即可         * void         * @exception          * @since  1.0.0         */        private void doFillInSheetData(HSSFSheet sheet, int beginRow,List<List<Object>> datalist) {            if(null != datalist && datalist.size() > 0){                 int beginNum=beginRow;//设定起始地行数                 HSSFRow row = null;                 HSSFCell cell = null;                 for(int i=0; i<datalist.size(); i++){//循环数据                     row = sheet.createRow(beginNum++);                     List<Object> data=datalist.get(i);                     int j=0;                     for(Object en :data){                         cell = row.createCell(j++);                         cell.setCellStyle(bodyStyle);                         cell.setCellValue(new HSSFRichTextString(String.valueOf(en)));                     }                 }            }        }        /**         * doExportExcel         * 进行excel导出         * @param response         * @param filename,文件名称         * @param wb          * void         * @exception          * @since  1.0.0         */        private void doExportExcel(HttpServletResponse response,String filename,HSSFWorkbook wb){            OutputStream out=null;              try {                  filename = new String(filename.getBytes("GBK"), "ISO8859_1");//中文处理                response.setHeader("content-disposition", "attachment; filename="+filename);                  response.setContentType("application/msexcel");                  out=response.getOutputStream();                  wb.write(out);                  out.flush();            } catch (Exception e) {                 e.printStackTrace();             } finally {                 if (out!=null){try {out.close();} catch (IOException e) {}}             }          }}

这里的导出时在web端的导出,想改成本地的自己调整下就好啦。
样式什么的自己在两个style里调整就好啦
不过还有一个问题,就是没做列的宽度自适应,想啦想,让他们自己拖去吧~~~

0 0
原创粉丝点击