POI导出数据并上色

   针对POI中的后台遍历,存值取值,逐行上色,合并列,在这一次的项目经历中有所学习。

   需求:针对给出的大致模板,后台生成excel文件,对某些列进行合并,对某几种条件下的数据进行颜色标注

   解决思路:1.根据导出模板,查询出需要导出的数据sql。

                     2.将表头给定义出来,由于是大致模板,初始化表头有利于后期改动

                     3.遍历数据,针对需要合并的单元格编写方法

                     4.筛选条件,对符合条件的数据进行颜色标注。

  大致效果,如下:(由于存在敏感数据,只能如此)

  

1.导出sql语句--根据模板要求写出sql语句即可,如果涉及到合并不好做的话,可以根据情况将sql分开。

2.定义表头,将表头定义到一个config中,这样后期针对顺序的变化以及其他参数的定义都有很大的好处,

public static List<String[]>  getNewExcelHeaders(){
		//设置表头
		List<String[]> headorder = new ArrayList<String[]>();
		
		String[] h1 = new String[5];
		h1[0] = "orgName";
		h1[1] = "部门";
		h1[2] = "5000";
		h1[3] ="3"; //3垂直剧中 
		h1[4] ="0"; //是否合并
		headorder.add(h1);
		
		String[] h2 = new String[5];
		h2[0] = "empName";
		h2[1] = "业务人员";
		h2[2] = "5000";
		h2[3] = "3";
		h2[4] ="0"; //是否合并
		headorder.add(h2);
		
		String[] h3 = new String[5];
		h3[0] = "firstOrderDate";
		h3[1] = "首单日期";
		h3[2] = "7000";
		h3[3] = "-1";
		h3[4] ="1"; //是否合并
		headorder.add(h3);
		
		String[] h4 = new String[5];
		h4[0] = "customType";
		h4[1] = "";
		h4[2] = "5000";
		h4[3] = "3";
		h4[4] ="0"; //是否合并
		headorder.add(h4);
		
		String[] h5 = new String[5];
		h5[0] = "customName";
		h5[1] = "客户名称";
		h5[2] = "8000";
		h5[3] = "3";
		h5[4] ="1"; //是否合并
		headorder.add(h5);

       return headorder;
}

这里说一下为何这样定义:

      定义h[0]和h[1],是为了显示和获取值可以一目了然,便于后期位置的变化,同时可以直接用属性名去遍历

     定义h[2]是为了控制宽度,很多时候由于字段名太长,默认宽度显示不了

    定义h[3]和h[4]是为了垂直居中(后面知晓有HSSFCellStyle.VERTICAL_CENTER后弃用了)和是否合并

下一步就是将标题和表头给显示出来

  

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		//1.取表头
		List<String[]> heads = PaConfig.getNewExcelHeaders();
		int line = 1, maxColumn = 0;
		maxColumn = heads.size();
		HSSFWorkbook workbook = new HSSFWorkbook();
		Sheet sheet = workbook.createSheet();
		Row row = null;
		Cell cell = null;
		Font font = workbook.createFont();
		CellStyle style = workbook.createCellStyle();
		style.setBorderBottom(CellStyle.BORDER_THIN); 
		style.setBorderLeft(CellStyle.BORDER_THIN); 
		style.setBorderRight(CellStyle.BORDER_THIN); 
		style.setBorderBottom(CellStyle.BORDER_THIN); 
		style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);

		//写标题
		String title = month+PaConfig.excelTitle;
		font.setFontHeightInPoints((short) 28);
		font.setBoldweight((short)10);
		style.setFont(font);
		row = sheet.createRow(0);
		row.setHeight((short) (25 * 20*2));  
		cell = row.createCell(0);
		cell.setCellValue(title);
		cell.setCellStyle(style);
		for(int i=1; i<heads.size(); i++){
			
			String[] h = heads.get(i);
			sheet.setColumnWidth((short) i, Short.parseShort(h[2]));
			cell = row.createCell(i);
			cell.setCellValue("");
			cell.setCellStyle(style);
		}
		//合并单元格
		CellRangeAddress cra1title =new CellRangeAddress(0, 0, 0, maxColumn-1); // 起始行, 终止行, 起始列, 终止列  
    	sheet.addMergedRegion(cra1title);
		
		//写表头
		row = sheet.createRow(line++);
		row.setHeightInPoints(23);
		font.setFontHeightInPoints((short) 13);
		style.setFont(font);
		
		for(int i=0; i<heads.size(); i++){
			String[] h = heads.get(i);
			sheet.setColumnWidth((short) i, Short.parseShort(h[2]));
			cell = row.createCell(i);
			cell.setCellValue(h[1]);
			cell.setCellStyle(style);
		}

