Skip to content

JSP基础

JSP(JavaServer Pages)是一种动态网页开发技术,它允许在HTML页面中嵌入Java代码,使开发者能够创建动态生成的Web页面。JSP是Java EE规范的一部分,它与Servlet紧密集成,可以看作是Servlet的扩展。本文将详细介绍JSP的基本概念、语法、内置对象、指令和常用技术。

JSP概述

什么是JSP?

JSP是一种基于文本的程序,它包含HTML标记和嵌入的Java代码。JSP文件的扩展名是.jsp,当客户端请求访问JSP页面时,Web容器会将JSP页面翻译成Servlet,然后编译并执行这个Servlet,最后将生成的HTML发送给客户端。

JSP的作用

  • 简化Web开发:将HTML和Java代码分离,使页面设计更加方便
  • 动态内容生成:根据不同的请求和数据生成不同的页面内容
  • 重用组件:可以使用和重用JavaBean、自定义标签等组件
  • 与Servlet集成:可以与Servlet配合,实现MVC架构
  • 易于维护:页面结构清晰,便于设计人员和开发人员协作

JSP的优点

  • 跨平台:基于Java技术,可以在任何支持Java的平台上运行
  • 组件化:支持组件化开发,提高代码重用性
  • 安全性:继承了Java的安全机制
  • 扩展性:可以通过标签库、自定义标签等进行扩展
  • 与JDBC集成:可以方便地访问数据库

JSP基本语法

脚本元素

1. 脚本段(Scriptlets)

脚本段用于在JSP页面中嵌入Java代码,语法为<% 代码 %>

jsp
<% 
    String username = "张三";
    int age = 25;
    System.out.println("用户名: " + username);
%>

2. 表达式(Expressions)

表达式用于输出Java表达式的值,语法为<%= 表达式 %>。它相当于out.print(表达式)

jsp
<p>用户名: <%= username %></p>
<p>年龄: <%= age %></p>
<p>当前时间: <%= new java.util.Date() %></p>

3. 声明(Declarations)

声明用于定义JSP页面中的变量和方法,语法为<%! 代码 %>。声明的变量和方法会成为生成的Servlet类的成员变量和成员方法。

jsp
<%!
    // 成员变量
    private int count = 0;
    
    // 成员方法
    public String getGreeting() {
        return "Hello, World!";
    }
%>

<p>访问次数: <%= ++count %></p>
<p>问候语: <%= getGreeting() %></p>

指令

JSP指令用于向JSP容器提供关于JSP页面的信息,语法为<%@ 指令名 属性="值" %>

1. page指令

page指令用于定义JSP页面的属性,如导入包、设置内容类型、设置错误页面等。

jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.*, java.io.*"
    errorPage="error.jsp" isErrorPage="false"
    session="true" buffer="8kb" autoFlush="true"
    isThreadSafe="true" info="This is a JSP page" %>

常用属性:

  • language:脚本语言,默认为"java"
  • contentType:响应的MIME类型和字符编码
  • pageEncoding:JSP页面的字符编码
  • import:导入Java包
  • errorPage:错误页面的URL
  • isErrorPage:是否为错误页面
  • session:是否可以使用session对象
  • buffer:输出缓冲区大小
  • autoFlush:是否自动刷新缓冲区

2. include指令

include指令用于在JSP页面加载时包含另一个文件的内容,语法为<%@ include file="文件路径" %>。这是静态包含,被包含的文件内容会在编译时插入到当前JSP页面中。

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

<h1>正文内容</h1>

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

3. taglib指令

注意:由于特殊要求,此处不详细展开自定义标签库相关内容。

动作元素

JSP动作元素用于在JSP页面执行一些操作,如包含文件、转发请求、创建JavaBean实例等,语法为<jsp:动作名 属性="值" />

1. jsp:include

jsp:include动作用于在JSP页面执行时包含另一个文件的内容,这是动态包含。

jsp
<jsp:include page="header.jsp" flush="true" />

<h1>正文内容</h1>

<jsp:include page="footer.jsp" flush="true" />

2. jsp:forward

jsp:forward动作用于将请求转发到另一个资源(JSP、Servlet或HTML页面)。

jsp
<jsp:forward page="welcome.jsp">
    <jsp:param name="username" value="admin" />
    <jsp:param name="role" value="user" />
