JSP 入门到实战:2 小时写出动态页面,吃透 Servlet+JSP 协作逻辑

世界杯开始 2025-10-17 15:58:29

很多刚学完 Servlet 的小伙伴,都会被一个问题搞崩溃:用out.write("

欢迎" + username + "

")拼 HTML 页面时,引号嵌套、标签错位、中文乱码轮番出现 —— 这就是 JSP 诞生的原因:它允许在 HTML 中直接嵌入 Java 代码,让动态页面开发从 “拼字符串” 变成 “写网页”。

本文专为 JavaWeb 新手设计,不堆复杂理论,只讲 “能直接用的实操知识”,带你从 0 到 1 理解 JSP 原理,用 Servlet+JSP 写出用户列表、登录回显等实用功能。

一、先搞懂:JSP 是什么?为什么它比 Servlet 写页面更高效?

JSP(Java Server Pages)本质是Servlet 的 “语法糖”—— 当浏览器访问 JSP 时,Tomcat 会先把 JSP 翻译成 Java 源文件(本质是 Servlet),编译成 class 后执行,最终生成 HTML 返回给浏览器。但对开发者来说,JSP 的优势太明显了:

对比维度

Servlet 写页面

JSP 写页面

代码风格

Java 代码中嵌套 HTML 字符串,格式混乱

HTML 中嵌入 Java 代码,直观易维护

开发效率

改页面需重新编译 Java 类,效率低

直接改 JSP 文件,Tomcat 自动重新编译

学习成本

需手动处理 HTML 标签拼接,新手易出错

懂 HTML 就能上手,Java 逻辑嵌入更自然

一句话总结:Servlet 负责 “处理业务逻辑”(如查数据库、验证登录),JSP 负责 “动态展示数据”(如渲染用户列表),两者配合形成 JavaWeb 开发的 “MVC 雏形”。

二、入门实操:10 分钟跑通第一个 JSP(IDEA+Tomcat)

JSP 入门门槛极低,只要会 HTML 和基础 Java 语法,跟着步骤走就能快速上手。

1. 第一步:创建 JSP 文件(IDEA 环境)

在 JavaWeb 项目的web目录下(存放前端资源的核心目录),右键→「New」→「JSP/JSPX」,命名为first.jsp,IDEA 会自动生成基础模板:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

$Title$

$END$

2. 第二步:写第一个动态功能(显示当前时间)

在body标签中嵌入 Java 代码,实现 “实时显示服务器时间”—— 这是 JSP 最基础的动态能力

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%@ page import="java.util.Date,java.text.SimpleDateFormat" %> <%-- 导入Java类 --%>

我的第一个JSP

Hello JSP!

<%-- JSP注释:不会输出到HTML源码中(区别于) --%>

<%

// 1. Java脚本片段:执行逻辑(声明变量、处理数据)

Date now = new Date();

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

String currentTime = sdf.format(now);

%>

<%-- 2. JSP表达式:输出Java变量到HTML(无需写分号) --%>

当前服务器时间:<%= currentTime %>

3. 第三步:启动并访问 JSP

配置 Tomcat(和运行 Servlet 一致):右上角「Add Configuration」→选择「Tomcat Server」→关联项目 WAR 包;

启动 Tomcat:控制台显示 “Server startup in xxx ms” 即成功;

访问 URL:http://localhost:8080/项目名/first.jsp(例:http://localhost:8080/JavaWebDemo/first.jsp);

效果:页面显示 “Hello JSP!” 和实时更新的服务器时间 —— 第一个 JSP 跑通了!

三、核心语法:新手必掌握的 3 类 JSP 元素

JSP 的核心语法就 3 类,不用死记,会用常用场景即可:

1. 脚本元素:在 HTML 中写 Java 逻辑(高频)

脚本元素是 JSP 的 “灵魂”,用于嵌入 Java 代码,新手重点掌握前 2 个:

元素类型

语法格式

作用

示例

脚本片段

<% Java代码 %>

执行逻辑(变量声明、循环、判断)

<% int count = 0; for(int i=0;i<5;i++){count++;} %>

表达式

<%= 变量/表达式 %>

输出结果到 HTML(无分号)

<%= count %>(输出变量值)、<%= 1+1 %>(输出 2)

声明(少用)

<%! 方法/全局变量 %>

定义 JSP 全局方法 / 变量(线程不安全)

<%! public int add(int a,int b){return a+b;} %>

避坑:脚本片段 vs 声明

脚本片段(<% %>)中的变量是 “局部变量”:每个请求都会重新创建,线程安全;

声明(<%! %>)中的变量是 “全局变量”:所有请求共享一个变量(如<%! int num = 0; %>,多用户访问会导致 num 值混乱),新手尽量不用。

2. 指令元素:配置 JSP 页面全局属性

指令元素以<%@开头,用于配置页面全局信息,常用 2 个:

(1)page 指令:解决中文乱码、导入类(必用)

<%@ page

contentType="text/html;charset=UTF-8" // 响应类型+编码(解决页面中文乱码)

pageEncoding="UTF-8" // JSP文件本身编码(和上一致即可)

import="java.util.List,com.example.User"// 导入Java类(多个用逗号分隔)

session="true" // 是否支持Session(默认true,关闭设false)

%>

新手必配:contentType和pageEncoding必须设为UTF-8,否则会出现中文乱码。

(2)include 指令:复用页面片段(减少重复代码)

把 “页眉、页脚、导航栏” 抽成单独 JSP,在其他页面中复用,比如:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%-- 静态包含页眉(把header.jsp的内容直接嵌入当前页面) --%>

<%@ include file="common/header.jsp" %>

这是首页内容

<%-- 静态包含页脚 --%>

<%@ include file="common/footer.jsp" %>

注意:静态包含是 “编译时合并”,被包含的文件(如 header.jsp)不能有重复的page指令(比如重复设置contentType)。

3. 内置对象:不用 new 就能用的 “工具”(核心)

JSP 有 9 个内置对象,是 Tomcat 自动创建的 Java 对象,新手只需掌握 6 个常用的,就能解决 80% 需求:

对象名

类型

作用

常用操作

request

HttpServletRequest

存储 “一次请求内” 的数据,获取表单参数

存数据:request.setAttribute("key", 值)取数据:request.getAttribute("key")获参数:request.getParameter("username")

session

HttpSession

存储 “一个用户会话” 的数据(登录态)

存用户:session.setAttribute("loginUser", "admin")取用户:session.getAttribute("loginUser")销毁:session.invalidate()

out

JspWriter

向浏览器输出内容(类似 PrintWriter)

out.print("Hello")、out.println("
")

application

ServletContext

存储 “整个应用” 的全局数据(少用)

application.setAttribute("globalCount", 100)

response

HttpServletResponse

重定向、设置 Cookie

重定向:response.sendRedirect("login.jsp")

pageContext

PageContext

简化数据查找(从 page→request→session→application)

pageContext.findAttribute("key")

四、实战:Servlet+JSP 协作开发(用户列表案例)

单独用 JSP 只能做简单动态页面,结合 Servlet 才能实现 “业务逻辑 + 数据展示” 的完整功能,这里用 “用户列表” 演示完整流程:

步骤 1:Servlet 处理业务(查数据,存到 request)

package com.example.servlet;

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;

// 1. 配置Servlet映射路径

@WebServlet("/user/list")

public class UserListServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

// 2. 模拟查数据库:获取用户列表(实际项目调用DAO层)

List userList = new ArrayList<>();

userList.add(new User(1, "张三", 25, "北京"));

userList.add(new User(2, "李四", 28, "上海"));

userList.add(new User(3, "王五", 30, "广州"));

// 3. 把用户列表存到request(一次请求内共享,转发后能拿到)

request.setAttribute("userList", userList);

// 4. 请求转发到JSP(重点:用转发不用重定向,否则request数据会丢失)

request.getRequestDispatcher("/user/list.jsp").forward(request, response);

}

// 内部User类(简化JavaBean,必须有getter才能被JSP访问)

static class User {

private Integer id;

private String name;

private Integer age;

private String city;

public User(Integer id, String name, Integer age, String city) {

this.id = id;

this.name = name;

this.age = age;

this.city = city;

}

// 必须写getter方法(JSP中${user.name}本质是调用getName())

public Integer getId() { return id; }

public String getName() { return name; }

public Integer getAge() { return age; }

public String getCity() { return city; }

}

}

