引言
在Java Web开发领域,JSP(Java Server Pages)技术曾经是构建动态网页的主流选择。随着技术的发展,JSTL(JSP Standard Tag Library)和EL(Expression Language)表达式的引入极大地简化了JSP页面的开发。本文将深入探讨这些技术的核心概念,并分析如何将它们与MVC分层模式相结合,构建更清晰、更易维护的Web应用程序。
一、JSP技术概述
JSP是一种基于Java的服务器端技术,允许开发者在HTML页面中嵌入Java代码,用于生成动态内容。其工作原理是:
- 服务器将JSP文件编译成Servlet 
- Servlet生成HTML响应 
- 响应发送给客户端浏览器 
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>简单JSP示例</title>
</head>
<body>
    <h1>当前时间: <%= new java.util.Date() %></h1>
</body>
</html>虽然JSP提供了强大的功能,但直接在页面中嵌入过多的Java代码会导致代码难以维护,这就是JSTL和EL表达式出现的原因。
二、EL表达式详解
2.1 EL表达式基础
EL(Expression Language)表达式是JSP 2.0引入的重要特性,它提供了一种简洁的方式来访问应用程序数据,消除了JSP页面中的大多数Java代码。
基本语法:${expression}
<!-- 传统方式 -->
<%= request.getAttribute("userName") %>
<!-- EL表达式方式 -->
${userName}2.2 EL表达式的隐含对象
EL提供了11个隐含对象,可以方便地访问各种作用域中的变量:
| 隐含对象 | 描述 | 
|---|---|
| pageScope | page作用域中的属性 | 
| requestScope | request作用域中的属性 | 
| sessionScope | session作用域中的属性 | 
| applicationScope | application作用域中的属性 | 
| param | 请求参数(Map<String,String>) | 
| paramValues | 请求参数(Map<String,String[]>) | 
| header | HTTP请求头信息 | 
| headerValues | HTTP请求头信息(多值) | 
| cookie | Cookie值 | 
| initParam | 上下文初始化参数 | 
| pageContext | 提供访问其他JSP隐含对象的方法 | 
2.3 EL表达式运算符
EL支持多种运算符,使表达式更加灵活:
- 算术运算符: - +,- -,- *,- /,- %
- 关系运算符: - ==,- !=,- <,- >,- <=,- >=
- 逻辑运算符: - &&,- ||,- !
- 条件运算符: - A ? B : C
- empty运算符: - empty A检查null或空
${(user.age >= 18) ? "成人" : "未成年"}
${empty userList ? "无用户数据" : "用户数量: " + userList.size()}三、JSTL标签库
3.1 JSTL概述
JSTL(JSP Standard Tag Library)是标准的JSP标签库,它封装了JSP应用的通用核心功能,进一步减少了页面中的脚本代码。
JSTL分为五个功能区域:
- 核心标签(c) 
- 格式化标签(fmt) 
- SQL标签(sql) 
- XML标签(x) 
- 函数标签(fn) 
3.2 核心标签库
核心标签库是最常用的部分,包括:
- 变量支持: - <c:set>,- <c:remove>
- 流程控制: - <c:if>,- <c:choose>,- <c:when>,- <c:otherwise>
- 迭代: - <c:forEach>,- <c:forTokens>
- URL相关: - <c:import>,- <c:url>,- <c:redirect>,- <c:param>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="salary" value="${2000*2}"/>
<c:if test="${salary > 2000}">
    <p>高薪人士<p>
</c:if>
<c:forEach items="${userList}" var="user" varStatus="status">
    <tr>
        <td>${status.index + 1}</td>
        <td>${user.name}</td>
        <td>${user.email}</td>
    </tr>
</c:forEach>3.3 格式化标签库
格式化标签库用于处理国际化(I18N)和格式化问题:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<fmt:formatNumber value="${product.price}" type="currency"/>
<fmt:formatDate value="${now}" pattern="yyyy-MM-dd HH:mm:ss"/>四、MVC分层模式
4.1 MVC概念
MVC(Model-View-Controller)是一种软件架构模式,将应用程序分为三个核心部分:
- Model(模型): 处理数据和业务逻辑 
- View(视图): 显示数据(JSP) 
- Controller(控制器): 处理用户输入(Servlet) 
4.2 JSP在MVC中的角色
在MVC模式中,JSP通常只负责视图层:
- 不应该包含复杂的业务逻辑 
- 尽量减少Java脚本代码 
- 主要使用EL和JSTL显示数据 
4.3 分层实现示例
Controller(Servlet):
@WebServlet("/user/list")
public class UserListServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        UserService service = new UserService();
        List<User> users = service.getAllUsers();
        
        request.setAttribute("users", users);
        request.getRequestDispatcher("/WEB-INF/views/userList.jsp").forward(request, response);
    }
}Model(Service):
public class UserService {
    public List<User> getAllUsers() {
        // 实际项目中这里会调用DAO访问数据库
        List<User> users = new ArrayList<>();
        users.add(new User(1, "张三", "zhangsan@example.com"));
        users.add(new User(2, "李四", "lisi@example.com"));
        return users;
    }
}View(JSP):
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<table>
    <tr>
        <th>序号</th>
        <th>姓名</th>
        <th>邮箱</th>
    </tr>
    <c:forEach items="${users}" var="user" varStatus="status">
        <tr>
            <td>${status.index + 1}</td>
            <td>${user.name}</td>
            <td>${user.email}</td>
        </tr>
    </c:forEach>
</table>五、最佳实践
5.1 JSP开发规范
- 避免脚本元素:尽量使用EL和JSTL替代 - <% %>和- <%= %>
- 分离显示逻辑:复杂的显示逻辑可以封装为自定义标签 
- 合理使用作用域:根据数据生命周期选择合适的作用域 
- 错误处理:使用 - <%@ page errorPage="error.jsp" %>处理错误
5.2 性能优化建议
- 减少JSP编译开销:预编译JSP或使用JSP缓存 
- 合理使用静态包含: - <%@ include file="header.jsp" %>(静态) vs- <jsp:include page="header.jsp"/>(动态)
- 避免过度使用Session:大对象存储在Session中会影响性能 
- 启用EL表达式缓存: - <%@ page isELIgnored="false" %>
六、现代Web开发中的演进
虽然JSP技术逐渐被Thymeleaf、FreeMarker等现代模板引擎取代,但在许多遗留系统中仍然广泛使用。理解JSP、JSTL和EL表达式对于维护这些系统至关重要。
Spring MVC等现代框架仍然借鉴了MVC的思想,只是实现方式有所不同:
- 控制器使用 - @Controller注解
- 视图解析器支持多种模板引擎 
- 模型数据通过 - Model对象传递
结语
JSP与JSTL结合EL表达式,配合MVC分层模式,曾经是Java Web开发的标准实践。虽然技术不断演进,但这些概念中的许多思想仍然影响着现代Web开发。理解这些基础知识不仅有助于维护遗留系统,也能更好地理解现代框架的设计理念。
希望本文能帮助您全面理解JSP、JSTL和MVC模式。如果您有任何问题或建议,欢迎在评论区留言讨论!