当前位置: 首页 > article >正文

DIY-Tomcat part 3 实现对动态资源的请求

实现ServletRequest

package connector;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
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;

/*
GET /index.html HTTP/1.1
        Host: localhost:8888
        Connection: keep-alive
        Cache-Control: max-age=0
        Upgrade-Insecure-Requests: 1
        User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
*/

public class Request implements ServletRequest {

  private static final int BUFFER_SIZE = 1024;

  private InputStream input;
  private String uri;

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

  public String getRequestURI() {
    return uri;
  }

  public void parse() {
    int length = 0;
    byte[] buffer = new byte[BUFFER_SIZE];
    try {
      length = input.read(buffer);
    } catch (IOException e) {
      e.printStackTrace();
    }

    StringBuilder request = new StringBuilder();
    for (int j=0; j<length; j++) {
      request.append((char)buffer[j]);
    }
    uri = parseUri(request.toString());
  }

  private String parseUri(String s) {
    int index1, index2;
    index1 = s.indexOf(' ');
    if (index1 != -1) {
      index2 = s.indexOf(' ', index1 + 1);
      if (index2 > index1) {
        return s.substring(index1 + 1, index2);
      }
    }
    return "";
  }

  @Override
  public Object getAttribute(String s) {
    return null;
  }

  @Override
  public Enumeration getAttributeNames() {
    return null;
  }

  @Override
  public String getCharacterEncoding() {
    return null;
  }

  @Override
  public void setCharacterEncoding(String s) throws UnsupportedEncodingException {

  }

  @Override
  public int getContentLength() {
    return 0;
  }

  @Override
  public String getContentType() {
    return null;
  }

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

  @Override
  public String getParameter(String s) {
    return null;
  }

  @Override
  public Enumeration getParameterNames() {
    return null;
  }

  @Override
  public String[] getParameterValues(String s) {
    return new String[0];
  }

  @Override
  public Map getParameterMap() {
    return null;
  }

  @Override
  public String getProtocol() {
    return null;
  }

  @Override
  public String getScheme() {
    return null;
  }

  @Override
  public String getServerName() {
    return null;
  }

  @Override
  public int getServerPort() {
    return 0;
  }

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

  @Override
  public String getRemoteAddr() {
    return null;
  }

  @Override
  public String getRemoteHost() {
    return null;
  }

  @Override
  public void setAttribute(String s, Object o) {

  }

  @Override
  public void removeAttribute(String s) {

  }

  @Override
  public Locale getLocale() {
    return null;
  }

  @Override
  public Enumeration getLocales() {
    return null;
  }

  @Override
  public boolean isSecure() {
    return false;
  }

  @Override
  public RequestDispatcher getRequestDispatcher(String s) {
    return null;
  }

  @Override
  public String getRealPath(String s) {
    return null;
  }
}
  • 主要是为了实现ServletRequest 接口

实现ServletResponse

package connector;

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

/*
HTTP/1.1 200 OK
 */
public class Response implements ServletResponse {

  private static final int BUFFER_SIZE = 1024;

  Request request;
  OutputStream output;

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

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

  public void sendStaticResource() throws IOException {
    File file = new File(ConnectorUtils.WEB_ROOT, request.getRequestURI());
    try {
      write(file, HttpStatus.SC_OK);
    } catch (IOException e) {
      write(new File(ConnectorUtils.WEB_ROOT, "404.html"), HttpStatus.SC_NOT_FOUND);
    }
  }

  private void write(File resource, HttpStatus status) throws IOException {
    try (FileInputStream fis = new FileInputStream(resource)) {
      output.write(ConnectorUtils.renderStatus(status).getBytes());
      byte[] buffer = new byte[BUFFER_SIZE];
      int length = 0;
      while ((length = fis.read(buffer, 0, BUFFER_SIZE)) != -1) {
        output.write(buffer, 0, length);
      }
    }
  }

  @Override
  public String getCharacterEncoding() {
    return null;
  }

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

  @Override
  public PrintWriter getWriter() throws IOException {
    PrintWriter writer = new PrintWriter(output, true);
    return writer;
  }

  @Override
  public void setContentLength(int i) {

  }

  @Override
  public void setContentType(String s) {

  }

  @Override
  public void setBufferSize(int i) {

  }

  @Override
  public int getBufferSize() {
    return 0;
  }

  @Override
  public void flushBuffer() throws IOException {

  }

  @Override
  public void resetBuffer() {

  }

  @Override
  public boolean isCommitted() {
    return false;
  }

  @Override
  public void reset() {

  }

  @Override
  public void setLocale(Locale locale) {

  }

  @Override
  public Locale getLocale() {
    return null;
  }
}
  • 也是主要为了实现ServletRequest 接口
  • 实现getWriter()方法

