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.