【Tomcat】第四站:模拟Tomcat

发布于:2024-12-18 ⋅ 阅读:(34) ⋅ 点赞:(0)

 

目录

 

1. 引入

例题1.

      扫描myweb目录下的所有文件,输出每个文件的@WebServlet注解值

  

 2. 服务端

3.  Servlet项目

3.1.  Servlet接口​编辑

3.2. GenericServlet抽象类

3.3. HttpServlet抽象类

http请求

 请求方式

项目

!!请求是怎么打进来的?


1. 引入

        servlet项目是运行在Tomcat容器当中。

        Tomcat项目当中创建servlet项目,在servlet项目里,写servlet

这里,myWeb就是我们的Servlet项目。

例题1.

      扫描myweb目录下的所有文件,输出每个文件的@WebServlet注解值

  

package com.qcby.tomcat;


import com.qcby.tomcat.webServlet.WebServlet;

import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class MyTomcat {
    public static void main(String[] args) {
        try {
            // 1. 扫描包路径 ()
            String packageName = "com.qcby.tomcat.myweb";
            //通过调用getclass方法,获取到了myweb这个包下的所有类的类对象,并将其放入到了容器当中
            List<Class<?>> classes = getClasses(packageName);

            // 2. 遍历所有类,检查是否有@WebServlet注解
            for (Class<?> clazz : classes) {
                if (clazz.isAnnotationPresent(WebServlet.class)) {//检查是否含有@WebServlet注解
                    // 3. 获取@WebServlet注解的值
                    WebServlet webServlet = clazz.getAnnotation(WebServlet.class);
                    System.out.println("类名: " + clazz.getName() + " | URL路径: " + webServlet.path());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取指定包下的所有类
     *
     * @param packageName 包名,例如 "com.qcby.tomcat.myweb"
     * @return 类对象列表
     * @throws Exception
     */
    private static List<Class<?>> getClasses(String packageName) throws Exception {
        List<Class<?>> classes = new ArrayList<>();//定义一个可变长数组,放置类对象

        String path = packageName.replace('.', '/'); // 将包名转换为文件路径

        // 通过类加载器获取包的资源路径 ClassLoader是类加载器,负责动态加载Java类到Java虚拟机(JVM)中。
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        //Thread.currentThread() 方法返回对当前执行线程的引用。
        //.getContextClassLoader() 方法则返回该线程的上下文类加载器。上下文类加载器是线的程在创建时从父线程继承,
        //                              或者在创建线程时没有设置父线程的上下文类加载器时,默认使用应用程序类加载器(Application ClassLoader)

        //ClassLoader 类提供了 getResources(String name) 方法,该方法用于---查找具有指定名称的资源
        Enumeration<URL> resources = classLoader.getResources(path);
        //Enumeration<URL> 对象包含了所有找到的资源的URL。


        while (resources.hasMoreElements()) {//通过hasMoreElements()方法来检查是否还有更多的元素
            如果返回true,则表示枚举中还有元素未被遍历,可以继续调用nextElement()方法来获取下一个元素
            URL resource = resources.nextElement();

            //调用URL对象的toURI()方法将其转换为URI对象。
            //使用new File(URI uri)构造函数将URI对象转换为File对象。
            File directory = new File(resource.toURI());

            //File对象代表目录,不是文件
            // 扫描文件夹下的所有类文件
            if (directory.exists()) {
                for (File file : directory.listFiles()) {//可以利用listFiles()方法来获取该目录下所有文件和子目录的数组
                    if (file.getName().endsWith(".class")) {
                        //java文件自己创建的话是xx.java文件,后经过编译是:xx.class文件,这里用的是编译后的文件
                        // 获取类的完整类名
                        String className = packageName + "." + file.getName().replace(".class", "");
                        classes.add(Class.forName(className));
                    }
                }
            }
        }
        return classes;
    }
}

java程序的三个状态:

        源文件状态 .java

        类对象状态 .class         class z1=Class.forName("xxx")

                                                class z2=类名.class;

                                                class z3=对象名.getclass;

        RUNTIME状态         运行状态

 2. 服务端

package com.qcby.tomcat.socket;

import com.qcby.tomcat.Request.Request;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    private static Request request=new Request();
    public static void main(String[] args) throws  Exception {
        // 1.打开通信端口   tomcat:8080   3306  ---------》进行网络通信
        ServerSocket serverSocket = new ServerSocket(8080);//监听8080端口号
        System.out.println("****************server start.....");

        //2.接受请求数据
        while (true){
            Socket socket = serverSocket.accept();  //--------------------->注意:此时监听网卡的是:主线程
            System.out.println("有客户进行了链接");
            new Thread(()->{        //利用子线程方式处理数据
                //处理数据---------》数据的处理在于读和写
                try {
                    handler(socket);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
    public static void handler(Socket socket) throws Exception {
        //读取请求的数据
        InputStream inputStream = socket.getInputStream();
        requestContext(inputStream);
    }
    public static void requestContext(InputStream inputStream) throws IOException {
        //将bit流转为文字信息
        int count = 0;
        while (count == 0){
            count = inputStream.available();
        }
        byte[] bytes = new byte[count];
        inputStream.read(bytes);
        String Context = new String(bytes);
        System.out.println(Context);

        //解析数据
        if(Context.equals("")){
            System.out.println("你输入了一个空请求");
        }else {
            //获得第一行的前两个
            String firstLine=Context.split("\\n")[0];//根据换行来获取第一行数据
            String path=firstLine.split("\\s")[1];
            String method=firstLine.split("\\s")[0];
            System.out.println(path+" "+method);
            request.setMethod(method);
            request.setPath(path);
        }
    }
}

3.  Servlet项目

        我们在写eclipse中写项目时,创建Servlet项目通常都会显示如下,继承HttpServlet.

在IDEA中打开,我们能够查看继承的类。

  !!

      

        以上结构是创建的Servlet项目继承的。

3.1.  Servlet接口

 

接口是用来定义方法的。接口当中有对类行为的定义。

                实现接口类,就必须实现接口类当中所有的方法。

        抽象类当中可以有抽象方法也可以有具体方法。

        抽象类实现了接口,那么抽象类可以有选择性地实现接口当中的方法。

servlet接口定义着servlet的生命周期

                init: 初始化 ---> servlet类什么时候初始化

                getServletConfig: 获取servlet配置信息

                service: 服务

                getServletInfo: 获取信息

                destory: 销毁

3.2. GenericServlet抽象类

         实现了除了service方法以外的所有方法。(生命周期中生死)

3.3. HttpServlet抽象类

        实现了service方法  -->  更好地去匹配http的请求方式

如何实现?

                http请求(最常用的请求)


http请求

        请求响应加起来是一个完整的http请求。(有请求,一定要对数据有响应)。

        通常,由HTTP客户端发起一个请求,建立一个到服务器指定端口(默认是80端口)的TCP连接。HTTP服务器则在那个端口监听客户端发送过来的请求。一旦收到请求,服务器(向客户端)发回一个状态行,比如"HTTP/1.1 200 OK",和(响应的)消息,消息的消息体可能是请求的文件、错误消息、或者其它一些信息。

        HTTP 的端口号为 80
        HTTPS 的端口号为 443 --  加密的

         比如:

                cookie&session就包含着请求人的信息。

请求人信息:

   

        请求头当中包含一个特殊的--请求方式 


 请求方式

默认访问的话使用get,

        get  请求一般多用于查询

        post  请求一般多用于数据量大的提交方式--提交文件,数据的增删改

              ...


项目

        写项目继承HttpServlet,这里没有,新建一个。(这里模拟Tomcat不深入模拟,仅模拟到HttpServlet,不再往上写)   

     

HttpServlet方法是要被实现的,那么他就一定不是抽象方法。 

Service方法:

        根据用户的请求方式,来调用不用的方法去处理

        * GET请求: doGet()方法去实现

        * POST请求: doPost()来实现

        两个不同类之间实现消息的传递:创建一个类,定义属性。

 

        在传递信息类新建 私有 静态 对象,赋值

        在接收信息类,get接收值。      

  

package com.qcby.tomcat.HttpServlet;

import com.qcby.tomcat.Request.Request;
import com.qcby.tomcat.Response.Response;

public abstract class HttpServlet {

    /*
    * Httpservlet方法是要被实现的,那么他就一定不是抽象方法
    * 根据用户的请求方式,来调用不用的方法去处理
    *       GET请求: doGet()方法去实现
    *       POST请求: doPost()来实现
    * */
    public void service(Request request, Response response){
        if(request.getMethod().equals("GET")){
            doGet(request,response);
        }else if(request.getMethod().equals("POST")){
            doPost(request,response);
        }
    }
    public abstract void doGet(Request request, Response response);
    public abstract void doPost(Request request, Response response);
}

!!请求是怎么打进来的?

当请求过来的时候,

//解析数据
if(Context.equals("")){
    System.out.println("你输入了一个空请求");
}else {

    String firstLine=Context.split("\\n")[0];//根据换行来获取第一行数据
    String path=firstLine.split("\\s")[1];
    String method=firstLine.split("\\s")[0];
    

        一定会到这里,进行解析。解析完的数据放到request对象当中去,这个reque有请求信息,如果发出的请求是get类型,

if(request.getMethod().equals("GET")){
    doGet(request,response);
}

就会调用doGet()方法。

public abstract void doGet(Request request, Response response);

        由于doGet()方法是个抽象方法,抽象类当中的抽象方法是一定要被实现抽象类的实现。-->抽象方法没有方法的实现--在这里,三个类实现了这个抽象方法,-- 就会打到doGet()的实现类上,具体打到哪个类上,需要根据url进行匹配(request包含path,即URL)。

@WebServlet(path="/MyFirstServlet")


网站公告

今日签到

点亮在社区的每一天
去签到