Unit04 - 表單點擊動作的處理 - Command Components

3 minute read

JSF 教學

目標

  • 瞭解產生可點擊元素的 JSF Facelet
  • 瞭解點擊後, 如何在後端執行 JSF Managed bean 的方法, 處理使用者的互動

知識

Facelets

JSF 的 Command Components 相關的 facelet 標籤:

  • h:commandButton: 顯示按鈕
  • h:commandLink: 顯示超連結(link)

Post Request

Command Component 被按下後, 使用 Post 的方式, 提交 Request 到應用程式伺服器.

如果要使用 Get Request 與應用程式伺服器溝通, 使用 h:button 或者 h:link facelets.

Command Component 重要元件屬性

  • action 屬性: 綁定到 JSF Managed Bean 的方法, 執行 UI 互動邏輯, 完成後回傳要轉跳的頁面名稱字串. 此方法稱之為 Action Method, 必須符合以下的方法簽名:
    1
    
    public String methodName()
    
  • 若有傳遞請求參數給 Action Method, 請使用 f:param facelet.
  • actionListener 屬性: 綁定到 JSF Managed Bean 的方法, 處理 UI 互動過程中元件產生的事件, 如 Value Change Event. 元件的事件處理會在後面單元介紹.

User Story

刪除購物車內的清單項目

假設購物車上有數個品項. 使用者在結賬前可以刪除購物車內的項目.

  1. 進入畫面, 顯示購物車內的內容.
  2. 使用者點選項目旁邊的刪除按鈕.
  3. 系統刪除購物車內的此項目. 之後, 更新頁面
  4. 使用者按下 Reset 按鈕, 重置購物車內的內容

實作程序

Step. 建立 entities.Dish class 以描述餐點名稱.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package entities;
  
/**
 *
 * @author user
 */
public class Dish {
    private int id;
    private String name;
    private float price;
  
    public int getId() {
        return id;
    }
  
    public void setId(int id) {
        this.id = id;
    }
  
    public String getName() {
        return name;
    }
  
    public void setName(String name) {
        this.name = name;
    }
  
    public float getPrice() {
        return price;
    }
  
    public void setPrice(float price) {
        this.price = price;
    }
  
    public Dish(int id, String name, float price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }
  
    public Dish(){
  
    }
}
  

Step. 建立 managed_beans.CartHandler 處理刪除購物車內品項及重置內容的動作.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package managed_beans;
  
import entities.Dish;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
  
/**
 *
 * @author user
 */
@Named(value = "cartHandler")
@SessionScoped
public class CartHandler implements Serializable {
  
    private Map<Integer, Dish> dishes;
    /**
     * Creates a new instance of CartHandler
     */
    public CartHandler() {
    }
  
    @PostConstruct
    public void init(){
        dishes = new HashMap<>();
  
        dishes.put(1, new Dish(1, "宮堡雞丁", 70));
        dishes.put(2, new Dish(2, "蜜汁排骨", 75));
        dishes.put(3, new Dish(3, "香酥雞腿", 90));
        dishes.put(4, new Dish(4, "炭烤排骨", 90));
    }
  
    /**
     * Return the collection for the <code> value </code> attribute of the <code> ui:repeat </code> facelet.
     * The name of a collection of items that this tag iterates over. 
     * The collection may be a List, array, java.sql.ResultSet, or an individual java Object. If the collection is null, this tag does nothing.
     * @return 
     */
    public Dish [] getDishList(){
        Dish[] availDishes = null;
        availDishes = dishes.values().toArray(new Dish [0]);
        return availDishes;
    }
  
    /**
     * Action method to delete a item in the cart.
     */
    public String delItem(){
        //get the request map
        ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
        Map<String, String> params = ec.getRequestParameterMap();
        Integer id = 0;
        if (null != params.get("ID")) {
            id = new Integer(params.get("ID"));
        }
  
        if (this.dishes.containsKey(id)){
            this.dishes.remove(id);
        }
  
        return null;
    }
  
    public String resetCart(){
        this.init();
        return null;
    }
}
  

Step. 建立 index.xhtml 頁面

<?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:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        <h1> </h1>
        已選擇菜色:
        <h:form>
        <table>
            <tr>
                <th>Name</th>
                <th>Price</th>
                <th>Action</th>
            </tr>
            <ui:repeat value="#{cartHandler.dishList}" var="dish">
                <tr>
                    <td>#{dish.id}</td>
                    <td>#{dish.name}</td>
                    <td>#{dish.price}</td>
                    <td> <h:commandButton action="#{cartHandler.delItem}" value="Del">
                            <f:param name="ID" value="#{dish.id}"/>
                        </h:commandButton>  </td>
                </tr>
            </ui:repeat>
        </table>
            <h:commandButton action="#{cartHandler.resetCart}" value="Reset Cart"/>
        </h:form>
    </h:body>
</html>
  
  

複習問題

  1. 在 JSF 中, 如何取得請求內的參數(Parameter)呢?
  2. 在 JSF 頁面, 使用那個 facelet 可以傳遞請求參數? 如何和 h:commandButton 搭配使用呢?
  3. f:param facelet 的 namevalue 屬性有何作用?

參考資料

[1] Oracle, 2014. Chapter 3 Creating JSF Pages Using Facelets. In JAVA EE 6: Develop Web Applications with JSF: Student Guide, vol 1.

Updated: