Swing是一流的Java圖形用戶界面開發(fā)工具。本書詳細介紹了Swing的設(shè)計思想、體系結(jié)構(gòu)、使用技巧,內(nèi)容豐富、深入細致、分析透徹。本書用大量實例代碼介紹了每個組件的用法,使初學者能很快入門;用大量圖示分析了Swing組件的特點、結(jié)構(gòu)及相互關(guān)系,使有經(jīng)驗的編程人員能高效利用Swing的強大功能。本書對掌握Swing技術(shù)提供了最全面的參考。

Java 2圖形設(shè)計――卷Ⅱ:SWING(附CD)造價信息

市場價 信息價 詢價
材料名稱 規(guī)格/型號 市場價
(除稅)
工程建議價
(除稅)
行情 品牌 單位 稅率 供應商 報價日期
上位機圖形軟件 V1.0 查看價格 查看價格

迅捷

13% 深圳迅捷光通科技有限公司
CRT圖形顯示系統(tǒng)軟件 CRT-B-2 查看價格 查看價格

北大青鳥

13% 佛山青鳥環(huán)宇消防設(shè)備有限公司
鋼質(zhì)單片簾片 F2型跨度≤9m,配件另計 查看價格 查看價格

中霍

m2 13% 廣東霍曼實業(yè)有限公司
鋼質(zhì)單片簾片 F2型跨度>9m,配件另計 查看價格 查看價格

中霍

m2 13% 廣東霍曼實業(yè)有限公司
設(shè)計系列蓋板 品種:分線盒蓋;類別:設(shè)計系列邊框;產(chǎn)品型號:MTN391960;產(chǎn)品組:EAT;庫存類型:IND;交貨期(工作日):40;最小起訂量(個) 查看價格 查看價格

施耐德

13% 上海隨樂貿(mào)易有限公司
設(shè)計系列蓋板 品種:分線盒蓋;類別:設(shè)計系列邊框;產(chǎn)品型號:MTN391919;產(chǎn)品組:EAT;庫存類型:IND;交貨期(工作日):40;最小起訂量(個) 查看價格 查看價格

施耐德

13% 上海隨樂貿(mào)易有限公司
設(shè)計系列蓋板 品種:分線盒蓋;類別:設(shè)計系列邊框;產(chǎn)品型號:MTN391943;產(chǎn)品組:EAT;庫存類型:IND;交貨期(工作日):40;最小起訂量(個) 查看價格 查看價格

施耐德

13% 上海隨樂貿(mào)易有限公司
設(shè)計系列蓋板 品種:分線盒蓋;類別:設(shè)計系列邊框;產(chǎn)品型號:MTN391946;產(chǎn)品組:EAT;庫存類型:IND;交貨期(工作日):40;最小起訂量(個) 查看價格 查看價格

施耐德

13% 上海隨樂貿(mào)易有限公司
材料名稱 規(guī)格/型號 除稅
信息價
含稅
信息價
行情 品牌 單位 稅率 地區(qū)/時間
導線 DSJ23-122 查看價格 查看價格

臺班 汕頭市2012年2季度信息價
導線 DSJ23-122 查看價格 查看價格

臺班 汕頭市2011年3季度信息價
導線 DSJ23-122 查看價格 查看價格

臺班 汕頭市2011年1季度信息價
導線 DSJ23-122 查看價格 查看價格

臺班 廣州市2010年4季度信息價
導線 DSJ23-122 查看價格 查看價格

臺班 汕頭市2010年4季度信息價
導線 DSJ23-122 查看價格 查看價格

臺班 韶關(guān)市2010年8月信息價
導線 DSJ23-122 查看價格 查看價格

臺班 汕頭市2010年2季度信息價
導線 DSJ23-122 查看價格 查看價格

臺班 廣州市2010年1季度信息價
材料名稱 規(guī)格/需求量 報價數(shù) 最新報價
(元)
供應商 報價地區(qū) 最新報價時間
核心展品內(nèi)容介紹 立體造型(發(fā)光)8、5厘進口亞克力噴漆,制作發(fā)光寬:9m 高:0.07m|13個 3 查看價格 東莞市創(chuàng)發(fā)廣告有限公司 廣東   2022-11-17
核心展品內(nèi)容介紹 畫面高清進口背膠寬:5.86m 高:1.78m|10個 3 查看價格 東莞市創(chuàng)發(fā)廣告有限公司 廣東   2022-11-17
核心展品內(nèi)容介紹 發(fā)光字5厘進口亞克力寬:0.06m 高:0.06m|27m2 3 查看價格 東莞市創(chuàng)發(fā)廣告有限公司 廣東   2022-11-17
核心展品內(nèi)容介紹 展板9厘,6厘安迪板/|11個 3 查看價格 東莞市創(chuàng)發(fā)廣告有限公司 廣東   2022-11-17
界面內(nèi)容 靜態(tài)內(nèi)容平面展示設(shè)計|1項 2 查看價格 廣州熹尚科技有限公司 全國   2022-11-11
魚池介紹牌(專業(yè)公司二次深化設(shè)計) 魚池介紹牌(專業(yè)公司二次深化設(shè)計)|1套 3 查看價格 界面內(nèi)容 靜態(tài)內(nèi)容平面展示設(shè)計|1項 2 查看價格 廣州熹尚科技有限公司 全國   2022-11-11
界面內(nèi)容 靜態(tài)內(nèi)容平面展示設(shè)計|1項 2 查看價格 廣州熹尚科技有限公司 全國   2022-11-11

譯者序

前言

第一部分 Swing基礎(chǔ)

第1章 簡介

1.1Swing的歷史

1.2輕量組件與重量組件的比較

1.3Swing組件

1.3.1AWT的替代組件

1.3.2Swing增加的組件

1.4J組件

1.5Swing包概覽

1.6Swing與AWT

1.7開始學習

1.8Swing資源

1.9本章回顧

第2章 Swing的基本知識

2.1小應用程序與應用程序

2.1.1小應用程序

2.1.2JApplet類

2.1.3應用程序

2.1.4JFrame類

2.1.5小應用程序/應用程序的組合

2.2GJApp

2.3混合使用Swing組件和AWT組件

2.3.1層序

2.3.2Swing彈出式菜單

2.3.3滾動

2.3.4內(nèi)部窗體

2.4Swing和線程

2.4.1Swing單線程設(shè)計的結(jié)果

2.4.2SwingUtilities 類的invokeLater

和invokeAndWait方法

2.5本章回顧

第3章 Swing組件的體系結(jié)構(gòu)

3.1典型的“模型-視圖-控制器”體系

結(jié)構(gòu)

3.1.1插入式視圖和控制器

3.1.2視圖更新

3.2SwingMVC

3.2.1Swing組件

3.2.2靜態(tài)認識

3.2.3動態(tài)認識

3.2.4模型

3.2.5UI代表

3.2.6組件UI的案例

3.2.7監(jiān)聽器

3.3本章回顧

第4章 JComponent類

4.1JComponent類概覽

4.1.1邊框

4.1.2可訪問性

4.1.3雙緩存

4.1.4調(diào)試圖形

4.1.5自動滾動

4.1.6工具提示

4.1.7鍵擊處理和客戶屬性

4.2JComponent類結(jié)構(gòu)

4.2.1Swing組件是AWT容器

4.2.2最小尺寸 最大尺寸和首選

尺寸

4.3繪制JComponent組件

4.3.1Swing組件中的定制繪制

4.3.2在AWT組件中重載繪制方法

4.3.3在Swing組件中重載繪制方法

4.3.4painT、repaint和update方法

4.3.5validate、invalidate和revalidate

方法

4.3.6不透明組件與透明組件的比較

4.3.7立即繪制Swing組件

4.4雙緩存

4.5調(diào)試圖形

4.6自動滾動

4.7工具提示

4.7.1基于鼠標位置的工具提示

4.7.2工具提示的首選位置

4.7.3定制工具提示的行為

4.7.4定制工具提示的界面樣式

4.8鍵擊處理

4.9客戶屬性

4.10焦點管理

4.10.1JComponent的焦點屬性

4.10.2焦點管理器

4.11支持可訪問性

4.12本章回顧

第5章 邊框、圖標和動作

5.1邊框

5.1.1邊框和邊襯

5.1.2Swing的邊框類型

5.1.3不透明與透明之間的比較

5.1.4邊框包

5.1.5邊框接口

5.1.6AbstracBorder類

5.1.7邊框庫――共享邊框

5.1.8替換內(nèi)置邊框

5.1.9實現(xiàn)定制邊框

5.2圖標

5.2.1把圖標與組件相關(guān)聯(lián)

5.2.2在組件中共享圖標

5.2.3圖像圖標

5.2.4動畫的圖像圖標

5.3動作

5.3.1作為控制中心點的動作

5.3.2動作常量

5.4本章回顧

第6章 實用工具

6.1計時器

6.2事件監(jiān)聽器列表

6.3Swing實用工具

6.4Swing常量

6.5BoxLayout和Box 類

6.5.1BoxLayout類

6.5.2Box類

6.6進度監(jiān)視器

6.6.1ProgressMonitor

6.6.2Progress MonitorInputStream

6.7撤消/重復

6.7.1一個簡單的撤消/重復樣例

6.7.2UndoableEditSupport

6.7.3組合編輯

6.7.4UndoManager

6.7.5狀態(tài)編輯

6.8本章回顧

第7章 插入式界面樣式

7.1界面樣式結(jié)構(gòu)

7.1.1界面樣式

7.1.2界面樣式缺省值

7.1.3UI管理器

7.1.4UI資源

7.2Java界面樣式

7.2.1客戶屬性

7.2.2主題

7.3附加UI

7.4本章回顧

第二部分Swing組件

第8章 標簽與按鈕

8.1JLabel與JButton

8.2JLabel

8.2.1內(nèi)容排列

8.2.2文本的位置

8.2.3圖標/文本間隙

8.2.4許可狀態(tài)

8.2.5JLabel屬 性

8.2.6JLabel事件

8.2.7JLabel類總結(jié)

8.3按鈕

8.4JButton

8.4.1JButton屬性

8.4.2JButton事件

8.4.3JButton類總結(jié)

8.4.4AWT兼容

8.5本章回顧

第9章 反轉(zhuǎn)按鈕、復選框和單選鈕

9.1JToggleButton類

9.1.1JToggleButton屬性

9.1.2JToggleButton事件

9.1.3JToggleButton類總結(jié)

9.1.4AWT兼容

9.2按鈕組

9.3復選框

9.3.1JCheckBox屬性

9.3.2JCheckBox事件

9.3.3JCheckBox類總結(jié)

9.4單選鈕

9.4.1JRadioButton屬性

9.4.2JRadioButton 事件

9.4.3JRadioButton類總結(jié)

9.4.4AWT兼容

9.5本章回顧

第10章 菜單和工具條

10.1菜單、菜單欄和工具條

10.2菜單和彈出式菜單

10.3JMenuItem

10.3.1菜單項快捷鍵和助記符鍵

10.3.2JMenuItem屬性

10.3.3JMenuItem事件

10.3.4JMenuItem類總結(jié)

10.3.5AWT兼容

10.4JCheckBoxMenuItem

10.4.1JCheckBoxMenuItem屬性

10.4.2JCheckBoxMenuItem事件

10.4.3JCheckBoxMenuItem類總結(jié)

10.4.4AWT兼容

10.5JRadioButtonMenuItem

10.5.1JRadioButt onMe nuItem 屬性

10.5.2JRadioButtonMenuItem事件

10.5.3JRadioButtonMenuItem類

總結(jié)

10.5.4AWT兼容

10.6JMenu

10.6.1動態(tài)修改菜單

10.6.2右拉式菜單

10.6.3JMenu屬性

10.6.4JMenu事件

10.6.5JMenu類總結(jié)

10.6.6AWT兼容

10.7菜單元素

10.8JPopu pMe nu

10.8.1彈出式菜單觸發(fā)器

10.8.2輕量/中量/重量彈出式

菜單

10.8.3彈出式菜單調(diào)用者

10.8.4JPopupMenu屬性

10.8.5JPopupMenu事件

10.8.6JPopupMenu類總結(jié)

10.8.7AWT兼容

10.9JMenuBar

10.9.1菜單欄菜單和組件

10.9.2JMenuBar屬性

10.9.3JMenuBar事件

10.9.4JMenuBar類總結(jié)

10.9.5AWT兼容

10.10JToolBar

10.10.1滾過式工具條

10.10.2在工具條中使用動作

10.10.3浮動工具條

10.10.4位置固定的工具提示

10.10.5JToolBar屬性

10.10.6JToolBar事件

10.10.7JToolBar類總結(jié)

10.10.8AWT兼容

10.11本章回顧

第11章 進度條、滑桿和分隔條

11.1JProgessBar

11.1.1進度條與線程

11.1.2JProges sBar屬性

11.1.3JProgessBar事件

11.1.4JProgessBar類總結(jié)

11.1.5AWT兼容

11.2JSlider

11.2.1填充的滑桿

11.2.2滑桿間隔標記

11.2.3滑桿標簽

11.2.4反轉(zhuǎn)滑桿值

11.2.5滑桿的外延值

11.2.6JSlider屬性

11.2.7JSlider事件

11.2.8JSlider類總結(jié)

11.2.9AWT兼容

11.3JSeparator

11.3.1分隔條與框

11.3.2JSeparator 屬性

11.3.3JSeparator事件

11.3.4AWT兼容

11.4本章回顧

第12章 輕量容器

12.1JPan el

12.1.1JPanel的屬性

12.1.2JPanel的事件

12.1.3JPanel類總結(jié)

12.1.4AWT兼容

12.2JRootPane

12.2.1RootPaneCotainer接口

12.2.2玻璃窗格

12.2.3內(nèi)容窗格

12.2.4JRootPane屬性

12.2.5JRooPane事件

12.2.6JRootPane類總結(jié)

12.2.7AWT兼容

12.3JLaye redPane

12.3.1回顧輕量組件的層序

12.3.2為組件分配層

12.3.3指定同一層中組件的位置

12.3.4使用拖動層

12.3.5JLay eredPane屬性

12.3.6JLayeredPane類總結(jié)

12.3.7AWT兼容

12.4JTabbedPane

12.4.1選項卡的位置

12.4.2JTabbedPane的屬性

12.4.3JTabbedPane事件

12.4.4JTabbedPane類總結(jié)

12.5JSplitPane類

12.5.1JSplitPane屬性

12.5.2JSplitPane事件

12.5.3JSplitPane類總結(jié)

12.5.4AWT兼容

12.6本章回顧

第13章 滾動

13.1JViewport

13.1.1拖動視口中的視圖

13.1.2使用scrollRectToV isible

方法

13.1.3JViewport屬性

13.1.4JViewport事件

13.1.5JViewport類總結(jié)

13.1.6AWT兼容

13.2JScrollPane

13.2.1滾動窗格的頭部

13.2.2滾動窗格的角部

13.2.3JScrollPane屬性

13.2.4JScrollPane事件

13.2.5JScrollPane類總結(jié)

13.2.6AWT兼容

13.3Scrollable接口

13.4JScrollBar

13.4.1使用Swing的JScrollBar類進

行手動滾動

13.4.2塊增量和單元增量

13.4.3JScrollBar屬性

13.4.4JScrollBar事件

13.4.5JScrollBar類總結(jié)

13.4.6AWT兼容

13.5本章回顧

第14章 窗口和對話框

14.1JWindow

14.1.1JWindow屬性

14.1.2JWindow類總結(jié)

14.1.3AWT兼容

14.2JDialog

14.2.1JDialog屬性

14.2.2JDialog類總結(jié)

14.2.3AWT兼容

14.3JOptionPane

14.3.1內(nèi)部窗體

14.3.2用JOptionPane靜態(tài)方法創(chuàng)建

對話框

14.3.3消息對話框

14.3.4確認對話框

14.3.5輸入對話框

14.3.6選項對話框

14.3.7JOptionPane屬性

14.3.8JOptionPane事件

14.3.9JOptionPane類總結(jié)

14.3.10AWT兼容

14.4本章回顧

第15章 內(nèi)部窗體和桌面窗格

15.1JInternalFrame

15.1.1jintertnalFrame屬性

15.1.2JInternalFrame事件

15.1.3AWT兼容

15.2JDesktopPane

15.2.1JDesktopPane屬性

15.2.2JDesktopPane事件

15.2.3JDesktopPane類總結(jié)

15.2.4AWT兼容

15.3DesktopManager

15.4本章回顧

第16章 選取器

16.1JFileChooser

16.1.1文件選取器類型

16.1.2可訪問組件

16.1.3過濾文件類型

16.1.4文件視圖

16.1.5多文件選取

16.1.6JFileCHOoser屬性

16.1.7JFileChooser事件

16.1.8JFileChooser類總結(jié)

16.1.9AWT兼容

16.2JColorChooser

16.2.1在對話框中顯示顏色

選取器

16.2.2定制顏色選取器

16.2.3JColorChooser屬性

16.2.4JColorChooser事件

16.2.5JColorChooser類總結(jié)

16.2.6AWT兼容

16.3本章回顧

第17章 列表

17.1列表模型

17.1.1AbstractListModel

17.1.2DefaultListModel

17.2列表選取

17.3列表單元繪制器

17.3.1JList屬性

17.3.2JList事件

17.3.3JList類總結(jié)

17.3.4AWT兼容

17.4本章回顧

第18章 組合框

181JComboBox與JList的比較

18.2JComboBox組件

18.3組合框模型

18.3.1ComboBoxModel

18.3.2MutableComboBoxModel

18.3.3DefaultComboBoxModel

18.4組合框單元繪制器

18.5組合框鍵選取管理器

18.5.1使用缺省鍵選取管理器

18.5.2定制鍵選取管理器

18.5.3程序式的鍵選取

18.6組合框編輯器

18.6.1JComboBox屬性

18.6.2JCombo Box 事件

18.6.3JComboBox類總結(jié)

18.6.4AWT兼容

18.7本章回顧

第19章 表格

19.1表格和滾動

19.2表格模型

19.2.1表格數(shù)據(jù)模型

19.2.2TableModel接口

19.2.3AbstractTableModel

19.2.4DefaultTableModel

19.2.5表格模型、缺省繪制器

和缺省編輯器

19.3表格列

19.3.1列調(diào)整大小模式

19.3.2列寬度

19.4表格列模型

19.4.1DefaultTableColumnModel類

19.4.2列邊距

19.4.3隱藏列

19.4.4鎖定左邊列

19.5表格選取

19.6繪制和編輯

19.6.1使用表格單元繪制器和編

輯器

19.6.2表格單元繪制器

19.6.31DefaultTableCellRenderer

19.6.4表格格式化繪制器

19.6.5單元編輯器

19.6.6表格單元編輯器

19.6.7實現(xiàn)TableCellEditor接口

19.7表格行

19.7.1行高

19.7.2繪制行

19.8表格裝飾器

19.9表格頭部

19.9.1JTableHeader

19.9.2列頭部繪制器和頭部工具

提示

19.9.3JTable屬性

19.9.4表格事件

19.9.5表格模型事件

19.9.6TableColumnModel事件

19.9.7列表選取事件

19.9.8JTable類總結(jié)

19.9.9AWT兼容

19.10本章回顧

第20章 樹

20.1創(chuàng)建樹

20.2樹節(jié)點

20.2.1TreeNode接口

20.2.2MutableTreeNode接口

20.2.3DefaultMutableTreeNode類

20.3樹路徑

20.4樹模型

20.5樹選取

20.6樹單元繪制

20.6.1DefaultTreeCellRenderer

20.6.2Metal界面樣式

20.6.3根節(jié)點和根句柄

20.7樹單元編輯

20.7.1擴展DefaultCellEditor

20.7.2DefaultTreeCellEditor

20.8繪制和編輯:學習一個樣例

20.8.1Test類

20.8.2SelectableFile類和FileNode

20.8.3繪制器

20.8.4編輯器

20.8.5JTree屬性

20.8.6樹事件

20.8.7JTree類總結(jié)

20.8.8AWT兼容

20.9本章回顧

第21章 文本基礎(chǔ)

21.1Swing文本組件

21.2動作

21.2.1文本動作

21.2.2動作和編輯工具包

21.3鍵映射

21.4文檔

21.4.1定制文檔

21.4.2文檔監(jiān)聽器

21.5加字符與加重器

21.5.1加字符

21.5.2加字符監(jiān)聽器

21.5.3定制加字符

21.5.4加重器

21.6撤銷/恢復

21.7JTextComponent

21.8本章回顧

第22章 文本組件

22.1JTexlField

22.1.1水平可視性和滾動偏移

22.1.2布局單行文本域

22.1.3使單行文本域有效

22.1.4JTextField組件總結(jié)

22.1.5JTextField屬性

22.1.6JTextField事件

22.1.7JTextField類總結(jié)

22.1.8AWT兼容

22.2JPasswordField

22.2.1JPasswordField組件總結(jié)

22.2.2JPasswordFi eld屬性

22.2.3JPasswordField類總結(jié)

22.3JTextArea

22.3.1JTextArea組件總結(jié)

22.3.2JTextArea屬性

22.3.3JTextArea類總結(jié)

22.3.4AWT兼容

22.4JEditorPane

22.4.1JEditorPane屬性

22.4.2JEditorPane事件

22.4.3JEditorPane類總結(jié)

22.5JTextPane

22.5.1嵌入圖標和組件

22.5.2用屬性標記內(nèi)容

22.5.3JTextPane屬性

22.5.4JTextPane類總結(jié)

22.6AWT兼容

22.7本章回顧

第23章 定制文本組件

23.1概覽

23.2屬性集和風格常量

23.3定制動作

23.4視圖

23.5風格和風格的相關(guān)內(nèi)容

23.6元素

23.7本章回顧

第三部分 附錄

附錄A 類圖

附錄B 插入式界面樣式常量

2100433B

Java 2圖形設(shè)計――卷Ⅱ:SWING(附CD)內(nèi)容介紹常見問題

Java 2圖形設(shè)計――卷Ⅱ:SWING(附CD)內(nèi)容介紹文獻

圖形設(shè)計 圖形設(shè)計

格式:pdf

大小:2.4MB

頁數(shù): 24頁

評分: 4.4

圖形設(shè)計

立即下載
圖形設(shè)計論文 圖形設(shè)計論文

格式:pdf

大?。?span id="cpglll5" class="single-tag-height">2.4MB

頁數(shù): 7頁

評分: 4.3

圖形設(shè)計論文

立即下載

JavaWeb應用開發(fā)框架實例

一、 概述

Web 應用架構(gòu)可以劃分為兩大子系統(tǒng):前端子系統(tǒng)和后臺子系統(tǒng)。

前端子系統(tǒng):

1. 基礎(chǔ)技術(shù): Html/Java/CSS / Flash

2. 開發(fā)框架: jQuery, Extjs , Flex 等;

后臺子系統(tǒng):

1. 基礎(chǔ)技術(shù): Java Servlet;

2. 開發(fā)框架: Struts, Spring, Hibernate, ibatis 等;

3. 應用服務器: Tomcat / Jetty

編程模型: B/S 模型。 客戶端向服務器端發(fā)送請求, 服務器經(jīng)過處理后返回響應, 然后客戶端根據(jù)響應及需求繪制前端展現(xiàn)。

在用戶客戶端和實際提供功能的Web 服務器之間還可能存在著代理服務器, 負載均衡服務器, 不過那些屬于錦上添花的事物,暫時不在考慮范圍內(nèi)。

客戶端應用理念: 客戶端承擔大量的交互邏輯及渲染工作,服務器端主要是處理請求和返回數(shù)據(jù)。

前后端系統(tǒng)耦合: 客戶端和服務器端各自處理自己內(nèi)部的子系統(tǒng)耦合;而客戶端與服務器端的耦合簡化為一個通信與數(shù)據(jù)通道。該通道用來傳輸通信請求和返回數(shù)據(jù)。

請求通信: 采用 Http / Tcp 協(xié)議

數(shù)據(jù)通道: 采用 Json, xml , 文本字符串,字節(jié)。 內(nèi)部系統(tǒng)一般采用 Json 作為數(shù)據(jù)交換格式;系統(tǒng)間的互操作則采用XML 來規(guī)范;文本字符串是最一般的形式, 字節(jié)是最底層的形式。

JavaWeb應用開發(fā)框架實例

二、 架構(gòu)演變

最輕的架構(gòu): jQuery + Servlet + ajax 在客戶端使用 jQuery發(fā)送 ajax 請求給Java 服務端的 Servlet 進行處理, Servlet 僅僅返回數(shù)據(jù)給客戶端進行渲染。

該架構(gòu)有效地分離了前端展示和后臺請求處理,同時又保持了最輕的復雜性, 只需要學會編寫 Servlet 及使用 jQuery , 就能構(gòu)建簡單的應用。

如果只是做個人創(chuàng)意演示, 可以采用該架構(gòu), 快速實現(xiàn)自己的創(chuàng)意功能。 Servlet 是Java web 應用的基礎(chǔ)技術(shù),jQuery 則是前端開發(fā)的簡單易用的利器。

后臺架構(gòu)演變:

1. 邏輯與頁面的分離: JSP/Servlet

JSP 實現(xiàn)了頁面邏輯與外觀的分離,但是, 前端子系統(tǒng)與后臺子系統(tǒng)仍然是緊密耦合的; 前端設(shè)計人員實際上只需要服務端返回的數(shù)據(jù), 就可設(shè)計出非常專業(yè)的界面顯示。

2. MVC 架構(gòu):Struts2(含Servlet,MVC) + JDBC

用Servlet 來添加服務器功能是基本的選擇,但在web.xml中配置大量的 Servlet 卻不是最佳的選擇。

Struts2 在服務端實現(xiàn)了更豐富的MVC 模式, 將本來由應用決定的控制器從web容器中分離。

3. SSH 架構(gòu): Struts2(含Servlet, MVC) + Spring (Ioc) + Hibernate (ORM,對象-關(guān)系映射)

通常, 應用系統(tǒng)中需要預先創(chuàng)建一些單例對象, 比如 Controller, Service, Dao, 線程池等, 可以引入 Spring Ioc 來有效地創(chuàng)建、管理和推送這些對象;使用 Hibernate 來實現(xiàn)關(guān)系數(shù)據(jù)庫的行與面向?qū)ο蟮膶傩灾g的映射與聯(lián)接,以更好地簡化和管理應用系統(tǒng)的數(shù)據(jù)庫操作。SSH 可以說是 JavaWeb應用系統(tǒng)開發(fā)的三劍客。

4. SI 架構(gòu): SpringMVC(含Servlet, Ioc, MVC, Rest) + iBatis (Semi-ORM)

過于復雜的架構(gòu)會將人搞暈。因此,在適應需求的情況下, 盡量選擇簡單的架構(gòu),是明智之選。 這種架構(gòu)使用面向資源的理念,著重使用Spring作為MVC及應用基礎(chǔ)服務設(shè)施, 同時使用 iBatis 來實現(xiàn)更簡單靈活的ORM映射, 使之在可以理解和維護的范圍內(nèi)。

前端架構(gòu):

1. Flash 架構(gòu): Flex + jQuery + JSP

這是一種比較傳統(tǒng)的前端架構(gòu),采用同步模式, Flex 承擔大量的頁面渲染工作, 并采用AMF協(xié)議與Java端進行通信, 而JSP 則可以用于更快速的頁面顯示。優(yōu)點是: 經(jīng)過考驗的結(jié)構(gòu), 通常是值得信賴的; 缺點是, 由于采用同步模式, 在交互效果上可能不夠流暢, 需要進行比較耗時的編譯過程;此外, Flex 基于瀏覽器插件運行,在調(diào)試方面有些麻煩。

2. MVC 架構(gòu): Extjs + jQuery

這是一種比較現(xiàn)代的前端架構(gòu), 采用異步模式, Extjs4 可以實現(xiàn)前端子系統(tǒng)的MVC 分離, 對于可維護性是非常不錯的支持;此外, jQuery 可以作為有效的補充。

優(yōu)點: 異步, 快速, 對于企業(yè)內(nèi)部的后臺管理系統(tǒng)是非常好的選擇。

缺點: Extjs4 的可定制性、可適應性可能難以適應各種特殊的需求,需要用其它組件來補充, 比如大數(shù)據(jù)量的繪制。對于互聯(lián)網(wǎng)應用, 速度可能是致命傷。

三、 架構(gòu)的選擇

不要去詢問哪種架構(gòu)更好,更需要做的是清晰地定位項目目標,根據(jù)自己的具體情況來選擇和定制架構(gòu)。反復地嘗試、觀察和改進,反復磨煉技藝,這樣才有助于設(shè)計水平的提升。

架構(gòu)的選擇通常有四種關(guān)注點:

1. 適用性: 是否適合你的項目需求。 架構(gòu)有大有小, 小項目用小架構(gòu), 大項目用大架構(gòu)。

2. 可擴展性: 該架構(gòu)在需要添加新功能時,是否能夠以常量的成本添加到現(xiàn)有系統(tǒng)中, 所做的改動在多大程度上會影響現(xiàn)有功能的實現(xiàn)(基本不影響,還是要大面積波及)。

3. 便利性: 使用該架構(gòu)是否易于開發(fā)功能和擴展功能, 學習、開發(fā)和測試成本有多大。

4. 復雜性: 使用該架構(gòu)后,維護起來的成本有多大。你自然希望能夠?qū)懸粭l語句做很多事,使用各種成熟的組件是正確的方式,同時,在項目中混雜各種組件,也會提升理解和維護系統(tǒng)的復雜度。便利性和復雜性需要達到較好的平衡。

特殊的關(guān)注點:

譬如,應用需要支持高并發(fā)的情況, 需要建立一個底層的并發(fā)基礎(chǔ)設(shè)施, 并向上層提供簡單易用的接口,屏蔽其復雜性。

四、 架構(gòu)演進的基本手段

架構(gòu)并不是一成不變的, 在做出最初的架構(gòu)之后,隨著開發(fā)的具體情況和需求的變更, 需要對最初架構(gòu)做出變更和改進。

架構(gòu)演進的基本手段:

一致性, 隔離與統(tǒng)一管理, 螺旋式重構(gòu)改進, 消除重復, 借鑒現(xiàn)有方案。

1. 一致性: 確保使用統(tǒng)一模式來處理相同或相似的功能; 解決一次, 使用多次。

2. 模塊化、隔離與統(tǒng)一管理: 對于整體的應用, 分而治之,將其劃分為隔離性良好的模塊,提供必要的通信耦合;對于特定的功能模塊, 采用隔離手段,將其隔離在局部統(tǒng)一管理,避免分散在系統(tǒng)的各處。

3. 不斷重構(gòu)改進, 一旦發(fā)現(xiàn)更好的方式, 馬上替換掉原有方式。

4. 盡可能重用,消除重復。

5. 盡可能先借鑒系統(tǒng)中已有方案并復用之;如果有更好方案可替換之;

有一條設(shè)計準則是: 預先設(shè)計, 但不要過早設(shè)計。

意思是說, 需要對需求清楚的部分進行仔細的設(shè)計, 但是對于未知不清楚的需求,要堅持去理解它,但不要過早地去做出“預測性設(shè)計”;設(shè)計必須是明確的、清晰的、有效的, 不能針對含糊的東西來設(shè)計??梢栽诤笃谕ㄟ^架構(gòu)演進來獲得對后續(xù)需求的適應能力。

點擊關(guān)注 異步圖書,置頂公眾號每天與你分享 IT好書 技術(shù)干貨 職場知識本文包括以下內(nèi)容:Web應用的生命周期步驟 從HTML代碼到Web頁面的處理過程 Java代碼的執(zhí)行順序 與事件交互 事件循環(huán)

我們對Java的探索從客戶端Web應用開始,其代碼也在瀏覽器提供的引擎上執(zhí)行。為了打好后續(xù)對Java語言和瀏覽器平臺的學習基礎(chǔ),首先我們要理解Web應用的生命周期,尤其要理解Java代碼執(zhí)行在生命周期的所有環(huán)節(jié)。

本文會完整探索客戶端Web應用程序的生命周期,從頁面請求開始,到用戶不同種類的交互,最后至頁面被關(guān)閉。首先我們來看看頁面是如何從HTML代碼建立的。然后我們將集中探討Java代碼的執(zhí)行,它給我們的頁面提供了大量交互。最后我們會看看為了響應用戶的動作,事件是如何被處理的。在這一些列過程中,我們將探索很多Web應用的基礎(chǔ)概念,例如DOM(Web頁面的一種結(jié)構(gòu)化表示方式)和事件循環(huán)(它決定了應用如何處理事件)。讓我們開始學習吧!

你知道嗎?

瀏覽器是否總是會根據(jù)給定的HTML來渲染頁面呢? Web應用一次能處理多少個事件? 為什么瀏覽器使用事件隊列來處理事件?

1.1 生命周期概覽典型客戶端Web應用的生命周期從用戶在瀏覽器地址欄輸入一串URL,或單擊一個鏈接開始。例如,我們想去Google的主頁查找一個術(shù)語。首先我們輸入了URL,www.google.com,其過程如圖1.1所示。

圖1.1 客戶端Web應用的周期從用戶指定某個網(wǎng)站地址(或單擊某個鏈接)開始,

其由兩個步驟組成:頁面構(gòu)建和事件處理

從用戶的角度來說,瀏覽器構(gòu)建了發(fā)送至服務器(序號2)的請求,該服務器處理了請求(序號3)并形成了一個通常由HTML、CSS和Java代碼所組成的響應。當瀏覽器接收了響應(序號4)時,我們的客戶端應用開始了它的生命周期。 由于客戶端Web應用是圖形用戶界面(GUI)應用,其生命周期與其他的GUI應用相似(例如標準的桌面應用或移動應用),其執(zhí)行步驟如下所示:

