package com.birdboot.core;

import com.birdboot.annotation.Controller;
import com.birdboot.annotation.RequestMapping;
import com.birdboot.http.HttpServletRequest;
import com.birdboot.http.HttpServletResponse;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URISyntaxException;

public class DispatcherServlet {
    private static DispatcherServlet instance = new DispatcherServlet();

    private DispatcherServlet() {
    }

    public static DispatcherServlet getInstance() {
        return instance;
    }

    private static File baseDir;
    private static File staticDir;

    static {
        try {
            baseDir = new File(
                    ClientHandler.class.getClassLoader().getResource('.').toURI()
            );
            staticDir = new File(baseDir, 'static');
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    public void service(HttpServletRequest request, HttpServletResponse response) throws Exception {

        String path = request.getRequestURI();

        System.out.println('请求的抽象路径是:' + path);

        // 1. 扫描controller包下的所有类
        File dir = new File(baseDir, 'com/birdboot/controller');
        File[] subs = dir.listFiles(f -> f.getName().endsWith('.class'));
        for (File sub : subs) {
            String className = sub.getName().replace('.class', '');
            // 加载对应类对象时,包名固定:com.birdboot.controller
            Class<?> cls = Class.forName('com.birdboot.controller.' + className);
            // 2. 查看哪些被注解@Controller标注的过的类(只有被该注解标注的类才认可为业务处理类)
            if (cls.isAnnotationPresent(Controller.class)) {
                Object obj = cls.newInstance();
                Method[] methods = cls.getMethods();
                // 3. 遍历这些类,并获取他们的所有方法,并查看哪些是业务方法
                for (Method method : methods) {
                    // 只有被注解@RequestMapping标注的方法才是业务方法
                    if (method.isAnnotationPresent(RequestMapping.class)) {
                        // 4. 遍历业务方法时比对该方法上@RequestMapping中传递的参数值是否与本次请求
                        // 路径path值一致?如果一致则说明本次请求就应当由该方法进行处理
                        // 因此利用反射机制调用该方法进行处理。
                        // 提示:反射调用后要记得return,避免执行后续处理静态资源的操作
                        method.invoke(obj, path, request.getQueryString());
                        return; // 处理完业务方法后直接返回
                    }
                }
            }
        }

        // 5. 如果扫描了所有的Controller中所有的业务方法,均未找到与本次请求匹配的路径
        // 则说明本次请求并非处理业务,那么执行下面请求静态资源的操作
        File file = new File(staticDir, path);

        if (file.isFile()) {
            response.setStatusCode(200);
            response.setStatusReason('OK');
            response.addHeader('Server', 'BirdServer');
            response.setContentFile(file);
        } else {
            response.setStatusCode(404);
            response.setStatusReason('NotFound');
            file = new File(staticDir, '404.html');
            response.addHeader('Server', 'BirdServer');
            response.setContentFile(file);
        }
    }
}

代码解析:

这段代码定义了 DispatcherServlet 类,它是 BirdBoot 框架的核心组件之一,负责处理 HTTP 请求并将其分发到相应的业务方法。

主要功能:

  1. 请求分发: 接收 HTTP 请求,并根据请求路径判断是否为业务请求。
  2. 业务处理: 如果是业务请求,则扫描所有带有 @Controller 注解的类,并查找匹配请求路径的 @RequestMapping 注解方法,然后通过反射机制调用该方法处理请求。
  3. 静态资源处理: 如果不是业务请求,则将其视为静态资源请求,并返回相应的静态资源文件。

代码优化:

  • 使用更清晰的注释解释代码逻辑。
  • 将业务处理逻辑与静态资源处理逻辑分开,提高代码可读性。
  • 在处理完业务方法后立即返回,避免执行不必要的代码。

总结:

DispatcherServlet 是 BirdBoot 框架的核心组件,它利用注解和反射机制实现了灵活的请求分发功能,是构建 Web 应用程序的重要基础。

基于注解的请求分发器:BirdBoot框架核心组件解析

原文地址: https://www.cveoy.top/t/topic/B9L 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录