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代码,语法为<% 代码 %>。
<%
String username = "张三";
int age = 25;
System.out.println("用户名: " + username);
%>2. 表达式(Expressions)
表达式用于输出Java表达式的值,语法为<%= 表达式 %>。它相当于out.print(表达式)。
<p>用户名: <%= username %></p>
<p>年龄: <%= age %></p>
<p>当前时间: <%= new java.util.Date() %></p>3. 声明(Declarations)
声明用于定义JSP页面中的变量和方法,语法为<%! 代码 %>。声明的变量和方法会成为生成的Servlet类的成员变量和成员方法。
<%!
// 成员变量
private int count = 0;
// 成员方法
public String getGreeting() {
return "Hello, World!";
}
%>
<p>访问次数: <%= ++count %></p>
<p>问候语: <%= getGreeting() %></p>指令
JSP指令用于向JSP容器提供关于JSP页面的信息,语法为<%@ 指令名 属性="值" %>。
1. page指令
page指令用于定义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:错误页面的URLisErrorPage:是否为错误页面session:是否可以使用session对象buffer:输出缓冲区大小autoFlush:是否自动刷新缓冲区
2. include指令
include指令用于在JSP页面加载时包含另一个文件的内容,语法为<%@ include file="文件路径" %>。这是静态包含,被包含的文件内容会在编译时插入到当前JSP页面中。
<%@ include file="header.jsp" %>
<h1>正文内容</h1>
<%@ include file="footer.jsp" %>3. taglib指令
注意:由于特殊要求,此处不详细展开自定义标签库相关内容。
动作元素
JSP动作元素用于在JSP页面执行一些操作,如包含文件、转发请求、创建JavaBean实例等,语法为<jsp:动作名 属性="值" />。
1. jsp:include
jsp:include动作用于在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: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:useBean id="user" class="com.example.User" scope="session" />4. jsp:setProperty
jsp:setProperty动作用于设置JavaBean的属性。
<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: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接口的实例。
常用方法:
<%
// 获取请求参数
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接口的实例。
常用方法:
<%
// 设置响应内容类型
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类的实例。
常用方法:
<%
// 输出内容
out.print("<h1>Hello</h1>");
out.println("<p>这是一个段落</p>");
// 写入缓冲区
out.write("Hello World");
// 刷新缓冲区
out.flush();
// 关闭输出流
out.close();
%>4. session
session对象表示客户端的会话,它是javax.servlet.http.HttpSession接口的实例。
常用方法:
<%
// 获取会话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接口的实例。
常用方法:
<%
// 设置和获取属性
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接口的实例。
常用方法:
<%
// 获取Servlet名称
String servletName = config.getServletName();
// 获取初始化参数
String paramValue = config.getInitParameter("paramName");
// 获取所有初始化参数名称
Enumeration<String> paramNames = config.getInitParameterNames();
%>7. page
page对象表示JSP页面本身,它是当前JSP页面转换后的Servlet类的实例,相当于Java中的this关键字。
<%
// 获取页面的类名
String className = page.getClass().getName();
%>8. pageContext
pageContext对象表示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页面中才能使用。
<%@ 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页面
- 生命周期: 从页面加载到页面响应结束
- 使用场景: 页面内部临时数据
<%
pageContext.setAttribute("pageAttr", "页面作用域的数据");
String value = (String) pageContext.getAttribute("pageAttr");
%>2. 请求作用域(Request Scope)
- 对象:
request - 范围: 当前请求(包括请求转发)
- 生命周期: 从请求开始到响应结束
- 使用场景: 请求处理过程中的数据共享
<%
request.setAttribute("requestAttr", "请求作用域的数据");
// 转发到另一个页面,属性在转发后的页面仍然可用
request.getRequestDispatcher("next.jsp").forward(request, response);
%>3. 会话作用域(Session Scope)
- 对象:
session - 范围: 当前用户会话
- 生命周期: 从会话创建到会话超时或失效
- 使用场景: 用户登录信息、购物车等
<%
session.setAttribute("username", "admin");
String username = (String) session.getAttribute("username");
%>4. 应用作用域(Application Scope)
- 对象:
application - 范围: 整个Web应用
- 生命周期: 从应用启动到应用关闭
- 使用场景: 全局配置、共享缓存等
<%
application.setAttribute("onlineUsers", 0);
Integer onlineUsers = (Integer) application.getAttribute("onlineUsers");
%>JSP与Servlet的关系
JSP和Servlet都是Java Web开发的核心技术,它们之间有着密切的关系。
JSP的执行过程
- 客户端发送请求访问JSP页面
- Web容器(如Tomcat)检查JSP页面是否已经被编译
- 如果没有被编译,Web容器将JSP页面翻译成Servlet源代码
- Web容器编译Servlet源代码生成字节码文件(.class)
- Web容器加载并实例化Servlet
- Web容器调用Servlet的
_jspService方法处理请求 - Servlet生成HTML响应并发送给客户端
JSP与Servlet的比较
| 特性 | JSP | Servlet |
|---|---|---|
| 开发重点 | 页面展示 | 业务逻辑处理 |
| 代码组织 | 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. 处理异常
使用错误页面(errorPage和isErrorPage)统一处理异常,提高用户体验。
6. 优化性能
- 使用缓存减少数据库访问
- 合理设置会话超时时间
- 避免在JSP中进行复杂的计算
7. 安全性
- 对用户输入进行验证和过滤,防止SQL注入和XSS攻击
- 不要在JSP中硬编码敏感信息
- 使用HTTPS传输敏感数据
示例:简单的用户登录系统
下面是一个简单的用户登录系统示例,展示了JSP和Servlet的结合使用。
1. 登录页面(login.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)
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)
<%@ 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)
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应用打下坚实的基础。