自己弄个简单的Tomcat玩玩 (静态资源访问)

1.前言

版本:v1.0.0 MyTomcat
功能:访问静态资源文件(html,css,js)
工具:Maven+Idea
此篇博客Mytomcat实现的功能只能访问静态资源(图片处理点问题),我们把项目部署到Mytomcat的webapps目录下,开启MyTomcat服务后,就可以进行访问了!
csdn下载:点击下载
github下载:点击下载


2.需要准备的知识

  1. Socket编程
  2. HTTP协议
  3. 反射
  4. xml解析
  5. 多线程

3.设计步骤

1.封装response

A:构建报文头
B:构建响应的HTML正文内容
C:将报文头和HTML正文内容发送给客户端(浏览器)

2.封装request

A:接受浏览器发送的请求
B:解析浏览器发送来的请求

3.建Servlet类来转码处理请求和响应的业务

A.实现service方法,传入request,response

4.多线程实现多的客户端发请求

A.把与客户端浏览器的通信封装到一个线程当中

5.启动MyTomcat服务

A.Bootstrap类中的start()方法


4.代码实现

这里写图片描述

4.1 封装request
package cxx.catalina;

import java.io.*;
import java.net.URLDecoder;
import java.util.*;
/**
 * 代表一个HTTP请求,它的构造方法传入一个InputStream输入流
 * @Author: cxx
 * @Date: 2018/6/22 9:33
 */
public class Request {
    private static final String ENTER = "\r\n";
    //接收请求
    private BufferedReader br ;
    //储存接受信息
    private String requestHeader;
    //通过解析头信息得到请求方法
    private String method ;
    //通过解析头信息得到请求url
    private String action ;
    //通过解析头信息得到传过来的请求参数 ,可能存在一Key多Value的情况所以用list
    private Map<String, List<String>> parameter;

