how to return excel in Struts2 result? - java

I am trying to return an Excel sheet from my struts2 action class.
I am not sure what result-type should I be using? Has anyone tried to return an excel from struts2 action class?
I would like the user to be presented with open/save/cancel dialog box

Omnipresent covered what you need in struts.xml. I'm adding an example with the Action as well:
InputStream excelStream
String contentDisposition
String documentFormat = "xlsx"
String excel() {
ServletContext servletContext = ServletActionContext.getServletContext()
String filePath = servletContext.getRealPath("/WEB-INF/template/excel/mytemplate.${documentFormat}")
File file = new File(filePath)
Workbook wb = WorkbookFactory.create(new FileInputStream(file))
Sheet sheet = wb.getSheetAt(0)
<write to excel file>
ByteArrayOutputStream baos = new ByteArrayOutputStream()
wb.write(baos)
excelStream = new ByteArrayInputStream(baos.toByteArray())
contentDisposition = "filename=\"myfilename.${documentFormat}\""
return SUCCESS
}
String getExcelContentType() {
return documentFormat == "xlsx" ? "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" : "application/vnd.ms-excel"
}
I'm using the poi model: org.apache.poi.ss.usermodel.
You can replace "xlsx" with "xls" if you want.
struts.xml:
<action name="myaction" class="com.example.MyAction" method="excel">
<result type="stream">
<param name="contentType">${excelContentType}</param>
<param name="inputName">excelStream</param>
<param name="contentDisposition">contentDisposition</param>
<param name="bufferSize">1024</param>
</result>
</action>
(add semicolons and stuff to translate to valid Java)

You can utilize the Stream Result type
an Example will look like this:
<result name="excel" type="stream">
<param name="contentType">application/vnd.ms-excel</param>
<param name="inputName">excelStream</param>
<param name="contentDisposition">attachment; filename="${fileName}"</param>
<param name="bufferSize">1024</param>
<param name="contentLength">${contentLength}</param>
</result>
excelStream will be a method in your action class, contentLength will be length of the stream, fileName will be a getter which will return back the name of the file.

If you need to dynamically generate an Excel file using POI/HSSF and return in Struts 2,
JSP
<s:url action="DownloadExcel.action" var="downloadUrl">
</s:url>
<s:a href="%{downloadUrl}">Click to Download</s:a>
Action Method
#Action(value = "DownloadExcel")
public void download() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
String filename = "report.xlsx"; // or any other filename strategy
String mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
String characterEncoding = response.getCharacterEncoding();
if (characterEncoding != null) {
mimeType += "; charset=" + characterEncoding;
}
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + filename);
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.getSheetAt(0);
// Fill out workbook as necessary... (simple example)
XSSFRow row = sheet.createRow(0);
XSSFCell cell = row.createCell(0);
cell.setCellValue("test");
//...
ServletOutputStream out = null;
try {
out = response.getOutputStream();
workbook.write(out);
workbook.close();
} catch (IOException e) {
log.error("Failed to write into response - fileName=" + filename + ", mimeType=" + mimeType, e);
}
finally {
if (out != null) {
out.flush();
out.close();
}
}
}

Related

Struts 2 Download File is 0 bytes

