模仿Tomcat和servlet规范

1.首先我们要监听一个端口,当浏览器发送请求的时候,我们通过监听端口获取socket对象,然后进行相应的==操作==。(定义Tomcat类)

2.一旦有浏览器发送请求,我们就会进行操作,考虑会有多个浏览器发送请求的情况,我们要把操作类实现多线程,具体来说,每当有浏览发送请求我们要开启线程完成相应的操作,具体的操作有:要获取浏览器发送的request请求的相关数据、根据得到的数据作为key去相关的容器获取实例对象,然后调用实例对象对应的service方法,(定义RequestHandler类)

3.tomcat会对http响应和请求进行包装得到httpServletRequest和HttpServletResponse对象,通过着两个对象我们可以获取浏览器http请求中携带的数据信息并且将相关的信息返回给浏览器。这里我们自己定义两个类,分别是HttpRequest和HttpResponse,HttpRequest这个类持有与socket关联的输入流,因此可以获取浏览器发送过来的信息,我们在这个类中实现一些方法来返回浏览器发送过来的数据,比如getMthod、getUri、getPatameters,通过这些方法,我们可以在处理的时候直接通过HttpRequest的实例来获取相关的信息。HttpResponse这个类持有与socket关联的文件输出流,同时我们需要设置一个response头信息,这样的话我们后面如果需要将自己的数据返回给浏览器,我们只需要将自己的信息与这个response头信息进行拼接即可。(定义HttpRequest和HttpResponse类

4.servlet规范,通过观察类的结构关系图我们可以知道,servlet规范可以分为三个模块,第一部分主要是一个Servlet接口,会定义一些抽象方法;第二个部分是HttpServlet抽象类,这个类实现了模板设计模式,具体就是实现了service方法,并且将HttpRequest对象和HttpResponse对象作为形参传进来,通过获取响应的方法,我们调用对应的get方法或者post方法;这里的doGet方法和doPost方法定义为抽象方法,具体的实现我们是在自己的servlet程序中实现实际的业务逻辑。(定义Myservlet接口、MyHttpServlet抽象类、MyCalServlet类)

补充:

TomCat会维持两个容器,一个容器对应web.xml文件的servlet标签,他的key存放servlerName,value用来存放对应的实例;另外一个容器对应servlet-mapping标签,key用来存储url,value用来存servletName

这个过程我们是利用DOM4j技术来实现的

RequestHandler的操作:

首先我们要获取浏览器的uri,因此我们要调用HttpRequest中的geturl方法,这个过程我们要创建HttpRequest实例,并且要把socket关联的inputStream传进去;有了uri之后,我们需要对uri进行处理,得到浏览器请求的资源,如果访问的是静态资源的话,我们直接获取静态资源并且利用HttpResponse返回给浏览器;如果请求的是servlet资源,我们需要去访问TomCat下的两个容器,根据uri中的资源名去找对应的实例对象,最后我们通过得到的实例对象调用service()方法。

Tomcat类代码

package com.lewisdeu.tomcat;
import com.lewisdeu.handler.RequestHandler;
import com.lewisdeu.servlet.MyHttpServlet;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lewis
 * @version 1.0
 */
//存放容器servletMapping
//    key 存放ServletName
//    value 存放对应的实例
public class TomcatV3 {
    public static final ConcurrentHashMap<String,MyHttpServlet>servletHapping
            = new ConcurrentHashMap<>();

    public static final ConcurrentHashMap<String,String>servletUrlMapping = new ConcurrentHashMap<>();


    public static void main(String[] args) {
        TomcatV3 tomcatV3 = new TomcatV3();
        tomcatV3.init();
        tomcatV3.run();
    }

    public void run(){
        try {
            ServerSocket serverSocket = new ServerSocket(8080);
            System.out.println("tomcatV3在监听...");
            while (!serverSocket.isClosed()){
                Socket socket = serverSocket.accept();
                RequestHandler requestHandler = new RequestHandler(socket);
                new Thread(requestHandler).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
//    对两个容器进行初始化
    public void init(){
        //读取web。xml文件 dom4j
        String path = TomcatV3.class.getResource("/").getPath();
//        System.out.println(path);
        //读取dom4j
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(new File(path+"web.xml"));
            //得到根元素
            Element rootElement = document.getRootElement();
            //得到根元素下面的所有元素
            List<Element> elements = rootElement.elements();
            //遍历并过滤得到servlet和servlet-mapping
            for (Element element : elements) {
                if("servlet".equalsIgnoreCase(element.getName())){
                    //这是一个servlet配置"
//                    System.out.println("发现servlet");
                    //使用反射将servlet实例放到存放容器servletMapping
                    Element servletName = element.element("servlet-name");
                    Element servlet_class = element.element("servlet-class");
                    servletHapping.put(servletName.getText(),(MyHttpServlet) Class.forName(servlet_class.getText().trim()).newInstance());
                }else if("servlet-mapping".equalsIgnoreCase(element.getName())){
                    //这是一个servlet-mapping的配置
//                    System.out.println("发现servlet-,apping");
                    Element servletName1 = element.element("servlet-name");
                    Element url_pattern = element.element("url-pattern");
                    System.out.println("通过dom4j获取的uri:"+url_pattern.getText());
                    System.out.println("uri对应的servletname在容器中:" +servletName1.getText());
                    servletUrlMapping.put(url_pattern.getText(),servletName1.getText());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

RequestHandler代码

package com.lewisdeu.handler;

import com.lewisdeu.http.HttpRequest;
import com.lewisdeu.http.HttpResponse;
import com.lewisdeu.servlet.MyHttpServlet;
import com.lewisdeu.tomcat.TomcatV3;

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

/**
 * @author lewis
 * @version 1.0
 */
public class RequestHandler implements Runnable{
    //定义socket
    private Socket socket;

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

    @Override
    public void run() {
        InputStream inputStream = null;
        try {
            inputStream = socket.getInputStream();
            HttpRequest httpRequest = new HttpRequest(inputStream);
            String method = httpRequest.getMethod();
            String num1 = httpRequest.getParameter("num1");
            String num2 = httpRequest.getParameter("num2");
            System.out.println("method" + method);
            System.out.println("num1 = " + num1 + "\tnum2 = "+ num2);
            System.out.println(httpRequest);

            HttpResponse httpResponse = new HttpResponse(socket.getOutputStream())
            //得到uri
            String uri = httpRequest.getUri();
            System.out.println("handler中展示:"+uri);
            //这里要判断是否是静态资源
            if(uri.contains(".") && !"/favicon.ico".equalsIgnoreCase(uri)){
                //如果uri中含有.结尾的,我们默认是静态资源/login.html
                String substring = uri.substring(1);
                String path = TomcatV3.class.getResource("/").getPath();
                BufferedReader bufferedReader = new BufferedReader(new FileReader(path+substring));
                String content;
                String all = "";
                OutputStream outputStream0 = httpResponse.getOutputStream();
                while((content = bufferedReader.readLine()) != null){
                    all+= content;
                }
                outputStream0.write((HttpResponse.respHeader+all).getBytes());
                outputStream0.close();
            }else{
                String servletName = TomcatV3.servletUrlMapping.get(uri);
                System.out.println("根据输入的uri在容器中找到的servletname:"+servletName);
                //进一步获取servlet的实例
//            servlet的运行类型是MyCalServlet
                if(servletName != null) {
                    MyHttpServlet servlet = TomcatV3.servletHapping.get(servletName);

                    if(servlet != null){
                        servlet.service(httpRequest,httpResponse);
                    }else {
                        //没有servlet
                        OutputStream outputStream1 = httpResponse.getOutputStream();
                        outputStream1.write((HttpResponse.respHeader+"<h1>404 not found<h1>").getBytes());
                        outputStream1.close();
                    }
                }else {
                    OutputStream outputStream1 = httpResponse.getOutputStream();
                    outputStream1.write((HttpResponse.respHeader+"<h1>404 not found<h1>").getBytes());
                    outputStream1.close();
                }

            }
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //确保socket关闭,否则会出现阻塞
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

HttpRequest类和HttpResonse

package com.lewisdeu.http;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;

/**
 * @author lewis
 * @version 1.0
 *和原始的http请求关联的对象,模仿httpservletRequest
 * HttpRequest封装http请求的数据
 * 比如:方法(get/post)、uri、数据
 * 数据格式:get /myCalServlet?num1=10&num2=20
 */
public class HttpRequest {
    private String method;
    private String uri;
    private HashMap<String,String>parametersHashMapping = new HashMap<>();
    private InputStream inputStream = null;



    public HttpRequest(InputStream inputStream){
        //完成对http请求的封装
        this.inputStream = inputStream;
        encapHttpRequest();
    }

    //将http的相关数据进行封装,然后提供相关的方法获取参数
    public void encapHttpRequest(){
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
            String s = bufferedReader.readLine();
            System.out.println(s);
//            GET /calServlet?num1=20&num2=20 HTTP/1.1
            String[] s1 = s.split(" ");
            method = s1[0];
            int index = s1[1].indexOf("?");
//            uri = s1[1].substring(0,index);

            //如果?的索引是-1,说明没有参数列表
            if(index == -1){
                uri = s1[1];
            }else{
                uri = s1[1].substring(0,index);
                //获取参数列表放到hashmap中
                String parameters = s1[1].substring(index + 1);
                String[] param = parameters.split("&");
                //防止用户提交的时候:/mycalServlet?
                if(param != null &&!"".equals(param)){
                    for (int i = 0; i < param.length; i++) {
                        String[] split = param[i].split("=");
                        if(split.length == 2){
//                            System.out.println(split[0]);
//                            System.out.println(split[1]);
                            parametersHashMapping.put(split[0],split[1]);
                        }
                    }
                }
            }
//            inputStream.close();

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

    public String getMethod(){
        return method;
    }


    public String getUri(){
        return uri;
    }
    public String getParameter(String parameters){
        if(parametersHashMapping.containsKey(parameters)){
            String s = parametersHashMapping.get(parameters);
            return s;
        }else{
            return null;
        }
    }


    @Override
    public String toString() {
        return "HttpRequest{" +
                "method='" + method + '\'' +
                ", uri='" + uri + '\'' +
                ", parametersHashMapping=" + parametersHashMapping +
                '}';
    }
}
package com.lewisdeu.http;

import java.io.OutputStream;

/**
 * @author lewis
 * @version 1.0
 * 1.HttpResonse可以封装outputstream
 */
public class HttpResponse {
    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";


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

    //当我们要返回数据的时候,可以通过HttpResponse的输出流
    public OutputStream getOutputStream(){
        return outputStream;
    }
}

servlet规范

package com.lewisdeu.http;

import java.io.OutputStream;

/**
 * @author lewis
 * @version 1.0
 * 1.HttpResonse可以封装outputstream
 */
public class HttpResponse {
    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";


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

    //当我们要返回数据的时候,可以通过HttpResponse的输出流
    public OutputStream getOutputStream(){
        return outputStream;
    }
}
package com.lewisdeu.servlet;

import com.lewisdeu.http.HttpRequest;
import com.lewisdeu.http.HttpResponse;

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

/**
 * @author lewis
 * @version 1.0
 */
public abstract class MyHttpServlet implements MyServlet{
    public void service(HttpRequest request, HttpResponse response){
        if("GET".equalsIgnoreCase(request.getMethod())){
            this.doGet(request, response);
        }else if("POST".equalsIgnoreCase(request.getMethod())){
            this.doPost(request, response);
        }

    }

    //使用模板设计模式
    public abstract void doGet(HttpRequest request,HttpResponse response);
    public abstract void doPost(HttpRequest request,HttpResponse response);
}
package com.lewisdeu.servlet;

import com.lewisdeu.http.HttpRequest;
import com.lewisdeu.http.HttpResponse;
import com.lewisdeu.utils.WebUtils;

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

/**
 * @author lewis
 * @version 1.0
 */
public class MyCalServlet extends MyHttpServlet {

    @Override
    public void doGet(HttpRequest request, HttpResponse response) {
        doPost(request, response);
    }

    @Override
    public void doPost(HttpRequest request, HttpResponse response) {
        //业务代码,完成计算
        String num1 = request.getParameter("num1");
        int num11 = WebUtils.toNum(num1,0);
        String num2 = request.getParameter("num2");
        int num22 = WebUtils.toNum(num2,0);
        int sum = num11 + num22;
        String res = HttpResponse.respHeader + "<h1>"+num1+"+"+num2+"="+sum+"</h1>";
        OutputStream outputStream = response.getOutputStream();
        try {
            outputStream.write(res.getBytes());
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void init(ServletConfig var1) throws ServletException {

    }

    @Override
    public void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException {

    }

    @Override
    public void destroy() {

    }
}

配置文件:web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>MyCalServlet</servlet-name>
    <servlet-class>com.lewisdeu.servlet.MyCalServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>MyCalServlet</servlet-name>
    <url-pattern>/myCalServlet</url-pattern>
  </servlet-mapping>

</web-app>

html文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算器</title>
</head>
<body>
<h1>计算器</h1>
<form action="/myCalServlet" method="get">
    num1:<input type="text" name="num1"><br/>
    num2:<input type="text" name="num2"><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>

运行结果:

要注意的是,本文中访问的servlet文件或者静态文件要放到target文件夹,如下图所示:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值