</jsp:forward>

3. jsp:useBean

jsp:useBean动作用于创建或查找一个JavaBean实例。

jsp
<jsp:useBean id="user" class="com.example.User" scope="session" />

4. jsp:setProperty

jsp:setProperty动作用于设置JavaBean的属性。

jsp
<jsp:useBean id="user" class="com.example.User" scope="session" />
<jsp:setProperty name="user" property="username" value="张三" />
<jsp:setProperty name="user" property="age" value="25" />
<jsp:setProperty name="user" property="*" /><!-- 自动匹配请求参数 -->

5. jsp:getProperty

jsp:getProperty动作用于获取JavaBean的属性值。

jsp
<jsp:useBean id="user" class="com.example.User" scope="session" />
<p>用户名: <jsp:getProperty name="user" property="username" /></p>
<p>年龄: <jsp:getProperty name="user" property="age" /></p>

JSP内置对象

JSP提供了9个内置对象,这些对象不需要显式创建就可以在JSP页面中使用。

1. request

request对象表示客户端的请求,它是javax.servlet.http.HttpServletRequest接口的实例。

常用方法:

jsp
<%
    // 获取请求参数
    String username = request.getParameter("username");
    String[] hobbies = request.getParameterValues("hobby");
    
    // 获取请求头
    String userAgent = request.getHeader("User-Agent");
    
    // 获取请求URL和URI
    StringBuffer requestURL = request.getRequestURL();
    String requestURI = request.getRequestURI();
    
    // 设置和获取属性
    request.setAttribute("message", "Hello");
    String message = (String) request.getAttribute("message");
    
    // 请求转发
    request.getRequestDispatcher("welcome.jsp").forward(request, response);
%>

2. response

response对象表示对客户端的响应,它是javax.servlet.http.HttpServletResponse接口的实例。

常用方法:

jsp
<%
    // 设置响应内容类型
    response.setContentType("text/html; charset=UTF-8");
    
    // 设置响应状态码
    response.setStatus(HttpServletResponse.SC_OK);
    
    // 设置响应头
    response.setHeader("Cache-Control", "no-cache");
    
    // 获取输出流
    PrintWriter out = response.getWriter();
    out.println("<h1>Hello</h1>");
    
    // 重定向
    response.sendRedirect("welcome.jsp");
    
    // 添加Cookie
    Cookie cookie = new Cookie("username", "admin");
    cookie.setMaxAge(30 * 24 * 60 * 60); // 30天
    response.addCookie(cookie);
%>

3. out

out对象用于向客户端输出内容,它是javax.servlet.jsp.JspWriter类的实例。

常用方法:

jsp
<%
    // 输出内容
    out.print("<h1>Hello</h1>");
    out.println("<p>这是一个段落</p>");
    
    // 写入缓冲区
    out.write("Hello World");
    
    // 刷新缓冲区
    out.flush();
    
    // 关闭输出流
    out.close();
%>

4. session

session对象表示客户端的会话,它是javax.servlet.http.HttpSession接口的实例。

常用方法:

jsp
<%
    // 获取会话ID
    String sessionId = session.getId();
    
    // 设置和获取属性
    session.setAttribute("username", "admin");
    String username = (String) session.getAttribute("username");
    
    // 移除属性
    session.removeAttribute("username");
    
    // 设置会话超时时间(秒)
    session.setMaxInactiveInterval(30 * 60); // 30分钟
    
    // 获取创建时间和最后访问时间
    long creationTime = session.getCreationTime();
    long lastAccessedTime = session.getLastAccessedTime();
    
    // 使会话失效
    // session.invalidate();
%>

5. application

application对象表示Web应用的上下文,它是javax.servlet.ServletContext接口的实例。

常用方法:

jsp
<%
    // 设置和获取属性
    application.setAttribute("appName", "MyWebApp");
    String appName = (String) application.getAttribute("appName");
    
    // 获取初始化参数
    String version = application.getInitParameter("version");
    
    // 获取真实路径
    String realPath = application.getRealPath("/WEB-INF/config.properties");
    
    // 获取MIME类型
    String mimeType = application.getMimeType("file.txt");
%>

6. config

config对象表示JSP页面的配置信息,它是javax.servlet.ServletConfig接口的实例。

常用方法:

