当前位置: 首页 > news >正文

上海网站建设开发哪家好深圳网站如何制作

上海网站建设开发哪家好,深圳网站如何制作,网站服务器指的是什么,网站建设属于会计的什么科目Tomcat 是一个广泛使用的开源 Servlet 容器,用于运行 Java Web 应用程序。深入理解 Tomcat 的工作原理对于 Java 开发者来说是非常有价值的。本文将带领大家手动实现一个简易版的 Tomcat,通过这个过程,我们可以更清晰地了解 Tomcat 是如何处理…

        Tomcat 是一个广泛使用的开源 Servlet 容器,用于运行 Java Web 应用程序。深入理解 Tomcat 的工作原理对于 Java 开发者来说是非常有价值的。本文将带领大家手动实现一个简易版的 Tomcat,通过这个过程,我们可以更清晰地了解 Tomcat 是如何处理 HTTP 请求和响应的。

        tomcat涉及到的知识点较多,主要有注解、抽象类、反射、IO流等,对基础掌握度要求较高,掌握这些基础后,我们开始手写tomcat

一、创建包

一个基本的 Tomcat 主要完成以下几个核心功能:

  1. 监听端口:等待客户端的 HTTP 请求。
  2. 解析请求:从客户端请求中提取关键信息,如请求方法、请求路径等。
  3. 处理请求:根据请求信息调用相应的处理逻辑。
  4. 返回响应:将处理结果封装成 HTTP 响应返回给客户端。

根据以上功能,我们创建如下图所示的包

--tomcat类的作用是启动整个tomcat容器

--webapp包下存放你自己创建的servlet动态资源

--httpServletRe包下有两个类HttpServletRequest和HttpservletResponse,这两个类可以说是与前端请求直接关联。

        在前端的请求信息中,请求方式和访问路径都要放在HttpServletRequest类中,可以说是相当的重要,我们可以通过socket将前端信息装到该类中,具体写法之后细讲,也就是说我们知道该类有请求方式和访问路径,通过和项目本身的资源对比从而定位到某个实际的静态资源或动态资源

而HttpServletResponse则是向前端发送我们自己写的消息,依赖outputStream来完成,该消息需要遵循响应信息的特定格式,之后的工具类中会给出

--servlet包下则是仿照Java类库中的servlet继承关系,创建了servlet接口,Gservlet抽象类和Httpservlet抽象类

--util包下存放两个工具类,一个类的作用是找到webapp下所有servlet类的类路径,用来进行反射;

一个类的作用是创建响应消息的返回格式,包展开如下:

二、写tomcat逻辑

要想得到前端发送的请求,我们首先需要创建一个ServerSocket对象实例来接收:

ServerSocket serverSocket = new ServerSocket(9090);
while(true){Socket socket = serverSocket.accept();
}

写一个while语句循环接收前端请求,一旦接收到请求,我们就可以创建输入流对象,将前端发送的消息存下来,在这里我们先只获取请求行的信息也就是第一行的信息

BufferedReader bufferedReader = new BufferedReader(new                             InputStreamReader(socket.getInputStream()));
String s = bufferedReader.readLine();

可以看到,浏览器中第一行有请求方式和访问路径,我们是以字符串形式接收的第一行数据,所以可以通过split()方法将请求方式和访问路径分开

String[] s1 = s.split(" ");

tomcat代码展示:(端口的话可以自己选,我写的是9090,tomcat默认端口是8080)

三、写HttpServletRequest的逻辑

得到请求方式和访问路径之后,我们需要将请求方式和访问路径封装到HttpServletRequest类中,在HttpServletRequest类中定义字符串类型的变量url和method,创建getter和setter方法:

public class HttpServletRequest {private String url;private String method;public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getMethod() {return method;}public void setMethod(String method) {this.method = method;}
}

四、补充tomcat逻辑

我们已经定义好HttpServletRequest类,接下来我们将tomcat类中拿到的请求方式和访问路径赋给该类中的变量method和url,首先在tomcat创建HttpServletRequest类的实例对象request,调用request的set方法,入参是inputStream获取到的请求方式和访问路径

代码如下:

写到该阶段我们可以先测试一下,在HttpServletRequest中重写toString方法,在tomcat中调用

到浏览器上输入http://localhost:9090,发现控制台输出:

请求方法和访问路径成功封装到了request中,我们继续下面的逻辑。

五、仿写servlet的继承关系

servlet包下是仿照Java类库中的servlet继承关系,创建了servlet接口,Gservlet抽象类和Httpservlet抽象类,我们现在在这三个类中添加逻辑

Servlet接口

