1. 程式人生 > 其它 >JavaSE02_Day05(上)-WebServer專案解析web.xml檔案、重構setEntity方法、完成註冊業務

JavaSE02_Day05(上)-WebServer專案解析web.xml檔案、重構setEntity方法、完成註冊業務

一、版本八:解析web.xml檔案

  在http包下新建一個類:HttpContext,使用這個類定義相關Http協議的內容。由於不同的檔案對應的Content-Type值不同,那麼在HttpContext類中定義一個Map。 使用Tomcat安裝目錄的下的conf/web.xml檔案,將裡面配置的所有媒介(介質)型別都解析出來,並初始化HttpContext中mimeMapping的這個Map,使得我們的WebServer也能支援所有的媒介(介質)型別。

步驟1:在專案的pom.xml檔案新增dom4j的依賴

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.tedu</groupId>
<artifactId>webserver01</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
</project>

步驟2:在專案目錄下建立一個目錄,名字為conf,將群檔案中上傳的web.xml複製進來

步驟3:編寫HttpContext類,通過解析web.xml檔案初始化mimeMapping

package cn.tedu.http;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
* 解析web.xml檔案,使用其中的媒介型別
* @author cjn
*
*/
public class HttpContext {
//定義用於儲存媒介型別的Map屬性
private static Map<String, String> mimeMapping =
new HashMap<String, String>();

static {
initMime();
}

/**
* 靜態方法,用於解析web.xml檔案中的媒介型別
* @param args
*/
public static void initMime() {
/*
* 解析web.xml檔案中的媒介型別,
* 然後新增到Map屬性中
*/
try {
SAXReader reader = new SAXReader();
Document document = reader.read(new File("conf/web.xml"));
//獲取根節點
Element root = document.getRootElement();
//獲取根節點中位元組點名字是mime-mapping的節點元素
List<Element> elements = root.elements("mime-mapping");
//獲取mime-mapping節點中子節點對應的內容
for (Element e : elements) {
String key = e.elementText("extension");
String value = e.elementText("mime-type");
//將獲取到的元素資料儲存到屬性Map中
mimeMapping.put(key, value);
}

} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 對外暴露可以根據請求的字尾進行響應的媒介型別value值
* @param args
*/
public static String getMimeType(String extension) {
return mimeMapping.get(extension);
}

public static void main(String[] args) {
//測試
String mimeType = HttpContext.getMimeType("png");
System.out.println(mimeType);
System.out.println("媒介型別的個數:" + mimeMapping.size());

}

}

輸出結果:

image/png
媒介型別的個數:1011

二、版本九:setEntity方法重構

  由於一個響應中包含響應正文時,一定會在響應頭中包含Content-Type和Content-Length。對此,我們直接在HttpResponse的setEntity方法中新增程式碼,根據給定的檔案自動設定這兩個頭,這樣就免去了在外界設定響應正文以後還要額外新增這兩個頭的麻煩。

HttpResponse.java

  public void setEntity(File entity) {
this.entity = entity;

//獲取請求資源的字尾名
String fileName = entity.getName();
int index = fileName.lastIndexOf(".");
String suffix = fileName.substring(index + 1);

/*

* 定義一個Map物件,這個Map中需要新增多個媒介型別作為Map的value值,
* 而key可以根據需要進行請求的資源字尾作為key值,這個Map的主要作用
* 是用於根據使用者的請求不同,進行查詢出不同的媒介型別
*/
String mime = HttpContext.getMimeType(suffix);

//向HttpResponse物件中的headers進行賦值,目的是後期進行傳送響應頭
putHeaders("Content-Type", mime);
putHeaders("Content-Length", entity.length()+"");
}

測試步驟:

(1)啟動服務端,然後開啟瀏覽器,在瀏覽器的位址列處輸入http://localhost:8888/myweb/index.html請求,檢視是否可以顯示一個首頁資源,包括首頁中的圖片,需要觀察瀏覽器中是否有報錯的資訊。

(2)開啟一個新的瀏覽器頁面,在位址列處輸入http://localhost:8888/myweb/qwer.html請求,檢視是否瀏覽器頁面顯示404自定義頁面。

三、版本十:完成註冊業務

使用者開啟註冊頁面,輸入註冊資訊後點擊註冊按鈕,服務端在接受這些資料後寫入檔案中,並響應註冊成功。

頁面完成註冊流程:

步驟1:在webapps/myweb目錄下新建一個註冊頁面reg.html頁面,表單提交的地址指定為reg

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>註冊使用者</title>
</head>
<body>
<center>
<h1>歡迎註冊</h1>
<form action="reg" method="get">
<table border="1">
<tr>
<td>使用者名稱:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密碼:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>暱稱:</td>
<td><input type="text" name="nickname"></td>
</tr>
<tr>
<td>年齡:</td>
<td><input type="text" name="age"></td>
</tr>
<tr>
<td align="center" colspan="2">
<input type="submit" value="註冊">
</td>
</tr>
</table>
</form>
</center>
</body>
</html>

測試:啟動服務端程式,開啟瀏覽器,在瀏覽器的位址列中輸入http://localhost:8888/myweb/reg.html請求路徑,觀察瀏覽器中顯示的頁面內容是否如下圖:

步驟2:由於請求中的url中可能包含使用者提交的資料,對此我們在解析請求時要對url進行進一步解析 將其拆分2部分: 請求路徑與引數部分.並且對引數再次進行進一步解析,得到每個具體的引數。

