In this section, we'll see how a Play! 2 server is able to render different resources in different ways rather than simply providing HTML pages.
The actions' body in Play! 2 not only have the responsibility of creating resources to be provided to the outside world, but also of declaring how this resource has to be rendered. Fortunately, there are a lot of boilerplates already written for our use in the default actions builder.
The so-called actions builder are the methods we have used almost blindly until now; that is to say, the static methods available in the play.mvc.Results.java
class such as ok
, redirect
, badRequest
, and unauthorized
.
Indeed, these methods have been overloaded several times in order to accept several representations. The following are some examples:
Content
: This takes content that is of the base type of classic string representations such as Html
, Xml
, and Txt
. This is also the result-type of a rendered template.String
: This will be rendered as is, as a plain text content (an overloaded version of the method accepts the encoding as a second argument).JsonNode
: This is trivial. If we create an instance of such a class, we'll have our resource serialized as application/json
.InputStream
: This is a convenient way to dump a stream into a response body (accepts chunks for an HTTP-chunked encoded connection).File
: This helps us avoid typing new FileInputStream(...)
in InputStream
. This accepts the file and will deal with the stream for us.Knowing all this, we'll now enhance our forum a bit to not only show the persisted attached images but also to provide a dynamic Atom feed for all chats that users have participated in.
To tackle this, we'll retrieve the empty Content
controller we saw at the beginning of this chapter. And we'll add two actions, routed as shown in the following screenshot:
The former action asks for a specific image content, whereas the latter one is asking for an Atom feed for certain users.
So, it's now time to render our images back to the client and show them in their respective chatrooms. The following screenshot shows how to do it:
So trivial... take the ID, get the related image in the database, ask for its underlying file, and return it in an OK (HTTP 200) response.
Thus, we're now able to use this action in our HTML templates using a simple img
tag that has its src
attribute pointing to our new action, shown as follows:
With the image rendering done, let's now move to the Atom feed.
This section is dedicated to the production of XML content.
In Java, we all know how painful it is to generate a DOM structure that has to be dumped as a string. Actually, Scala has a native syntax for XML, but it's still better (easier) to use templates for that.
Indeed, we used Scala templates for generating Html
responses (remember Html
derives from Content
), but we could also generate Xml
contents for the templates that are accordingly named. In other words, where myBeautifulContent.scala.html
creates an Html
response, myStructuredContent.scala.xml
generates Xml
content.
But first of all, we'll have to gather the data before applying them to an XML template. This is done in the code shown in the following screenshot:
Apart from database interactions to retrieve user and chat information, the points worth noting are the following:
ok
result builder that relies on a template to generate contenttext/xml
), but we override it by specifying the Atom one, application/atom+xml
, using the as
method on the ok
responseHaving prepared the data and the content type to be rendered, we can now look at the real representation: the template.
According to the action that uses the views.xml.content.atom.render
method, the template must be located in the content
package under the views
one and must be named atom.scala.xml
. And its content might be as shown in the following screenshot:
We were able to gracefully generate our Xml
content using XML directly, which avoided the headaches with DOM manipulations.
The only noticeable thing in the previous screenshot is the first line (all of the others are just data manipulations for displaying purposes), which is declaring the necessary parameters directly after we find the first XML line. That's because of the XML specification that requires this meta-information to be positioned at the very first character.
With this small amount of effort and code, we're already done and can now see the result in an appropriate Atom viewer, shown as follows:
This client enables us to add our feed to Google Reader for instance.