Вы находитесь на странице: 1из 67

2011 Marty Hall

A Very Fast Overview of JSF 2.0 Development


Originals of Slides and Source Code for Examples: http://www.coreservlets.com/JSF-Tutorial/jsf2/
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.

JSF 2.0: Basics with Annotations

Topics in This Section


JSF basics
Simplified flow of control @ManagedBean and default bean names Default mappings for action controller return values Custom bean names Using bean properties to handle request parameters

More annotations
Annotations for bean scopes
@SessionScoped, @ApplicationScoped Other scopes

@ManagedProperty and dependency injection


5

2011 Marty Hall

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.

Review from Previous Sections


faces-config.xml
For this entire section: empty body (start/end tags only)
This tutorial section uses Java-based annotations and default mappings of action controller values to results pages. Later tutorial sections will look at explicit values in faces-config.xml.

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)

Installation and setup


JSF 2.0 JAR files required; JSTL 1.2 JARs recommended
Omit them in Glassfish and other Java EE 6 servers

These examples use Tomcat and Eclipse


7

But code is general to any JSF 2.0 implementation

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

2011 Marty Hall

@ManagedBean Basics

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.

JSF Flow of Control (Highly Simplified)


Blah.xhtml
Uses <h:commandButton action="#{someBean.someMethod}"/> In this simple version, the page matches the return value of the action controller method. E.g., if the method returns "foo", then the system will forward to foo.xhtml. In later sections, we will use navigation rules in faces-config.xml that explicitly map the action controller return value to a file.

Business Logic
results submit form POST request Blah.jsf

Instantiate Bean

Run Action Controller Method

return value

Choose Page

forward

result1.xhtml result2.xhtml ... resultN.xhtml

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.

This is the exact method name given in the pushbuttons action.

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).

Return values of action controller method


If action controller method returns "foo" and "bar" and there are no explicit mappings in faces-config.xml, then results pages are foo.xhtml and bar.xhtml
From same folder that contained the form
13

Example
Idea
Click on button in initial page Get one of three results pages, chosen at random

What you need


A starting page
<h:commandButtonaction="#{simpleBean.doNavigation}"/>

A bean
Class: SimpleBean (bean name above except for case) @ManagedBean annotation doNavigation method returns 3 possible Strings
"page1", "page2", or "page3"

Three results pages


Names match return values of doNavigation method
14

page1.xhtml, page2.xhtml, and page3.xhtml

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

Reminder: Eclipse 3.6 Support (Not Available in Eclipse 3.5)


Add JSF 2.0 project facet
R-click project, Properties, Project Facets, check JavaServer Faces 2
Note that the downloadable Eclipse projects from JSF 2.0 tutorial at coreservlets.com already have this facet set.

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

Eclipse 3.6 Support: Issues


Problems
web.xml file
Creates a web.xml file with spurious entries, and without the very valuable Development PROJECT_STAGE entry

Editing .xhtml files


By default, they open in normal HTML editor, not smart editor that understands and previews the h: tags.

Solutions
web.xml file
Copy the version from jsf-blank or the annotations project at coreservlets.com. Copy it back in after adding facet.

Editing .xhtml files


R-click .xhtml files, choose Open With, Web Page Editor Or (better), you can make it automatic by going to Window, Preferences, General, Editors, File Associations, *.xhtml, make Web Page Editor the default

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

2011 Marty Hall

Giving Custom Names to Beans


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.

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

What you need (same except for bean name)


A starting page
<h:commandButtonaction="#{coolName.doNavigation}"/>

A bean
Name: SimpleBean2 (not related to bean name above) @ManagedBean(name="coolName") doNavigation returns 3 possible Strings as before
"page1", "page2", or "page3"

Three results pages as before


Names matching method return values
23

page1.xhtml, page2.xhtml, and page3.xhtml

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

2011 Marty Hall

Using Beans to Handle Request Parameters


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.

JSF Flow of Control (Updated but Still Simplified)


Blah.xhtml
Uses <h:commandButton action="#{someBean.someMethod}"/> and <h:inputText value="#{someBean.someProperty}"/> Bean getter methods are called

Run Setter Methods


submit form POST request Blah.jsf

Business Logic
results

Instantiate Bean

Run Action Controller Method

return value Store results of business logic in bean

Choose Page

forward

result1.xhtml result2.xhtml ... resultN.xhtml


(Use #{someBean.someProperty} to display bean properties)

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.

Same behavior as with bean properties in JSF 1.x

Beans are request scoped by default


Bean is instantiated twice: once when form is initially displayed, then again when form is submitted. Same behavior as with request-scoped beans in JSF 1.x.

Can use #{bean.someProp} directly in output


Instead of <h:outputText value="#{bean.someProp}"/> New behavior in JSF 2.0
29

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

Error message about missing or invalid data

What you need


Bean
Properties corresponding to request parameters

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)); }

Provides some simple hardcoded test cases.

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.

Results (Legal ID and Password)

negative balance high balance normal balance

40

Results (Bad Inputs)

41

2011 Marty Hall

Controlling Bean Scopes

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.

Bean Scopes
Idea
Designates how long managed beans will stay alive, and which users and requests can access previous bean instances.

JSF 1.x scopes


Request, session, application Specified in faces-config.xml Request scope is the default

JSF 2.0 scopes


request, session, application, view, none, custom Specified either in faces-config.xml or by one of the new annotations (e.g., @SessionScoped) Request scope is still the default

43

Annotations to Specify Bean Scope


@RequestScoped
Default. Make a new instance for every HTTP request. Since beans are also used for initial values in input form, this means bean is generally instantiated twice (once when form is displayed, once when form is submitted).

@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

Annotations to Specify Bean Scope (Continued)


@ViewScoped
Same bean instance is used as long as same user is on same page (e.g., with event handlers or Ajax).
New scope in JSF 2.0. Bean should implement Serializable

@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

JSF Flow of Control (Updated but Still Simplified)


Blah.xhtml
Uses <h:commandButton action="#{someBean.someMethod}"/> and <h:inputText value="#{someBean.someProperty}"/>

Run Setter Methods


submit form POST request Blah.jsf

Business Logic
results

Find Bean

Run Action Controller Method

If request scope, instantiate bean. If other scope, possibly return existing instance.

return value Store results of business logic in bean

Choose Page

forward

result1.xhtml result2.xhtml ... resultN.xhtml


(Use #{someBean.someProperty} to display bean properties)

46

Main Points
You can use annotations to give scope
@RequestScoped (same as omitting scope) @SessionScoped @ApplicationScoped @ViewScoped @CustomScoped @NoneScoped

Traditionally placed after @ManagedBean


@ManagedBean @SessionScoped public class SomePojo { }
47

Application Scope: Main Points


Useful for beans that have no state
Either navigation rules only (no getters/setters)
As in SimpleBean example earlier (this is rare in real life)

Or data structures used as properties in backing beans


See later section on @ManagedBeanProperty

SimpleBean from first example


There was no state (no instance variables), just an action controller method So, application scope prevents unnecessary object instantiation.
In practice, instantiation of small objects is very fast, so this optimization is probably not even measurable. For large data structures (especially large Maps), this trick can help significantly, though.

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.

Session Scope: Main Points


Bean instance reused if
Same user Same browser session
Usually based on cookies, but can be based on URL rewriting

Useful for
Remembering user preferences Prefilling values from previous entries Accumulating lists of user data (ala shopping carts)

Normal Java session tracking rules apply


Custom classes should be Serializable
50

Some servers save session data to disk on restart Distributed Web apps need this to replicate sessions

Session Scope: Example


Idea
Small variation of banking example Remember previously entered id
If end user comes back to input page, the ID they entered last time is already filled in

What you need


Add @SessionScoped for bean Make bean Serializable Optionally, add faces-redirect=true to end of return values, to tell JSF to redirect (instead of forward) to results pages
Allows users to access results pages directly
51

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.

Results (Initial Access)

negative balance high balance normal balance

55

Results (User Returns in Same Browser Session)

User directly entered this URL (or followed a link to it).

56

2011 Marty Hall

Advanced Topic: Using @ManagedProperty


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.

@ManagedProperty: Main Points


JSF supports simple dependency injection
That is, you can assign values to a managed bean property (i.e., a value the main bean depends on) without hardcoding it into the class definition
Not as powerful as with Spring, but still useful

@ManagedProperty lets you do this with annotations


@ManagedProperty(value="#{someBean}") private SomeType someField;

<managed-property> lets you do it in faces-config.xml


This is same as in JSF 1.x

Setter method for the property is required


E.g., in example above, you must have setSomeField
58

You can use name attribute of @ManagedProperty if setter method name does not match field name

@ManagedProperty: Secondary Points


You can instantiate beans at app load time
@ManagedBean(eager=true) @ApplicationScoped public class SomePojo { }
This is useful for the bean that you inject into the main bean. The injected bean is often something shared like a lookup service, whereas the main bean usually contains user-specific data

Unclear that annotation approach is better


One of the points of dependency injection is to let you change the concrete class without changing any Java code
This partially violates that principle

faces-config.xml lets you specify Map elements


The annotation does not
59

@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

What you need


Main bean
@ManagedProperty(value="#{lookupServiceBeanName}") private CustomerLookupService service; public void setService() { }

Lookup service bean (the bean being injected)


60

@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.

Results (Same Behavior as First Banking Example)

negative balance high balance normal balance

65

2011 Marty Hall

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.

Common Beginner Problems


JSF tags appear to be ignored
You entered URL ending in blah.xhtml instead of blah.jsf

Error message about null source


You have XML syntax error in main page. For example:
<h:commandButton action=""> (instead of <h:commandButton action=""/> ) Note that Eclipse is moderately helpful in finding XML syntax errors

Error message that view has expired


You went a very long time (e.g., during the lecture) without reloading the page or pressing a button. Solution: copy the URL and paste it back into browser
67

Highly Simplified JSF Flow of Control


Blah.xhtml
Uses <h:commandButton action="#{someBean.someMethod}"/> and <h:inputText value="#{someBean.someProperty}"/> Bean getter methods are called

Run Setter Methods


submit form POST request Blah.jsf

Business Logic
results

Find Bean

Run Action Controller Method

return value Store results of business logic in bean

Choose Page

forward

result1.xhtml result2.xhtml ... resultN.xhtml


(Use #{someBean.someProperty} to display bean properties)

68

Summary
@ManagedBean
Bean name is class name with first letter in lower case Give custom name with @ManagedBean(name="")

Mappings of results pages


By default, return values of action controller become base names of results pages

Changing scope (request is default)


@SessionScoped, @ApplicationScoped
Sometimes use eager for application scoped data

Injecting one bean into property of another


Put @ManagedProperty before a field You still need a setter method for that field
69

2011 Marty Hall

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.

Вам также может понравиться