仿写DispatcherServlet

仿写DispatcherServlet

一、DispatcherServlet是什么?

DispatcherServlet是一个继承Servlet封装的类,相当于一个前置控制器,配置在web.xml文件当中的,拦截匹配的请求,Servlet拦截匹配规则要自己定义,将拦截下来的请求按照相应的规则分发到目标Controller来处理

	<servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springMVC.xml</param-value>
        </init-param>
        <load-on-startup>0</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

二、实现代码

1.创建存储RequestMap的对象

代码如下:

import java.io.Serializable;
import java.lang.reflect.Method;

public class RequestMap implements Serializable {
    private Method method;
    private Object object;
    private String requestMethod;

    public RequestMap() {
    }

    public RequestMap(Method method, Object object, String requestMethod) {
        super();
        this.method = method;
        this.object = object;
        this.requestMethod = requestMethod;
    }
    public Method getMethod() {
        return method;
    }
    public void setMethod(Method method) {
        this.method = method;
    }
    public Object getObject() {
        return object;
    }
    public void setObject(Object object) {
        this.object = object;
    }

    public String getRequestMethod() {
        return requestMethod;
    }

    public void setRequestMethod(String requestMethod) {
        this.requestMethod = requestMethod;
    }

    @Override
    public String toString() {
        return "RequestMap{" +
                "method=" + method +
                ", object=" + object +
                ", requestMethod='" + requestMethod + '\'' +
                '}';
    }
}

2.创建RequestMapping的注解

代码如下:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
	String value();
	String method() default "get";
}

3.创建DispatcherServlet对象

代码如下:

import cn.hutool.cron.CronUtil;
import cn.hutool.cron.task.Task;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import com.annotation.RequestMapping;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.util.*;

// 通过@WebServlet来拦截请求
// 也可以配置到web.xml文件中,这就是一个Servlet
@WebServlet("/")
public class DispatcherServlet extends HttpServlet {
	// 映射地址和Request对象
    public final static Map<String, RequestMap> map = new HashMap<>();
    // 静态资源
    public final static List<String> staticList = new ArrayList<>();