jsp
<%
    // 获取Servlet名称
    String servletName = config.getServletName();
    
    // 获取初始化参数
    String paramValue = config.getInitParameter("paramName");
    
    // 获取所有初始化参数名称
    Enumeration<String> paramNames = config.getInitParameterNames();
%>

7. page

page对象表示JSP页面本身,它是当前JSP页面转换后的Servlet类的实例,相当于Java中的this关键字。

jsp
<%
    // 获取页面的类名
    String className = page.getClass().getName();
%>

8. pageContext

pageContext对象表示JSP页面的上下文,它提供了访问页面中所有对象和命名空间的方法。

常用方法:

jsp
<%
    // 获取其他内置对象
    HttpServletRequest req = (HttpServletRequest) pageContext.getRequest();
    HttpServletResponse resp = (HttpServletResponse) pageContext.getResponse();
    HttpSession sess = pageContext.getSession();
    ServletContext app = pageContext.getServletContext();
    
    // 设置和获取属性(在不同作用域中)
    pageContext.setAttribute("pageAttr", "page value"); // 页面作用域
    pageContext.setAttribute("requestAttr", "request value", PageContext.REQUEST_SCOPE); // 请求作用域
    pageContext.setAttribute("sessionAttr", "session value", PageContext.SESSION_SCOPE); // 会话作用域
    pageContext.setAttribute("applicationAttr", "application value", PageContext.APPLICATION_SCOPE); // 应用作用域
    
    // 查找属性(按作用域顺序查找)
    Object attr = pageContext.findAttribute("attrName");
    
    // 转发请求
    pageContext.forward("welcome.jsp");
    
    // 包含页面
    pageContext.include("header.jsp");
%>

9. exception

exception对象表示JSP页面中发生的异常,它是java.lang.Throwable类的实例。只有在设置了isErrorPage="true"的JSP页面中才能使用。

jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" isErrorPage="true" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>错误页面</title>
</head>
<body>
    <h1>发生错误</h1>
    <p>错误信息: <%= exception.getMessage() %></p>
    <p>错误类型: <%= exception.getClass().getName() %></p>
    <hr>
    <h3>堆栈跟踪:</h3>
    <pre>
<%
    exception.printStackTrace(new java.io.PrintWriter(out));
%>
    </pre>
</body>
</html>

JSP作用域

JSP中的属性可以存储在不同的作用域中,作用域决定了属性的可见范围和生命周期。

1. 页面作用域(Page Scope)

  • 对象: pageContext
  • 范围: 当前JSP页面
  • 生命周期: 从页面加载到页面响应结束
  • 使用场景: 页面内部临时数据
jsp
<%
    pageContext.setAttribute("pageAttr", "页面作用域的数据");
    String value = (String) pageContext.getAttribute("pageAttr");
%>

2. 请求作用域(Request Scope)

  • 对象: request
  • 范围: 当前请求(包括请求转发)
  • 生命周期: 从请求开始到响应结束
  • 使用场景: 请求处理过程中的数据共享
jsp
<%
    request.setAttribute("requestAttr", "请求作用域的数据");
    // 转发到另一个页面,属性在转发后的页面仍然可用
    request.getRequestDispatcher("next.jsp").forward(request, response);
%>

3. 会话作用域(Session Scope)

  • 对象: session
  • 范围: 当前用户会话
  • 生命周期: 从会话创建到会话超时或失效
  • 使用场景: 用户登录信息、购物车等
jsp
<%
    session.setAttribute("username", "admin");
    String username = (String) session.getAttribute("username");
%>

4. 应用作用域(Application Scope)

  • 对象: application
  • 范围: 整个Web应用
  • 生命周期: 从应用启动到应用关闭
  • 使用场景: 全局配置、共享缓存等
jsp
<%
    application.setAttribute("onlineUsers", 0);
    Integer onlineUsers = (Integer) application.getAttribute("onlineUsers");
%>

JSP与Servlet的关系

JSP和Servlet都是Java Web开发的核心技术,它们之间有着密切的关系。

JSP的执行过程

  1. 客户端发送请求访问JSP页面
  2. Web容器(如Tomcat)检查JSP页面是否已经被编译
  3. 如果没有被编译,Web容器将JSP页面翻译成Servlet源代码
  4. Web容器编译Servlet源代码生成字节码文件(.class)
  5. Web容器加载并实例化Servlet
  6. Web容器调用Servlet的_jspService方法处理请求
  7. Servlet生成HTML响应并发送给客户端

