目录
### 4.2.2 response 对象的 HTTP 文件头
```
在本文中,我们将介绍JSP中最常用的五种内置对象:request、response、session、application和out,它们分别用于获取用户请求的信息、向用户发送响应的信息、管理用户会话的状态、存储应用程序范围的数据和控制数据输出的操作。我们将通过一些示例代码来展示它们的用法和功能。
## 4.1 request对象
request对象代表了客户端通过HTTP协议发送给服务器端的请求信息,它通常是HttpServletRequest的子类,它的作用域是一次request请求。通过request对象,我们可以获取用户提交的参数、头信息、系统信息、Cookie和Session等对象和数据。
### 4.1.1 获取用户提交的信息
当用户通过表单或超链接向服务器发送请求时,我们可以使用request对象的getParameter(String name)方法来获取指定名称的参数值。例如:
```jsp
<%-- 假设用户通过一个表单提交了用户名和密码 --%>
<%-- 表单代码如下:
<form action="login.jsp" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
--%>
<%-- 在login.jsp页面中,我们可以使用request.getParameter(String name)方法来获取用户名和密码 --%>
<%
String username = request.getParameter("username"); // 获取用户名
String password = request.getParameter("password"); // 获取密码
out.println("用户名:" + username + "<br>");
out.println("密码:" + password + "<br>");
%>
```
如果一个参数有多个值,例如复选框或多选列表,我们可以使用request对象的getParameterValues(String name)方法来获取一个字符串数组,包含所有参数值。例如:
```jsp
<%-- 假设用户通过一个表单提交了喜欢的颜色 --%>
<%-- 表单代码如下:
<form action="color.jsp" method="post">
喜欢的颜色:<br>
<input type="checkbox" name="color" value="red">红色<br>
<input type="checkbox" name="color" value="green">绿色<br>
<input type="checkbox" name="color" value="blue">蓝色<br>
<input type="submit" value="提交">
</form>
--%>
<%-- 在color.jsp页面中,我们可以使用request.getParameterValues(String name)方法来获取所有选择的颜色 --%>
<%
String[] colors = request.getParameterValues("color"); // 获取颜色数组
out.println("喜欢的颜色有:<br>");
for (String color : colors) {
out.println(color + "<br>");
}
%>
```
如果我们想要获取所有参数的名称,我们可以使用request对象的getParameterNames()方法来获取一个枚举类型(Enumeration)的对象,然后遍历该对象来获取每个参数名。例如:
```jsp
<%-- 假设用户通过一个表单提交了姓名、年龄和性别 --%>
<%-- 表单代码如下:
<form action="info.jsp" method="post">
姓名:<input type="text" name="name"><br>
年龄:<input type="text" name="age"><br>
性别:<input type="radio" name="gender" value="male">男
<input type="radio" name="gender" value="female">女<br>
<input type="submit" value="提交">
</form>
--%>
<%-- 在info.jsp页面中,我们可以使用request.getParameterNames()方法来获取所有参数名 --%>
<%
Enumeration<String> names = request.getParameterNames(); // 获取参数名枚举对象
while (names.hasMoreElements()) {
String name = names.nextElement(); // 获取下一个参数名
String value = request.getParameter(name); // 获取对应的参数值
out.println(name + ":" + value + "<br>");
}
%>
```
### 4.1.2 处理汉字信息
当用户提交包含汉字的信息时,我们需要注意编码问题,否则可能出现乱码。为了解决这个问题,我们需要在表单中指定编码方式为UTF-8,并且在JSP页面中使用request对象的setCharacterEncoding(String chaen)方法来设置请求编码方式为UTF-8。例如:
```jsp
<%-- 假设用户通过一个表单提交了姓名 --%>
<%-- 表单代码如下:
<form action="name.jsp" method="post" enctype="multipart/form-data">
姓名:<input type="text" name="name"><br>
<input type="submit" value="提交">
</form>
--%>
<%-- 在name.jsp页面中,我们需要设置请求编码方式为UTF-8 --%>
<%
request.setCharacterEncoding("UTF-8"); // 设置请求编码方式为UTF-8
String name = request.getParameter("name"); // 获取姓名
out.println("姓名:" + name + "<br>");
%>
```
### 4.1.3 常用方法举例
除了上面介绍的getParameter系列方法外,request对象还提供了很多其他有用的方法,下面列举一些常用的方法举例:
- getHeader(String name):获取指定名称的请求头信息。例如:
```jsp
<%
String userAgent = request.getHeader("User-Agent"); // 获取User-Agent请求头信息
out.println("User-Agent:" + userAgent + "<br>");
%>
```
- getMethod():获取请求方式(GET或POST)。例如:
```jsp
<%
String method = request.getMethod(); // 获取请求方式
out.println("请求方式:" + method + "<br>");
%>
```
- getRequestURI():获取请求URI(统一资源标识符)。例如:
```jsp
<%
String uri = request.getRequestURI(); // 获取请求URI
out.println("请求URI:" + uri + "<br>");
%>
```
- getRemoteAddr():获取客户端IP地址。例如:
```jsp
<%
String ip = request.getRemoteAddr(); // 获取客户端IP地址
out.println("客户端IP地址:" + ip + "<br>");
%>
```
- getCookies():获取客户端发送的Cookie数组。例如:
```jsp
<%
Cookie[] cookies = request.getCookies(); // 获取Cookie数组
if (cookies != null) {
for (Cookie cookie : cookies) {
String name = cookie.getName(); // 获取Cookie名
String value = cookie.getValue(); // 获取Cookie值
out.println(name + ":" + value + "<br>");
}
}
%>
```
- getSession():获取或创建与当前请求关联的Session对象。例如:
```jsp
<%
HttpSession session = request.getSession(); // 获取或创建Session对象
session.setAttribute("username", "张三"); // 设置Session属性
%>
``
## 4.2 response对象
response对象代表了服务器端向客户端发送响应信息,它通常是HttpServletResponse的子类,它也是一次request请求范围内有效。通过response对象,我们可以设置响应头信息、响应状态码、
响应内容类型、响应状态码、重定向用户到其他页面或发送Cookie等。
### 4.2.1 动态响应 contentType 属性
contentType 属性用于指定响应的内容类型和字符编码,它的默认值是 text/html;charset=ISO-8859-1,这意味着响应的内容是 HTML 格式,并且使用 ISO-8859-1 编码。如果我们想要改变响应的内容类型或字符编码,我们可以使用 response 对象的 setContentType(String type) 方法来设置 contentType 属性。例如:
```jsp
<%-- 假设我们想要响应一个 XML 格式的内容,并且使用 UTF-8 编码 --%>
<%
response.setContentType("text/xml;charset=UTF-8"); // 设置 contentType 属性
%>
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book>
<title>Java编程思想</title>
<author>埃克尔</author>
<price>108</price>
</book>
<book>
<title>JSP从入门到精通</title>
<author>张三</author>
<price>68</price>
</book>
</books>
```
### 4.2.2 response 对象的 HTTP 文件头
HTTP 文件头是响应信息中的一部分,它用于传递一些元数据,例如响应的日期、服务器的类型、缓存控制、Cookie等。response 对象提供了一些方法来设置或添加 HTTP 文件头,例如:
- setHeader(String name, String value):设置指定名称的文件头的值,如果该文件头已经存在,则覆盖原来的值。
- addHeader(String name, String value):添加指定名称的文件头的值,如果该文件头已经存在,则保留原来的值,并追加新的值。
- setDateHeader(String name, long date):设置指定名称的文件头的日期值,如果该文件头已经存在,则覆盖原来的值。
- addDateHeader(String name, long date):添加指定名称的文件头的日期值,如果该文件头已经存在,则保留原来的值,并追加新的值。
- setIntHeader(String name, int value):设置指定名称的文件头的整数值,如果该文件头已经存在,则覆盖原来的值。
- addIntHeader(String name, int value):添加指定名称的文件头的整数值,如果该文件头已经存在,则保留原来的值,并追加新的值。
例如:
```jsp
<%-- 假设我们想要设置响应的缓存控制为不缓存 --%>
<%
response.setHeader("Cache-Control", "no-cache"); // 设置 Cache-Control 文件头
response.setDateHeader("Expires", -1); // 设置 Expires 文件头
response.setHeader("Pragma", "no-cache"); // 设置 Pragma 文件头
%>
```
### 4.2.3 response 对象的重定向
有时候,我们可能想要将用户从一个页面重定向到另一个页面,例如登录成功后跳转到主页,或者访问了一个不存在或禁止访问的页面跳转到错误页面等。response 对象提供了一个方法来实现重定向,即 sendRedirect(String location) 方法,它接受一个参数 location,表示重定向目标的 URL。例如:
```jsp
<%-- 假设我们想要将用户从 login.jsp 页面重定向到 index.jsp 页面 --%>
<%
response.sendRedirect("index.jsp"); // 发送重定向
%>
```
当服务器执行 sendRedirect(String location) 方法时,它会向客户端发送一个状态码为 302 的响应,并且在响应头中添加一个 Location 文件头,其值为重定向目标的 URL。当客户端收到这个响应时,它会根据 Location 文件头中提供的 URL 发送一个新的请求,从而完成重定向。
需要注意的是,sendRedirect(String location) 方法只能在没有输出任何内容之前调用,否则会抛出 IllegalStateException 异常。另外,sendRedirect(String location) 方法会结束当前请求,所以在调用该方法之后不要再输出任何内容或执行任何逻辑
## 4.3 session 对象
session 对象用于管理用户会话的状态,它通常是 HttpSession 的子类,它可以在多个请求之间共享数据。通过 session 对象,我们可以存储和获取用户会话范围内有效的数据和对象。
### 4.3.1 session 对象的 id
每个 session 对象都有一个唯一标识符,称为 session id,它是由服务器自动生成并分配给客户端。session id 可以通过 Cookie 或 URL 重写(URL Rewriting)两种方式传递给服务器。Cookie 是一种在客户端存储少量数据并随请求发送给服务器
的一种机制,URL 重写是一种在 URL 中附加额外参数的技术。session id 通常以 JSESSIONID 为名称,例如:
```jsp
<%-- 假设客户端发送了一个包含 Cookie 的请求,其中有一个 Cookie 名为 JSESSIONID,值为 ABAD1D --%>
<%
Cookie[] cookies = request.getCookies(); // 获取 Cookie 数组
for (Cookie cookie : cookies) {
if ("JSESSIONID".equals(cookie.getName())) { // 判断是否是 JSESSIONID
out.println("Cookie 中的 session id:" + cookie.getValue() + "<br>"); // 输出 session id
}
}
%>
```
```jsp
<%-- 假设客户端发送了一个包含 URL 重写的请求,其中有一个参数名为 JSESSIONID,值为 ABAD1D --%>
<%
String sessionId = request.getParameter("JSESSIONID"); // 获取 URL 重写中的参数值
if (sessionId != null) { // 判断是否存在 session id
out.println("URL 重写中的 session id:" + sessionId + "<br>"); // 输出 session id
}
%>
```
无论是通过 Cookie 还是 URL 重写传递的 session id,我们都可以使用 request 对象的 getSession() 方法来获取或创建与当前请求关联的 session 对象。例如:
```jsp
<%
HttpSession session = request.getSession(); // 获取或创建 session 对象
%>
```
getSession() 方法有一个布尔型的参数,表示是否在没有找到现有的 session 对象时创建一个新的 session 对象,默认值为 true。如果我们只想获取现有的 session 对象而不创建新的对象,我们可以传递 false 作为参数。例如:
```jsp
<%
HttpSession session = request.getSession(false); // 只获取现有的 session 对象,不创建新的对象
%>
```
如果我们想要获取当前 session 对象的 id,我们可以使用 getId() 方法。例如:
```jsp
<%
HttpSession session = request.getSession(); // 获取或创建 session 对象
out.println("session id:" + session.getId() + "<br>"); // 输出 session id
%>
```
### 4.3.2 session 对象与 URL 重写
当客户端不支持或禁用了 Cookie 时,我们就不能通过 Cookie 来传递 session id,这时候我们就需要使用 URL 重写来实现 session 跟踪。URL 重写的原理是在每个响应给客户端的 URL 中附加一个名为 JSESSIONID 的参数,并且其值为当前 session 的 id。这样当客户端再次访问这些 URL 时,就会将 JSESSIONID 参数和值一起发送给服务器,从而让服务器能够识别出是同一个会话。
URL 重写的工作需要由服务器和开发者共同完成。服务器负责在响应给客户端的 URL 中添加 JSESSIONID 参数和值,开发者负责在编写 JSP 页面时使用特定的标签或方法来生成 URL,并且保证这些 URL 能够被服务器正确地重写。
如果我们想要使用 URL 重写来实现 session 跟踪,我们需要注意以下几点:
- 我们不能直接在 JSP 页面中硬编码 URL,而是要使用动态生成 URL 的方式,例如使用 response 对象的 encodeURL(String url) 方法或 encodeRedirectURL(String url) 方法来生成 URL。这些方法会根据客户端是否支持 Cookie 来决定是否在 URL 中添加 JSESSIONID 参数和值。例如:
```jsp
<%-- 假设当前页面是 index.jsp,并且当前 session 的 id 是 ABAD1D --%>
<%
String url1 = response.encodeURL("login.jsp"); // 动态生成 login.jsp 的 URL
String url2 = response.encodeRedirectURL("register.jsp"); // 动态生成 register.jsp 的 URL
%>
<a href="<%=url1%>">登录</a> <!-- 如果客户端不支持 Cookie,则 url1 的值为 login.jsp;JSESSIONID=ABAD1D -->
<a href="<%=url2%>">注册</a> <!-- 如果客户端不支持 Cookie,则 url2 的值为 register.jsp;JSESSIONID=ABAD1D -->
```
- 我们不能使用 HTML 表单中的 action 属性来指定提交表单数据的目标 URL,而是要使用 jsp:forward 标签或 jsp:param 标签来实现表单数据的传递。这些标签会自动处理 URL 重写,并且不会暴露表单数据给客户端。例如:
```jsp
<%-- 假设当前页面是 login.jsp,并且当前 session 的 id 是 ABAD1D --%>
<form method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
<%-- 使用 jsp:forward 标签和 jsp:param 标签来传递表单数据 --%>
<jsp:forward page="checkLogin.jsp"> <!-- 如果客户端不支持 Cookie,则 page 的值为 checkLogin.jsp;JSESSIONID=ABAD1D -->
<jsp:param name="username" value="<%=request.getParameter("username")%>" /> <!-- 将 username 参数传递给 checkLogin.jsp -->
<jsp:param name="password" value="<%=request.getParameter("password")%>" /> <!-- 将 password 参数传递给 checkLogin.jsp -->
</jsp:forward>
```
- 我们不能使用 JavaScript 或其他客户端脚本来生成或跳转到目标 URL,因为这些脚本无法处理 URL 重写。如果我们必须使用客户端脚本,我们可以将动态生成的 URL 存储在隐藏字段中,并且在脚本中引用这些隐藏字段。例如:
```jsp
<%-- 假设当前页面是 index.jsp,并且当前 session 的 id 是 ABAD1D --%>
<%
String url1 = response.encodeURL("login.jsp"); // 动态生成 login.jsp 的 URL
%>
<input type="hidden" id="url1" value="<%=url1%>"> <!-- 将 url1 存储在隐藏字段中 -->
<script>
function goToLogin() {
var url = document.getElementById("url1").value; // 获取隐藏字段中的 url1 值
window.location.href = url; // 跳转到 url
}
</script>
<button οnclick="goToLogin()">登录</button> <!-- 点击按钮时调用 goToLogin 函数 -->
```
## 4.4 application 对象
application 对象用于存储应用程序范围内有效的数据和对象,它通常是 ServletContext 的子类,它可以在多个会话和请求之间共享数据。通过 application 对象,我们可以存储和获取应用程序启动时初始化或运行时产生的数据和对象。
### 4.4.1 application对象的常用方法
application 对象提供了一些常用方法来操作应用程序范围内有效的数据和对象,例如:
- setAttribute(String name, Object value):设置指定名称的属性值,如果该属性已经存在,则覆盖原来的值。
- getAttribute(String name):获取指定名称的属性值,如果该属性不存在,则返回 null。
- removeAttribute(String name):移除指定名称的属性及其值。
- getAttributeNames():获取所有属性名称的枚举类型(Enumeration)对象。
- getInitParameter(String name):获取 web.xml 文件中配置的指定名称的初始化参数值。
- getInitParameterNames():获取 web.xml 文件中配置的所有初始化参数名称的枚举类型(Enumeration)对象。
<%-- 假设我们在 web.xml 文件中配置了一个初始化参数,如下:
<context-param>
<param-name>appName</param-name>
<param-value>JSP Demo</param-value>
</context-param>
--%>
<%-- 在任意 JSP 页面中,我们可以使用 application 对象来获取或设置应用程序范围内的数据 --%>
<%
String appName = application.getInitParameter("appName"); // 获取初始化参数
out.println("应用程序名称:" + appName + "<br>");
application.setAttribute("count", 0); // 设置一个属性
int count = (Integer)application.getAttribute("count"); // 获取该属性
out.println("访问次数:" + count + "<br>");
application.removeAttribute("count"); // 移除该属性
%>
### 4.4.2 application对象的监听器
application对象的监听器是一种特殊的类,它可以实现ServletContextListener接口,从而监听application对象的创建和销毁事件。当web应用程序启动时,服务器会创建一个application对象,并且调用监听器的contextInitialized(ServletContextEvent sce)方法;当web应用程序停止时,服务器会销毁application对象,并且调用监听器的contextDestroyed(ServletContextEvent sce)方法。通过这些方法,我们可以在应用程序的生命周期中执行一些初始化或清理的操作。
要使用application对象的监听器,我们需要在web.xml文件中配置监听器类的全限定名,例如:
```xml
<web-app ...>
<listener>
<listener-class>com.example.MyApplicationListener</listener-class>
</listener>
</web-app>
```
下面是一个简单的application对象的监听器的示例,它在应用程序启动时打印一条信息,并且在应用程序停止时打印另一条信息:
```java
package com.example;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyApplicationListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("Application started");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("Application stopped");
}
}
```
## 4.5 out对象
out对象是JSP中的一个隐式对象,它用于向客户端输出内容,它是jsp.JspWriter类的一个实例。out对象可以在JSP页面中的任何位置使用,它提供了一些方法来输出不同类型的数据,例如:
- print(Object obj):输出指定对象的字符串表示形式,不换行。
- println(Object obj):输出指定对象的字符串表示形式,并换行。
- printf(String format, Object... args):按照指定的格式输出参数列表,不换行。
- println():输出一个空行。
- clear():清空缓冲区中的内容,如果缓冲区已经被刷新,则抛出IOException异常。
- flush():刷新缓冲区中的内容,将其写入目标流中。
下面是一个简单的out对象的使用示例:
```jsp
<%-- 假设当前页面是 index.jsp --%>
<%
out.print("Hello, this is "); // 输出字符串,不换行
out.println("index.jsp"); // 输出字符串,并换行
out.printf("Today is %tF", new Date()); // 按照格式输出日期,不换行
out.println(); // 输出一个空行
out.flush(); // 刷新缓冲区
%>
```
输出结果为:
```
Hello, this is index.jsp
Today is 2022-01-25
```