用BIO实现tomcat

news2024/12/21 19:20:57

一、前言

本课程的难度较高,需要将Servlet原理和IO课程全部学完。

二、当前项目使用方式

(1).自定义servlet

自定义servlet需要实现@WebServlet并且实现name和urlMapping
在这里插入图片描述
重启进行访问
http://localhost:8090/myServlet
在这里插入图片描述

(2).自定义html

在这里插入图片描述
重启进行访问
http://localhost:8090/index.html
在这里插入图片描述

(3).关于servlet位置

在这里插入图片描述
在SearchClassUtil类当中可以设置servlet包的位置

三、关于web须知

我们本次设计的tomcat能够将用户请求的资源进行返回

资源分类
1.静态资源:所有用户访问后,得到的结果都是一样的,称为静态资源。
           静态资源可以直接被浏览器解析。
           *例如:html/css/jpg/js..
2.动态资源:每个用户访问相同的资源后,得到的结果可能不一样,称为动态资源。
           动态资源被访问后需要先转化为静态资源,再返回给浏览器,浏览器进行解析
           *例如:servlet/jsp ...

四、tomcat设计原理

在这里插入图片描述

五、实现tomcat对静态资源的访问

(1).创建maven项目

在这里插入图片描述
在这里插入图片描述

(2).tomcat启动阶段

配置HttpServlet

创建HttpServletRequest接口

public interface HttpServletRequest {
    public String getUrl();


    public void setUrl(String url);

    public String getMethod();

    public void setMethod(String method);
}

创建HttpServletResponse接口

public interface HttpServletResponse {
    void write(String context) throws IOException;
}

创建HttpServlet

/**
 * class HttpServlet
 */
public abstract class HttpServlet {

    public abstract void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException;

    public abstract void doPost(HttpServletRequest request,HttpServletResponse response);

    /**
     * HttpServlet 实现service方法
     */
    public void service(HttpServletRequest request,HttpServletResponse response) throws IOException {
        if("GET".equals(request.getMethod())){
            doGet(request,response);
        }else if("POST".equals(request.getMethod())){
            doPost(request,response);
        }
    }

}

创建工具类,描述返回的信息

/**
 * 返回信息工具类
 */
public class ResponseUtil {

    public  static  final String responseHeader200 = "HTTP/1.1 200 \r\n"+
            "Content-Type:text/html \r\n"+"\r\n";

    public static String getResponseHeader404(){
        return "HTTP/1.1 404 \r\n"+
                "Content-Type:text/html \r\n"+"\r\n" + "404";
    }

    public static String getResponseHeader200(String context){
        return "HTTP/1.1 200 \r\n"+
                "Content-Type:text/html \r\n"+"\r\n" + context;
    }
}

配置注解信息

@Retention(RetentionPolicy.RUNTIME)  //注解的生命周期,运行期间保留
@Target(value = {ElementType.TYPE,ElementType.FIELD}) // 该注解作用在类上边
public @interface WebServlet {
    String urlMapping() default ""; //自定义的servlet路径
}

配置servlet容器

创建ServletConfig存储注解信息

/**
 * 注解上的信息
 */
public class ServletConfig {
    private String urlMapping; //2.url
    private String classpath; //3.类的全路径名

    public ServletConfig(String urlMapping,String classpath){
        this.classpath = classpath;
        this.urlMapping = urlMapping;
    }

    public String getUrlMapping() {
        return urlMapping;
    }

    public void setUrlMapping(String urlMapping) {
        this.urlMapping = urlMapping;
    }

    public String getClasspath() {
        return classpath;
    }

    public void setClasspath(String classpath) {
        this.classpath = classpath;
    }
}

工具类,获取servlet的全路径名

/**
 * 扫描指定包,获取该包下所有的类的全路径信息
 */
public class SearchClassUtil {
    public static  List<String> classPaths = new ArrayList<String>();

