Managed Beans Part 2

Hôm nay chúng ta tiếp tục phần bài JSF . Chúng ta sẻ hiện thực các phạm vi trong managed beans. Và các hoạt động của các đổi tượng Request và Response, và annotation @ManagredProperty (dependency injection) in JSF

Source code : Managed Bean

Managed Bean

  • Chúng ta có thể tùy chỉnh name khi tạo bean .

Ví dụ : @ManagedBean( name = “yourBeanName” ) => #{ yourBeanName.attributes }.

  • Điều khiển Scope Bean ( Phạm vi của một Bean ).

Từ ban đầu chúng ta sử dụng Scope mặc định là [ Request ].

Chúng ta có các scope sau đây : request, session, application, view, none, custom

Chúng ta có thể thiết lập scope cho bean của chúng ta trong file faces-config.xml or sử dụng annotations [ example @SessionScoped ]. trên bean khi chúng ta tạo ra.

  1. @RequestScoped : Mặc định của mổi Bean, Nó tạo ra một new instance cho mổi lần HTTP request. Kể từ khi Bean của chúng ta được sử dụng để show các data lên các input form khi load page lên. Điều này có nghĩ là chúng ta khởi tạo Bean 2 lần [ lần thứ nhất khi form hiển thị, và lần 2 khi form được submit].
  2. @SessionScoped : Thiết lập Session scope cho Bean. Nếu trên cùng một user với cùng một cookie (JSESSIONID) trả về trước khi session timeout. Thì chúng ta sẻ sử dụng Bean mà chúng ta khởi tạo. Khi thiết lập Session Scope cho Bean bạn nên thiết lập Serializable cho Bean.
  3. @ApplicationScopded : Thiết lập Application Scope cho Bean. Khi chúng ta muốn Share Bean cho all User sử dụng. Phải nên cẩn thận khi dùng phạm vi này, có thể một User nào đó thay đổi Bean vì vậy không nên thay đổi Bean khi dùng phạm vi này, và nên thiết lập synchronize access cho Bean.
  4. @ViewScoped : Trên cùng một Bean – cùng một User – Cùng một page (example : Event handlers hoặc sử dụng Ajax ) bean của chúng ta nên thiết lập Serializable
  5. @CustomScoped (value=”#{someMap}”) : Bean này được dùng để lưu trữ trong một Map. và chúng ta có thể điều lifecycle cho riêng chúng ta .
  6. @NoneScoped : Khởi tạo một bean và Bean này không có Scope. hữu ích khi chúng ta tham chiếu đến Bean này bởi một Bean khác.
  • Các dùng thường dùng sau Anonation @ManagedBean.

Vd: @ManagedBean

      @SessionScoped

      Public class ClassBean {……..}

1 – Application Scope

Khi nào chúng ta nên dùng Scope này.

  1. Thiết lập Bean với trạng thái không bao giờ thay đổi.
  2. Thường chỉ thiết lập cho navigation rule ( No setter / getter)
  3. Ví dụng chúng ta có thể thiết lập 1 List các item cho việc lựa chọn tring Drop Down Menus
  4. VD <h:selectOnemenu value=”#{requestScopeBean.choice}”>
  5.         <f:selectItems value=”#{applicationScopeBean.options}”/>
  6. </h:selectOneMenu>
  7. Sử dụng để thiết lập một Data Structures như một properties trong main beans : @ManagedBeanProperty
  8. Share Bean thông qua all Users vs all pages, You củng nên cẩn thận sử dụng synchronization để né tránh race conditions.

1.1 – Syntax

Cách 1 :

@ManagedBean
@ApplicationScoped
public class ApplicationBean {}

ApplicationBean khi chúng ta thể hiện lần đầu tiên ( Sử dụng nó ). All user và All request share trên Bean này sẻ củng 1 instance.

Cách 2 :

@ManagedBean(eager=true)
@ApplicationScoped
public class ApplicationBeanBigData {}

ApplicationBeanBigData được thể hiện khi ứng dụng được load ( thường khi server starts ). Sau lần thể hiện đó all users vs all request sẻ hiện thực trên cùng thể hiện. Nó hữu ích khi Bean của chúng ta có 1 cấu trúc dữ liệu lớn ( big data) và mất khá nhiều thời gian để khởi tạo nó.

1.2 – Không thiết lập Các trạng thái thay đổi khi dùng Application Scope

  • Không thể hiển của variable, chỉ có các action controller method.
  • Application scope ngăn chặn nhựng đối tượng không cần thiết khi intantiation.
  • Khi thể hiện các small objects thì rất nhanh vì vậy việc để tối ưu hóa (optimization) có lẻ khổng thể được đo lường. Nó có thể gậy ra lỗi lầm khi chúng ta thêm input field và nó truy cập vào các getter/setter . Vì vậy nó thường được dùng để chuyển hướng trang
  • Được hiện thực khi có một lượng data lớn cần load. ( Đặc biệt các Map có chứa nhiều data ) và nó hoạt động rất tốt. ( Ví dụ khi chúng ta có 1 lượng lớn các List Object cho các đối tượng như drop down menus or Maps để hiện thực business logic như ví dụ lần trước ta dùng )

1.3 – Example cơ bản như sau :

@ManagedBean
@ApplicationScoped
public class ApplicationBean {
// no variable (not attribute)
// set action controller for bean
public String actionController(){
return "your-page";
}

2 – Session Scope

  • Mục đích Bean thể hiện được tái sử dụng nếu [ Cùng trên một User ] – [ Cùng trên một Browser session ]
  • Thường xuyên dự trên cookies, có thể dự trên URL để tái sử dụng bean.
  • Hữu ích khi sử dụng :
  1. Ghi nhớ user preferences.

  2. Thiết lập lại các values từ các entries trước

  3. Tính toán List các data của người dùng ( Shopping carts )

  • Bean thường Seriablizable. Một vài servers thường lưu session data trên disk khi restart, và các web apps cần để thiết lập lại session cho lần dùng kế tiếp.

Request vs Response Object.

Tại sao chúng ta cần 2 đối tượng này. Khi chúng ta có thể truy xuất data thông qua Bean một cach rất dể dàng như các bài trước ta thầy. Nhưng các Bean không thể làm các điều sau đây các bạn xem qua khi 2 đối tượng Request vs Response in JSF

  • Request Object

– HIện thực các thao tác trên session một cách rõ ràng.( Thay đổi các giá trị của session, session timeout, remove session..)

– Thao tác trên các cookies một cách rõ ràng ( VD : long-lived cookies).

– Đọc các request headers (vd : User-Agent, ..)

– Tra cứu các request host name.

  • Response Object

– Thiết lập status codes, respnse headers, long-lived cookies…

  • Giải pháp ( Solution ) kHá tương tự như Struts chung ta dùng các static method để gọi 2 đứa nó.

ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();     
HttpServletRequest request = (HttpServletRequest) context.getRequest();
HttpServletResponse response = (HttpServletResponse) context.getResponse();Note : Trong các môi trường khác nhau bạn phải cast getRequest, getResponse vè các đối tượng mà chúng ta cần, VD trong môi trường portlet chúng ta cast 2 đối tượng là PortletRequest vs PortletResponse.

Sử dụng @ManagedProperty ( Dependency injection )

JSF hổ trợ cơ bản cho việc sử dụng (Dependency injection), bạn có thể thiết lập values đến managed bean property mà không cần hardcoding nó vào trong class Bean.

Chắc hẵn nó thì không có năng lực so với Spring . nhưng vẫn hữu ích cho việc sử dụng trong JSF.

Cách 1 :

@ManagedProperty (value=”#{yourBean}”)

private YoutType someType;

Note : Setter method phải được thiết lập cho property này. trong ví dụ trên chúng ta phải có setSomeType(YourType type); Bạn có thể sử dụng thuộc tính name của @ManagedProperty nếu setter method thì không match với field name.

Cách 2 :

Bạn có thể hiện thực bean tại thời điểm load app

@ManagedBean(eager=true)
@ApplicationScoped
public class ApplicationBeanBigData {}

Điều này hữu ích khi bean của chúng ta được inject vào trong main bean. và Bean được inject thì thường được share
như môt service. Chúng ta thường dùng main bean chửa data khi load.

Note : faces-config tốt hơn annotations và Spring cách lựa chọn tốt nhất và bạn có thể dùng Spring trực tiếp trong
JSF application

Example cho ví dụ này chúng ta sẻ thay đổi Example login của chúng ta từ ví dụ trước như sau :

Thay đổi tại class LoginBean.java

@ManagedProperty(value="#{loginUtils}")
private LoginUtils loginUtils;
public void setLoginUtils(LoginUtils loginUtils) {
this.loginUtils = loginUtils;
}

Thay đổi class LoginUtils.java như sau :

@ManagedBean(eager=true)
@ApplicationScoped
public class LoginUtils {..... }

Kết quả run tương tự, chúc các bạn thành công .

Example Basic with JSF2

Hôm nay mình sẻ cho các bạn làm quen với các vấn đề sau :

 

  1. Mô hình flow control của JSF
  2. Hiểu được cấu trúc của một page XHTML.
  3. Textfield vs Textarea trong JSF
  4. Cách cơ bản nhất để Summit một form từ một Managed Bean cơ bản ( Bean là gì các bạn có thể gác lại mình sẻ giải thích sau này )

Mô hình Flow Control của một cấu trúc JSF cơ bản như sau :

d3

Ví dụ của chúng ta

Chúng ta tạo ra một Managed Bean như sau: Tên là ProductBean.java

package com.thaihoanghai.test;

import javax.faces.bean.ManagedBean;

@ManagedBean
public class ProductBean {
	public String registerProduct(){
		if(Math.random() < 0.5){
			return "success";
		}else{
			return "fail";
		}
	}
}
  • @ManagedBean : Chúng ta khai báo annotation này để thể hiện class ProductBean như một Managed Bean, Nếu không sử dụng @annotation chúng ta phải khai báo trong file faces-config.xml ( các loạt bài của mình đều dùng annotation )
  • method registerProduct() trả về loại String thể hiện nó như một action. Khi nhấn summit trên form với action này chúng ta sẻ có 2 trường hợp xãy ra, nếu Math.random < 0.5 thì chúng ta chuyển đến trang success.xhtml ngược lại sẻ chuyển đến trang fail.xhtml.

Trang index.xhtml của chúng ta như sau :

<!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>
<title>Example JSF</title>
</h:head>
<h:body>
	<h:form>
		<fieldset>
			<legend>Product Information</legend>
			Product ID : <h:inputText/><br/>
			Product Price : <h:inputText/><br/>
			Description : <h:inputTextarea/><br/>
			<h:commandButton value="Register Product" action="#{productBean.registerProduct}"/>
		</fieldset>
	</h:form>
</h:body>
</html>
  • xmlns:h="http://java.sun.com/jsf/html đây là một header chúng ta thể hiện đây là một page JSF, và nó có đuôi là .jsf , or .faces tùy lúc chúng ta khai báo trong web.xml.
  • Cách cơ bản để tạo một textfield vs textarea chúng ta dùng <h:inputText/> vs <h:inputTextarea/>
  • Để submit một form chúng ta sử dụng button như sau <h:commandButton value=”….” action=”#{yourBean.your_method}” /> Chúng ta có Class ProductBean là Managed Bean của mình, và có một method trả về 1 String như 1 action. Nhớ để submit 1 form chúng ta cần có thẻ <h:form> vậy chúng ta sẻ dùng nó như sau #{productBean.registerProduct} ( Note : sử dụng chữ cái đầu tiên của bean là chữ thường )

Page success.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>
<title>Product Success</title>
</h:head>
<h:body>
	<h1>Success .....=]] =]]</h1>
