Skip to content

Commit 76cf5be

Browse files
committed
Support for XSSFWorkbook and SXSSFWorkbook (xmlx format; POI 3.9+)
Introduces an AbstractXlsView and dedicated subclasses for POI's xmlx support. Deprecates the traditional AbstractExcelView which is based on pre POI 3.5 API. Issue: SPR-6898
1 parent e2110e3 commit 76cf5be

File tree

7 files changed

+367
-17
lines changed

7 files changed

+367
-17
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,7 @@ project("spring-webmvc") {
837837
optional("javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1")
838838
optional("net.sourceforge.jexcelapi:jxl:2.6.12")
839839
optional("org.apache.poi:poi:3.11")
840+
optional("org.apache.poi:poi-ooxml:3.11")
840841
optional("org.apache.velocity:velocity:1.7")
841842
optional("velocity-tools:velocity-tools-view:1.4")
842843
optional("org.freemarker:freemarker:${freemarkerVersion}")

spring-webmvc/src/main/java/org/springframework/web/servlet/view/document/AbstractExcelView.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import org.apache.poi.hssf.usermodel.HSSFRow;
2727
import org.apache.poi.hssf.usermodel.HSSFSheet;
2828
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
29-
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
3029

3130
import org.springframework.core.io.Resource;
3231
import org.springframework.core.io.support.LocalizedResourceHelper;
@@ -92,7 +91,10 @@
9291
* @author Jean-Pierre Pawlak
9392
* @author Juergen Hoeller
9493
* @see AbstractPdfView
94+
* @deprecated as of Spring 4.2, in favor of {@link AbstractXlsView} and its
95+
* {@link AbstractXlsxView} and {@link AbstractXlsxStreamingView} variants
9596
*/
97+
@Deprecated
9698
public abstract class AbstractExcelView extends AbstractView {
9799

98100
/** The content type for an Excel response */
@@ -172,8 +174,7 @@ protected HSSFWorkbook getTemplateSource(String url, HttpServletRequest request)
172174
if (logger.isDebugEnabled()) {
173175
logger.debug("Loading Excel workbook from " + inputFile);
174176
}
175-
POIFSFileSystem fs = new POIFSFileSystem(inputFile.getInputStream());
176-
return new HSSFWorkbook(fs);
177+
return new HSSFWorkbook(inputFile.getInputStream());
177178
}
178179

179180
/**
@@ -194,7 +195,7 @@ protected abstract void buildExcelDocument(
194195
* <p>Creates the row and the cell if they still doesn't already exist.
195196
* Thus, the column can be passed as an int, the method making the needed downcasts.
196197
* @param sheet a sheet object. The first sheet is usually obtained by workbook.getSheetAt(0)
197-
* @param row thr row number
198+
* @param row the row number
198199
* @param col the column number
199200
* @return the HSSFCell
200201
*/
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright 2002-2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.servlet.view.document;
18+
19+
import java.io.Closeable;
20+
import java.io.IOException;
21+
import java.util.Map;
22+
import javax.servlet.ServletOutputStream;
23+
import javax.servlet.http.HttpServletRequest;
24+
import javax.servlet.http.HttpServletResponse;
25+
26+
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
27+
import org.apache.poi.ss.usermodel.Workbook;
28+
29+
import org.springframework.web.servlet.view.AbstractView;
30+
31+
/**
32+
* Convenient superclass for Excel document views in traditional XLS format.
33+
* Compatible with Apache POI 3.5 and higher.
34+
*
35+
* <p>For working with the workbook in the subclass, see
36+
* <a href="http://poi.apache.org">Apache's POI site</a>
37+
*
38+
* @author Juergen Hoeller
39+
* @since 4.2
40+
*/
41+
public abstract class AbstractXlsView extends AbstractView {
42+
43+
/**
44+
* Default Constructor.
45+
* Sets the content type of the view to "application/vnd.ms-excel".
46+
*/
47+
public AbstractXlsView() {
48+
setContentType("application/vnd.ms-excel");
49+
}
50+
51+
52+
@Override
53+
protected boolean generatesDownloadContent() {
54+
return true;
55+
}
56+
57+
/**
58+
* Renders the Excel view, given the specified model.
59+
*/
60+
@Override
61+
protected final void renderMergedOutputModel(
62+
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
63+
64+
// Create a fresh workbook instance for this render step.
65+
Workbook workbook = createWorkbook(model, request);
66+
67+
// Delegate to application-provided document code.
68+
buildExcelDocument(model, workbook, request, response);
69+
70+
// Set the content type.
71+
response.setContentType(getContentType());
72+
73+
// Flush byte array to servlet output stream.
74+
renderWorkbook(workbook, response);;
75+
}
76+
77+
78+
/**
79+
* Template method for creating the POI {@link Workbook} instance.
80+
* <p>The default implementation creates a traditional {@link HSSFWorkbook}.
81+
* Spring-provided subclasses are overriding this for the OOXML-based variants;
82+
* custom subclasses may override this for reading a workbook from a file.
83+
* @param model the model Map
84+
* @param request current HTTP request (for taking the URL or headers into account)
85+
* @return the new {@link Workbook} instance
86+
*/
87+
protected Workbook createWorkbook(Map<String, Object> model, HttpServletRequest request) {
88+
return new HSSFWorkbook();
89+
}
90+
91+
/**
92+
* The actual render step: taking the POI {@link Workbook} and rendering
93+
* it to the given response.
94+
* @param workbook the POI Workbook to render
95+
* @param response current HTTP response
96+
* @throws IOException when thrown by I/O methods that we're delegating to
97+
*/
98+
protected void renderWorkbook(Workbook workbook, HttpServletResponse response) throws IOException {
99+
ServletOutputStream out = response.getOutputStream();
100+
workbook.write(out);
101+
out.flush();
102+
103+
// Closeable only implemented as of POI 3.10
104+
if (workbook instanceof Closeable) {
105+
((Closeable) workbook).close();
106+
}
107+
}
108+
109+
/**
110+
* Application-provided subclasses must implement this method to populate
111+
* the Excel workbook document, given the model.
112+
* @param model the model Map
113+
* @param workbook the Excel workbook to populate
114+
* @param request in case we need locale etc. Shouldn't look at attributes.
115+
* @param response in case we need to set cookies. Shouldn't write to it.
116+
*/
117+
protected abstract void buildExcelDocument(
118+
Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response)
119+
throws Exception;
120+
121+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2002-2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.servlet.view.document;
18+
19+
import java.io.IOException;
20+
import java.util.Map;
21+
import javax.servlet.http.HttpServletRequest;
22+
import javax.servlet.http.HttpServletResponse;
23+
24+
import org.apache.poi.ss.usermodel.Workbook;
25+
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
26+
27+
/**
28+
* Convenient superclass for Excel document views in the Office 2007 XLSX format,
29+
* using POI's streaming variant. Compatible with Apache POI 3.9 and higher.
30+
*
31+
* <p>For working with the workbook in the subclass, see
32+
* <a href="http://poi.apache.org">Apache's POI site</a>
33+
*
34+
* @author Juergen Hoeller
35+
* @since 4.2
36+
*/
37+
public abstract class AbstractXlsxStreamingView extends AbstractXlsxView {
38+
39+
/**
40+
* This implementation creates a {@link SXSSFWorkbook} for streaming the XLSX format.
41+
*/
42+
@Override
43+
protected SXSSFWorkbook createWorkbook(Map<String, Object> model, HttpServletRequest request) {
44+
return new SXSSFWorkbook();
45+
}
46+
47+
/**
48+
* This implementation disposes the {@link SXSSFWorkbook} when done with rendering.
49+
* @see org.apache.poi.xssf.streaming.SXSSFWorkbook#dispose()
50+
*/
51+
@Override
52+
protected void renderWorkbook(Workbook workbook, HttpServletResponse response) throws IOException {
53+
super.renderWorkbook(workbook, response);
54+
55+
// Dispose temporary files in case of streaming variant...
56+
((SXSSFWorkbook) workbook).dispose();
57+
}
58+
59+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2002-2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.servlet.view.document;
18+
19+
import java.util.Map;
20+
import javax.servlet.http.HttpServletRequest;
21+
22+
import org.apache.poi.ss.usermodel.Workbook;
23+
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
24+
25+
/**
26+
* Convenient superclass for Excel document views in the Office 2007 XLSX format
27+
* (as supported by POI-OOXML). Compatible with Apache POI 3.5 and higher.
28+
*
29+
* <p>For working with the workbook in the subclass, see
30+
* <a href="http://poi.apache.org">Apache's POI site</a>
31+
*
32+
* @author Juergen Hoeller
33+
* @since 4.2
34+
*/
35+
public abstract class AbstractXlsxView extends AbstractXlsView {
36+
37+
/**
38+
* Default Constructor.
39+
* Sets the content type of the view to
40+
* "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet".
41+
*/
42+
public AbstractXlsxView() {
43+
setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
44+
}
45+
46+
/**
47+
* This implementation creates an {@link XSSFWorkbook} for the XLSX format.
48+
*/
49+
@Override
50+
protected Workbook createWorkbook(Map<String, Object> model, HttpServletRequest request) {
51+
return new XSSFWorkbook();
52+
}
53+
54+
}

spring-webmvc/src/test/java/org/springframework/web/servlet/view/document/ExcelViewTests.java

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -36,7 +36,6 @@
3636
import org.apache.poi.hssf.usermodel.HSSFRow;
3737
import org.apache.poi.hssf.usermodel.HSSFSheet;
3838
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
39-
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
4039
import org.junit.Before;
4140
import org.junit.Test;
4241

@@ -59,8 +58,6 @@
5958
@SuppressWarnings("deprecation")
6059
public class ExcelViewTests {
6160

62-
private MockServletContext servletCtx;
63-
6461
private MockHttpServletRequest request;
6562

6663
private MockHttpServletResponse response;
@@ -70,7 +67,7 @@ public class ExcelViewTests {
7067

7168
@Before
7269
public void setUp() {
73-
servletCtx = new MockServletContext("org/springframework/web/servlet/view/document");
70+
MockServletContext servletCtx = new MockServletContext("org/springframework/web/servlet/view/document");
7471
request = new MockHttpServletRequest(servletCtx);
7572
response = new MockHttpServletResponse();
7673
webAppCtx = new StaticWebApplicationContext();
@@ -99,8 +96,7 @@ protected void buildExcelDocument(Map<String, Object> model, HSSFWorkbook wb,
9996

10097
excelView.render(new HashMap<String, Object>(), request, response);
10198

102-
POIFSFileSystem poiFs = new POIFSFileSystem(new ByteArrayInputStream(response.getContentAsByteArray()));
103-
HSSFWorkbook wb = new HSSFWorkbook(poiFs);
99+
HSSFWorkbook wb = new HSSFWorkbook(new ByteArrayInputStream(response.getContentAsByteArray()));
104100
assertEquals("Test Sheet", wb.getSheetName(0));
105101
HSSFSheet sheet = wb.getSheet("Test Sheet");
106102
HSSFRow row = sheet.getRow(2);
@@ -134,8 +130,7 @@ protected void buildExcelDocument(Map<String, Object> model, HSSFWorkbook wb,
134130
excelView.setUrl("template");
135131
excelView.render(new HashMap<String, Object>(), request, response);
136132

137-
POIFSFileSystem poiFs = new POIFSFileSystem(new ByteArrayInputStream(response.getContentAsByteArray()));
138-
HSSFWorkbook wb = new HSSFWorkbook(poiFs);
133+
HSSFWorkbook wb = new HSSFWorkbook(new ByteArrayInputStream(response.getContentAsByteArray()));
139134
HSSFSheet sheet = wb.getSheet("Sheet1");
140135
HSSFRow row = sheet.getRow(0);
141136
HSSFCell cell = row.getCell(0);
@@ -168,8 +163,7 @@ protected void buildExcelDocument(Map<String, Object> model, HSSFWorkbook wb,
168163
excelView.setUrl("template");
169164
excelView.render(new HashMap<String, Object>(), request, response);
170165

171-
POIFSFileSystem poiFs = new POIFSFileSystem(new ByteArrayInputStream(response.getContentAsByteArray()));
172-
HSSFWorkbook wb = new HSSFWorkbook(poiFs);
166+
HSSFWorkbook wb = new HSSFWorkbook(new ByteArrayInputStream(response.getContentAsByteArray()));
173167
HSSFSheet sheet = wb.getSheet("Sheet1");
174168
HSSFRow row = sheet.getRow(0);
175169
HSSFCell cell = row.getCell(0);
@@ -202,8 +196,7 @@ protected void buildExcelDocument(Map<String, Object> model, HSSFWorkbook wb,
202196
excelView.setUrl("template");
203197
excelView.render(new HashMap<String, Object>(), request, response);
204198

205-
POIFSFileSystem poiFs = new POIFSFileSystem(new ByteArrayInputStream(response.getContentAsByteArray()));
206-
HSSFWorkbook wb = new HSSFWorkbook(poiFs);
199+
HSSFWorkbook wb = new HSSFWorkbook(new ByteArrayInputStream(response.getContentAsByteArray()));
207200
HSSFSheet sheet = wb.getSheet("Sheet1");
208201
HSSFRow row = sheet.getRow(0);
209202
HSSFCell cell = row.getCell(0);

0 commit comments

Comments
 (0)