    public static List<String> searchClass(){
        //需要扫描的包名
        String basePack = "com.qcby.webapp";
        //将获取到的包名转换为路径
        String classPath = SearchClassUtil.class.getResource("/").getPath();
        basePack =  basePack.replace(".", File.separator);
        String searchPath = classPath + basePack;
        doPath(new File(searchPath),classPath);
        //这个时候我们已经得到了指定包下所有的类的绝对路径了。我们现在利用这些绝对路径和java的反射机制得到他们的类对象
        return classPaths;
    }

    /**
     * 该方法会得到所有的类,将类的绝对路径写入到classPaths中
     * @param file
     */
    private static void doPath(File file,String classpath) {
        if (file.isDirectory()) {//文件夹
            //文件夹我们就递归
            File[] files = file.listFiles();
            for (File f1 : files) {
                doPath(f1,classpath);
            }
        } else {//标准文件
            //标准文件我们就判断是否是class文件
            if (file.getName().endsWith(".class")) {
                String path = file.getPath().replace(classpath.replace("/","\\").
                                replaceFirst("\\\\",""),"").replace("\\",".").
                        replace(".class","");
                //如果是class文件我们就放入我们的集合中。
                classPaths.add(path);
            }
        }
    }

    public static void main(String[] args) {
        List<String> classes = SearchClassUtil.searchClass();
        for (String s: classes
             ) {
            System.out.println(s);
        }
    }
}

创建ServletConfigMapping生成servlet容器

/**
 *  servlet容器
 */
public class ServletConfigMapping {
    
    //定义一个集合用来存储自定义servlet的配置信息
    private static List<ServletConfig> configs = new ArrayList<>();
    //定义servlet容器
    public static Map<String,Class<HttpServlet>> classMap = new HashMap<>();

    //解析注解 ---- 为了实现当mytomcat类启动的时候就将webapp下边所有的类的注解信息获取到我们需要写一个static代码块
    static {
        //1.获取webapp包下有哪些类
        List<String> classPaths = SearchClassUtil.searchClass();
        //2.获取类的注解信息
        for (String classpath: classPaths) {
            try {
                //利用反射获取类的注解信息
                getMessage(classpath);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    //利用反射获取类的注解信息
    public static void getMessage(String classPath) throws ClassNotFoundException {
        Class clazz = Class.forName(classPath);
        //注解对象
        WebServlet webServlet = (WebServlet) clazz.getDeclaredAnnotation(WebServlet.class);
        //将解析的信息放入到集合当中
        configs.add(new ServletConfig(webServlet.urlMapping(),classPath));
    }

    //初始化类容器
    public static void initServlet() throws ClassNotFoundException {
        for (ServletConfig servletConfig: configs) {
            // 将servlet对象和 url请求地址放入到 map集合当中去
            classMap.put(servletConfig.getUrlMapping(), (Class<HttpServlet>) Class.forName(servletConfig.getClasspath()));
        }
    }
}

(3).接收前端请求

创建Request类接收前端数据并实现HttpServletRequest接口

public class Request implements 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) {
        Method = method;
    }
}

创建Response类用来实现HttpServletResponse

public class Response implements HttpServletResponse {
    //输出流
    private OutputStream outputStream;

    public Response(OutputStream outputStream){
        this.outputStream = outputStream;
    }

    /**
     * 返回动态资源
     * @param context
     */
    public void write(String context) throws IOException {
        outputStream.write(context.getBytes());
    }

    /**
     * 返回静态资源
     */
    public void writeHtml(String path) throws Exception {
        String resourcesPath = FileUtil.getResoucePath(path);
        File file = new File(resourcesPath);
        if(file.exists()){
            //静态文件存在
            System.out.println("静态文件存在");
            FileUtil.writeFile(file,outputStream);
        }else {
            System.out.println("静态文件不存在");
            write(ResponseUtil.getResponseHeader404());
        }
    }
}

工具类获取静态资源

/**
 * 该类的主要作用是进行读取文件
 */
public class FileUtil {