步骤 2:JSP 展示数据(从 request 取数据,渲染表格)

在web/user目录下新建list.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%@ page import="java.util.List,com.example.servlet.UserListServlet.User" %> <%-- 导入User类 --%>

用户列表

用户列表(共<%= ((List)request.getAttribute("userList")).size() %>人)

<%-- 从request中取用户列表,循环渲染 --%>

<% List userList = (List) request.getAttribute("userList"); %>

<% if (userList != null && !userList.isEmpty()) { %>

<% for (User user : userList) { %>

<% } %>

<% } else { %>

<% } %>

ID 姓名 年龄 城市
<%= user.getId() %> <%= user.getName() %> <%= user.getAge() %> <%= user.getCity() %>
暂无用户数据

步骤 3:运行效果

启动 Tomcat,访问http://localhost:8080/JavaWebDemo/user/list;

页面显示格式化的用户表格,包含 ID、姓名、年龄、城市 ——Servlet+JSP 协作成功!

五、新手避坑:5 个高频问题及解决方案

坑 1:JSP 页面中文乱码

现象:页面文字或表单参数显示 “???”。

✅ 解决方案:

页面乱码:page指令配置contentType="text/html;charset=UTF-8"和pageEncoding="UTF-8";

POST 参数乱码:在 Servlet 中加request.setCharacterEncoding("UTF-8");

