Mostrar / descargar archivos txt o csv con commandLink y Tree2 tomahawk JSF

I have a tree (tree2 tomahawk 1.1.11) that shows a list of dirs and files. When I click on a file I would like to show the download dialog to let the client download the file. My page looks like

    ...
    <h:form>
        <t:tree2 id="tree" value="#{listFiles.treeData}"
                 var="node" varNodeToggler="t" >
            <f:facet name="folder">
                <h:panelGroup>
                    <f:facet name="expand">
                        <t:graphicImage value="images/folderOpen.png"
                                        rendered="#{t.nodeExpanded}}"
                                        border="0" />
                    </f:facet>
                    <f:facet name="collapse">
                        <t:graphicImage value="images/folderClose.png"
                                        rendere="#{t.nodeExpanded}}"
                                        border="0" />
                    </f:facet>
                    <h:outputText value="#{node.description}"
                                  styleClass="nodeFolder" />
                </h:panelGroup>
            </f:facet>
            <f:facet name="file">
                <h:panelGroup>
                    <h:commandLink action="#{listFiles.download()}" >
                        <t:graphicImage value="images/file.png" border="0" />
                        <h:outputText value="#{node.description}" />
                    </h:commandLink>
                </h:panelGroup>
            </f:facet>
        </t:tree2>
    </h:form>
    ...

And my bean is

@ManagedBean
@RequestScoped
public class ListFiles implements Serializable {

    private String path = "C:\\";
    private TreeNode treeRoot;
    private File dirRoot;
    @ManagedProperty("#{userVerifier}")
    private UserVerifier userVerifier;

    public void setUserVerifier(UserVerifier userVerifier) {
        this.userVerifier = userVerifier;
    }

    public UserVerifier getUserVerifier() {
        return userVerifier;
    }

    public TreeNode getTreeData() {
        path = loadConfiguredPath();
        String dependencia = userVerifier.getDependencia();

        if (dependencia.equals("DESARROLLO")) {
            path = path + "dataFiles";
            treeRoot = new TreeNodeBase("folder", "SRC", false);
        } else {
            path = path + "dataFiles\\" + dependencia;
            treeRoot = new TreeNodeBase("folder", dependencia, false);
        }

        dirRoot = new File(path);
        createTree(dirRoot, treeRoot);

        return treeRoot;
    }

    private void createTree(File fileRoot, TreeNode treeRoot) {
        File[] files = fileRoot.listFiles();
        TreeNodeBase tnb;
        for (File f : files) {
            if (f.isDirectory()) {
                tnb = new TreeNodeBase("folder", f.getName(), false);
                treeRoot.getChildren().add(tnb);
                createTree(f, tnb);
            }
            if (f.isFile()) {
                tnb = new TreeNodeBase("file", f.getName(), false);
                treeRoot.getChildren().add(tnb);
            }
        }
        return;
    }

    private String loadConfiguredPath() {
        String dir;
        ReadXML reader = new ReadXML(".\\webapps\\SRC\\configFiles\\confSRC.xml");
        dir = reader.getValue("baseDir");
        if (dir == null) {
            return path;
        } else {
            return dir;
        }
    }

    public String download(){
        System.out.println("Yes we are downloading");
        return "ok";
    }
}

Everything works fine except I don't know how to achieve the download action when click on the h: commandLink

The only type of files I have are txt or csv.

ACTUALIZACIÓN:

Now as I have the code, this exception is thrown.

javax.servlet.ServletException
    javax.faces.webapp.FacesServlet.service(FacesServlet.java:422)
    org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:349)

ACTUALIZACIÓN:

I'll post my web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>

    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>

    <welcome-file-list>
        <welcome-file>faces/index.xhtml</welcome-file>
    </welcome-file-list>

    <filter>
        <filter-name>MyFacesExtensionsFilter</filter-name>
        <filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class>

        <init-param>
            <param-name>uploadMaxFileSize</param-name>
            <param-value>5g</param-value>
        </init-param>
        <init-param>
            <param-name>uploadThresholdSize</param-name>
            <param-value>500m</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>MyFacesExtensionsFilter</filter-name>
        <servlet-name>Faces Servlet</servlet-name>
    </filter-mapping>

    <filter-mapping>
        <filter-name>MyFacesExtensionsFilter</filter-name>
        <servlet-name>/faces/*</servlet-name>
    </filter-mapping>

    <context-param>
        <param-name>org.apache.myfaces.CHECK_EXTENSIONS_FILTER</param-name>
        <param-value>false</param-value>
    </context-param>

</web-app>

preguntado el 08 de noviembre de 11 a las 19:11

1 Respuestas

Basically, you'd need to pass the physical File o al menos File#getAbsolutePath() around as value so that the download action method can read it from disk. I've never used <t:tree2> so I checked the Javadoc of TreeNodeBase and it doesn't seem to support anything else than String description as node value. It's not possible to set it with a File. So you really need to pass File#getAbsolutePath() down into it. I think you can use the String identifier argument for this:

tnb = new TreeNodeBase("file", f.getName(), f.getAbsolutePath(), false);

Then, in the view, just pass it to the action method:

<h:commandLink action="#{listFiles.download(node.identifier)}" >

Finally, stream it as follows:

public String download(String absolutePath) throws IOException {
    File file = new File(absolutePath);
    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);
    } finally {
        IOUtils.closeQuietly(output);
        IOUtils.closeQuietly(input);
    }

    facesContext.responseComplete();
}

respondido 08 nov., 11:23

Ick, try adding context param of javax.faces.PARTIAL_STATE_SAVING con valor de false a web.xml and retry. Can you tell what Mojarra impl/version you're using? - BalusC

Oh wait, you're creating the tree data in the getter method. You should do it in a @PostConstruct method instead. The getter should only return the property. - BalusC

The exact JSF impl/version should be visible in webapp startup log, e.g. Mojarra 2.1.3. According to the stacktrace you're definitely using Mojarra, I only need to know the exact version. As to the solution, the NullPointerException which you got there suggests that the partial state saving of a <f:facet> tag has failed. Right now I can't tell if it's a bug in Mojarra or a bug in Tomahawk's t:tree2. You could try with latest Mojarra which is 2.1.3 or try it together with the alternative JSF implementation MyFaces. This problem has nothing to do with your own code. - BalusC

Tomcat doesn't ship with JSF out the box, so you should surely have downloaded and installed it yourself in /WEB-INF/lib folder. Do you know what download link you've used? Perhaps you've still the original zip file? It should contain the exact version in the filename. The webapp startup logs can be found in Tomcat/logs (or just in console of your IDE). Disabling the partial state saving has the only disadvantage that the size of the view state grows in memory and that processing ajax requests will be somewhat slower. - BalusC

No, Tomahawk is a standalone component library which just happen to be developed/maintained by the same guys as those behind MyFaces. Tomahawk should run without problems on all other JSF implementations, including Mojarra. Mojarra doesn't have an extended component library, but the Mojarra developers have a "sandbox" which is known as báscula. It doesn't contain much of really interesting components though. - BalusC

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.