JSP 入门到实战:2 小时写出动态页面,吃透 Servlet+JSP 协作逻辑
很多刚学完 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" %>
$END$
2. 第二步:写第一个动态功能(显示当前时间)
在body标签中嵌入 Java 代码,实现 “实时显示服务器时间”—— 这是 JSP 最基础的动态能力
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.Date,java.text.SimpleDateFormat" %> <%-- 导入Java类 --%>
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.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类 --%>
table { border-collapse: collapse; width: 80%; margin: 20px auto; }
th, td { border: 1px solid #333; padding: 12px; text-align: center; }
th { background: #f0f0f0; }
用户列表(共<%= ((List)request.getAttribute("userList")).size() %>人)
| 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中配置
重要场景用 Cookie 存储(如 “记住我” 功能)。
六、进阶方向:JSP 之后该学什么?
掌握 JSP 基础后,推荐按以下路径进阶,衔接现代 JavaWeb 技术:
JSTL 标签库:替代 Java 脚本,让 JSP 更简洁
用
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%-- 引入JSTL核心库 --%>
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 展示数据” 的链路。
如果这篇文章帮你