I'm having an issue downloading a file using Struts2. I've done a pile of research and found a bunch of similar questions, but none of the answers have helped me out.
Here is what I currently have
JSP
<s:url id="fileDownload" namespace="/jsp" action="download"></s:url>
Download file - <s:a href="%{fileDownload}">MyFile.pdf</s:a>
Action
private InputStream inputStream;
private String fileName;
public String execute() throws Exception {
File fileToDownload = new File("C:My Documents/MyFile.pdf");
fileName = fileToDownload.getName();
inputStream = new FileInputStream(fileToDownload);
return SUCCESS;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public InputStream getInputStream() {
return inputStream;
}
Struts.xml
<action name="download" class="com.my.path.to.action.class">
<result name="success" type="stream">
<param name="contentDisposition">attachment;filename=${fileName}</param>
<param name="contentType">application/pdf</param>
<param name="inputName">inputStream</param>
<param name="bufferSize">4096</param>
</result>
</action>
When I click on the link, it will download a file that's named correctly, but it has no data in it. If anyone has any ideas as to what I'm doing wrong, I would love a suggestion as I'm sure it's just something dumb.
I found my answer. You must define the content length in struts. To do this I did the following:
Struts.xml
<param name="contentLength">${contentLength}</param>
Action
private long contentLength;
public long getContentLength() {
return contentLength;
}
public void setContentLength(long contentLength) {
this.contentLength = contentLength;
}
in execute()
contentLength = fileToDownload.length();

Declatring Struts 2 actions as annotation

I found a code for a class in the internet which using Spring and Struts2.
I only know how to declare actions in the XML file, so in that class I found this :
#ParentPackage(value = "showcase")
public class Languages extends ActionSupport {
//deleted code
#Action(value = "/languages", results = {
#Result(type = "json", name = "success", params = {
"root", "languages"
})})
public String execute() throws Exception {
if (term != null && term.length() > 1) {
ArrayList<String> tmp = new ArrayList<String>();
for (String staticLanguage : staticLanguages) {
if (StringUtils.contains(staticLanguage.toLowerCase(), term.toLowerCase())) {
tmp.add(staticLanguage);
}
}
languages = tmp.toArray(new String[tmp.size()]);
}
return SUCCESS;
}
//deleted code
So what is the equivalent for this using the XML file for Struts2?
It's not equivalent, but is mapped to the same URL.
<package name="mypackage" namespace="/" extends="showcase">
<action name="languages" class=com.struts.Languages">
<result type="json">
<param name="root">languages</param>
</result>
</action>
</package>

Struts 2 - HTTP Status 500 - Can not find a java.io.InputStream with the name

This is similar problem to:
Question A
Question B
yet I can't apply solutions in my case. Maybe someone can spot error in my code.
I want to generate Excel file in my Struts2 app and let user download it, but I get an error:
"HTTP Status 500 - Can not find a java.io.InputStream with the name"
With debugger I have confirmed that proper input stream with file content is created and method returns 'Success', so it seems that Struts is not picking up this stream.
In struts.xml I have:
<action name="exportReferences" class="manageRefAction" method="exportReferences">
<result name="success" type="stream">
<param name="contentType">application/vnd.ms-excel;charset=utf-8</param>
<param name="contentDisposition">contentDisposition</param>
<param name="inputName">excelStream</param>
<param name="bufferSize">1024</param>
</result>
(...)
</action>
Then in ManageRefAction class I have:
private InputStream excelStream;
public InputStream getExcelStream() {
return this.excelStream;
}
public String exportReferences() {
List<ReferenceData> referenceXLSList = null;
String exportFilename = null;
String filename = "";
String retrunStr = process();
Map session = (Map) ActionContext.getContext().get("session");
if (retrunStr.equalsIgnoreCase(ActionSupport.LOGIN)) {
setLog("2");
return LOGIN;
} else {
//Export only data with user's locale
ArrayList userLocale = (ArrayList) session.get("userLocale");
List<ArrayList> list = Arrays.asList(userLocale);
try {
referenceXLSList = referenceDataService.fetchReferenceDataXls();
// Data filtering
for (Iterator<ReferenceData> iterator = referenceXLSList.iterator(); iterator.hasNext(); ) {
ReferenceData ref = iterator.next();
String l = ref.getLocal().toLowerCase();
if (!userLocale.contains(l)) {
iterator.remove();
}
}
if (referenceXLSList.isEmpty()) {
return INPUT;
}
ServletContext servletContext = ServletActionContext.getServletContext();
String exportFolderPath = servletContext.getRealPath("/files" + "/xls");
File folder = new File(exportFolderPath);
// Creation of the folder if it is not existing
if (!folder.exists())
folder.mkdirs();
exportFilename = PLConstants.REF_SHEET_NAME + PLConstants.XLS_FILE_EXTENSION;
filename = exportFolderPath + "/" + exportFilename;
File file = new File(filename);
file.createNewFile();
ExcelWriter writer = new ExcelWriter();
Workbook wb = writer.writeRefData(filename, exportFilename, referenceXLSList);
setContentDisposition("attachment; filename=" + exportFilename);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
wb.write(baos);
this.excelStream = new ByteArrayInputStream(baos.toByteArray());
return SUCCESS;
} catch (Throwable e) {
e.printStackTrace();
logger.info("Exception while exporting partner references", e);
return INPUT;
}
}
}
Try this, contentDisposition is String value not getting in struts.xml.
so,it's throwing an exception.use this syntax ${contentDisposition} in param
<action name="exportReferences" class="manageRefAction" method="exportReferences">
<result name="success" type="stream">
<param name="contentType">application/vnd.ms-excel;charset=utf-8</param>
<param name="contentDisposition">${contentDisposition}</param>
<param name="inputName">excelStream</param>
<param name="bufferSize">1024</param>
</result>
(...)
</action>

