Skip to content

Commit 08f6a19

Browse files
basic refactoring
chained formatters flexible headers
1 parent 84a063d commit 08f6a19

File tree

8 files changed

+466
-99
lines changed

8 files changed

+466
-99
lines changed

grails-app/services/de/andreasschmitt/export/ExportService.groovy

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ class ExportService {
1212
def exporterFactory
1313
def grailsApplication
1414

15+
void setupResponse(String type, HttpServletResponse response, String filename, String extension){
16+
response.contentType = grailsApplication.config.grails.mime.types[type]
17+
response.setHeader("Content-disposition", "attachment; filename=\"${filename}.${extension}\"")
18+
}
19+
1520
void export(String type, OutputStream outputStream, List objects, Map formatters, Map parameters) throws ExportingException {
1621
export(type, outputStream, objects, null, null, formatters, parameters)
1722
}
@@ -26,9 +31,7 @@ class ExportService {
2631
}
2732

2833
void export(String type, HttpServletResponse response, String filename, String extension, List objects, List fields, Map labels, Map formatters, Map parameters) throws ExportingException {
29-
// Setup response
30-
response.contentType = grailsApplication.config.grails.mime.types[type]
31-
response.setHeader("Content-disposition", "attachment; filename=\"${filename}.${extension}\"")
34+
setupResponse(type, response, filename, extension)
3235

3336
Exporter exporter = exporterFactory.createExporter(type, fields, labels, formatters, parameters)
3437
exporter.export(response.outputStream, objects)

src/groovy/de/andreasschmitt/export/builder/ExcelBuilder.groovy

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,22 @@
11
package de.andreasschmitt.export.builder
22

3-
import groovy.util.BuilderSupport
3+
import groovy.util.logging.Log4j
44
import jxl.CellView
55
import jxl.format.Border
66
import jxl.format.BorderLineStyle
7-
import jxl.format.CellFormat
87
import jxl.format.Colour
9-
import jxl.format.Pattern
10-
import jxl.write.WritableFont
118
import jxl.Workbook
129
import jxl.write.Label
1310
import jxl.write.Number
1411
import jxl.write.DateTime
15-
import jxl.write.WritableCellFormat
16-
import jxl.write.WritableFont
1712
import jxl.write.WritableSheet
1813
import jxl.write.WritableWorkbook
19-
import jxl.write.WriteException
20-
import jxl.write.biff.RowsExceededException
21-
import jxl.write.WritableFont
22-
import jxl.format.UnderlineStyle
2314
import jxl.format.UnderlineStyle
2415
import jxl.write.WritableCellFormat
2516
import jxl.write.biff.CellValue
2617
import jxl.write.WritableFont
2718
import jxl.write.WritableHyperlink
2819

29-
import org.apache.commons.logging.*
30-
3120
/**
3221
* @author Andreas Schmitt
3322
*
@@ -62,6 +51,7 @@ import org.apache.commons.logging.*
6251
*
6352
*/
6453

54+
@Log4j
6555
class ExcelBuilder extends BuilderSupport {
6656

6757
WritableWorkbook workbook
@@ -70,8 +60,6 @@ class ExcelBuilder extends BuilderSupport {
7060
String format
7161
Map formats = [:]
7262

73-
private static Log log = LogFactory.getLog(ExcelBuilder)
74-
7563
/**
7664
* This method isn't implemented.
7765
*/
@@ -137,15 +125,13 @@ class ExcelBuilder extends BuilderSupport {
137125
try {
138126
log.debug("Creating sheet")
139127
sheet = workbook.createSheet(attributes?.name, workbook.getNumberOfSheets())
140-
if (attributes?.widths && !attributes?.widths?.isEmpty()) {
141-
attributes.widths.eachWithIndex { width, i ->
142-
sheet.setColumnView(i, (width < 1.0 ? width * 100 : width) as int)
143-
}
144-
} else {
145-
if (attributes?.widthAutoSize!=false) {
146-
for (int i = 0; i < attributes.numberOfFields; i++) {
128+
if (attributes?.widthAutoSize!=false) {
129+
for (int i = 0; i < attributes.numberOfFields; i++) {
130+
Integer width = !attributes.widths?.isEmpty() ? attributes.widths.getAt(i) : null
131+
if (width!=null)
132+
sheet.setColumnView(i, (width < 1.0 ? width * 100 : width) as int)
133+
else if (attributes?.widthAutoSize!=false)
147134
sheet.setColumnView(i, new CellView(autosize: true))
148-
}
149135
}
150136
}
151137
}
@@ -241,7 +227,7 @@ class ExcelBuilder extends BuilderSupport {
241227
}
242228
catch (Exception e) {
243229
println "Error!"
244-
e.printStackTrace();
230+
e.printStackTrace()
245231
}
246232
break
247233
case "mergeCells":

src/groovy/de/andreasschmitt/export/exporter/DefaultExcelExporter.groovy

Lines changed: 93 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
package de.andreasschmitt.export.exporter
22

33
import de.andreasschmitt.export.builder.ExcelBuilder
4+
import groovy.util.logging.Log4j
45
import jxl.format.Alignment
56
import jxl.format.Colour
67
import jxl.write.WritableCellFormat
7-
import jxl.write.WritableFont
88

99
/**
1010
* @author Andreas Schmitt
1111
*
1212
*/
13+
@Log4j
1314
class DefaultExcelExporter extends AbstractExporter {
1415

16+
private static final int MAX_PER_SHEET = 60 //000 // See https://github.com/gpc/export/pull/23
17+
1518
protected void exportData(OutputStream outputStream, List data, List fields) throws ExportingException {
1619
try {
1720
def builder = new ExcelBuilder()
@@ -27,9 +30,10 @@ class DefaultExcelExporter extends AbstractExporter {
2730
useZebraStyle = getParameters().get("zebraStyle.enabled")
2831
}
2932

30-
int maxPerSheet = 60000
33+
int maxPerSheet = MAX_PER_SHEET
3134
if (getParameters().containsKey("max.rows.persheet")) {
3235
maxPerSheet = getParameters().get("max.rows.persheet")
36+
maxPerSheet = maxPerSheet < MAX_PER_SHEET ? maxPerSheet : MAX_PER_SHEET
3337
}
3438

3539
def (sheets, limitPerSheet) = computeSheetsAndLimit(data, maxPerSheet)
@@ -40,69 +44,12 @@ class DefaultExcelExporter extends AbstractExporter {
4044
workbook(outputStream: outputStream) {
4145
for (int j = 1; j <= sheets; j++) {
4246
def dataPerSheet = data.subList(startIndex, endIndex)
43-
sheet(name: getParameters().get("title") + "-$j" ?: "Export-$j", widths: getParameters().get("column.widths"), numberOfFields: fields.size(), widthAutoSize: getParameters().get("column.width.autoSize")!=false) {
44-
45-
format(name: "title") {
46-
Alignment alignment = Alignment.GENERAL
47-
if (getParameters().containsKey('titles.alignment')) {
48-
alignment = Alignment."${getParameters().get('titles.alignment')}"
49-
}
50-
font(name: "arial", bold: true, size: 14, alignment: alignment)
51-
}
52-
53-
format(name: "header") {
54-
if (useZebraStyle) {
55-
font(name: "arial", bold: true, backColor: Colour.GRAY_80, foreColor: Colour.WHITE, useBorder: true)
56-
} else {
57-
// Use default header format
58-
font(name: "arial", bold: true)
59-
}
60-
}
61-
format(name: "odd") {
62-
font(backColor: Colour.GRAY_25, useBorder: true)
63-
}
64-
format(name: "even") {
65-
font(backColor: Colour.WHITE, useBorder: true)
66-
}
67-
68-
int rowIndex = 0
69-
70-
// Option for titles on top of data table
71-
def titles = getParameters().get("titles")
72-
titles.each {
73-
cell(row: rowIndex, column: 0, value: it, format: "title")
74-
rowIndex++
75-
}
76-
77-
//Create header
78-
if (isHeaderEnabled) {
79-
fields.eachWithIndex { field, index ->
80-
String value = getLabel(field)
81-
cell(row: rowIndex, column: index, value: value, format: "header")
82-
}
83-
84-
rowIndex++
85-
}
86-
87-
final Map columnFormats=getParameters().get("column.formats")
88-
//Rows
89-
dataPerSheet.eachWithIndex { object, k ->
90-
91-
fields.eachWithIndex { field, i ->
92-
def format = useZebraStyle ? ( (k % 2) == 0 ? "even" : "odd" ) : ''
93-
format = columnFormats?.containsKey(field)?columnFormats[field]:format
94-
Object value = getValue(object, field)
95-
cell(row: k + rowIndex, column: i, value: value, format: format)
96-
}
97-
}
98-
99-
if (getParameters().get('titles.mergeCells')) {
100-
//Merge title cells
101-
titles.eachWithIndex { title, index ->
102-
mergeCells(startColumn: 0, startRow: index, endColumn: fields.size(), endRow: index)
103-
}
104-
}
105-
}
47+
48+
processSheet (getDelegate(), getParameters().get("title") + "-$j" ?: "Export-$j",
49+
dataPerSheet, fields,
50+
isHeaderEnabled, useZebraStyle,
51+
getParameters().get("column.width.autoSize")!=false)
52+
10653
startIndex = endIndex
10754
endIndex = endIndex + limitPerSheet > data.size() ? data.size() : endIndex + limitPerSheet
10855
}
@@ -116,13 +63,92 @@ class DefaultExcelExporter extends AbstractExporter {
11663
}
11764
}
11865

119-
private computeSheetsAndLimit(List data, maxPerSheet) {
66+
private void processSheet(ExcelBuilder workbook, String sheetName, List data, List fields,
67+
boolean isHeaderEnabled, boolean useZebraStyle, boolean widthAutoSize){
68+
workbook.sheet (name: sheetName,
69+
widths: getParameters().get("column.widths"),
70+
numberOfFields: fields.size(),
71+
widthAutoSize: widthAutoSize) {
72+
73+
format(name: "title") {
74+
Alignment alignment = Alignment.GENERAL
75+
if (getParameters().containsKey('titles.alignment')) {
76+
alignment = Alignment."${getParameters().get('titles.alignment')}"
77+
}
78+
font(name: "arial", bold: true, size: 14, alignment: alignment)
79+
}
80+
81+
format(name: "header") {
82+
if (useZebraStyle) {
83+
font(name: "arial", bold: true, backColor: Colour.GRAY_80, foreColor: Colour.WHITE, useBorder: true)
84+
} else {
85+
// Use default header format
86+
font(name: "arial", bold: true)
87+
}
88+
}
89+
format(name: "odd") {
90+
font(backColor: Colour.GRAY_25, useBorder: true)
91+
}
92+
format(name: "even") {
93+
font(backColor: Colour.WHITE, useBorder: true)
94+
}
95+
96+
int rowIndex = 0
97+
98+
// Option for titles on top of data table
99+
def titles = getParameters().get("titles")
100+
titles.each {
101+
cell(row: rowIndex, column: 0, value: it, format: "title")
102+
rowIndex++
103+
}
104+
105+
//Create header
106+
if (isHeaderEnabled) {
107+
final def headerFormat=getParameters().get("header.format")
108+
final Map headerFormats=getParameters().get("header.formats")
109+
//WritableCellFormat format = headerFormats.containsKey() headerFormat
110+
111+
fields.eachWithIndex { field, index ->
112+
def format = headerFormats.get(index)?:headerFormat
113+
String value = getLabel(field)
114+
cell(row: rowIndex, column: index, value: value, format: format?:"header")
115+
}
116+
117+
rowIndex++
118+
}
119+
120+
final Map columnFormats=getParameters().get("column.formats")
121+
//Rows
122+
data.eachWithIndex { object, k ->
123+
124+
fields.eachWithIndex { field, i ->
125+
def format = useZebraStyle ? ( (k % 2) == 0 ? "even" : "odd" ) : ''
126+
format = columnFormats?.containsKey(field)?columnFormats[field]:format
127+
if (format?.hasProperty('formatter') && format.formatter && !formatters.containsKey(field))
128+
formatters.put(field, format.formatter)
129+
130+
Object value = getValue(object, field)
131+
cell(row: k + rowIndex, column: i, value: value, format: format)
132+
}
133+
}
134+
135+
if (getParameters().get('titles.mergeCells')) {
136+
//Merge title cells
137+
titles.eachWithIndex { title, index ->
138+
mergeCells(startColumn: 0, startRow: index, endColumn: fields.size(), endRow: index)
139+
}
140+
}
141+
}
142+
143+
}
144+
145+
private static List computeSheetsAndLimit(List data, maxPerSheet) {
120146
if (!data)
121147
throw new ExportingException("Error during export: Empty data!")
122148

123149
def limitPerSheet = data.size() > maxPerSheet ? maxPerSheet : data.size()
124150
def sheetsCount = Math.ceil(data.size() / limitPerSheet)
125-
log.debug "limitPerSheet:$limitPerSheet ::: sheetsCount:$sheetsCount"
151+
log.debug("limitPerSheet:$limitPerSheet ::: sheetsCount:$sheetsCount")
126152
return [sheetsCount, limitPerSheet]
127153
}
128154

src/groovy/de/andreasschmitt/export/exporter/DefaultODSExporter.groovy

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package de.andreasschmitt.export.exporter
22

3-
import org.odftoolkit.simple.SpreadsheetDocument;
4-
import org.odftoolkit.simple.table.Cell;
5-
import org.odftoolkit.simple.table.Table;
3+
import org.odftoolkit.simple.SpreadsheetDocument
4+
import org.odftoolkit.simple.table.Cell
5+
import org.odftoolkit.simple.table.Table
66

77
/**
88
* @author Andreas Schmitt

src/groovy/de/andreasschmitt/export/exporter/DefaultPDFExporter.groovy

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package de.andreasschmitt.export.exporter
22

33
import com.lowagie.text.Document
4-
import com.lowagie.text.DocumentException
54
import com.lowagie.text.PageSize
65
import com.lowagie.text.Paragraph
76
import com.lowagie.text.pdf.PdfPTable
@@ -15,7 +14,6 @@ import com.lowagie.text.Phrase
1514
import com.lowagie.text.Element
1615
import com.lowagie.text.Rectangle
1716
import java.awt.Color
18-
import java.util.Map;
1917
import com.lowagie.text.Image
2018

2119
/**

src/groovy/de/andreasschmitt/export/exporter/DefaultRTFExporter.groovy

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package de.andreasschmitt.export.exporter
22

33
import com.lowagie.text.Cell
44
import com.lowagie.text.Document
5-
import com.lowagie.text.DocumentException
65
import com.lowagie.text.Font
76
import com.lowagie.text.FontFactory
87
import com.lowagie.text.PageSize

0 commit comments

Comments
 (0)