第②章一个简单得servlet容器

本文详细介绍了一个简易Servlet容器的构建过程,包括核心组件如PrimitiveServlet、Request、Response的实现,以及如何处理静态和动态请求。通过自定义的Servlet容器,深入理解Servlet的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本章的主要内容是:第一个描述的是最基本的web容器,但是他只能处理静态的请求,不能处理servlet代码,即动态的网页。所以这一章就给出了最基础版本的可以处理静态和动态的servlet容器。

下面给出主要的代码

1.PrimitiveServlet

这里首先给出对应的servlet的代码。这里的servlet代码实现了Servlet接口

注意:所有的自定义的servlet类都必须实现javax.servlet.servlet接口或者继承实现了该接口的类。为什么呢?因为在容器中一般是根据你自己定义的servlet的类名来获取对应的对象,每个人写的类名都不一样,如果不给出一个共有的接口的话,那么tomcat怎么知道要读取到对应的类对象以后,调用他的哪个方法, 传什么参数进去呢?所以这里就做了上述的约定。必须继承上述的接口或者实现该接口的类。

package servlet;

import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 原始的servlet
 */
public class PrimitiveServlet implements Servlet {
    public void init(ServletConfig config) throws ServletException {
        System.out.println("执行init()方法....");
    }

    public ServletConfig getServletConfig() {
        return null;
    }

    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("执行service");


        //这里自己定义了相应头部,作者源代码中没有写,会导致对应的
        String s="HTTP/1.1 200 OK\r\n\r\n";

        //获取输出流工具类
        PrintWriter outputStream = res.getWriter();
        outputStream.println(s+"hello rose are red....");
//        outputStream.print("vio are blue");
//        outputStream.close();
    }
    public String getServletInfo() {
        return null;
    }

    public void destroy() {
        System.out.println("执行destory....");
    }
}

注意上述的outputStream,前提要加上相应头部!不然前端无法看到对应的输出信息。

2.Request

这里和第一张的功能是一样的,Request主要是来提取请求的信息,在本章主要是用来提取URI的。下面给出他的具体的代码

package demon2;

import javax.servlet.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;

/**
 * 为什么继承ServletRequest,因为我们自己编写的servlet类的service方法都需要传入ServletRequest
 * 所以这里让我们自定义的Request继承对应的ServletRequest
 */
public class Request implements ServletRequest {
    /**
     * 输入流
     */
    private InputStream input;

    /**
     * 请求的资源
     */
    private String uri;

    public Request(InputStream input) {
        this.input = input;
    }

    /**
     * 解析报文方法
     */
    public void parse(){
        StringBuilder stringBuilder = new StringBuilder(2048);
        int readSum=0;
        byte[] buffer=new byte[2048];
        try {
            readSum= input.read(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
        for(int j=0;j<readSum;j++){
            stringBuilder.append((char) buffer[j]);
        }
        //解析请求资源
        uri=parseUri(stringBuilder.toString());
    }

    private String parseUri(String requestString){

        int index1,index2=0;
        index1=requestString.indexOf(' ');
        if(index1!=-1){
            index2=requestString.indexOf(' ',index1+1);
        }
        if(index2>index1){
            return requestString.substring(index1+1,index2);
        }
        return null;
    }

    public String getUri(){
        return uri;
    }
    public Object getAttribute(String name) {
        return null;
    }

    public Enumeration<String> getAttributeNames() {
        return null;
    }

    public String getCharacterEncoding() {
        return null;
    }

    public void setCharacterEncoding(String env) throws UnsupportedEncodingException {

    }

    public int getContentLength() {
        return 0;
    }

    public long getContentLengthLong() {
        return 0;
    }

    public String getContentType() {
        return null;
    }

    public ServletInputStream getInputStream() throws IOException {
        return null;
    }

    public String getParameter(String name) {
        return null;
    }

    public Enumeration<String> getParameterNames() {
        return null;
    }

    public String[] getParameterValues(String name) {
        return new String[0];
    }

    public Map<String, String[]> getParameterMap() {
        return null;
    }

    public String getProtocol() {
        return null;
    }

    public String getScheme() {
        return null;
    }

    public String getServerName() {
        return null;
    }

    public int getServerPort() {
        return 0;
    }

    public BufferedReader getReader() throws IOException {
        return null;
    }

    public String getRemoteAddr() {
        return null;
    }

    public String getRemoteHost() {
        return null;
    }

    public void setAttribute(String name, Object o) {

    }

    public void removeAttribute(String name) {

    }

    public Locale getLocale() {
        return null;
    }

    public Enumeration<Locale> getLocales() {
        return null;
    }

    public boolean isSecure() {
        return false;
    }

    public RequestDispatcher getRequestDispatcher(String path) {
        return null;
    }

    public String getRealPath(String path) {
        return null;
    }

    public int getRemotePort() {
        return 0;
    }

    public String getLocalName() {
        return null;
    }

    public String getLocalAddr() {
        return null;
    }

    public int getLocalPort() {
        return 0;
    }

    public ServletContext getServletContext() {
        return null;
    }

    public AsyncContext startAsync() throws IllegalStateException {
        return null;
    }

    public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
        return null;
    }

    public boolean isAsyncStarted() {
        return false;
    }

    public boolean isAsyncSupported() {
        return false;
    }

    public AsyncContext getAsyncContext() {
        return null;
    }

    public DispatcherType getDispatcherType() {
        return null;
    }
}

 

这里的自己写的Request方法实现了ServletRequest接口,为什么必须实现呢,和上述的servlet一样,因为规定的servlet的service方法中只认这ServletRequest类型,但是为了方便,这里只简单的实现的实现了几个方法。

 

3.Response

这里的主要的功能就是获取对应的输出流,将对应的数据返回给用户。(在这里静态方法的返回写在这里了),同样他也继承了ServletResponse,原因和Request一样的。

import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import java.io.*;
import java.util.Locale;

public class Response implements ServletResponse {
    private Request request;
    private OutputStream output;