    //得到浏览器发过来的头信息
    public Request() {
        requestHeader = "";
        method = "";
        action = "";
        parameter = new HashMap<String, List<String>>();
    }
    public Request(InputStream is){
        this();
        br=new BufferedReader(new InputStreamReader(is));
        //接收到头部信息
        try {
            String temp;
            while(!(temp=br.readLine()).equals("")){
                requestHeader += (temp+ENTER);
            }
            System.out.println(requestHeader);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //解析头部信息
        parseRequestHeader();
    }

    /**
     * 解析头信息
     */
    public void parseRequestHeader(){
        //声明一个字符串,来存放请求参数
        String parameterString = "";
        //读取都头信息的第一行
        String firstLine = requestHeader.substring(0, requestHeader.indexOf(ENTER));
        //开始分离第一行
        //splitPoint分割点1
        int splitPointOne = firstLine.indexOf("/");
        method = firstLine.substring(0, splitPointOne).trim();
        //splitPoint分割点2
        int splitPointTwo = firstLine.indexOf("HTTP/");
        String actionTemp = firstLine.substring(splitPointOne,splitPointTwo).trim();
        if(method.equalsIgnoreCase("post")){
            //此处代码为得到post请求的参数字符串,哈哈哈哈,读者自己想想该怎么写哦~~
            this.action = actionTemp;
        }else if(method.equalsIgnoreCase("get")){
            if(actionTemp.contains("?")){
                parameterString = actionTemp.substring((actionTemp.indexOf("?")+1)).trim();
                this.action = actionTemp.substring(0, actionTemp.indexOf("?"));
            }else{
                this.action = actionTemp;
            }
            //将参数封装到Map中哦
            try {
                parseParameterString(parameterString);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 解析参数字符串,将参数封装到Map中
     * @param parameterString
     */
    private void parseParameterString(String parameterString) throws Exception {
        if("".equals(parameterString)){
            return;
        }else{
            String[] parameterKeyValues = parameterString.split("&");
            for (int i = 0; i < parameterKeyValues.length; i++) {
                String[] KeyValues = parameterKeyValues[i].split("=");
                //可能会出现有key没有value的情况
                if(KeyValues.length == 1){
                    KeyValues = Arrays.copyOf(KeyValues, 2);
                    KeyValues[1] = null;
                }
                String key = KeyValues[0].trim();
                String values = null == KeyValues[1] ? null : decode(KeyValues[1].trim(),"UTF-8");
                //将key和values封装到Map中
                if(!parameter.containsKey(key)){//如果不存在key,就创建一个
                    parameter.put(key, new ArrayList<String>());
                }
                List<String> value = parameter.get(key);
                value.add(values);
            }
        }
    }

    /**
     * 反解码:使用指定的编码机制对 application/x-www-form-urlencoded 字符串解码。
     * @param string
     * @param encoding
     * @return
     */
    public String decode(String string,String encoding){
        try {
            return URLDecoder.decode(string, encoding);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据名字得到多个值
     * @param name
     * @return
     */
    public String[] getParamterValues(String name){
        List<String> values = parameter.get(name);
        if(values == null){
            return null;
        }else{
            return values.toArray(new String[0]);
        }
    }

    /**
     * 根据名字返回单个值
     * @param name
     * @return
     */
    public String getParamter(String name){
        String[] value = getParamterValues(name);
        if(value == null){
            return null;
        }else{
            return value[0];
        }
    }

    public String getMethod() {
        return method;
    }

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

    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }
}
4.2 封装response
package cxx.catalina;

import java.io.*;
import java.util.Date;


/**
 * Http响应
 * @Author: cxx
 * @Date: 2018/6/22 9:45
 */
public class Response {
    private static final int BUFFER_SIZE=1024;
    private static final String SPACE=" ";
    private static final String ENTER = "\r\n";
    //头信息
    private StringBuilder headerInfo;
    //正文信息
    private StringBuilder textContent;
    //正文信息长度
    private int contentLength;
    //构建输出流
    private BufferedWriter bw;
    //获取request请求
    private Request request;

    public Response(){
        headerInfo=new StringBuilder();
        textContent=new StringBuilder();
        contentLength=0;
    }

    public Response(OutputStream os,Request request){
        this();
        this.request=request;
        this.bw=new BufferedWriter(new OutputStreamWriter(os));
    }

    /**
     * 创建头部信息 html报文
     * @param code
     */
    private void createHeader(int code){
        String type = request.getAction();
        headerInfo.append("HTTP/1.1").append(SPACE).append(code).append(SPACE);
        switch (code) {
            case 200:
                headerInfo.append("OK").append(ENTER);
                break;
            case 404:
                headerInfo.append("NOT FOUND").append(ENTER);
                break;
            case 500:
                headerInfo.append("SERVER ERROR").append(ENTER);
                break;
            default:
                break;
        }
        headerInfo.append("Server:myServer").append(SPACE).append("0.0.1v").append(ENTER);
        headerInfo.append("Date:Sat,"+SPACE).append(new Date()).append(ENTER);
        headerInfo.append("Content-Length:").append(contentLength).append(ENTER);
        if(type.endsWith("html")){
            headerInfo.append("Content-Type:text/html;charset=UTF-8").append(ENTER);
        }
        if (type.endsWith("ico")){
            headerInfo.append("Content-Type:application/octet-stream;charset=UTF-8").append(ENTER);
        }
        if (type.endsWith("png")||type.endsWith("jpg")){
            System.out.println("图片资源");
            headerInfo.append("Content-Type:image/jpeg;charset=UTF-8").append(ENTER);
        }
        headerInfo.append(ENTER);
    }

    /**
     * 响应给浏览器解析的内容(html正文)
     * @param content
     * @return
     */
    public Response htmlContent(String content){
        textContent.append(content).append(ENTER);
        contentLength+=(content+ENTER).toString().getBytes().length;
        return this;
    }

    /**
     * 发送给浏览器端
     * @param code
     */
    public void pushToClient(int code){
        createHeader(code);
        try {
            bw.append(headerInfo.toString());
            System.out.println(headerInfo.toString());
            bw.append(textContent.toString());
            bw.flush();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
4.3 建Servlet类来转码处理请求和响应的业务
package cxx.tomcat.server.http;
import cxx.catalina.Request;
import cxx.catalina.Response;
import cxx.tomcat.server.http.HttpServer;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;

/**
 * 专门处理请求和响应
 * @Author: cxx
 * @Date: 2018/6/22 21:39
 */
public class Servlet {
    private static final int BUFFER_SIZE=1024;
    public void service(Request request, Response response){
        System.out.println("service方法");
        byte[] b = new byte[BUFFER_SIZE];
        FileInputStream fis = null;
        try {
            StringBuilder contextText = new StringBuilder();
            File file = new File(HttpServer.WEB_ROOT + request.getAction());
            fis = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(fis);
            int ch = 0;
            while ((ch = bis.read(b)) != -1) {
                contextText.append(new String(b, 0, ch));
            }
            String username = request.getParamter("user");
            //response.htmlContent("<html><head></head><body>This is my page<br><br>");
            //response.htmlContent("欢迎:"+username+"  来到我的地盘</body></html>");
            response.htmlContent(contextText.toString());
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}
4.4 多线程实现多的客户端发请求
package cxx.tomcat.server.http;

import cxx.catalina.Request;
import cxx.catalina.Response;

import java.net.Socket;

/**
 * 多线程实现 多的客户端发请求
 * @Author: cxx
 * @Date: 2018/6/22 23:02
 */
public class HttpServerThread implements Runnable {
    private Socket client;
    private Request request;
    private Response response;
    private int code = 200;
    public HttpServerThread(Socket client){
        this.client=client;
        try{
            request=new Request(client.getInputStream());
            response=new Response(client.getOutputStream(),request);
        }catch (Exception e){
            code=500;
            return;
        }
    }

    @Override
    public void run() {
        Servlet servlet = new Servlet();
        servlet.service(request,response);
        response.pushToClient(code);
        try {
            client.close();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }
}
4.5启动MyTomcat服务
package cxx.tomcat.server;

import cxx.tomcat.server.http.HttpServerThread;

import java.net.ServerSocket;
import java.net.Socket;

/**
 * 启动MyTomcat
 * @Author: cxx
 * @Date: 2018/6/22 23:11
 */
public class Bootstrap {
    private boolean isShutDown = false;
    /**
     * 启动服务器
     */
    public void start(){
        int port=8888;
        System.out.println("Mytomcat服务开启.....http://127.0.0.1:"+port+"/login.html");
        start(port);
    }

    /**
     * 关闭服务器
     */
    private void stop() {
        isShutDown = true;
        System.out.println("Mytomcat服务关闭.....");
    }

    /**
     * 指定服务器端口
     * @param port
     */
    public void start(int port){
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            //2、接收来自浏览器的请求
            this.recevie(serverSocket);
        } catch (Exception e) {
            stop();
        }
    }

    /**
     * 接受客户端信息
     * @param serverSocket
     */
    private void recevie(ServerSocket serverSocket){
        try {
            while(!isShutDown){
                Socket client = serverSocket.accept();
                new Thread(new HttpServerThread(client)).start();
            }
        } catch (Exception e) {
            //如果这里面有问题直接关闭服务器
            isShutDown = true;
        }
    }

    public static void main(String[] args) {
       Bootstrap boot = new Bootstrap();
       boot.start();
    }
}

测试截图

这里写图片描述

访问的资源

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

猜你喜欢

转载自blog.csdn.net/m0_37499059/article/details/80779823
今日推荐