手写简单的Tomcat(代码源于韩顺平老师的javaweb章节)

1.Maven的示意图

手写简单的Tomcat(代码源于韩顺平老师的javaweb章节)_第1张图片

2.重点

补充:如何配置阿里 maven 镜像

(1) 把 D:\program\JavaIDEA 2020.2\plugins\maven\lib\maven3\conf\settings.xml 拷贝默认的 maven 配置目录

(2) C:\Users\Administrator.m2 目录 settings.xml

** (3) 修改 C:\Users\Administrator.m2\settings.xml , 增加红色的部分**




alimaven
aliyun maven
http://maven.aliyun.com/nexus/content/groups/public/central

3.步骤和要点

  1. dependency 表示依赖, 也就是我们这个项目需要依赖的jar 包

  2. groupId 和 artifactId 被统称为坐标, 是为了去定位这个项目/jar

  3. groupId: 一般是公司 比如 com.baidu , 这里是 avax.servlet

  4. artifactId 一般是项目名, 这里是 javax.servlet-api

  5. 这样的化就可以定位一个 jar 包

  6. version 表示你引入到我们项目的 jar 包的版本是 3.1.0

  7. scope: 表示作用域,也就是你引入的 jar 包的作用范围

  8. provided 表示在 tomcat 本身是有这个 jar 的,因此在编译,测试使用,但是在打包发布就不用要带上

  9. 在默认情况下, 引入的 jar 会到 中央仓库去下载 https://mvnrepository.com/

  10. 会下载到哪里到你指定的目录 C:\Users\Administrator.m2\repository

  11. 有时为了下载更快, 往往配置镜像,

  12. 在 默 认 的 路 径 下 拷 贝 一份setting.xml 到C:\Users\Administrator.m2\settings.xml

手写Tomcat代码

1.HSPRequestHandler 是一个线程对象
2.处理Http请求的
import com.hspedu.servlet.CalServlet;
import com.hspedu.tomcat.HspTomcatV3;
import com.hspedu.tomcat.http.HspRequest;
import com.hspedu.tomcat.http.HspResponse;
import com.hspedu.tomcat.servlet.HspCalServlet;
import com.hspedu.tomcat.servlet.HspHttpServlet;
import com.hspedu.tomcat.utils.WebUtils;

import java.io.*;
import java.net.Socket;

public class HSPRequestHandler implements Runnable {
    //定义一个Socket
    private Socket socket = null;