1.頁面構(gòu)建——創(chuàng)建用戶界面;

2.事件處理——進入循環(huán)(序號5)從而等待事件(序號6)的發(fā)生,發(fā)生后調(diào)用事件處理器。

應用的生命周期隨著用戶關(guān)掉或離開頁面(序號7)而結(jié)束。現(xiàn)在讓我們一起看一個簡單的示例程序:每當用戶移動鼠標或單擊頁面就會顯示一條消息。本文會始終使用這個示例,如清單1.1所示。

清單 1.1 一個帶有GUI的Web應用小程序,其描述了對事件的響應

1<!DOCTYPE html>

2<html>

3 <head>

4 <title>Web app lifecycle</title>

5 <style>

6 #first { color: green;}

7 #second { color: red;}

8 </style>

9 </head>

10 <body>

11 <ul id="first"> </ul>

1213 <>

14 function addMessage(element, message){

15 var messageElement = document.("li");

16 messageElement.textContent = message;

17 element.(messageElement);

18 } ?--- 定義一個函數(shù)用于向一個元素增加一條信息

19 var first = document.getElementById("first");

20 addMessage(first, "Page loading");

21 </>

2223 <ul id="second"> </ul>

2425 <>

26 document.body.addEventListener("mousemove", function() { ?--- 為body附上鼠標移動事件處理函數(shù)

27 var second = document.getElementById("second");

28 addMessage(second, "Event: mousemove");

29 });

30 document.body.addEventListener("click", function(){ ?---

31 var second = document.getElementById("second");

32 addMessage(second, "Event: click");

33 });

34 </>

35 </body>

36</html>

清單1.1首先定義了兩條CSS 規(guī)則,即#first和#second,其指定了ID為first和second兩個元素的文字顏色(從而使我們方便地區(qū)分兩者)。隨后用first這個id定義了一個列表元素:1<ul id="first"></ul>然后定義一個addMessage函數(shù),每當調(diào)用該函數(shù)都會創(chuàng)建一個新的列表項元素,為其設(shè)置文字內(nèi)容,然后將其附加到一個現(xiàn)有的元素上:

1function addMessage(element, message){

2 var messageElement = document.("li");

3 messageElement.textContent = message;

4 element.(messageElement);

5}

如下所示,通過使用內(nèi)置的方法getElementById來從文檔中獲取ID為first的元素,然后為該元素添加一條信息,用于告知頁面正在加載中:

1var first = document.getElementById("first");

2addMessage(first, "Page loading");

然后我們又定義了一個列表元素,這次給該列表賦予的ID屬性為second:1<ul id="second"></ul>最后將這兩個事件處理器附加到Web頁面的body上。每當用戶移動鼠標,鼠標移動事件處理器就會被執(zhí)行,然后該處理器調(diào)用addMessage方法,為第二個列表元素加上一句話“Event: mousemove”。

1document.body.addEventListener("mousemove", function() {

2 var second = document.getElementById("second");

3 addMessage(second, "Event: mousemove");

4});

我們還注冊了一個單擊事件處理器,每當用戶單擊頁面就會輸出該消息“Event: click”,并添加至第二個列表元素中。

1document.body.addEventListener("click", function(){

2 var second = document.getElementById("second");

3 addMessage(second, "Event: click");

4});

該應用的運行結(jié)果和交互如圖1.2所示。

我們還會用這個例子來展示W(wǎng)eb應用生命周期階段之間的不同之處。讓我們從頁面構(gòu)建階段開始講起。

圖1.2 清單1.1中的代碼運行后,用戶的動作會被記錄為消息

1.2 頁面構(gòu)建階段當Web應用能被展示或交互之前,其頁面必須根據(jù)服務器獲取的響應(通常是HTML、CSS和Java代碼)來構(gòu)建。頁面構(gòu)建階段的目標是建立Web應用的UI,其主要包括兩個步驟:

1.解析HTML代碼并構(gòu)建文檔對象模型 (DOM);

2.執(zhí)行Java代碼。

步驟1會在瀏覽器處理HTML節(jié)點的過程中執(zhí)行,步驟二會在HTML解析到一種特殊節(jié)點——腳本節(jié)點(包含或引用Java代碼的節(jié)點)時執(zhí)行。頁面構(gòu)建階段中,這兩個步驟會交替執(zhí)行多次,如圖1.3所示。

圖1.3 頁面構(gòu)建階段從瀏覽器接收頁面代碼開始。其執(zhí)行分為兩個步驟:HTML解析和DOM構(gòu)建,以及Java代碼的執(zhí)行

1.2.1 HTML解析和DOM構(gòu)建頁面構(gòu)建階段始于瀏覽器接收HTML代碼時,該階段為瀏覽器構(gòu)建頁面UI的基礎(chǔ)。通過解析收到的HTML代碼,構(gòu)建一個個HTML元素,構(gòu)建DOM。在這種對HTML結(jié)構(gòu)化表示的形式中,每個HTML元素都被當作一個節(jié)點。如圖1.4所示,直到遇到第一個腳本元素,示例頁面都在構(gòu)建DOM。

注意圖1.4中的節(jié)點是如何組織的,除了第一個節(jié)點——html根節(jié)點(序號1)以外,所有節(jié)點都只有一個父節(jié)點。例如,head節(jié)點(序號2)父節(jié)點為html節(jié)點(序號1)。同時,一個節(jié)點可以有任意數(shù)量的子節(jié)點。例如,html節(jié)點(序號1)有兩個孩子節(jié)點:head節(jié)點(序號2)和body節(jié)點。同一個元素的孩子節(jié)點被稱作兄弟節(jié)點。(head節(jié)點和body節(jié)點是兄弟節(jié)點)盡管DOM是根據(jù)HTML來創(chuàng)建的,兩者緊密聯(lián)系,但需要強調(diào)的是,它們兩者并不相同。你可以把HTML代碼看作瀏覽器頁面UI構(gòu)建初始DOM的藍圖。為了正確構(gòu)建每個DOM,瀏覽器還會修復它在藍圖中發(fā)現(xiàn)的問題。讓我們看下面的示例,如圖1.5所示。

圖1.4 當瀏覽器遇到第一個腳本元素時,它已經(jīng)用多個HTML元素(右邊的節(jié)點)創(chuàng)建了一個DOM樹

圖1.5展示了一個簡單的錯誤HTML代碼示例,頁面中的head元素中錯誤地包含了一個paragraph元素。head元素的一般用途是展示頁面的總體信息,例如,頁面標題、字符編碼和外部樣式腳本,而不是用于類似本例中的定義頁面內(nèi)容。故而這里出現(xiàn)了錯誤,瀏覽器靜默修復錯誤,將段落元素放入了理應放置頁面內(nèi)容的body元素中,構(gòu)造了正確的DOM(如圖1.5右側(cè))。

圖1.5 瀏覽器修正了錯誤的HTML代碼

HTML規(guī)范和DOM規(guī)范

 當前HTML的版本是HTML5, 可以通過 https://html.spec.whatwg.org/ 查看當前版本中有哪些可用特性。你若需要更易讀的文檔,我們向你推薦Mozilla的HTML5指南,可通過https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5 查看。而另一方面,DOM的發(fā)展則相對緩慢。當前的DOM版本是DOM3,可以通過 https://dom.spec.whatwg.org/ 查看該標準。同樣,Mozilla也為DOM提供了一份報告,可以通過https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model 進行查看。

在頁面構(gòu)建階段,瀏覽器會遇到特殊類型的HTML元素——腳本元素,該元素用于包括Java代碼。每當解析到腳本元素時,瀏覽器就會停止從HTML構(gòu)建DOM,并開始執(zhí)行Java代碼。

1.2.2 執(zhí)行Java代碼所有包含在腳本元素中的Java代碼由瀏覽器的Java引擎執(zhí)行,例如,F(xiàn)irefox的Spidermonkey引擎, Chrome 和 Opera和 V8引擎和Edge的(IE的)Chakra引擎。由于代碼的主要目的是提供動態(tài)頁面,故而瀏覽器通過全局對象提供了一個API 使Java引擎可以與之交互并改變頁面內(nèi)容。

Java中的全局對象瀏覽器暴露給Java 引擎的主要全局對象是window對象,它代表了包含著一個頁面的窗口。window對象是獲取所有其他全局對象、全局變量(甚至包含用戶定義對象)和瀏覽器API的訪問途徑。全局window對象最重要的屬性是document,它代表了當前頁面的DOM。通過使用這個對象,Java代碼就能在任何程度上改變DOM,包括修改或移除現(xiàn)存的節(jié)點,以及創(chuàng)建和插入新的節(jié)點。

