一、引言
在 Java Web 开发领域,JSP(JavaServer Pages)和 Servlet 是两个至关重要的技术,它们共同构成了动态网页开发的基础。Servlet 作为服务器端的 Java 程序,负责处理客户端请求并生成响应;而 JSP 则是一种简化的 Servlet 开发方式,允许开发者在 HTML 页面中嵌入 Java 代码,使页面的开发更加直观和便捷。本文将深入探讨 Servlet 的生命周期、请求响应处理机制,以及 JSP 与 Servlet 的交互原理,并通过一个真实的项目实战来加深理解。
二、Servlet 详解
2.1 Servlet 生命周期
Servlet 的生命周期包括加载、实例化、初始化、服务和销毁五个阶段,每个阶段都对应着特定的方法调用。以下是详细的生命周期流程图:
2.1.1 加载
当客户端首次请求访问一个 Servlet 时,Web 容器(如 Tomcat)会查找该 Servlet 的类文件,并将其加载到内存中。
2.1.2 实例化
Web 容器使用 new
关键字创建 Servlet 类的实例。一个 Servlet 类在整个 Web 应用程序的生命周期中通常只会被实例化一次。
2.1.3 初始化
在实例化之后,Web 容器会调用 Servlet 的 init()
方法进行初始化操作。init()
方法只会被调用一次,通常用于加载配置文件、建立数据库连接等初始化工作。以下是一个简单的 Servlet 初始化示例:
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
public class MyServlet implements Servlet {
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("Servlet 初始化");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
// 服务方法
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
// 销毁方法
}
}
2.1.4 服务
当客户端发送请求时,Web 容器会调用 Servlet 的 service()
方法来处理请求并生成响应。service()
方法会根据请求的类型(如 GET、POST)调用相应的 doGet()
或 doPost()
方法。以下是一个处理 GET 请求的示例:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/myServlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/html;charset=UTF-8");
PrintWriter out = res.getWriter();
out.println("<html>");
out.println("<head><title>Hello Servlet</title></head>");
out.println("<body>");
out.println("<h1>Hello, Servlet!</h1>");
out.println("</body>");
out.println("</html>");
}
}
2.1.5 销毁
当 Web 应用程序关闭或 Servlet 被卸载时,Web 容器会调用 Servlet 的 destroy()
方法进行资源释放操作,如关闭数据库连接、释放文件句柄等。
2.2 请求响应处理
在 Servlet 中,通过 HttpServletRequest
和 HttpServletResponse
对象来处理客户端请求和返回响应。
2.2.1 请求参数解析
HttpServletRequest
对象提供了一系列方法来获取请求参数,如 getParameter()
、getParameterValues()
等。以下是一个解析请求参数的示例:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/paramServlet")
public class ParamServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
String name = req.getParameter("name");
String age = req.getParameter("age");
res.setContentType("text/html;charset=UTF-8");
PrintWriter out = res.getWriter();
out.println("<html>");
out.println("<head><title>Request Parameters</title></head>");
out.println("<body>");
out.println("<h1>Name: " + name + "</h1>");
out.println("<h1>Age: " + age + "</h1>");
out.println("</body>");
out.println("</html>");
}
}
2.2.2 响应内容设置
HttpServletResponse
对象用于设置响应的内容类型、状态码和输出响应内容。以下是一个设置响应内容的示例:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/responseServlet")
public class ResponseServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("text/plain;charset=UTF-8");
res.setStatus(HttpServletResponse.SC_OK);
PrintWriter out = res.getWriter();
out.println("这是一个响应示例");
}
}
三、Servlet 与 JSP 的交互
3.1 JSP 本质
JSP 本质上是 Servlet 的一种特殊形式。当 JSP 页面第一次被请求时,Web 容器会将 JSP 页面翻译成一个 Servlet 类,并编译成字节码文件。这个过程由 JSP 引擎自动完成,开发者无需手动干预。以下是 JSP 翻译为 Servlet 的流程图:
3.2 协同工作原理
Servlet 和 JSP 可以协同工作实现动态网页开发。通常,Servlet 负责处理业务逻辑和数据处理,而 JSP 负责页面的展示。以下是一个简单的项目架构图,展示了 Servlet 和 JSP 的协同工作方式:
四、真实项目实战
4.1 项目需求
开发一个简单的用户信息管理系统,包括用户信息的添加、查询和显示功能。
4.2 项目结构图
user-management-system
├── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ ├── controller
│ │ │ ├── AddUserServlet.java
│ │ │ └── ListUsersServlet.java
│ │ └── model
│ │ └── User.java
│ └── webapp
│ ├── WEB-INF
│ │ └── web.xml
│ ├── addUser.jsp
│ └── listUsers.jsp
4.3 源码实现
4.3.1 User.java
package com.example.model;
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
4.3.2 AddUserServlet.java
package com.example.controller;
import com.example.model.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/addUser")
public class AddUserServlet extends HttpServlet {
private static List<User> users = new ArrayList<>();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
String name = req.getParameter("name");
int age = Integer.parseInt(req.getParameter("age"));
User user = new User(name, age);
users.add(user);
res.sendRedirect("listUsers");
}
}
4.3.3 ListUsersServlet.java
package com.example.controller;
import com.example.model.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/listUsers")
public class ListUsersServlet extends HttpServlet {
private static List<User> users = new ArrayList<>();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
req.setAttribute("users", users);
req.getRequestDispatcher("listUsers.jsp").forward(req, res);
}
}
4.3.4 addUser.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>添加用户</title>
</head>
<body>
<form action="addUser" method="post">
<label for="name">姓名:</label>
<input type="text" id="name" name="name" required><br>
<label for="age">年龄:</label>
<input type="number" id="age" name="age" required><br>
<input type="submit" value="添加">
</form>
</body>
</html>
4.3.5 listUsers.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<title>用户列表</title>
</head>
<body>
<h1>用户列表</h1>
<table border="1">
<tr>
<th>姓名</th>
<th>年龄</th>
</tr>
<c:forEach items="${users}" var