| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" | |
| "http://www.w3.org/TR/html4/loose.dtd"> | |
| <!-- | |
| Licensed to the Apache Software Foundation (ASF) under one | |
| or more contributor license agreements. See the NOTICE file | |
| distributed with this work for additional information | |
| regarding copyright ownership. The ASF licenses this file | |
| to you under the Apache License, Version 2.0 (the | |
| "License"); you may not use this file except in compliance | |
| with the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, | |
| software distributed under the License is distributed on an | |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| KIND, either express or implied. See the License for the | |
| specific language governing permissions and limitations | |
| under the License. | |
| --> | |
| <html> | |
| <head> | |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/> | |
| <meta name="Author" content="Malcolm Edgar"/> | |
| <meta name="description" lang="en" content="Apache Click Java web application framework"/> | |
| <meta name="keywords" lang="en" content="Apache Click, Click Framework, Java, JEE, J2EE, web application framework, open source"/> | |
| <title>Apache Click</title> | |
| <link rel="stylesheet" type="text/css" href="../help.css"/> | |
| </head> | |
| <body> | |
| <h1>Pages</h1> | |
| Pages are the heart of web applications. In Click, Pages encapsulate the processing of | |
| HTML requests and the rendering of HTML responses. The section discusses Click pages | |
| and covers to following topics: | |
| <ol> | |
| <li><a href="#page-class">Classes</a> - page Java classes | |
| </li> | |
| <li><a href="#page-execution">Execution</a> - page execution sequence | |
| </li> | |
| <li><a href="#page-param-auto-binding">Request Param Auto Binding</a> - request parameter to page field auto binding | |
| </li> | |
| <li><a href="#page-security">Security</a> - page security model | |
| </li> | |
| <li><a href="#page-navigation">Navigation</a> - navigation between pages | |
| </li> | |
| <li><a href="#page-templating">Page Templating</a> - templating common page content | |
| </li> | |
| <li><a href="#page-direct-rendering">Direct Rendering</a> - page direct rendering | |
| </li> | |
| <li><a href="#page-stateful">Stateful</a> - stateful pages | |
| </li> | |
| <li><a href="#page-error-handling">Error Handling</a> - page error handling | |
| </li> | |
| <li><a href="#page-not-found">Page Not Found</a> - page not found handling | |
| </li> | |
| <li><a href="#page-messages">Message Properties</a> - pages message properties | |
| </li> | |
| </ol> | |
| <p> </p> | |
| In Click, a logical page is composed of a Java class and a Velocity template, with these | |
| components being defined in page elements of the | |
| <a target="topic" href="configuration.html#application-configuration">click.xml</a> file. | |
| <pre class="codeConfig"> | |
| <page path="<span class="blue">search.htm</span>" classname="<span class="red">com.mycorp.page.Search</span>"/> | |
| </pre> | |
| The path attribute specifies the location of the page Velocity template, and the classname | |
| attribute specifies the page Java class name. | |
| <p/> | |
| If you use an alternative template engine such as Freemarker, the setup above is the same. | |
| <p/> | |
| Alternatively you can also configure Click to use JSP pages for rendering. | |
| <pre class="codeConfig"> | |
| <page path="<span class="blue">search.jsp</span>" classname="<span class="red">com.mycorp.page.Search</span>"/> | |
| </pre> | |
| <a name="page-class" class="heading"></a><h2>1. Classes</h2> | |
| All custom Click pages must subclass the | |
| <a target="topic" href="click-api/org/apache/click/Page.html">Page</a> base class. | |
| The Page class and its associated companion classes, Context and Control, are depicted | |
| below in Figure 1. | |
| <p/> | |
| <img src="../images/click-class-diagram.png"/> | |
| <p class="diagram"> | |
| <b>Figure 1. Page Class Diagram</b> | |
| - <span class="sparx">created with Enterprise Architect courtesy <a target="blank" href="http://www.sparxsystems.com.au">Sparx Systems</a></span> | |
| </p> | |
| The Page class provides a <a href="click-api/org/apache/click/Page.html#model">model</a> | |
| attribute which is used to hold all the objects that are rendered in the page's | |
| Velocity template. The model may also contain | |
| <a target="topic" href="click-api/org/apache/click/Control.html">Control</a> objects, which | |
| provide user interface controls on the Page. | |
| <p/> | |
| Pages also have an associated | |
| <a target="topic" href="click-api/org/apache/click/Context.html">Context</a> object | |
| which references all the javax.servlet objects associated with the request. When | |
| programming in Click you use the Context object to access HttpServletRequest attributes, | |
| parameters and the HttpSession object. | |
| <p/> | |
| <a name="page-execution" class="heading"></a><h2>2. Execution</h2> | |
| The Page class provide a number of empty handler methods which subclasses can override to | |
| provide functionality: | |
| <ul> | |
| <li><a href="click-api/org/apache/click/Page.html#onSecurityCheck()">onSecurityCheck()</a></li> | |
| <li><a href="click-api/org/apache/click/Page.html#onInit()">onInit()</a></li> | |
| <li><a href="click-api/org/apache/click/Page.html#onGet()">onGet()</a></li> | |
| <li><a href="click-api/org/apache/click/Page.html#onPost()">onPost()</a></li> | |
| <li><a href="click-api/org/apache/click/Page.html#onRender()">onRender()</a></li> | |
| <li><a href="click-api/org/apache/click/Page.html#onDestroy()">onDestroy()</a></li> | |
| </ul> | |
| The ClickServlet relies on instantiating Pages using a public no arguments constructor, | |
| so when you create Page subclasses you must ensure you don't add an incompatible | |
| constructor. | |
| The GET request execution sequence for Pages is summarized below in the Figure 2. | |
| <p/> | |
| <img src="../images/get-sequence-diagram.png"/> | |
| <p class="diagram"> | |
| <b>Figure 2. GET Request Sequence Diagram</b> | |
| - <span class="sparx">created with Enterprise Architect courtesy <a target="blank" href="http://www.sparxsystems.com.au">Sparx Systems</a></span> | |
| </p> | |
| Stepping through this GET request sequence, a new Page instance is created and the | |
| attributes for the Page are set (context, format, headers, path). Next, request | |
| parameter values are bound to any matching public Page fields. | |
| <p/> | |
| Then the <tt>onSecurityCheck()</tt> handler is executed. This method can be used to | |
| ensure the user is authorized to access the page, and if necessary abort any | |
| further processing. | |
| <p/> | |
| The next method invoked is <tt>onInit()</tt>, this is where you place any | |
| post constructor initialization code. <tt>onInit()</tt> is the ideal place to | |
| create controls such as Forms, Fields and Tables. As illustrated by the diagram, | |
| after a Page's <tt>onInit()</tt> is called, each Control, available at that stage, | |
| will have their <tt>onInit()</tt> method called. | |
| <p/> | |
| The next step is the processing of the Page's <a href="click-api/org/apache/click/Page.html#controls">controls</a>. | |
| The ClickSerlvet gets the list of | |
| Controls from the page and then iterates through the list calling <tt>onProcess()</tt>. | |
| If any of the Control's <tt>onProcess()</tt> methods return false, processing of | |
| subsequent controls and the Page's <tt>onGet()</tt> method is aborted. | |
| <p/> | |
| If everything is executing normally the Page's <tt>onGet()</tt> method is now called. | |
| <p/> | |
| The next step is rendering the page template to generate the displayed HTML. The | |
| ClickServlet gets the model (<tt>Map</tt>) from the Page then adds the following | |
| objects to the model: | |
| <ul> | |
| <li> | |
| any public Page fields using the fields name | |
| </li> | |
| <li>context - | |
| the Servlet context path, e.g. <span class="">/mycorp</span> | |
| </li> | |
| <li>cssImports - | |
| the CSS imports and style blocks to include in the pages header. | |
| Please see <a href="../click-api/org/apache/click/util/PageImports.html">PageImports</a> | |
| for more details. | |
| </li> | |
| <li>format - | |
| the <a href="../click-api/org/apache/click/util/Format.html">Format</a> | |
| object for formatting the display of objects. | |
| </li> | |
| <li>imports - | |
| the CSS and JavaScript imports to include in the pages header. | |
| Please see <a href="../click-api/org/apache/click/util/PageImports.html">PageImports</a> | |
| for more details. | |
| </li> | |
| <li>jsImports - | |
| the JavaScript imports and script blocks to include in the pages footer. | |
| Please see <a href="../click-api/org/apache/click/util/PageImports.html">PageImports</a> | |
| for more details. | |
| </li> | |
| <li>messages - | |
| the <a target="topic" href="click-api/org/apache/click/util/MessagesMap.html">MessagesMap</a> adaptor | |
| for the Page <a href="click-api/org/apache/click/Page.html#getMessage(java.lang.String)">getMessage()</a> | |
| method | |
| </li> | |
| <li>path - the <a href="click-api/org/apache/click/Page.html#path">path</a> | |
| of the page template to render | |
| </li> | |
| <li>request - | |
| the pages <a class="external" target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/http/HttpServletRequest.html">HttpServletRequest</a> | |
| object | |
| </li> | |
| <li>response - | |
| the pages <a class="external" target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/http/HttpServletResponse.html">HttpServletResponse</a> | |
| object | |
| </li> | |
| <li>session - | |
| the <a href="click-api/org/apache/click/util/SessionMap.html">SessionMap</a> adaptor | |
| for the users <a class="external" target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/http/HttpSession.html">HttpSession</a> | |
| </li> | |
| </ul> | |
| It then merges the template with the page model and writes out results to the HttpServletResponse. | |
| When the model is being merged with the template, any Controls in the model may be | |
| rendered using their <tt>toString()</tt> method. | |
| <p/> | |
| The final step in this sequence is invoking each control's <tt>onDestroy()</tt> method | |
| and lastly invoke the Page's <tt>onDestroy()</tt> method. This | |
| method can be used to clean up resource associated with the Control or Page before | |
| it is garbage collected. The <tt>onDestroy()</tt> method is guaranteed to be called | |
| even if an exception occurs in the previous steps. | |
| <p/> | |
| The execution sequence for POST requests is almost identical, except the <tt>onPost()</tt> | |
| method is invoked instead on <tt>onGet()</tt>. See the | |
| <a href="../images/post-sequence-diagram.png">POST Request Sequence Diagram</a>. | |
| <p/> | |
| Another view on the execution flow of Pages is illustrated in the Activity diagram below. | |
| <p/> | |
| <a name="activity-diagram" class="heading"><img src="../images/activity-diagram-small.png" style="margin-left:4em;"/></a> | |
| <p class="diagram"> | |
| <b>Figure 3. Page Execution Activity Diagram</b> | |
| - <span class="sparx">created with Enterprise Architect courtesy <a target="blank" href="http://www.sparxsystems.com.au">Sparx Systems</a></span> | |
| </p> | |
| <a name="page-param-auto-binding" class="heading"></a><h2>3. Request Param Auto Binding</h2> | |
| Click will automatically bind any request parameter values to public Page fields | |
| with the same name. When binding these values it will also attempt to convert them | |
| to the correct type. | |
| <p/> | |
| The best way to understand this is to walk through an example. Our application | |
| recieves a GET request: | |
| <pre class="codeConfig"> | |
| http://localhost:8080/mycorp/customer-details.htm?<span class="blue">customerId</span>=<span class="red">7203</span> | |
| </pre> | |
| This request is automatically handled by our <tt>CustomerDetails</tt> page: | |
| <pre class="codeJava"> | |
| <span class="kw">package</span> com.mycorp.page; | |
| <span class="kw">public class</span> CustomerDetails <span class="kw">extends</span> Page { | |
| <span class="kw">public</span> Integer <span class="blue">customerId</span>; | |
| } </pre> | |
| After the CustomerDetails page has been created the "customerId" request parameter | |
| value "7023" will be converted into an Integer and assigned to the public page field | |
| <tt>customerId</tt>. | |
| <p/> | |
| Another feature of Click is that any public Page fields are automatically | |
| added to the page's model before it is rendered. This will make these values available in | |
| the page template for display. In our example the public <tt>customerId</tt> field | |
| will be added to the Page model and will be available for rendering in the | |
| page template: | |
| <p/> | |
| Our customer-details.htm page template contains: | |
| <pre class="codeHtml"> | |
| <html> | |
| <body> | |
| Customer ID: <span class="red">$</span><span class="blue">customerId</span> | |
| </body> | |
| </html> </pre> | |
| After processing the request our page would be rendered as: | |
| <table class="htmlExample" cellspacing="12" width="100%"> | |
| <tr> | |
| <td>Customer ID: 7203</td> | |
| </tr> | |
| </table> | |
| <h3>3.1 Customizing Auto Binding</h3> | |
| Auto binding supports the conversion of request string parameters into the Java | |
| classes: Integer, Double, Boolean, Byte, Character, Short, Long, Float, BigInteger, | |
| BigDecimal, String and the various Date classes. | |
| <p/> | |
| By default type conversion is performed by the | |
| <a target="topic" href="click-api/org/apache/click/util/RequestTypeConverter.html">RequestTypeConverter</a> class | |
| which is used by the ClickServlet method | |
| <a target="topic" href="click-api/org/apache/click/ClickServlet.html#getTypeConverter()">getTypeConverter()</a>. | |
| <p/> | |
| If you need to add support for additional types, you would write your own type | |
| converter class and subclass the ClickSerlvet to use your custom converter. | |
| <p/> | |
| For example if we wanted to automatically load a <tt>Customer</tt> object from the database | |
| when a customer id request parameter is specified, you could write your own type converter: | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> CustomTypeConverter <span class="kw">extends</span> RequestTypeConverter { | |
| <span class="kw">private</span> CustomerService customerService = <span class="kw">new</span> CustomerService(); | |
| <span class="cm">/** | |
| * @see RequestTypeConverter#convertValue(Object, Class) | |
| */</span> | |
| <span class="kw">protected</span> Object convertValue(Object value, Class toType) { | |
| <span class="kw">if</span> (toType == Customer.<span class="kw">class</span>) { | |
| <span class="kw">return</span> customerService.getCustomerForId(value); | |
| } <span class="kw">else</span> { | |
| <span class="kw">return super</span>.convertValue(value, toType); | |
| } | |
| } | |
| } </pre> | |
| This type converter would handle the following request: | |
| <pre class="codeConfig"> | |
| http://localhost:8080/mycorp/customer-details.htm?<span class="blue">customer</span>=<span class="red">7203</span> | |
| </pre> | |
| This request will load the customer object from the database using "7203" as the customer id value. | |
| The ClickServlet would then assign this customer object to the matching page field: | |
| <pre class="codeJava"> | |
| <span class="kw">package</span> com.mycorp.page; | |
| <span class="kw">public class</span> CustomerDetails <span class="kw">extends</span> Page { | |
| <span class="kw">public</span> Customer <span class="blue">customer</span>; | |
| } </pre> | |
| To make your custom type converter available you will need to subclass ClickServlet and override the | |
| <tt>getTypeConverter()</tt> method. For example: | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> CustomClickServlet <span class="kw">extends</span> ClickServlet { | |
| <span class="cm">/** | |
| * @see ClickServlet#getTypeConverter() | |
| */</span> | |
| <span class="kw">protected</span> TypeConverter getTypeConverter() { | |
| <span class="kw">if</span> (typeConverter == <span class="kw">null</span>) { | |
| typeConverter = <span class="kw">new</span> CustomTypeConverter(); | |
| } | |
| <span class="kw">return</span> typeConverter; | |
| } | |
| } </pre> | |
| <a name="page-security" class="heading"></a><h2>4. Security</h2> | |
| Pages provide an | |
| <a target="topic" href="click-api/org/apache/click/Page.html#onSecurityCheck()">onSecurityCheck</a> | |
| event handler which application pages can override to implement a programmatic security | |
| model. | |
| <p/> | |
| Please note you generally don't need to use this capability, and where possible | |
| you should use the declarative JEE security model. See the Best Practices | |
| <a href="best-practices.html#security">Security</a> topic for more details. | |
| <h3>4.1 Application Authentication</h3> | |
| Applications can use the <tt>onSecurityCheck()</tt> method to implement their own security model. The example | |
| class below provides a base Secure page class which other pages can extend | |
| to ensure the user is logged in. In this example the login page creates a session | |
| when a user successfully authenticates. This Secure page then checks to make sure | |
| the user has a session, otherwise the request is redirected to the login page. | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> Secure <span class="kw">extends</span> Page { | |
| <span class="jd">/** | |
| * @see Page#onSecurityCheck() | |
| */</span> | |
| <span class="kw">public boolean</span> onSecurityCheck() { | |
| <span class="kw">if</span> (getContext().hasSession()) { | |
| <span class="kw">return true</span>; | |
| } <span class="kw">else</span> { | |
| setRedirect(LoginPage.<span class="kw">class</span>); | |
| <span class="kw">return false</span>; | |
| } | |
| } | |
| } | |
| </pre> | |
| <h3>4.2 Container Authentication</h3> | |
| Alternatively you can also use the security services provided by the JEE Servlet | |
| Container. For instance to ensure users have been authenticated by the Serlvet Container | |
| you could use a Secure page of: | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> Secure <span class="kw">extends</span> Page { | |
| <span class="jd">/** | |
| * @see Page#onSecurityCheck() | |
| */</span> | |
| <span class="kw">public boolean</span> onSecurityCheck() { | |
| <span class="kw">if</span> (getContext().getRequest().<a target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/http/HttpServletRequest.html#getRemoteUser()">getRemoteUser</a>() != <span class="kw">null</span>) { | |
| <span class="kw">return true</span>; | |
| } <span class="kw">else</span> { | |
| setRedirect(LoginPage.<span class="kw">class</span>); | |
| <span class="kw">return false</span>; | |
| } | |
| } | |
| } | |
| </pre> | |
| <h3>4.3 Container Access Control</h3> | |
| The Servlet Container also provides facilities to enforce role based access control | |
| (authorization). The example below is a base page to ensure only users | |
| in the "admin" role can access the page, otherwise users are redirected to the login page. | |
| Application Admin pages would extend this secure page to provide their functionality. | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> AdminPage <span class="kw">extends</span> Page { | |
| <span class="jd">/** | |
| * @see Page#onSecurityCheck() | |
| */</span> | |
| <span class="kw">public boolean</span> onSecurityCheck() { | |
| <span class="kw">if</span> (getContext().getRequest().<a target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/http/HttpServletRequest.html#isUserInRole(java.lang.String)">isUserInRole</a>(<span class="st">"admin"</span>)) { | |
| <span class="kw">return true</span>; | |
| } <span class="kw">else</span> { | |
| setRedirect(LoginPage.<span class="kw">class</span>); | |
| <span class="kw">return false</span>; | |
| } | |
| } | |
| } | |
| </pre> | |
| <h3>4.4 Logging Out</h3> | |
| To logout using the application or container based security models you would simply | |
| invalidate the session. | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> Logout <span class="kw">extends</span> Page { | |
| <span class="jd">/** | |
| * @see Page#onInit() | |
| */</span> | |
| <span class="kw">public void</span> onInit() { | |
| getContext().getSession().<a target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/http/HttpSession.html#invalidate()">invalidate</a>(); | |
| } | |
| } | |
| </pre> | |
| <a name="page-navigation" class="heading"></a><h2>5. Navigation</h2> | |
| Navigation between pages is achieved by using forwards, redirects and by setting the | |
| page template path. | |
| <a name="page-foward" class="heading"></a><h3>5.1 Forward</h3> | |
| To forward to another page using the servlet | |
| <a class="external" target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/RequestDispatcher.html">RequestDispatcher</a>, | |
| set the Page's forward property. For example to forward to a page with a path | |
| <span class="html">index.htm</span>: | |
| <pre class="codeJava"> | |
| <span class="jd">/** | |
| * @see Page#onPost() | |
| */</span> | |
| <span class="kw">public void</span> onPost() { | |
| <span class="cm">// Process form post</span> | |
| .. | |
| setForward(<span class="st">"index.htm"</span>); | |
| } | |
| </pre> | |
| This will invoke a new Page class instance mapped to the path | |
| <span class="html">index.htm</span>. | |
| <p/> | |
| <b>Please note</b> when a request is forwarded to another Page, | |
| the controls on the second page will not be processed. This prevents confusion and bugs, | |
| like a form on the second page trying to process a POST request from the first page. | |
| <h4>5.1.1 Forward Parameter Passing</h4> | |
| When you forward to another page the request parameters are maintained. This is a handy way | |
| of passing through state information with the request. For example you could | |
| add a customer object as a request parameter which is displayed in the template of the | |
| forwarded page. | |
| <pre class="codeJava"> | |
| <span class="kw">public boolean</span> onViewClick() { | |
| Long id = viewLink.getValueLong(); | |
| Customer customer = CustomerDAO.findByPK(id); | |
| <span class="cm">// Set the customer object as a request parameter</span> | |
| getContext().setRequestAttribute(<span class="st">"customer"</span>, customer); | |
| setForward(<span class="st">"view-customer.htm"</span>); | |
| <span class="kw">return false</span>; | |
| } | |
| </pre> | |
| The snippet above forwards to the page template <span class="html">view-customer.htm</span>: | |
| <pre class="codeHtml"> | |
| <html> | |
| <head> | |
| <title>Customer Details</title> | |
| </head> | |
| <body> | |
| <h1>Customer Details</h1> | |
| <pre> | |
| Full Name: <span class="st">$customer.fullName</span> | |
| Email: <span class="st">$customer.email</span> | |
| Telephone: <span class="st">$customer.telephone</span> | |
| </pre> | |
| </body> | |
| </html> | |
| </pre> | |
| Request attributes are automatically added to the Velocity Context object so are | |
| available in the page template. | |
| <a name="page-forwarding" class="heading"></a><h4>5.1.2 Page Forwarding</h4> | |
| Page forwarding is another way of passing information between pages. In this case | |
| you create the page to be forwarded to using the Context | |
| <a href="click-api/org/apache/click/Context.html#createPage(java.lang.String)">createPage()</a> | |
| method and then set properties directly on the Page. | |
| Finally set this page as the page to forward the request to. For example: | |
| <pre class="codeJava"> | |
| <span class="kw">public boolean</span> onEditClick() { | |
| Long id = viewLink.getValueLong(); | |
| Customer customer = CustomerDAO.findByPK(id); | |
| <span class="cm">// Create a new EditPage instance based on the specified path</span> | |
| EditPage editPage = (EditPage) getContext().createPage(<span class="st">"/edit-customer.htm"</span>); | |
| editPage.setCustomer(customer); | |
| setForward(editPage); | |
| <span class="kw">return false</span>; | |
| } | |
| </pre> | |
| When creating a page with the <tt>createPage()</tt> method ensure you prefix | |
| the page path with the <tt class="st">"/"</tt> character. | |
| <p/> | |
| You can also specify the target page using its class as long as the Page has | |
| a unique path. (Although uncommon it is possible to map more than one path to the | |
| same class. In these cases invoking <span class="st">Context.createPage</span> will | |
| throw an exception, because Click will not be able to determine which path to use). | |
| <p/> | |
| Using this technique the above code becomes: | |
| <pre class="codeJava"> | |
| <span class="kw">public boolean</span> onEditClick() { | |
| Long id = viewLink.getValueLong(); | |
| Customer customer = CustomerDAO.findByPK(id); | |
| <span class="cm">// Create a new EditPage instance based on its class</span> | |
| EditPage editPage = (EditPage) getContext().createPage(EditPage.<span class="kw">class</span>); | |
| editPage.setCustomer(customer); | |
| setForward(editPage); | |
| <span class="kw">return false</span>; | |
| } | |
| </pre> | |
| This Page forwarding technique is best practice as it provides you with compile time safety and | |
| alleviates you from having to specify page paths in your code. | |
| <p/> | |
| Please always use the Context <tt>createPage()</tt> methods to allow Click to | |
| inject Page dependencies. | |
| <a name="page-template-path" class="heading"></a><h3>5.2 Template Path</h3> | |
| An alternative method of forwarding to a new page is to simply set the current Page's path | |
| to the new page template to render. With this approach the page template being rendered | |
| must have everything it needs without having its associated Page object created. Our modified | |
| example would be: | |
| <pre class="codeJava"> | |
| <span class="kw">public boolean</span> onViewClick() { | |
| Long id = viewLink.getValueLong(); | |
| Customer customer = CustomerDAO.findByPK(id); | |
| addModel(<span class="st">"customer"</span>, customer); | |
| <span class="cm">// Set the Page's path to a new value</span> | |
| setPath(<span class="st">"view-customer.htm"</span>); | |
| <span class="kw">return false</span>; | |
| } | |
| </pre> | |
| Note how the <font color="red">customer</font> object is passed through to the template in the Page model. This | |
| approach of using the Page model is not available when you forward to another Page, as | |
| the first Page object is | |
| "<a target="topic" href="click-api/org/apache/click/Page.html#onDestroy()">destroyed</a>" | |
| before the second Page object is created and any model values would be lost. | |
| <a name="page-redirect" class="heading"></a><h3>5.3 Redirect</h3> | |
| Redirects are another very useful way to navigate between pages. See | |
| HttpServletResponse.<a target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/http/HttpServletResponse.html#sendRedirect(java.lang.String)">sendRedirect</a>(location) | |
| for details. | |
| <p/> | |
| The great thing about redirects are that they provide a clean URL in the users browser | |
| which matches the page that they are viewing. This is important for when users want to | |
| bookmark a page. The downside of redirects are that they involve a communications round | |
| trip with the users browser which requests the new page. Not only does this take time, | |
| it also means that all the page and request information is lost. | |
| <p/> | |
| An example of a redirect to a <span class="html">logout.htm</span> | |
| page is provided below: | |
| <pre class="codeJava"> | |
| <span class="kw">public boolean</span> onLogoutClick() { | |
| setRedirect(<span class="st">"/logout.htm"</span>); | |
| <span class="kw">return false</span>; | |
| } | |
| </pre> | |
| If the redirect location begins with a <span class="wr">"/"</span> | |
| character the redirect location will be prefixed with the web applications | |
| context path. | |
| <p/> | |
| For example if an application is deployed to the context | |
| <span class="wr">"mycorp"</span> calling | |
| <tt>setRedirect(<span class="navy">"/customer/details.htm"</span>)</tt> | |
| will redirect the request to: | |
| <span class="wr">"/mycorp/customer/details.htm"</span> | |
| <p/> | |
| You can also obtain the redirect path via the target Page's class. For example: | |
| <pre class="codeJava"> | |
| <span class="kw">public boolean</span> onLogoutClick() { | |
| String path = getContext().getPagePath(Logout.<span class="kw">class</span>); | |
| setRedirect(path); | |
| <span class="kw">return false</span>; | |
| } | |
| </pre> | |
| Note when using this redirect method, the target Page class must have a unique path. | |
| <p/> | |
| A short hand way of redirecting is to simply specify the target Page class in | |
| the redirect method. For example: | |
| <pre class="codeJava"> | |
| <span class="kw">public boolean</span> onLogoutClick() { | |
| setRedirect(Logout.<span class="kw">class</span>); | |
| <span class="kw">return false</span>; | |
| } | |
| </pre> | |
| <h4>5.3.1 Redirect Parameter Passing</h4> | |
| You can pass information between redirected pages using URL request parameters. | |
| The ClickServlet will encode the URL for you using | |
| HttpServletResponse.<a target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/http/HttpServletResponse.html#encodeRedirectURL(java.lang.String)">encodeRedirectURL</a>(url). | |
| <p/> | |
| In the example below a user will click on an OK button to confirm a payment. The | |
| <tt>onOkClick()</tt> button handler processes the payment, gets the payment transaction id, and then | |
| redirects to the <span class="html">trans-complete.htm</span> page with the | |
| transaction id encoded in the URL. | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> Payment <span class="kw">extends</span> Page { | |
| .. | |
| <span class="kw">public boolean</span> onOkClick() { | |
| <span class="kw">if</span> (form.isValid()) { | |
| <span class="cm">// Process payment</span> | |
| .. | |
| <span class="cm">// Get transaction id</span> | |
| Long transId = OrderDAO.purchase(order); | |
| setRedirect(<span class="st">"trans-complete.htm?transId="</span> + transId); | |
| <span class="kw">return false</span>; | |
| } | |
| <span class="kw">return true</span>; | |
| } | |
| } | |
| </pre> | |
| The Page class for the <span clas="html">trans-complete.htm</span> page can | |
| then get the transaction id through the request parameter | |
| <tt>"<span color="red">transId</span>"</tt>: | |
| <pre class="codeJava"> | |
| <span class="kw">public class</span> TransComplete <span class="kw">extends</span> Page { | |
| <span class="jd">/** | |
| * @see Page#onInit() | |
| */</span> | |
| <span class="kw">public void</span> onInit() { | |
| String transId = getContext().getRequest().getParameter(<span class="st">"transId"</span>); | |
| <span class="kw">if</span> (transId != <span class="kw">null</span>) { | |
| <span class="cm">// Get order details</span> | |
| Order order = OrderDAO.findOrderByPK(<span class="kw">new</span> Long(transId)); | |
| <span class="kw">if</span> (order != <span class="kw">null</span>) { | |
| addModel(<span class="st">"order"</span>, order); | |
| } | |
| } | |
| } | |
| } | |
| </pre> | |
| <h4>5.3.2 Post Redirect</h4> | |
| The parameter passing example above is also an example of a Post Redirect. The Post | |
| Redirect technique is a very useful method of preventing users from submitting a form | |
| twice by hitting the refresh button. | |
| <a name="page-templating" class="heading"></a><h2>6. Page Templating</h2> | |
| Click supports page templating (a.k.a. <i>Tiles</i> in Struts) enabling you to | |
| create a standardized look and feel for your web application and greatly reducing | |
| the amount of HTML you need to maintain. | |
| <p/> | |
| To implement templating define a border template base Page | |
| which content Pages should extend. The template base Page class overrides the | |
| Page <a href="click-api/org/apache/click/Page.html#getTemplate()">getTemplate()</a> | |
| method, returning the path of the border template to render. For example: | |
| <pre class="codeJava"><span class="kw">public class</span> BorderedPage <span class="kw">extends</span> Page { | |
| <span class="jd">/** | |
| * @see Page#getTemplate() | |
| */</span> | |
| <span class="kw">public</span> String getTemplate() { | |
| <span class="kw">return</span> <span class="st">"/border.htm"</span>; | |
| } | |
| } </pre> | |
| <p/> | |
| The BorderedPage template <span class="blue">border.htm</span>: | |
| <pre class="codeHtml"> | |
| <html> | |
| <head> | |
| <title><span class="blue">$title</span></title> | |
| <link rel="stylesheet" type="text/css" href="style.css" title="Style"/> | |
| </head> | |
| <body> | |
| <h2 class="title"><span class="blue">$title</span></h2> | |
| <span class="red">#parse</span>(<span class="blue">$path</span>) | |
| </body> | |
| </html> </pre> | |
| Other pages insert their content into this template using the Velocity | |
| <a href="velocity/vtl-reference-guide.html#parse">#parse</a> directive, | |
| passing it their contents pages <a href="click-api/org/apache/click/Page.html#path">path</a>. | |
| The <span class="blue">$path</span> value is automatically added to | |
| the VelocityContext by the ClickServlet. | |
| <p/> | |
| An example bordered Home page is provided below: | |
| <pre class="codeConfig"> | |
| <page path="<span class="blue">home.htm</span>" classname="Home"/> | |
| </pre> | |
| <pre class="codeJava"><span class="kw">public class</span> Home <span class="kw">extends</span> BorderedPage { | |
| <span class="kw">public</span> String title = <span class="st">"Home"</span>; | |
| } </pre> | |
| The Home page's content <span class="blue">home.htm</span>: | |
| <pre class="codeHtml"> | |
| <b>Welcome</b> to Home page your starting point for the application. | |
| </pre> | |
| When a request is made for the Home page (home.htm) Velocity will | |
| merge the <span class="blue">border.htm</span> page and | |
| <span class="blue">home.htm</span> page together returning: | |
| <pre class="codeHtml"> | |
| <html> | |
| <head> | |
| <title>Home</title> | |
| <link rel="stylesheet" type="text/css" href="style.css" title="Style"/> | |
| </head> | |
| <body> | |
| <h2 class="title">Home</h2> | |
| <b>Welcome</b> to Home page your application starting point. | |
| </body> | |
| </html> </pre> | |
| Which may be rendered as: | |
| <table class="htmlExample" cellspacing="12"> | |
| <tr> | |
| <td> | |
| <h2 style="color: white; background-color: navy; padding: 0.25em; margin-top: 0em;"> | |
| Home | |
| </h2> | |
| <p> | |
| <b>Welcome</b> to Home page your application starting point. | |
| <p/> | |
| </td> | |
| </tr> | |
| </table> | |
| Note how the Home page class defines a <span class="blue">title</span> model value | |
| which is referenced in the <span class="blue">border.htm</span> template as <span class="blue">$title</span>. | |
| Each bordered page can define their own title which is rendered in this template. | |
| <p/> | |
| Templating with JSP pages is also supported using the same pattern. Please | |
| see the Click Examples application for a demonstration. | |
| <a name="page-direct-rendering" class="heading"></a><h2>7. Direct Rendering</h2> | |
| Pages support a direct rendering mode where you can render directly to the | |
| servlet response and bypass the page template rendering. This is useful for | |
| scenarios where you want to render non HTML content to the response, such as a | |
| PDF or Excel document. To do this: | |
| <ul> | |
| <li>get the servlet response object</li> | |
| <li>set the content type on the response</li> | |
| <li>get the response output stream</li> | |
| <li>write to the output stream</li> | |
| <li>close the output stream</li> | |
| <li>set the page path to null to inform the ClickServlet that rendering has been completed</li> | |
| </ul> | |
| A direct rendering example is provided below. | |
| <pre class="codeJava"> | |
| <span class="cm">/** | |
| * Render the Java source file as "text/plain". | |
| * | |
| * @see Page#onGet() | |
| */</span> | |
| <span class="kw">public void</span> onGet() { | |
| String filename = .. | |
| HttpServletResponse response = getContext().getResponse(); | |
| response.setContentType(<span class="st">"text/plain"</span>); | |
| response.setHeader(<span class="st">"Pragma"</span>, <span class="st">"no-cache"</span>); | |
| ServletContext context = getContext().getServletContext(); | |
| InputStream inputStream = <span class="kw">null</span>; | |
| <span class="kw">try</span> { | |
| inputStream = context.getResourceAsStream(filename); | |
| PrintWriter writer = response.getWriter(); | |
| BufferedReader reader = | |
| <span class="kw">new</span> BufferedReader(new InputStreamReader(inputStream)); | |
| String line = reader.readLine(); | |
| <span class="kw">while</span> (line != <span class="kw">null</span>) { | |
| writer.println(line); | |
| line = reader.readLine(); | |
| } | |
| setPath(<span class="kw">null</span>); | |
| } <span class="kw">catch</span> (IOException ioe) { | |
| ioe.printStackTrace(); | |
| } <span class="kw">finally</span> { | |
| ClickUtils.close(inputStream); | |
| } | |
| } </pre> | |
| <a name="page-stateful" class="heading"></a><h2>8. Stateful Pages</h2> | |
| Click supports stateful pages where the state of the page is saved between the | |
| users requests. Stateful pages are useful in a number of scenarios including: | |
| <ul> | |
| <li>Search page and edit page interactions. In this scenario you navigage from a | |
| stateful search page which may have filter criteria applied to an object edit page. | |
| Once object update has been completed on the edit page, the user is redirected to | |
| the search page and the stateful filter criteria still applies. | |
| </li> | |
| <li>Complex pages with multiple forms and or tables which need to maintain their | |
| state between interactions. | |
| </li> | |
| </ul> | |
| To make a page stateful you simply need to set the page | |
| <a target="topic" href="click-api/org/apache/click/Page.html#stateful">stateful</a> | |
| property to true, have the page implement the <tt>Serializable</tt> interface | |
| and set the <tt>serialVersionUID</tt> indicator. For example: | |
| <pre class="codeJava"> | |
| <span class="kw">package</span> com.mycorp.page; | |
| <span class="kw">import</span> java.io.Serializable; | |
| <span class="kw">import</span> org.apache.click.Page; | |
| <span class="kw">public class</span> SearchPage <span class="kw">extends</span> Page <span class="kw">implements</span> Serializable { | |
| <span class="kw">private static final long</span> serialVersionUID = 1L; | |
| <span class="kw">public</span> SearchPage() { | |
| setStateful(<span class="kw">true</span>); | |
| .. | |
| } | |
| } | |
| </pre> | |
| Stateful page instances are stored in the user's | |
| <a class="external" target="_blank" href="http://java.sun.com/products/servlet/2.3/javadoc/javax/servlet/http/HttpSession.html">HttpSession</a> | |
| using the pages class name as the key. In the example above the page would be stored in | |
| the users session using the class name: <tt>com.mycorp.page.SearchPage</tt> | |
| <h3>8.1 Page Creation</h3> | |
| With stateful pages they are only created once, after which they are retrieved from the session. | |
| However page event handlers are invoked for each request, including the <tt>onInit()</tt> method. | |
| <p/> | |
| When you are creating stateful pages you typically place all your control creation code in the Pages | |
| constructor so it is invoked only once. It is important not to place control creation code in the | |
| <tt>onInit()</tt> method which will be invoked with each request. | |
| <p/> | |
| If you have dynamic control creation code you would typically place this in the <tt>onInit()</tt> method, | |
| but you will need to take care that controls and or models are not already present in the page. | |
| <h3>8.2 Page Execution</h3> | |
| The default Click page execution model is thread safe as a new Page instance is created | |
| for each request and thread. With stateful pages a user will have a single page instance which is | |
| reused in multiple requests and threads. To ensure page execution is thread safe, users | |
| page instances are synchronized so only one request thread can execute a page instance at | |
| any one time. | |
| <h3>8.3 Page Destruction</h3> | |
| After normal page instances have been executed, they are de-referenced and garbage | |
| collected by the JVM. However with stateful pages they are stored in the users | |
| <tt>HttpSession</tt> so care needs to be take not to store too many objects in stateful | |
| page instances which may cause memory and performance issues. | |
| <p/> | |
| When pages have completed their execution, all the Page's controls <tt>onDestroy()</tt> | |
| methods are invoked, and then the Page's <tt>onDestroy()</tt> method is invoked. This | |
| is your opportunity to de-reference any large sets or graphs. For example the Table | |
| control by default de-references its rowList in its | |
| <a target="topic" href="click-api/org/apache/click/control/Table.html#onDestroy()">onDestory()</a> | |
| method. | |
| <a name="page-error-handling" class="heading"></a><h2>9. Error Handling</h2> | |
| If an Exception occurs processing a Page object or rendering a template the error | |
| is delegated to the registered handler. The default Click error handler is the | |
| <a target="topic" href="click-api/org/apache/click/util/ErrorPage.html">ErrorPage</a>, | |
| which is automatically configured as: | |
| <pre class="codeConfig"> | |
| <page path="<span class="blue">click/error.htm</span>" classname="<span class="red">org.apache.click.util.ErrorPage</span>"/> | |
| </pre> | |
| To register an alternative error handler you must subclass ErrorPage and define | |
| your page using the path "<span class="html">click/error.htm</span>". For example: | |
| <pre class="codeConfig"> | |
| <page path="<span class="blue">click/error.htm</span>" classname="<span class="red">com.mycorp.page.ErrorPage</span>"/> | |
| </pre> | |
| When the ClickSevlet starts up it checks to see whether the <span class="html">error.htm</span> template exists in the | |
| <span class="html">click</span> web sub directory. If it cannot find the page the ClickServlet will automatically deploy one. | |
| You can tailor the <span class="html">click/error.htm</span> template to suite you own tastes, and the ClickServlet | |
| will not overwrite it. | |
| <p/> | |
| The default error template will display extensive debug information when the application is in <tt>development</tt> | |
| or <tt>debug</tt> mode. Example error page displays include: | |
| <ul> | |
| <li><a href="error-npe.html">NullPointerException</a> - in a page method</li> | |
| <li><a href="error-parsing.html">ParseErrorException</a> - in a page template </li> | |
| </ul> | |
| When the application is in <tt>production</tt> mode only a simple | |
| error message is displayed. See <a target="topic" href="configuration.html#application-mode">Configuration</a> | |
| for details on how to set the application mode. | |
| <p/> | |
| Please also see the <a href="examples.html">Examples</a> web app Exception Demo for demonstrations of Clicks error | |
| handling. | |
| <a name="page-not-found" class="heading"></a><h2>10. Page Not Found</h2> | |
| If the ClickServlet cannot find a requested page in the <tt>click.xml</tt> config file | |
| it will use the registered <a href="not-found.html">not-found.htm</a> page. | |
| <p/> | |
| The Click not found page is automatically configured as: | |
| <pre class="codeConfig"> | |
| <page path="<span class="blue">click/not-found.htm</span>" classname="<span class="red">org.apache.click.Page</span>"/> | |
| </pre> | |
| You can override the default configuration and specify your own class, but you cannot change the path. | |
| <p/> | |
| When the ClickSevlet starts up it checks to see whether the <span class="html">not-found.htm</span> template exists in the | |
| <span class="html">click</span> web sub directory. If it cannot find the page the ClickServlet will automatically deploy one. | |
| <p/> | |
| You can tailor the <span class="html">click/not-found.htm</span> template to suite you own needs. This page template | |
| has access to the usual Click objects. | |
| <a name="page-messages" class="heading"></a><h2>11. Message Properties</h2> | |
| The Page class provides a | |
| <a href="click-api/org/apache/click/Page.html#messages">messages</a> property which | |
| is a <a href="click-api/org/apache/click/util/MessagesMap.html">MessagesMap</a> | |
| of localized messages for the page. These messages are made available | |
| in the VelocityContext when the page is rendered under the key <tt>messages</tt>. | |
| So for example if you had a page title message you would access it in your page template as: | |
| <pre class="codeHtml"> | |
| <h1> <span class="red">$</span><span class="blue">messages.title</span> </h1> </pre> | |
| This messages map is loaded from the page class property bundle. For example | |
| if you had a page class <tt>com.mycorp.page.CustomerList</tt> you could have | |
| an associated property file containing the pages localized messages: | |
| <pre class="codeConfig"> | |
| /com/mycorp/page/CustomerList.properties </pre> | |
| You can also defined a application global page messages properties file: | |
| <pre class="codeConfig"> | |
| /click-page.properties </pre> | |
| Messages defined in this file will be available to all pages throughout your | |
| application. Note messages defined in your page class properties file will | |
| override any messages defined in the application global page properties file. | |
| <p/> | |
| Page messages can also be used to override Control messages, see the Controls | |
| <a href="controls.html#message-properties">Message Properties</a> topic for | |
| more details. | |
| </body> | |
| </html> |