Thứ Tư, 25 tháng 1, 2012

JSF - Bài 5: Tổ chức giải bóng đá

Lập trình JavaServer Faces

Center of Excellence, SaigonTech

Bài 5
Tổ chức giải bóng đá

I. Bài Toán

Hãy phát triển một web application nhận từ bàn phím số cầu thủ qui định cho từng đội bóng và tổng số cầu thủ tham dự giải đấu, trong đó số cầu thủ mỗi đội phải từ 9 đến 15, và tổng số cầu thủ tham dự phải là dương. Application sẽ cho biết kết quả về số đội bóng mà liên đoàn có thể tổ chức giải đấu và số cầu thủ bị dôi ra. 
Sau đây là một UI mẫu.

Hình 1


II. Giải pháp

Project: SoccerJSF

1. Thiết kế UI screen


Hình 2


2. Bổ sung phần động cho UI screen

2.1. Thiết kế managed bean
Hình 3


2.2. Tạo fields và method cho managed bean

package controller;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named(value = "index")
@RequestScoped
public class Index {
    private Integer playersPerTeam;
    private Integer players;
    private Integer teams;
    private Integer leftOverPlayers;

    public Index() {}
    
    public void computeResults() {
        // TODO
    }
    
    public void clear() {
        playersPerTeam = players = teams = leftOverPlayers = null;
    }

    public Integer getPlayers() { return players; }
    public void setPlayers(Integer players) { this.players = players; }
    
    public Integer getPlayersPerTeam() { return playersPerTeam; }
    public void setPlayersPerTeam(Integer playersPerTeam) {
        this.playersPerTeam = playersPerTeam;
    }
    
    public Integer getLeftOverPlayers() { return leftOverPlayers; }
    
    public Integer getTeams() { return teams; }
}


2.3. Ràng buộc UI screen với managed bean
<h:form>
    <fieldset>
        <label>Number of players per team:</label>
        <h:inputText value="#{index.playersPerTeam}" required="true"/><br/>
        
        <label>Total number of players:</label>
        <h:inputText value="#{index.players}" required="true"/><br/>
        
        <label>Number of teams:</label>
        <input disabled="true" value="#{index.teams}"/><br/>
                
        <label>Number of left over players:</label>
        <input disabled="true" value="#{index.leftOverPlayers}"/>
    </fieldset>
            
    <div class="buttons">
        <h:commandButton value="Compute Results" action="#{index.computeResults()}"/>
        <h:commandButton value="Clear" action="#{index.clear()}"
                         immediate="true" onclick="clearInputTexts(this.form)"/>
    </div>
</h:form>


3. Phát triển model


3.1. Design


Hình 4


3.2. Test class
package model;

import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class OrganizerTest {
    private final Organizer organizer0 = new Organizer(11, 10);
    private final Organizer organizer1 = new Organizer(11, 11);
    private final Organizer organizer2 = new Organizer(11, 100);
    
    @Test
    public void computeTeams() {
        assertEquals(0, organizer0.computeTeams());
        assertEquals(1, organizer1.computeTeams());
        assertEquals(9, organizer2.computeTeams());
    }
    
    @Test
    public void computeLeftOverPlayers() {
        assertEquals(10, organizer0.computeLeftOverPlayers());
        assertEquals(0, organizer1.computeLeftOverPlayers());
        assertEquals(1, organizer2.computeLeftOverPlayers());
    }
}


3.3. Main class

package model;

public class Organizer {
    private final int playersPerTeam;
    private final int players;

    public Organizer(int playersPerTeam, int players) {
        this.playersPerTeam = playersPerTeam;
        this.players = players;
    }
    
    public int computeTeams() {
        return players / playersPerTeam;
    }
    
    public int computeLeftOverPlayers() {
        return players % playersPerTeam;
    }
}


4. Kết nối managed bean với model



Hình 5


5. Kiểm tra tính hợp lệ của input

Trước tiên ta sẽ chèn các giá trị ràng buộc về input vào trang .xhtml, sau đó để tạo điều kiện thuận lợi cho việc bảo trì application, ta chuyển các giá trị này vào một file chuyên biệt gọi là properties file.


5.1. Đặt ràng buộc về input vào .xhtml page



Trong những bài trước, ta đã dùng một <h:message> component cho từng input component riêng biệt. Ở bài này, ta chọn phương án dùng một <h:messages> (cần lưu ý sự khác biệt nhỏ giữa message và messages) component chung cho tất cả các input components. Khi đó ta cần khai báo thêm attribute id cho các input components để thông báo lỗi trở nên rõ ràng hơn. Riêng đối với <h:form>, ta đặt attribute prependId="false" để tránh phải đặt một id cho nó. Cách làm này sẽ giúp thông báo lỗi ngắn hơn một chút, do không phải hiển thị id của form.<h:form prependId="false">
  <fieldset>
    <label>Number of players per team:</label>
    <h:inputText id="PlayersPerTeam" value="#{index.playersPerTeam}" required="true"/><br/>
                
    <label>Total number of players:</label>
    <h:inputText id="Players" value="#{index.players}" required="true"/><br/>
                
    <label>Number of teams:</label>
    <input disabled="true" value="#{index.teams}"/><br/>
                
    <label>Number of left over players:</label>
    <input disabled="true" value="#{index.leftOverPlayers}"/>
  </fieldset>
            
  <div class="buttons">
      <h:commandButton value="Compute Results" action="#{index.computeResults()}"/>
      <h:commandButton value="Clear" action="#{index.clear()}"
                       immediate="true" onclick="clearInputTexts(this.form)"/>
  </div>
</h:form>
<h:messages errorStyle="color:red"/>

Đến đây ta sẵn sàng đặt các giá trị ràng buộc mà bài toán đã nêu vào page.

<label>Number of players per team:</label>
<h:inputText id="PlayersPerTeam" value="#{index.playersPerTeam}" required="true">
    <f:validateLongRange minimum="9" maximum="15"/>
</h:inputText><br/>

<label>Total number of players:</label>
<h:inputText id="Players" value="#{index.players}" required="true">
    <f:validateLongRange minimum="1"/>
</h:inputText><br/>
5.2. Đặt ràng buộc về input vào properties file


Giả định rằng sau khi sử dụng application một khoảng thời gian, user muốn thay đổi qui định về số cầu thủ trong mỗi đội, hoặc tổng số cầu thủ tham dự, hoặc cả hai. Khi đó, là developer, ta cần vào index.xhtml để thay đổi các ràng buộc ở những vị trí thích hợp. Có một cách ít tốn kém thời gian hơn, là ta đặt các giá trị có khả năng biến động theo thời gian vào một file chuyên biệt gọi là properties file. Ở đó, ta đặt cho mỗi giá trị một cái tên, và từ nay về sau, mỗi khi cần thay đổi giá trị, ta chỉ cầnthực hiện việc thay đổi bên trong file này. Right-click Source Packages, chọn New, rồi chọn tiếp Other để chuyển sang New File window.

Hình 6

Chọn Other trong mục Categories:, chọn tiếp Properties File trong mục File Types:, rồi click Next để chuyển sang New Properties File window.



Hình 7

Trong ô File Name:, đặt tên cho file là constraints rồi click Finish.


Hình 8

Đến đây ta nhập các cặp tên=giá-trị vào file rồi lưu file.


Hình 9


5.3. Sử dụng properties file trong .xhtml page

Bây giờ ta sẽ thay thế các giá trị trong index.xhtml bằng tên tương ứng đã được đặt trong .properties file. Nhưng trước tiên, ta cần dùng <f:loadBundle> để khai báo.properties file. Ta đặt tên file vào attribute basename và tên tham chiếu đến file này vào attribute var. Từ nay về sau, trong .xhtml page, ta sẽ dùng tên tham chiếu để truy xuất các giá trị trong properties file.


Hình 10

Sau khi thay các giá trị cụ thể bằng tên tham chiếu, ta được kết quả sau.


Hình 11


III. Tổng kết

Bài viết đã trình bày cách sử dụng properties file để chuyển các giá trị có khả năng thay đổi trong tương lai về một nơi, tạo thuận lợi cho việc bảo trì về sau. Ngoài ra, đối với các thông báo lỗi, ta có thể dùng một <h:messages> tag thay nhiều <h:message>.



IV. Tài liệu tham khảo


  1. Gaddis T. (2010) Starting Out with Java: From Control Structures Through Objects, 4th edition, Pearson Education, Boston. Chương 4.




Không có nhận xét nào:

Đăng nhận xét