</h:body>
</html>

Page fail.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>
<title>Product Fail</title>
</h:head>
<h:body>
	<h1>Fail..........:[[ :[[</h1>
</h:body>
</html>

d1

Chúc các bạn thành công !!!

Config and install JSF with Eclipse

Bươc 1 : Cài đặt JDK và Thiết lập biến môi trường JAVA_HOME  – Có lẻ ai củng đả có (Bỏ qua )

Bước 2 : Cài đặt Java vs Tomcat Tuân thủ các bước sau

  • Tomcat 7 – Run với Java 6++  Here
  • Tomcat 6 – Run với Java 5++ Here

Bước 3 : Download Eclipse Chọn bảng Java EE (Version  Juno ++ ) được đề cử

  • Download  (Mình dùng bản Java EE Juno ) ( Có hổ trợ JSF2.x )

Bước 4 : Thiết lập JDK cho Eclipse :

d1

Bước 5 : Thiết lập Tomcat Server Cho Eclipse

d1

Bước 6 : Cài đặt JSF2 cho eclipse : Các bạn có thể chọn 1 trong 3 loại này Loại 1 – 2 khi config eclipse cho project JSF2 nó sẻ mặc định yêu cầu bạn chọn 1 trong 2. 

  • Oracle Mojarra
  • Apache MyFaces
  • Java EE 6 server

Chọn New -> Dynamic Web Project và thiết lập các thông số tương ứng với máy mình cài đặt , ở đây mình dùng Tomcat 7, Servlet 3.0, JSF2.1

d1

Dowload thư viện để Implement JSF2

d2

Cấu trúc thư mục như sau :

d1

Các bạn có thể thấy Lib JSF2.1 . Nếu các bạn không tự thiết lập như trên có thể vào các trang web Apache MyFaces or Oracle Mojarra để download các thư viện đó.

Bước 6 :  Chúng ta xem qua file web.xml config cho JSF 2 như sau :

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>Session1</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <!-- ===============================Default ================================== -->
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </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>
  <!-- ===============================End ================================== -->
  <context-param>
    <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
    <param-value>resources.application</param-value>
  </context-param>
  <context-param>
    <description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
  </context-param>
  <context-param>
    <description>
	This parameter tells MyFaces if javascript code should be allowed in
	the rendered HTML output.
	If javascript is allowed, command_link anchors will have javascript code
	that submits the corresponding form.
	If javascript is not allowed, the state saving info and nested parameters
	will be added as url parameters.
	Default is 'true'</description>
    <param-name>org.apache.myfaces.ALLOW_JAVASCRIPT</param-name>
    <param-value>true</param-value>
  </context-param>
  <context-param>
    <description>
	If true, rendered HTML code will be formatted, so that it is 'human-readable'
	i.e. additional line separators and whitespace will be written, that do not
	influence the HTML code.
	Default is 'true'</description>
    <param-name>org.apache.myfaces.PRETTY_HTML</param-name>
    <param-value>true</param-value>
  </context-param>
  <context-param>
    <param-name>org.apache.myfaces.DETECT_JAVASCRIPT</param-name>
    <param-value>false</param-value>
  </context-param>
  <context-param>
    <description>
	If true, a javascript function will be rendered that is able to restore the
	former vertical scroll on every request. Convenient feature if you have pages
	with long lists and you do not want the browser page to always jump to the top
	if you trigger a link or button action that stays on the same page.
	Default is 'false'
</description>
    <param-name>org.apache.myfaces.AUTO_SCROLL</param-name>
    <param-value>true</param-value>
  </context-param>
  <listener>
    <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
  </listener>
</web-app>

 

Bước 8 : Chúng ta ra 1 page index.xhtml như sau :

<!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>
<title>Insert title here</title>
</h:head>
    <h:body>
        <h1>Hello World</h1>
    </h:body>
</html>

Kết quả chúng ta nhận được khi run :

d1

 

Chúc các bạn thành công !!!