Help

Web applications often need to provide a link for the user to download a file, such as an expense report. Seam 2.1.2.CR1 makes the task of serving a file to the user easy and RESTful using a combination of the s:resource and s:download tags. But before we can use these tags, we need to do some simple configuration.

The s:resource tag uses Seam’s DocumentStore to serve (or push) documents. You'll need to configure this servlet in to your web.xml:

web.xml

<servlet>
   <servlet-name>Document Store Servlet</servlet-name>
   <servlet-class>org.jboss.seam.document.DocumentStoreServlet</servlet-class>
</servlet>
<servlet-mapping>
   <servlet-name>Document Store Servlet</servlet-name>
   <url-pattern>/seam/docstore/*</url-pattern>
</servlet-mapping>

Alone in a page, s:resource will act as the file download provider by defining where to get the file data and meta-data. You use it in place of HTML (not inside of HTML) since the intent is to serve the document and not a web page. Thus, the page template should look something like this.

resources.xhtml

<s:resource xmlns="http://www.w3.org/1999/xhtml"
	xmlns:s="http://jboss.com/products/seam/taglib"
	data="#{fileResourceProvider.data}"
	contentType="#{fileResourceProvider.contentType}"
	fileName="#{fileResourceProvider.fileName}" />
  • data is the actual file data. It may be a java.util.File, an InputStream or a byte[].
  • contentType (e.g., image/jpeg)
  • filename (e.g., someFile.jpg) which will likely be displayed in the user's file download prompt

Other attributes are described in the Seam reference documentation.

If we want resources.xml to serve all of our documents (or at least those handled by the fileResourceProvider component), we need to pass one (or many) parameters to it such that it can load the document information and data for a given request. We do that by using request parameters (e.g., http://localhost/app/resources.seam?fileId=1). There are at least two ways of getting the parameter holding the file id into the fileResourceProvider component. You could use the @RequestParameter annotation;

@RequestParameter
private Long fileId;

or inject it via pages.xml:

<page view-id=”/resources.xhtml”>
   <param name="fileId" value="#{fileResourceProvider.fileId}"/>
</page>

Taking the first approach, the FileResourceProvider.java would then be defined as follows:

@Name("fileResourceProvider")
@Scope(ScopeType.EVENT)
public class FileResourceProvider
{

   @RequestParameter
   private Long fileId;
   private String fileName;
   private String contentType;
   private byte[] data;

   @Create
   public void create()
   {
      FileItem item = em.find(FileItem.class, fileId); // Get document representation
      this.fileName = item.getFileName();
      this.data = item.getData();
      this.contentType = item.getContentType();
   }
   //.. getters setters
}

That's all that is needed to serve documents in a RESTful way. To make the creation of the download link even easier, you can use the s:download tag. Here's how it works:

<s:download src=”/resources.xhtml”>
    <f:param name=”fileId” value=”#{someBean.downloadableFileId}”/>
</s:download>

The s:download tag is a variation on the Seam s:link tag. It will generate a bookmarkable link looking something like http://localhost/resources.seam?fileId=1. You can then use Seam URL rewriting to translate the link into http://localhost/resources/1. See examples in the examples/ui in the Seam distribution for further guidance!

4 comments:
 
07. Jan 2009, 19:38 CET | Link
John Ament

After implementing something like this in my 2.1.1.GA app, I can't say I'm a fan of the approach you're describing. Not to mention, it'll only work w/ JSF, not other technology stacks. If I understand what I did correctly (which sometimes happens), mine should work across all view technologies.

http://seamframework.org/Community/HowToCreateAViewThatDisplaysAFile

Adding the separate view and separate servlet makes it a bit too much work. The only problem I currently have is I can't define a link to an item w/ something like...

<s:link value="...">
   <f:param name="username" value="SomeUser"/>
   <f:param name="filename" value="somefilename"/>
</s:link>
 
29. Jan 2009, 04:33 CET | Link
Carey Foushee
I have 2.1.1GA but can't find the s:downnload tag in it anywhere. I thought maybe it was just my JBoss Tools TLD not being updating in my IDE but I even looked in the jboss-seam-ui.jar and didn't see anything class *download* anything. I assumed I would find it there because the FileUploadTag.class is there.

Here's my error:
<s:download> Tag Library supports namespace: http://jboss.com/products/seam/taglib, but no tag was defined for name: download

I get this when JBoss starts up so I assume I have everything I need configured correctly:
13:13:29,475 INFO [ServletContextListener] Welcome to Seam 2.1.1.GA
 
29. Jan 2009, 08:11 CET | Link
Carey Foushee

Never mind I didn't notice that you were talking about 2.1.2CR1 not 2.1.1CR1 so its not even released yet.

 
15. Apr 2010, 08:17 CET | Link
jboss so good!
Post Comment
Name:
E-mail address (optional):
Homepage URL (optional):
Subject:
Help
Let me type some plain text, not markup
Enable live preview
Enter characters (ignore circles):