这一步就是将刚才在config中定义的表头数据给显示到上面,主要代码就是

  //1.取表头
        List<String[]> heads = PaConfig.getNewExcelHeaders();
int line = 1, maxColumn = 0;

第一个是取刚才定义的表头,第二行是定义行数,用于后面的合并数据。

下一步就是读取sql文件显示数据了,如果只是为了单纯的显示数据,那就如下即可:

        //写入数据
		for(int j=0;j<objs.length;j++){
			//保留表头开始另起一行
			row = sheet.createRow(line++);
			DataObject obj  = null;
			if(j!=objs.length)
					obj = objs[j];
			//写入数据--k
			for(int  k=0; k<heads.size()&&objs!=null; k++){
				String[] h = heads.get(k);
				cell = row.createCell(k);
				cell.setCellStyle(style);
                //此处则是取定义表头中的属性值,代码自动遍历读取塞值即可
                cell.setCellValue(obj.getString[0]);

很显然,需求不仅仅于此,接下来我们需要合并单元格

由于需求的特殊性,需要根据业务员来进行区分和合并

  1.定义dto,存储需要合并的起始列和结束列

     

package com.mj.flx.pa.excelDto;

public class downloadDtoOrg {
	private int startRowIndex;
	private int endRowIndex;
	private int columnIndex;
	public int getStartRowIndex() {
		return startRowIndex;
	}
	public void setStartRowIndex(int startRowIndex) {
		this.startRowIndex = startRowIndex;
	}
	public int getEndRowIndex() {
		return endRowIndex;
	}
	public void setEndRowIndex(int endRowIndex) {
		this.endRowIndex = endRowIndex;
	}
	public int getColumnIndex() {
		return columnIndex;
	}
	public void setColumnIndex(int columnIndex) {
		this.columnIndex = columnIndex;
	}
	
}

2.传入遍历的数据和起始行数(最开始的第二行代码),进行遍历读取

public List<downloadDtoOrg> getNewExcelIndexOrg(DataObject[] objs, int line2){
		if(objs==null||objs.length==0){
			return null;
		}
		List<downloadDtoOrg> edds = new ArrayList<downloadDtoOrg>(); //建立所有部门dto集合
		int line = line2;
		//写内容
		String tempdetp = null; //区分当前
		//处理部门合并对象
		downloadDtoOrg edd = null;
		for(int i=0; i<=objs.length; i++){
            line ++;
			DataObject obj  = null;
			if(i!=objs.length){
				obj = objs[i];
			}
			if(tempdetp==null){
				edd = new downloadDtoOrg();
				edd.setStartRowIndex(line-1);
			}else if(obj==null){
				edd.setEndRowIndex(line-2);
				edds.add(edd);
			}else if(tempdetp.equals(obj.getString("orgName"))){ //如果此行的部门与上一行的部门一样
				//取上一行的edd对象
				//edd = edd;
			}else if(!tempdetp.equals(obj.getString("orgName"))){ //如果此行的部门与上一行的部门不一行
				edd.setEndRowIndex(line-2);
				edds.add(edd);
				//重新创建新对象
				edd = new downloadDtoOrg();
				edd.setStartRowIndex(line-1);
			}else {
				throw new RuntimeException("未考虑到问题异常");
			}
			tempdetp = obj==null?null:obj.getString("orgName");
		}
		return edds;
	}

上面代码的意思大致如下:通过对比数据中业务员的姓名进行分组,碰到不一致的则重新开始下一列,所以我们在sql中就要分好组,以免出现数据不一致的情况。在这里我们记录了合并的起始列和结束列,但是调用poi的方法还需要起始行和结束行,所以。

//合并部门
		for(int i=0;i<orgs.size(); i++){
			downloadDtoOrg org = orgs.get(i);
			int columnIndex = PaConfig.getNewColumnIndex("orgName");
			CellRangeAddress cra =new CellRangeAddress(org.getStartRowIndex(), org.getEndRowIndex(), columnIndex, columnIndex); // 起始行, 终止行, 起始列, 终止列
			sheet.addMergedRegion(cra);
		}

通过最初始定义的表头,获取起始列和结束列。这样就可以进行合并列的操作了,其他以此类推。

思考:如果需要合并的列很多,又不想在一条sql中处理的话,可以分多条sql关注合并列,可以大大减低难度。

public List<downloadDtoOrg> getNewExcelIndexCustomType(DataObject[] objs, int line2){
		if(objs==null||objs.length==0){
			return null;
		}
		List<downloadDtoOrg> edds = new ArrayList<downloadDtoOrg>(); //建立所有部门dto集合
		int line = line2;
		//写内容
		String tempdetp = null; //区分当前
		String empNames =null;
		//处理客户类型合并对象
		downloadDtoOrg edd = null;
		for(int i=0; i<=objs.length; i++){
            line ++;
			DataObject obj  = null;
			if(i!=objs.length){
				obj = objs[i];
			}
			if(tempdetp==null){
				edd = new downloadDtoOrg();
				edd.setStartRowIndex(line-1);
			}else if(obj==null){
				edd.setEndRowIndex(line-2);
				edds.add(edd);
			}else { 
				//如果销售员和客户类型匹配一致
				if(tempdetp.equals(obj.getString("customType"))&&empNames.equals(obj.getString("empName"))){
					
				}else{
					edd.setEndRowIndex(line-2);
					edds.add(edd);
					//重新创建新对象
					edd = new downloadDtoOrg();
					edd.setStartRowIndex(line-1);
				}
			}
			tempdetp = obj==null?null:obj.getString("customType");
			empNames = obj==null?null:obj.getString("empName");
		}
		return edds;
	}

如果后面有需要合并的,又是依赖前面业务员的条件,可以在当中进行多重判断,进而取到相应的起始列,行数据。

最后就是一个标色的操作了,因为有些合并列是不需要标色的,所以在初始化的时候,定义的h[4]的值就开始起作用了。通过判断定义的值就可以进行是否标色操作了。

//标注颜色
				if(obj.getString("agendOrder")!=null){
					if(heads.get(k)[4].equals("1")){
						//cell = row.createCell(k);
						style2.setFillForegroundColor(HSSFColor.PALE_BLUE.index);
						style2.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);  
					}
					cell.setCellStyle(style2);
}

style2第一行是定义颜色,第二行是定义填充样式,最好是我这样,全填充,如果忘记了编写这一行,你会发现,没有任何效果。(POI的一个硬伤就是不能整行标色,只能自己遍历)

思考:我这里因为标了三种不同颜色,通过了三个style进行解决,然后会出现合并列也会被标色的现象,所以没有办法,又定义了一个style将合并列的背景色定义为白色,感觉很low,但是没找到办法,希望有大佬看到后能解惑一下。

总结:

   起始就是考验你对POI的相关属性是否熟悉,以及对java的基础知识能否灵活运用,其中POI的几个常用属性如下:

        //定义工作簿
        HSSFWorkbook workbook = new HSSFWorkbook();
        //表格
		Sheet sheet = workbook.createSheet();
        //行
        Row row = null;
        //单元格
		Cell cell = null;
        //字体
		Font font = workbook.createFont();
        //属性
		CellStyle style = workbook.createCellStyle();
        各种小属性
        style.setBorderBottom(CellStyle.BORDER_THIN); 
		style.setBorderLeft(CellStyle.BORDER_THIN); 
		style.setBorderRight(CellStyle.BORDER_THIN); 
		style.setBorderBottom(CellStyle.BORDER_THIN); 
		style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        style2.setFillForegroundColor(HSSFColor.PALE_BLUE.index);
		style2.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); 

还得继续努力学习哦!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值