杰瑞科技汇

servlet jsp教程

Servlet & JSP 教程:从入门到实践

第一部分:基础概念与入门

什么是 Servlet 和 JSP?

在开始编码之前,我们首先要理解这两个技术是什么,以及它们为什么存在。

  • Servlet (Server Applet)

    • 本质:一个运行在 Web 服务器端的 Java 小程序。
    • 作用:接收来自客户端(通常是浏览器)的请求,处理业务逻辑(如查询数据库、计算数据),然后生成响应(通常是 HTML 页面)并返回给客户端。
    • 核心思想:用 Java 代码来动态生成网页内容,你可以把它想象成一个“网页生成器”。
    • 缺点:如果直接在 Servlet 中用 out.println() 输出大量的 HTML 代码,会使 Java 代码和 HTML 代码高度耦合,导致代码难以阅读和维护。
  • JSP (JavaServer Pages)

    • 本质:一个特殊的 Servlet,当你第一次访问一个 JSP 文件时,Web 服务器(如 Tomcat)会自动将其编译成一个 Servlet 类。
    • 作用:提供一个更方便的方式来在 HTML 页面中嵌入 Java 代码,实现页面的动态化。
    • 核心思想:以 HTML 为基础,在需要动态内容的地方插入 Java 代码(JSP 标签/脚本),它解决了 Servlet 中 HTML 和 Java 代码混合的问题,让“美工”和“程序员”可以更好地分工。
    • 优点:视图层和逻辑层初步分离,代码更清晰。

Servlet 更适合处理复杂的业务逻辑,而 JSP 更适合展示数据,在实际开发中,它们总是协同工作的,形成经典的 MVC(Model-View-Controller) 模式雏形:

  • Model (模型):JavaBean 或 POJO,封装数据。
  • View (视图):JSP 页面,负责显示数据。
  • Controller (控制器):Servlet,接收请求,调用 Model 处理业务,然后将数据传递给 View 进行展示。

开发环境搭建

你需要以下三样东西:

  1. JDK (Java Development Kit):Java 开发工具包,提供 Java 运行环境和编译/调试工具。

  2. Web 服务器:用于运行和部署你的 Web 应用,最常用的是 Apache Tomcat

    • 下载地址:Tomcat 官网
    • 下载与你的 JDK 版本匹配的 Tomcat(JDK 11/17 下载 Tomcat 9+)。
    • 解压即可使用,无需安装,配置好 CATALINA_HOME 环境变量。
  3. IDE (集成开发环境):用于编写和管理代码,推荐使用 IntelliJ IDEA (Ultimate Edition) 或 Eclipse IDE for Enterprise Java and Web Developers

    • IntelliJ IDEA 对 Maven/Gradle 和 Web 开发支持极佳,是首选。
    • Eclipse 是老牌的免费 IDE,社区庞大。

第一个 Servlet 程序

让我们创建一个最简单的 Servlet,它在浏览器上输出 "Hello, World!"。

步骤 1:创建 Web 项目

在 IDEA 中:

  1. File -> New -> Project
  2. 选择 Java Enterprise
  3. 勾选 Web applicationCreate from archetype (可选,但推荐使用 Maven/Gradle 管理项目)。
  4. 选择你的 Application Server (Tomcat)。
  5. 点击 Finish

IDEA 会为你创建一个标准的 Maven Web 项目结构,如下所示:

hello-servlet/
├── src/
│   ├── main/
│   │   ├── java/         // 存放 Java 源代码,如 Servlet
│   │   ├── resources/    // 存放配置文件
│   │   └── webapp/       // 存放 Web 资源,如 JSP, HTML, CSS, JS
│   │       ├── WEB-INF/  // 重要!存放 web.xml 和私有资源
│   │       │   └── web.xml // 部署描述符,用于配置 Servlet
│   │       └── index.jsp
│   └── test/
└── pom.xml               // Maven 项目配置文件

步骤 2:编写 Servlet 代码

