jxls 使用模板文件导出生成excel

jxls官方网站http://jxls.sourceforge.net/
jxls采用基于excel模板的方式来导出excel,支持
支持写sql语句导数据
简单属性访问
强大的表达式
报表导出
报表标签使用
列隐藏
动态样式
jdbc resultset导出
在一个单元格上使用多个bean的属性
合并单元格
动态分组

等等,底层采用的poi来操作excel,所以要下载poi,下列表是依赖包
* POI (3.5 or later)
* Commons BeanUtils
* Commons Collections
* Commons JEXL
* Commons Logging
* Commons Digester
使用模板的直接好处就是减少了设置excel相应单元格样式,复杂表格不好编码,手动填充数据,减少编码出错率等诸多不便之处。


简单的使用就不用做例子了,直接上一个难一点的。该功能最终的导出效果图如下

要求:1.导出的excel的表头是动态的且支持单元格合并,2.支持分组,通过设置合并单元格的属性,能自动将相同数据纵向合并单元格

所操作excel的模板图如下


测试用例所使用的简单bean

public class ExcelColumn {
 private String value;
 private int row;
 private int col;

 public ExcelColumn(String value, int row, int col) {
  super();
  this.value = value;
  this.row = row;
  this.col = col;
 }
 //getter/setter
}

public class Column {
 private String sumweight;
 private String count;
 //getter/setter
}

public class FundsVO {
 private String sumweight;
 private String count;
 //getter/setter
}

public class Head {

 private String name;
 //getter/setter
}
public class Record {
 private String wasteType;
 private Collection<ValueBean> valuebeans;
 //getter/setter
}
public class ValueBean { 
 private String collector;
 private Collection<FundsVO> fund;
 //getter/setter
}

测试用例主体方法

 @Test
 public void dymicColumnTest() throws ParsePropertyException, InvalidFormatException, IOException {

  List<Head> heads = new ArrayList<Head>();
  Head col1 = new Head("南山");
  Head col2 = new Head("龙岗");
  heads.add(col1);
  heads.add(col2);

  List<Column> cols = new ArrayList<Column>();
  Column co1 = new Column();
  co1.setSumweight("垃圾净重量");
  co1.setCount("车次");
  cols.add(co1);
  cols.add(co1);
  List<Collection<ValueBean>> data = new ArrayList<Collection<ValueBean>>();
  data.add(new ArrayList<ValueBean>());
  data.add(new ArrayList<ValueBean>());
  for (int k = 0; k < 2; k++) {

   for (int i = 0; i < 3; i++) {

    ValueBean con1 = new ValueBean();
    con1.setCollector("收集者" + k);
    Collection<FundsVO> fund = new ArrayList<FundsVO>();
    for (int j = 0; j < 2; j++) {
     FundsVO f1 = new FundsVO();
     f1.setCount("1" + i + j);
     f1.setSumweight("10" + j + i);
     fund.add(f1);
    }
    con1.setFund(fund);
    data.get(k).add(con1);
   }
  }

  Collection<Record> records = new ArrayList<Record>();
  Record r1 = new Record();
  r1.setWasteType("生活垃圾");

  r1.setValuebeans(data.get(0));

  records.add(r1);
  Record r2 = new Record();
  r2.setWasteType("污水");
  r2.setValuebeans(data.get(1));
  records.add(r2);

  Map map = new HashMap();
  map.put("records", records);
  map.put("heads", heads);
  map.put("cols", cols);
  String templateFileName = "D:\\workspace\\jxlsdemo\\src\\hi\\magicdetective\\dynmiccolumn\\dynmic.xls";
  String destFileName = "D:\\workspace\\jxlsdemo\\src\\hi\\magicdetective\\dynmiccolumn\\dynmic_output.xls";
  XLSTransformer transformer = new XLSTransformer();
  //注册自定义合并单元格转换器
  transformer.registerCellProcessor(new MultPropertyCellProcessor(new String[] { "record.wasteType" }));
  transformer.transformXLS(templateFileName, map, destFileName);
 }

 

package hi.magicdetective.dynmiccolumn;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import net.sf.jxls.parser.Cell;
import net.sf.jxls.processor.CellProcessor;

import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

/**
 * 多属性合并单元格转换器
 * @author ydw
 *
 */
public class MultPropertyCellProcessor implements CellProcessor {
 /**
  * 合并属性集
  */
 private String[] keys;
 /**
  * 合并数据集
  */
 private Map<String, List<ExcelColumn>> mergedMap = new HashMap<String, List<ExcelColumn>>();
 /**
  * 合并属性的起始行列
  */
 private Map<String, ExcelColumn> first = new HashMap<String, ExcelColumn>();

 public MultPropertyCellProcessor(String[] keys) {
  this.keys = keys;
 }

 /**
  *  刚开始不明白这个Map namedCells参数的含义,通过跟踪源代码发现是下面类调用的
  *  SimpleRowTransformer
  *  private void applyCellProcessors(Sheet sheet, Cell cell) {
     for (int i = 0; i < cellProcessors.size(); i++) {
         CellProcessor cellProcessor = (CellProcessor) cellProcessors.get(i);
         cellProcessor.processCell(cell, sheet.getNamedCells());
     }
 }
  */
 @Override
 public void processCell(Cell cell, Map namedCells) {

  for (String key : keys) {
   if (cell.getStringCellValue().contains(key)) {
    first.put(key,
      new ExcelColumn(key, cell.getPoiCell().getRowIndex(), cell.getPoiCell().getColumnIndex()));
   }
  }
  //同行列,实际数据,不是表达式值
  for (String key : keys) {
   int firstRow = first.get(key) == null ? -1 : first.get(key).getRow();
   int firstCol = first.get(key) == null ? -1 : first.get(key).getCol();
   if (cell.getPoiCell().getRowIndex() == firstRow && cell.getPoiCell().getColumnIndex() == firstCol
     && !cell.getStringCellValue().contains(key)) {
    String value = cell.getStringCellValue();
    //由属性+值构成键
    String tmpKey = key + "_" + value;
    if (mergedMap.containsKey(tmpKey)) {
     mergedMap.get(tmpKey).add(new ExcelColumn(value, firstRow, firstCol));
    } else {
     List<ExcelColumn> list = new ArrayList<ExcelColumn>();
     list.add(new ExcelColumn(value, firstRow, firstCol));
     mergedMap.put(tmpKey, list);
    }

   }

   merged(cell.getPoiCell().getSheet(), mergedMap);
  }

 }

 private void merged(Sheet sheet, Map<String, List<ExcelColumn>> map) {
  Set<Entry<String, List<ExcelColumn>>> set = map.entrySet();
  for (Entry<String, List<ExcelColumn>> entry : set) {
   String tmpKey = entry.getKey();
   int firstRow = 9999;
   int lastRow = -1;
   int colindex = 0;
   for (ExcelColumn col : map.get(tmpKey)) {
    colindex = col.getCol();
    if (col.getRow() < firstRow)
     firstRow = col.getRow();
    if (col.getRow() > lastRow)
     lastRow = col.getRow();
   }
   CellRangeAddress range = new CellRangeAddress(firstRow, lastRow, colindex, colindex);
   sheet.addMergedRegion(range);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值