JavaWeb的学习(上)
尚硅谷JavaWEB基础教程,哔哩哔哩链接:https://www.bilibili.com/video/BV1jW411u7PZ
一、JavaWeb应用概述
• 在Sun
的Java Servlet
规范中,对Java Web
应用作了这样定义:Java Web应用由一组Servlet、HTML页、类、以及其它可以被绑定的资源构成。它可以在各种供应商提供的实现Servlet规范的Servlet容器中运行。
• Java Web应用中可以包含如下内容:
– Servlet
– JSP
– 实用类
– 静态文档如HTML、图片等
– 描述Web应用的信息(web.xml
)
Web 程序结构
– 一个 web 应用程序是由一组 Servlet,HTML 页面,类,以及其它的资源组成的运行在 web 服务器上的完整的应用程序,以一种结构化的有层次的目录形式存在
– 组成 web 应用程序的这些文件要部署在相应的目录层次中,根目录代表整个 web 应用程序的根
– 通常将 web 应用程序的目录放在Tomcat
的 webapps
目录下,在 webapps
目录下的每一个子目录都是一个独立的 web 应用程序,子目录的名字就是 web 应用程序的名字,也就是 web 应用程序的根
。用户通过 web 应用程序的根
来访问 web 应用程序中的资源
Web 应用程序的目录解析
• 说明:
– WEB-INF
目录下的classes
和lib
目录都可以存放Java的类文件,在Servlet容器运行时,Web应用程序的类加载器将首先加载classes
目录下的,其次才是lib
目录下的类。如果这两个目录下存在同名的类,起作用的将是classes
目录下的类
–WEB-INF
是一个特殊的目录(所有字母都要大写)。这个目录并不属于Web应用程序可以访问的上下文路径的一部分,对客户端来说,这个目录是不可见的。但该目录下的内容对于Servlet
代码是可见的
配置任意目录下的Web应用1
• 在Web服务器中可以配置虚拟目录,而虚拟目录所对应的真实目录可以在任何路径下。
• 在Tomcat服务器中,主要在XML
配置文件中通过<Context>
元素的设置来完成的。一个元素就表示一个Web应用程序,运行在特定的虚拟主机中。
• <Context>
元素是<Host>
元素的子元素,可以在conf\server.xml
文件中设置Context
元素。
Context元素的常用属性
• 使用docBase
属性指定Web应用程序的真实路径。将属性reloadable
设置为true
,Tomcat在运行时会自动监测Servlet类的改动,如果发现有类被更新,Tomcat服务器将自动重新加载该Web应用程序。这样,在开发时,就不需要频繁重启Tomcat了
配置任意目录下的Web应用2
二、Servlet容器和Servlet
1.Servlet容器的概念
– Servlet容器为JavaWeb应用提供运行时环境,它负责管理Servlet和JSP的生命周期,以及管理它们的共享数据。
– Servlet容器也称为JavaWeb应用容器
,或者Servlet/JSP容器
。
Servlet容器响应客户请求的过程
Servlet 容器
目前最流行的Servlet容器软件包括:
– Tomcat
– Resin
– J2EE服务器(如Weblogic
)中也提供了内置的Servlet容器
Tomcat 简介
– Tomcat 是一个免费的开放源代码的 Servlet 容器,它是 Apache 软件基金会的一个*项目,由 Apache,Sun和其他一些公司及个人共同开发而成。由于有了 Sun 的参与与支持,最新的 Servlet 和 JSP 规范总是能在 Tomcat 中得到体现。
Tomcat 的目录结构
运行 Tomcat
– 1. 配置java_home
或 jre_home
– 2. 双击 bin
目录下的 startup.bat
文件,或cmd
窗口输入startup run
(在已配置环境变量的情况下)
– 3. 在地址栏中输入 http://localhost:8080/
当出现如下标识即为成功:
关闭 Tomcat & 配置 Tomcat 的端口号
• 1.双击 bin
目录下的shutdown.bat
文件关闭 Tomcat 服务器
• 2. 修改 Tomcat 默认的端口号:
– 打开 conf
目录下的 server.xml
文件
– 修改端口号
Tomcat 启动分析1
Tomcat 启动分析2
• 若想在任意目录下都能启动 Tomcat,则需设置 CATALINA_HOME
环境变量
• 直接执行 catalina.bat
时需要带上命令行参数,常用的参数是start,run 和 stop
Tomcat启动时乱码解决
Tomcat 的管理程序:manager
– Tomcat 提供了一个管理程序:manager
,用于管理部署到 Tomcat 服务器中的 web 应用程序
– 要访问 manager web 应用程序,需要添加具有管理员权限的账号,编辑 conf
目录下的 tomcat-users.xml
文件,添加 manager 角色,设置用户名和密码
2.Servlet 简介
• Java Servlet是和平台无关的服务器端组件
,它运行在Servlet容器中。Servlet容器负责Servlet和客户的通信以及调用Servlet的方法,
Servlet和客户的通信采用“请求/响应”的模式。
• Servlet可完成如下功能:
– 创建并返回基于客户请求的动态HTML页面。
– 创建可嵌入到现有HTML 页面中的部分HTML 页面(HTML 片段)。
– 与其它服务器资源(如数据库或基于Java的应用程序)进行通信。
ServletAPI
Servlet容器响应客户请求的过程
①Servlet引擎检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
②装载并创建该Servlet的一个实例对象:调用该 Servlet 的构造器
③调用Servlet实例对象的init()
方法。
④创建一个用于封装请求的ServletRequest
对象和一个代表响应消息的ServletResponse
对象,然后调用Servlet的service()
方法并将请求和响应对象作为参数传递进去。
⑤WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()
方法。
Servlet的注册与运行
• Servlet程序必须通过Servlet容器来启动运行并且储存目录有特殊要求,通常需要存储在<WEB应用程序目录>\WEB-INF\classes\目录中
。
• Servlet程序必须在WEB应用程序的web.xml
文件中进行注册和映射其访问路径,才可以被Servlet引擎加载和被外界访问。
• 一个<servlet>
元素用于注册一个Servlet,它包含有两个主要的子元素:<servlet-name>
和<servlet-class>
,分别用于设置Servlet的注册名称
和Servlet的完整类名
。
• 一个<servlet-mapping>
元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name>
和<url-pattern>
,分别用于指定Servlet的注册名称
和Servlet的对外访问路径
。
Servlet映射的细节
• 同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>
元素的<servlet-name>
子元素的设置值可以是同一个Servlet的注册名。
• 在Servlet映射到的URL中也可以使用 *
通配符,但是只能有两种固定的格式:一种格式是.扩展名
,另一种格式是以正斜杠(/
)开头并以/*
结尾。
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AnyName</servlet-name>
<url-pattern>/action/*</url-pattern>
</servlet-mapping>
ServletConfig 接口
• Servlet在有些情况下可能需要访问Servlet容器或借助Servlet容器访问外部的资源,所以,Serlvet引擎需要将表示Servlet容器的对象传递给Servlet。另外,在web.xml
文件中为某个Servlet设置的友好名称
和初始化参数
等信息也需要传递给该Servlet
• Servlet引擎将代表Servlet容器的对象(ServletContext)和Servlet的配置参数信息一并封装到一个称为ServletConfig
的对象中,并在初始化Servlet实例对象时传递给该Servlet。ServletConfig接口
则用于定义ServletConfig对象
需要对外提供的方法,以便在Servlet程序中可以调用这些方法来获取有关信息。
• Servlet引擎调用Servlet的实例对象的init(ServletConfig config)
方法将ServletConfig对象
传递给Servlet。Servlet.getServletConfig()
方法必须返回init(ServletConfig config)
方法传递进来的这个ServletConfig对象的引用
。
ServletConfig接口的方法
- getInitParameterNames
- getInitParameter
- getServletName
- getServletContext
ServletContext接口(application 对象或Web应用程序对象)
• Servlet引擎为每个WEB应用程序都创建一个对应的ServletContext
对象,ServletContext
对象被包含在ServletConfig
对象中,调用ServletConfig.getServletContext
方法可以返回ServletContext
对象的引用。
• **由于一个WEB应用程序中的所有Servlet都共享同一个ServletContext对象,**所以,ServletContext
对象被称之为 application 对象(Web应用程序对象)
。
• 功能:
- 获取WEB应用程序的初始化参数
- 记录日志
- application域范围的属性
- 访问资源文件
- 获取虚拟路径所映射的本地路径
- WEB应用程序之间的访问
- ServletContext的其他方法
获取WEB应用程序的初始化参数
• 为WEB应用程序设置初始化参数的好处在于不需要修改Servlet源程序,就可以改变一些参数信息
。
• ServletContext.getInitParameterNames
方法用于返回一个包含WEB应用程序的所有初始化参数名称的Enumeration
集合对象,ServletContext.getInitParameter
方法用于返回某个指定名称的初始化参数值。
• 在web.xml
文件的根元素<web-app>
中增加<context-param>
子元素,如下所示:
<context-param>
<param-name>companyName</param-name>
<param-value>lampbrother</param-value>
</context-param>
获取虚拟路径所映射的本地路径
• getRealPath(String path)
方法: 用于返回某个虚拟路径所映射的本地文件系统路径
Servlet登录验证示例
编写继承httpServlet
的自定义servlet类UserServlet
,重写doGet
或者doPost
方法。
package com.gxuwz.attends.servlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import javax.servlet.ServletException;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 定义用户登录验证Servlet
* @author x240
*
*/
public class UserServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("C");
String userid=req.getParameter("userid");
String pwd=req.getParameter("pwd");
if("admin".equals(userid)&&"123".equals(pwd)){
resp.sendRedirect(req.getContextPath()+"/index.jsp");
}else{
resp.sendRedirect(req.getContextPath()+"/login.jsp");
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("B");
super.service(req, resp);
}
@Override
public void init() throws ServletException {
System.out.println("A");
super.init();
}
常用的发起请求的方式:get请求和post请求
1.get请求的发起方式
通常采用超链接标签发起一个get请求,语法格式如下:
<a href="api/app/helloworldServlet">发起get请求</a>
2.post请求的发起方式
通常采用表单标签,显式设置表单标签中method的值为post来发起一个post请求,注意表单标签默认的请求方式为get,语法格式是:
<form action="api/app/helloworldServlet" method="post">
<!--表单标签之间可以使用其他的html标签(包括布局标签或者表单元素标签。表单元素标签用于发送请求参数)-->
<input type="text" name="stuNo" value="20180101003"/>
</form>
重写doGet
或者doPost
方法的目的。
具体业务逻辑的处理,重写doGet或者doPost方法中一般的编码步骤为:
(1)接收参数
(2)具体业务逻辑的实现(这一部分通常由实现逻辑处理的java程序片段构成)
(3)跳转页面。
//1:接收参数,注意不是使用jsp内置对象request来接收参数,
//用doGet||doPost方法的方法参数 HttpServletRquest类型的请求对象名称[x]。
String userid=x.getParameter("userid");//用户名
String password=x.getParameter("pwd"); //密码
//2:登录验证处理
boolean flag="admin".equals(userid)&&"123".equals(password);
if(flag){
//3:跳转(重定向)
resp.sendRedirect("index.jsp");
}else{
//3:跳转(转发)
//获得指定路径的转发对象
RequestDispatcher rd=x.getRequestDispatcher("login.jsp");
//调用转发对象的xx方法跳转
rd.forward(x,resp);
}
配置Servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>attends_javabean_56</display-name>
<!-- 配置servlet名称,等价于对象变量 -->
<servlet>
<!-- 这里的名字取名随意,建议与类名一致 -->
<servlet-name>userServlet</servlet-name>
<!--这里要写servlet的具体路径 -->
<servlet-class>com.gxuwz.attends.servlet.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<!--这里的name要设置与上面的name一致-->
<servlet-name>userServlet</servlet-name>
<!--映射的URL路径元素,是一个虚拟的请求路径元素,与web目录下的子文件夹没有任何关系
/表示以及根目录,可以写多级表示具体的作用,取的名字随意-->
<url-pattern>/system/userServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>
注意:
在web.xml配置userServlet,由web容器加载并实例化对应的对象,该对象是单例的。
web容器实例化userServlet对象的过程,等价于UserServlet userServlet=new UserServlet()。
三、HTTP协议简介
• WEB浏览器与WEB服务器之间的一问一答的交互过程必须遵循一定的规则,这个规则就是HTTP协议
。
• HTTP是 hypertext transfer protocol(超文本传输协议)
的简写,它是 TCP/IP 协议集
中的一个应用层协议,用于定义WEB浏览器与WEB服务器之间交换数据的过程以及数据本身的格式。
• HTTP协议的版本 HTTP/1.0、HTTP/1.1、HTTP-NG
1.HTTP 的会话方式
• 四个步骤:
– 浏览器与WEB服务器的连接过程是短暂的,每次连接只处理一个请求和响应。对每一个页面的访问,浏览器与WEB服务器都要建立一次单独的连接。
– 浏览器到WEB服务器之间的所有通讯都是完全独立分开的请求和响应对。
2.浏览器访问多图网页的过程
3.HTTP请求消息
请求消息的结构:
一个请求行、若干消息头、以及实体内容,其中的一些消息头和实体内容都是可选的,消息头和实体内容之间要用空行隔开。
4.HTTP响应消息
响应消息的结构:
一个状态行、若干消息头、以及实体内容 ,其中的一些消息头和实体内容都是可选的,消息头和实体内容之间要用空行隔开。
5.HTTP消息—>其他细节
• 响应消息的实体内容就是网页文件的内容,也就是在浏览器中使用查看源文件
的方式所看到的内容。
• 一个使用GET
方式的请求消息中不能包含实体内容
,只有使用POST、PUT和DELETE
方式的请求消息中才可以包含实体内容。
使用GET和POST方式传递参数
• 在URL
地址后面可以附加一些参数
举例:http://www.it315.org/servlet/ParamsServlet?param1=abc¶m2=xyz
• GET方式
举例:GET /servlet/ParamsServlet?param1=abc¶m2=xyz HTTP/1.1
特点:传送的数据量是有限制的,一般限制在1KB以下。
• POST方式
举例:
POST /servlet/ParamsServlet HTTP/1.1
Host:
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
//空一行
param1=abc¶m2=xyz
特点:传送的数据量要比GET方式传送的数据量大得多 。
使用GET方式传递参数
• 在浏览器地址栏中输入某个URL地址或单击网页上的一个超链接时,浏览器发出的HTTP请求消息的请求方式为GET
。
• 如果网页中的<form>
表单元素的method
属性被设置为了GET
,浏览器提交这个FORM表单时生成的HTTP请求消息的请求方式也为GET
。
• 使用GET
请求方式给WEB服务器传递参数的格式:
http://www.lampbrother.net/counter.jsp?name=lc&password=123
• 使用GET
方式传送的数据量一般限制在1KB
以下。
使用POST方式传递参数
• POST请求方式主要用于向WEB服务器端程序提交FORM表单中的数据。
• POST方式将各个表单字段元素及其数据作为HTTP消息的实体内容
发送给WEB服务器,传送的数据量要比使用GET方式传送的数据量大得多。
//POST请求消息的格式:
POST /counter.jsp HTTP/1.1
referer: http://localhost:8080/Register.html
content-type: application/x-www-form-urlencoded
host: localhost:8080
content-length: 43
//空一行
name=zhangsan&password=123
6.HttpServletRequest 简介
• Servlet API 中定义的 ServletRequest
接口类用于封装请求消息。
• HttpServletRequest
是专用于HTTP协议的ServletRequest
子接口,它用于封装 HTTP
请求消息。
• 在 service()
方法内部调用 HttpServletRequest
对象的各种方法来获取请求消息。
获取请求行的相关信息
- HTTP请求消息的请求行包括请求方式、资源路径和HTTP协议版本:
GET /lampbrother/servlet/RequestURI?param1=a¶m2=b HTTP/1.1
-
getMethod
:返回HTTP请求消息中的请求方式。 -
getRequestURI
:返回请求行中的资源名部分。 -
getQueryString
:返回请求行中的参数部分。 -
getProtocol
:返回请求行中的协议名和版本。 -
getContextPath
:返回请求资源所属于的WEB应用程序的路径。 -
getPathInfo
:返回请求URL中的额外路径信息。额外路径信息是请求URL中的位于Servlet的路径之后和查询参数之前的内容,它以/
开头。 -
getPathTranslated
:返回URL中的额外路径信息所对应的资源的真实路径。 -
getServletPath
方法:Servlet的名称或Servlet所映射的路径。
获取网络连接信息
-
getRemoteAddr
方法返回发出请求的客户机的IP地址,其格式为192.168.0.3
这种形式的字符文本。 -
getRemoteHost
方法返回发出请求的客户机的完整主机名,即pc1.atguigu.com
这种格式。 -
getRemotePort
方法返回发出请求的客户机所使用的网络接口的端口号。 -
getLocalAddr
方法返回WEB服务器上接收当前请求的网络接口的IP地址。 -
getLocalName
方法返回WEB服务器上接收当前请求的网络接口的IP地址所对应的主机名。 -
getLocalPort
方法返回WEB服务器上接收当前请求的网络接口的端口号。 -
getServerName
方法返回当前请求所指向的主机名。 -
getServerPort
方法返回当前请求所连接的服务器端口号。 -
getScheme
方法返回请求的协议名,例如http、https或ftp
。 -
getRequestURL
方法返回客户端发出请求时的完整URL。
获取请求头信息
-
getHeader方法
-
getHeaders方法
-
getHeaderNames方法
-
getIntHeader方法
-
getDateHeader方法
-
getContentType方法
-
getContentLength方法
-
getCharacterEncoding方法
获取请求参数
- getParameter方法
- getParameterValues方法
- getParameterNames方法
- getParameterMap方法
获取请求参数实例
Enumeration paramNames = request.getParameterNames();
while(paramNames.hasMoreElements())
{
String paramName = (String)paramNames.nextElement();
out.print(paramName + " : " + request.getParameter(paramName) + "<br>");
<%-- 如果要考虑同一个请求头名可能出现多次,那么应该用下面的代码段代替上面一行程序代码
String [] paramValues = request.getParameterValues(paramName);
--%>
<%--良好的编程习惯,在使用对象和数组之前先判断其是否为null--%>
if(paramValues != null)
{
for(int i=0;i<paramValues.length;i++)
{
out.print(paramName + " : " + (String)paramValues[i] + "<br>");
}
}
}
请求域属性
• 存储在ServletRequest
对象中的对象称之为请求域属性,属于同一个请求的多个处理模块之间可以通过请求域属性来传递对象数据。
与请求域属性相关的方法:
-
setAttribute
方法 -
getAttribute
方法 -
removeAttribute
方法 -
getAttributeNames
方法
7.HttpServletResponse简介
• Servlet API中定义的ServletResponse
接口类用于创建响应消息。
• HttpServletResponse
是专用于HTTP协议的ServletResponse
子接口,它用于封装HTTP响应消息。
请求重定向与请求转发
• RequestDispatcher
接口
• 用forward
方法实现请求转发
• 请求转发的运行流程
• 用sendRedirect
方法实现请求重定向
• 请求重定向的运行流程
• 请求重定向与请求转发的比较
RequestDispatcher接口
• RequestDispatcher
实例对象是由Servlet引擎创建的,它用于包装一个要被其他资源调用的资源(例如,Servlet、HTML文件、JSP文件
等),并可以通过其中的方法将客户端的请求转发给所包装的资源。
• RequestDispatche
r接口中定义了两个方法:forward
方法和include
方法。
• forward
和include
方法接收的两个参数必须是传递给当前Servlet
的service
方法的那两个ServletRequest
和ServletResponse
对象,或者是对它们进行了包装的ServletRequestWrapper
或ServletResponseWrapper
对象。
获取RequestDispatcher对象的方法:
- ServletContext.getRequestDispatcher (参数只能是以“/”开头的路径)
- ServletContext.getNamedDispatcher
- ServletRequest.getRequestDispatcher (参数可以是不以“/”开头的路径)
用sendRedirect方法实现请求重定向
• sendRedirect
方法不仅可以重定向到当前应用程序中的其他资源,它还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。
• 传递给sendRedirect
方法的相对URL以/
开头,则是相对于整个WEB站点的根目录,而不是相对于当前WEB应用程序的根目录。
请求转发与请求重定向的比较
-
RequestDispatcher.forward
方法只能将请求转发
给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect
方法还可以重定向
到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL
重定向到其他站点的资源。 -
创建
RequestDispatcher
对象时指定的相对URL以/
开头,它是相对于当前WEB应用程序的根目录。传递给HttpServletResponse.sendRedirect
方法的相对URL以/
开头,它是相对于整个WEB站点的根目录; -
调用
RequestDispatcher.forward
方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。调用HttpServletResponse.sendRedirect
方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL; -
RequestDispatcher.forward
方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。HttpServletResponse.sendRedirect
方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求; -
RequestDispatcher.forward
方法的调用者与被调用者之间共享相同的request
对象和response
对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect
方法调用者与被调用者使用各自的request
对象和response
对象,它们属于两个独立的访问请求和响应过程。
application域范围的属性
• application 对象(ServletContext对象)
内部有一个哈希表集合对象,存储进application
对象内的哈希表集合对象中的每对关键字/值被称为application
对象的属性。
• 存储在application
对象中的属性也被称之为application
域范围的属性,application
域范围的属性可以被当作该WEB应用程序范围内的全局变量使用。
• ServletContext
接口中定义了4个分别用于增加、删除、访问application域范围的属性的方法:
- getAttributeNames方法
- getAttribute方法
- removeAttribute方法
- setAttribute方法
四、JSP
1.JSP起源
• 在很多动态网页中,绝大部分内容都是固定不变的,只有局部内容
需要动态产生和改变。
• 如果使用Servlet程序来输出只有局部内容需要动态改变的网页,其中所有的静态内容也需要程序员用Java程序代码产生,整个Servlet程序的代码将非常臃肿,编写和维护都将非常困难。
• 对大量静态内容的美工设计和相关HTML语句的编写,并不是程序员所要做的工作,程序员对此也不一定在行。网页美工设计和制作人员不懂Java编程,更是无法来完成这样的工作。
• 为了弥补 Servlet 的缺陷,SUN
公司在Servlet的基础上推出了JSP(Java Server Pages)
技术作为解决方案。
• JSP是简化Servlet
编写的一种技术,它将Java代码和HTML语句混合在同一个文件中编写,只对网页中的要动态产生的内容采用Java代码来编写,而对固定不变的静态内容采用普通静态HTML页面的方式编写。
2.建立对JSP的直观认识
- JSP页面是由HTML语句和嵌套在其中的Java代码组成的一个普通文本文件,JSP 页面的文件扩展名必须为
.jsp
。 - 在JSP页面中编写的Java代码需要嵌套在
<%
和%>
中,嵌套在<%
和%>
之间的Java代码被称之为脚本片段(Scriptlets),没有嵌套在<%
和%>
之间的内容被称之为JSP的模版元素。 - JSP中的Java代码可以使用
out.println
语句将其他Java程序代码产生的结果字符串输出给客户端,也可以使用System.out.println
语句将它们打印到命令行窗口。 - JSP文件就像普通的HTML文件一样,它们可以放置在WEB应用程序中的除了WEB-INF及其子目录外的其他任何目录中,JSP页面的访问路径与普通HTML页面的访问路径形式也完全一样。
- 在JSP页面中也可以使用一种称之为JSP表达式的元素,只需将要输出的变量或表达式直接封装在
<%=
和%>
之中,就可以向客户端输出这个变量或表达式的运算结果。在JSP表达式中嵌套的变量或表达式后面不能有分号
。
3.JSP的运行原理
• WEB容器(Servlet引擎)接收到以.jsp
为扩展名的URL的访问请求时,它将把该访问请求交给JSP引擎去处理。
• 每个JSP 页面在第一次被访问时,JSP引擎将它翻译成一个Servlet源程序
,接着再把这个Servlet源程序编译成Servlet的class类文件
,然后再由**WEB容器(Servlet引擎)**像调用普通Servlet程序一样的方式来装载和解释执行这个由JSP页面翻译成的Servlet程序。
• JSP规范也没有明确要求JSP中的脚本程序代码必须采用Java语言,JSP中的脚本程序代码可以采用Java语言之外的其他脚本语言来编写
,但是,JSP页面最终必须转换成Java Servlet程序。
• 可以在WEB应用程序正式发布之前,将其中的所有JSP页面预先编译成Servlet程序。
4.注册与配置JSP页面的访问路径
<servlet>
<servlet-name>SimpleJspServlet</servlet-name>
<jsp-file>/jsp/simple.jsp</jsp-file>
<load-on-startup>1</load-on-startup >
</servlet>
……
<servlet-mapping>
<servlet-name>SimpleJspServlet</servlet-name>
<url-pattern>/xxx/yyy.html</url-pattern>
</servlet-mapping>
5.JSP与Servlet的应用比较
- JSP是一种以产生网页显示内容为中心的WEB开发技术,它可以直接使用模版元素来产生网页文档的内容。
- JSP页面的源文件要比Servlet源文件简单,并且JSP页面的开发过程要比Servlet的开发过程简单得多。
- JSP引擎可以对JSP页面的修改进行检测,并自动重新翻译和编译修改过的JSP文件。
-
JSP技术是建立在Servlet技术基础之上的
,所有的JSP页面最终都要被转换成Servlet来运行。 - 在大型WEB应用程序的开发中,Servlet与JSP经常要混合使用,各司其职,Servlet通常用作控制组件,并处理一些复杂的后台业务,JSP则作为显示组件。
- 一次响应过程可以划分成几个功能模块来协同完成,
首先
由Servlet
完成流程控制和业务处理,并将结果数据存储在request
或session
域中,然后
将请求转发(forward
)到JSP页面,再由
JSP页面从request
或session
域中取出结果数据并完成响应内容的输出。通过这种方式实现业务逻辑与显示内容的分离,从而将应用程序开发者和网页作者的工作分离。
6.JSP基本语法
JSP模版元素
• JSP页面中的静态HTML内容称之为JSP模版元素
,在静态的HTML内容之中可以嵌套JSP的其他各种元素来产生动态内容和执行业务逻辑。
• JSP模版元素定义了网页的基本骨架,即定义了页面的结构和外观。
JSP表达式<%= %>
• JSP表达式(expression)提供了将一个java变量或表达式的计算结果输出到客户端的简化方式,它将要输出的变量或表达式直接封装在<%=
和%>
之中。
举例:Current time: <%= new java.util.Date() %>
• JSP表达式中的变量或表达式的计算结果将被转换成一个字符串,然后被插入进整个JSP页面输出结果的相应位置处。
• JSP表达式中的变量或表达式后面不能有分号(;),JSP表达式被翻译成Servlet程序中的一条out.print(…)
语句。
JSP脚本片断 (1)<% %>
• JSP脚本片断(scriptlet)是指嵌套在<%
和 %>
之中的一条或多条Java程序代码。
• 在JSP脚本片断
中,可以定义变量、执行基本的程序运算、调用其他Java类、访问数据库、访问文件系统等普通Java程序所能实现的功能。
• 在JSP脚本片断可以直接使用JSP提供的隐式对象
来完成WEB应用程序特有的功能。
• JSP脚本片断中的Java代码将被原封不动地搬移进由JSP页面所翻译成的Servlet的jspService方法中,所以,JSP脚本片断之中只能是符合Java语法要求的程序代码,除此之外的任何文本、HTML标记、其他JSP元素都必须在脚本片断之外编写。
• JSP脚本片断中的Java代码必须严格遵循Java语法,例如,每条命令执行语句后面必须用分号(;
)结束。
• 在一个JSP页面中可以有多个脚本片断(每个脚本片断代码嵌套在各自独立的一对<%
和 %>
之间),在两个或多个脚本片断之间可以嵌入文本、HTML标记和其他JSP元素。
JSP脚本片断 (2)<% %>
JSP脚本片断 (3)<% %>
• **单个脚本片断中的Java语句可以是不完整的,但是,多个脚本片断组合后的结果必须是完整的Java语句,**例如,涉及条件和循环处理时,多个脚本片断及其他元素组合的结果必须能形成完整的条件和循环控制语句。
• 由于脚本片断中的Java代码将被原封不动地搬移进由JSP页面所翻译成的Servlet的jspService
方法中,脚本片断之外的任何文本、HTML标记以及其他JSP元素也都会被转换成相应的Java程序代码插入进jspService
方法中,且脚本片断和其他JSP元素的插入位置与它们在JSP页面中的原始位置相对应。
• 在脚本片断中可以使用条件、循环、选择等流程控制语句来创建其周围的其他元素的执行逻辑,因此,在编写JSP页面时应考虑各个元素之间的先后顺序和相互关系,特别是将循环、条件判断等语句分布在若干个脚本片断中编写时对其邻近的其他JSP元素产生的影响。
JSP声明<%! %>
• JSP声明将Java代码封装在<%!
和%>
之中,它里面的代码将被插入进Servlet的jspService方法的外面,所以,JSP声明可用于定义JSP页面转换成的Servlet程序的静态代码块、成员变量和方法
。
• 多个静态代码块、变量和函数可以定义在一个JSP声明中,也可以分别单独定义在多个JSP声明中。
• JSP隐式对象的作用范围仅限于Servlet的_jspService方法,所以在JSP声明中不能使用这些隐式对象。
JSP声明实例
<%!
static { System.out.println("loading Servlet!"); }
private int globalVar = 0;
public void jspInit(){
System.out.println("initializing jsp!");
}
%>
<%!
public void jspDestroy(){
System.out.println("destroying jsp!");
}
%>
<%
int localVar = 0;
%>
globalVar:<%= ++globalVar %><br>
localVar:<%= ++localVar %>
JSP注释 <%-- 注释信息 --%>
• JSP注释的格式:
<%-- 注释信息 --%>
• JSP引擎在将JSP页面翻译成Servlet程序时,忽略
JSP页面中被注释的内容。
7.如何查找JSP页面中的错误
• JSP页面中的JSP语法格式有问题,导致其不能被翻译成Servlet源文件,JSP引擎将提示这类错误发生在JSP页面中的位置(行和列)
以及相关信息。
• JSP页面中的JSP语法格式没有问题,但被翻译成的Servlet源文件中出现了Java语法问题,导致JSP页面翻译成的Servlet源文件不能通过编译,JSP引擎也将提示这类错误发生在JSP页面中的位置(行和列)
以及相关信息。
• JSP页面**翻译成的Servlet程序在运行时出现异常,**这与普通Java程序的运行时错误完全一样,Java虚拟机将提示错误发生在Servlet源文件中的位置(行和列)
以及相关信息。
8.out隐式对象
• 在JSP页面中应使用out隐式对象来向客户端发送文本形式的实体内容。
• out对象
是通过调用pageContext
对象的getOut
方法返回的,其作用和用法与ServletResponse.getWriter
方法返回的PrintWriter
对象非常相似。
• JSP页面中的out隐式对象
的类型为JspWriter
,JspWriter
相当于一种带缓存功能的PrintWriter
,设置JSP页面的page
指令的buffer
属性可以调整它的缓存大小,甚至关闭它的缓存。
• JSP页面中的out隐式对象相当于插入到ServletResponse.getWriter
方法返回的PrintWriter
对象前面的缓冲包装类对象。
• 只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter
方法,并通过该方法返回的PrintWriter
对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
设置page
指令的buffer
属性关闭了out
对象的缓存功能
写入到out对象中的内容充满了out对象的缓冲区
整个JSP页面结束
out隐式对象的工作原理图
9.pageContext对象
pageContext对象简介
• pageContext
对象封装了当前JSP页面的运行信息,它提供了返回JSP页面的其他隐式对象的方法。
• PageContext
类中定义了一个setAttribute
方法来将对象存储进pageContext
对象内部的一个HashMap
对象中,同时也定义了一个getAttribute
方法来检索存储在该HashMap
对象中的对象。
• PageContext
类除了可以存储和检索自身中的属性对象外,还定义了可以存储和检索其他域范围内的属性对象的方法。
获得其他隐式对象
• getException
方法返回exception隐式对象
• getPage
方法返回page隐式对象
• getRequest
方法返回request隐式对象
• getResponse
方法返回response隐式对象
• getServletConfig
方法返回config隐式对象
• getServletContext
方法返回application隐式对象
• getSession
方法返回session隐式对象
• getOut
方法返回out隐式对象
引入和跳转到其他资源
• PageContext
类中定义了一个forward
方法和两个include
方法来分别简化和替代RequestDispatcher.forward
方法和RequestDispatcher.include
方法的调用:
• 传递给这些方法的资源路径都只能是相对路径,如果路径以/
开头,表示相对于当前WEB应用程序的根目录,否则,表示相对于当前JSP所映射到的访问路径。
访问各个域范围中的属性
• 在application、session、request、pageContext
对象中都可以调用setAttribute
方法和getAttribute
方法来设置和检索各自域范围内的属性。
• 存储在application
对象中的属性可以被同一个WEB应用程序中的所有Servlet和JSP页面访问
。
• 存储在session对象中的属性可以被属于同一个会话的所有Servlet和JSP页面访问。
• 存储在request
对象中的属性可以被属于同一个请求的所有Servlet和JSP页面访问,例如使用PageContext.forward
和PageContext.include
方法连接起来的多个Servlet和JSP页面。
• 存储在pageContext
对象中的属性仅可以
被当前JSP页面的当前响应过程中调用的各个组件访问,例如,正在响应当前请求的JSP页面和它调用的各个自定义标签类。
• PageContext
类中还提供了对各个域范围的属性进行统一管理的方法,以简化对各个域范围内的属性的访问。
• setAttribute方法
public void setAttribute(java.lang.String name,java.lang.Object value)
public void setAttribute(java.lang.String name, java.lang.Object value,int scope)
• 常量
PageContext.APPLICATION_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.PAGE_SCOPE
• getAttribute方法
public java.lang.Object getAttribute(java.lang.String name)
public java.lang.Object getAttribute(java.lang.String name,int scope)
• removeAttribute方法
public void removeAttribute(java.lang.String name)
public void removeAttribute(java.lang.String name,int scope)
• getAttributeNamesInScope方法
• findAttribute方法
10.JSP指令<%@ %>
1.JSP指令简介
2.page指令
3.include指令
11.JSP标签概念
• JSP还提供了一种称之为Action
的元素,在JSP页面中使用Action元素可以完成各种通用的JSP页面功能,也可以实现一些处理复杂业务逻辑的专用功能。
• Action元素采用XML
元素的语法格式,即每个Action元素在JSP页面中都以XML
标签的形式出现。
• JSP规范中定义了一些标准的Action元素,这些元素的标签名都以jsp作为前缀,并且全部采用小写,例如,<jsp:include>
、<jsp:forward>
等等。
12.JSP标签内容
<jsp:include>
标签
<jsp:include>
标签与include指令的比较
• <jsp:include>标签是在当前JSP页面的执行期间插入被引入资源的输出内容,
当前JSP页面与被动态引入的资源是两个彼此独立的执行实体,
被动态引入的资源必须是一个能独立被WEB容器调用和执行的资源。
include指令只能引入遵循JSP格式的文件,被引入文件与当前JSP文件共同合被翻译成一个Servlet的源文件。
• 使用<jsp:include>标签和include指令都可以把一个页面的内容分成多个组件来生成,
开发者不必再把页眉和页脚部分的相同HTML代码复制到每个JSP文件中,从而可以更轻松地完成维护工作,
但是都应注意最终的输出结果内容应遵循HTML语法结构,
例如,如果当前页面产生了<html>、</html>、<body>、</body>等标记,
那么在被引入文件中就不能再输出<html>、</html>、<body>、</body>等标记。
• <jsp:include>标签对JSP引擎翻译JSP页面的过程不起作用,它是在JSP页面的执行期间才被调用,
因此不会影响两个页面的编译。由于include指令是在JSP引擎翻译JSP页面的过程中被解释处理的,
所以它对JSP引擎翻译JSP页面的过程起作用,如果多个JSP页面中都要用到一些相同的声明,
那么就可以把这些声明语句放在一个单独的文件中编写,然后在每个JSP页面中使用include指令将那个文件包含进来。
<jsp:forward>
标签
<jsp:param>
标签
13.JSP中文乱码
五、MVC 设计模式
1.组件开发
JavaEE 开发中常见的组件
2.JavaEE 开发流程
3.MVC处理过程
4.MVC的概念
• MVC是Model-View-Controller
的简称,即模型-视图-控制器
。
• MVC是一种设计模式,它把应用程序分成三个核心模块:模型、视图、控制器
,它们各自处理自己的任务。
模型(model)
• 模型是应用程序的主体部分,模型表示业务数据和业务逻辑。
• 一个模型能为多个视图提供数据。
• 由于应用于模型的代码只需写一次就可以被多个视图重用,所以提高了代码的可重用性。
视图
• 视图是用户看到并与之交互的界面,作用如下:
– 视图向用户显示相关的数据。
– 接受用户的输入。
– 不进行任何实际的业务处理。
控制器
• 控制器接受用户的输入并调用模型和视图
去完成用户的需求。
• 控制器接收请求并决定调用哪个模型组件
去处理请求,然后决定调用哪个视图来显示模型处理返回的数据。
六、会话与状态管理(HttpSession)
提出问题
• **HTTP协议是一种无状态的协议,**WEB服务器本身不能识别出哪些请求是同一个浏览器发出的 ,浏览器的每一次请求都是完全孤立的
• 即使HTTP1.1
支持持续连接,但当用户有一段时间没有提交请求,连接也会关闭。
• 怎么才能实现网上商店中的购物车呢:某个用户从网站的登录页面登入后,再进入购物页面购物时,负责处理购物请求的服务器程序必须知道处理上一次请求的程序所得到的用户信息。
• 作为 web 服务器,必须能够采用一种机制来唯一地标识一个用户,同时记录该用户的状态
会话和会话状态
• WEB应用中的会话
是指一个客户端浏览器与WEB服务器之间连续发生的一系列请求和响应过程。
• WEB应用的会话状态
是指WEB服务器与浏览器在会话过程中产生的状态信息,借助会话状态,WEB服务器能够把属于同一会话中的一系列的请求和响应过程关联起来。
1.如何实现有状态的会话
• WEB服务器端程序要能从大量的请求消息中区分出哪些请求消息属于同一个会话,即能识别出来自同一个浏览器的访问请求,这需要浏览器对其发出的每个请求消息都进行标识:属于同一个会话中的请求消息都附带同样的标识号,而属于不同会话的请求消息总是附带不同的标识号,这个标识号就称之为会话ID
(SessionID)。
• 在 Servlet 规范中,常用以下两种机制完成会话跟踪
– Cookie
– Session
Cookie机制
• cookie机制采用的是在客户端保持 HTTP 状态信息的方案
• Cookie是在浏览器访问WEB服务器的某个资源时,由WEB服务器在HTTP响应消息头
中附带传送给浏览器的一个小文本文件。
• 一旦WEB浏览器保存了某个Cookie,那么它在以后每次访问该WEB服务器时,都会在HTTP请求头中将这个Cookie回传给WEB服务器。
• 底层的实现原理: WEB服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将Cookie信息发送给浏览器,浏览器则通过在HTTP请求消息中增加Cookie请求头字段
将Cookie回传给WEB服务器。
• 一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME
)和设置值(VALUE
)。
• 一个WEB站点可以给一个WEB浏览器发送多个
Cookie,一个WEB浏览器也可以存储多个
WEB站点提供的Cookie。
• 浏览器一般只允许存放300
个Cookie,每个站点最多存放20
个Cookie,每个Cookie的大小限制为4KB
。
Cookie的传送过程示意图
在Servlet程序中使用Cookie
• Servlet API
中提供了一个javax.servlet.http.Cookie
类来封装Cookie
信息,它包含有生成Cookie信息
和提取Cookie信息
的各个属性的方法。
• Cookie类的方法:
构造方法: public Cookie(String name,String value)
getName方法
setValue与getValue方法
setMaxAge与getMaxAge方法
setPath与getPath方法
• HttpServletResponse
接口中定义了一个addCookie
方法,它用于在发送给浏览器的HTTP响应消息中增加一个Set-Cookie
响应头字段。
• HttpServletRequest
接口中定义了一个getCookies
方法,它用于从HTTP请求消息的Cookie请求头字段中读取所有
的Cookie项。
Cookie的发送
• 1.创建Cookie
对象
• 2.设置最大时效
• 3.将Cookie
放入到HTTP响应报头
– 如果创建了一个cookie
,并将他发送到浏览器,默认情况下它是一个会话级别的cookie
; 存储在浏览器的内存
中,用户退出浏览器之后被删除
。若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge
,并给出一个以秒
为单位的时间。将最大时效设为0
则是命令浏览器删除该cookie
。
– 发送cookie
需要使用HttpServletResponse
的addCookie
方法,将cookie
插入到一个 Set-Cookie
HTTP响应报头中。由于这个方法并不修改任何之前指定的Set-Cookie
报头,而是创建新的报头,因此将这个方法称为是addCookie
,而非setCookie
。
会话cookie和持久cookie的区别
• 如果不设置过期时间,则表示这个cookie
生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie
就消失了。这种生命期为浏览器会话期的cookie
被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。
• 如果设置了过期时间,浏览器就会把cookie
保存到硬盘上,关闭后再次打开浏览器,这些cookie
依然有效直到超过设定的过期时间。
• 存储在硬盘上的cookie
可以在不同的浏览器进程间共享,比如两个IE
窗口。而对于保存在内存的cookie
,不同的浏览器有不同的处理方式。
Cookie的读取
• 1.调用request.getCookies
要获取浏览器发送来的cookie
,需要调用HttpServletRequest
的getCookies
方法,这个调用返回Cookie
对象的数组,对应由HTTP
请求中Cookie
报头输入的值。
• 2.对数组进行循环,调用每个cookie
的getName
方法,直到找到感兴趣的cookie
为止
自动登录
不需要填写用户名和密码等信息,可以自动登录到系统
显示最近浏览的 5 本书的 title
跟踪用户上次访问站点的时间
•功能:
帮助网站实现提示客户端计算机上次访问网站的时间
•实现原理:
将每一个会话作为一次访问过程,将每次会话的开始时间作为每次访问网站的时间,然后将这个时间以Cookie
的形式存储到客户端的计算机中,客户端进行下次访问时通过该Cookie
回传上次访问站点的时间值。
为了让Cookie
信息在客户端浏览器或计算机关闭后仍然保持存在,Cookie
的保存时间被设置为了一年。
2.session在不同环境下的不同含义
• session
,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话是从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session
。
• session
在Web开发环境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器端之间保持状态的解决方案。有时候Session
也用来指这种解决方案的存储结构。
3.Session机制
• session
机制采用的是在服务器端保持 HTTP 状态信息的方案 。
• 服务器使用一种类似于散列表的结构
(也可能就是使用散列表)来保存信息。
• 当程序需要为某个客户端的请求创建一个session
时,服务器首先检查这个客户端的请求里是否包含了一个session标识(即sessionId)
,如果已经包含一个sessionId
则说明以前已经为此客户创建过session
,服务器就按照session id
把这个session
检索出来使用(如果检索不到,可能会新建一个,这种情况可能出现在服务端已经删除了该用户对应的session
对象,但用户人为地在请求的URL后面附加上一个JSESSION
的参数)。
• 如果客户请求不包含sessionId
,则为此客户创建一个session
并且生成一个与此session
相关联的sessionId
,这个session id
将在本次响应中返回给客户端保存。
保存session id的几种方式
• 保存session id
的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。
• 由于cookie
可以被人为的禁用,必须有其它的机制以便在cookie
被禁用时仍然能够把session id
传递回服务器,经常采用的一种技术叫做URL重写,就是把session id附加在URL路径的后面,附加的方式也有两种
,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面。网络在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id
。
Session cookie
• session
通过SessionID
来区分不同的客户,session
是以cookie
或URL重写
为基础的,默认使用cookie
来实现,系统会创造一个名为JSESSIONID
的输出cookie
,这称之为session cookie
,以区别persistent cookies
(也就是我们通常所说的cookie
)
• session cookie
是存储于浏览器内存
中的,并不是写到硬盘上的,通常看不到JSESSIONID
,但是当把浏览器的cookie
禁止后,web服务器会采用URL重写
的方式传递Sessionid
,这时地址栏看到
• session cookie
针对某一次会话而言,会话结束session cookie
也就随着消失了,而persistent cookie
只是存在于客户端硬盘上的一段文本。
• 关闭浏览器,只会使浏览器端内存里的session cookie
消失,但不会使保存在服务器端的session
对象消失,同样也不会使已经保存到硬盘上的持久化cookie
消失。
Session的创建与删除
• 一个常见的错误是以为session
在有客户端访问时就被创建,然而事实是直到某server
端程序(如Servlet
)调用HttpServletRequest.getSession(true)
或者 HttpServletRequest.getSession()
这样的语句时才会被创建。
• session在下列情况下被删除:
– A.程序调用HttpSession.invalidate()
– B.距离上一次收到客户端发送的session id
时间间隔超过了session
的最大有效时间
– C.服务器进程被停止
• 注意:关闭浏览器只会使存储在客户端浏览器内存中的session cookie失效,不会使服务器端的session对象失效。
两个浏览器窗口访问应用程序会使用同一个session
• 通常session cookie
是不能跨窗口使用的(IE 8
版本以前),当你新开了一个浏览器窗口进入相同页面时,系统会赋予你一个新的session id
,这样信息共享的目的就达不到了。
• 此时可以先把session id
保存在persistent cookie
中(通过设置cookie
的最大有效时间),然后在新窗口中读出来,就可以得到上一个窗口的session id
了,这样通过session cookie
和persistent cookie
的结合就可以实现了跨窗口的会话跟踪。
Session的超时管理
• WEB服务器无法判断当前的客户端浏览器是否还会继续访问,也无法检测客户端浏览器是否关闭,所以,即使客户已经离开或关闭了浏览器,WEB服务器还要保留与之对应的HttpSession
对象。
• 随着时间的推移而不断增加新的访问客户端,WEB服务器内存中将会因此积累起大量的不再被使用的HttpSession
对象,并将最终导致服务器内存耗尽。
• WEB服务器采用“超时限制”的办法来判断客户端是否还在继续访问,如果某个客户端在一定的时间之内没有发出后续请求,WEB服务器则认为客户端已经停止了活动,结束与该客户端的会话并将与之对应的HttpSession
对象变成垃圾。
• 如果客户端浏览器超时后再次发出访问请求,WEB服务器则认为这是一个新的会话的开始,将为之创建新的HttpSession
对象和分配新的会话标识号。
• 会话的超时间隔可以在web.xml文件中设置,其默认值由Servlet容器
定义。
<session-config>
<!-- 表示30分钟 -->
<session-timeout>30</session-timeout>
</session-config>
HttpSession接口中的方法
HttpServletRequest接口中的Session方法
• getSession
方法
public HttpSession getSession(boolean create)
public HttpSession getSession()
• isRequestedSessionIdValid
方法
• isRequestedSessionIdFromCookie
方法
• isRequestedSessionIdFromURL
方法
利用URL重写实现Session跟踪
• Servlet
规范中引入了一种补充的会话管理机制,**它允许不支持Cookie的浏览器也可以与WEB服务器保持连续的会话。**这种补充机制要求在响应消息的实体内容中必须包含
下一次请求的超链接,并将会话标识号作为超链接的URL地址的一个特殊参数。
• **将会话标识号以参数形式附加在超链接的URL地址后面的技术称为URL重写。**如果在浏览器不支持Cookie
或者关闭了Cookie
功能的情况下,WEB服务器还要能够与浏览器实现有状态的会话,就必须对所有可能被客户端访问的请求路径(包括超链接、form表单的action属性设置和重定向的URL)进行URL重写
。
• HttpServletResponse接口中定义了两个用于完成URL重写方法:
encodeURL
方法
encodeRedirectURL
方法
application域范围的属性
Session域范围的属性
什么时候会创建HttpSession对象
1.是否浏览器访问服务端的任何一个 JSP
或 Servlet
,服务器都会立即创建一个 HttpSession
对象呢?
不一定。若当前的 JSP(或 Servlet) 是客户端访问的当前 WEB 应用的第一个资源,且 JSP 的 page
指定的 session
属性值为 false
, 则服务器就不会为 JSP 创建一个 HttpSession
对象;若当前 JSP 不是客户端访问的当前 WEB 应用的第一个资源,且其他页面已经创建一个 HttpSession
对象,则当前 JSP 页面会返回一个会话的 HttpSession
对象,而不会创建一个新的 HttpSession
对象
对于 Serlvet
而言,若 Serlvet
是客户端访问的第一个 WEB 应用的资源,则只有调用了 request.getSession()
或 request.getSession(true)
才会创建 HttpSession
对象
2.session="false"
到底表示什么意思?
当前 JSP 页面禁用 session
隐含变量!但可以使用其他的显式的 HttpSession
对象
4.避免表单的重复提交
• 调用 RequestDispatcher.forward()
方法,浏览器所保留的URL 是先前的表单提交的 URL,此时点击”刷新”, 浏览器将再次提交用户先前输入的数据,引起重复提交
• 如果采用 HttpServletResponse.sendRedirct()
方法将客户端重定向到成功页面,将不会出现重复一条问题
JS 客户端避免表单重复提交
不足:当用户单击”刷新”,或单击”后退”再次提交表单,将导致表单重复提交
利用Session防止表单重复提交
• 包含有FORM
表单的页面必须通过一个服务器程序动态产生,服务器程序为每次产生的页面中的FORM
表单都分配一个唯一的随机标识号,并在FORM
表单的一个隐藏字段中设置这个标识号,同时在当前用户的Session
域中保存这个标识号。
• 当用户提交FORM
表单时,负责接收这一请求的服务器程序比较FORM
表单隐藏字段中的标识号与存储在当前用户的Session
域中的标识号是否相同,如果相同则处理表单数据,处理完后清除当前用户的Session
域中存储的标识号。在下列情况下,服务器程序将忽略提交的表单请求:
当前用户的Session
中不存在表单标识号
用户提交的表单数据中没有标识号字段
存储在当前用户的Session
域中的表单标识号与表单数据中的标识号不同
• 浏览器只有重新向WEB服务器请求包含FORM
表单的页面时,服务器程序才又产生另外一个随机标识号,并将这个标识号保存在Session
域中和作为新返回的FORM
表单中的隐藏字段值。
• 问题:
同一个用户打开同一个浏览器进程的多个窗口来并发访问同一个WEB站点的多个FORM
表单页面时,将会出现表单无法正常提交的情况。
• 解决方案:
1. 将FORM表单的标识号作为表单隐藏字段的名称,如下所示:
<input type='hidden' name='4b15c6b2f573831b4b5107d849fcafb8' value=''>
2. 将所有的表单标识号存储进一个`Vector`集合对象中,并将`Vector`集合对象存储进`Session`域中。当表单提交时,先从`Session`域中取出`Vector`集合对象,然后再从`Vector`集合对象中逐一取出每个表单标识号作为参数调用`HttpServletRequest.getParameter`方法,如果其中有一次调用的返回值不为`null`,则接受并处理该表单数据,处理完后将该表单标识号从`Vector`集合对象中删除。
利用Session实现一次性验证码
• 一次性验证码的主要目的就是为了限制人们利用工具软件来暴力猜测密码,其原理与利用Session
防止表单重复提交的原理基本一样,只是将表单标识号变成了验证码的形式,并且要求用户将提示的验证码手工填写进一个表单字段中,而不是通过表单的隐藏字段自动回传给服务器。
• 服务器程序接收到表单数据后,首先判断用户是否填写了正确的验证码,只有该验证码与服务器端保存的验证码匹配时,服务器程序才开始正常的表单处理流程。
• 密码猜测工具要逐一尝试每个密码的前题条件是先输入正确的验证码,而验证码是一次性有效的,这样基本上就阻断了密码猜测工具的自动地处理过程。
源码获取
至此,我们的JavaWeb的学习(上)
就讲解完成了。下篇我们将介绍JavaBean、自定义标签、过滤器Filter、监听器、文件的上传下载、国际化
,源码素材可以通过关注我的微信公众号 我爱学习呀嘻嘻
,回复关键字JavaWeb源码素材
进行获取哦。
JavaWeb的学习(下):JavaBean、自定义标签、过滤器Filter、监听器、文件的上传下载、国际化