JSP与Servlet的比较

特性JSPServlet
开发重点页面展示业务逻辑处理
代码组织HTML中嵌入Java代码Java代码中生成HTML
适用场景内容丰富的动态页面控制器、API接口
性能首次访问需要翻译和编译直接编译执行
维护性设计人员和开发人员分离主要面向开发人员

MVC架构中的角色

在MVC(Model-View-Controller)架构中:

  • Model: 业务逻辑和数据访问(JavaBean、EJB等)
  • View: 用户界面(JSP)
  • Controller: 控制流程(Servlet)

这种架构可以将业务逻辑、控制流程和页面展示分离,提高代码的可维护性和可扩展性。

JSP最佳实践

1. 遵循MVC架构

将业务逻辑放在Servlet或JavaBean中,JSP只负责页面展示,实现关注点分离。

2. 避免在JSP中编写大量Java代码

尽量使用EL表达式和JSTL标签替代Java脚本,使页面更加清晰。

3. 使用JavaBean封装数据

将数据和业务逻辑封装在JavaBean中,通过jsp:useBean动作在JSP中使用。

4. 合理使用作用域

根据数据的生命周期和使用范围,选择合适的作用域(page、request、session、application)存储数据。

5. 处理异常

使用错误页面(errorPageisErrorPage)统一处理异常,提高用户体验。

6. 优化性能

  • 使用缓存减少数据库访问
  • 合理设置会话超时时间
  • 避免在JSP中进行复杂的计算

7. 安全性

  • 对用户输入进行验证和过滤,防止SQL注入和XSS攻击
  • 不要在JSP中硬编码敏感信息
  • 使用HTTPS传输敏感数据

示例:简单的用户登录系统

下面是一个简单的用户登录系统示例,展示了JSP和Servlet的结合使用。

1. 登录页面(login.jsp)

jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
    <h1>用户登录</h1>
    <form action="LoginServlet" method="post">
        <table>
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username" required /></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="password" required /></td>
            </tr>
            <tr>
                <td colspan="2"><input type="submit" value="登录" /></td>
            </tr>
        </table>
    </form>
    <p style="color: red;">
        <%= request.getAttribute("errorMessage") == null ? "" : request.getAttribute("errorMessage") %>
    </p>
</body>
</html>

2. 登录Servlet(LoginServlet.java)

java
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.*;

@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置请求编码
        request.setCharacterEncoding("UTF-8");
        
        // 获取请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        
        // 简单的登录验证(实际应用中应该查询数据库)
        if ("admin".equals(username) && "123456".equals(password)) {
            // 登录成功,将用户信息存入session
            HttpSession session = request.getSession();
            session.setAttribute("username", username);
            
            // 重定向到欢迎页面
            response.sendRedirect("welcome.jsp");
        } else {
            // 登录失败,设置错误信息并转发回登录页面
            request.setAttribute("errorMessage", "用户名或密码错误");
            request.getRequestDispatcher("login.jsp").forward(request, response);
        }
    }
}

3. 欢迎页面(welcome.jsp)

jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>欢迎页面</title>
</head>
<body>
    <h1>欢迎,<%= session.getAttribute("username") %></h1>
    <p>您已成功登录系统!</p>
    <a href="LogoutServlet">退出登录</a>
</body>
</html>

4. 退出登录Servlet(LogoutServlet.java)

java
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.*;

@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 使session失效
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.invalidate();
        }
        
        // 重定向到登录页面
        response.sendRedirect("login.jsp");
    }
}

小结

JSP是Java Web开发中的重要技术,它允许在HTML页面中嵌入Java代码,使开发者能够创建动态生成的Web页面。本文介绍了JSP的基本概念、语法、内置对象、指令和常用技术,包括:

  • JSP的脚本元素:脚本段、表达式、声明
  • JSP的指令:page、include、taglib
  • JSP的动作元素:include、forward、useBean等
  • JSP的9个内置对象:request、response、out、session、application、config、page、pageContext、exception
  • JSP的4种作用域:page、request、session、application
  • JSP与Servlet的关系和MVC架构
  • JSP的最佳实践

通过学习这些知识,您可以掌握JSP的基本用法,为开发Java Web应用打下坚实的基础。