Spring MVC and Apache POI to create xls doc. Can't save newly created file from model

Good day people. I'm new in Spring as well as new here.
I have problem. I have class to create xls document with Apache POI:
public class PagetoExcelConverter extends AbstractExcelView{
List<FormDate> attributesList = null;
//Create massive of constants for making table header
private final String[] HEADER_NAMES_MASSIVE = {"HEADER1", "HEADER2", "HEADER3"};
#SuppressWarnings("unchecked")
#Override
protected void buildExcelDocument(Map<String, Object> model,
HSSFWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
//Creating new instance of ArrayList for add model attributes to
attributesList = new ArrayList<FormDate>();
//Adding model attributes to ArrayList
attributesList.addAll((List<FormDate>)model.get("findAttributes"));
//Creating sheet inside of book with given name
Sheet sheet = workbook.createSheet("Result");
sheet.autoSizeColumn(0);
//Making first row as a header
Row headerRow = sheet.createRow(0);
for(int i=0; i<HEADER_NAMES_MASSIVE.length; i++) {
Cell headCell = headerRow.createCell(i);
headCell.setCellValue(HEADER_NAMES_MASSIVE[i]);
headCell.setCellStyle(headCellstyle);
}
int rowNumber=1;
for(int i=0; i<attributesList.size(); i++) {
Row dataRow = sheet.createRow(rowNumber);
Cell dataCell;
int cellNumber=0;
dataCell = dataRow.createCell(cellNumber);
dataCell.setCellValue(attributesList.get(i).getFormDescriptionList().get(i).getInstitutions().getNameOfInstitution());
cellNumber++;
dataCell = dataRow.createCell(cellNumber);
dataCell.setCellValue(attributesList.get(i).getFormDescriptionList().get(i).getInstitutionType().getTypeOfInstitution());
cellNumber++;
dataCell = dataRow.createCell(cellNumber);
dataCell.setCellValue(attributesList.get(i).getParticularDate().toString());
cellNumber++;
rowNumber++;
FileOutputStream fos = new FileOutputStream("/home/vadim/Desktop/mybook.xls");
workbook.write(fos);
}
attributesList = null;
}
}
In my servlet-context I have:
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/classes directory. Goes first -->
<beans:bean id="xlsviewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<beans:property name="order" value="1" />
<beans:property name="basename" value="views"/>
</beans:bean>
In my controller class I have method:
#RequestMapping(value="/result", method=RequestMethod.POST, params="asexcel")
public String resultXLS(#RequestParam String particularDate,
#RequestParam String institutionName,
#RequestParam String institutionType, Model model) throws Exception {
if((!particularDate.equals("")) && !institutionName.equals("") && institutionType.equals("")) {
model.addAttribute("findAttributes", educationWebService.fetchByDateAndNameService(dateConvertation(particularDate), institutionName));
} else if((!particularDate.equals("")) && (institutionName.equals("")) && (!institutionType.equals(""))) {
model.addAttribute("findAttributes", educationWebService.fetchByDateAndTypeService(dateConvertation(particularDate), institutionType));
} else if((!particularDate.equals("")) && institutionName.equals("") && institutionType.equals("")) {
model.addAttribute("findAttributes", educationWebService.fetchByDateService(dateConvertation(particularDate)));
} else {
throw new Exception("Exception occurs because it's not correspond to any case in controller");
}
return "xlspage";
}
The problem is that it doesn't save newly created file fetched from model data. Instead of this it saves something completely different file looks like TEXT/HTML not xls. When I open this this file try to open browser and direct me on url. When I add to my PagetoExcelConverter class this:
FileOutputStream fos = new FileOutputStream("/home/vadim/Desktop/mybook.xls");
workbook.write(fos);
It saves all correctly, I mean it saves the file with TXT/HTML which I don't need and saves xls by where I point it to. I need a little window pop up for user from his browser to give a user chance to save in particular place. Could you help me please?
Added call to buildExelDocument():
#This view property triggered from org.springframework.web.servlet.view.ResourceBundleViewResolver for xls converting
#Here is xlspage is name of the jsp page, is tied in with (class) with do converting model to xls
xlspage.(class)=edu.demidov.service.PagetoExcelConverter
There are a couple of tutorials on using POI with Spring MVC.
A simple usage is demonstrated by Mark Serrano here - http://krams915.blogspot.in/2011/02/spring-3-apache-poi-hibernate-creating.html.
A slightly more complex version of how to generate the excel template and import the data filled into the excel file to your own database using Spring MVC is demonstrated in my blog using BO and DAO - http://avik-ganguly.blogspot.in/2013/06/import-bulk-data-tutorial-apache-poi.html.
Hope this helps.
1º.- Add the jar of apache.poi libraries to your project.
2º.- In a method of your controller generates the xlsx as follows:
#RequestMapping
public void descargar_archivo(String dato, HttpServletRequest hsr, HttpServletResponse response) {
// Initialize your book and sheet
Workbook wb = new XSSFWorkbook();
String safeName = WorkbookUtil.createSafeSheetName("Datos");
Sheet sheet = wb.createSheet(safeName);
sheet.getPrintSetup().setLandscape(true);
sheet.getPrintSetup().setPaperSize(XSSFPrintSetup.LETTER_PAPERSIZE);
//
Row row;
Cell cell;
// We put the data we want
String titulo = dato + "Generated Data";
row = sheet.createRow(0);
cell = row.createCell(0);
cell.setCellValue(titulo);
// We set the column width auto
sheet.autoSizeColumn((short) 0);
// We modify the return flow
// to return our file xlsx
try {
// We place the necessary headers
response.reset();
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Expires:", "0"); // eliminates browser caching
// We assign the name of our file
response.setHeader("Content-Disposition", "inline; attachment; filename=MisDatos.xlsx");
// Captured backflow
OutputStream out = response.getOutputStream();
wb.write(out); // We write in that flow
out.flush(); // We emptied the flow
out.close(); // We close the flow
} catch (Exception ex) {
ex.printStackTrace();
}
}

How to define the annotation for action with image result?

I was ok to define it in struts.xml config.
<action name="getImage" class="my.action.GetImageAction">
<result name="success" type="stream">
<param name="contentType">image/jpeg</param>
<param name="inputName">imageStream</param>
<param name="bufferSize">1024</param>
</result>
</action>
And I am now trying to define it by annotation on the class with namesapce, result path, and I have no idea how to do it. Please help :)
I have tried
#Namespace("/my/namespace")
#ResultPath("/")
#Result(name = "success", type = "imageResult")
public class GetImageAction extends ActionSupport {
.....
#Override
#Action("/getImage")
public String execute() throws Exception {
.....
And I got an error
HTTP Status 404 - No result defined for action
As the error says the results have to be defined at the Action.
The definition would look like this
#Action(value = "getImage", results = { #Result(
name = "success",
type = "stream",
params = {"contentType", "application/pdf" }) })
In the example you see the type too and how to define the contentType.
And the stream will be returned by the "getFileInputStream"-method:
public InputStream getFileInputStream() {
return fileInputStream;
}
the "getContentDisposition"-Method has to be available in the Action-class
public String getContentDisposition() {
return "attachment; filename=" + getFilename() + ".pdf";
}

Categories