    public Response(OutputStream output) {
        this.output = output;
    }
    public void setRequest(Request request){
        this.request=request;
    }

    /**
     * 发送静态资源给浏览器
     */
    public void sendStaticResource() throws IOException {
        byte[] bytes=new byte[1024];
        FileInputStream fis=null;
        try{
            System.out.println(demon1.PropertiesConst.WEB_ROOT);
            File file=new File(demon1.PropertiesConst.WEB_ROOT,request.getUri());
            if(file.exists()){
                fis = new FileInputStream(file);
                int ch=fis.read(bytes,0,1024);
                output.write("HTTP/1.1 200 OK\r\n\r\n".getBytes());
                while(ch!=-1){
                    output.write(bytes,0,ch);
                    ch=fis.read(bytes,0,1024);
                }
            }else {
                String errorMessge = "HTTP/1.1 404 FILE NOT Found\r\n" +
                        "Content-Type:text/html\r\n" +
                        "Content-Length:23\r\n" +
                        "\r\n" +
                        "<h1>file not found</h1>";
                output.write(errorMessge.getBytes());

            }
        }catch (Exception e){
            System.out.println(e.toString());
        }finally {
            if(fis!=null){
                fis.close();
            }
        }
    }

    public String getCharacterEncoding() {
        return null;
    }

    public String getContentType() {
        return null;
    }

    public ServletOutputStream getOutputStream() throws IOException {
        return null;
    }

    /**
     * 这里使用的true,表示使用   printWriter.println();的时候会自动刷新输出到浏览器
     * 而使用 printWriter.print();不会自动刷新
     * @return
     * @throws IOException
     */
    public PrintWriter getWriter() throws IOException {
        //使用最原始的输出流outputStream,创建一个给servlet使用的输出流
        return new PrintWriter(output, true);
    }

    public void setCharacterEncoding(String charset) {

    }

    public void setContentLength(int len) {

    }

    public void setContentLengthLong(long len) {

    }

    public void setContentType(String type) {

    }

    public void setBufferSize(int size) {

    }

    public int getBufferSize() {
        return 0;
    }

    public void flushBuffer() throws IOException {

    }

    public void resetBuffer() {

    }

    public boolean isCommitted() {
        return false;
    }

    public void reset() {

    }

    public void setLocale(Locale loc) {

    }

    public Locale getLocale() {
        return null;
    }
}

4.下面给出静态资源处理器和servlet资源处理器。

a)静态资源处理器

package demon2;

import java.io.IOException;

/**
 * 处理静态请求的类
 */
public class StaticResourceProcessor {
    public void process(Request request,Response response){
        try {
            response.sendStaticResource();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

b)servlet处理器

package demon2;

import demon1.PropertiesConst;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;

/**
 * 处理动态请求的方法,在这个里面调用service
 */
public class ServletProcessor {
    public void process(Request request,Response response){
        //获取资源
        String uri = request.getUri();
       //提取对应的servlet类名
        String servletName=uri.substring(uri.lastIndexOf("/")+1);
        URLClassLoader loader=null;
        try {
        URL[] urls=new URL[1];
        URLStreamHandler urlStreamHandler=null;
        File classPath=new File(PropertiesConst.WEB_ROOT);

            String repository=new URL("file",null,classPath.getCanonicalPath()+File.separator).toString();
            urls[0]=new URL(null,repository,urlStreamHandler);
            loader=new URLClassLoader(urls);
        } catch (IOException e) {
            e.printStackTrace();
        }

        Class myClass=null;
        try {
         myClass=loader.loadClass(servletName);
//            myClass=Class.forName(servletName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Servlet servlet;

        try {
            servlet= (Servlet) myClass.newInstance();
            servlet.service(request,response);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这里的主要功能就是根据servlet的类名获取对应的servlet对象,并调用其service方法。

 

最后给出对应的HttpServer类

他的主要的功能,

1.建立socket链接

2.提取对应的请求流和输出流InputStream和OutputStream

3.根据请求类型判断你是静态的请求还是servlet请求,分别调用对应不同的处理器。

package demon2;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class HttpServer {
    private static final String SHUTDOWN_COMMAND="/shutdown";

    private boolean shutdown=false;

    private static final int PORT=8080;

    private static final String IP="127.0.0.1";

    public void await(){
        ServerSocket serverSocket=null;
        try {
            serverSocket=new ServerSocket(PORT,1, InetAddress.getByName(IP));
        } catch (IOException e) {
            e.printStackTrace();
        }
        while(!shutdown){
            try {
                assert serverSocket != null;

                //阻塞监听端口
                Socket socket = serverSocket.accept();
                //输入流,包含请求报文
                InputStream inputStream = socket.getInputStream();
                Request request=new Request(inputStream);
                request.parse();
                //输出流,向浏览器写入输出报文
                OutputStream outputStream = socket.getOutputStream();
                Response response=new Response(outputStream);
                response.setRequest(request);

                /**
                 * 判断对应的是servlet还是静态资源
                 */
                if(request.getUri().startsWith("/servlet/")){
                    //
                    ServletProcessor servletProcessor=new ServletProcessor();
                    servletProcessor.process(request,response);
                }else {
                    StaticResourceProcessor staticResourceProcessor=new StaticResourceProcessor();
                    staticResourceProcessor.process(request,response);
                }

                socket.close();
                shutdown=request.getUri().equals(SHUTDOWN_COMMAND);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

上述就是本节内容的主要内容。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值