    public  static  boolean witeFile(InputStream inputStream, OutputStream outputStream){
        boolean success = false ;
        BufferedInputStream bufferedInputStream ;
        BufferedOutputStream bufferedOutputStream;

        try {
            bufferedInputStream = new BufferedInputStream(inputStream);
            bufferedOutputStream = new BufferedOutputStream(outputStream);
            bufferedOutputStream.write(ResponseUtil.responseHeader200.getBytes());

            int count = 0;
            while (count == 0){
                count = inputStream.available();
            }
            int fileSize = inputStream.available();
            long written = 0;
            int beteSize = 1024;
            byte[] bytes = new byte[beteSize];
            while (written < fileSize){
                if(written + beteSize > fileSize){
                    beteSize = (int)(fileSize - written);
                    bytes = new byte[beteSize];
                }
                bufferedInputStream.read(bytes);
                bufferedOutputStream.write(bytes);
                bufferedOutputStream.flush();
                written += beteSize;
            }
            success = true;

        } catch (IOException e) {
            e.printStackTrace();
        }
        return success;
    }

    public static boolean writeFile(File file,OutputStream outputStream) throws Exception{
        return witeFile(new FileInputStream(file),outputStream);
    }


    public static String getResoucePath(String path){
        String resource = FileUtil.class.getResource("/").getPath();
        return resource + "\\" + path;
    }

}

获取输入流信息,获取访问方式和访问地址

public class MyTomcat {

    Request request = new Request();

    //启动tomcat主方法
    public void startUp() throws IOException, ClassNotFoundException {
        
        //1.定义socket对象,监听8080端口
        ServerSocket serverSocket = new ServerSocket(8080);
        while (true){
            Socket socket = serverSocket.accept();//等待接收 BIO
            System.out.println("有用户请求过来了.....");
            // 给每一个请求都开启一个线程处理信息
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        杜凯(socket);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

    }
    //2.创建出入流,读取用户请求信息
    public void 杜凯(Socket socket) throws Exception {
        //创建输入流
        InputStream inputStream = socket.getInputStream();
        //解析输入流
        getInputStream(inputStream);

        socket.close();
    }

    public void getInputStream(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]; //根据换行来获取第一行数据
            request.setUrl(firstLine.split("\\s")[1]);
            request.setMethod(firstLine.split("\\s")[0]);
        }

    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        MyTomcat myTomcat = new MyTomcat();
        myTomcat.startUp();
    }

}

加载tomcat启动配置,判断访问内容时否是静态资源

public class MyTomcat {

    Request request = new Request();

