一、HttpRequest 封装思路
核心目标是解析 HTTP 请求报文,提取关键信息并封装为对象,简化后续处理。
- 定义核心成员变量:存储请求报文原始内容、请求方法(GET/POST)、请求 URL、请求模块、协议版本、请求参数(GET/POST 统一存储)、请求头参数等。
- 分步骤解析:先拆分请求报文为请求行、请求头、请求体三部分,再分别解析。
- 针对性处理:GET 请求参数从 URL 中提取,POST 请求参数从请求体中提取,请求头按 “Key: Value” 格式拆分存储。
- 提供便捷方法:通过 get 方法获取解析后的各类信息,无需重复解析逻辑。
二、HttpResponse 封装思路
核心目标是标准化 HTTP 响应格式,简化向客户端(浏览器)发送响应的操作。
- 定义核心成员变量:持有客户端 Socket 连接(用于获取输出流)、响应状态行(默认 HTTP/1.1 200 OK)、响应头(键值对存储)、响应体(字节数组形式)。
- 封装核心方法:提供 addHeader 方法灵活设置响应头,setBody 方法设置响应体,write 方法统一拼接响应格式(状态行→响应头→空行→响应体)并写入流。
- 细节优化:自动计算并补充 Content-Length 头部,统一处理换行符(\r\n)符合 HTTP 规范,支持动态传入媒体类型(适配不同资源)。
- 重载适配:支持直接传入字节数组(动态资源)或结合静态资源处理器(静态资源),简化调用。
三、静态资源处理器封装流程
核心目标是统一处理静态资源(HTML/CSS/JS/ 图片等)的读取、媒体类型匹配,简化静态资源响应。
- 定义核心属性:存储静态资源文件路径、文件字节数据、对应的媒体类型(Content-Type)。
- 初始化流程:通过构造方法传入文件路径,自动触发 “读取文件字节数据” 和 “匹配媒体类型” 两个核心操作。
- 关键功能实现:
- 读取字节数据:通过 FileInputStream 读取文件,根据文件大小创建字节数组,存入文件字节数据。
- 匹配媒体类型:根据文件后缀(.html/.css/.png 等)映射对应的媒体类型(如 text/html、image/png)。
- 对外提供接口:提供 getFileByte(获取文件字节)和 getMedia(获取媒体类型)方法,供 HttpResponse 调用。
四、静态资源与动态资源的判断逻辑
核心是区分 “直接返回文件” 和 “需执行业务逻辑生成响应” 两类请求,避免误判。
- 初始判断规则:通过请求模块(请求 URL 的核心路径)是否包含 “.” 来区分,包含则视为静态资源(如 /pages/index.html、/123.png)。
- 优化后判断规则(更严谨):
- 先查询动态资源映射(配置文件或注解),若能匹配到对应的 Servlet,则为动态资源。
- 若未匹配到,视为静态资源,交由 DefaultServlet 处理。
- 若静态资源文件不存在,则返回 404 页面(动态资源不存在也返回 404)。
五、动态资源的一步步优化流程
核心目标是解耦业务逻辑与请求分发,提升扩展性和可维护性。
1. 初始阶段:switch-case 分发
- 思路:在服务器主逻辑中,根据 HttpRequest 解析出的请求模块(如 /login、/enroll),通过 switch-case 分支匹配对应的业务逻辑。
- 优点:实现简单,适合初期少量动态资源。
- 缺点:耦合度极高,新增业务需修改主逻辑,违反开闭原则,维护成本随业务量增长而剧增。
2. 第一次优化:抽取 Servlet 基类(继承 + 多态)
- 思路:将每个动态资源的业务逻辑抽取为独立 Servlet 类,继承 BaseServlet 抽象类。
- 核心设计:BaseServlet 定义 doGet、doPost 抽象方法,以及 requestMethodHandler 方法(自动根据请求方法分发到 doGet/doPost)。
- 优点:业务逻辑与主逻辑解耦,每个 Servlet 专注自身业务,符合单一职责原则。
- 缺点:仍需通过 switch-case 匹配请求模块与 Servlet 实例,新增 Servlet 需修改分发逻辑。
3. 第二次优化:配置文件 + 反射
- 思路:用配置文件(如 servlet.properties)存储 “请求模块 = Servlet 类名” 的映射关系,通过反射动态创建 Servlet 实例,替代 switch-case。
- 核心步骤:
- 编写配置文件:如 /login=LoginServlet、/enroll=EnrollServlet。
- 编写工具类:加载配置文件到 HashMap,提供根据请求模块获取 Servlet 类名的方法。
- 反射创建实例:根据配置文件中的类名,通过 Class.forName 加载字节码,创建 Servlet 实例,调用 requestMethodHandler 方法。
- 优点:新增动态资源只需修改配置文件,无需改动主逻辑,扩展性大幅提升。
4. 第三次优化:注解 + 包扫描(最终优化)
- 思路:用自定义注解(如 @ServletMapping)标记 Servlet 对应的请求模块,通过包扫描工具自动识别带注解的 Servlet,替代配置文件。
- 核心步骤:
- 定义自定义注解:@ServletMapping(作用于类,存储请求模块路径)。
- 编写扫描工具类:使用 Reflections 框架扫描指定包下带 @ServletMapping 注解的类。
- 自动映射存储:解析注解中的请求模块,通过反射创建 Servlet 实例,存入 HashMap。
- 分发请求:根据请求模块从 HashMap 中获取 Servlet 实例,调用业务方法。
- 优点:无需配置文件,新增 Servlet 只需添加注解,配置零成本,扩展性和维护性达到最优。
1268

被折叠的 条评论
为什么被折叠?