讓我們看看清單1.1中所示的代碼片段:

1var first = document.getElementById("first");

這個示例中使用全局document對象來通過ID選擇一個元素,然后將該元素賦值給變量first。隨后我們就能在該元素上用Java代碼來對其作各種操作,例如改變其文字內(nèi)容,修改其屬性,動態(tài)創(chuàng)建和增加新孩子節(jié)點,甚至可以從DOM上將該元素移除。

瀏覽器API 本文自始至終都會描述一系列瀏覽器內(nèi)置對象和函數(shù)(例如,window和document)。不過很遺憾,瀏覽器所支持的全部特性已經(jīng)超出本文探討Java的范圍。幸好Mozilla為我們提供支持,通過https://developer.mozilla.org/en-US/docs/Web/API,你可以查找到WebAPI接口的當前狀態(tài)。

對瀏覽器提供的基本全局對象有了基本了解后,我們可以開始看看Java代碼中兩種不同類型的定義方式。

Java代碼的不同類型我們已能大致區(qū)分出兩種不同類型的Java代碼:全局代碼和函數(shù)代碼。清單1.2會幫你理解這兩種類型代碼的不同。

清單1.2 Java全局代碼和函數(shù)代碼

1<>

2 function addMessage(element, message){

3 var messageElement = document.("li");

4 messageElement.textContent = message; ?--- 函數(shù)代碼指的是包含在函數(shù)中的代碼

5 element.(messageElement);

6 }

7 var first = document.getElementById("first");

8 addMessage(first, "Page loading"); ?--- 全局代碼指的是位于函數(shù)之外的代碼

9</>

這兩類代碼的主要不同是它們的位置:包含在函數(shù)內(nèi)的代碼叫作函數(shù)代碼,而在所有函數(shù)以外的代碼叫作全局代碼。

這兩種代碼在執(zhí)行中也有不同(隨后你將能看到一些其他的不同)。全局代碼由Java引擎(后續(xù)會作更多解釋)以一種直接的方式自動執(zhí)行,每當遇到這樣的代碼就一行接一行地執(zhí)行。例如,在清單1.2中,定義在addMessage函數(shù)中的全局代碼片段使用內(nèi)置方法getElementById來獲取ID為first的元素,然后再調(diào)用addMessage函數(shù),如圖1.6所示,每當遇到這些代碼就會一個個執(zhí)行。

圖1.6 執(zhí)行Java代碼時的程序執(zhí)行流

反過來,若想執(zhí)行函數(shù)代碼,則必須被其他代碼調(diào)用:既可以是全局代碼(例如,由于全局代碼的執(zhí)行過程中執(zhí)行了addMessage函數(shù)代碼,所以addMessage函數(shù)得意被調(diào)用),也可以是其他函數(shù),還可以由瀏覽器調(diào)用(后續(xù)會作更多解釋)。

在頁面構(gòu)建階段執(zhí)行Java代碼當瀏覽器在頁面構(gòu)建階段遇到了腳本節(jié)點,它會停止HTML到DOM的構(gòu)建,轉(zhuǎn)而開始執(zhí)行Java代碼,也就是執(zhí)行包含在腳本元素的全局Java 代碼 (以及由全局代碼執(zhí)行中調(diào)用的函數(shù)代碼)。讓我們看看清單1.1中的示例。

圖1.7顯示了在全局Java代碼被執(zhí)行后DOM的狀態(tài)。讓我們仔細看看這個執(zhí)行過程。首先定義了一個addMessage函數(shù):

1<>

2 function addMessage(element, message){

3 var messageElement = document.("li");

4 messageElement.textContent = message; ?--- 函數(shù)代碼指的是包含在函數(shù)中的代碼

5 element.(messageElement);

6 }

7 var first = document.getElementById("first");

8 addMessage(first, "Page loading"); ?--- 全局代碼指的是位于函數(shù)之外的代碼

9</>

然后通過全局document對象上的getElementById方法從DOM上獲取了一個元素:1var first = document.getElementById("first");

這段代碼后緊跟著對函數(shù)addMessage 的調(diào)用:

1addMessage(first, "Page loading");

這條代碼創(chuàng)建了一個新的li元素,然后修改了其中的文字內(nèi)容,最后將其插入DOM中。

圖1.7 當執(zhí)行了腳本元素中的Java代碼后,頁面中的DOM結(jié)構(gòu)

這個例子中,Java通過創(chuàng)建一個新元素并將其插入DOM節(jié)點修改了當前的DOM結(jié)構(gòu)。一般來說,Java 代碼能夠在任何程度上修改DOM結(jié)構(gòu):它能創(chuàng)建新的接單或移除現(xiàn)有DOM節(jié)點。但它依然不能做某些事情,例如選擇和修改還沒被創(chuàng)建的節(jié)點。這就是為什么要把元素放在頁面底部的原因。如此一來,我們就不必擔心是否某個HTML元素已經(jīng)加載為DOM。

一旦Java引擎執(zhí)行到了腳本元素中(如圖1.5中的addMessage函數(shù)返回)Java代碼的最后一行,瀏覽器就退出了Java執(zhí)行模式,并繼將余下的HTML構(gòu)建為DOM節(jié)點。在這期間,如果瀏覽器再次遇到腳本元素,那么從HTML到DOM的構(gòu)建再次暫停,Java運行環(huán)境開始執(zhí)行余下的Java代碼。需要重點注意:Java應用在此時依然會保持著全局狀態(tài)。所有在某個Java代碼執(zhí)行期間用戶創(chuàng)建的全局變量都能正常地被其他腳本元素中的Java代碼所訪問到。其原因在于全局window對象會存在于整個頁面的生存期之間,在它上面存儲著所有的Java變量。只要還有沒處理完的HTML元素和沒執(zhí)行完的Java代碼,下面兩個步驟都會一直交替執(zhí)行。

1.將HTML構(gòu)建為DOM。

2.執(zhí)行Java代碼。

最后,當瀏覽器處理完所有HTML元素后,頁面構(gòu)建階段就結(jié)束了。隨后瀏覽器就會進入應用生命周期的第二部分:事件處理。

1.3 事件處理客戶端Web 應用是一種GUI應用,也就是說這種應用會對不同類型的事件作響應,如鼠標移動、單擊和鍵盤按壓等。因此,在頁面構(gòu)建階段執(zhí)行的Java代碼,除了會影響全局應用狀態(tài)和修改DOM外,還會注冊事件監(jiān)聽器(或處理器)。這類監(jiān)聽器會在事件發(fā)生時,由瀏覽器調(diào)用執(zhí)行。有了這些事件處理器,我們的應用也就有了交互能力。在詳細探討注冊事件處理器之前,讓我們先從頭到尾看一遍事件處理器的總體 思想。

1.3.1 事件處理器概覽瀏覽器執(zhí)行環(huán)境的核心思想基于:同一時刻只能執(zhí)行一個代碼片段,即所謂的單線程執(zhí)行模型。想象一下在銀行柜臺前排隊,每個人進入一支隊伍等待叫號并“處理”。但Java則只開啟了一個營業(yè)柜臺!每當輪到某個顧客時(某個事件),只能處理該位顧客。

你所需要的僅僅是一個在營業(yè)柜臺(所有人都在這個柜臺排隊?。┑穆殕T為你處理工作,幫你訂制全年的財務計劃。當一個事件抵達后,瀏覽器需要執(zhí)行相應的事件處理函數(shù)。這里不保證用戶總會極富耐心地等待很長時間,直到下一個事件觸發(fā)。所以,瀏覽器需要一種方式來跟蹤已經(jīng)發(fā)生但尚未處理的事件。為實現(xiàn)這個目標,瀏覽器使用了事件隊列,如圖1.8所示。

所有已生成的事件(無論是用戶生成的,例如鼠標移動或鍵盤按壓,還是服務器生成的,例如Ajax事件)都會放在同一個事件隊列中,以它們被瀏覽器檢測到的順序排列。如圖1.8的中部所示,事件處理的過程可以描述為一個簡單的流程圖。

瀏覽器檢查事件隊列頭; 如果瀏覽器沒有在隊列中檢測到事件,則繼續(xù)檢查; 如果瀏覽器在隊列頭中檢測到了事件,則取出該事件并執(zhí)行相應的事件處理器(如果存在)。在這個過程中,余下的事件在事件隊列中耐心等待,直到輪到它們被處理。

由于一次只能處理一個事件,所以我們必須格外注意處理所有事件的總時間。執(zhí)行需要花費大量時間執(zhí)行的事件處理函數(shù)會導致Web應用無響應?。ㄈ绻犉饋磉€不太明確,不要擔心,以后我們還會學習事件循環(huán),再看看它是如何損害Web應用在感受上的性能的)。

