首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2EE

JSF 2 打造可重用 Ajax 組件實戰(三):托管 Bean 與數據模型

     編輯:J2EE

前言:組件背後的數據與狀態 — CDI Bean 定義

自動完成組件需要兩類數據:用戶選擇的值 (綁定到表單模型) 和 可選完成項列表 (靜態/動態數據源)。本文定義兩個 CDI Bean:`User` (會話級,存儲用戶選擇的國家) 和 `AutoComplete` (應用級,提供虛構國家列表),並解析其在 Facelet 中的綁定方式。

1. User Bean — 會話級表單模型

package com.corejsf;

import java.io.Serializable;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;

@Named
@SessionScoped
public class User implements Serializable {

    private String country;

    public String getCountry() { return country; }
    public void setCountry(String country) { this.country = country; }
}

關鍵點

  • `@Named`:CDI 命名 Bean,EL 可直接用 `#{user}` 訪問。
  • `@SessionScoped`:跨請求保持用戶選擇,模擬真實表單流程 (如註冊向導)。
  • 實現 `Serializable`:支援 Session 複製/集群/鈍化。
  • 屬性 `country` 對應組件 `value` 屬性綁定:`value="#{user.country}"`。

2. AutoComplete Bean — 應用級數據提供者

package com.corejsf;

import java.io.Serializable;
import javax.inject.Named;
import javax.enterprise.context.ApplicationScoped;

@Named
@ApplicationScoped
public class AutoComplete implements Serializable {

    public String[] getCountries() {
        return new String[] {
            "Abari", "Absurdsvanj", "Adjikistan", "AfroMacoland",
            "Agrabah", "Agaria", "Aijina", "Ajir", "Al-Alemand",
            "Al Amarja", "Alaine", "Albenistan", "Aldestan",
            "Al Hari", "Alpine Emirates", "Altruria",
            "Allied States of America", "BabaKiueria", "Babalstan",
            "Babar's Kingdom", "Backhairistan", "Bacteria",
            "Bahar", "Bahavia", "Bahkan", "Bakaslavia",
            "Balamkadar", "Baki", "Balinderry", "Balochistan",
            "Baltish", "Baltonia", "Bataniland, Republic of",
            "Bayview", "Banania, Republica de", "Bandrika",
            "Bangalia", "Bangstoff", "Bapetikosweti", "Baracq",
            "Baraza", "Barataria", "Barclay Islands",
            "Barringtonia", "Bay View", "Basenji"
        };
    }
}

關鍵點

  • `@ApplicationScoped`:全應用單例,數據源只載入一次,極低開銷。
  • 方法 `getCountries()` 返回 `String[]`,直接匹配 Facelet `completionItems="#{autoComplete.countries}"` (EL 解析 `getCountries()` → `countries` 屬性)。
  • 實際項目中可注入 `CountryService` / `JpaRepository`,從 DB/Redis/REST 獲取,並加入緩存 (Caffeine/Redis)。

3. Facelet 中的綁定 (index.xhtml 片段)

<html xmlns="https://www.w3.org/1999/xhtml"
      xmlns:h="https://java.sun.com/jsf/html"
      xmlns:util="https://java.sun.com/jsf/composite/util">

<h:body>
    <h:form>
        <h:panelGrid columns="2">
            #{msgs.locationsPrompt}
            <util:autoComplete value="#{user.country}"
                               completionItems="#{autoComplete.countries}" />
        </h:panelGrid>
    </h:form>
</h:body>
</html>

綁定解析

屬性EL 表達式綁定目標方向
`value``#{user.country}``User.country` (String)雙向 (輸入 → model、選中 → model)
`completionItems``#{autoComplete.countries}``AutoComplete.getCountries()` (String[])單向 (組件讀取初始數據)

4. CDI 作用域選型指南

作用域生命週期典型用途本組件角色
`@RequestScoped`單次 HTTP 請求控制器、臨時計算不適用 (需跨請求保持值)
`@ViewScoped` (JSF)同一 View 多次 POSTCRUD 頁面、分頁表格可替代 SessionScoped (若無跨頁需求)
`@SessionScoped`用戶會話用戶偏好、購物車、登錄狀態`User` Bean — 跨請求保持選擇
`@ApplicationScoped`應用啟動到關閉配置、緩存、靜態數據源、服務門面`AutoComplete` Bean — 共享國家列表
`@ConversationScoped`用戶標記的長會話向導、多步驟表單進階場景可替代 SessionScoped

5. 進階:動態數據源與懶加載

若完成項數據量大 (萬級) 或需遠程查詢,`AutoComplete` 可改為:

@Named
@ApplicationScoped
public class AutoComplete {
    @Inject CountryService countryService; // 統一數據訪問介面
    private Cache> prefixCache; // Caffeine 緩存

    public List getCountries(String prefix) { // 改為帶參方法
        if (prefix == null || prefix.length() < 2) return Collections.emptyList();
        return prefixCache.get(prefix, k -> countryService.findByPrefix(k));
    }
}

Facelet 需配合修改:`completionItems="#{autoComplete.countries['Al']}"` (EL 不支援帶參方法,需在組件內部 JS/Java 協調調用,見監聽器篇)。

結語

兩個精簡的 CDI Bean (`User`、`AutoComplete`) 完美詮釋了 **「關注點分離」**:會話級模型負責用戶狀態,應用級提供者負責共享數據。配合 JSF 2 EL 表達式的直觀綁定,組件使用者無需關心數據獲取細節。下篇將進入組件核心 — Facelet 復合組件定義 (`autoComplete.xhtml`),展示如何將 HTML、JS、Ajax、Java 監聽器編織成可重用標籤。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved