A Simple JSF Tutorial with PrimeFaces and JSON Object Parsing in Java (Updated Jan ’18)
In this tutorial, you will see an example of parsing JSON objects containing exchange rates for certain currencies and displaying them on a web page using JSF 2.1 and PrimeFaces 2.2 which is a rich-component framework for JSF adding AJAX and Web 2.0 capabilities to your web application.
What you need for this tutorial
Table of Contents
- Oracle JDK 1.6 or later
- Netbeans 7.0 or later (if you choose a different IDE, you will need to manually get the necessary libraries and components for this tutorial. See the following section)
- Tomcat 7
Technologies and libraries used
- JSF 2.1 (Mojarra 2 libraries a.k.a. jsf-api.jar, jsf-impl.jar, jstl.jar and standard.jar)
- PrimeFaces 2.2.1
- JSON (for Java)
- commons-logging-1.1.1.jar
- log4j-1.2.16.jar
- httpcore-4.1.4.jar
- httpclient-4.1.3.jar
Setting up the Project with JSF 2 and PrimeFaces Support
Launch Netbeans, and then go along the following steps:
- Choose New Project (Ctrl-Shift-N; ⌘-Shift-N on Mac) from the File menu. Select the Java Web category, then under Projects select Web Application. Click Next.
- In the Project Name field type ‘exchangeratesweb’ (without the quotes), and click Next.
- In this step, make sure the platform is selected as Java EE 6 and deselect the option ‘Enable contexts and dependency injection’ and also select Apache Tomcat 7 from the Server drop-down menu. Click Next
- Select Java Server Faces from the list of Frameworks, then in the Libraries tab under the Java Server Faces Configuration, select JSF 2.1 from the Registered Libraries option (whose radio button must also be chosen).
- Go to the Configuration tab now, and select “Facelets” as the preferred page language, and optionally specify the JSF Servlet URL pattern as ‘*.go’. (The most typical extension used by JSF developers is ‘*.jsf’ whereas in Sun’s legacy blueprints it would be ‘/faces/*’ which also comes as default. )
- Finally open the Components tab and select PrimeFaces 2.2.1, and then click Finish.
- Now we’ll create a JSF Managed Bean which will be used as a controller for the entire project. Right-click the project (exchangeratesweb) and select New > JSF Managed Bean… from the pop-up menu. (If this item does not show up in the drop-down menu, select Other… and then JavaServer Faces > JSF Managed Bean in the pop-up window titled New File).
- Name the managed bean class ‘ExchangeRatesBean‘ (without the quotes), type ‘net.ozar.egitim.jsf.kurlar.managed‘ for the package name, specify the bean name ‘exchangeRatesBean‘ and select ‘session‘ for the scope from the drop-down list.
Clarification about JSF Backing Bean Scopes
@RequestScoped: JSF Managed Bean lives as long as the HTTP request-response lives. The instantiated object dovizKurlariBean is created upon a HTTP request and gets destroyed when the HTTP response associated with the HTTP request is finished.
@ViewScoped: JSF Backing Bean lives as long as the user is interacting with the same JSF view in the browser window/tab. The instantiated object dovizKurlariBean gets created upon a HTTP request and gets destroyed once the user postbacks to a different view.
@SessionScope: JSF ManagedBean of this scope lives as long as the HTTP session of the web application lasts. The instantiated object dovizKurlariBean gets created upon the first HTTP request involving this bean in the session and gets destroyed when the HTTP session is invalidated.
@ApplicationScoped: JSF BackingBean of this scope lives as long as the web application lives. The object dovizKurlariBean is instantiated upon the first HTTP request involving this bean in the application (or when the web application starts up and the eager=true attribute is set in @ManagedBean) and gets destroyed when the web application shuts down.For the purposes of this tutorial, we’ll go with the session scope.
- Click Finish when you’re done.
- Enter the following code in the class source:
package net.ozar.egitim.jsf.kurlar.managed; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Calendar; import javax.annotation.PostConstruct; import javax.faces.application.FacesMessage; import javax.faces.bean.ApplicationScoped; import javax.faces.bean.ManagedBean; import javax.faces.context.FacesContext; import net.ozar.egitim.jsf.kurlar.pojo.ExchangeRate; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.json.JSONObject; /** * @author Gökhan Ozar * https://gokhan.ozar.net */ @ManagedBean @SessionScoped public class ExchangeRatesBean implements java.io.Serializable { private static final String ERURL = "http://openexchangerates.org/latest.json"; private static final String APPINFO = "This application is intended as a simple tutorial example on JSF 2, PrimeFaces 2 (Web 2.0 & AJAX) and JSON object parsing. Visit <a href="\"http://gokhan.ozar.net\"">http://gokhan.ozar.net</a> for more... "; private ExchangeRate erate = new ExchangeRate(); private String msj = ""; public ExchangeRatesBean() { } @PostConstruct public void kurlariYukle() { HttpClient webIstemci = new DefaultHttpClient(); HttpGet webdenGetir = new HttpGet(ERURL); HttpResponse donenCevap; try { donenCevap = webIstemci.execute(webdenGetir); // Getting the web (HTML) response from the URL HttpEntity birim = donenCevap.getEntity(); // Setting the HttpEntity to the Http Response object if (birim != null) { InputStream gelenVeri = birim.getContent(); String sonuc = convertStreamToString(gelenVeri); JSONObject json = new JSONObject(sonuc); JSONObject currs = json.getJSONObject("rates"); msj = APPINFO.concat(json.getString("license" )); erate.setBaseCurrency(json.getString("base" )); erate.setEur (currs.getDouble("EUR")); // Euro erate.setGbp (currs.getDouble("GBP")); // British Pound Sterling erate.setJpy (currs.getDouble("JPY")); // Japanese Yen erate.setCad (currs.getDouble("CAD")); // Canadian Dollars erate.setMxn (currs.getDouble("MXN")); // Mexican Pezo erate.setAed (currs.getDouble("AED")); // United Arab Emirates Dirham erate.setTrl (currs.getDouble("TRY")); // Turkish Lira long t = json.getLong("timestamp"); // getting the last update date & time Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(t*1000); // converting into a human-readable date format erate.setLastModif(cal.getTime()); erate.setDisclaimer(json.getString("disclaimer").concat(APPINFO.replaceAll("\\", ""))); // Getting the disclaimer and stripping the HTML tags from the APPINFO String before concatenating it erate.setMesaj (msj); FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msj, msj); FacesContext.getCurrentInstance().addMessage("successInfo", facesMsg); gelenVeri.close(); } } catch (Exception e) { msj= "Loading the exchange rates failed!\nThere appears to be a problem with the server connection."; erate.setMesaj(msj); Logger.getLogger(ExchangeRatesBean.class.getName()).log(Level.ERROR, null, e); FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msj, msj); FacesContext.getCurrentInstance().addMessage(null, facesMsg); } } public String convertStreamToString(InputStream is) { // The incoming input stream is accumulated in a String to be returned BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) { sb.append(line).append("\n"); } } catch (IOException e) { } finally { try { is.close(); } catch (IOException e) { } } return sb.toString(); } // Managed bean getter & setter for the sake of abstraction public ExchangeRate getErate() { return erate; } public void setErate(ExchangeRate erate) { this.erate = erate; } }
- Now we need a POJO (plain old Java object) to hold the exchange rate data which will be acquired via JSON.Create a new Java class named ExchangeRate.java in a package called net.ozar.egitim.jsf.kurlar.pojo and enter the following code into its source:
package net.ozar.egitim.jsf.kurlar.pojo; import java.util.Date; /** * @author Gökhan Ozar * https://gokhan.ozar.net */ public class ExchangeRate implements java.io.Serializable { private String baseCurrency; private Double usd; // US dollar private Double gbp; // British Pound Sterling private Double eur; // Euro private Double jpy; // Japanese Yen private Double trl; // Turkish Lira "TRY" private Double cad; // Canadian Dollar private Double mxn; // Mexican Pezo private Double aed; // United Arab Emirates Dirham private Date lastModif; private String disclaimer; private String license; private String mesaj; public String getBaseCurrency() { return baseCurrency; } public void setBaseCurrency(String baseCurrency) { this.baseCurrency = baseCurrency; } public Double getEur() { return eur; } public void setEur(Double eur) { this.eur = eur; } public Date getLastModif() { return lastModif; } public void setLastModif(Date lastModif) { this.lastModif = lastModif; } public String getMesaj() { return mesaj; } public void setMesaj(String mesaj) { this.mesaj = mesaj; } public Double getUsd() { return usd; } public void setUsd(Double usd) { this.usd = usd; } public String getDisclaimer() { return disclaimer; } public void setDisclaimer(String disclaimer) { this.disclaimer = disclaimer; } public String getLicense() { return license; } public void setLicense(String license) { this.license = license; } public Double getAed() { return aed; } public void setAed(Double aed) { this.aed = aed; } public Double getCad() { return cad; } public void setCad(Double cad) { this.cad = cad; } public Double getGbp() { return gbp; } public void setGbp(Double gbp) { this.gbp = gbp; } public Double getJpy() { return jpy; } public void setJpy(Double jpy) { this.jpy = jpy; } public Double getMxn() { return mxn; } public void setMxn(Double mxn) { this.mxn = mxn; } public Double getTrl() { return trl; } public void setTrl(Double trl) { this.trl = trl; } }
- Now go to the Web Pages in the project folder and double-click index.xhtml. Modif its source code so as to match the following:
<?xml version='1.0' encoding='UTF-8' ?> <!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:p="http://primefaces.prime.com.tr/ui" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <h:head> <title>Exchange Rates</title> </h:head> <h:body> <h:form> <p:commandButton value="Display the rates" onclick="dlg1.show();" type="button" /> <p:commandButton id ="ref" value="Refresh" ajax="true" action="#{exchangeRatesBean.kurlariYukle}" type="submit" update="dovizKurPaneli, dovizKurPaneli2" /> <p:dialog id="dlg" header="Exchange Rates" widgetVar="dlg1" width="500"> <p:panel id="dovizKurPaneli"> <h:panelGrid columns="2"> #{exchangeRatesBean.erate.baseCurrency} 1.00 : <h:outputText value="GBP #{exchangeRatesBean.erate.gbp}" /> #{exchangeRatesBean.erate.baseCurrency} 1.00 : <h:outputText value="EUR #{exchangeRatesBean.erate.eur}" /> #{exchangeRatesBean.erate.baseCurrency} 1.00 : <h:outputText value="JPY #{exchangeRatesBean.erate.jpy}" /> #{exchangeRatesBean.erate.baseCurrency} 1.00 : <h:outputText value="CAD #{exchangeRatesBean.erate.cad}" /> #{exchangeRatesBean.erate.baseCurrency} 1.00 : <h:outputText value="MXN #{exchangeRatesBean.erate.mxn}" /> #{exchangeRatesBean.erate.baseCurrency} 1.00 : <h:outputText value="AED #{exchangeRatesBean.erate.aed}" /> </h:panelGrid> <br /> <p:panel> Last update: <h:outputText value="#{exchangeRatesBean.erate.lastModif}"><f:convertDateTime pattern="MM/dd/yyyy HH:mm" /></h:outputText> <br /><br /> <h:outputText value="#{exchangeRatesBean.erate.disclaimer}" /> </p:panel> </p:panel> </p:dialog> <p:messages /> </h:form> </h:body> </html>
You can download a zip archive containing all the jar files of the used libraries here:
[Download not found]
And you can see the finished application below.
Here is a screenshot from the finished application:
JSF (Java Server Faces) ile PrimeFaces ve JSON Object Parsing Kullanımı
JSF (Java Server Faces) ile PrimeFaces ve JSON Object Parsing Kullanımı
13 Comments
Great tutorial, G, thanks! With HTML 5 and AJAX, we’ll need JSON more than ever.
How/when is exchangeRatesBean instantiated?
A Managed Bean is instantiated as soon as a JSF action references a method contained in it, in the case of the ExchangeRatesBean, it’s invoked as index.xhtml is called in the browser.
Great read, thanks gokhan
A good tutorial for beginning JSF. Can you provide a download for the project files?
I put the complete NetBeans project(s) in the Downloads section under the Tutorial files category.
Can I ask the reason why using ApplicationScoped Managed Bean?
Sure. The main strategy here is pulling the exchange rate data once and providing that very data to all visitors (until someone invokes the Refresh action, which will benefit every new visitor) as there’s a very very little chance that there would be dramatic changes in the rates. You could change to scope of the managed bean to “session” (i.e. @SessionScoped) or even lower the scope as low as to the “request” (@RequestScoped) but I didn’t want to add extra load to the service (data) provider for a free service and therefore chose to avoid pissing them off.
Primefaces action commands does not function on cloudbees, though it is all wirk on local machine with the same server version. What could cause to this?
Never heard of or experienced such a problem. What application server / web container are you using?
Guzel makale. Tesekkurler gokhan.
Change this code:
into:
@PostConstruct is automatically called when the bean gets initiated, so you shouldn’t call that method yourself.
@Serkan,
Thanks for your comment. My current WordPress configuration seems to have stripped some of your <code> suggestion, but
since
invokes the method
for refreshing the exchange rates, and I didn’t want to use extra space for this example, I simply put @PostConstruct above it to have this method called automatically once the bean is initiated.
But yes, a good practice in a real life application could have been separating this logic elsewhere and a shorter @PostConstruct method to call the method from wherever it is positioned.
Note: Please use the pre tag instead of <code if you wish to comment further and submit a <code suggestion.