圖1.8 客戶端Web應用的周期從用戶指定某個網(wǎng)站地址(或單擊某個鏈接)開始。

其由兩個步驟組成:頁面構(gòu)建和事件處理

重點注意瀏覽器在這個過程中的機制,其放置事件的隊列是在頁面構(gòu)建階段和事件處理階段以外的。這個過程對于決定事件何時發(fā)生并將其推入事件隊列很重要,這個過程不會參與事件處理線程。

事件是異步的事件可能會以難以預計的時間和順序發(fā)生(強制用戶以某個順序按鍵或單擊是非常奇怪的)。我們對事件的處理,以及處理函數(shù)的調(diào)用是異步的。如下類型的事件會在其他類型事件中發(fā)生。

瀏覽器事件,例如當頁面加載完成后或無法加載時; 網(wǎng)絡(luò)事件,例如來自服務器的響應(Ajax事件和服務器端事件); 用戶事件,例如鼠標單擊、鼠標移動和鍵盤事件; 計時器事件,當timeout時間到期或又觸發(fā)了一次時間間隔。

Web應用的Java代碼中,大部分內(nèi)容都是對上述事件的處理!

事件處理的概念是Web應用的核心,你在本文中的例子會反復看到:代碼的提前建立是為了在之后的某個時間點執(zhí)行。除了全局代碼,頁面中的大部分代碼都將作為某個事件的結(jié)果執(zhí)行。

在事件能被處理之前,代碼必須要告知瀏覽器我們要處理特定事件。接下來看看如何注冊事件處理器。

1.3.2 注冊事件處理器前面已經(jīng)講過了,事件處理器是當某個特定事件發(fā)生后我們希望執(zhí)行的函數(shù)。為了達到這個目標,我們必須告知瀏覽器我們要處理哪個事件。這個過程叫作注冊事件處理器。在客戶端Web應用中,有兩種方式注冊事件。

通過把函數(shù)賦給某個特殊屬性; 通過使用內(nèi)置addEventListener方法。

例如,編寫如下代碼,將一個函數(shù)賦值給window對象上的某個特定屬性:

1window. = function(){};

通過這種方式,事件處理器就會注冊到load事件上(當DOM已經(jīng)就緒并全部構(gòu)建完成,就會觸發(fā)這個事件)。(如果你對賦值操作符右邊的記法有些困惑,不要擔心,隨后的章節(jié)中我們會細致地講述函數(shù))類似,如果我們想要為在文檔中body元素的單擊事件注冊處理器,我們可以輸入下述代碼:

1document.body.onclick = function(){};

把函數(shù)賦值給特殊屬性是一種簡單而直接的注冊事件處理器方式。但是,我們并不推薦你使用這種方式來注冊事件處理器,這是因為這種做法會帶來缺點:對于某個事件只能注冊一個事件處理器。也就是說,一不小心就會將上一個事件處理器改寫掉。幸運的是,還有一種替代方案:addEventListener方法讓我們能夠注冊盡可能多的事件,只要我們需要。如下清單使用了清單1.3中的示例,向你展示這種便捷的用法。

清單1.3 注冊事件處理器

1<>

2 document.body.addEventListener("mousemove", function() { ?--- 為mousemove事件注冊處理器

3 var second = document.getElementById("second");

4 addMessage(second, "Event: mousemove");

5 });

6 document.body.addEventListener("click", function(){ ?--- 為click事件注冊處理器

7 var second = document.getElementById("second");

8 addMessage(second, "Event: click");

9 });

10</>

本例中使用了某個HTML元素上的內(nèi)置的方法addEventListener,并在函數(shù)中指定了事件的類型(mousemove事件或click)和事件的處理器。這意味著當鼠標從頁面上移動后,瀏覽器會調(diào)用該函數(shù)添加一條消息到ID位second的list元素上,"Event: mousemove"(類似,當body被單擊時,"Event: click"也會被添加到同樣的元素上)。 現(xiàn)在你學習了如何創(chuàng)建事件處理器,讓我們回憶下前面看到的簡單流程圖,然后仔細看看事件是如何被處理的。

1.3.3 處理事件事件處理背后的的主要思想是:當事件發(fā)生時,瀏覽器調(diào)用相應的事件處理器。如前面提到的,由于單線程執(zhí)行模型,所以同一時刻只能處理一個事件。任何后面的事件都只能在當前事件處理器完全結(jié)束執(zhí)行后才能被處理!

讓我們回到清單1.1中的應用。圖1.9展示了在用戶快速移動和單擊鼠標時的執(zhí)行情況。

讓我們看看這里發(fā)生了什么。為了響應用戶的動作,瀏覽器把鼠標移動和單擊事件以它們發(fā)生的次序放入事件隊列:第一個是鼠標移動事件,第二個是單擊事件序號1。

在事件處理階段中,事件循環(huán)會檢查隊列,其發(fā)現(xiàn)隊列的前面有一個鼠標移動事件,然后執(zhí)行了相應的事件處理器序號2。當鼠標移動事件處理器處理完畢后,輪到了等待在隊列中的單擊事件。當鼠標移動事件處理器函數(shù)的最后一行代碼執(zhí)行完畢后,Java引擎退出事件處理器函數(shù),鼠標移動事件完整地處理了序號3,事件循環(huán)再次檢查隊列。這一次,在隊列的最前面,事件循環(huán)發(fā)現(xiàn)了鼠標單擊事件并處理了該事件。一旦單擊處理器執(zhí)行完成,隊列中不再有新的事件,事件循環(huán)就會繼續(xù)循環(huán),等待處理新到來的事件。這個循環(huán)會一直執(zhí)行到用戶關(guān)閉了Web應用。

圖1.9 兩個事件——鼠標移動和單擊中的事件處理階段示例

現(xiàn)在我們有了個總體的認識,理解了事件處理階段的所有步驟。讓我們看看這個過程是如何影響DOM的(如圖1.10所示)。執(zhí)行鼠標移動處理器時會選擇第二個列表元素,其ID為second。

圖1.10 當鼠標移動和鼠標點擊事件都處理完成后,實例應用的DOM樹結(jié)構(gòu)

然后通過使用addMessage,使用文字“Event: mousemove”添加了一個新的列表項元素序號1。一旦鼠標移動處理器結(jié)束后,事件循環(huán)執(zhí)行單擊事件處理器,從而創(chuàng)建了另一個列表元素序號2,并附加在ID為second的第二個列表元素后。

對Web應用客戶端的生命周期有了清晰的理解后,本文的下一部分,我們會開始聚焦于Java語言,理清函數(shù)的來龍去脈。

1.4 小結(jié)瀏覽器接收的HTML代碼用作創(chuàng)建DOM的藍圖,它是客戶端Web應用結(jié)構(gòu)的內(nèi)部展示階段。 我們使用Java代碼來動態(tài)地修改DOM以便給Web應用帶來動態(tài)行為。 客戶端Web應用的執(zhí)行分為兩個階段。頁面構(gòu)建代碼是用于創(chuàng)建DOM的,而全局Java代碼是遇到節(jié)點時執(zhí)行的。在這個執(zhí)行過程中,Java代碼能夠以任意程度改變當前的DOM,還能夠注冊事件處理器——事件處理器是一種函數(shù),當某個特定事件(例如,一次鼠標單擊或鍵盤按壓)發(fā)生后會被執(zhí)行。注冊事件處理器很容易:使用內(nèi)置的addEventListener方法。 事件處理——在同一時刻,只能處理多個不同事件中的一個,處理順序是事件生成的順序。事件處理階段大量依賴事件隊列,所有的事件都以其出現(xiàn)的順序存儲在事件隊列中。事件循環(huán)會檢查實踐隊列的隊頭,如果檢測到了一個事件,那么相應的事件處理器就會被調(diào)用。

1.5 練習1.客戶端Web應用的兩個生命周期階段是什么?

2.相比將事件處理器賦值給某個特定元素的屬性上,使用addEventListener方法來注冊事件處理器的優(yōu)勢是什么?

3.Java引擎在同一時刻能處理多少個事件?

4.事件隊列中的事件是以什么順序處理的?

1 </div>

2 <p id="copyright-declare">

3 本文僅用于學習和交流目的,不代表異步社區(qū)觀點。非商業(yè)轉(zhuǎn)載請注明作譯者、出處,并保留本文的原始鏈接。

4 </p>

5 </div>

本文摘自《Java忍者秘籍 第2版》