该接口中定义以下方法:init方法、service方法和destroy方法,service方法用来判断是get请求还是post请求,在本接口中只定义,在HttpServlet抽象类中实现。其中有两个入参,HttpServletRequest类型的request和HttpservletResponse的response,之前request对象封装过请求方式,该方法会通过拿到入参的请求方式判断是get请求还是post请求

package com.qcby.servlet;import com.qcby.httpServletRe.HttpServletRequest;
import com.qcby.httpServletRe.HttpServletResponse;public interface Servlet {void init();void service(HttpServletRequest request, HttpServletResponse response) throws Exception;void destroy();
}

Gservlet抽象类

该抽象类继承Servlet接口并实现init方法和destroy方法,这两种方法我们不写实际功能,了解java类库中这两种方法的作用即可

package com.qcby.servlet;public abstract class Gservlet implements Servlet{@Overridepublic void init() {System.out.println("初始化");}@Overridepublic void destroy() {System.out.println("销毁");}
}

HttpServlet抽象类

该类继承Gservlet抽象类,实现了Servlet接口中的service方法,此外HttpServlet类中还增加了两种方法,doGet方法和doPost方法,相信学过servlet的小伙伴们并不陌生,doGet方法和doPost方法作为抽象方法不具体实现,子类也就是我们自己创建的servlet类继承该类时就必须实现该方法,至于service方法是用来区分get方法和post方法的,所以之前的request入参就是为了提供method做if判断

package com.qcby.servlet;import com.qcby.httpServletRe.HttpServletRequest;
import com.qcby.httpServletRe.HttpServletResponse;import java.io.IOException;public abstract class HttpServlet extends Gservlet{@Overridepublic void service(HttpServletRequest request, HttpServletResponse response) throws Exception{if(request.getMethod().equals("GET")){doGet(request,response);}else{doPost(request,response);}}public abstract void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException;public abstract void doPost(HttpServletRequest request, HttpServletResponse response);
}

六、创建注解类WebSocket

在工具包下创建WebSocket注解类,该注解类的作用是定义servlet类的url路径

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface WebSocket {public String url() default "";
}

七、创建servlet容器

tomcat启动时,Servlet 容器需要将客户端请求的 URL 路径映射到具体的 Servlet 上,以便正确处理请求。为了实现这一功能,容器使用 Map 来存储 URL 路径和 Servlet 名称或实例之间的映射关系。

要想获取URL路径和Servlet实例对象,我们首先要通过反射获取到类的类信息,而获取类信息需要获取类的全路径,所以写一个工具类获取webapp包下所有类的全路径,然后初始化map容器

