楼层: 首页/ 软件技术/ JavaEE / Jakarta EE/ JSP:在网页里混 Java(MVC 的 V)
03

JSP:在网页里混 Java(MVC 的 V)

JSP · EL · JSTL · MVC Pattern

Servlet 里手写 out.write("<h1>...") 拼 HTML,拼到第 50 行你会想死。JSP(JavaServer Pages)就是"反着来":先写好 HTML,需要动态插内容的地方嵌 Java。它本质上会被容器翻译成一个 Servlet——你以为在写网页,其实还是在写 Servlet。

show.jsp:HTML 为主,混少量动态代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://xmlns.jcp.org/jsp/jstl/core" %>
<html>
<body>
  <h1>学生名单</h1>
  <ul>
    <%-- JSP 注释(用户看不到),下面 EL 表达式 ${} 直接取 request 里的 list --%>
    <c:forEach items="${list}" var="s">
      <li>${s.name} —— ${s.score} 分</li>
    </c:forEach>
  </ul>
</body>
</html>

论MVC:Servlet 和 JSP 怎么分工

M(Model 模型):数据本身,就是你的 JavaBean / record(学生对象)。V(View 视图):JSP,负责把数据画成网页。C(Controller 控制器):Servlet,接请求、调数据、挑页面。

一次请求的标准流程:浏览器 → Servlet(查数据库,把 list 塞进 request)→ forward 给 JSP → JSP 用 EL 把 list 显示出来。这套分工叫 MVC,是所有 Web 框架(包括 Spring MVC)的祖师爷。

为什么这么分:HTML 写在 Servlet 的 out.write("<h1>...") 里,改个样式要改 Java 代码;Java 业务写在 JSP 的 <% %> 里,前端想改页面要碰后端代码。MVC 把"长什么样"和"怎么算"分开,各改各的。

JSP 是怎么跑起来的(一次翻译,终身受益)

浏览器第一次访问 show.jsp
  → Tomcat 发现没跑过这个 JSP
  → 把 show.jsp 翻译成 show_jsp.java(一个 HttpServlet 子类)
  → 编译成 show_jsp.class,放进内存
  → 以后再访问,直接用编译好的 class,飞快

你改了 JSP,Tomcat 会自动检测并重新翻译——
但生产环境建议把 JSP 预编译好,别让用户第一次访问撞上编译延迟。
JSP 零件干什么用
指令
<%@ ... %>
页面级设置:contentType、导入 JSTL 标签库。
脚本片段
<% ... %>
直接嵌 Java 代码(能不用就不用,见第 10 章)。
EL 表达式
${name}
从 request/session/application 域里取值,自动判空,推荐用。
JSTL c:forEach遍历集合,代替裸 for 循环。
JSTL c:if页面上做条件判断。

EL 表达式常用隐式对象与 c:choose

${} 不是只会取 request 属性,它背后有几个自带的"隐式对象",查参数、查 Cookie 都靠它们。

EL 写法等价的 Java 代码
${name}依次从 page / request / session / application 找名字叫 name 的属性。
${param.xxx}request.getParameter("xxx"),取请求参数。
${header.host}取请求头。
${cookie.token.value}名叫 token 的 Cookie 的值。
${sessionScope.loginUser}显式从 Session 域取,别靠默认搜索顺序。

多分支判断:c:choose / when / otherwise 相当于 if-else if-else

<c:choose>
  <c:when test="${score >= 90}"><b>优秀</b></c:when>
  <c:when test="${score >= 60}">及格</c:when>
  <c:otherwise>不及格,补考见</c:otherwise>
</c:choose>

完整 MVC 案例:Servlet 控制器 + JSP 视图 + JavaBean 模型 + EL + JSTL

// —— M:Model,一个普通 JavaBean(学生)——
public class Student {
    private String name;
    private int score;
    public Student(String name, int score) { this.name = name; this.score = score; }
    public String getName() { return name; }
    public int getScore() { return score; }
}

// —— C:Controller,Servlet 接请求、查数据、挑视图 ——
@WebServlet("/students")
public class StudentServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // 1. 查数据(真实场景从 DAO 查数据库)
        List<Student> list = List.of(
            new Student("小明", 92),
            new Student("小红", 88)
        );
        // 2. 塞进 request 域
        req.setAttribute("studentList", list);
        // 3. 转发给 JSP 展示(地址栏还是 /students)
        req.getRequestDispatcher("/students.jsp").forward(req, resp);
    }
}

// —— V:View,students.jsp 只负责显示 ——
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://xmlns.jcp.org/jsp/jstl/core" %>
<html><body>
  <h1>学生名单</h1>
  <table border="1">
    <tr><th>姓名</th><th>分数</th></tr>
    <c:forEach items="${studentList}" var="s">
      <tr>
        <td>${s.name}</td>
        <td>
          <c:choose>
            <c:when test="${s.score >= 90}"><b style="color:green">${s.score}</b></c:when>
            <c:when test="${s.score >= 60}">${s.score}</c:when>
            <c:otherwise><span style="color:red">${s.score}</span></c:otherwise>
          </c:choose>
        </td>
      </tr>
    </c:forEach>
  </table>
</body></html>

// 访问 http://localhost:8080/students,输出表格:
// 小明 92(绿色)
// 小红 88
JSP 里写大段 Java 是坏味道

看到 JSP 里 <% for(...) { ... } %> 塞了几十行业务逻辑——这叫"意大利面条式代码",页面又乱又难维护。规矩:业务逻辑全在 Servlet(或 Service)里,JSP 只负责"显示",最多写几个 c:forEach。现代前端(Vue/React)+ 后端返回 JSON 的架构,就是把这条规矩推到了极致。

章末面试 · JSP 与 MVC(4 题)

1.(概念题)JSP 本质是什么?它怎么变成 Servlet 的?

查看答案

答案:JSP 是一个会被容器翻译成 Servlet 的文本模板。第一次访问时 Tomcat 把 .jsp 翻译成 _jsp.java 再编译成 class,以后访问直接用编译好的 class。

2.(概念题)MVC 三个字母分别对应什么?

查看答案

答案:Model 是数据(JavaBean/record),View 是 JSP(显示),Controller 是 Servlet(接请求、调数据、挑页面)。

3.(概念题)JSP 九大隐式对象是哪几个?

查看答案

答案:pageContext、request、response、session、application、out、config、page、exception。最常用的是 request(取参数)、session(取登录态)、out(写输出)。

4.(排错题)JSP 里 ${name} 输出空,怎么排查?

查看答案

答案:EL 表达式依次从 page/request/session/application 找属性。检查 Servlet 里 setAttribute 的名字和 JSP 里 ${} 里写的是否一致。名字拼错是最高频原因。