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();
Related
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>
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>
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";
}
In struts2 upload methods, can I choose where the uploaded file must be saved. I mean, all the examples in web ask me to store in WEB-INF which surely is not a good idea. I want to be able to store the uploaded file in any place in my disk.
How should i do it? Can i do it with help of ServletContextAware interceptor ?
When I use
public class DownloadFileAction extends ActionSupport implements ServletContextAware{
//private InputStream inputStream;
private int fileid;
private ServletContext servletContext;
private FileCrud fileCrud;
private MyFile myFile;
public FileCrud getFileCrud() {
return fileCrud;
}
public void setFileCrud(FileCrud fileCrud) {
this.fileCrud = fileCrud;
}
public MyFile getMyFile() {
return myFile;
}
public void setMyFile(MyFile myFile) {
this.myFile = myFile;
}
public InputStream getInputStream(){
String homepath = "c:\\files";
String fname = null;
try{
fname=getFileCrud().getAFileName(getFileid());
}catch(Exception e){
e.printStackTrace();
}
String thePathToFile = homepath+File.separator+fname;
//File targetfile = new File(thePathToFile);
return getServletContext().getResourceAsStream(thePathToFile);
}
// public void setInputStream(InputStream inputStream) {
// this.inputStream = inputStream;
// }
public int getFileid() {
return fileid;
}
public void setFileid(int fileid) {
this.fileid = fileid;
}
public ServletContext getServletContext() {
return servletContext;
}
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
public String execute(){
return SUCCESS;
}
}
and struts xml file is
<action name="fileDownload" class="com.projit1.file.DownloadFileAction">
<result type="stream" name="success">
<param name="inputName">inputStream</param>
<param name="contentType">application/octet-stream</param>
</result>
</action>
I get the following error
javax.servlet.ServletException: java.lang.IllegalArgumentException: Can not find a java.io.InputStream with the name [inputStream] in the invocation stack. Check the <param name="inputName"> tag specified for this action.
org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:515)
org.apache.struts2.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:419)
I am trying but am not getting any results.. what is wrong in this ?
To write an InputStream to a File, you need FileOutputStream.
To get an InputStream from a File, you need FileInputStream.
In your code you're trying to allocate a file using ServletContext#getResourceAsStream(), but this is intented to allocate a classpath resource. Replace it by new FileInputStream(file).
Having just finished implementing this myself. I suggest tackling the two problems separately. Do the file uploads first then the file downloads. One immediate issue with your download support is that you don't have a public getInputStream() method per your result configuration:
<param name="inputName">inputStream</param>
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();
}
}
}