手写tomcat(二) 访问servlet

1、HTTPServer

package core;

import annotations.Servlet;
import baseservlet.AbstractServlet;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Set;


public class HTTPServer {
    /**
     * 监听端口
     */
    public static int port = 8080;

    /**
     * Key值为Servlet的别名(uri),value为该Servlet对象
     * default权限
     */
    static HashMap<String, AbstractServlet> map;

    static {
        //包名,可以通过application.properties设置
        getServlets("servlet");
    }

    static ServerSocket serverSocket = null;


public void acceptWait() {
        try {
            serverSocket = new ServerSocket(port);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //工作队列
        ArrayBlockingQueue<Runnable> workQueue  = new ArrayBlockingQueue<>(50);
        //线程池的基本大小,即在没有任务需要执行的时候线程池的大小
        int corePoolSize = 10;
        //线程池中允许的最大线程数
        int maximumPoolSize = 50;
        //空闲线程存活时间
        long keepAliveTime = 100L;
        //时间单位
        TimeUnit unit = TimeUnit.SECONDS;
        //拒绝策略
        RejectedExecutionHandler rejectionStrategy = new ThreadPoolExecutor.DiscardOldestPolicy();

        ThreadPoolExecutor tpe = new ThreadPoolExecutor(corePoolSize,
                maximumPoolSize,keepAliveTime,unit,workQueue, Executors.defaultThreadFactory(),rejectionStrategy);

        while (!serverSocket.isClosed()) {
            try {
                //单线程,阻塞式监听(bio)
                Socket socket = serverSocket.accept();
                RequestHandler handler = new RequestHandler(socket);
                tpe.execute(handler);
                handler.start();
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }
    }


    private static void getServlets(String packageName) {

        //class类的集合
        Set<Class<?>> classes = new LinkedHashSet<>();

        try {
            String packageDirName = packageName.replace(".", "/");
            Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(packageDirName);

            while (resources.hasMoreElements()) {
                URL url = resources.nextElement();
                String protocol = url.getProtocol();
                if ("file".equals(protocol)) {
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    findAndAddClassesInPackageByFile(packageName, filePath,true,classes);
                }else if("jar".equals(protocol)){
                    //扫描JAR包
                }
            }
            //遍历class集合
            if (map == null){
                map = new HashMap<>(classes.size());
            }
            for (Class<?> aClass : classes) {
                //如果该class有Servlet注解
                if (aClass.isAnnotationPresent(Servlet.class)){
                    try {
                        //添加至map集合中
                        map.put(aClass.getAnnotation(Servlet.class).value(), (AbstractServlet) aClass.newInstance());
                    } catch (InstantiationException | IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void findAndAddClassesInPackageByFile(String packageName,
                                                        String packagePath, final boolean recursive, Set<Class<?>> classes) {
        // 获取此包的目录 建立一个File
        File dir = new File(packagePath);
        // 如果不存在或者 也不是目录就直接返回
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        // 如果存在 就获取包下的所有文件 包括目录
        File[] dirfiles = dir.listFiles(new FileFilter() {
            // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
            @Override
            public boolean accept(File file) {
                return (recursive && file.isDirectory())
                        || (file.getName().endsWith(".class"));
            }
        });
        // 循环所有文件
        for (File file : dirfiles) {
            // 如果是目录 则继续扫描
            if (file.isDirectory()) {
                findAndAddClassesInPackageByFile(packageName + "."
                                + file.getName(), file.getAbsolutePath(), recursive,
                        classes);
            } else {
                // 如果是java类文件 去掉后面的.class 只留下类名
                String className = file.getName().substring(0,
                        file.getName().length() - 6);
                try {
                    // 添加到集合中去
                    // classes.add(Class.forName(packageName + '.' +
                    // className));
                    // 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
                    classes.add(Thread.currentThread().getContextClassLoader()
                            .loadClass(packageName + '.' + className));
                } catch (ClassNotFoundException e) {
                    // log.error("添加用户自定义视图类错误 找不到此类的.class文件");
                    e.printStackTrace();
                }
            }
        }
    }
}

2、Request

package core;

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


public class Request {

    private InputStream is;

    private String url;

    private String method;

    public Request(){

    }

    public Request(InputStream is){
        this.is = is;
        parse();
    }

    public String getMethod() {
        return method;
    }

    public String getUrl(){
        return url;
    }

    /**
     * 解析url
     */
    public void parse(){
        StringBuilder request = new StringBuilder(Response.BUFFER_SIZE);

        byte[] buffer = new byte[Response.BUFFER_SIZE];

        int i = 0;
        try{
            i = is.read(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }

        for (int j = 0; j < i; j++) {
            request.append((char)buffer[j]);
        }
        System.out.println(request.toString());
        parseUrl(request.toString());
    }

    /**
     *
     * @param request
     * @return
     */
    private void parseUrl(String request) {
        int index1,index2;
        //查看socket获取的请求头是否有值
        index1 = request.indexOf(' ');
        if (index1 != -1){
            this.method = request.substring(0, index1);
            index2 = request.indexOf(' ', index1 + 1);
            if (index2 > index1){
                this.url = request.substring(index1 + 1,index2);
            }
        }
    }

}

3、Response

package core;

import java.io.*;


public class Response {

    public static final Integer BUFFER_SIZE = 2048;

    private static final String WEB_ROOT = "D:";

    private static final String RESPONSE_HEADER = "HTTP/1.1 200 Read File Success\r\n" +
            "Content-Type: text/html;charset=UTF-9\r\n" + "\r\n";

    private Request request;

    private OutputStream outputStream;

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

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

    public void sendStaticResource() throws IOException {
        byte[] buffer = new byte[BUFFER_SIZE];
        FileInputStream fis = null;
        File file = new File(WEB_ROOT, request.getUrl());
        String returnMsg = null;
        try {
            if (file.exists() && !file.isDirectory()) {
                fis = new FileInputStream(file);
                StringBuilder sb = new StringBuilder();
                int length;
                while ((length = fis.read(buffer, 0, buffer.length)) != -1) {
                    sb.append(new String(buffer, 0, length, "gbk"));
                }
                returnMsg = "HTTP/1.1 200 OK\r\n" +
                        "Content-Type: text/html \r\n" +
                        "Content-Length: " + sb.length() + "\r\n" +
                        "\r\n" +
                        sb.toString();
            } else {
                String errorMsg = "<h1>" + file.getName() + " file or directory not exists</h1>";
                returnMsg = "HTTP/1.1 404 File Not Fount\r\n" +
                        "Content-Type: text/html \r\n" +
                        "Content-Length: " + errorMsg.length() + "\r\n" +
                        "\r\n" +
                        errorMsg;
            }
            outputStream.write(returnMsg.getBytes());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                fis.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }

    public void sendResponseContent(StringBuilder message){
        try {
            outputStream.write(new StringBuilder(RESPONSE_HEADER).append(message).toString().getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

4、Requesthandler,收到请求就会开启一个线程去处理

package core;

import baseservlet.AbstractServlet;
import com.sun.net.httpserver.HttpServer;

import java.net.Socket;


public class RequestHandler extends Thread{

    private Socket socket;

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

    @Override
    public void run() {

        try {
            //接收请求参数
            Request request = new Request(socket.getInputStream());
            AbstractServlet abstractServlet = HTTPServer.map.get(request.getUrl());

            //创建用于返回浏览器的对象
            Response response = new Response(socket.getOutputStream());
            response.setRequest(request);

            if (abstractServlet != null){
                abstractServlet.service(request,response);
            }else{
                //找不到对应的Servlet则直接访问文件
                response.sendStaticResource();
            }
            //如果http短连接则关闭socket
            //socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

5、GenericServlet,定义servlet里的方法

package baseservlet;

import core.Request;
import core.Response;


public interface GenericServlet {

    public void init();

    public void destroy();

    public void service(Request request , Response response);
}

6、AbstractServlet

package baseservlet;

import core.Request;
import core.Response;


public abstract class AbstractServlet implements GenericServlet{

    private static final String GET_METHOD = "GET";

    private static final String POST_METHOD = "POST";


    @Override
    public void service(Request request, Response response) {
        if(GET_METHOD.equalsIgnoreCase(request.getMethod())){
            doGet(request,response);
        }else if (POST_METHOD.equalsIgnoreCase(request.getMethod())){
            doPost(request,response);
        }
    }

    public abstract void doGet(Request request, Response response);

    public abstract void doPost(Request request, Response response);

    @Override
    public void init() {

    }

    @Override
    public void destroy() {

    }

}

7、测试用的servlet

package servlet;

import annotations.Servlet;
import baseservlet.AbstractServlet;
import core.Request;
import core.Response;

//标注路径
@Servlet("/user")
public class UserServlet extends AbstractServlet {

    @Override
    public void doGet(Request request, Response response) {
        doPost(request,response);
    }

    @Override
    public void doPost(Request request, Response response) {
        //执行业务代码
        response.sendResponseContent(new StringBuilder("<h1>Your are requesting the UserServlet</h1>"));
    }

}

8、Main 主启动类

import core.HTTPServer;


public class Main {
    //主启动类
    public static void main(String[] args) {
        HTTPServer httpServer = new HTTPServer();
        httpServer.acceptWait();
    }
}

在上一篇的基础上,实现了访问servlet

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值