    public HSPRequestHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        //对客户端/浏览器进行交互
        InputStream inputStream;
        try {
                HspRequest hspRequest = new HspRequest(socket.getInputStream());
                HspResponse hspResponse = new HspResponse(socket.getOutputStream());
               //1.得到uri=>servletUrlMapping的key
            String uri = hspRequest.getUri();

            if (WebUtils.isHtml(uri)){//如果就是一个静态页面
                String content = WebUtils.readHtml(uri.substring(1));
                content=HspResponse.respHeader+content;
                //得到outputstream,返回信息给浏览器
                OutputStream outputStream = hspResponse.getOutputStream();
                outputStream.write(content.getBytes());
                outputStream.flush();
                outputStream.close();
                socket.close();
                return;

            }


            String servletName = HspTomcatV3.servletUrlMapping.get(uri);

                //2.通过uri->servletName->servlet实例,真正的运行类型是其子类 HspCalServlet
                HspHttpServlet hspHttpServlet = HspTomcatV3.servletMapping.get(servletName);

                //3.调用service,通过或OOP的动态绑定机制,调用运动类型的doGet/doPost
                if (hspHttpServlet != null) {//得到
                    hspHttpServlet.service(hspRequest, hspResponse);
                } else {
                    //没有这个servlet,返回404提示信息
                    String resp = HspResponse.respHeader + "

404 Not Found

"; OutputStream outputStream = hspResponse.getOutputStream(); outputStream.write(resp.getBytes()); outputStream.flush(); outputStream.close(); } socket.close(); } catch (IOException e) { e.printStackTrace(); } finally { //确保socket要关闭 if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
1.HspRequest 作用是封装http请求的数据
2.比如:method 、uri、还有参数列表
3.HspRequest等价与原生的servlet中的HttpServletRequest
4.此处只考虑GET请求
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;

public class HspRequest {
    private String method;
    private String uri;
    //存放参数列表 使用HashMap
    private HashMap parametersMapping =
            new HashMap<>();
    private InputStream inputStream=null;

    //构造器
    //inputStream是和对应的Http请求的socket关联
    public HspRequest(InputStream inputStream) {
        this.inputStream=inputStream;
        //完成对http请求的封装
       encapHttpRequest();
    }
    //将http请求的相关数据,进行封装,然后提供相关的方法,进行获取
    private void encapHttpRequest(){
        try {
            //将inputStream转化为BufferedReader
            BufferedReader bufferedReader =
                    new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
            //读取第一行
            String requestLine = bufferedReader.readLine();

            String[] requestLineArr = requestLine.split(" ");
            //获取method
            method = requestLineArr[0];

            //
            int index = requestLineArr[1].indexOf("?");
            if (index == -1) {//说明没有参数列表
                uri = requestLineArr[1];
            } else {
                uri = requestLineArr[1].substring(0, index);
                //获取参数列表放入parametersMapping
                String parameters = requestLineArr[1].substring(index + 1);
                String[] parametersPair = parameters.split("&");
                if (null != parametersPair && !"".equals(parametersPair)) {
                    for (String parameterPair : parametersPair) {
                        String[] parameterVal = parameterPair.split("=");
                        if (parameterVal.length == 2) {
                            //放入到parametersMapping
                            parametersMapping.put(parameterVal[0], parameterVal[1]);
                        }
                    }
                }
            }
            //这里不能关闭流
//            inputStream.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //request有一个特别重要的方法
    public String getParameter(String name) {
        if (parametersMapping.containsKey(name)) {
            return parametersMapping.get(name);
        } else {
            return "";
        }

    }


    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    @Override
    public String toString() {
        return "HspRequest{" +
                "method='" + method + '\'' +
                ", uri='" + uri + '\'' +
                ", parametersMapping=" + parametersMapping +
                '}';
    }
}

 

1.HspResponse对象可以封装OutputStream(是socket关联)
2.即可以通过 HspResponse对象 返回Http响应给浏览器/客户端、
3.HspResponse等价于原生的servlet的HttpServletResponse
public class HspResponse {
    private OutputStream outputStream=null;

    //写一个http响应头
    public static final String respHeader = "HTTP/1.1 200 OK\r\n" +
            "Content-Type:text/html;charset=utf-8\r\n\r\n";

    //在创建HspResponse 对象时,传入的outputStream是和Socket关联的
    public HspResponse(OutputStream outputStream) {
        this.outputStream = outputStream;
    }

    //当需要给浏览器返回数据时,可以通过HspResponse 的输出流完成
    public OutputStream getOutputStream() {
        return outputStream;
    }
}

1.业务代码,完成计算任务

import com.hspedu.tomcat.http.HspRequest;
import com.hspedu.tomcat.http.HspResponse;
import com.hspedu.tomcat.utils.WebUtils;

import java.io.IOException;
import java.io.OutputStream;

public class HspCalServlet1 extends HspHttpServlet{
    @Override
    public void doGet(HspRequest request, HspResponse response) {
        //写业务代码,完成计算任务
        int num1 = WebUtils.parseInt(request.getParameter("num1"), 0);
        int num2 = WebUtils.parseInt(request.getParameter("num2"), 0);

        int sum = num1 * num2;

        //返回计算结果给浏览器/客户端
        //outputStream 是和当前 Socket关联
        OutputStream outputStream = response.getOutputStream();
        String respMes = HspResponse.respHeader
                + "

" + num1 + "*" + num2 + "=" + sum + "HspTomcatV3 -反射+xml创建 -乘法

"; try { outputStream.write(respMes.getBytes()); outputStream.flush(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void doPost(HspRequest request, HspResponse response) { this.doGet(request,response); } @Override public void init() throws Exception { } @Override public void destroy() { } }

抽象类

package com.hspedu.tomcat.servlet;

import com.hspedu.tomcat.http.HspRequest;
import com.hspedu.tomcat.http.HspResponse;

import java.io.IOException;

public abstract class HspHttpServlet implements HspServlet {
    @Override
    public void service(HspRequest request, HspResponse response) throws IOException {
        //equalsIgnoreCase 比较两个字符串内容是否相等,并且不区分大小写
        if ("GET".equalsIgnoreCase(request.getMethod())){
            //这里会有动态绑定
            this.doGet(request,response);
        }else if("POST".equalsIgnoreCase(request.getMethod())){
            this.doPost(request,response);
        }
    }
    //使用了模板设计模式
    //让HspHttpServlet 子类 HspCalServlet 实现
    public abstract  void doGet(HspRequest request,HspResponse response);
    public abstract  void doPost(HspRequest request,HspResponse response);
}

接口

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

/**
 * 先搭建结构,再写内容
 * 只保留了三个核心方法
 */
public interface HspServlet {
    void init() throws Exception;

    void service(HspRequest request, HspResponse response) throws  IOException;

    void destroy();

工具类

package com.hspedu.tomcat.utils;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class WebUtils {
    //将字符串转化为数字的方法
    public static int parseInt(String StrNum,int defaultVal){
        try{
            return Integer.parseInt(StrNum);
        }catch (NumberFormatException e){
            System.out.println(StrNum+"格式不对,转换失败");
        }
        return defaultVal;
    }

    //判断uri是不是html文件
    public static boolean isHtml(String uri){

        return uri.endsWith(".html");
    }

    //根据文件名来读取文件‘
    public static String readHtml(String fileName){
        String path= com.hspedu.utils.WebUtils.class.getResource("/").getPath();
        StringBuilder stringBuilder = new StringBuilder();
        try {
            BufferedReader bufferedReader = new BufferedReader(new FileReader(path + fileName));
            String buff="";
            while ((buff=bufferedReader.readLine())!=null){
                stringBuilder.append(buff);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuilder.toString();
    }

}

实现类

package com.hspedu.tomcat;

import com.hspedu.tomcat.handler.HSPRequestHandler;
import com.hspedu.tomcat.servlet.HspHttpServlet;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

//第3版Tomcat,实现通过xml+反射来初始化容器
public class HspTomcatV3 {
    //1.存放容器 servletMapping
    //-ConcurrentHashMap
    //-HashMap
    //key           -value
    //ServletName   对应的实例

    public static final HashMap
            servletMapping = new HashMap<>();


    //2.容器 servletUrlMapping
    //-ConcurrentHashMap
    //-HashMap
    //key           -value
    //url-pattern   ServletName

    public static final HashMap
        servletUrlMapping=new HashMap<>();


    public static void main(String[] args) {
        HspTomcatV3 hspTomcatV3 = new HspTomcatV3();
        hspTomcatV3.init();
        //启动后hspTomcat容器
        hspTomcatV3.run();
    }


    //启动HspTomcatV3容器
    public void run(){
        try {
            ServerSocket serverSocket = new ServerSocket(8080);
            System.out.println("======MyTomcatV3在8080端口监听======");
            while (!serverSocket.isClosed()){
                Socket socket = serverSocket.accept();
                HSPRequestHandler hspRequestHandler = new HSPRequestHandler(socket);
                new Thread(hspRequestHandler).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }



    //直接对两个容器进行初始化
    public void init(){
        //读取web.xml  =>使用dom4j
        //得到web.xml文件路径
        String path=HspTomcatV3.class.getResource("/").getPath();
        SAXReader saxReader=new SAXReader();

        try {
            Document document = saxReader.read(new File(path + "web.xml"));
            System.out.println("document="+document);

            //得到根元素
            Element rootElement = document.getRootElement();
            //得到根元素下的所有元素
            List elements = rootElement.elements();
            //遍历并过滤到 servlet servlet-mapping
            for (Element element : elements) {
                if("servlet".equalsIgnoreCase(element.getName())){
                    //这是一个servlet配置
                    //使用反射讲该servlet实例放入到servletMapping
                    Element servletName = element.element("servlet-name");
                    Element servletClass = element.element("servlet-class");
                    servletMapping.put(servletName.getText(),
                            (HspHttpServlet) Class.forName(servletClass.getText().trim()).newInstance());

                }else if("servlet-mapping".equalsIgnoreCase(element.getName())){
                    //这是一个servlet-mapping配置
                    Element servletName = element.element("servlet-name");
                    Element urlPattern = element.element("url-pattern");
                    servletUrlMapping.put(urlPattern.getText(),servletName.getText());

                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("servletMapping="+servletMapping);
        System.out.println("servletUrlMapping="+servletUrlMapping);

    }

}

你可能感兴趣的:(tomcat,java)