    /**
     * servlet分发器
     * @param request
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public void dispatch(Request request, Response response) throws Exception {
        //根据请求的信息来获取servlet类
        Class<HttpServlet> servletClass = ServletConfigMapping.classMap.get(request.getUrl());
        //真实的创建servlet对象
        if(servletClass !=null){
           HttpServlet servlet =  servletClass.newInstance();
           servlet.service(request,response);
        }else {
            response.write(ResponseUtil.getResponseHeader404());
        }
    }

    //启动tomcat主方法
    public void startUp() throws IOException, ClassNotFoundException {
        //加载servlet信息
        ServletConfigMapping.initServlet();

        //1.定义socket对象,监听8080端口
        ServerSocket serverSocket = new ServerSocket(8080);
        while (true){
            Socket socket = serverSocket.accept();//等待接收 BIO
            System.out.println("有用户请求过来了.....");
            // 给每一个请求都开启一个线程处理信息
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        杜凯(socket);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

    }
    //2.创建出入流,读取用户请求信息
    public void 杜凯(Socket socket) throws Exception {
        //创建输入流
        InputStream inputStream = socket.getInputStream();
        //解析输入流
        getInputStream(inputStream);

        //输出流
        Response response = new Response(socket.getOutputStream());

        //根据url判断是静态资源还是动态资源
        if(request.getUrl().equals("")){
            //没有访问数据
            response.write(ResponseUtil.getResponseHeader404());
        }else if(ServletConfigMapping.classMap.get(request.getUrl()) == null){
            //访问静态资源
            response.writeHtml(request.getUrl());
        }else {
            //访问动态资源
            dispatch(request,response);
        }

        socket.close();
    }

    public void getInputStream(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]; //根据换行来获取第一行数据
            request.setUrl(firstLine.split("\\s")[1]);
            request.setMethod(firstLine.split("\\s")[0]);
        }

    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        MyTomcat myTomcat = new MyTomcat();
        myTomcat.startUp();
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1487538.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

四川古力未来科技抖音小店:未来零售的新风口

随着互联网的快速发展&#xff0c;电商行业日新月异&#xff0c;短视频平台抖音凭借其庞大的用户群体和独特的内容形式&#xff0c;已经成为当下最热门的社交媒体之一。抖音小店作为抖音平台上的一个重要功能&#xff0c;正逐渐展现出其巨大的商业潜力和发展前景。本文将探讨抖…

【脑科学相关合集】有关脑影像数据相关介绍的笔记及有关脑网络的笔记合集

【脑科学相关合集】有关脑影像数据相关介绍的笔记及有关脑网络的笔记合集 前言脑模板方面相关笔记清单 基于脑网络的方法方面数据基本方面 前言 这里&#xff0c;我将展开有关我自己关于脑影像数据相关介绍的笔记及有关脑网络的笔记合集。其中&#xff0c;脑网络的相关论文主要…

C++原子变量的使用案例

说明 核心原子变量是pDeviceStatus&#xff0c;该变量的夸线程修改&#xff0c;就不需要使用锁了&#xff1b; std::atomic<IPDeviceStatus*> pDeviceStatus new IPDeviceStatus(); 代码功能 某公共场所使用的IP喇叭&#xff0c;类似物联网设备&#xff0c;基于嵌入…

Vue3自定义文章列表组件

一、Vue3的代码展示 <template><div><div v-for"article in articles" :key"article.id" class"article-card"><div class"author-info"><img :src"article.avatar" alt"Author Avatar&qu…

水电站数字孪生:水力发电在可视化领域的应用

自水轮机的早期发明被用于农业灌溉&#xff0c;到 18 世纪末期的工业革命促使水轮机技术的改良&#xff0c;再到 19 世纪末水利发电的崛起&#xff0c;直至今日&#xff0c;智慧水电站数字孪生技术正处于蓬勃发展之中。通过整合物联网、大数据、云计算等现代信息技术&#xff0…

PYCHARM PYSIDE6 QT 打包异常3种处理方式 no qt platform plugin could be initialized

安装有PYSIDE6的电脑 异常错误 … no qt platform plugin could be initialized … 变量名&#xff1a;QT_QPA_PLATFORM_PLUGIN_PATH &#xff08;一个字都不能改&#xff01;&#xff01;&#xff09; 自己环境变量值&#xff1a;D:\Users\topma\anaconda3\Lib\site-package…

【STM32】STM32学习笔记-FLASH闪存(48)

00. 目录 文章目录 00. 目录01. FLASH简介02. 闪存模块组织03. FLASH基本结构04. FLASH解锁05. 使用指针访问存储器06. 程序存储器编程07. 选项字节08. 选项字节编程09. 选项字节擦除10. 器件电子签名11. 附录 01. FLASH简介 STM32F1系列的FLASH包含程序存储器、系统存储器和选…

HarmonyOS Stage模型 用程序运行切换 验证UIAbility 启动模式(下) 验证:specified启动模式 Ability间切换

上文 HarmonyOS Stage模型 用程序运行切换 验证UIAbility 启动模式(上) 验证:singleton、multiton、standard启动模式 我们已经验证完了 singleton multiton standard 三种启动模式 留下了毕竟复杂的 specified 这里 首先 我们要写两个不同的界面 index 编写代码如下 import…

就业班 2401--2.29 Linux Day8--存储管理2(LVM)+swap+磁盘阵列raid

&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;小伙伴们一定要看到最后&#xff0c;有彩蛋呢^--^ 一、存储管理Ⅱ 逻辑卷LVM &#xff08;Logical Volume Manager&#xff08;逻辑卷管理&#xff09;的简写&#xff09; LVM管理 lvm概念&#xf…

即时设计案例分享: 网页设计案例解析

优秀的网页设计案例可以帮助设计快速完成设计项目&#xff0c;优秀的网页设计网站也是设计师的灵感电站。网页承载着品牌希望向访问者传递的信息。当用户进入网站时&#xff0c;人们对网站的第一印象开始潜移默化地形成。因此&#xff0c;优秀的网页设计非常重要&#xff0c;这…

uniapp问卷调查(单选)

前言 该代码片段只支持问卷调查的单选功能 使用组件库 配置 | uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架 (uviewui.com) 代码 <template> <view> <view v-for"(item, index) in radiolist1" :key"index"> …

LeetCode --- 无重复字符的最长子串

题目描述 无重复字符的最长子串 找到无重复的最长连续字符串。 示例1中 abc | bca | cab 都符合题意。输出3即可。 代码 可以使用暴力枚举 哈希表&#xff0c;哈希表来判断是否重复&#xff0c;枚举来判断每一种情况&#xff0c;需要开两层for循环&#xff0c;时间复杂度n…

Linux --- 应用层 | HTTP | HTTPS

前言 前面写的TCP/UDP客户端在访问服务端的时候&#xff0c;需要输入ip地址和端口号才可以访问&#xff0c; 但在现实中&#xff0c;我们访问一个网站是直接输入的一个域名&#xff0c;而不是使用的ip地址端口号。 比如在访问百度 https://www.baidu.com/的时候&#xff0c; …

操作系统|概述|系统分类——笔记

1.1_1操作系统的概念和功能 操作系统的概念 操作系统&#xff08;Operating System&#xff0c; OS&#xff09; 是指控制和管理整个计算机系统的 硬件和软件 资源&#xff0c;并合理地组织调度计算机和工作和资源的分配&#xff1b; 1操作系统是系统资源的管理者 以提供给用…

Springboot 过滤器、拦截器、全局异常处理

Springboot 过滤器、拦截器、全局异常处理 一 过滤器&#xff08;Filter&#xff09; 过滤器是JavaWeb三大组件&#xff08;Servlet&#xff0c;Filter&#xff0c;Listener&#xff09;之一。 Filter可以把对资源的请求拦截下来&#xff0c;从而实现一些功能。 注意&#…

罐头食品加工污废水需要哪些工艺设备

罐头食品加工是目前广泛应用于食品行业的一种加工方式&#xff0c;由于其加工过程中产生的废水所含有的有机物质和化学物质含量较高&#xff0c;对环境造成了一定的污染问题。为了解决这一问题&#xff0c;罐头食品加工污废水需要采用一系列的工艺设备进行处理和净化。 首先&am…

技术实践|百度安全「大模型内容安全」高级攻击风险评测

1、引子 2023年10月16日&#xff0c;OWASP发布了《OWASP Top 10 for LLM Applications》&#xff0c;这对于新兴的大语言模型安全领域&#xff0c;可谓一份纲领性的重要报告。 OWASP是开放式Web应用程序安全项目&#xff08;Open Web Application Security Project&#xff0…

Mysql运维篇(七) 部署MHA--完结

一路走来&#xff0c;所有遇到的人&#xff0c;帮助过我的、伤害过我的都是朋友&#xff0c;没有一个是敌人。如有侵权&#xff0c;请留言&#xff0c;我及时删除&#xff01; 一、MHA软件构成 Manager工具包主要包括以下几个工具&#xff1a; masterha_manger 启…

【直播来袭】威睿电池:车载ECU网络安全开发落地开发实践|谈思AutoSec直播课第42期

如果恶意黑客导致动力总成和底盘ECU出现问题&#xff0c;你会感到害怕甚至不敢想。车辆电气系统中的所有ECU都可能成为目标。更不用说互联车辆了。为了防止软件被未经授权的操作或访问至关重要的关键材料&#xff0c;现代车辆需要强大的IT安全机制来与外界隔离。 由于汽车智能…

.md转pdf

1、使用vscode安装Markdown PDF Markdown PDF 打开预览转pdf,同目录下自动生成pdf文件