  • 2.1 重構HttpRequest解析請求行的程式碼

  • 2.2 定義三個屬性:String requestUri;儲存url請求部分、String queryString;儲存url中的引數部分、Map parameters;儲存具體的每一個引數(key:引數名、value:引數值)

  • 2.3 提供一個方法:parseURL ,該方法要對url進行進一步解析,並將解析出來的內容分別設定到 (2.2)中定義的屬性中

  • 2.4 在原來的解析請求行中的方法內,當獲得到url後,就呼叫parseURL,對其進一步解析

  • 2.5 在(2.2)定義的屬性對外提供get方法.

步驟3:建立一個包servlets,定義一個用於處理註冊業務的類RegServlet,並定義一個用於處理註冊的方法service

步驟4:在ClientHandler處理請求的地方再新增一個分支,先根據請求判斷是否為請求註冊業務,如果是請求註冊業務,則例項化一個 RegServlet並呼叫其service方法處理;如果不是,則執行原流程,判斷是否請求一個資源 。

步驟5:在webapps/myweb下新建一個註冊成功頁面:reg_success.html頁面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>註冊成功</title>
</head>
<body>
<h1>恭喜您註冊成功!!!</h1>
</body>
</html>

步驟6:完成RegServlet的service方法,在該方法中首先獲取使用者提交的註冊資訊,並寫入user.dat檔案之後,設定response響應註冊成功頁面

package cn.tedu.servlets;

import java.io.File;
import cn.tedu.http.HttpRequest;
import cn.tedu.http.HttpResponse;

/**
* 處理註冊業務
* @author cjn
*
*/
public class RegServlet {

public void service(HttpRequest request, HttpResponse response) {
/*
* 1.從paramters這個Map中取出對應key的value值
* 2.檢查使用者是否已經註冊過
* 3.將沒有註冊過的使用者資訊儲存到user.dat檔案中
* 4.註冊成功以後,響應一個註冊成功的頁面,反之註冊失敗響應註冊失敗的頁面
* username=包佳奇
* password=123456
* nickname=baozi
* age=30
*/
String userName = request.getParamters("username");
String password = request.getParamters("password");
String nickName = request.getParamters("nickname");
String age = request.getParamters("age");
System.out.println("使用者名稱:" + userName + ",密碼:" + password
+ ",暱稱:" + nickName + ",年齡" + age);

//目前測試沒有響應報空指標異常,給一個響應
response.setEntity(new File("webapps/myweb/reg_success.html"));
}

}

測試:啟動專案的服務端主類,然後開啟瀏覽器,在瀏覽器位址列輸入localhost:8888/myweb/reg.html請求路徑,可以在瀏覽器頁面中檢視到一個註冊頁面,在註冊頁面的輸入框位置新增相關注冊資訊,當點選註冊按鈕時,會跳轉到一個登入成功頁面,在服務端控制檯中沒有任何的報錯資訊,並且可以看到註冊的使用者資訊的列印內容。

有關於將註冊資訊寫入到user.dat檔案中週二完成。

注意:在註冊時年齡填寫不正確,報錯NumberFormatException:For input string:"xxx" 包裝類把字串轉換成數字時會丟擲異常,裡面輸入的不是數字。

四、擴充套件

  URI包括URL(統一資源定位符)和URN(統一資源名稱)