访问html页面
如果我们想访问html页面其实就是将本地的html文件以流的方式响应给前端即可,下面我们对HttpResponseServlet这个类做一些改造
package com.tomcatServer.domain;
import com.tomcatServer.utils.ScanUtil;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* http servlet响应
*
* @author ez4sterben
* @date 2023/08/15
*/
public class HttpServletResponse {
private final PrintWriter out;
private static final String response;
private static final String htmlResponse;
public HttpServletResponse(PrintWriter out) {
this.out = out;
}
static {
response = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/plain\r\n" +
"\r\n";
htmlResponse = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html\r\n" +
"\r\n";
}
/**
* 写
*
* @param content 内容
*/
public void write(String content) {
out.println(response + content);
}
/**
* 编写html
*
* @param htmlFileName html文件名字
* @throws IOException ioexception
*/
public void writeHtml(String htmlFileName) throws IOException {
Path path = Paths.get(ScanUtil.WEB_APP_PATH + "\\" + htmlFileName);
byte[] bytes = Files.readAllBytes(path);
out.println(htmlResponse + new String(bytes, StandardCharsets.UTF_8));
}
}
writeHtml这个方法将会读取webApp下面的html文件,注意只读取下面一级文件中的html文件,然后将这个文件以二进制流的形式转换成字符串拼接到上面定义的html格式的响应头。
处理静态资源请求
当我们有了解析html文件的方法后,下面要做的就是处理静态资源,也就是判断一下请求路径中是否有.html这个字符串,有的话就把这次请求当做静态资源请求处理,没有的话再交给GET或者POST请求。这个逻辑将添加在SocketStore中,下面展示更改玩的SocketStore代码
package com.tomcatServer.socket;
import com.tomcatServer.domain.HttpServletRequest;
import com.tomcatServer.domain.HttpServletResponse;
import com.tomcatServer.utils.ScanUtil;
import com.tomcatServer.utils.ServletUtil;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
/**
* 套接字存储
*
* @author ez4sterben
* @date 2023/08/15
*/
public class SocketStore {
private static ServerSocket socket;
public static void connect(Integer port) throws IOException {
socket = new ServerSocket(port);
}
public static void close() throws IOException {
socket.close();
}
public static ServerSocket getSocket() {
return socket;
}
/**
* 处理请求
*
* @throws IOException ioexception
*/
public static void handleRequest(Socket accept) throws IOException {
// 获取输入输出流
BufferedReader in = new BufferedReader(new InputStreamReader(accept.getInputStream()));
PrintWriter out = new PrintWriter(accept.getOutputStream(), true);
// 定义字符串接收Http协议内容
String inputLine;
StringBuilder requestData = new StringBuilder();
// 读取数据
while ((inputLine = in.readLine()) != null && !inputLine.isEmpty()) {
requestData.append(inputLine).append("\r\n");
}
// 解析request param
String url = requestData.toString().split(" ")[1];
// 处理静态资源
if(url.contains(".html")){
String staticSourceName = (url.split(".html")[0] + ".html").substring(1);
HttpServletResponse response = new HttpServletResponse(out);
response.writeHtml(staticSourceName);
}else {
// 处理GET与POST请求
if (!requestData.toString().trim().equals("")){
handleGetAndPostReuqest(in, out, String.valueOf(requestData));
}
}
// 关闭资源
accept.close();
}
/**
* 处理post请求
*
* @param in 在
* @param requestData 请求数据
* @throws IOException ioexception
*/
private static void handleGetAndPostReuqest(BufferedReader in,PrintWriter out, String requestData) throws IOException {
// 解析request param
String url = requestData.split(" ")[1];
String[] urlContent = url.split("\\?");
String requestPath = urlContent[0];
String params = urlContent[1];
String[] paramsKeyValue = params.split("=");
// 设置请求参数
HttpServletRequest request = new HttpServletRequest();
Map<String, String> paramsMap = request.getParams();
for (int i = 0; i < paramsKeyValue.length; i += 2) {
paramsMap.put(paramsKeyValue[i],paramsKeyValue[i+1]);
}
if (requestData.contains("POST")) {
// 解析request body
int contentLength = Integer.parseInt(requestData.split("Content-Length: ")[1].split("\r\n")[0]);
StringBuilder requestBody = new StringBuilder();
for (int i = 0; i < contentLength; i++) {
requestBody.append((char) in.read());
}
// 设置request body
request.setRequestBody(String.valueOf(requestBody));
// 设置响应内容
HttpServletResponse response = new HttpServletResponse(out);
ServletUtil.invokePost(requestPath,request,response);
}
if (requestData.contains("GET")){
// 设置响应内容
HttpServletResponse response = new HttpServletResponse(out);
ServletUtil.invokeGet(requestPath,request,response);
}
}
}
访问测试
接下来我们在index.html里面写点东西并访问一下试试
http://localhost:8080/index.html
路由支持
其实刚才完成这个功能的时候就会发现,如何访问子目录里面的html呢?
这里其实就要写一个小方法来支持路由重定向了,下面编写一个HttpUtil
package com.tomcatServer.utils;
import com.tomcatServer.domain.HttpServletRequest;
import com.tomcatServer.domain.HttpServletResponse;
import java.io.IOException;
public class HttpUtil {
private final String redirectPath;
public HttpUtil(String redirectPath) {
this.redirectPath = redirectPath;
}
public void forward(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.writeHtml(redirectPath);
}
}
对HttpServletRequest做一些改进,提供一个加载静态资源的方法。
public HttpUtil getStaticSource(String path){
return new HttpUtil(path);
}
其实这样我们的功能就完成了,写一个servlet以及html来测试一下
package tomcatProject.com.ez4sterben.servlet;
import com.tomcatServer.annotation.WebServlet;
import com.tomcatServer.domain.HttpServlet;
import com.tomcatServer.domain.HttpServletRequest;
import com.tomcatServer.domain.HttpServletResponse;
import java.io.IOException;
@WebServlet("/router")
public class RouterServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
request.getStaticSource("WEB-INF/page/"+request.getParam("path")+".html").forward(request, response);
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
doGet(request, response);
}
}
多线程改进
为什么要在这里谈多线程改进呢,其实是因为我们最近本的接收请求,响应请求,响应页面以及完成了,接下来要考虑的就是如何支持并发处理请求,如何配置并发数,如何配置端口等优化问题。
如果想实现并发处理请求的话,实际上只需要预先定义一个线程池即可,把处理请求的方法交给一个任务类并且实现Runnable接口,当然我们后面会再优化这种方案。
package com.tomcatServer.task;
import com.tomcatServer.socket.SocketStore;
import java.io.IOException;
import java.net.Socket;
public class RequestTask implements Runnable{
private final Socket accept;
public RequestTask(Socket accept) {
this.accept = accept;
}
@Override
public void run() {
try {
SocketStore.handleRequest(accept);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
...
public static ExecutorService threadPool;
...
// 5.初始化线程池
threadPool = Executors.newFixedThreadPool(10);
// 6.处理http请求
try {
SocketStore.connect(PORT);
while (true){
Socket accept = SocketStore.getSocket().accept();
if (accept != null){
threadPool.submit(new RequestTask(accept));
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
SocketStore.close();
}
【仿写tomcat】六、解析xml文件配置端口、线程池核心参数