《Java忍者秘籍 第2版》

[美] John,Resig(萊西格),Bear,Bibeault(貝比奧特),Josip ... 著

點擊封面購買紙書

Java語言非常重要,相關(guān)的技術(shù)圖書也很多,但至今市面沒有一本對Java語言的重要部分(函數(shù)、閉包和原型)進行深入、全面介紹的圖書,也沒有一本講述跨瀏覽器代碼編寫的圖書。而本書彌補了這一空缺,是由jQuery庫創(chuàng)始人編寫的一本深入剖析Java語言的書?!禞ava 忍者秘籍(第2版)》使用實際的案例清晰地詮釋每一個核心概念和技術(shù)。本書向讀者介紹了如何掌握 Java 核心的概念,諸如函數(shù)、閉包、對象、原型和 promise,同時還介紹了 Java API, 包括 DOM、事件和計時器。你將學會測試、跨瀏覽器開發(fā),所有這些都是高級Java開發(fā)者應該掌握的技能。

延伸推薦2018年1月重磅新書小學生開始學Python,最接近AI的編程語言:安利一波Python書單政策升溫:大家都在學大數(shù)據(jù),一大波好書推薦一本基于Python語言的Selenium自動化測試書 8本新書,送出一本你喜歡的AI經(jīng)典書單| 入門人工智能該讀哪些書?

點擊關(guān)鍵詞閱讀更多新書:Python|機器學習|Kotlin|Java|移動開發(fā)|機器人|有獎活動|Web前端|書單

在“異步圖書”后臺回復“關(guān)注”,即可免費獲得2000門在線視頻課程;推薦朋友關(guān)注根據(jù)提示獲取贈書鏈接,免費得異步圖書一本。趕緊來參加哦!

掃一掃上方二維碼,回復“關(guān)注”參與活動!

點擊閱讀原文購買《Java忍者秘籍 第2版》

閱讀原文

內(nèi)部類不是很好理解,但說白了其實也就是一個類中還包含著另外一個類。

如同一個人是由大腦、肢體、器官等身體結(jié)果組成,而內(nèi)部類相當于其中的某個器官之一,例如心臟:它也有自己的屬性和行為(血液、跳動)。

顯然,此處不能單方面用屬性或者方法表示一個心臟,而需要一個類。

而心臟又在人體當中,正如同是內(nèi)部類在外部內(nèi)當中。

實例1:內(nèi)部類的基本結(jié)構(gòu)

//外部類 class Out { private int age = 12; //內(nèi)部類 class In { public void print() { System.out.println(age); } } } public class Demo { public static void main(String[] args) { Out.In in = new Out().new In(); in.print(); //或者采用下種方式訪問 /* Out out = new Out(); Out.In in = out.new In(); in.print(); */ } }

運行結(jié)果:12

從上面的例子不難看出,內(nèi)部類其實嚴重破壞了良好的代碼結(jié)構(gòu),但為什么還要使用內(nèi)部類呢?

因為內(nèi)部類可以隨意使用外部類的成員變量(包括私有)而不用生成外部類的對象,這也是內(nèi)部類的唯一優(yōu)點。

如同心臟可以直接訪問身體的血液,而不是通過醫(yī)生來抽血

程序編譯過后會產(chǎn)生兩個.class文件,分別是Out.class和Out$In.class。

其中$代表了上面程序中Out.In中的那個 。

Out.In in = new Out().new In()可以用來生成內(nèi)部類的對象,這種方法存在兩個小知識點需要注意:

1、開頭的Out是為了標明需要生成的內(nèi)部類對象在哪個外部類當中;

2、必須先有外部類的對象才能生成內(nèi)部類的對象,因為內(nèi)部類的作用就是為了訪問外部類中的成員變量。

實例2:內(nèi)部類中的變量訪問形式

class Out { private int age = 12; class In { private int age = 13; public void print() { int age = 14; System.out.println("局部變量:" + age); System.out.println("內(nèi)部類變量:" + this.age); System.out.println("外部類變量:" + Out.this.age); } } } public class Demo { public static void main(String[] args) { Out.In in = new Out().new In(); in.print(); } }

運行結(jié)果:局部變量:14;內(nèi)部類變量:13;外部類變量:12

從實例1中可以發(fā)現(xiàn),內(nèi)部類在沒有同名成員變量和局部變量的情況下,內(nèi)部類會直接訪問外部類的成員變量,而無需指定Out.this.屬性名。

否則,內(nèi)部類中的局部變量會覆蓋外部類的成員變量。

而訪問內(nèi)部類本身的成員變量可用this.屬性名,訪問外部類的成員變量需要使用Out.this.屬性名。

實例3:靜態(tài)內(nèi)部類

class Out { private static int age = 12; static class In { public void print() { System.out.println(age); } } } public class Demo { public static void main(String[] args) { Out.In in = new Out.In(); in.print(); } }

運行結(jié)果:12

可以看到,如果用static 將內(nèi)部內(nèi)靜態(tài)化,那么內(nèi)部類就只能訪問外部類的靜態(tài)成員變量,具有局限性。

其次,因為內(nèi)部類被靜態(tài)化,因此Out.In可以當做一個整體看,可以直接new 出內(nèi)部類的對象(通過類名訪問static,生不生成外部類對象都沒關(guān)系)。

實例4:私有內(nèi)部類

class Out { private int age = 12; private class In { public void print() { System.out.println(age); } } public void outPrint() { new In().print(); } } public class Demo { public static void main(String[] args) { //此方法無效 /* Out.In in = new Out().new In(); in.print(); */ Out out = new Out(); out.outPrint(); } }

運行結(jié)果:12

如果一個內(nèi)部類只希望被外部類中的方法操作,那么可以使用private聲明內(nèi)部類。

上面的代碼中,我們必須在Out類里面生成In類的對象進行操作,而無法再使用Out.In in = new Out().new In() 生成內(nèi)部類的對象。

也就是說,此時的內(nèi)部類只有外部類可控制。

如同是,我的心臟只能由我的身體控制,其他人無法直接訪問它。

實例5:方法內(nèi)部類

class Out { private int age = 12; public void Print(final int x) { class In { public void inPrint() { System.out.println(x); System.out.println(age); } } new In().inPrint(); } } public class Demo { public static void main(String[] args) { Out out = new Out(); out.Print(3); } }

運行結(jié)果:3;12

在上面的代碼中,我們將內(nèi)部類移到了外部類的方法中,然后在外部類的方法中再生成一個內(nèi)部類對象去調(diào)用內(nèi)部類方法。

如果此時我們需要往外部類的方法中傳入?yún)?shù),那么外部類的方法形參必須使用final定義。

至于final在這里并沒有特殊含義,只是一種表示形式而已。

最后,覺得不錯,大家一起分享給其他的同學吧

Java新人自學交流群:202250194

Java 2圖形設(shè)計――卷Ⅱ:SWING(附CD)相關(guān)推薦
  • 相關(guān)百科
  • 相關(guān)知識
  • 相關(guān)專欄

最新詞條

安徽省政采項目管理咨詢有限公司 數(shù)字景楓科技發(fā)展(南京)有限公司 懷化市人民政府電子政務管理辦公室 河北省高速公路京德臨時籌建處 中石化華東石油工程有限公司工程技術(shù)分公司 手持無線POS機 廣東合正采購招標有限公司 上海城建信息科技有限公司 甘肅鑫禾國際招標有限公司 燒結(jié)金屬材料 齒輪計量泵 廣州采陽招標代理有限公司河源分公司 高鋁碳化硅磚 博洛尼智能科技(青島)有限公司 燒結(jié)剛玉磚 深圳市東海國際招標有限公司 搭建香蕉育苗大棚 SF計量單位 福建省中億通招標咨詢有限公司 泛海三江 威海鼠尾草 Excel 數(shù)據(jù)處理與分析應用大全 廣東國咨招標有限公司 甘肅中泰博瑞工程項目管理咨詢有限公司 拆邊機 山東創(chuàng)盈項目管理有限公司 當代建筑大師 廣西北纜電纜有限公司 大山檳榔 上海地鐵維護保障有限公司通號分公司 舌花雛菊 甘肅中維國際招標有限公司 華潤燃氣(上海)有限公司 湖北鑫宇陽光工程咨詢有限公司 GB8163標準無縫鋼管 中國石油煉化工程建設(shè)項目部 韶關(guān)市優(yōu)采招標代理有限公司 莎草目 電梯平層準確度 建設(shè)部關(guān)于開展城市規(guī)劃動態(tài)監(jiān)測工作的通知 廣州利好來電氣有限公司 四川中澤盛世招標代理有限公司