Reputation: 6623
This is my xhtml-code
<p:tree value="#{documentsController.root}"
var="node" selectionMode="single"
dynamic="true">
<p:treeNode
expandedIcon="ui-icon-folder-open"
collapsedIcon="ui-icon-folder-collapsed">
<h:outputText value="#{node}" />
</p:treeNode>
<p:treeNode type="file" icon="ui-icon-document">
<h:outputText value="#{node}"/>
</p:treeNode>
<p:ajax event="select" listener="#{documentsController.onNodeSelect}"/>
</p:tree>
and this is the backing bean
@ManagedBean
@ViewScoped
public class DocumentsController implements Serializable {
TreeNode root;
//TreeNode[] selectedNodes;
@PostConstruct
public void init() {
root = new DefaultTreeNode("SRC", null);
TreeNode node0 = new DefaultTreeNode("A", root);
TreeNode node1 = new DefaultTreeNode("B", root);
TreeNode node2 = new DefaultTreeNode("C", root);
TreeNode node3 = new DefaultTreeNode("file", "D", node0);
TreeNode node4 = new DefaultTreeNode("file", "E", node0);
TreeNode node5 = new DefaultTreeNode("file", "F", node0);
String p = "C:\\Users\\federico.martinez\\Desktop\\a.wmv";
TreeNode node6 = new DefaultTreeNode("file", new File(p), node1);
TreeNode node7 = new DefaultTreeNode("file", "h", node1);
TreeNode node8 = new DefaultTreeNode("file", "i", node1);
}
public TreeNode getRoot() {
return root;
}
/*
public void setSelectedNodes(TreeNode[] selectedNodes){
this.selectedNodes = selectedNodes;
}
public TreeNode[] getSelectedNodes(){
return selectedNodes;
}*/
public void onNodeSelect(NodeSelectEvent event) {
if (event.getTreeNode().getType().equals("file")) {
File file = new File(event.getTreeNode().getData().toString());
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.setResponseHeader("Content-Type", externalContext.getMimeType(file.getName()));
externalContext.setResponseHeader("Content-Length", String.valueOf(file.length()));
externalContext.setResponseHeader("Content-Disposition", "attachment;filename=\"" + file.getName() + "\"");
InputStream input = null;
OutputStream output = null;
try {
input = new FileInputStream(file);
output = externalContext.getResponseOutputStream();
IOUtils.copy(input, output);
} catch (FileNotFoundException ex) {
System.out.println("FileNotFound: " + ex.getMessage());
} catch (IOException ex) {
System.out.println("IO: " + ex.getMessage());
} finally {
IOUtils.closeQuietly(output);
IOUtils.closeQuietly(input);
}
facesContext.responseComplete();
}
}
}
But it is not downloading the file, I used this download method with the Tomahawk tree and it worked, now I'm trying with PrimeFaces but this doesn't download the file and no error!
any advise what could be wrong?
Thanks in advance !
UPDATE
I have this modification but can't make it download the file.
<p:tree value="#{documentsController.root}"
var="node" selectionMode="single"
dynamic="true">
<p:treeNode
expandedIcon="ui-icon-folder-open"
collapsedIcon="ui-icon-folder-collapsed">
<h:outputText value="#{node}" />
</p:treeNode>
<p:treeNode type="file" icon="ui-icon-document">
<p:commandButton value="#{node}" ajax="false">
<p:fileDownload value="#{documentsController.download(node)}" />
</p:commandButton>
</p:treeNode>
</p:tree>
and the backbean is
public void download(String path) {
File f = new File(path);
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
InputStream is = ((ServletContext)externalContext.getContext()).getResourceAsStream(path);
file = new DefaultStreamedContent(is, externalContext.getMimeType(f.getName()), f.getName());
}
public StreamedContent getFile(){
return file;
}
Upvotes: 0
Views: 5893
Reputation: 1108642
Your first problem is that you're attempting to download a file by an Ajax request. This is not possible. Ajax is executed and managed by JavaScript code. JavaScript has due to security restrictions no facilities to trigger a Save As dialogue. You need to fire a fullworthy synchronous request instead. The original page will remain the same anyway if the content disposition is set to attachment
.
So, you need at least a <h:commandButton>
or <p:commandButton ajax="false">
.
Your second problem which you got when you attempted to use <p:fileDownload>
is that the value
must point to a method returning StreamedContent
, not void
. You've bound it to a void
method and hence nothing will be returned.
So, you need to return StreamedContent
on <p:fileDownload>
value.
Your third problem is that you're getting the file as classpath resource by ServletContext#getResourceAsStream()
(which I believe you blindly copypasted from PrimeFaces showcase example, which in turn is by itself also pretty poor, it could just have used ExternalContext#getResourceAsStream()
instead without the need to grab ServletContext
from under the JSF's hoods, but that aside), instead of FileInputStream
as in your original code.
So, either of those solutions must help:
<p:treeNode type="file" icon="ui-icon-document">
<p:commandButton value="#{node}" ajax="false">
<p:fileDownload value="#{documentsController.download(node)}" />
</p:commandButton>
</p:treeNode>
with
public StreamedContent download(String path) {
File file = new File(path);
InputStream input = new FileInputStream(file);
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
return new DefaultStreamedContent(input, externalContext.getMimeType(file.getName()), file.getName());
}
or
<p:treeNode type="file" icon="ui-icon-document">
<h:commandButton value="#{node}" action="#{documentsController.download(node)}" />
</p:treeNode>
with your original onNodeSelect()
method with the argument changed to String path
.
Upvotes: 2