GET 参数乱码:改 Tomcat 的conf/server.xml,在Connector标签加URIEncoding="UTF-8"。

坑 2:JSP 获取不到 Servlet 存的 request 数据

原因:Servlet 用了response.sendRedirect()(重定向),会丢失 request 数据(重定向是 2 次请求,request 只在 1 次请求内有效)。

✅ 解决方案:

需共享 request 数据时(如 Servlet 传数据给 JSP),用请求转发:request.getRequestDispatcher("/xxx.jsp").forward(req, resp);

无需共享数据时(如登录成功跳首页),用重定向。

坑 3:JSP 中调用 User 属性报错 “找不到方法”

原因:User 类没有写getter方法 ——JSP 中<%= user.getName() %>本质是调用getter,不是直接访问属性。

✅ 解决方案:给 JavaBean 的所有属性写getter(如getName()、getAge()),若需要修改属性,再写setter。

坑 4:include 指令包含文件后报错 “重复 page 指令”

原因:静态包含(<%@ include %>)会合并文件,被包含的header.jsp也写了page指令,导致重复。

✅ 解决方案:被包含的片段文件(header.jsp、footer.jsp)只保留 HTML 内容,去掉page指令,page指令只在主页面配置。

坑 5:Session 存的登录态 “突然消失”

原因:Session 默认有效期 30 分钟(Tomcat 配置),或 Tomcat 重启、浏览器关闭(Session 依赖 Cookie,关闭浏览器 Cookie 失效)。

✅ 解决方案:

延长 Session 有效期:在web.xml中配置60(单位:分钟);

重要场景用 Cookie 存储(如 “记住我” 功能)。

六、进阶方向:JSP 之后该学什么?

掌握 JSP 基础后,推荐按以下路径进阶,衔接现代 JavaWeb 技术:

JSTL 标签库:替代 Java 脚本,让 JSP 更简洁

替代<% for %>循环,替代<% if %>判断,避免 JSP 中写大量 Java 代码。示例:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%-- 引入JSTL核心库 --%>

<%-- 循环用户列表 --%>

${user.id}

${user.name}

EL 表达式:简化数据获取,替代<%= %>

用${requestScope.userList}替代<%= request.getAttribute("userList") %>,用${sessionScope.loginUser}替代<%= session.getAttribute("loginUser") %>,代码更简洁。

理解 “服务端渲染” vs “客户端渲染”

JSP 是 “服务端渲染”(服务器生成完整 HTML 返回),而 Vue/React 是 “客户端渲染”(服务器返回 JSON,前端 JS 渲染页面)。理解两者差异,能更好地选择项目技术栈。

学习现代模板引擎:Thymeleaf

SpringBoot 默认推荐 Thymeleaf,它支持 “静态预览”(JSP 不支持),语法更接近 HTML,是现在企业级开发的主流。学习 Thymeleaf 时,对比它与 JSP 的异同,能快速上手。

总结

JSP 的核心是 “HTML 中嵌 Java,实现服务端渲染”,它与 Servlet 的配合是 JavaWeb 的基础,也是理解 SpringMVC 等框架的关键。新手学习的重点不是死记语法,而是多动手写实战案例(如用户列表、登录回显),理清 “Servlet 处理业务→JSP 展示数据” 的链路。

如果这篇文章帮你