package com.github.ryoasai.springmvc.jxls;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.jxls.transformer.XLSTransformer;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.LocalizedResourceHelper;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.servlet.view.AbstractUrlBasedView;
import com.github.ryoasai.springmvc.Controllers;
public class JxlsView extends AbstractUrlBasedView {
/** The content type for an Excel response */
private static final String CONTENT_TYPE = "application/vnd.ms-excel";
/** The extension to look for existing templates */
private static final String EXTENSION = ".xls";
private DownloadFilenameEncoder downloadFilenameEncoder = new DefaultDownloadFilenameEncoder();
/**
* Default Constructor. Sets the content type of the view to
* "application/vnd.ms-excel".
*/
public JxlsView() {
setContentType(CONTENT_TYPE);
}
public void setDownloadFilenameEncoder(
DownloadFilenameEncoder downloadFilenameEncoder) {
this.downloadFilenameEncoder = downloadFilenameEncoder;
}
@Override
protected boolean generatesDownloadContent() {
return true;
}
/**
* Renders the Excel view, given the specified model.
*/
@Override
protected final void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
HSSFWorkbook workbook = createWorkbook(request);
buildExcelDocument(model, workbook, request, response);
setupHeader(model, request, response);
doRender(response, workbook);
}
protected void setupHeader(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response)
throws UnsupportedEncodingException {
// Set the content type.
response.setContentType(getContentType());
setupHeaderForDownloadFilename(model, request, response);
}
protected void setupHeaderForDownloadFilename(Map<String, Object> model, HttpServletRequest request,
HttpServletResponse response) throws UnsupportedEncodingException {
Jxls jxls = getJxslAnnotation();
assert jxls != null; // This view is only applied when @Jxls is present.
String filename = jxls.filename();
if (model.containsKey(filename)) {
filename = model.get(filename).toString();
}
response.setHeader("Content-Disposition", "attachment; filename=" + downloadFilenameEncoder.encode(request, filename));
}
private Jxls getJxslAnnotation() {
Method currentHandlerMethod = Controllers.getCurrentHandlerMethod();
assert currentHandlerMethod != null;
return currentHandlerMethod.getAnnotation(Jxls.class);
}
private HSSFWorkbook createWorkbook(HttpServletRequest request) throws Exception {
HSSFWorkbook workbook;
if (getUrl() != null) {
workbook = getTemplateSource(getUrl(), request);
} else {
workbook = new HSSFWorkbook();
logger.debug("Created Excel Workbook from scratch");
}
return workbook;
}
private void doRender(HttpServletResponse response, HSSFWorkbook workbook) throws IOException {
// Flush byte array to servlet output stream.
ServletOutputStream out = response.getOutputStream();
workbook.write(out);
out.flush();
}
/**
* Creates the workbook from an existing XLS document.
*
* @param url
* the URL of the Excel template without localization part nor
* extension
* @param request
* current HTTP request
* @return the HSSFWorkbook
* @throws Exception
* in case of failure
*/
protected HSSFWorkbook getTemplateSource(String url, HttpServletRequest request) throws Exception {
LocalizedResourceHelper helper = new LocalizedResourceHelper(getApplicationContext());
Locale userLocale = RequestContextUtils.getLocale(request);
Resource inputFile = helper.findLocalizedResource(url, url.endsWith(EXTENSION) ? "" : EXTENSION, userLocale);
// Create the Excel document from the source.
if (logger.isDebugEnabled()) {
logger.debug("Loading Excel workbook from " + inputFile);
}
POIFSFileSystem fs = new POIFSFileSystem(inputFile.getInputStream());
return new HSSFWorkbook(fs);
}
/**
* Build excel document using jXML template and the given model.
*
* @param model
* the model Map
* @param workbook
* the Excel workbook to complete
* @param request
* in case we need locale etc. Shouldn't look at attributes.
* @param response
* in case we need to set cookies. Shouldn't write to it.
*/
protected void buildExcelDocument(Map<String, Object> model, HSSFWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
XLSTransformer transformer = new XLSTransformer();
transformer.transformWorkbook(workbook, model);
}
}