Download file, filename doesn't work in portlet

后端 未结 2 745
你的背包
你的背包 2021-01-27 13:12

I set filename in the HttpServletResponse header but when I download it has not this filename

FileInputStream fis = new FileInputStream(fileDocument         


        
相关标签:
2条回答
  • 2021-01-27 14:03

    You should not use the HttpServletResponse. Instead you should create a custom Resource and ResourceHandler:

    CustomResourceHandler.java:

    public final class CustomResourceHandler extends ResourceHandlerWrapper {
    
        // Public Constants
        public static final String LIBRARY_NAME = "exampleLib";
        public static final String RESOURCE_NAME = "exampleName";
    
        // Private Data Members
        private ResourceHandler wrappedResourceHandler;
    
        public CustomResourceHandler(ResourceHandler resourceHandler) {
            this.wrappedResourceHandler = resourceHandler;
        }
    
        @Override
        public Resource createResource(String resourceName, String libraryName) {
    
            if (LIBRARY_NAME.equals(libraryName)) {
    
                if (RESOURCE_NAME.equals(resourceName)) {
                    return new CustomResource(libraryName, resourceName,
                        "exampleFileName.txt", "Example Content");
                }
                else {
                    return super.createResource(resourceName, libraryName);
                }
            }
            else {
                return super.createResource(resourceName, libraryName);
            }
        }
    
        @Override
        public ResourceHandler getWrapped() {
            return wrappedResourceHandler;
        }
    
        @Override
        public boolean libraryExists(String libraryName) {
    
            if (LIBRARY_NAME.equals(libraryName)) {
                return true;
            }
            else {
                return super.libraryExists(libraryName);
            }
        }
    
        /* package-private */ static final class CustomResource extends Resource {
    
            private final String content;
            private final Map<String, String> responseHeaders;
            private final String requestPath;
            private final URL url;
    
            public CustomResource(String libraryName, String resourceName,
                String fileName, String content) {
    
                super.setLibraryName(libraryName);
                super.setResourceName(resourceName);
                super.setContentType("text/plain");
    
                Map<String, String> responseHeaders = new HashMap<String, String>();
                responseHeaders.put("Content-Disposition",
                    "attachment; filename=" + fileName + ";");
    
                this.responseHeaders = Collections.unmodifiableMap(responseHeaders);
    
                StringBuilder sb = new StringBuilder();
                sb.append(ResourceHandler.RESOURCE_IDENTIFIER);
                sb.append("/");
                sb.append(super.getResourceName());
                sb.append("?ln=");
                sb.append(super.getLibraryName());
                this.requestPath = sb.toString();
    
                URL url;
    
                try {
    
                    FacesContext facesContext = FacesContext.getCurrentInstance();
                    ExternalContext externalContext = facesContext.getExternalContext();
                    url = new URL(externalContext.encodeResourceURL(this.requestPath));
                }
                catch (MalformedURLException e) {
                    url = null;
                }
    
                this.url = url;
                this.content = content;
            }
    
            @Override
            public InputStream getInputStream() throws IOException {
                return new ByteArrayInputStream(
                    content.getBytes(StandardCharsets.UTF_8));
            }
    
            @Override
            public String getRequestPath() {
                return requestPath;
            }
    
            @Override
            public Map<String, String> getResponseHeaders() {
                return responseHeaders;
            }
    
            @Override
            public URL getURL() {
                return url;
            }
    
            @Override
            public boolean userAgentNeedsUpdate(FacesContext facesContext) {
    
                // Return false if the content cannot change dynamically.
                return true;
            }
        }
    }
    

    WEB-INF/faces-config.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
    
        <application>
            <!-- ... -->
            <resource-handler>custom.resource.handler.CustomResourceHandler</resource-handler>
        </application>
    <!-- ... -->
    </faces-config>
    

    Here's some example code for downloading the resource:

    <h:outputLink target="_blank" value="#{bean.getDownloadURL(facesContext)}">
        <h:outputText value="download" />
    </h:outputLink>
    

    public String getDownloadURL(FacesContext facesContext) {
    
        return facesContext.getApplication().getResourceHandler()
                .createResource(CustomResourceHandler.RESOURCE_NAME,
                    CustomResourceHandler.LIBRARY_NAME)
                .getURL().toString();
    }
    

    You can also look at the Liferay Faces JSF Export PDF for a full portlet example to download/export a file.

    0 讨论(0)
  • 2021-01-27 14:13

    If you are in the action or render phase of your portlet (what I would guess for a JSF portlet): there is a ResponseWrapper which will suppress any header. I'm using this method to find the response for sending binary data during the JSF lifecycle:

    public static HttpServletResponse getHttpServletResponse() {
        final FacesContext facesContext = FacesContext.getCurrentInstance();
        if (facesContext == null) {
            throw new IllegalStateException("Not inside a JSF request");
        }
        final Object responseObject = facesContext.getExternalContext().getResponse();
        if (responseObject instanceof HttpServletResponse) {
            return (HttpServletResponse) responseObject;
        }
        if (responseObject instanceof PortletResponse) {
            // Use Liferays util to find the real response
            HttpServletResponse response = PortalUtil.getHttpServletResponse((PortletResponse) responseObject);
            // Find the outer most response (setting the headers would have no effect, as we are included)
            while (response instanceof ServletResponseWrapper) {
                final ServletResponse servletResponse = ((ServletResponseWrapper) response).getResponse();
                if (!(servletResponse instanceof HttpServletResponse)) {
                    break;
                }
                response = (HttpServletResponse) servletResponse;
            }
            return response;
        }
        throw new IllegalStateException("Unknown type of response object: " + responseObject);
    }
    
    0 讨论(0)
提交回复
热议问题