HTTP请求与HTTP响应的格式相近,都有着如下结构:
举例来说,一个服务器响应头看起来就像下面这样:
HTTP/1.1 200 OK
Content-Type: text/html
Header2: ...
...
HeaderN: ...
(Blank Line)
...
...
状态行包含HTTP版本,一个状态码,和状态码相对应的短消息。
下表列出了可能会从服务器返回的HTTP状态码和与之关联的消息:
状态码 | 消息 | 描述 |
---|---|---|
100 | Continue | 只有一部分请求被服务器接收,但只要没被服务器拒绝,客户端就会延续这个请求 |
101 | Switching Protocols | 服务器交换机协议 |
200 | OK | 请求被确认 |
201 | Created | 请求时完整的,新的资源被创建 |
202 | Accepted | 请求被接受,但未处理完 |
203 | Non-authoritative Information | |
204 | No Content | |
205 | Reset Content | |
206 | Partial Content | |
300 | Multiple Choices | 一个超链接表,用户可以选择一个超链接并访问,最大支持5个超链接 |
301 | Moved Permanently | 被请求的页面已经移动到了新的URL下 |
302 | Found | 被请求的页面暂时性地移动到了新的URL下 |
303 | See Other | 被请求的页面可以在一个不同的URL下找到 |
304 | Not Modified | |
305 | Use Proxy | |
306 | Unused | 已经不再使用此状态码,但状态码被保留 |
307 | Temporary Redirect | 被请求的页面暂时性地移动到了新的URL下 |
400 | Bad Request | 服务器无法识别请求 |
401 | Unauthorized | 被请求的页面需要用户名和密码 |
402 | Payment Required | 目前还不能使用此状态码 |
403 | Forbidden | 禁止访问所请求的页面 |
404 | Not Found | 服务器无法找到所请求的页面 |
405 | Method Not Allowed | 请求中所指定的方法不被允许 |
406 | Not Acceptable | 服务器只能创建一个客户端无法接受的响应 |
407 | Proxy Authentication Required | 在请求被服务前必须认证一个代理服务器 |
408 | Request Timeout | 请求时间超过了服务器所能等待的时间,连接被断开 |
409 | Conflict | 请求有矛盾的地方 |
410 | Gone | 被请求的页面不再可用 |
411 | Length Required | "Content-Length"没有被定义,服务器拒绝接受请求 |
412 | Precondition Failed | 请求的前提条件被服务器评估为false |
413 | Request Entity Too Large | 因为请求的实体太大,服务器拒绝接受请求 |
414 | Request-url Too Long | 服务器拒绝接受请求,因为URL太长。多出现在把"POST"请求转换为"GET"请求时所附带的大量查询信息 |
415 | Unsupported Media Type | 服务器拒绝接受请求,因为媒体类型不被支持 |
417 | Expectation Failed | |
500 | Internal Server Error | 请求不完整,服务器遇见了出乎意料的状况 |
501 | Not Implemented | 请求不完整,服务器不提供所需要的功能 |
502 | Bad Gateway | 请求不完整,服务器从上游服务器接受了一个无效的响应 |
503 | Service Unavailable | 请求不完整,服务器暂时重启或关闭 |
504 | Gateway Timeout | 网关超时 |
505 | HTTP Version Not Supported | 服务器不支持所指定的HTTP版本 |
下表列出了HttpServletResponse 类中用来设置状态码的方法:
S.N. | 方法 & 描述 |
---|---|
1 | public void setStatus ( int statusCode ) 此方法可以设置任意的状态码。如果您的响应包含一个特殊的状态码和一个文档,请确保在用PrintWriter返回任何内容前调用setStatus方法 |
2 | public void sendRedirect(String url) 此方法产生302响应,同时产生一个 Location 头告诉URL 一个新的文档 |
3 | public void sendError(int code, String message) 此方法将一个状态码(通常为 404)和一个短消息,自动插入HTML文档中并发回给客户端 |
接下来的例子将会发送407错误码给浏览器,然后浏览器将会告诉您"Need authentication!!!"。
<%
// 设置错误代码,并说明原因
response.sendError(407, "Need authentication!!!" );
%>
访问以上JSP页面,将会得到以下结果:
您也可以试试使用其他的状态码,看会不会得到什么意想不到结果。
JSP 表单处理我们在浏览网页的时候,经常需要向服务器提交信息,并让后台程序处理。浏览器中使用 GET 和 POST 方法向服务器提交数据。
GET方法将请求的编码信息添加在网址后面,网址与编码信息通过"?"号分隔。如下所示:
http://www.runoob.com/hello?key1=value1&key2=value2
GET方法是浏览器默认传递参数的方法,一些敏感信息,如密码等建议不使用GET方法。
用get时,传输数据的大小有限制 (注意不是参数的个数有限制),最大为1024字节。
一些敏感信息,如密码等我们可以通过POST方法传递,POST提交数据是隐式的。
POST提交数据是不可见的,GET是通过在url里面传递的(可以看一下你浏览器的地址栏)。
JSP使用getParameter()来获得传递的参数,getInputStream()方法用来处理客户端的二进制数据流的请求。
getParameter(): 使用 request.getParameter() 方法来获取表单参数的值。
getParameterValues(): 获得如checkbox类(名字相同,但值有多个)的数据。 接收数组变量 ,如checkbox类型
getParameterNames():该方法可以取得所有变量的名称,该方法返回一个 Enumeration。
getInputStream():调用此方法来读取来自客户端的二进制数据流。
以下是一个简单的URL,并使用GET方法来传递URL中的参数:
http://localhost:8080/testjsp/main.jsp?name=菜鸟教程&url=http://ww.runoob.com
testjsp 为项目地址。
以下是 main.jsp 文件的JSP程序用于处理客户端提交的表单数据,我们使用getParameter()方法来获取提交的数据:
<%@ page language="java" cOntentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>
站点名:
<%= request.getParameter("name")%>
网址:
<%= request.getParameter("url")%>
接下来我们通过浏览器访问 http://localhost:8080/testjsp/main.jsp?name=菜鸟教程&url=http://ww.runoob.com 输出结果如下所示:
以下是一个简单的 HTML 表单,该表单通过GET方法将客户端数据提交 到 main.jsp 文件中:
站点名:
网址:
将以上HTML代码保存到test.htm文件中。 将该文件放置于当前jsp项目的 WebContent 目录下(与 main.jsp 同一个目录)。
通过访问 http://localhost:8080/testjsp/test.html 提交表单数据到 main.jsp 文件,演示 Gif 图如下所示:
在 "站点名" 与 "网址" 两个表单中填入信息,并点击 "提交" 按钮,它将输出结果。
接下来让我们使用POST方法来传递表单数据,修改main.jsp与Hello.htm文件代码,如下所示:
main.jsp文件代码:
<%@ page language="java" cOntentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>
站点名:
<%
// 解决中文乱码的问题
String name = new String((request.getParameter("name")).getBytes("ISO-8859-1"),"UTF-8");
%>
<%=name%>
网址:
<%= request.getParameter("url")%>
代码中我们使用 new String((request.getParameter("name")).getBytes("ISO-8859-1"),"UTF-8")来转换编码,防止中文乱码的发生。
以下是test.htm修改后的代码:
站点名:
网址:
通过访问 http://localhost:8080/testjsp/test.html 提交表单数据到 main.jsp 文件,演示 Gif 图如下所示:
复选框 checkbox 可以传递一个甚至多个数据。
以下是一个简单的HTML代码,并将代码保存在test.htm文件中:
Google
菜鸟教程
淘宝
以上代码在浏览器访问如下所示:
以下为main.jsp文件代码,用于处理复选框数据:
<%@ page language="java" cOntentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>
Google 是否选中:
<%= request.getParameter("google")%>
菜鸟教程是否选中:
<%= request.getParameter("runoob")%>
淘宝是否选中:
<%= request.getParameter("taobao")%>
通过访问 http://localhost:8080/testjsp/test.html 提交表单数据到 main.jsp 文件,演示 Gif 图如下所示:
以下我们将使用 HttpServletRequest 的 getParameterNames() 来读取所有表单参数,该方法可以取得所有变量的名称,该方法返回一个枚举。
一旦我们有了一个 Enumeration(枚举),我们就可以调用 hasMoreElements() 方法来确定是否还有元素,以及使用nextElement()方法来获得每个参数的名称。
<%@ page language="java" cOntentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>
参数名 | 参数值 |
---|---|
" + paramName + " | \n");" + paramValue + " |
以下是test.htm文件的内容:
Google
菜鸟教程
淘宝
现在我们通过浏览器访问 test.htm 文件提交数据,输出结果如下:
通过访问 http://localhost:8080/testjsp/test.html 提交表单数据到 main.jsp 文件,演示 Gif 图如下所示:
你可以尝试使用以上的JSP代码读取其它对象,如文本框,单选按钮或下拉框等等其他形式的数据。
JSP 过滤器JSP 和 Servlet 中的过滤器都是 Java 类。
过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息。
可以将一个或多个过滤器附加到一个 Servlet 或一组 Servlet。过滤器也可以附加到 JavaServer Pages (JSP) 文件和 HTML 页面。
过滤器是可用于 Servlet 编程的 Java 类,可以实现以下目的:
根据规范建议的各种类型的过滤器:
过滤器通过 Web 部署描述符(web.xml)中的 XML 标签来声明,然后映射到您的应用程序的部署描述符中的 Servlet 名称或 URL 模式。
当 Web 容器启动 Web 应用程序时,它会为您在部署描述符中声明的每一个过滤器创建一个实例。
Filter 的执行顺序与在 web.xml 配置文件中的配置顺序一致,一般把 Filter 配置在所有的 Servlet 之前。
过滤器是一个实现了 javax.servlet.Filter 接口的 Java 类。javax.servlet.Filter 接口定义了三个方法:
序号 | 方法 & 描述 |
---|---|
1 | public void doFilter (ServletRequest, ServletResponse, FilterChain) 该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet 容器将先调用过滤器的 doFilter 方法。FilterChain 用于访问后续过滤器。 |
2 | public void init(FilterConfig filterConfig) web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。 |
3 | public void destroy() Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。 |
Filter 的 init 方法中提供了一个 FilterConfig 对象。
如 web.xml 文件配置如下:
在 init 方法使用 FilterConfig 对象获取参数:
public void init(FilterConfig config) throws ServletException {
// 获取初始化参数
String site = config.getInitParameter("Site");
// 输出初始化参数
System.out.println("网站名称: " + site);
}
以下是 Servlet 过滤器的实例,将输出网站名称和地址。本实例让您对 Servlet 过滤器有基本的了解,您可以使用相同的概念编写更复杂的过滤器应用程序:
//导入必需的 java 库
import javax.servlet.*;
import java.util.*;
//实现 Filter 类
public class LogFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
// 获取初始化参数
String site = config.getInitParameter("Site");
// 输出初始化参数
System.out.println("网站名称: " + site);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {
// 输出站点名称
System.out.println("站点网址:http://www.runoob.com");
// 把请求传回过滤链
chain.doFilter(request,response);
}
public void destroy( ){
/* 在 Filter 实例被 Web 容器从服务移除之前调用 */
}
}
DisplayHeader.java 文件代码如下:
//导入必需的 java 库
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/DisplayHeader")
//扩展 HttpServlet 类
public class DisplayHeader extends HttpServlet {
// 处理 GET 方法请求的方法
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// 设置响应内容类型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "HTTP Header 请求实例 - 菜鸟教程实例";
String docType =
" \n";
out.println(docType +
"\n" +
"\n"+
"\n" +
"
Header 名称 | Header 值 | \n"+
---|---|
" + paramName + " | \n");" + paramValue + " |
定义过滤器,然后映射到一个 URL 或 Servlet,这与定义 Servlet,然后映射到一个 URL 模式方式大致相同。在部署描述符文件 web.xml 中为 filter 标签创建下面的条目:
上述过滤器适用于所有的 Servlet,因为我们在配置中指定 /* 。如果您只想在少数的 Servlet 上应用过滤器,您可以指定一个特定的 Servlet 路径。
现在试着以常用的方式调用任何 Servlet,您将会看到在 Web 服务器中生成的日志。您也可以使用 Log4J 记录器来把上面的日志记录到一个单独的文件中。
接下来我们访问这个实例地址 http://localhost:8080/TomcatTest/DisplayHeader, 然后在控制台看下输出内容,如下所示:
Web 应用程序可以根据特定的目的定义若干个不同的过滤器。假设您定义了两个过滤器 AuthenFilter 和 LogFilter。您需要创建一个如下所述的不同的映射,其余的处理与上述所讲解的大致相同:
web.xml 中的 filter-mapping 元素的顺序决定了 Web 容器应用过滤器到 Servlet 的顺序。若要反转过滤器的顺序,您只需要在 web.xml 文件中反转 filter-mapping 元素即可。
例如,上面的实例将先应用 LogFilter,然后再应用 AuthenFilter,但是下面的实例将颠倒这个顺序:
指定一个过滤器。
用于为过滤器指定一个名字,该元素的内容不能为空。
元素用于指定过滤器的完整的限定类名。
元素用于为过滤器指定初始化参数,它的子元素
指定参数的名字,
指定参数的值。FilterConfig
接口对象来访问初始化参数。
元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
子元素用于设置filter的注册名称。该值必须是在
元素中声明过的过滤器的名字
设置 filter 所拦截的请求路径(过滤器关联的URL样式)
指定过滤器所拦截的Servlet名称。
指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST
,INCLUDE
,FORWARD
和ERROR
之一,默认REQUEST
。用户可以设置多个
子元素用来指定 Filter 对资源的多种调用方式进行拦截。
子元素可以设置的值及其意义REQUEST
:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。INCLUDE
:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。FORWARD
:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。ERROR
:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。COOKIE 是存储在客户机的文本文件,它们保存了大量轨迹信息。在 Servlet 技术基础上,JSP 显然能够提供对 HTTP COOKIE 的支持。
通常有三个步骤来识别回头客:
本章节将会传授您如何去设置或重设 COOKIE 的方法,还有如何访问它们及如何删除它们。
JSP COOKIE 处理需要对中文进行编码与解码,方法如下:
String str = java.net.URLEncoder.encode("中文", "UTF-8"); //编码
String str = java.net.URLDecoder.decode("编码后的字符串","UTF-8"); // 解码
COOKIE 通常在 HTTP 信息头中设置(虽然 Javascript 能够直接在浏览器中设置 COOKIE)。在 JSP 中,设置一个 COOKIE 需要发送如下的信息头给服务器:
HTTP/1.1 200 OK
Date: Fri, 04 Feb 2015 21:03:38 GMT
Server: Apache/1.3.9 (UNIX) PHP/4.0b3
Set-COOKIE: name=runoob; expires=Friday, 04-Feb-17 22:03:38 GMT;
path=/; domain=runoob.com
Connection: close
Content-Type: text/html
正如您所见,Set-COOKIE 信息头包含一个键值对,一个 GMT(格林尼治标准)时间,一个路径,一个域名。键值对会被编码为URL。有效期域是个指令,告诉浏览器在什么时候之后就可以清除这个 COOKIE。
如果浏览器被配置成可存储 COOKIE,那么它将会保存这些信息直到过期。如果用户访问的任何页面匹配了 COOKIE 中的路径和域名,那么浏览器将会重新将这个 COOKIE 发回给服务器。浏览器端的信息头长得就像下面这样:
GET / HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.6 (X11; I; Linux 2.2.6-15apmac ppc)
Host: zink.demon.co.uk:1126
Accept: image/gif, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
COOKIE: name=xyz
JSP 脚本通过 request 对象中的 getCOOKIEs() 方法来访问这些 COOKIE,这个方法会返回一个 COOKIE 对象的数组。
下表列出了 COOKIE 对象中常用的方法:
序号 | 方法 & 描述 |
---|---|
1 | public void setDomain(String pattern) 设置 COOKIE 的域名,比如 runoob.com |
2 | public String getDomain() 获取 COOKIE 的域名,比如 runoob.com |
3 | public void setMaxAge(int expiry) 设置 COOKIE 有效期,以秒为单位,默认有效期为当前session的存活时间 |
4 | public int getMaxAge() 获取 COOKIE 有效期,以秒为单位,默认为-1 ,表明COOKIE会活到浏览器关闭为止 |
5 | public String getName() 返回 COOKIE 的名称,名称创建后将不能被修改 |
6 | public void setValue(String newValue) 设置 COOKIE 的值 |
7 | public String getValue() 获取COOKIE的值 |
8 | public void setPath(String uri) 设置 COOKIE 的路径,默认为当前页面目录下的所有 URL,还有此目录下的所有子目录 |
9 | public String getPath() 获取 COOKIE 的路径 |
10 | public void setSecure(boolean flag) 指明 COOKIE 是否要加密传输 |
11 | public void setComment(String purpose) 设置注释描述 COOKIE 的目的。当浏览器将 COOKIE 展现给用户时,注释将会变得非常有用 |
12 | public String getComment() 返回描述 COOKIE 目的的注释,若没有则返回 null |
使用 JSP 设置 COOKIE 包含三个步骤:
(1)创建一个 COOKIE 对象: 调用 COOKIE 的构造函数,使用一个 COOKIE 名称和值做参数,它们都是字符串。
COOKIE COOKIE = new COOKIE("key","value");
请务必牢记,名称和值中都不能包含空格或者如下的字符:
[ ] ( ) = , " / ? @ : ;
(2) 设置有效期:调用 setMaxAge() 函数表明 COOKIE 在多长时间(以秒为单位)内有效。下面的操作将有效期设为了 24 小时。
COOKIE.setMaxAge(60*60*24);
(3) 将 COOKIE 发送至 HTTP 响应头中:调用 response.addCOOKIE() 函数来向 HTTP 响应头中添加 COOKIE。
response.addCOOKIE(COOKIE);
main.jsp 文件代码如下所示:
<%@ page language="java" cOntentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.net.*" %>
<%
// 编码,解决中文乱码
String str = URLEncoder.encode(request.getParameter("name"),"utf-8");
// 设置 name 和 url COOKIE
COOKIE name = new COOKIE("name",
str);
COOKIE url = new COOKIE("url",
request.getParameter("url"));
// 设置COOKIE过期时间为24小时。
name.setMaxAge(60*60*24);
url.setMaxAge(60*60*24);
// 在响应头部添加COOKIE
response.addCOOKIE( name );
response.addCOOKIE( url );
%>
网站名:
<%= request.getParameter("name")%>
网址:
<%= request.getParameter("url")%>
以下是一个简单的 HTML 表单通过 GET 方法将客户端数据提交到 main.jsp 文件中,并设置 COOKIE:
站点名:
网址:
将以上 HTML 代码保存到 test.htm 文件中。
将该文件放置于当前 jsp 项目的 WebContent 目录下(与 main.jsp 同一个目录)。
通过访问 http://localhost:8080/testjsp/test.html 提交表单数据到 main.jsp 文件,演示 Gif 图如下所示:
试着输入 "站点名" 和 "网址",然后点击提交按钮,它将会在您的屏幕中显示 "站点名" 和 "网址",并且设置 "站点名" 和 "网址" 的两个 COOKIE。
想要读取 COOKIE,您就需要调用 request.getCOOKIEs() 方法来获得一个 javax.servlet.http.COOKIE 对象的数组,然后遍历这个数组,使用 getName() 方法和 getValue() 方法来获取每一个 COOKIE 的名称和值。
让我们来读取上个例子中的COOKIE, 以下为 COOKIE.jsp 文件代码:
<%@ page language="java" cOntentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.net.*" %>
<%
COOKIE COOKIE = null;
COOKIE[] COOKIEs = null;
// 获取 COOKIEs 的数据,是一个数组
COOKIEs = request.getCOOKIEs();
if( COOKIEs != null ){
out.println("
浏览器访问后,输出结果为:
删除 COOKIE 非常简单。如果您想要删除一个 COOKIE,按照下面给的步骤来做就行了:
下面的程序删除一个名为 "name" 的 COOKIE,当您第二次运行 COOKIE.jsp时,name 将会为 null。
<%@ page language="java" cOntentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.net.*" %>
<%
COOKIE COOKIE = null;
COOKIE[] COOKIEs = null;
// 获取当前域名下的COOKIEs,是一个数组
COOKIEs = request.getCOOKIEs();
if( COOKIEs != null ){
out.println("
通过浏览器访问,输出结果为:
再次访问 http://localhost:8080/testjsp/COOKIE.jsp,将会得到如下结果:
可以看到名为 "name" 的 COOKIE 已经不见了。
您也可以手动在浏览器中删除 COOKIE。IE 浏览器通过点击 Tools 菜单项,然后选择 Internet Options,点击 Delete COOKIEs,就能删除所有 COOKIE 。
JSP SessionHTTP是无状态协议,这意味着每次客户端检索网页时,都要单独打开一个服务器连接,因此服务器不会记录下先前客户端请求的任何信息。
有三种方法来维持客户端与服务器的会话:
网络服务器可以指定一个唯一的session ID作为COOKIE来代表每个客户端,用来识别这个客户端接下来的请求。
这可能不是一种有效的方式,因为很多时候浏览器并不一定支持COOKIE,所以我们不建议使用这种方法来维持会话。
一个网络服务器可以发送一个隐藏的HTML表单域和一个唯一的session ID,就像下面这样:
这个条目意味着,当表单被提交时,指定的名称和值将会自动包含在GET或POST数据中。每当浏览器发送一个请求,session_id的值就可以用来保存不同浏览器的轨迹。
这种方式可能是一种有效的方式,但点击标签中的超链接时不会产生表单提交事件,因此隐藏表单域也不支持通用会话跟踪。
您可以在每个URL后面添加一些额外的数据来区分会话,服务器能够根据这些数据来关联session标识符。
举例来说,http://w3cschool.cc/file.htm;sessiOnid=12345, session标识符为sessiOnid=12345,服务器可以用这个数据来识别客户端。
相比而言,重写URL是更好的方式来,就算浏览器不支持COOKIEs也能工作,但缺点是您必须为每个URL动态指定session ID,就算这是个简单的HTML页面。
除了以上几种方法外,JSP利用servlet提供的HttpSession接口来识别一个用户,存储这个用户的所有访问信息。
默认情况下,JSP允许会话跟踪,一个新的HttpSession对象将会自动地为新的客户端实例化。禁止会话跟踪需要显式地关掉它,通过将page指令中session属性值设为false来实现,就像下面这样:
<%@ page session="false" %>
JSP引擎将隐含的session对象暴露给开发者。由于提供了session对象,开发者就可以方便地存储或检索数据。
下表列出了session对象的一些重要方法:
S.N. | 方法 & 描述 |
---|---|
1 | public Object getAttribute(String name) 返回session对象中与指定名称绑定的对象,如果不存在则返回null |
2 | public Enumeration getAttributeNames() 返回session对象中所有的对象名称 |
3 | public long getCreationTime() 返回session对象被创建的时间, 以毫秒为单位,从1970年1月1号凌晨开始算起 |
4 | public String getId() 返回session对象的ID |
5 | public long getLastAccessedTime() 返回客户端最后访问的时间,以毫秒为单位,从1970年1月1号凌晨开始算起 |
6 | public int getMaxInactiveInterval() 返回最大时间间隔,以秒为单位,servlet 容器将会在这段时间内保持会话打开 |
7 | public void invalidate() 将session无效化,解绑任何与该session绑定的对象 |
8 | public boolean isNew() 返回是否为一个新的客户端,或者客户端是否拒绝加入session |
9 | public void removeAttribute(String name) 移除session中指定名称的对象 |
10 | public void setAttribute(String name, Object value) 使用指定的名称和值来产生一个对象并绑定到session中 |
11 | public void setMaxInactiveInterval(int interval) 用来指定时间,以秒为单位,servlet容器将会在这段时间内保持会话有效 |
这个例子描述了如何使用HttpSession对象来获取创建时间和最后一次访问时间。我们将会为request对象关联一个新的session对象,如果这个对象尚未存在的话。
<%@ page language="java" cOntentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>
<%
// 获取session创建时间
Date createTime = new Date(session.getCreationTime());
// 获取最后访问页面的时间
Date lastAccessTime = new Date(session.getLastAccessedTime());
String title = "再次访问菜鸟教程实例";
Integer visitCount = new Integer(0);
String visitCountKey = new String("visitCount");
String userIDKey = new String("userID");
String userID = new String("ABCD");
// 检测网页是否有新的访问用户
if (session.isNew()){
title = "访问菜鸟教程实例";
session.setAttribute(userIDKey, userID);
session.setAttribute(visitCountKey, visitCount);
} else {
visitCount = (Integer)session.getAttribute(visitCountKey);
visitCount += 1;
userID = (String)session.getAttribute(userIDKey);
session.setAttribute(visitCountKey, visitCount);
}
%>
Session 信息 | 值 |
---|---|
id | <% out.print( session.getId()); %> |
创建时间 | <% out.print(createTime); %> |
最后访问时间 | <% out.print(lastAccessTime); %> |
用户 ID | <% out.print(userID); %> |
访问次数 | <% out.print(visitCount); %> |
试着访问 http://localhost:8080/testjsp/main.jsp ,第一次运行时将会得到如下结果:
再次访问,将会得到如下结果:
当处理完一个用户的会话数据后,您可以有如下选择:
调用public void removeAttribute(String name) 方法来移除指定的属性。
调用public void invalidate() 方法来使整个session无效。
调用 public void setMaxInactiveInterval(int interval) 方法来设置session超时。
支持servlet2.4版本的服务器,可以调用 logout()方法来登出用户,并且使所有相关的session无效。
如果使用的是Tomcat,可以向下面这样配置web.xml文件:
超时以分钟为单位,Tomcat中的默认的超时时间是30分钟。
Servlet中的getMaxInactiveInterval( ) 方法以秒为单位返回超时时间。如果在web.xml中配置的是15分钟,则getMaxInactiveInterval( ) 方法将会返回900。
JSP 文件上传JSP 可以与 HTML form 标签一起使用,来允许用户上传文件到服务器。上传的文件可以是文本文件或图像文件或任何文档。
本章节我们使用 Servlet 来处理文件上传,使用到的文件有:
结构图如下所示:
接下来我们详细介绍。
下面的 HTML 代码创建了一个文件上传表单。以下几点需要注意:
upload.jsp 文件代码如下:
<%@ page language="java" cOntentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
"http://www.w3.org/TR/html4/loose.dtd">
以下是 UploadServlet 的源代码,同于处理文件上传,在这之前我们先确保依赖包已经引入到项目的 WEB-INF/lib 目录下:
你可以直接下载本站提供的两个依赖包:
UploadServlet 的源代码 如下所示:
package com.runoob.test; message.jsp 文件代码如下: <%@ page language="java" cOntentType="text/html; charset=UTF-8" 编译上面的 Servlet UploadServlet,并在 web.xml 文件中创建所需的条目,如下所示: 现在尝试使用您在上面创建的 HTML 表单来上传文件。当您在浏览器中访问:http://localhost:8080/TomcatTest/upload.jsp ,演示如下所示:
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* Servlet implementation class UploadServlet
*/
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {
private static final long serialVersiOnUID= 1L;
// 上传文件存储目录
private static final String UPLOAD_DIRECTORY = "upload";
// 上传配置
private static final int MEMORY_THRESHOLD = 1024 * 1024 * 3; // 3MB
private static final int MAX_FILE_SIZE = 1024 * 1024 * 40; // 40MB
private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50; // 50MB
/**
* 上传数据及保存文件
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 检测是否为多媒体上传
if (!ServletFileUpload.isMultipartContent(request)) {
// 如果不是则停止
PrintWriter writer = response.getWriter();
writer.println("Error: 表单必须包含 enctype=multipart/form-data");
writer.flush();
return;
}
// 配置上传参数
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中
factory.setSizeThreshold(MEMORY_THRESHOLD);
// 设置临时存储目录
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置最大文件上传值
upload.setFileSizeMax(MAX_FILE_SIZE);
// 设置最大请求值 (包含文件和表单数据)
upload.setSizeMax(MAX_REQUEST_SIZE);
// 中文处理
upload.setHeaderEncoding("UTF-8");
// 构造临时路径来存储上传的文件
// 这个路径相对当前应用的目录
String uploadPath = getServletContext().getRealPath("/") + File.separator + UPLOAD_DIRECTORY;
// 如果目录不存在则创建
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) {
uploadDir.mkdir();
}
try {
// 解析请求的内容提取文件数据
@SuppressWarnings("unchecked")
List
if (formItems != null && formItems.size() > 0) {
// 迭代表单数据
for (FileItem item : formItems) {
// 处理不在表单中的字段
if (!item.isFormField()) {
String fileName = new File(item.getName()).getName();
String filePath = uploadPath + File.separator + fileName;
File storeFile = new File(filePath);
// 在控制台输出文件的上传路径
System.out.println(filePath);
// 保存文件到硬盘
item.write(storeFile);
request.setAttribute("message",
"文件上传成功!");
}
}
}
} catch (Exception ex) {
request.setAttribute("message",
"错误信息: " + ex.getMessage());
}
// 跳转到 message.jsp
getServletContext().getRequestDispatcher("/message.jsp").forward(
request, response);
}
}
pageEncoding="UTF-8"%>
"http://www.w3.org/TR/html4/loose.dtd">
${message}
编译和运行 Servlet
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">