Jxls2 合并单元格 (横向循环、自定义函数)

JXLS是一款基于模板的Java报表工具,支持Excel文件处理。它能够利用Excel模板创建报表,并提供丰富的指令集来操作数据。该工具支持遍历、条件判断、图片插入等功能,适用于批量数据处理场景。
该文章已生成可运行项目,

文档 :JXLS -

源码:GitHub - jxlsteam/jxls: Java library for creating Excel reports using Excel templates

基本使用方法

<dependency>
    <groupId>org.jxls</groupId>
    <artifactId>jxls-poi</artifactId>
    <version>2.9.0</version>
</dependency>

public void test() throws ParseException, IOException {
    logger.info("Running Formula Copy demo");
    List<Org> orgs = Org.generate(3, 3);
    try(InputStream is = Demo.class.getResourceAsStream("formula_copy_template.xls")) {
        try (OutputStream os = new FileOutputStream("target/formula_copy_output.xls")) {
            Context context = new Context();
            context.putVar("orgs", orgs);
            JxlsHelper jxlsHelper = JxlsHelper.getInstance();
            jxlsHelper.setUseFastFormulaProcessor(false);
            jxlsHelper.processTemplate(is, os, context);
        }
    }
}

基本语法

Each-Command (横向:direction="RIGHT")

  • var is a name of the variable in Jxls context to put each new collection item when iterating

  • varIndex  is a name of a context variable containing the index to iterate

  • items is a name of a context variable containing the collection (Iterable<?>) or array to iterate

  • area is a reference to XLS Area used as each command body

  • direction is a value of Direction enumeration which may have values DOWN or RIGHT to indicate how to repeat the command body - by rows or by columns. The default value is DOWN.

  • select is an expression selector to filter out collection items during the iteration

  • groupBy is a property to do the grouping

  • groupOrder indicates ordering for groups (‘desc’ or ‘asc’)

  • orderBy contains the names separated with comma and each with an optional postfix “ ASC” (default) or “ DESC” for the sort order

  • cellRefGenerator is a custom strategy for target cell references creation

  • multisheet is a name of a context variable containing a list of sheet names to output the collection

  • lastCell is a common attribute for any command pointing to the last cell of the command area

If-Command

  • condition is a conditional expression to test

  • ifArea is a reference to an area to output when this command condition evaluates to true

  • elseArea is a reference to an area to output when this command condition evaluates to false

  • lastCell is a common attribute for any command pointing to the last cell of the command area

eg.

jx:if(condition="employee.payment <= 2000", lastCell="F9", areas=["A9:F9","A18:F18"])

Grid-Command

可以自定义各列单元格格式

Grid-Command has the following attributes

  • headers - name of a context variable containing a collection of headers (Collection<Object>)

  • data - name of a context variable containing a collection of data (Collection<Collection<Object>>)

  • props - comma separated list of object properties for each grid row (required only if each grid row is an Object)

  • formatCells - comma-separated list of type-format map cells e.g. formatCells=“Double:E1, Date:F1”

  • headerArea - source xls area for headers

  • bodyArea - source xls area for body

  • lastCell is a common attribute for any command pointing to the last cell of the command area

${header}
${cell}

Image-Command

eg.

InputStream imageInputStream = ImageDemo.class.getResourceAsStream("business.png");
byte[] imageBytes = Util.toByteArray(imageInputStream);
context.putVar("image", imageBytes);
jx:image(lastCell="D10" src="image" imageType="PNG")

MergeCells-Command

jx:mergeCells(
lastCell="Merge cell ranges"
[, cols="Number of columns combined"]
[, rows="Number of rows combined"]
[, minCols="Minimum number of columns to merge"]
[, minRows="Minimum number of rows to merge"]
)

其他

Multiple sheets

jx:each 命令中添加属性 multisheet 

eg.

jx:each(items="departments", var="dep", multisheet="sheetnames", lastCell="D4")

Excel Formulas

  • 公式默认值

jx:params(defaultValue="1")
  • 拷贝公式

jx:params(formulaStrategy="BY_COLUMN")
  • Joined cell (同一行对应多个模板行时)

$[SUM(U_(D9,D18))]

