JSP + Servlet 完整教程:从零到项目实战
前言:为什么学习 JSP 和 Servlet?
虽然现在市面上有更现代的框架(如 Spring Boot、Spring MVC、Play Framework 等),但 JSP 和 Servlet 是 Java Web 开发的基石,理解它们的工作原理,对于学习任何现代 Java Web 框架都至关重要,它们就像是汽车的发动机和底盘,无论外壳多么花哨,核心原理是相通的。
本教程将带你:
- 理解 Web 应用程序的基本工作原理。
- 掌握 Servlet 如何处理 HTTP 请求和响应。
- 掌握 JSP 如何优雅地展示数据。
- 理解 MVC 设计模式,并实现一个简单的登录案例。
第一部分:核心概念与环境搭建
1. 基本概念
- Servlet (Server Applet):运行在 Web 服务器端的 Java 小程序,它的主要任务是接收客户端的 HTTP 请求,处理业务逻辑,并生成 HTTP 响应,你可以把它想象成一个“后台处理员”。
- JSP (JavaServer Pages):一种用于创建动态 Web 页面的技术,它看起来像 HTML,但可以在其中嵌入 Java 代码,它的主要任务是展示数据(视图),你可以把它想象成一个“前台美工”。
- HTTP 协议:Web 应用通信的基础,浏览器(客户端)向服务器发送请求(
Request),服务器处理后返回响应(Response)。 - MVC 设计模式:
- M (Model - 模型):数据模型,负责业务逻辑和数据处理,通常由 JavaBean 或 Service/DAO 层构成。
- V (View - 视图):负责数据显示,在 JSP 中,JSP 页面本身。
- C (Controller - 控制器):接收用户请求,调用 Model 处理,然后选择合适的 View 进行展示,在 JSP/Servlet 中,Servlet 充当控制器的角色。
工作流程:
- 用户在浏览器中输入一个 URL,请求一个 JSP 页面(
login.jsp)。 - 服务器收到请求,发现这是一个 JSP,会先将其翻译成一个 Java Servlet 源文件,再编译成
.class文件。 - 浏览器显示
login.jsp页面。 - 用户在表单中输入用户名和密码,点击“登录”按钮,表单的
action指向一个 Servlet(LoginServlet)。 - 浏览器向
LoginServlet发送一个 HTTP 请求。 LoginServlet(控制器)接收请求,获取用户名和密码参数。LoginServlet调用 Model 层的代码(UserService)来验证用户名和密码。UserService返回验证结果(成功或失败)。LoginServlet根据验证结果,决定将请求转发到哪个 JSP 页面(welcome.jsp或error.jsp)。- JSP 页面被渲染成 HTML,并返回给浏览器。
2. 环境搭建
你需要以下工具:
- JDK (Java Development Kit):Java 开发工具包,建议使用 JDK 8 或更高版本。
- IDE (Integrated Development Environment):推荐使用 IntelliJ IDEA (Ultimate 版或 Community 版均可) 或 Eclipse。
- Web 服务器/容器:推荐使用 Apache Tomcat,它是 Servlet 和 JSP 规范的参考实现,免费且易于使用。
Tomcat 安装与配置:
- 下载 Tomcat:从 Apache Tomcat 官网 下载最新版本的 Tomcat (Tomcat 10)。
- 解压:将下载的 zip 文件解压到一个固定的目录,
D:\apache-tomcat-10.1.x。 - 配置环境变量(可选但推荐):
- 新建系统变量
CATALINA_HOME,值为你的 Tomcat 安装目录。 - 在
Path变量中,添加%CATALINA_HOME%\bin。
- 新建系统变量
- 验证:在命令行中进入
bin目录,运行startup.bat(Windows) 或./startup.sh(Linux/Mac),如果看到 Tomcat 启动的日志,并且浏览器访问http://localhost:8080能看到 Tomcat 欢迎页,则安装成功。
IDE 配置(以 IntelliJ IDEA 为例):
- 创建新项目:选择
New Project->Java Enterprise。 - 配置:
- Application server: 选择你之前安装的 Tomcat。
- Template: 选择
Web Application。 - Add Framework support: 确保
Web Application(勾选Create web.xml) 和JSP都被选中。
- 点击
Create,IDEA 会自动为你创建一个标准的 Web 项目结构。
第二部分:Servlet 开发详解
1. 创建第一个 Servlet
- 在
src目录下创建一个包,com.example.controller。 - 在包中创建一个 Java 类,
HelloServlet。 - 让这个类继承
HttpServlet,并重写doGet或doPost方法。
// src/com/example/controller/HelloServlet.java
package com.example.controller;
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("/hello") // 这是 Servlet 3.0+ 的注解方式,比在 web.xml 中配置更简单
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 设置响应内容类型为 HTML
response.setContentType("text/html;charset=UTF-8");
// 2. 获取向客户端输出内容的 PrintWriter 对象
PrintWriter out = response.getWriter();
// 3. 输出 HTML 内容
out.println("<html>");
out.println("<head><title>My First Servlet</title></head>");
out.println("<body>");
out.println("<h1>Hello, Servlet World!</h1>");
out.println("</body>");
out.println("</html>");
}
}
- 部署和运行:
- 确保 Tomcat 服务器在 IDEA 中配置并运行。
- 右键点击
HelloServlet->Run 'HelloServlet'。 - IDEA 会自动将项目部署到 Tomcat 并启动。
- 在浏览器中访问
http://localhost:8080/你的项目名/hello,你应该能看到 "Hello, Servlet World!"。
2. Servlet 核心对象详解
-
HttpServletRequest(请求对象):- 代表客户端的请求,你可以从中获取所有请求信息。
- 常用方法:
String getParameter(String name): 获取表单提交的参数值。String[] getParameterValues(String name): 获取同名复选框的多个值。getRequestDispatcher(String path): 获取请求转发器,用于将请求转发到其他资源(Servlet 或 JSP)。setAttribute(String name, Object obj): 在请求范围内设置一个属性,常用于在转发时传递数据。getAttribute(String name): 获取请求范围内的属性。
-
HttpServletResponse(响应对象):- 代表服务器对客户端的响应。
- 常用方法:
PrintWriter getWriter(): 获取字符输出流,用于输出文本内容(如 HTML)。ServletOutputStream getOutputStream(): 获取字节输出流,用于输出二进制内容(如图片、文件)。void setContentType(String type): 设置响应内容的 MIME 类型。void sendRedirect(String location): 实现重定向(客户端会收到一个 302 状态码和新的 URL,然后浏览器重新请求新地址)。
第三部分:JSP 开发详解
1. JSP 语法
JSP 页面通常放在 webapp 目录下,它包含三种类型的元素:
-
JSP 指令:告诉 JSP 引擎如何处理整个页面。
page指令:定义页面的全局属性。<%@ page contentType="text/html;charset=UTF-8" language="java" %>
include指令:在翻译阶段,将另一个文件的内容静态包含进来。<%@ include file="header.html" %>
taglib指令:引入标签库(如 JSTL)。<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
-
JSP 脚本元素:在 JSP 页面中嵌入 Java 代码。
- 脚本片段:
<% // Java 代码块 String user = "张三"; int age = 25; %> - 表达式:输出一个表达式的值,会被自动转换成字符串。
<p>欢迎您,<%= user %>!</p> <p>您的年龄是:<%= age %>岁。</p>
- 声明:定义变量或方法,会被翻译成 Servlet 类的成员。
<%! private int count = 0; public void increment() { count++; } %>
- 脚本片段:
-
JSP 动作标签:在请求处理阶段执行的动作。
jsp:include:动态包含,包含的是另一个资源的输出结果。<jsp:include page="footer.jsp" />
jsp:forward:将请求转发到另一个资源。<jsp:forward page="anotherPage.jsp" />
jsp:param:与include或forward一起使用,传递参数。<jsp:forward page="greeting.jsp"> <jsp:param name="username" value="李四" /> </jsp:forward>
2. JSP 内置对象
JSP 引擎会自动为每个页面创建 9 个内置对象,你无需声明即可直接使用。
| 内置对象 | 类型 | 描述 |
|---|---|---|
request |
HttpServletRequest |
请求对象 |
response |
HttpServletResponse |
响应对象 |
session |
HttpSession |
会话对象 |
application |
ServletContext |
Servlet 上下文对象 |
config |
ServletConfig |
Servlet 配置对象 |
out |
JspWriter |
输出对象 |
pageContext |
PageContext |
页面上下文对象,其他对象的“大管家” |
page |
Object |
指向当前 Servlet 实例 |
exception |
Throwable |
异常对象 |
第四部分:实战项目 - 用户登录系统
我们将使用 Servlet 作为控制器,JSP 作为视图,实现一个简单的登录功能。
1. 项目结构
java/
└── com/
└── example/
├── controller/
│ └── LoginServlet.java
├── model/
│ └── User.java
└── service/
└── UserService.java
└── UserServiceImpl.java
webapp/
├── index.html (登录页面)
├── WEB-INF/
│ ├── web.xml
│ └── jsp/
│ ├── welcome.jsp (登录成功页面)
│ └── error.jsp (登录失败页面)
2. 步骤详解
步骤 1:创建 Model (数据模型) - User.java
// src/com/example/model/User.java
package com.example.model;
public class User {
private String username;
private String password;
// 构造器、Getter 和 Setter
public User() {}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
步骤 2:创建 Service (业务逻辑) - UserService.java 和 UserServiceImpl.java
// src/com/example/service/UserService.java
package com.example.service;
public interface UserService {
boolean login(String username, String password);
}
// src/com/example/service/UserServiceImpl.java
package com.example.service;
public class UserServiceImpl implements UserService {
@Override
public boolean login(String username, String password) {
// 这里是硬编码的验证逻辑,实际项目中应该连接数据库
if ("admin".equals(username) && "123456".equals(password)) {
return true;
}
return false;
}
}
步骤 3:创建 View (视图)
index.html(登录表单)
<!-- webapp/index.html -->
<!DOCTYPE html>
<html>
<head>登录</title>
</head>
<body>
<h1>用户登录</h1>
<form action="login" method="post">
用户名: <input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
welcome.jsp(登录成功页)
<!-- webapp/WEB-INF/jsp/welcome.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>欢迎页</title>
</head>
<body>
<h1>欢迎您,<%= request.getAttribute("username") %>!</h1>
<p>登录成功。</p>
<a href="index.html">返回登录页</a>
</body>
</html>
error.jsp(登录失败页)
<!-- webapp/WEB-INF/jsp/error.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>错误页</title>
</head>
<body>
<h1>登录失败!</h1>
<p>用户名或密码错误。</p>
<a href="index.html">返回登录页</a>
</body>
</html>
注意:JSP 文件会放在
WEB-INF目录下,以防止用户通过 URL 直接访问它们,只能通过 Servlet 转发访问。
步骤 4:创建 Controller (控制器) - LoginServlet.java
// src/com/example/controller/LoginServlet.java
package com.example.controller;
import com.example.model.User;
import com.example.service.UserService;
import com.example.service.UserServiceImpl;
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;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
// 2. 调用 Service 层处理业务逻辑
boolean isSuccess = userService.login(username, password);
// 3. 根据处理结果,进行转发
if (isSuccess) {
// 登录成功,将用户名存入 request 域
request.setAttribute("username", username);
// 转发到 welcome.jsp
request.getRequestDispatcher("/WEB-INF/jsp/welcome.jsp").forward(request, response);
} else {
// 登录失败,转发到 error.jsp
request.getRequestDispatcher("/WEB-INF/jsp/error.jsp").forward(request, response);
}
}
}
3. 运行项目
- 确保你的 Tomcat 服务器在 IDEA 中已启动。
- 打开浏览器,访问
http://localhost:8080/你的项目名/index.html。 - 输入用户名
admin,密码123456,点击登录。 - 你应该会被成功转发到欢迎页面。
- 输入错误的用户名或密码,你应该会被转发到错误页面。
第五部分:进阶与最佳实践
1. 使用 JSTL 和 EL 表达式
直接在 JSP 中写 Java 脚本片段(<% ... %>)被称为 "Scriptlet",在现代开发中已经不推荐使用,因为它会导致页面混乱,难以维护。
替代方案:
- EL (Expression Language - 表达式语言):简化获取数据的语法。
- 语法:
${expression} ${username}会自动调用pageContext.findAttribute("username")并输出。
- 语法:
- JSTL (JSP Standard Tag Library - JSP 标准标签库):提供一系列标签来完成逻辑判断、循环、格式化等操作。
改造 welcome.jsp 使用 EL 和 JSTL:
<!-- webapp/WEB-INF/jsp/welcome.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>欢迎页</title>
</head>
<body>
<h1>欢迎您,<c:out value="${username}" />!</h1>
<p>登录成功。</p>
<a href="${pageContext.request.contextPath}/index.html">返回登录页</a>
</body>
</html>
pageContext.request.contextPath用于获取项目的上下文路径,这是最佳实践,可以避免因项目名改变而导致链接失效。
2. 会话管理
HttpSession 对象用于在多个请求之间保存用户的状态,用户登录后,我们希望在后续的每个页面都能知道他已登录。
在 LoginServlet 中创建会话:
// 在 LoginServlet 的 doPost 方法中,登录成功后
HttpSession session = request.getSession(); // 获取或创建会话
session.setAttribute("user", new User(username, password)); // 将用户对象存入会话
在 welcome.jsp 中检查会话:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:if test="${empty sessionScope.user}">
<jsp:forward page="/index.html" />
</c:if>
<html>
<head>欢迎页</title>
</head>
<body>
<h1>欢迎您,${sessionScope.user.username}!</h1>
<p>登录成功。</p>
<a href="logout">退出登录</a>
</body>
</html>
创建一个 LogoutServlet 用于退出登录:
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession(false); // false表示如果不存在会话则不创建
if (session != null) {
session.invalidate(); // 销毁会话
}
response.sendRedirect(request.getContextPath() + "/index.html"); // 重定向到登录页
}
}
3. 总结与后续学习
你已经掌握了 JSP + Servlet 的核心知识,这是一个非常好的起点,你可以:
- 学习 JDBC:将
UserService中的硬编码逻辑替换为从数据库(如 MySQL)读取用户信息。 - 深入理解 MVC:尝试将项目结构分层得更清晰,
dao(数据访问层)、service(业务逻辑层)、controller(控制层)、vo/dto(值对象)。 - 学习 Maven/Gradle:使用构建工具来管理项目依赖(如数据库驱动、JSTL库等),而不是手动导入 JAR 包。
- 学习 Filter 和 Listener:它们是 Servlet 规范中的重要组件,用于处理通用的预处理和后处理逻辑(如字符编码过滤、监听会话创建/销毁等)。
- 学习前端技术:学习 HTML5, CSS3, JavaScript 和主流前端框架(如 Vue.js, React),它们是现代 Web 开发不可或缺的部分。
- 拥抱现代框架:当你对底层原理有了深刻理解后,学习 Spring MVC 或 Spring Boot 会变得非常容易,你会发现它们只是对 Servlet 和 JSP 进行了更高层次的封装和优化,让你能更专注于业务逻辑开发。
希望这份详尽的教程能帮助你顺利开启 Java Web 开发之旅!祝你学习愉快!
