Java poi操作Excel 是比较常用的,通常我们用来导出Excel格式的文本数据。比如说两个表,一个是入库明细,一个是结算明细。针对每一条的入库明细可能有对于的几条的结算明细信息,结算明细中有id关联到入库明细。这时候可能会要求把数据展示在一张Excel中。
类似以下的表格
从入库时间到有效期是 来自于 入库明细的表,从结算时间到后面的列是来源于结算明细的表。
要操作合并单元格 主要用到的对 CellRangeAddress的操作。
public CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) 计算好 它的构造参数的值
根据每条入库明细下的结算明细数量 计算出跨行的 firstRow 与lastRow
/**
* 根据跨行数来转化 CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol) 的 firstRow 与 lastRow
* @param list 每条记录需要的跨行数
* @param minRow 从第几行开始跨行
* @return
*/
private Map<Integer,Integer> transPositionMap(List<Integer> list,Integer minRow){
if(CollectionUtils.isNotEmpty(list)){
Map<Integer,Integer> linkedMap = new LinkedHashMap<>();
List<Integer> xPositionList = new ArrayList<>();
xPositionList.add(minRow);
for(Integer pos:list){
if(pos == 1 || pos == 0){
pos = 1;
Integer xPosition = Collections.max(xPositionList);
xPositionList.add(xPosition+pos);
continue;
}
Integer xPosition = Collections.max(xPositionList);
linkedMap.put(xPosition, xPosition+pos-1);
xPositionList.add(xPosition+pos);
}
return linkedMap;
}
return Collections.emptyMap();
}
@Test
public void test3(){
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("test");
HSSFRow row = sheet.createRow(0);
String[] strArr = {"入库时间","产品名","商业公司","批号","单价","数量","金额","有效期","结算时间","实际结算数量","实际结算单价","实际结算金额","票号","税金","备注"};
HSSFCellStyle cellStyle = workbook.createCellStyle();
Font fontStyle = workbook.createFont();
fontStyle.setFontHeightInPoints((short) 11);
cellStyle.setFont(fontStyle);
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
for(int i = 0;i<strArr.length;i++){
HSSFCell cell = row.createCell(i);
cell.setCellValue(strArr[i]);
cell.setCellStyle(cellStyle);
}
for(int i = 1;i < 20 ;i++){
row = sheet.createRow(i);
for(int j = 0;j<strArr.length;j++){
HSSFCell cell = row.createCell(j);
cell.setCellValue("单元格"+i);
cell.setCellStyle(cellStyle);
}
}
//spanRows 表示 每条记录可能的跨行数
List<Integer> spanRows = Arrays.asList(1,3,4,4,4,3,1);
Map<Integer,Integer> positions = transPositionMap(spanRows, 1);
for(int j = 0;j<8 ;j++){
for(Map.Entry<Integer, Integer> entry:positions.entrySet()){
CellRangeAddress cra =new CellRangeAddress(entry.getKey(),entry.getValue(), j, j);// 起始行, 终止行, 起始列, 终止列
sheet.addMergedRegion(cra);
}
}
String excelName = "D:/myExcel.xls";
FileOutputStream out = null;
try {
out = new FileOutputStream(excelName);
workbook.write(out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null)
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
out = null;
}
}
控制台执行单元测试后
以上为了简便,直接用的数据来模拟效果。实际中比如 agent_stock 入库明细表 agent_stock 结算明细表
1.agent_stock left join agent_stock 来刷选匹配的记录集
2.agent_stock left join agent_stock group by agent_stock 的id ,count(agent_stock.id) 计算每条 agent_stock的跨行数
即相当于单元测试中 List<Integer> spanRows 的作用。
3.注意private Map<Integer,Integer> transPositionMap(List<Integer> list,Integer minRow) 中的方法。