目錄
一、本篇簡介
本篇記錄Java之HTTP網絡編程,定位於網頁瀏覽器程序設計,與上篇TCP/SSL網頁下載有所不同,接下來將實現通過URL進行網頁的下載以及編程簡易瀏覽器訪問網站。網頁下載程序簡潔清晰,可以訪問網站,獲取界面的源碼;簡易瀏覽器擁有基礎功能,包括訪問網頁,刷新,下載,聽音樂……還有很多可以嘗試的功能,模仿常用的瀏覽器!
基礎知識的學習主要在上一篇,可查看Java之HTTP網絡編程(上篇:TCP/SSL網頁下載)。
二、URL類
上一篇通過TCP/SSL直接發送http請求的程序,對於複雜的地址,例如指向具體頁面的地址,無法完成網頁下載任務,因此這裏使用Java中提供的URL類,解決網頁訪問的問題。
URL(Uniform Resource Locator):統一資源定位符,用於表示資源地址,資源如網頁或者FTP地址等。URL的格式爲protocol://資源地址,protocol可以是HTTP、HTTPS、FTP 和 File,資源地址中可以帶有端口號及查詢參數,例如https://www.baidu.com
在java中,URL類用來處理有關URL的內容,並且其封裝有一個InputStream返回類型的openStream()方法,程序就可以讀取這個字節輸入流來獲得對應內容。
URL url = new URL(address);
//獲得url的字節流輸入
InputStream in = url.openStream();
//裝飾成字符輸入流
br = new BufferedReader(new InputStreamReader(in, "utf-8"));
相比於發送HTTP請求頭的方式,使用URL獲取網頁內容顯得更加簡單,返回結果也存在不同之處,接下來介紹具體實現。
三、基於URL類的網頁下載
界面如圖:
這裏的界面實現不再貼出代碼,與之前類似,只需稍作修改。下面給出關鍵的代碼。
1、發送按鈕
在發送按鈕事件中,使用URL類對輸入的URL地址進行解析,指定一“http”開頭的纔是有效的網址,然後使用InputStream包含的方法接收網頁內容。
//網頁請求按鈕事件
btnSend.setOnAction(event -> {
taDisplay.clear();
String domainName=tfSend.getText().trim();
if (!domainName.substring(0,4).equals("http"))
taDisplay.appendText("URL地址輸入不合規則!");
try {
URL url = new URL(domainName);
System.out.println("連接"+domainName+"成功!\n");
InputStream in=url.openStream();
br=new BufferedReader(new InputStreamReader(in,"utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
});
2、接收數據的多線程
可以發現,一按發送按鈕,立即觸發與網站的通信,對方服務器會返回網頁內容,這裏就包括了多次的信息的發送和接收。所以,我們的客戶端需要實現接收網頁數據的多線程,避免阻塞完整內容的接收。
readThread = new Thread(()->{
String receiveMsg=null;//從服務器接收一串字符
try {
while ((receiveMsg=br.readLine())!=null){
String msgTemp = receiveMsg;
Platform.runLater(()->{
taDisplay.appendText(msgTemp+"\n");
});
}
}catch (IOException e){
e.printStackTrace();
}
Platform.runLater(()->{
taDisplay.appendText("對話已關閉!\n");
});
});
readThread.start();
開啓一個接收服務器信息的線程,專門處理接收數據,這部分添加到發送按鈕中,觸發按鈕事件時候便啓動線程,達到完整接收信息的目的。
四、URL網頁下載客戶端
這樣就實現了網頁的下載,相當於一個小工具,獲取網頁的HTML源代碼!
五、編寫web瀏覽器
前面的所有程序都只是實現了網頁文件的下載,沒有經過渲染得到瀏覽網頁的效果,下面就實現網頁顯示功能,首先認識一下JavaFX的WebEngine、WebView、WebHistory類相關內容,然後實現自己簡單的瀏覽器。
1、WebEngine類
WebEngine類提供了基本的web頁面功能。儘管它並不與用戶直接交互,但它也支持用戶交互,如導航鏈接和提交HTML表單。WebEngine類一次處理一個web頁面,支持加載HTML內容和訪問DOM對象等基本功能,也支持執行JavaScript指令。
創建WebEngine對象的兩個構造方法:空構造和帶一個URL參數的構造。
如果你使用空構造方法來實例化它,那麼URL可以通過WebEngine對象的load()方法來傳入。WebEngine對象實例的getLocation()方法會返回當前加載頁面的URL地址。
2、WebView類
WebView類是Node類的一個擴展。它封裝了WebEngine對象,將HTML內容加入程序的scene中,並且提供各種屬性和方法來應用特效和變換。WebView對象的getEngine()方法返回一個與之關聯的web engine,例如可以這樣使用:
WebView webView = new WebView();
WebEngine webEngine = webView.getEngine();
webEngine.load("https://www.baidu.com");
當load另一個URL,webView就自動加載另外一個頁面。
3、WebHistory類
WebHistory類可獲取已訪問的頁面列表,它表示與WebEngine對象關聯的一個會話歷史記錄。WebEngine.getHistory()方法可以獲取某特定webEngine對象的WebHistory實例。
WebHistory history = webEngine.getHistory();
該歷史記錄基本上是一種特殊類型的列表。類似普通List,該列表也是下標從0開始,每一個條目表示一個已訪問過的頁面並且提供對該頁面相關信息的訪問。該列表可通過getEntries()方法獲得。
該對象的getCurrentIndex()方法返回值表示當前訪問頁面在列表中的索引位置。該對象的go(int index)方法表示頁面的跳轉,例如history.go(-1)就是返回上一個訪問的頁面,history.go(1)表示前進到下一個訪問過的頁面,這兩個方法使用要注意邊界條件判斷,否則會拋出異常,例如已經沒有可回退的頁面記錄,再執行回退方法就拋出異常。
瀏覽器頁面組件如上圖,接下來給出具體關鍵步驟的實現。
六、簡易瀏覽器關鍵步驟代碼
1、首頁加載按鈕
首先,聲明成員變量以及創建Web對象:
private Button fresh=new Button("刷新");
private Button forward=new Button("前進");
private Button backward=new Button("後退");
private Button mainIndex=new Button("首頁");
private Button enter=new Button("跳轉");
private TextField urlSend=new TextField();
WebView webView=new WebView();
WebEngine webEngine=webView.getEngine();
JavaFx窗體可以重用上一篇的內容,這裏只需要將webView組件添加到中央。
borderPane.setCenter(webView);
需要注意的是,實現按鈕的功能,必須符合程序執行邏輯,以免誤操作出現異常,比如“前進”、“後退”按鈕使用中,需要獲取網頁加載列表的邊界長度,才能正常讀取歷史訪問記錄。
因此,在適當的時候禁用相關按鈕可以保證程序正常運行。
forward.setDisable(true);
backward.setDisable(true);
fresh.setDisable(true);
一些準備工作完成之後,開始編寫按鈕事件,相對簡單。
//首頁
mainIndex.setOnAction(event -> {
webEngine.load("https://www.baidu.com");
fresh.setDisable(false);
});
2、刷新按鈕
刷新方法比較粗暴,獲取當前頁面的URL,重新加載該頁面。
//刷新按鈕
fresh.setOnAction(event ->{
WebHistory history=webEngine.getHistory();
// 獲取當前頁面的URL,重新加載該頁面
webEngine.load(history.getEntries().get(history.getCurrentIndex()).getUrl());
});
3、跳轉按鈕
獲取輸入區的URL地址,交給webEngine加載網頁。
//跳轉按鈕
enter.setOnAction(event -> {
String url=urlSend.getText();
if (url!=null){
webEngine.load(url);
backward.setDisable(false);
fresh.setDisable(false);
}
});
4、前進/後退按鈕
“前進”和“後退”按鈕能夠根據實際情況自動禁用和啓用。所以進行歷史記錄條目長度的判斷。
//前進
forward.setOnAction(event -> {
WebHistory history=webEngine.getHistory();
//判斷已訪問頁面數與當前頁面下標大小,再執行前進操作
if (history.getCurrentIndex()+1<history.getEntries().size()){
history.go(1);
backward.setDisable(false);
}
else {
forward.setDisable(true);
}
});
//後退
backward.setOnAction(event -> {
WebHistory history=webEngine.getHistory();
if (history.getCurrentIndex()-1>=0){
history.go(-1);
forward.setDisable(false);
}
else {
backward.setDisable(true);
}
});
5、狀態監聽器
使用webEngine的狀態監聽器,監聽頁面的載入狀態,只要頁面有載入動作,就會觸發其中的代碼。在這個監聽器中設置前進後退按鈕的可用性。
webEngine.getLoadWorker().stateProperty().addListener((observable,oldValue,newValue) -> {
forward.setDisable(false);
backward.setDisable(false);
});
6、效果演示
完整演示視頻
web瀏覽器
如果覺得不錯歡迎“一鍵三連”哦,點贊收藏關注,有問題直接評論,交流學習!
Java之HTTP網絡編程:
我的CSDN博客:https://blog.csdn.net/Charzous/article/details/112254723