傳送門 ☞ 輪子的專欄 ☞ 轉載請注明 ☞ http://blog.csdn.net/leverage_1229
前面我們實作了TomJetty響應無參請求靜态頁面的功能,但真實情況下,幾乎所有請求都得攜帶參數。不能處理使用者參數請求的Web伺服器就好比溫室裡的花朵,始終上不了台面。是以本節我們将為TomJetty加入響應使用者參數的功能。此外,前面我們使用的送出請求的方式都是GET方式,但在實際情況下,POST方式使用的更廣泛,是以我們也将給TomJetty增加響應POST請求的能力。
1擴充RequestHeader類
1.1在RequestHeader類中新增parameter屬性,用于标示請求頭中客戶請求的參數,并提供對應的getter/setter方法
private String parameter;
public String getParameter() {
return parameter;
}
public void setParameter(String parameter) {
this.parameter = parameter;
}
1.2在RequestHeaderParserImpl類的parse()方法中加入如下片段,用于解析在GET和POST兩種送出方式下的請求頭的參數部分,并将其儲存到requestHeader對象中
String parameter = null;
try {
if(method.equalsIgnoreCase("post")) {
parameter = txt.substring(txt.lastIndexOf("\n") + 1, txt.length());
} else if(method.equalsIgnoreCase("get")) {
parameter = url.substring(url.indexOf("?") + 1, url.length());
url = url.substring(0, url.indexOf("?"));
}
} catch (Exception e) {
}
header.setParameter(parameter);
2自定義請求參數類
建立一個Parameter類,采用鍵值對的方式存儲請求攜帶的參數。如果直接使用HashMap資料結構進行存儲,由于其底層的設計原則,将無法避免用戶端浏覽器重複送出的問題。
package cn.lynn.tomjetty;
public class Parameter {
private String key;
private String value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Parameter other = (Parameter) obj;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}
3封裝請求對象
前面我們講過,為Java語言服務的Web容器,實際上裝載的是Servlet(Java服務端應用程式)。打開Java EE幫助文檔,檢索Servlet關鍵字。可以看到Servlet實際上被設計成一個接口。其設計層次如下:
它有三個實作子類,分别對應于不同的網絡協定,這裡我們隻關注HttpServlet。此外,它還聲明了五個方法,分别是:destroy()、getServletConfig()、getServletInfo()、init()、service(ServletRequest req, ServletResponse res),學過JSP的同學知道,service()方法才是Servlet容器響應請求的核心方法。看到這裡,我們将Servlet相關HTTP協定的架構設計思想引入到TomJetty中。
3.1.建立一個Servlet接口,并聲明一個service()方法
package cn.lynn.tomjetty;
public interface IServlet {
public void service(Request req, Response res);
}
3.2新增一個IServlet接口的HTTP協定實作類HttpServletImpl,并提供doGet()方法和doPost()方法(方法體暫時為空)分别處理來自用戶端浏覽器的兩種不同的送出方式
package cn.lynn.tomjetty;
public class HttpServletImpl implements IServlet {
public void service(Request req, Response res) {
}
public void doGet(Request req, Response res) {
}
public void doPost(Request req, Response res) {
}
}
那麼為什麼要添加這兩個方法?通過檢視Java EE的HttpServlet的設計文檔,我們知道HttpServlet也提供了這兩個方法。當然提供的不止這兩個,還有doDelete()、doPut()等,呵呵,想多了,它們不屬于本系列關注的範疇^_^。
我們發現service()方法中傳入參數類型已經不是普通的Request和Response,Servlet對它們進行了封裝。是以我們也照貓畫虎學着做。
3.3建立一個Request類,用于封裝HTTP請求頭和請求參數。并提供對應的存取它們的方法以供外部調用
package cn.lynn.tomjetty;
import java.util.ArrayList;
import java.util.List;
public class Request {
// 引入請求頭
private RequestHeader header;
// 設定參數集合
private List<Parameter> params = new ArrayList<Parameter>();
// 設定請求參數
public void setParameter(String param) {
if(param == null || param.trim().equals("")) {
return;
}
String[] result = param.split("&");
for (int i = 0; i < result.length; i++) {
Parameter parameter = new Parameter();
parameter.setKey(result[i].split("=")[0]);
parameter.setValue((result[i].split("=").length <= 1) ? "" : result[i].split("=")[1]);
params.add(parameter);
}
}
// 擷取請求參數的值
public String getParameterValue(String key) {
String result = null;
for(Parameter parameter : params) {
if(parameter.getKey().equals(key)) {
result = parameter.getValue();
}
}
return result;
}
public RequestHeader getHeader() {
return header;
}
public void setHeader(RequestHeader header) {
this.header = header;
}
}
3.4在TomJetty類的run()方法中加入如下片段,将請求頭和請求參數存放到Request對象中進行統一管理
// 封裝請求頭
Request request = new Request();
request.setParameter(header.getParameter());
request.setHeader(header);
4響應請求參數效果展示
4.1GET方式送出
在IE浏覽器輸入上述位址後回車,控制台列印如下:
RequestHeader [
GET /index.htm HTTP/1.1
Accept: */*
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; KB974488)
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:9527
Connection: Keep-Alive
Cookie: null
parameter: username=lynnli1229&password=123456
]
4.2POST方式送出
建立一個input.htm檔案,在其<body>标簽内編寫一個表單用于POST送出使用者資訊。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="http://127.0.0.1:9527/index.htm" name="form" id="form" method="post">
使用者名:<input name="username" type="text"></br>
密 碼:<input name="password" type="password"></br>
<input name="submit" value="送出" type="submit">
<input name="reset" value="重置" type="reset">
</form>
</body>
</html>
在IE浏覽器輸入上述位址後回車,接着填寫表單項,點選送出按鈕,頁面會導航到index.htm,控制台列印如下:
RequestHeader [
GET /input.htm HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/QVOD, application/QVOD, */*
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; KB974488)
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:9527
Connection: Keep-Alive
Cookie: null
parameter: /input.htm
]
RequestHeader [
POST /index.htm HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/QVOD, application/QVOD, */*
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; KB974488)
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:9527
Connection: Keep-Alive
Cookie: null
parameter: username=lynnli1229&password=123456&submit=%E6%8F%90%E4%BA%A4
]
至此,TomJetty伺服器已經能夠在POST和GET兩種請求送出方式下,都可以為攜帶參數的靜态頁面請求提供服務。然而隻能處理靜态頁面請求的伺服器還是遠遠不夠的,畢竟現階段動态網頁才是主流。是以下一節我們将賦予TomJetty伺服器處理動态網頁的能力。