Servlet 体系结构的类层次关系
- Servlet(接口):定义了 Servlet 的核心生命周期方法(如
init()
、service()
、destroy()
),是所有 Servlet 的顶层规范,任何 Servlet 都需实现该接口。 - GenericServlet(抽象类):实现了
Servlet
接口,提供了与协议无关的通用功能(如初始化、销毁等),但未具体处理 HTTP 协议相关逻辑,保留抽象方法。 - HttpServlet(抽象类):继承
GenericServlet
,针对 HTTP 协议进行扩展,实现了基于 HTTP 方法(如 GET、POST)的请求分发逻辑(如doGet()
、doPost()
等方法),专注于处理 HTTP 场景。 - 自定义 Servlet 类:通过继承
HttpServlet
,重写对应的方法(如doGet()
、doPost()
),实现具体的业务逻辑,以处理客户端的 HTTP 请求。
Servlet资源准备
1、Servlet接口:
- Servlet接口的作用:实现Servlet生命周期,定义init()、service(request,response)和destroy()方法。
- 接口中的方法全都是抽象方法,只定义不实现,方法头默认为public abstract。
import com.qcby.Servlet.req.HttpServletRequest;
import com.qcby.Servlet.req.HttpServletResponse;public interface Servlet {void init();void service(HttpServletRequest request, HttpServletResponse response) throws Exception;void destroy();
}
-
init()
方法- 功能:初始化 Servlet 实例。
- 调用时机:Servlet 容器(如 Tomcat)创建 Servlet 实例后立即调用,通常用于资源初始化(如加载配置文件、建立数据库连接等)。
- 注意事项:该方法在 Servlet 的生命周期中仅调用一次。
-
service(HttpServletRequest request, HttpServletResponse response)
方法- 功能:处理客户端请求并返回响应。
- 参数:
HttpServletRequest
:封装客户端请求信息(如请求头、请求参数、URL 等)。HttpServletResponse
:封装服务器响应信息(如状态码、响应头、响应体等)。
- 异常处理:声明抛出
Exception
,允许实现类处理各类异常(如 IO 异常、业务异常等)。 - 调用时机:每次接收到客户端请求时,容器会调用该方法。
-
destroy()
方法- 功能:销毁 Servlet 实例。
- 调用时机:Servlet 容器关闭或重新加载 Servlet 时调用,通常用于资源释放(如关闭数据库连接、释放文件句柄等)。
- 注意事项:该方法在 Servlet 的生命周期中仅调用一次。
2、GenericServlet抽象类
- GenericServlet抽象类实现Servlet接口中的init()方法和destroy()方法。
为什么GenericServlet类是抽象类?
我们知道当一个普通类继承一个接口时,需要对接口中的所有方法进行实现,但这里我们不实现Servlet接口中的service(request,response)方法,因此我们需要把GenericServlet类变成抽象类,因为抽象类不必实现接口中的全部方法。
public abstract class GenericServlet implements Servlet {public void init(){System.out.println("初始化成功");}public void destroy(){System.out.println("销毁成功");}
}
3、HttpServlet抽象类
HttpServlet抽象类实现Servlet接口中的service(request,response)方法
为什么HttpServlet类也是抽象类?
之所以HttpServlet类也是抽象类,是因为普通类中必须对方法进行实现,而在HttpServlet类中,实现service(request,response)方法的逻辑为:如果接收到GET请求,那么执行doGet方法;如果接收到POST请求,那么执行doPost方法。在此我们只需要对doGet和doPost方法进行定义不需要实现,所以HttpServlet只有成为抽象类,才不必实现doGet和doPost方法。
import com.qcby.Servlet.req.HttpServletRequest;
import com.qcby.Servlet.req.HttpServletResponse;public abstract class HttpServlet extends GenericServlet {//实现Servlet生命周期的service方法public void service(HttpServletRequest request, HttpServletResponse response) throws Exception {//如果接收到GET请求,那么执行doGet方法if(request.getMethod().equals("GET")){doGet(request,response);}//如果接收到POST请求,那么执行doPost方法else if(request.getMethod().equals("POST")){doPost(request,response);}}protected abstract void doGet(HttpServletRequest request,HttpServletResponse response) throws Exception;protected abstract void doPost(HttpServletRequest request,HttpServletResponse response)throws Exception;
}
4、HttpRequest类
- HttpRequest类实现请求路径和请求方法的获取与输出。
public class HttpServletRequest {private String path;private String method;public String getPath(){return path;};public void setPath(String path){this.path = path;}public String getMethod(){return method;}public void setMethod(String method){this.method = method;}
}
5、HttpResponse类
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;public class HttpServletResponse {private OutputStream outputStream;public HttpServletResponse(OutputStream outputStream){this.outputStream = outputStream;}public void writeServlet(String context) throws IOException{outputStream.write(context.getBytes());}
}
I/0请求
客户端向浏览器发出的请求,浏览器不会主动向客户端发送请求
1、请求方式
HTTP协议的请求方式有很多,在这里我们只介绍GET请求和POST请求。
(1)GET请求
通过URL传递参数,URL与参数之间用?隔开,多个参数用&隔开,也是表单的默认提交方式。
GET传送的数据量较小,这主要是因为受到URL长度的限制。
GET会将数据显示到URL当中不安全。
基于以上三个特点,GET一般用于直接获取数据,提高查询速度。
请求头
- Accept-Encoding:gzip,deflate,br----浏览器所使用的语言
- Host:www.baidu.com----远程主机
- Cookie----cookie
- User-Agent----浏览器类型
即我们想要请求的信息。
Socket
Socket(套接字)是计算机网络编程中用于实现网络通信的关键编程接口(API),它是对底层网络协议(如 TCP/IP)的封装,为开发者提供了便捷的网络通信能力,屏蔽了协议底层的复杂实现细节。
一、Socket 的核心作用
- 标识进程通信:网络中主机靠 IP 地址唯一标识,而主机内的进程通信依赖 “协议 + 端口”。Socket 结合 IP 地址与端口号(如
IP 地址:端口号
),唯一标识网络中的进程,实现不同主机进程间的数据交互。 - 提供通信能力:如同 “发动机”,为程序提供发送和接收数据的网络通信基础能力,支持多种网络协议的应用开发。
二、Socket 的常见类型
- 流式套接字(
SOCK_STREAM
)- 基于 TCP 协议,提供面向连接、可靠的数据传输。
- 确保数据无差错、无重复发送,并按顺序接收,内置流量控制(如网页浏览、文件传输)。
- 数据包套接字(
SOCK_DGRAM
)- 基于 UDP 协议,提供无连接服务。
- 不保证数据传输的可靠性,可能丢失、重复或乱序(如视频会议、在线游戏)。
- 原始套接字(
SOCK_RAW
)- 允许直接访问较低层次协议(如 IP、ICMP),用于网络底层机制调试、新协议开发或网络监听。
三、Socket 的工作流程
- 服务端:
- 初始化 Socket 对象,指定协议族(如
AF_INET
表示 IPv4)和套接字类型(如SOCK_STREAM
)。 - 绑定(
bind
)服务端的 IP 地址和端口号。 - 对端口进行监听(
listen
),等待客户端连接。 - 接受连接(
accept
),与客户端建立通信链路后,通过读写操作(如read
/write
、recv
/send
)传输数据。 - 通信结束后关闭连接。
- 初始化 Socket 对象,指定协议族(如
- 客户端:
- 初始化 Socket 对象。
- 连接(
connect
)到服务端的 IP 地址和端口。 - 连接成功后,发送请求数据并接收响应。
- 通信结束后关闭连接。
四、Socket 与协议的关系
- Socket 是工具层:它是网络通信的编程接口,而非具体协议,支持基于 TCP、UDP 等协议的通信。
- TCP 和 UDP 是实现方式:
- TCP 是面向连接的可靠协议,适合对数据准确性要求高的场景。
- UDP 是无连接的轻量级协议,适合对实时性要求高、容忍少量丢包的场景。
五、通俗比喻辅助理解
将 Socket 比作 “邮局”:
- 每个程序(进程)如同 “城市”,需通过 “邮局(Socket)” 收发信息(数据)。
- 邮局(Socket)负责处理邮件(数据)发送的复杂细节(如分类、路由),程序员无需关心底层网络协议(如 TCP/IP)的复杂实现,只需通过简单接口(如发信、收信操作)即可完成通信。
- 不同的邮寄方式(如普通信件、快递)类似 Socket 支持的不同协议(TCP 可靠、UDP 快速但不保证送达)。
package Servlet.test;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) {// 使用try-with-resources自动关闭ServerSockettry (ServerSocket serverSocket = new ServerSocket(8080)) {System.out.println("服务器启动,监听端口: 8080");// 循环监听多个客户端连接while (true) {try (Socket socket = serverSocket.accept();InputStream inputStream = socket.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"))) {System.out.println("客户端连接成功: " + socket.getInetAddress());// 读取HTTP请求String line;while ((line = reader.readLine()) != null) {if (line.isEmpty()) { // 空行表示HTTP请求头结束break;}System.out.println("请求行: " + line);}// 返回简单的HTTP响应String response = "HTTP/1.1 200 OK\r\n" +"Content-Type: text/html\r\n" +"\r\n" +"<html><body><h1>Hello, World!</h1></body></html>";socket.getOutputStream().write(response.getBytes("UTF-8"));} catch (IOException e) {System.err.println("处理客户端连接时发生异常: " + e.getMessage());e.printStackTrace();}}} catch (IOException e) {System.err.println("服务器启动失败: " + e.getMessage());e.printStackTrace();}}
}
- 创建 ServerSocket 并绑定 8080 端口
- 监听客户端连接(accept 方法会阻塞)
- 获取客户端输入流并读取数据
- 将接收到的字节数据按 UTF-8 编码转换为字符串输出