src/main/java 目录下创建你的包,com.example.servlet,然后在该包下创建一个 HelloServlet.java 文件。

package com.example.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
// 1. 继承 HttpServlet
public class HelloServlet extends HttpServlet {
    // 2. 重写 doGet 或 doPost 方法
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 3. 设置响应内容类型和字符编码
        response.setContentType("text/html;charset=UTF-8");
        // 4. 获取输出流,向浏览器写入内容
        response.getWriter().println("<h1>Hello, Servlet World!</h1>");
        response.getWriter().println("当前时间是: " + new java.util.Date());
    }
    // 如果需要处理 POST 请求,就重写 doPost 方法
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response); // 通常让 doPost 调用 doGet
    }
}

代码解释

  1. HttpServlet:是专门用于处理 HTTP 请求的 Servlet 基类,我们继承它来获得处理 HTTP 请求的能力。
  2. doGet():当客户端通过 GET 方式(如在浏览器地址栏输入 URL 并回车)请求此 Servlet 时,此方法会被调用。
  3. response.setContentType("text/html;charset=UTF-8"):告诉浏览器,我返回的内容是 HTML 格式,并且使用 UTF-8 编码,防止中文乱码。
  4. response.getWriter():获取一个字符输出流,通过它向响应体中写入内容。

步骤 3:在 web.xml 中配置 Servlet

为了让 Web 服务器知道你的 HelloServlet 存在以及如何访问它,你需要在 src/main/webapp/WEB-INF/web.xml 文件中进行配置。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- Servlet 配置 -->
    <servlet>
        <!-- Servlet 的内部名称,可以自定义 -->
        <servlet-name>helloServlet</servlet-name>
        <!-- Servlet 的全限定类名 -->
        <servlet-class>com.example.servlet.HelloServlet</servlet-class>
    </servlet>
    <!-- Servlet 映射配置 -->
    <servlet-mapping>
        <!-- 映射到哪个 Servlet,这里的名称要和上面的 <servlet-name> 一致 -->
        <servlet-name>helloServlet</servlet-name>
        <!-- 访问这个 Servlet 的 URL 模式 -->
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

配置解释

  • <servlet>:定义一个 Servlet。
    • <servlet-name>:给 Servlet 起个名字。
    • <servlet-class>:指定 Servlet 类的完整路径。
  • <servlet-mapping>:将一个 URL 路径映射到某个 Servlet。
    • <servlet-name>:指定要映射的 Servlet 的名字。
    • <url-pattern>:指定访问该 Servlet 的 URL。/hello 表示项目的根路径后跟 /hello

步骤 4:部署并运行

  1. 确保 IDEA 已经配置好了 Tomcat 服务器。
  2. 点击工具栏上的 Run 按钮(绿色三角形)。
  3. IDEA 会自动将项目打包成 .war 文件并部署到 Tomcat,然后启动 Tomcat。
  4. 打开浏览器,访问 http://localhost:8080/你的项目名/hello

注意:如果你的项目名是 hello-servlet,URL http://localhost:8080/hello-servlet/hello

如果一切顺利,你将看到浏览器中显示了 "Hello, Servlet World!" 和当前时间。


第一个 JSP 程序

JSP 的使用比 Servlet 更直观。

步骤 1:创建 JSP 文件

src/main/webapp 目录下创建一个 hello.jsp 文件。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>My First JSP</title>
</head>
<body>
    <h1>Hello, JSP World!</h1>
    <p>当前时间是: <%= new java.util.Date() %></p>
</body>
</html>

代码解释

  • <%@ page ... %>:这是 JSP 指令,用于设置整个页面的属性。contentType 设置内容类型和编码,language 指定脚本语言。
  • <h1>:这是普通的 HTML 标签。
  • <%= ... %>:这是 JSP 表达式,它会把里面的 Java 代码计算结果,输出到页面上。new java.util.Date() 会生成一个日期对象,然后被转换成字符串显示。

步骤 2:访问 JSP

直接在浏览器中访问 http://localhost:8080/你的项目名/hello.jsp

