Page Action is a feature to directly invoke a Page method
from the browser. The Page Action method returns an
ActionResult
object that is rendered directly to the browser. In other words the Page template will
not be rendered.
To invoke a Page Action, specify the parameter "pageAction"
and the name of the page method, for example: "onRenderImage".
Let's take a quick look at how a Page Action can be leveraged to retrieve
an image. In this example we'll create an HTML <img>
element which src
attribute specifies the Page Action
that will return the image data.
First we create our template:
<img src="$context/mycorp/image.htm?pageAction
=onRenderImage"/>
Next we create our ImagePage with a Page Action method called onRenderImage that returns an ActionResult instance:
public class ImagePage extends Page { public ActionResult onRenderImage() { byte[] imageData = getImageAsBytes(); String contentType = ClickUtils.getMimeType("png"); return new ActionResult(imageData, contentType); } }
A Page Action is a normal Page method with the following signature: a public no-arg method returning an ActionResult instance:
// The Page Action method is public, doesn't accept any arguments and returns an ActionResult public ActionResult onRenderImage() { byte[] imageData = getImageAsBytes(); String contentType = ClickUtils.getMimeType("png"); return new ActionResult(imageData, contentType); }
The ActionResult contains the data that is rendered to
the client browser. In the example above, the result will the Image byte array
with a Content-Type of: "images/png"
.
Page Actions are page methods that handle the processing of a user request and render a result to the browser. The execution sequence for a Page Action being processed and rendered is illustrated in the figure below.
Stepping through this Page Action request sequence, a new Page instance is created and the attributes for the Page are set (format, headers). Next, request parameter values are bound to matching Page fields.
Then the onSecurityCheck()
handler is executed.
This method can be used to ensure the user is authorized to access the Page Action,
and if necessary abort any further processing. If
onSecurityCheck()
return false, no response is
sent back to the client. Note, if you want to send a specific response to
the client you have to do that from the
onSecurityCheck()
event, since other Page events
are not executed. Please see
this
example for some strategies on implementing
onSecurityCheck
to handle ajax requests.
Next the target page method
is invoked
which returns an ActionResult
that is rendered to
the client.
If the page method returns null
no response is
rendered to the browser.
An ActionResult represents the content returned by a Page Action which is then rendered to the client browser. ActionResults normally contains HTML or image data that is rendered to the browser. When a Page Action is invoked the Page template rendering is bypassed and only the ActionResult content is rendered to the browser. This allows a Page Action to return a "partial" response, as opposed to a "full" response, because the Page template (which can be viewed as a "full" response) is bypassed when invoking a Page Action.
Let's step through a Page Action example. First we create an ImagePage class with the method "getImageData" which is the Page Action we want to invoke:
public ImagePage extends Page { public ActionResult getImageData() { byte[] imageData = loadImageData(); String contentType = ClickUtils.getContentType("png"); return new ActionResult(imageData, contentType); } }
Next we have the page template image.htm:
<html>
<body>
<img src="/mycorp/image.htm?pageAction
=getImageData"/>
</body>
</html>
The browser renders the <img>
element and
requests the image src url. Click invokes the page method getImageData
and renders the result to the browser.
Looking at the output log we see the following trace:
[Click] [info ] handleRequest: /image.htm - 84 ms
[Click] [debug] GET http://localhost:8080/mycorp/image.htm
[Click] [trace] is Ajax request: false
[Click] [trace] request param: pageAction=getImageData
[Click] [trace] invoked: ImagePage.<<init>>
[Click] [trace] invoked: ImagePage.onSecurityCheck() : true
[Click] [trace] invoked: ImagePage.getImageData() : ActionResult
[Click] [info ] renderActionResult (image/png) - 0 ms
[Click] [trace] invoked: ImagePage.onDestroy()
[Click] [info ] handleRequest: /image.htm - 98 ms
Request parameters can be accessed through the Context
as shown below:
public ImagePage extends Page { public ActionResult getImageData() { // Retrieve a request parameter through the Context Context context = getContext(); String imageName = context.getRequestParameter("imageName"); byte[] imageData = loadImageData(imageName); String contentType = ClickUtils.getContentType("png"); return new ActionResult(imageData, contentType); } }
When handling a Page Action you might need to set the HTTP response
headers or status code. You do this through the Servlet API's,
HttpServetlResponse
which can be accessed
through the Context
.
For example:
package examples.page; import java.util.Date; import org.apache.click.Page; public ImagePage extends Page { public ActionResult getImageData() { // Headers and Status code are set on the HttpServletResponse HttpServletResponse response = getContext().getResponse(); // The headers can be set as follows: response.setHeader("Content-Disposition", "attachment; filename=\"report.xls\""); ... // The response status can be set as follows: response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); ... } }