Академический Документы
Профессиональный Документы
Культура Документы
More annotations
Annotations for bean scopes
@SessionScoped, @ApplicationScoped Other scopes
Introduction
Customized Java EE Training: http://courses.coreservlets.com/
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location.
web.xml
Must have a url-pattern for *.jsf (or other pattern you choose) Usually sets PROJECT_STAGE to Development
some-page.xhtml
Use URL some-page.jsf (matches url-pattern)
faces-config.xml
<?xml version="1.0"?> <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0"> </faces-config>
File is mostly empty, but the file must exist (in WEB-INF), and you must have legal start and end tags that designate JSF 2.0. There will be no content inside the tags for any of the examples in this section. All examples in this section use default bean names (derived from the beans class name with the first letter changed to lower case) and default results pages (derived from the action controllers return values).
web.xml
<?xml version="1.0" encoding="UTF-8"?> You must have a url-pattern for the FacesServlet, just as in JSF 1.x. You can optionally set the PROJECT_STAGE, <web-app version="2.5"> which is recommended during development and testing. <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> <context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param> <welcome-file-list> <welcome-file>index.jsp</welcome-file> <welcome-file>index.html</welcome-file> </welcome-file-list> </web-app>
some-page.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head> You use facelets with xhtml syntax for all JSF 2.0 pages; you never use old-style JSP syntax. You always have xmlns:h, </h:head> h:head, h:body, and h:form. In later sections we will see that you sometimes also have xmlns:f... and/or xmlns:ui <h:body> No @taglib entries needed. Remember that the URL does not match the real filename: you use blah.xhtml for the files, but blah.jsf for the URLs (or <h:form> whatever matches the url-pattern in web.xml). </h:form> </h:body> </html>
10
@ManagedBean Basics
Business Logic
results submit form POST request Blah.jsf
Instantiate Bean
return value
Choose Page
forward
12
The pushbutton said action="#{someBean.someMethod}". So, instantiate bean whose name is someBean. In this section, we will declare bean with @ManagedBean, so that means to instantiate bean whose class name is SomeBean. Later we will see that the bean could be session-scoped (or have other scopes), so this will be called Find Bean instead of Instantiate Bean.
Main Points
@ManagedBean annotation
@ManagedBean public class SomeName { }
You refer to bean with #{someName.blah}, where bean name is class name (minus packages) with first letter changed to lower case. Request scoped by default.
And blah is either an exact method name (as with action of h:commandButton), or a shortcut for a getter and setter method (as with value of h:inputText).
Example
Idea
Click on button in initial page Get one of three results pages, chosen at random
A bean
Class: SimpleBean (bean name above except for case) @ManagedBean annotation doNavigation method returns 3 possible Strings
"page1", "page2", or "page3"
start-page.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head></h:head> <h:body> <fieldset> <legend>Random Results Page</legend> <h:form> Press button to get 1 of 3 possible results pages. <br/> <h:commandButton value="Go to Random Page" action="#{simpleBean.doNavigation}"/> </h:form> </fieldset> This means that when you press button, JSF instantiates bean whose name is simpleBean and then runs the doNavigation method. This is same format as in JSF 1.x, but name of bean is automatically derived from Java class name. </h:body></html>
15
The first time you do it, you will have to give location of the JSF 2.0 (and JSTL) JAR files
Benefits
16
Lots and lots of support for editing faces-config.xml Visual previews of .xhtml files
Solutions
web.xml file
Copy the version from jsf-blank or the annotations project at coreservlets.com. Copy it back in after adding facet.
17
SimpleBean.java
package coreservlets; import javax.faces.bean.*;
Declares this as managed bean, without requiring entry in faces-config.xml. Since no name given, name is class name with first letter changed to lower case (i.e., simpleBean). You can also do @ManagedBean(name="someName"). See next section.
Since no scope given, it is request scoped. You can also @ManagedBean use an annotation like @SessionScoped. See upcoming section. public class SimpleBean { public String doNavigation() { String[] results = { "page1", "page2", "page3" }; return(RandomUtils.randomElement(results)); The randomElement method just returns an element from the array at } random. Source code is in the downloadable Eclipse project. Later example adds @ApplicationScoped to this code, but it has same basic } behavior without it.
18
Since there are no explicit navigation rules in faces-config.xml, these return values correspond to page1.xhtml, page2.xhtml, and page3.xhtml (in same folder as page that has the form).
page1.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> I dont actually have any dynamic code in this simplistic example, but <h:head> it is a good idea to plan ahead and always include these tags. </h:head> <h:body> <div align="center"> <table border="5"> <tr><th class="title">Result Page 1</th></tr> </table> <p/> <h2>One. Uno. Isa.</h2> </div></h:body></html>
page2.xhtml and page3.xhtml are similar.
19
Results
20
Main Point
The name attribute of @ManagedBean
@ManagedBean(name="customName") public class SomeName { }
You refer to bean with #{customName.blah}, where bean name is exact value of name attribute.
Still request scoped by default. Still no entries in faces-config.xml
22
Example
Idea (same behavior as last example)
Click on button in initial page Get one of three results pages, chosen at random
A bean
Name: SimpleBean2 (not related to bean name above) @ManagedBean(name="coolName") doNavigation returns 3 possible Strings as before
"page1", "page2", or "page3"
start-page2.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head></h:head> <h:body> <fieldset> <legend>Random Results Page</legend> <h:form> Press button to get 1 of 3 possible results pages. <br/> <h:commandButton value="Go to Random Page" action="#{coolName.doNavigation}"/> </h:form> </fieldset> Same as start-page.xhtml except for bean name. </h:body></html>
24
SimpleBean2.java
package coreservlets; import javax.faces.bean.*; @ManagedBean(name="coolName") public class SimpleBean2 extends SimpleBean {}
Uses the name coolName instead of simpleBean2. Inherits the doNavigation method that returns "page1", "page2", or "page3". This example shares the results pages with the last example: page1.xhtml, page2.xhtml, and page3.xhtml.
25
Results
26
Business Logic
results
Instantiate Bean
Choose Page
forward
28
Main Points
Input values correspond to bean properties
<h:inputText value="#{someBean.someProp}"/>
When form is displayed, calls getSomeProp(). If value is other than null or empty String, puts value in textfield. When form is submitted, takes value in textfield and passes it to setSomeProp.
Validation and type conversion (if any) is first. See later section.
Example
Idea
Enter a bank customer id and a password Get either
Page showing first name, last name, and balance
Various versions depending on balance
Input form
value attribute for h:inputText
Results pages
#{someBean.someProperty}
30
bank-lookup.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> This value plays a dual role. When form is first displayed, bankingBean is instantiated and getCustomerId is called. If the value is non-empty, that result is the initial value of the textfield. Otherwise, the textfield is <h:body> initially empty. When the form is submitted, bankingBean is reinstantiated (assuming request scope) and the value in the textfield is passed to setCustomerId. This is the same behavior as in JSF 1.x. <fieldset> <legend>Bank Customer Lookup (Request Scope)</legend> <h:form> Customer ID: <h:inputText value="#{bankingBean.customerId}"/><br/> Password: <h:inputSecret value="#{bankingBean.password}"/><br/> <h:commandButton value="Show Current Balance" action="#{bankingBean.showBalance}"/> </h:form> </fieldset> </h:body></html>
31
BankingBeanBase.java
public abstract class BankingBeanBase { protected String customerId, password; protected Customer customer; public String getCustomerId() { return(customerId); } public void setCustomerId(String customerId) { this.customerId = customerId; These will be automatically called by }
JSF when form is submitted.
public String getPassword() { return(password); } public void setPassword(String password) { this.password = password; }
32
BankingBeanBase.java
public Customer getCustomer() { return(customer); } public abstract String showBalance(); }
The action controller method (showBalance) will fill in the customer based on the id and password supplied. Since the customer is filled in by the action controller method, not automatically by JSF, a setter method (setCustomer) is not strictly required.
This is an abstract method because I have three different versions: the basic one in this example, a later one in this section that uses dependency injection for the lookup service, and one in a later section on Ajax that does not return Strings corresponding to results pages. In general, the action controller method just has to take no arguments and return a String.
33
BankingBean.java
@ManagedBean public class BankingBean extends BankingBeanBase { public String showBalance() { if (!password.equals("secret")) { return("wrong-password"); Filled in by JSF before } this action controller method is called. CustomerLookupService service = new CustomerSimpleMap(); customer = service.findCustomer(customerId); if (customer == null) { return("unknown-customer"); The customer is not filled in automatically by } else if (customer.getBalance() < 0) { JSF, since it is not directly part of the submitted data, but rather indirectly derived (by the return("negative-balance"); business logic) from the submitted data. So, it is } else if (customer.getBalance() < 10000) { filled in by this action controller method. Just as in JSF 1.x, beans are typically composed of return("normal-balance"); three parts: properties corresponding to the input, action controller methods, and } else { placeholders for the results data. return("high-balance"); } } There are five possible results pages: wrong-password.xhtml, unknown-customer.xhtml, negative-balance.xhtml, normalbalance.xhtml, and high-balance.xhtml. We are using the default mapping of return values to file names in all cases (rather than } explicit navigation rules in faces-config.xml).
34
CustomerSimpleMap.java
public class CustomerSimpleMap implements CustomerLookupService { private Map<String,Customer> customers; public CustomerSimpleMap() { customers = new HashMap<String,Customer>(); addCustomer(new Customer("id001", "Harry", "Hacker", -3456.78)); addCustomer(new Customer("id002", "Codie", "Coder", 1234.56)); addCustomer(new Customer("id003", "Polly", "Programmer", 987654.32)); }
35
CustomerSimpleMap.java (Continued)
public Customer findCustomer(String id) { if (id!=null) { return(customers.get(id.toLowerCase())); } else { return(null); } } private void addCustomer(Customer customer) { customers.put(customer.getId(), customer); } }
36
CustomerLookupService.java
public interface CustomerLookupService { public Customer findCustomer(String id); }
Although the previous class used hardcoded test cases from a Map, the interface makes it relatively easy to switch to other ways of finding customers without making significant changes to the main JSF code. Dependency injection with @ManagedProperty (later in this tutorial section) improves further on this idea of changing the implementation without changing the Java code.
37
normal-balance.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head> In JSF 2.0 you can use #{result} instead of <h:outputText value="#{result}"/>. Both approaches escape HTML characters, so use the shorter approach </h:head> shown here unless you need one of the options to h:outputText like escape <h:body> (with a value of false), rendered (with a computed value), id, converter, etc. <ul> <li>First name: #{bankingBean.customer.firstName}</li> <li>Last name: #{bankingBean.customer.lastName}</li> <li>ID: #{bankingBean.customer.id}</li> <li>Balance: $#{bankingBean.customer.balanceNoSign}</li> </ul> </h:body></html>
negative-balance.xhtml and high-balance.xhtml are similar.
38
unknown-customer.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head> Even though customerId came from the user and could contain HTML characters, it is safe to use #{bankingBean.customerId} instead of <h:outputText value="#{bankingBean.customerId}"/>. </h:head> The same HTML escaping is done for #{result} as for <h:body> <h:outputText value="#{result}"/> <h2>No customer found with id "#{bankingBean.customerId}"</h2> <p>Please <a href="bank-lookup.jsf">try again</a>.</p> </h:body></html>
39
unknown-password.xhtml is similar.
40
41
Bean Scopes
Idea
Designates how long managed beans will stay alive, and which users and requests can access previous bean instances.
43
@SessionScoped
Put bean in session scope. If same user with same cookie returns before session timeout, same bean instance is used. You should make bean Serializable.
@ApplicationScoped
Put bean in application scope. Shared by all users. Bean either should have no state or you must carefully synchronize access.
44
@CustomScoped(value="#{someMap}")
Bean is stored in the Map, and programmer can control lifecycle.
New scope in JSF 2.0
@NoneScoped
Bean is not placed in a scope. Useful for beans that are referenced by other beans that are in scopes.
New scope in JSF 2.0
45
Business Logic
results
Find Bean
If request scope, instantiate bean. If other scope, possibly return existing instance.
Choose Page
forward
46
Main Points
You can use annotations to give scope
@RequestScoped (same as omitting scope) @SessionScoped @ApplicationScoped @ViewScoped @CustomScoped @NoneScoped
48
SimpleBean.java
package coreservlets; import javax.faces.bean.*; @ManagedBean @ApplicationScoped public class SimpleBean { public String doNavigation() { String[] results = { "page1", "page2", "page3" }; return(RandomUtils.randomElement(results)); } }
The xhtml pages and results were shown earlier in this section. One of page1.xhtml, page2.xhtml, and page3.xhtml is displayed at random. 49
Since there is no state, all users can share the same instance of this bean.
Useful for
Remembering user preferences Prefilling values from previous entries Accumulating lists of user data (ala shopping carts)
Some servers save session data to disk on restart Distributed Web apps need this to replicate sessions
bank-lookup2.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:body> <fieldset> <legend>Bank Customer Lookup (Session Scope)</legend> <h:form> Customer ID: <h:inputText value="#{bankingBean2.customerId}"/><br/> Password: <h:inputSecret value="#{bankingBean2.password}"/><br/> <h:commandButton value="Show Current Balance" action="#{bankingBean2.showBalance}"/> </h:form> Same as bank-lookup.xhtml except for bean name and some minor changes to text. </fieldset> </h:body></html>
52
BankingBean2.java
import java.io.*; import javax.faces.bean.*; @ManagedBean @SessionScoped public class BankingBean2 extends BankingBean implements Serializable { @Override public String showBalance() { String origResult = super.showBalance(); return(origResult + "2?faces-redirect=true"); } Results pages are negative-balance2.xhtml, normal-balance2.xhtml, etc. By also appending } faces-redirect=true, JSF will redirect instead of
forward to the results pages, thus exposing the URLs of the results pages and letting users navigate directly to them later.
53
If a page uses the name bankingBean2 and is accessed by the same user in the same browser session, the same bean instance will be used.
normal-balance2.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head> </h:head> <h:body> <ul> <li>First name: #{bankingBean2.customer.firstName}</li> <li>Last name: #{bankingBean2.customer.lastName}</li> <li>ID: #{bankingBean2.customer.id}</li> <li>Balance: $#{bankingBean2.customer.balanceNoSign}</li> </ul> </h:body></html>
54 Same as normal-balance.xhtml except for bean name. negative-balance2.xhtml and high-balance2.xhtml are similar.
55
56
You can use name attribute of @ManagedProperty if setter method name does not match field name
@ManagedProperty: Example
Idea
Refactoring of banking example Customer lookup service will be injected into main bean via @ManagedProperty Lookup service will be application scoped and created at application load time
@ManagedBean(eager=true) @ApplicationScoped
bank-lookup3.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:body> <fieldset> <legend>Bank Customer Lookup</legend> <h:form> Customer ID: <h:inputText value="#{bankingBean3.customerId}"/><br/> Password: <h:inputSecret value="#{bankingBean3.password}"/><br/> <h:commandButton value="Show Current Balance" action="#{bankingBean3.showBalance}"/> </h:form> Same as bank-lookup.xhtml except for bean name and some minor changes to text. </fieldset> </h:body></html>
61
BankingBean3.java
@ManagedBean public class BankingBean3 extends BankingBeanBase { @ManagedProperty(value="#{customerSimpleMap2}") private CustomerLookupService service; public void setService(CustomerLookupService service) { this.service = service; There is now no explicit reference to the concrete class that provides the lookup service. So, it is easier to change among test } implementations and real implementations without changing this code. However, when you use annotations only, the bean name is public String showBalance() { often tied closely to the bean name. The bean name need not be class name, but you still specify the name in the Java code. if (!password.equals("secret")) { the So, it is not clear that the annotation-based way of doing dependency injection is better than the JSF 1.x way of using return("wrong-password3"); faces-config.xml. } customer = service.findCustomer(customerId); if (customer == null) { Even though you must put the @ManagedProperty before the field (instance variable), the setter is what is called by JSF. If the setter name does not match the field name, use } @ManagedProperty(name, value). }
62
CustomerSimpleMap2.java
@ManagedBean(eager=true) @ApplicationScoped public class CustomerSimpleMap2 extends CustomerSimpleMap { }
Since the lookup service is shared by all instances of the banking bean, it is declared application scoped. Since it might take some time to initialize the Map, it is instantiated at application load time via eager. You are required to have @ApplicationScoped if you use eager=true.
The only reason for the subclass (instead of just putting the annotations on CustomerSimpleMap) is so that I can use eager here but not in previous example that used CustomerSimpleMap. Also note that the lookup service is immutable (does not change), so we dont have to worry about synchronizing access to it.
63
normal-balance3.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head> </h:head> <h:body> <ul> <li>First name: #{bankingBean3.customer.firstName}</li> <li>Last name: #{bankingBean3.customer.lastName}</li> <li>ID: #{bankingBean3.customer.id}</li> <li>Balance: $#{bankingBean3.customer.balanceNoSign}</li> </ul> </h:body></html>
64 Same as normal-balance.xhtml except for bean name. negative-balance3.xhtml and high-balance3.xhtml are similar.
65
Wrap-Up
Customized Java EE Training: http://courses.coreservlets.com/
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location.
Business Logic
results
Find Bean
Choose Page
forward
68
Summary
@ManagedBean
Bean name is class name with first letter in lower case Give custom name with @ManagedBean(name="")
Questions?
Customized Java EE Training: http://courses.coreservlets.com/
Servlets, JSP, JSF 2.0, Java 6, Ajax, jQuery, GWT, Spring, Hibernate, RESTful Web Services, Android. Developed and taught by well-known author and developer. At public venues or onsite at your location.