Download files & filename
cleric Dec 30, 2010 7:51 AMHello.
In my application users can upload and download files. And they want to download files with names which they upload. Those can be files with names on different languages. So, i must return their names in UTF-8 encoding.
But the Seam
DocumentStoreServlet
doesn't apply any encoding for this approach.
For some research i'd gone for conclusion: seam doesn't support all existing browsers.
i took the DocumentStoreServlet class and I wrote own. It is his source:
public class MyDocumentStoreServlet extends HttpServlet { private static final String ENCODING = "UTF-8"; protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { new ContextualHttpServletRequest(request) { @Override public void process() throws ServletException, IOException { doWork(request, response); } }.run(); } private static void doWork(HttpServletRequest request, HttpServletResponse response) throws IOException { Parameters params = Parameters.instance(); String contentId = (String) params.convertMultiValueRequestParameter(params.getRequestParameters(), "docId", String.class); DocumentStore store = DocumentStore.instance(); if (store.idIsValid(contentId)) { DocumentData documentData = store.getDocumentData(contentId); response.setContentType(documentData.getDocumentType().getMimeType()); new ContentDispositionBuilder(request, response, documentData).build(); documentData.writeDataToStream(response.getOutputStream()); } else { String error = store.getErrorPage(); if (error != null) { if (error.startsWith("/")) { error = request.getContextPath() + error; } response.sendRedirect(error); } else { response.sendError(404); } } } private static class ContentDispositionBuilder { private HttpServletRequest request; private HttpServletResponse response; private DocumentData documentData; private String userAgent; private ContentDispositionBuilder(HttpServletRequest request, HttpServletResponse response, DocumentData documentData) { this.request = request; this.response = response; this.documentData = documentData; } public void build() throws UnsupportedEncodingException { userAgent = request.getHeader("User-Agent").toLowerCase(); String fileName = buildFileName(); String fileNameAttr = "filename="; if (isIE() || isChrome()) { fileName = "\"" + fileName + "\""; } else { fileNameAttr = fileNameAttr.replace("=", "*=") + ENCODING + "''"; } response.setHeader("Content-Disposition", documentData.getDisposition() + "; " + fileNameAttr + fileName); } private String buildFileName() throws UnsupportedEncodingException { String fileName = documentData.getFileName(); return URLEncoder.encode(fileName, ENCODING).replaceAll("\\+", "%20"); } private boolean isFirefox() { return userAgent.contains("gecko"); } private boolean isIE() { return userAgent.contains("msie"); } private boolean isOpera() { return userAgent.contains("opera"); } private boolean isChrome() { return userAgent.contains("webkit"); } } }
It is a sample of usage this approche:
1. My facelet messageFile.xhtml:
<s:resource xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.com/products/seam/taglib" data="#{messageFileResource.body}" fileName="#{messageFileResource.fileName}"/>
and second sample:
<s:resource xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.com/products/seam/taglib" data="#{reqDocumentResource.body}" fileName="#{reqDocumentResource.fileName}"/>
2. My component:
public abstract class DownloadFileResource<T> { protected byte[] body; protected String fileName; public byte[] getBody() { return body; } public String getFileName() { return fileName; } protected abstract String buildFileName(T o); }
3. And implementation:
@Name("messageFileResource") @Scope(ScopeType.EVENT) public class MessageFileResource extends DownloadFileResource<MessageFile> { @RequestParameter private String name; @RequestParameter private Long messageId; @In private EntityHome<MessageFile> messageFileHome; @Create public void create() throws UnsupportedEncodingException { MessageFilePk pk = new MessageFilePk(new Message(messageId), name); messageFileHome.setId(pk); MessageFile file = messageFileHome.getInstance(); body = file.getFileBody(); fileName = buildFileName(file); messageFileHome.clearInstance(); } @Override protected String buildFileName(MessageFile o) { return o.getId().getFileName() + "." + o.getContentType(); } }
In my logic the ContentType is the file extension.
I think my solution may help for many developers who make applications with internationalized interface and they is cross-browser.