在上一节,我们已经成功实现了一个简单的HTTP服务器,但是,好像和Servlet没啥关系,因为整个操作都是基于HttpExchange
接口做的。
而Servlet处理HTTP的接口是基于HttpServletRequest
和HttpServletResponse
,前者负责读取HTTP请求,后者负责写入HTTP响应。
怎么把基于HttpExchange
的操作转换为基于HttpServletRequest
和HttpServletResponse
?答案是使用Adapter模式。
首先我们定义HttpExchangeAdapter
,它持有一个HttpExchange
实例,并实现HttpExchangeRequest
和HttpExchangeResponse
接口:
interface HttpExchangeRequest {
String getRequestMethod();
URI getRequestURI();
}
interface HttpExchangeResponse {
Headers getResponseHeaders();
void sendResponseHeaders(int rCode, long responseLength) throws IOException;
OutputStream getResponseBody();
}
public class HttpExchangeAdapter implements HttpExchangeRequest, HttpExchangeResponse {
final HttpExchange exchange;
public HttpExchangeAdapter(HttpExchange exchange) {
this.exchange = exchange;
}
// 实现方法
...
}
紧接着我们编写HttpServletRequestImpl
,它内部持有HttpServletRequest
,并实现了HttpServletRequest
接口:
public class HttpServletRequestImpl implements HttpServletRequest {
final HttpExchangeRequest exchangeRequest;
public HttpServletRequestImpl(HttpExchangeRequest exchangeRequest) {
this.exchangeRequest = exchangeRequest;
}
// 实现方法
...
}
同理,编写HttpServletResponseImpl
如下:
public class HttpServletResponseImpl implements HttpServletResponse {
final HttpExchangeResponse exchangeResponse;
public HttpServletResponseImpl(HttpExchangeResponse exchangeResponse) {
this.exchangeResponse = exchangeResponse;
}
// 实现方法
...
}
用一个图表示从HttpExchange
转换为HttpServletRequest
和HttpServletResponse
如下:
┌──────────────────────┐ ┌───────────────────────┐
│ HttpServletRequest │ │ HttpServletResponse │
└──────────────────────┘ └───────────────────────┘
▲ ▲
│ │
┌──────────────────────┐ ┌───────────────────────┐
│HttpServletRequestImpl│ │HttpServletResponseImpl│
┌──│- exchangeRequest │ │- exchangeResponse ────┼──┐
│ └──────────────────────┘ └───────────────────────┘ │
│ │
│ ┌──────────────────────┐ ┌───────────────────────┐ │
└─▶│ HttpExchangeRequest │ │ HttpExchangeResponse │◀─┘
└──────────────────────┘ └───────────────────────┘
▲ ▲
│ │
│ │
┌───────────────────┐
│HttpExchangeAdapter│ ┌────────────┐
│- httpExchange ────┼──▶│HttpExchange│
└───────────────────┘ └────────────┘
接下来我们改造处理HTTP请求的HttpHandler
接口:
public class HttpConnector implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
var adapter = new HttpExchangeAdapter(exchange);
var request = new HttpServletRequestImpl(adapter);
var response = new HttpServletResponseImpl(adapter);
process(request, response);
}
void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO
}
}
在handle(HttpExchange)
方法内部,我们创建的对象如下:
所以实际上创建的实例只有3个。最后调用process(HttpServletRequest, HttpServletResponse)
方法,这个方法内部就可以按照Servlet标准来处理HTTP请求了,因为方法参数是标准的Servlet接口:
void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter("name");
String html = "<h1>Hello, " + (name == null ? "world" : name) + ".</h1>";
response.setContentType("text/html");
PrintWriter pw = response.getWriter();
pw.write(html);
pw.close();
}
目前,我们仅实现了代码调用时用到的getParameter()
、setContentType()
和getWriter()
这几个方法。如果补全HttpServletRequest
和HttpServletResponse
接口所有的方法定义,我们就得到了完整的HttpServletRequest
和HttpServletResponse
接口实现。
运行代码,在浏览器输入http://localhost:8080/?name=World
,结果如下:
为了实现Servlet服务器,我们必须把jdk.httpserver提供的输入输出HttpExchange
转换为Servlet标准定义的HttpServletRequest
和HttpServletResponse
接口,转换方式是Adapter模式;
转换后的HttpExchangeAdapter
类再用HttpExchangeRequest
和HttpExchangeResponse
把读取和写入功能分开,使得结构更加清晰。