    @Override
    public void init(ServletConfig config) throws ServletException {
        ServletContext servletContext = config.getServletContext();
        String realPath = servletContext.getRealPath("/");
        // servlet的目录
        File file = new File(realPath + "\\WEB-INF\\classes\\com\\controller");
        // 获取servlet目录下的所有类
        String[] list = file.list();
        File staticFile = new File(realPath);
        FileUtil.itemFile(staticFile, staticList, realPath);
        assert list != null;
        for (String string : list) {
            // 截取类名称
            String name = string.substring(0, string.lastIndexOf("."));
            try {
                // 通过反射获取Class对象
                Class<?> c = Class.forName("com.controller." + name);
                // 判断该类上是否有RequestMapping注解
                String value = "";
                if (c.isAnnotationPresent(RequestMapping.class)) {
                    // 获取注解,进行强制转换成RequestMapping对象
                    RequestMapping annotation = c.getAnnotation(RequestMapping.class);
                    // 获取RequestMapping对象的值
                    value += annotation.value();
                }
                // 获取所有的方法
                // 没有就调用父类的service方法
                Method[] methods = c.getDeclaredMethods();
                // 循环遍历判断是否RequestMapping这个注解
                for (Method method : methods) {
                    if (method.isAnnotationPresent(RequestMapping.class)) {
                        RequestMapping meRequestMapping = method.getAnnotation(RequestMapping.class);
                        String requestMethod = meRequestMapping.method();
                        String meValue = meRequestMapping.value();
                        // 创建继承HttpServlet的类
                        Object o = c.newInstance();
                        // 添加Servlet
                        map.put(value + meValue, new RequestMap(method, o, requestMethod));
                    }
                }
            } catch (ClassNotFoundException | IllegalArgumentException | InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        // 这三个是我做的项目功能,你们可以不用
        //selectId(ApiDataUtils.INFORMATION);
        //selectId(ApiDataUtils.ROOT_ID);
        //selectId(ApiDataUtils.ROOT_DETAIL_ID);
        // 这是一个定时器
        //CronUtil.schedule("*/1 * * * *", (Task) () -> {
//            System.out.println("每一分钟执行一次,图片删除");
//            try {
//                List<String> headPhoto = Db.use().query("select head_photo from information where head_photo is not null and head_photo != ''", String.class);
//                String path = getServletContext().getRealPath("/page/image/head");
//                File staticPath = new File(path);
//                if (staticPath.exists() && headPhoto != null){
//                    String[] fileList = staticPath.list();
//                    if (fileList != null){
//                        for (String s : fileList) {
//                            if (!headPhoto.contains("/cartoon/page/image/head/" + s)){
//                                boolean delete = new File(staticPath, s).delete();
//                                if (delete){
//                                    System.out.println("成功删除-" + s + "-文件");
//                                }
//                            }
//                        }
//                    }
//                }
//            } catch (SQLException e) {
//                e.printStackTrace();
//            }
//        });
//        CronUtil.setMatchSecond(true);
//        CronUtil.start();
        super.init(config);
    }

	/**
		这个是我其他项目功能你们可以不用
	**/
    public void selectId(int choose) {
        Entity entity = null;
        try {
            switch (choose) {
                case ApiDataUtils.INFORMATION:
                    entity = Db.use().queryOne("select * from information order by id desc limit 1");
                    if (entity == null) {
                        ApiDataUtils.INFORMATION_ID = 1;
                    } else {
                        ApiDataUtils.INFORMATION_ID = entity.getInt("id") + 1;
                    }
                    break;
                case ApiDataUtils.ROOT:
                    entity = Db.use().queryOne("select * from root order by id desc limit 1");
                    if (entity == null) {
                        ApiDataUtils.ROOT_ID = 1;
                    } else {
                        ApiDataUtils.ROOT_ID = entity.getInt("id") + 1;
                    }
                    break;
                case ApiDataUtils.ROOT_DETAIL:
                    entity = Db.use().queryOne("select * from root_detail by id desc limit 1");
                    if (entity == null) {
                        ApiDataUtils.ROOT_DETAIL_ID = 1;
                    } else {
                        ApiDataUtils.ROOT_DETAIL_ID = entity.getInt("id") + 1;
                    }
                    break;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
        Set<String> keySet = map.keySet();
        String uri = req.getRequestURI().replace(req.getContextPath(), "");
        if (keySet.contains(uri)) {
            RequestMap requestMap = map.get(uri);
            if (req.getMethod().toLowerCase().equals(requestMap.getRequestMethod())) {
                try {
                    resp.setContentType("application/json;charset=utf-8");
                    requestMap.getMethod().invoke(requestMap.getObject(), req, resp);
                } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) {
                	// 这边是异常处理500
                    e.printStackTrace();
                    resp.setStatus(500);
                    resp.setContentType("text/html;charset=UTF-8");
                    ServletOutputStream outputStream = resp.getOutputStream();
                    outputStream.write("<!doctype html><html lang=\"zh\"><head><title>HTTP状态 500 - 内部服务器错误</title><style type=\"text/css\">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP状态 500 - 内部服务器错误</h1>".getBytes(StandardCharsets.UTF_8));
                    outputStream.write("<p><b>注意</b> 主要问题的全部在控制台里查看</p><hr class=\"line\" /><h3>Apache Tomcat/8.5.76</h3></body></html>".getBytes(StandardCharsets.UTF_8));
                    outputStream.close();
                }
            } else {
            	// 这边是异常处理405
                resp.setStatus(405);
                resp.setContentType("text/html;charset=UTF-8");
                OutputStream writer = resp.getOutputStream();
                writer.write(("<!doctype html><html lang='zh'><head><title>HTTP状态 405 - 方法不允许</title><style type='text/css'>body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP状态 405 - 方法不允许</h1><hr class='line' /><p><b>类型</b> 状态报告</p><p><b>消息</b> 此URL不支持Http方法POST</p><p><b>描述</b> 请求行中接收的方法由源服务器知道,但目标资源不支持</p><hr class='line' /><h3>" + getServletContext().getServerInfo() + "</h3></body></html>").getBytes(StandardCharsets.UTF_8));
                writer.close();
            }
        } else {
            resp.setContentType(FileUtil.responseType(uri) + ";charset=UTF-8");
            OutputStream writer = resp.getOutputStream();
            if (staticList.contains(uri)) {
                String realPath = req.getServletContext().getRealPath("/");
                File file = new File(realPath + "/" + uri);
                BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
                byte[] arr = new byte[1024];
                int l;
                while ((l = in.read(arr, 0, 1024)) != -1) {
                    writer.write(arr, 0, l);
                }
                return;
            }
            // 这边是异常处理404
            resp.setStatus(404);
            resp.setContentType("text/html;charset=UTF-8");
            writer.write(("<!doctype html><html lang='zh'><head><title>HTTP状态 404 - 未找到</title><style type='text/css'>body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP状态 404 - 未找到</h1><hr class='line' /><p><b>类型</b> 状态报告</p><p><b>消息</b> 请求的资源[&#47;]不可用</p><p><b>描述</b> 源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示。</p><hr class='line' /><h3>" + getServletContext().getServerInfo() + "</h3></body></html>").getBytes(StandardCharsets.UTF_8));
            writer.close();
        }
    }

    @Override
    public void destroy() {
        CronUtil.stop();
        super.destroy();
    }
}

三、运行项目

码云仓库地址https://gitee.com/lan_nan/cartoon
登录页面
在这里插入图片描述
首页
在这里插入图片描述


总结

以上就是通过对Servlet和DispatcherServlet的理解来完成这个功能,当然还有很多缺陷,就比如静态资源的上传,需要我手动调用才能配置一个映射地址,希望大家多多支持。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值