From 495044b8fa1398f470d31e3af0f5e7da64a90ee0 Mon Sep 17 00:00:00 2001 From: pedda Date: Sat, 9 Nov 2019 12:34:34 +0100 Subject: [PATCH 1/2] :sparkles: enable loading existing excel files as templates --- build.gradle | 2 +- .../com/jameskleeh/excel/ExcelBuilder.groovy | 10 +++++--- .../com/jameskleeh/excel/Workbook.groovy | 4 ++- .../com/jameskleeh/excel/WorkbookSpec.groovy | 25 ++++++++++++++++++- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index dd36f80..393df86 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ apply plugin: "jacoco" group 'com.jameskleeh' -version '0.4.4' +version '0.4.5-SNAPSHOT' targetCompatibility = 1.7 sourceCompatibility = 1.7 diff --git a/src/main/groovy/com/jameskleeh/excel/ExcelBuilder.groovy b/src/main/groovy/com/jameskleeh/excel/ExcelBuilder.groovy index 6d0f1be..985652a 100644 --- a/src/main/groovy/com/jameskleeh/excel/ExcelBuilder.groovy +++ b/src/main/groovy/com/jameskleeh/excel/ExcelBuilder.groovy @@ -34,21 +34,23 @@ class ExcelBuilder { * Builds an excel document and sends the data to an output stream. The output stream is NOT closed. * * @param outputStream An output stream to push data onto + * @param template A excel file that is used a template, if null a new workbook will be created. * @param callable The closure to build the document */ - static void output(OutputStream outputStream, @DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = Workbook) Closure callable) { - XSSFWorkbook wb = build(callable) + static void output(InputStream template = null, OutputStream outputStream, @DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = Workbook) Closure callable) { + XSSFWorkbook wb = build(template, callable) wb.write(outputStream) } /** * Builds an excel document * + * @param template A excel file that is used a template, if null a new workbook will be created. * @param callable The closure to build the document * @return The native workbook */ - static XSSFWorkbook build(@DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = Workbook) Closure callable) { - XSSFWorkbook wb = new XSSFWorkbook() + static XSSFWorkbook build(InputStream template = null, @DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = Workbook) Closure callable) { + XSSFWorkbook wb = template == null ? new XSSFWorkbook() : new XSSFWorkbook(template) callable.resolveStrategy = Closure.DELEGATE_FIRST callable.delegate = new Workbook(wb) if (callable.maximumNumberOfParameters == 1) { diff --git a/src/main/groovy/com/jameskleeh/excel/Workbook.groovy b/src/main/groovy/com/jameskleeh/excel/Workbook.groovy index 5c76af7..94c5a96 100644 --- a/src/main/groovy/com/jameskleeh/excel/Workbook.groovy +++ b/src/main/groovy/com/jameskleeh/excel/Workbook.groovy @@ -52,7 +52,9 @@ class Workbook { * @return The native sheet object */ XSSFSheet sheet(String name, Map options, @DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = Sheet) Closure callable) { - handleSheet(wb.createSheet(WorkbookUtil.createSafeSheetName(name)), options, callable) + XSSFSheet sheet = wb.getSheet(name) + sheet = sheet ?: wb.createSheet(WorkbookUtil.createSafeSheetName(name)) + handleSheet(sheet, options, callable) } /** diff --git a/src/test/groovy/com/jameskleeh/excel/WorkbookSpec.groovy b/src/test/groovy/com/jameskleeh/excel/WorkbookSpec.groovy index 0fa9d11..375bd97 100644 --- a/src/test/groovy/com/jameskleeh/excel/WorkbookSpec.groovy +++ b/src/test/groovy/com/jameskleeh/excel/WorkbookSpec.groovy @@ -1,8 +1,10 @@ package com.jameskleeh.excel +import org.apache.poi.ss.usermodel.Cell +import org.apache.poi.ss.usermodel.Sheet +import org.apache.poi.xssf.usermodel.XSSFSheet import org.apache.poi.xssf.usermodel.XSSFWorkbook import spock.lang.Specification -import org.apache.poi.ss.usermodel.Sheet class WorkbookSpec extends Specification { @@ -29,4 +31,25 @@ class WorkbookSpec extends Specification { config.defaultRowHeightInPoints == 12F config.defaultColumnWidth == 20 } + + void "test open with template and use sheet by name access"() { + given: + XSSFWorkbook workbook = ExcelBuilder.build(this.class.getResourceAsStream('/template.xlsx')) { + sheet('sheet') { + row { + cell('created with builder') + } + } + } + + when: + XSSFSheet sheet = workbook.getSheet('sheet') + Iterator buildRow = sheet.getRow(0).cellIterator() + Iterator rowFromTemplate = sheet.getRow(1).cellIterator() + + then: + buildRow.next().stringCellValue == 'created with builder' + rowFromTemplate.next().stringCellValue == 'from template' + } + } From 2b64a7a7e737728cf6997732a38cd90770902f2d Mon Sep 17 00:00:00 2001 From: pedda Date: Sat, 9 Nov 2019 12:36:23 +0100 Subject: [PATCH 2/2] :bug: add missing test template.xlsx file --- src/test/resources/template.xlsx | Bin 0 -> 4995 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/test/resources/template.xlsx diff --git a/src/test/resources/template.xlsx b/src/test/resources/template.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a4ffb110eaa10bef4d0d6de449908a93f7325836 GIT binary patch literal 4995 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 vbYlBOH;Aur|CQ!`XTKU5Xw?0pw