你会看到页面显示了 JSP 中的内容,当你第一次访问时,Tomcat 会在其工作目录下自动将 hello.jsp 编译成一个 hello_jsp.java 文件(这是一个 Servlet),然后再编译成 .class 文件并执行,后续访问将直接使用编译后的 class 文件,速度更快。


第二部分:核心技术与实践

Servlet 生命周期

理解 Servlet 的生命周期对于掌握其工作原理至关重要,一个 Servlet 的生命周期由三个阶段组成:

  1. 初始化

    • 当 Servlet 第一次被请求时(或服务器启动时配置为 load-on-startup),服务器会创建一个 Servlet 实例。
    • 紧接着,服务器会调用 init(ServletConfig config) 方法。
    • init 方法只被调用一次,用于执行一次性的初始化操作,如加载配置文件、建立数据库连接等。
  2. 处理请求

    • 每次客户端请求该 Servlet 时,服务器都会调用 service() 方法。
    • HttpServletservice() 方法会根据请求的 HTTP 方法(GET, POST, PUT...)来调用相应的 doGet(), doPost(), doPut() 等方法。
    • 这个方法可以被调用多次,每次请求都会调用一次。
  3. 销毁

    • 当 Web 应用被卸载或服务器关闭时,服务器会调用 destroy() 方法。
    • destroy 方法也只被调用一次,用于释放资源,如关闭数据库连接。

示例:

public class LifecycleServlet extends HttpServlet {
    // 1. 初始化阶段
    @Override
    public void init() throws ServletException {
        System.out.println("Servlet 正在被初始化...");
        // 在这里执行初始化代码
    }
    // 2. 处理请求阶段
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet 正在处理 GET 请求...");
        resp.getWriter().println("Lifecycle Servlet is running.");
    }
    // 3. 销毁阶段
    @Override
    public void destroy() {
        System.out.println("Servlet 正在被销毁...");
        // 在这里执行清理代码
    }
}

Request 和 Response 对象

这是 Servlet 开发的核心。

  • HttpServletRequest (请求对象):代表客户端的请求。

    • 获取请求信息
      • request.getMethod(): 获取 HTTP 方法 (GET, POST)
      • request.getRequestURI(): 获取请求的 URI
      • request.getParameter("username"): 获取表单提交的参数值
      • request.getRequestDispatcher("target.jsp").forward(request, response): 请求转发,将请求和响应对象传递给另一个资源。
    • 请求转发 vs 重定向
      • 转发 (forward):服务器行为,地址栏 URL 不会改变,在服务器内部将请求从一个 Servlet/JSP 传递给另一个,共享同一个 request 对象。
      • 重定向 (sendRedirect):客户端行为,服务器返回一个 302 状态码和新的 Location,浏览器收到后会自动向新的 URL 发送一次新的请求,地址栏 URL 会改变,不共享 request 对象。
  • HttpServletResponse (响应对象):代表服务器对客户端的响应。

    • 设置响应内容
      • response.setContentType("text/html;charset=UTF-8"): 设置响应内容类型和编码。
      • response.getWriter(): 获取字符输出流。
      • response.getOutputStream(): 获取字节输出流(用于下载文件等)。
      • response.sendRedirect("login.jsp"): 实现重定向。

JSP 核心元素

除了表达式 <%= ... %>,JSP 还有其他核心元素:

  1. JSP 脚本片段

    • 语法:<% ... %>
    • 作用:可以编写任意多的 Java 语句,多个片段代码会被合并到 _jspService 方法中。
    • 注意:不能在片段中定义方法,但可以调用方法。
    <%
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }
    %>
    <p>1 到 100 的和是: <%= sum %></p>
  2. JSP 声明

    • 语法:<%! ... %>
    • 作用:在生成的 Servlet 类中定义字段或方法,生命周期与 Servlet 实例相同。
    <%!
        private int hitCount = 0;
        public int getHitCount() {
            return hitCount;
        }
    %>
    <p>页面访问次数: <%= ++hitCount %></p>
  3. JSP 注释

    • 语法:<%-- ... --%>
    • 作用:注释内容不会被发送到客户端,也不会被编译到 Servlet 中,这是推荐的注释方式。
    • 对比:HTML 注释 <!-- ... --> 会被发送到客户端。
  4. JSP 指令

    • 语法:<%@ directive ... %>
    • 主要指令:
      • page: 设置整个页面的属性,如 contentType, import 等。
      • include: 静态包含,将另一个文件的内容原封不动地插入到当前文件中,在翻译阶段完成。
      • taglib: 引入标签库,如 JSTL。

