模拟带Servlet技术的HTTP服务器的Java实现

上一篇文章说道, Web发展初期, 用户只能查看静态页面. 随着Web发展,只能显示静态页面的web显然已经不能满足大众的需求,所以出现了CGI和用Java编写的Servlet程序.
Servlet可以根据用户的请求动态的生成html页面,然后发给浏览器.

下面模拟一下这个过程:

  • HttpServer2类:服务器类,负责启动Http服务.
  • Servlet接口: 定义Servlet服务接口.
  • HelloServlet类:实现Servlet接口.用户提交请求时,HttpServer2将请求发给HelloServlet处理.处理完后动态生成页面返回给用户.
  • ServletRequest类: 封装用户的请求.交给HelloServlet处理.
  • ServletResponse类: 封装返回的响应.由HelloServlet返回.

HttpServer2类

服务器类,负责启动Http服务.

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

public class HttpServer2 {
    private static final int port = 8088;
    private ServerSocket serverSocket = null;

    public HttpServer2() throws IOException {
        serverSocket = new ServerSocket(port);
        System.out.println("HTTPServer startup OK...");
    }

    public void work() throws IOException {
        while (true) {
            try {
                Socket socket = serverSocket.accept();

                ServletRequest request = new ServletRequest(
                        socket.getInputStream());
                ServletResponse response = new ServletResponse(
                        socket.getOutputStream());

                System.out.println("Receive request:\n" + request.getRequest());
                String servletName = request.getServletName();
    ​
    ​//动态生成servlet
                Servlet servlet = (Servlet) Class.forName(servletName)
                        .newInstance();

    ​//调用servlet接口
                servlet.init();
                servlet.service(request, response);
                servlet.destroy();

                socket.close();

            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

    }
    public static void main(String[] args) throws IOException,
            InterruptedException {
        HttpServer2 httpServer = new HttpServer2();

        httpServer.work();
    }

}

Servlet接口

定义Servlet服务接口.

public interface Servlet {
    public void init();
    public void service(ServletRequest req, ServletResponse res) throws Exception;
    public void destroy();
}

HelloServlet类

实现Servlet接口.用户提交请求时,HttpServer2将请求发给HelloServlet处理.处理完后动态生成页面返回给用户.

public class HelloServlet implements Servlet {

    @Override
    public void init() {
        // TODO Auto-generated method stub
        System.out.println("servlet init ");
    }

    @Override
    public void service(ServletRequest req, ServletResponse res)
            throws Exception {
        // TODO Auto-generated method stub
        String contentType = req.getContentType();
        String param = req.getParam();
    ​//组装HTTP响应头
        String header = res.assembleResponseHeader(contentType);
    ​//组装HTTP响应正文
        String body = res.assembleResponseBody(param);
    ​//返回响应
        res.write(header + body);
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        System.out.println("servlet destroy ");
    }

}

ServletRequest类

封装用户的请求.交给HelloServlet处理.

import java.io.IOException;
import java.io.InputStream;

public class ServletRequest {
    private String request;
    private InputStream socketIn;
    private String URI;
    private String contentType;
    private String param;

    public ServletRequest(InputStream socketIn) throws IOException {
        // TODO Auto-generated constructor stub
        this.socketIn = socketIn;
        this.request = _getRequest();
        this.URI = _getURI();
        this.contentType = _getContentType();
        this.param = _getParam();
    }

    public String getRequest() {
        return request;
    }

    public String getURI() {
        return URI;
    }

    public String getContentType() {
        return contentType;
    }

    public String getParam() {
        return param;
    }

    private String _getRequest() throws IOException {
        int size = socketIn.available();
        byte[] requestBuff = new byte[size];
        socketIn.read(requestBuff);
        return new String(requestBuff);
    }
    ​//获得要调用servlet的类名
    public String getServletName(){
        return URI.substring(URI.indexOf("/") + 1, URI.indexOf("?"));
    }

    private String _getURI() {
        String firstLine = request.substring(0, request.indexOf("\r\n"));
        String[] parts = firstLine.split(" ");

        return parts[1];
    }

    private String _getContentType() {
        /* 决定HTTP响应正文的类型 */
        return "html";
    }

//获得请求参数
    private String _getParam() {
        String paramString = URI.substring(URI.indexOf("?") + 1);
        String[] paramPairs = paramString.split("=");
        return paramPairs[1];
    }
}

ServletResponse类

封装返回的响应.由HelloServlet返回.

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

public class ServletResponse {
    private OutputStream outputStream;

    public ServletResponse(OutputStream outputStream) {
        // TODO Auto-generated constructor stub
        this.outputStream = outputStream;
    }

    public String assembleResponseHeader(String contentType) {
        /* 创建HTTP响应结果 */
        // HTTP响应的第一行
        String responseFirstLine = "HTTP/1.1 200 OK\r\n";
        // HTTP响应头
        String responseHeader = "Content-Type:" + contentType + "\r\n\r\n";

        return responseFirstLine + responseHeader;
    }

    public String assembleResponseBody(String param) {
        String content = "<body><h1>Hello:" + param + "</h1></body>";
        String title = "<head><title>HelloWorld</title></head>";
        String body = "<html>" + title + content + "</html>";
        return body;
    }

    public void write(String res) throws IOException {
        outputStream.write(res.getBytes());
    }

}

测试

在chrome浏览器输入http://localhost:8088/HelloServlet?username=tom.
即用户请求的参数是tom,要调用HelloServlet. (在实际的servlet实现中,是用一个web.xm配置文件实现URI到servlet的映射.)

这里写图片描述

servlet解析出来后组装成html返回给浏览器.显示为Hello:tom

这里写图片描述

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>

版权声明:本文为博主原创文章,未经博主允许不得转载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值