Custom Function

JxlsHelper jxlsHelper = JxlsHelper.getInstance();
Transformer transformer = jxlsHelper.createTransformer(is, os);
JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator) transformer.getTransformationConfig().getExpressionEvaluator();
Map<String, Object> functionMap = new HashMap<>();
functionMap.put("fn", new MyCustomFunctions());
JexlEngine customJexlEngine = new JexlBuilder().namespaces(functionMap).create();
evaluator.setJexlEngine(customJexlEngine);
jxlsHelper.processTemplate(context, transformer);
​

public static class MyCustomFunctions {
    public Object ifelse(boolean b, Object o1, Object o2) {
        return b ? o1 : o2;
    }
​
    public boolean contains(Collection o1, Object o2) {
        return o1.contains(o2);
    }
​
    public String concat(Object o1, Object o2) {
        return String.valueOf(o1).concat(String.valueOf(o2));
    }
}
${fn:ifelse(fn:contains(data.ext,"prevQyoy"),"上季度增速","上年度增速")}

UpdateCell-Command

见官方文档

Custom Commands

见官方文档

示例

Report template

Excel output

本文章已经生成可运行项目
<think>我们正在处理关于jXLS 1.0中合并单元的问题。根据引用内容,我们知道在jXLS1的时候,通常的做法是使用Jxls生成报表Excel文件,然后再使用Apache POI进行二次处理来实现单元合并(引用[1])。因此,我们可以采用类似的方法。 步骤: 1. 使用Jxls 1.0生成基本的Excel文件(不带合并单元)。 2. 然后使用POI的API来读取这个Excel文件,并在需要的地方添加合并单元的操作。 3. 保存修改后的Excel文件。 示例代码思路: 首先,我们使用Jxls 1.0的API生成一个Excel文件。然后,我们使用POI打开这个文件,定位到需要合并的单元区域,调用`sheet.addMergedRegion()`方法合并单元,最后保存。 注意:在合并单元时,我们需要知道要合并的起始行、结束行、起始列、结束列。这些信息可以在生成Excel时通过一些方式记录下来,或者根据数据内容动态判断。 由于引用中并没有提供具体的Jxls 1.0合并单元的示例,我们将根据上述思路编写一个示例。 假设我们有一个需求:在生成的Excel中,对于某一列中相同值的连续单元进行合并。 步骤: 1. 使用Jxls 1.0生成一个基本的Excel文件(假设为temp.xls)。 2. 读取temp.xls,遍历需要合并的列(例如第0列),找出连续相同的单元,记录合并区域。 3. 按照合并区域进行合并。 4. 保存为最终文件。 下面是一个简单的示例代码: 首先,使用Jxls 1.0生成Excel的代码(这里仅作示例,具体根据实际数据): ```java // 使用Jxls 1.0生成Excel XLSTransformer transformer = new XLSTransformer(); transformer.transformXLS("template.xls", new HashMap<String, Object>(), "temp.xls"); ``` 然后,使用POI进行合并: ```java import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.util.Region; // 读取临时文件 FileInputStream tempFile = new FileInputStream("temp.xls"); HSSFWorkbook workbook = new HSSFWorkbook(tempFile); HSSFSheet sheet = workbook.getSheetAt(0); // 假设操作第一个sheet // 假设我们要合并第一列(索引0)中连续相同的单元 int colIndex = 0; int firstRow = 0; // 起始行(根据实际情况调整,可能跳过标题行) int lastRow = sheet.getLastRowNum(); int startRow = firstRow; int currentRow = firstRow; while (currentRow <= lastRow) { String currentValue = getCellValueAsString(sheet, currentRow, colIndex); int nextRow = currentRow + 1; while (nextRow <= lastRow && currentValue.equals(getCellValueAsString(sheet, nextRow, colIndex))) { nextRow++; } // 如果连续相同的行数大于1,则合并 if (nextRow - currentRow > 1) { Region region = new Region(currentRow, (short)colIndex, nextRow-1, (short)colIndex); sheet.addMergedRegion(region); } currentRow = nextRow; } // 保存最终文件 FileOutputStream outputStream = new FileOutputStream("final.xls"); workbook.write(outputStream); outputStream.close(); tempFile.close(); // 辅助方法:获取单元的字符串值 private String getCellValueAsString(HSSFSheet sheet, int row, int col) { HSSFRow r = sheet.getRow(row); if (r == null) { return ""; } HSSFCell cell = r.getCell(col); if (cell == null) { return ""; } return cell.toString(); // 注意:这里简单处理,实际可能需要根据单元类型获取值 } ``` 注意:上面的代码仅用于演示思路,实际使用时需要根据具体需求调整,例如合并多列、处理空行等。另外,合并单元后可能需要调整样式(如边框、居中等),这里没有展示。 引用[1]中提到:“之前在Jxls1的时候也都是使用它生产报表Excel文件,再使用Poi二次去实现单元合并的逻辑。” 所以我们采用的方式是符合引用中的实践。 另外,引用[3]提到jxls能够处理更复杂的场景,但合并单元Jxls1中并没有内置支持,因此使用POI进行二次处理是一种常见做法。 相关问题: 1. 在Jxls 1.0中如何实现多列单元的合并? 2. 使用POI合并单元后如何保持样式一致? 3. Jxls 2.0在合并单元方面有哪些改进?</think>### jXLS 1.0 单元合并实现方案 在 jXLS 1.0 中,原生不支持直接合并单元的功能。根据引用[1]和[3]的实践建议,通常需要结合 Apache POI 进行二次处理来实现单元合并。以下是具体实现步骤: #### 实现步骤 1. **生成基础 Excel** 使用 jXLS 1.0 生成不含合并的基础 Excel 文件 ```java InputStream template = getClass().getResourceAsStream("template.xls"); OutputStream output = new FileOutputStream("output_temp.xls"); Map<String, Object> data = new HashMap<>(); data.put("items", getItems()); // 填充数据 XLSTransformer transformer = new XLSTransformer(); transformer.transformXLS(template, data, output); output.close(); ``` 2. **POI 二次处理合并** 使用 POI 读取临时文件并添加合并逻辑: ```java HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream("output_temp.xls")); HSSFSheet sheet = workbook.getSheetAt(0); // 示例:合并 A2:A5 区域 CellRangeAddress region = new CellRangeAddress(1, 4, 0, 0); // (起始行, 结束行, 起始列, 结束列) sheet.addMergedRegion(region); // 保存最终文件 FileOutputStream finalOutput = new FileOutputStream("final_output.xls"); workbook.write(finalOutput); finalOutput.close(); ``` #### 动态合并技巧 当需要根据数据动态合并时(如相同值合并): ```java List<Item> items = getItems(); int startRow = 2; // 数据起始行 for (int i = 0; i < items.size(); i++) { String currentValue = items.get(i).getCategory(); int mergeStart = i; // 检测连续相同值 while (i + 1 < items.size() && items.get(i + 1).getCategory().equals(currentValue)) { i++; } if (i > mergeStart) { // 存在连续相同值 CellRangeAddress region = new CellRangeAddress( startRow + mergeStart, startRow + i, 0, 0 // 合并第0列(A列) ); sheet.addMergedRegion(region); // 设置合并后居中(可选) HSSFCell cell = sheet.getRow(startRow + mergeStart).getCell(0); HSSFCellStyle style = workbook.createCellStyle(); style.setAlignment(HorizontalAlignment.CENTER); cell.setCellStyle(style); } } ``` #### 注意事项 1. **模板设计**:在 jXLS 模板中预留需要合并的单元位置 2. **依赖配置**: ```xml <!-- jXLS 1.x 核心依赖 --> <dependency> <groupId>net.sf.jxls</groupId> <artifactId>jxls-core</artifactId> <version>1.0.6</version> </dependency> <!-- POI 依赖 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency> ``` 3. **性能考量**:大数据量时建议在内存中直接处理,避免临时文件IO[^1] > **关键提示**:jXLS 2.x 可通过自定义函数实现合并(引用[2][4]),但 jXLS 1.x 需依赖 POI 二次处理。如需复杂合并逻辑,建议升级到 jXLS 2.x 版本[^3]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值