上一篇 博客中我們實現了一個簡單的服務器,真是極其簡單。實際場景中當然不可能只是訪問一下http://localhost:8080/。本篇博客,我們的目的是優化簡單服務器,讓它支持複雜請求。
1. 優化HttpRequest
我們先來看看,目前的服務器對複雜get請求的支持。我們通過瀏覽器訪問地址 http://localhost:8080/hello.do?id=123&name=456 ,控制檯輸出如下:
可以看到,參數還是拼接在地址後面的,我們拿到的並不是純粹的路徑,所以第一個需要優化的地址,就是截取地址和解析參數了。下面是修改後的HttpRequest:
package com.zlyx.easy.server.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
public class HttpRequest {
/**
* 請求方式
*/
private String method;
/**
* http地址
*/
private String httpUrl;
/**
* 請求地址
*/
private String requetUrl;;
/**
* 參數
*/
private Map<String, String> paramMap = new HashMap<String, String>();
public HttpRequest(InputStream in) throws IOException {
InputStreamReader isReader = new InputStreamReader(in);
BufferedReader bufferedReader = new BufferedReader(isReader);
String string = bufferedReader.readLine();
String[] httpInfos = string.split(" ");
this.method = httpInfos[0];
this.httpUrl = httpInfos[1];
int indexOf = httpInfos[1].indexOf("?");
if (indexOf != -1) {
this.requetUrl = httpInfos[1].substring(0, indexOf);
ResoveParams(httpInfos[1].substring(indexOf + 1));
} else {
this.requetUrl = httpInfos[1];
}
}
private void ResoveParams(String str) {
String[] params = str.split("&");
for (String p : params) {
String[] split = p.split("=");
if (split[0] != null) {
paramMap.put(split[0], split[1]);
}
}
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getHttpUrl() {
return httpUrl;
}
public void setHttpUrl(String httpUrl) {
this.httpUrl = httpUrl;
}
public String getRequetUrl() {
return requetUrl;
}
public void setRequetUrl(String requetUrl) {
this.requetUrl = requetUrl;
}
public Map<String, String> getParamMap() {
return paramMap;
}
public void setParamMap(Map<String, String> paramMap) {
this.paramMap = paramMap;
}
@Override
public String toString() {
return "HttpRequest [method=" + method + ", httpUrl=" + httpUrl + ", requetUrl=" + requetUrl + ", paramMap="
+ paramMap + "]";
}
}
修改HttpServlet的doGet方法,如下:
/**
* 處理get請求
*
* @throws IOException
*/
public void doGet() throws IOException {
System.out.println(request);
response.write(String.valueOf(request.hashCode()));
}
重新發起請求,控制檯輸出如下:
可以看到,我們得到了期望的結果。
2. 優化HttpServlet
實際場景中,請求方式有post、get等八種。目前我們只支持doGet,很明顯這是不合理的。所以接下來,我們需要優化這部分內容,支持更多請求類型:
package com.zlyx.easy.server.servlet;
import java.io.IOException;
import java.net.Socket;
import com.zlyx.easy.server.http.HttpRequest;
import com.zlyx.easy.server.http.HttpResponse;
public class HttpServlet {
private String method;
private HttpRequest request;
private HttpResponse response;
private HttpServlet(HttpRequest request, HttpResponse response) throws IOException {
this.request = request;
this.response = response;
this.method = request.getMethod();
}
/**
* 處理請求
*
* @param request
* @param response
* @throws IOException
*/
private void doGet() throws IOException {
System.out.println(request);
response.write(String.valueOf(request.hashCode()));
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public HttpRequest getRequest() {
return request;
}
public void setRequest(HttpRequest request) {
this.request = request;
}
public HttpResponse getResponse() {
return response;
}
public void setResponse(HttpResponse response) {
this.response = response;
}
public static void doService(Socket socket) throws IOException {
HttpRequest request = new HttpRequest(socket.getInputStream());
HttpResponse response = new HttpResponse(socket.getOutputStream());
new HttpServlet(request, response).doGet();
}
}
修改後的代碼,HttpServlet構造方法被私有化,同時,對外提供doService()方法來完成方法調用(所有的請求類型都會走Get這條線路)。