实现Servlet

import connector.ConnectorUtils;
import connector.HttpStatus;
import connector.Request;

import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

public class TimeServlet implements Servlet {

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

  }

  @Override
  public ServletConfig getServletConfig() {
    return null;
  }

  @Override
  public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    PrintWriter out = servletResponse.getWriter();
    out.println(ConnectorUtils.renderStatus(HttpStatus.SC_OK));
    out.println("What time is it now?");
    out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
          .format(new Date()));
  }

  @Override
  public String getServletInfo() {
    return null;
  }

  @Override
  public void destroy() {

  }
}

  • service实时返回当前时间的具体值

实现ServletProcessor

package processor;

import connector.*;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class ServletProcessor {

  URLClassLoader getServletLoader() throws MalformedURLException {
    File webroot = new File(ConnectorUtils.WEB_ROOT);
    URL webrootUrl = webroot.toURI().toURL();
    return new URLClassLoader(new URL[]{webrootUrl});
  }

  Servlet getServlet(URLClassLoader loader, Request request) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    /*
     /servlet/TimeServlet
    */
    String uri = request.getRequestURI();
    String servletName = uri.substring(uri.lastIndexOf("/") + 1);

    Class servletClass = loader.loadClass(servletName);
    Servlet servlet = (Servlet) servletClass.newInstance();
    return servlet;
  }

  public void process(Request request, Response response) throws IOException {
  //加载loader, 以获得具体servlet的上级目录
    URLClassLoader loader = getServletLoader();
    //通过request中的uri和loader中的上级目录加载对应的具体servlet类处理请求
    Servlet servlet = getServlet(loader, request);
    //用加载的servlet类处理请求
    servlet.service(request, response);
}

主要方法功能解释

  1. Class servletClass = loader.loadClass(servletName);
    loader会从webrootUrl的路径下尝试加载名字为servletName的类,这是实现请求动态资源的关键
  2. 用loader和request加载具体的servlet,再用该servlet处理请求,输出内容

改进Connector

改进Connector使其能够处理来自客户端对动态资源的访问请求

      if (request.getRequestURI().startsWith("/servlet/")) {
        ServletProcessor processor = new ServletProcessor();
        processor.process(request, response);
      } else {
        StaticProcessor processor = new StaticProcessor();
        processor.process(request, response);
      }
  • 如果请求是以/servlet/开头的,代表是对动态资源的请求,则将该请求交由ServletProcessor处理
  • 如果不是以/servlet/开头的,代表是对静态资源的请求,则交由StaticProcessor处理

测试

IDE客户端请求测试

    public static void main(String[] args)throws Exception{
        Socket socket = new Socket("localhost", 8888);
        OutputStream output = socket.getOutputStream();
        output.write("GET /servlet/TimeServlet HTTP/1.1".getBytes());
        socket.shutdownOutput();

        InputStream input = socket.getInputStream();
        byte[] buffer = new byte[2048];
        int length = input.read(buffer);
        StringBuilder response = new StringBuilder();
        for (int j=0; j<length; j++) {
            response.append((char)buffer[j]);
        }
        System.out.println(response.toString());
        socket.shutdownInput();

        socket.close();
    }

web浏览器测试

在这里插入图片描述
上述两种测试方法均能返回正确结果


http://www.kler.cn/a/415287.html

相关文章:

  • 列表上移下移功能实现
  • vue页面跟数据不同步this.$set
  • STL-开篇啦~
  • 阅读《基于蒙特卡洛法的破片打击无人机易损性分析》_笔记
  • Spring Boot【二】
  • Java面试题、八股文——JVM篇最终篇
  • 在shardingsphere执行存储过程
  • 力扣每日一题 单调数组对的数目(dp)
  • 期权懂|期权中的期权到期日引力是什么意思?
  • TextFSM模板太复杂?ntc-templates让一切变得简单!
  • Android studio与JS交互
  • Android Studio 右侧Gradle窗口只有test的task问题解决
  • pytest+allure生成报告显示loading和404
  • 浅谈C#库之DevExpress
  • Rust 组织管理
  • 知识点回顾
  • python的文件操作练习
  • 基于Java Springboot社区助老志愿者服务平台
  • 如何在 GitHub 上下载并切换到仓库的历史版本
  • Java学习,反射
  • 常用指标采集 exporter
  • 前端网络安全分析
  • 知识蒸馏中有哪些经验| 目标检测 |mobile-yolov5-pruning-distillation项目中剪枝知识分析
  • 在内网工作时,如何使用 vscode remote ssh 去连接内网服务器?
  • 开源项目:纯Python构建的中后台管理系统
  • 解决 YOLOv5 加载模型时 ‘AttributeError Can‘t get attribute ‘SPPF‘‘ 错误的方法