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

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里调整就好啦
不过还有一个问题,就是没做列的宽度自适应,想啦想,让他们自己拖去吧~~~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值