EL 表达式 和 JSTL 标签库

直接在 JSP 中写 Java 代码(脚本片段和表达式)被称为脚本式编程,虽然方便,但破坏了视图层的纯粹性,不符合 MVC 思想,现代 JSP 开发推荐使用 EL (Expression Language)JSTL (JSP Standard Tag Library)

  • EL 表达式

    • 语法:
    • 作用:简化从作用域中获取数据的写法。
    • 示例
      • JSP 表达式:<%= request.getAttribute("user") %>
      • EL 表达式:${user}
    • EL 会自动从四个作用域(page, request, session, application)中按顺序查找名为 "user" 的属性,找到即返回。
  • JSTL 标签库

    • 作用:用标签代替 Java 代码,实现逻辑判断、循环、格式化等。
    • 使用前需要引入:
      <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    • 常用 JSTL 标签
      • <c:set>: 设置变量。
        <c:set var="username" value="张三" scope="request" />
      • <c:if>: 条件判断。
        <c:if test="${user.age >= 18}">
            <p>已成年</p>
        </c:if>
      • <c:forEach>: 循环。
        <ul>
            <c:forEach var="item" items="${list}">
                <li>${item.name}</li>
            </c:forEach>
        </ul>

第三部分:MVC 模式与项目实践

经典的 MVC 模式

我们将 Servlet 和 JSP 结合起来,实现一个简单的 MVC 应用,这个应用的功能是:用户在 JSP 页面输入姓名,提交给 Servlet 处理,Servlet 将处理结果(包含问候语)存入 request 作用域,然后转发给另一个 JSP 页面显示。

项目结构

webapp/
├── index.jsp          // 视图:输入页面
├── welcome.jsp        // 视图:显示结果页面
└── WEB-INF/
    └── web.xml
src/main/java/
└── com/example/controller/
    └── GreetingServlet.java  // 控制器
└── com/example/model/
    └── User.java             // 模型 (JavaBean)

步骤 1:创建 Model (JavaBean) User.java - 一个简单的 POJO,用于封装数据。

package com.example.model;
public class User {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

步骤 2:创建 View 1 (输入页面) index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>输入姓名</title>
</head>
<body>
    <form action="greeting" method="post">
        请输入您的姓名: <input type="text" name="username">
        <input type="submit" value="提交">
    </form>
</body>
</html>
  • action="greeting":表单提交的地址,对应 Servlet 的 URL 映射。

步骤 3:创建 Controller (Servlet) GreetingServlet.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;
// 使用注解配置 Servlet,替代 web.xml
@WebServlet("/greeting")
public class GreetingServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 获取请求参数
        String username = request.getParameter("username");
        // 2. 处理业务逻辑 (这里很简单,实际可能更复杂)
        User user = new User();
        user.setName(username);
        // 3. 将数据存入 request 作用域
        request.setAttribute("user", user);
        // 4. 请求转发到 welcome.jsp 页面
        request.getRequestDispatcher("/welcome.jsp").forward(request, response);
    }
}
  • @WebServlet("/greeting"):这是 Servlet 3.0+ 提供的注解,可以替代 web.xml 中的配置,更加简洁。
  • request.setAttribute(): 将数据存入 request 作用域,以便下一个页面(转发到的页面)可以获取。