import com.qcby.servlet.HttpServlet;import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;public class FindServletAllPath {public static HashMap<String, HttpServlet> map = new HashMap<>();public static List<String> getClassPaths(String packageName) throws IOException, ClassNotFoundException {List<String> classPaths = new ArrayList<>();// 将包名转换为文件系统路径String path = packageName.replace('.', '/');// 获取类加载器ClassLoader classLoader = Thread.currentThread().getContextClassLoader();// 获取指定路径下的所有资源Enumeration<URL> resources = classLoader.getResources(path);while (resources.hasMoreElements()) {URL resource = resources.nextElement();// 获取资源的文件路径String filePath = resource.getFile();// 递归扫描目录scanDirectory(new File(filePath), packageName, classPaths);}return classPaths;}/*** 递归扫描目录,查找所有的 .class 文件* @param directory 要扫描的目录* @param packageName 当前包名* @param classPaths 存储类路径的列表*/private static void scanDirectory(File directory, String packageName, List<String> classPaths) {if (!directory.exists()) {return;}// 获取目录下的所有文件和文件夹File[] files = directory.listFiles();if (files != null) {for (File file : files) {if (file.isDirectory()) {// 递归扫描子目录scanDirectory(file, packageName + "." + file.getName(), classPaths);} else if (file.getName().endsWith(".class")) {// 获取类名String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);classPaths.add(className);}}}}static{try {// 指定要扫描的包名String packageName = "com.qcby.webapp";// 获取类路径列表List<String> classPaths = getClassPaths(packageName);// 打印类路径for (String classPath : classPaths) {Class<?> aClass = Class.forName(classPath);WebSocket annotation = aClass.getAnnotation(WebSocket.class);HttpServlet o = (HttpServlet) aClass.newInstance();map.put(annotation.url(),o);}} catch (Exception e) {e.printStackTrace();}}
}

我们把这个过程装入static块中,这样在类加载时就能完成容器的映射

八、创建servlet动态资源

在webapp包下创建一个servlet类,继承HttpServlet抽象类,重写doGet和doPost方法,各自添加一个输出语句,添加WebSocket注解,确定该类的url路径

import com.qcby.httpServletRe.HttpServletRequest;
import com.qcby.httpServletRe.HttpServletResponse;
import com.qcby.servlet.HttpServlet;
import com.qcby.util.WebSocket;import java.io.IOException;@WebSocket(url = "/first")
public class FirstServlet extends HttpServlet {@Overridepublic void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {System.out.println("first的doGet方法被调用");}@Overridepublic void doPost(HttpServletRequest request, HttpServletResponse response) {System.out.println("first的doPost方法被调用");}
}

九、补充tomcat逻辑

前端发送的请求方式和url路径已经封装到request对象当中,map中k值存放着请求路径,通过map映射可以找到对应的servlet实例对象,此时servlet的引用类型是父类类型,我们可以直接调用父类的方法service,有两个参数request和response,创建一个response对象放入对应参数位置

if(FindServletAllPath.map.containsKey(request.getUrl())){HttpServlet servlet = FindServletAllPath.map.get(request.getUrl());servlet.service(request,response);
}

进入service方法后,会通过获取request的请求方式判断是执行doget方法还是doPost方法,因为方法被子类重写,所以最终会调用到实际servlet的doget方法或者doPost方法

十、写HttpServletResponse逻辑

我们已经完成了请求的接受和处理,接下来需要将信息返回给前端

创建BufferOutputStream包装流将socket.outputStream包装后进行发送,需要注意的是,发送回前端的数据需要遵循特定的响应格式,我们再util包下创建一个工具类将数据封装到固定格式中

package com.qcby;public class ResponseUtil {public  static  final String responseHeader200 = "HTTP/1.1 200 \r\n"+"Content-Type:text/html; charset=utf-8 \r\n"+"\r\n";public static String getResponseHeader404(){return "HTTP/1.1 404 \r\n"+"Content-Type:text/html; charset=utf-8 \r\n"+"\r\n" + "404";}public static String getResponseHeader200(String context){return "HTTP/1.1 200 \r\n"+"Content-Type:text/html; charset=utf-8 \r\n"+"\r\n" + context;}
}

之后通过bufferoutputStream的write方法将数据返回给前端,注意发送后需要进行刷新

import com.qcby.ResponseUtil;
import java.io.BufferedOutputStream;
import java.io.IOException;import java.net.Socket;
import java.nio.charset.StandardCharsets;public class HttpServletResponse {Socket socket;public HttpServletResponse(Socket socket){this.socket = socket;}public void write(String s) throws IOException {BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream());s = ResponseUtil.getResponseHeader200(s);outputStream.write(s.getBytes(StandardCharsets.UTF_8));outputStream.flush();outputStream.close();}
}

tomcat的整体流程如上,现在测试一下接收前端数据以及向前端返回数据信息:

http://www.dtcms.com/a/420591.html

相关文章:

  • 平面设计资源网站网站建设西街
  • 中山做网站联系电话网站规划与开发技术专业
  • o2o网站建设基本流程爱企查企业服务平台
  • signal_connect
  • 什么是网站反向链接wordpress 到访人数
  • 自己做的视频可以传别的网站去吗.net开发微信网站
  • 网站如何做淘客桐城网站建设
  • 5、Lombok原理深入剖析:编译期注解处理机制与替代方案对比
  • 简述织梦网站上传步骤东莞外贸建站及推广
  • pid控制作为反馈控制,增加前馈控制,什么是前馈控制解释
  • 成品网站w灬源码火龙果住房和规划建设局网站
  • wordpress上传网站模板wordpress cms
  • MCU模块系统时钟
  • 温州 网站制作wordpress 自动升级
  • memblock-1
  • 云南住房和城乡建设厅网站首页网站建设策划基本流程
  • 深度学习核心技术演进:从函数到 Transformer 架构
  • 圣耀做单网站商城类小程序
  • 仿贴吧的网站网站建设费账务处理
  • 博客网站源码带后台前端电商网站登录界面怎么做
  • 成都网站建设平台郑州建站优化
  • 手机wap网站免费制作中山最好的网站建设公司哪家好
  • 网站阵地建设管理办法微网站建设网站
  • 郑州网站制作哪家便宜租房平台网站开发
  • 详解MySQL中的索引、事务和锁
  • 用cms织梦做网站图文教程网站优化计划
  • [C++项目组件]Etcd的简单介绍和使用
  • 重庆网站排名优化wordpress网页手机版
  • 怎样在手机上做自己的网站不是做有网站都叫狠狠
  • 解锁CRM系统流程优势:重塑企业客户关系管理的核心动能