杰瑞科技汇

JSP和Servlet如何协同工作?

JSP + Servlet 完整教程:从零到项目实战

前言:为什么学习 JSP 和 Servlet?

虽然现在市面上有更现代的框架(如 Spring Boot、Spring MVC、Play Framework 等),但 JSP 和 Servlet 是 Java Web 开发的基石,理解它们的工作原理,对于学习任何现代 Java Web 框架都至关重要,它们就像是汽车的发动机和底盘,无论外壳多么花哨,核心原理是相通的。

本教程将带你:

  1. 理解 Web 应用程序的基本工作原理。
  2. 掌握 Servlet 如何处理 HTTP 请求和响应。
  3. 掌握 JSP 如何优雅地展示数据。
  4. 理解 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 充当控制器的角色。

工作流程:

  1. 用户在浏览器中输入一个 URL,请求一个 JSP 页面(login.jsp)。
  2. 服务器收到请求,发现这是一个 JSP,会先将其翻译成一个 Java Servlet 源文件,再编译.class 文件。
  3. 浏览器显示 login.jsp 页面。
  4. 用户在表单中输入用户名和密码,点击“登录”按钮,表单的 action 指向一个 Servlet(LoginServlet)。
  5. 浏览器向 LoginServlet 发送一个 HTTP 请求。
  6. LoginServlet(控制器)接收请求,获取用户名和密码参数。
  7. LoginServlet 调用 Model 层的代码(UserService)来验证用户名和密码。
  8. UserService 返回验证结果(成功或失败)。
  9. LoginServlet 根据验证结果,决定将请求转发到哪个 JSP 页面(welcome.jsperror.jsp)。
  10. JSP 页面被渲染成 HTML,并返回给浏览器。

2. 环境搭建

你需要以下工具:

  1. JDK (Java Development Kit):Java 开发工具包,建议使用 JDK 8 或更高版本。
  2. IDE (Integrated Development Environment):推荐使用 IntelliJ IDEA (Ultimate 版或 Community 版均可) 或 Eclipse
  3. Web 服务器/容器:推荐使用 Apache Tomcat,它是 Servlet 和 JSP 规范的参考实现,免费且易于使用。

Tomcat 安装与配置:

  1. 下载 Tomcat:从 Apache Tomcat 官网 下载最新版本的 Tomcat (Tomcat 10)。
  2. 解压:将下载的 zip 文件解压到一个固定的目录,D:\apache-tomcat-10.1.x
  3. 配置环境变量(可选但推荐):
    • 新建系统变量 CATALINA_HOME,值为你的 Tomcat 安装目录。
    • Path 变量中,添加 %CATALINA_HOME%\bin
  4. 验证:在命令行中进入 bin 目录,运行 startup.bat (Windows) 或 ./startup.sh (Linux/Mac),如果看到 Tomcat 启动的日志,并且浏览器访问 http://localhost:8080 能看到 Tomcat 欢迎页,则安装成功。

IDE 配置(以 IntelliJ IDEA 为例):

  1. 创建新项目:选择 New Project -> Java Enterprise
  2. 配置:
    • Application server: 选择你之前安装的 Tomcat。
    • Template: 选择 Web Application
    • Add Framework support: 确保 Web Application (勾选 Create web.xml) 和 JSP 都被选中。
  3. 点击 Create,IDEA 会自动为你创建一个标准的 Web 项目结构。

第二部分:Servlet 开发详解

1. 创建第一个 Servlet

  1. src 目录下创建一个包,com.example.controller
  2. 在包中创建一个 Java 类,HelloServlet
  3. 让这个类继承 HttpServlet,并重写 doGetdoPost 方法。
// 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>");
    }
}
  1. 部署和运行
    • 确保 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 目录下,它包含三种类型的元素:

  1. 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" %>
  2. JSP 脚本元素:在 JSP 页面中嵌入 Java 代码。

    • 脚本片段
      <%
          // Java 代码块
          String user = "张三";
          int age = 25;
      %>
    • 表达式:输出一个表达式的值,会被自动转换成字符串。
      <p>欢迎您,<%= user %>!</p>
      <p>您的年龄是:<%= age %>岁。</p>
    • 声明:定义变量或方法,会被翻译成 Servlet 类的成员。
      <%!
          private int count = 0;
          public void increment() {
              count++;
          }
      %>
  3. JSP 动作标签:在请求处理阶段执行的动作。

    • jsp:include:动态包含,包含的是另一个资源的输出结果
      <jsp:include page="footer.jsp" />
    • jsp:forward:将请求转发到另一个资源。
      <jsp:forward page="anotherPage.jsp" />
    • jsp:param:与 includeforward 一起使用,传递参数。
      <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.javaUserServiceImpl.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. 运行项目

  1. 确保你的 Tomcat 服务器在 IDEA 中已启动。
  2. 打开浏览器,访问 http://localhost:8080/你的项目名/index.html
  3. 输入用户名 admin,密码 123456,点击登录。
  4. 你应该会被成功转发到欢迎页面。
  5. 输入错误的用户名或密码,你应该会被转发到错误页面。

第五部分:进阶与最佳实践

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 的核心知识,这是一个非常好的起点,你可以:

  1. 学习 JDBC:将 UserService 中的硬编码逻辑替换为从数据库(如 MySQL)读取用户信息。
  2. 深入理解 MVC:尝试将项目结构分层得更清晰,dao (数据访问层)、service (业务逻辑层)、controller (控制层)、vo/dto (值对象)。
  3. 学习 Maven/Gradle:使用构建工具来管理项目依赖(如数据库驱动、JSTL库等),而不是手动导入 JAR 包。
  4. 学习 Filter 和 Listener:它们是 Servlet 规范中的重要组件,用于处理通用的预处理和后处理逻辑(如字符编码过滤、监听会话创建/销毁等)。
  5. 学习前端技术:学习 HTML5, CSS3, JavaScript 和主流前端框架(如 Vue.js, React),它们是现代 Web 开发不可或缺的部分。
  6. 拥抱现代框架:当你对底层原理有了深刻理解后,学习 Spring MVCSpring Boot 会变得非常容易,你会发现它们只是对 Servlet 和 JSP 进行了更高层次的封装和优化,让你能更专注于业务逻辑开发。

希望这份详尽的教程能帮助你顺利开启 Java Web 开发之旅!祝你学习愉快!

分享:
扫描分享到社交APP
上一篇
下一篇