步骤 4:创建 View 2 (显示结果页面) welcome.jsp - 使用 EL 和 JSTL 来显示数据。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>欢迎页面</title>
</head>
<body>
    <h1>欢迎您, ${user.name}!</h1>
    <p>欢迎来到 MVC 世界。</p>
    <a href="index.jsp">返回</a>
</body>
</html>
  • ${user.name}:EL 表达式,从 request 作用域中取出名为 "user" 的对象,然后调用其 getName() 方法获取值。

步骤 5:配置 web.xml 如果使用了注解,web.xml 中可以不需要 Servlet 映射,但通常我们会保留 web.xml 来配置欢迎页面等。

<web-app ...>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

运行项目,访问 http://localhost:8080/你的项目名/,你将看到一个完整的 MVC 流程。


第四部分:进阶与总结

会话管理

HTTP 是无状态的协议,服务器无法区分两次请求是否来自同一个用户,为了解决这个问题,我们需要会话管理

  • Cookie

    • 服务器在响应中通过 Set-Cookie 头将一小段数据发送到客户端,客户端浏览器会保存它。
    • 之后客户端每次请求同一网站时,都会在请求头中带上这个 Cookie。
    • 服务器通过读取 Cookie 来识别用户。
    • 特点:数据存储在客户端,可以禁用,有大小限制(4KB)。
  • Session

    • Session 是存储在服务器端的会话机制。
    • 当一个用户首次访问时,服务器会为他创建一个唯一的 Session ID,并将这个 ID 通过 Cookie 发送给客户端。
    • 服务器将用户的会话数据(如登录信息、购物车)与这个 Session ID 关联起来,存储在服务器内存或数据库中。
    • 客户端后续请求带上 Session ID,服务器就能找到对应的会话数据。
    • 特点:数据存储在服务器端,更安全,无大小限制(但会占用服务器内存)。

Session 使用示例:

// 在 Servlet 中
HttpSession session = request.getSession(); // 获取或创建 Session
// 存储数据
session.setAttribute("userLoginInfo", "some user data");
// 获取数据
String userInfo = (String) session.getAttribute("userLoginInfo");
// 销毁 Session (用户退出登录时)
session.invalidate();

过滤器

过滤器是一个可以拦截请求和响应的对象,它可以在请求到达 Servlet 之前,或在响应返回给客户端之前,对请求和响应进行预处理和后处理。

常见用途

  • 字符编码过滤器:统一处理所有请求的字符编码,避免每个 Servlet 都写一遍。
  • 权限验证过滤器:检查用户是否登录,未登录则重定向到登录页面。
  • 日志记录过滤器:记录所有请求的详细信息。

示例:一个通用的字符编码过滤器

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*") // 过滤所有请求
public class CharacterEncodingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 1. 对请求进行预处理
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        // 2. 将请求和响应传递给下一个过滤器或目标 Servlet
        chain.doFilter(request, response);
        // 3. 对响应进行后处理 (如果需要)
    }
    // ... init() 和 destroy() 方法
}

总结与学习路径

Servlet & JSP 的核心地位: 虽然现在 Spring Boot 等框架非常流行,但它们底层依然依赖于 Servlet,理解 Servlet 和 JSP 是理解 Java Web 开发原理的基石。

学习路径建议

  1. 基础掌握:熟练编写 Servlet 和 JSP,理解 request, response, session 对象。
  2. MVC 实践:用 Servlet + JSP + JavaBean 完成一个完整的项目(如用户登录、简单的留言板)。
  3. 框架引入:学习使用 JSTL 和 EL 优化 JSP 页面。
  4. 进阶技术:掌握过滤器、监听器,理解会话管理。
  5. 拥抱框架:当你对 Servlet/JSP 有了扎实的理解后,学习 Spring MVC 或 Spring Boot 会事半功倍,你会发现,Spring 框架的本质就是对 Servlet 和 JSP 的高级封装和增强。

推荐资源

这份教程涵盖了 Servlet 和 JSP 的核心知识点,从理论到实践,希望能帮助你顺利入门 Java Web 开发世界!祝你学习愉快!

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