【Hibernate学习笔记】第二章节:JSP/Servlet及相关技术详解
程序员文章站
2022-03-26 11:07:27
JSP(Java Servr Page)和Servlet是Java EE规范的两个基本成员,他们是Java Web开发的重点知识,也是Java EE开发的基础知识。JSP和Serv...
JSP(Java Servr Page)和Servlet是Java EE规范的两个基本成员,他们是Java Web开发的重点知识,也是Java EE开发的基础知识。JSP和Servlet的本质是一样的,因此JSP最终必须编译成Servlet才能运行,或者说JSP只是生成Servlet的“草稿”文件。JSP的特点是在HTML页面中嵌入了Java代码片段,从而可以动态的提供页面内容。
1.Web应用和web.xml文件
JSP、Servlet、Listener和Filter等都必须运行在Web应用中。
1.1. 构建Web应用
下面我们将‘徒手’建立一个Web应用:
(1):建立webDemo文件夹;
(2):在webDemo文件夹中建立WEB-INF文件夹;
(3):在其他任何一个Web应用下的WEB-INF文件夹中将web.xml文件复制到第二步中我们建立的WEB-INF文件夹下;
(4):修改复制到的web.xml文件,将该文件修改成只有一个根元素的XML文件,修改后的文件如下所示:
-=程序清单:wenDemo\WEB-INF\web.xml=-
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/javaee"
https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd
version="3.0">
(5):在WEB-INF路径下,新建两个文件夹:classes和lib,这两个文件夹的作用完全一样:都是保存Web应用所需要的Java类文件,区别是classes保存单个*.class文件,而lib保存打包后的JAR文件。
经过以上五个步骤已经建立了一个空的Web应用。将该Web应用复制到Tomcat的webapps路径下,该Web应用将可以自动部署在Tomcat中。
通常我们只需要将JSP放在Web应用的根目录下,然后就可以通过浏览器来访问这些页面了。
根据以上的介绍,我们可以发现Web应用应该具有以下的文件结构:
————这是Web应用的名称(名称可以改变)
|—WEB-INF
| |—classes
| |—lib
| |—web.xml
|—jsp... ...="">————这里存放多个JSP页面(名称可以改变)
1.2. 配置描述符web.xml
web.xml文件对于Web应用十分重要,而且必须放置在WEB-INF文件夹下。
对于Servlet3.0而言,web.xml文件不再是必须的,但是通常还是建议保留该配置文件。
对于Java Web应用而言,WEB-INF是一个特殊的文件夹,Web容器会包含该文件夹下的内容,但是客户端浏览器不会访问WEB-INF文件夹下的任何内容。
Servlet2.5规范之前,Java Web应用的绝大部分组件都是通过web.xml文件来配置管理,Servlet3.0规范可以通过Annotation来配置管理Web组件,因此web.xml文件可以变得更加简洁。
web.xml文件的根元素是元素。
在Servlet3.0规范中,新添加了metadata-complete属性,该属性接受true和false两个属性值。为true时,应用不会加载Annotation。
在web.xml文件中,使用welcome-file-list元素及其子元素welcome-file,来配置一个首页。
每个Web容器都会提供一个系统的web.xml文件,用于描述所有Web应用共同的配置属性。Tomcat的系统web.xml放置在conf路径下。
2.JSP的基本原理
JSP的本质是Servlet(一个特殊的Java类),当用户向指定Servlet发送请求时,Servlet利用输出流动态生成HTML页面,包括每一个静态的HTML标签和所有的HTML页面中出现的内容。
JSP页面的内容由以下两部分组成:
>>静态部分:静态HTML页面;
>>动态部分:受Java程序控制的内容,这部分内容由Java程序来动态生成。(Java脚本,代码放置于<%...%>之间)
对于Tomcat而言,JSP生成的Servlet(*_jsp.java类文件)放在work路径下的Web应用下,该Java类主要包含如下三个方法:
>>init():初始化JSP/Servlet的方法;
>>destroy():销毁JSP/Servlet之前的方法;
>>service():对于用户的请求生成响应的方法。
JSP页面中的所有内容都由*_jsp.java文件的页面输出流来生成。
依据JSP页面的工作原理,可以得到以下四个结论:
>>JSP文件必须在JSP服务器内运行;
>>JSP文件必须被编译生成Servlet才能执行;
>>每个JSP页面的第一个访问者的访问速度很慢,因为必须等待JSP文件被编译成Servlet文件;
>>JSP文件的访问者,无需安装任何客户端,甚至不需要可以运行Java的运行环境,因为JSP页面输送给客户端的是标准HTML页面。
3.JSP注释
JSP注释的格式:<%-- 注释内容 --%>
HTML注释的格式:
4.JSP声明
JSP声明用于声明变量和方法。在JSP声明中,似乎不需要定义类就可直接定义方法,方法似乎可以脱离类独立存在,实际上,JSP声明会转换成对应的Servlet的成员变量和成员方法,因此JSP声明依然复合Java语法。
JSP声明的语法格式:<%! 声明部分 %>
5.输出JSP表达式
JSP提供了一种输出表达式值的简单方法,输出表达式值得语法格式:<%=表达式%>
6.JSP脚本
JSP脚本里面可以包含任何可执行的Java代码。通常来说,所有可执行的Java代码都可以通过JSP脚本嵌入到HTML页面里。
JSP脚本里面不能定义方法。
7.JSP的3个编译指令
JSP的编译指令是通知JSP引擎的消息,他不直接生成输出。编译指令都有默认值,开发人员不需要为每个编译指令设置值。
常见的编译指令有如下3个:
>>page:针对当前页面的指令;
>>include:用于指定包含另一个页面;
>>taglib:用于定义和访问自定义标签。
使用编译指令的语法格式:<%@ 编译指令名 属性名="属性值"... ...%>
7.1. page指令
page指令通常位于JSP页面的顶部,一个JSP页面可以使用多条page指令。
page编译指令的语法格式如下:
<%@ page
[language="java"] <%-- 声明当前JSP页面使用的脚本语言 --%>
[extends="package.class"]<%-- 指定JSP页面编译后所产生的Java类所继承的父类,或所实现的接口 --%>
[import="package.class | package.*,......"]<%-- 导入包 --%>
[session="true | false"] <%-- 用于设定JSP页面是否需要HTTP Session --%>
[buffer="none | 8KB | size KB"] <%-- 指定输出缓冲区的大小 --%>
[autoFlush="true | false"] <%-- 当缓冲区即将溢出时,是否需要强制输出缓冲区的内容 --%>
[isThreadSafe="true | false"]<%-- 设置该JSP页面是否线程安全 --%>
[info="text"]<%-- 设置该JSP程序的说明 --%>
[errorPage="relativeURL"]<%-- 设置错误处理页面(实质是JSP的异常处理机制,JSP脚本不要求强制处理异常) --%>
[contentType="mimeType[;charset=characterSet]" | "text/html;charSet=ISO-8859-1"]<%-- 用于设定生成网页的文件格式和编码字符集 --%>
[pageEncoding="ISO-8859-1"]<%-- 生成网页的编码字符集 --%>
[isErrorPage="true | false"]<%-- 设置该JSP页面是否为错误处理页面 --%>
%>
7.2 include指令
include指令,可以将一个外部文件嵌入到当前的JSP文件中,同时解析这个页面中的JSP语句(如果有的话)。
include既可以包含静态的文本,也可包含动态的JSP页面。静态的include编译指令会将被包含的页面加入到本页面,融合成一个页面,因此被包含的页面甚至不需要是一个完整的页面。需要指出的是,静态包含还会将被包含页面的编译指令也包含进来,如果两个页面的编译指令冲突,那么页面将会出错。
include编译指令的语法格式:<%@ include file="relativeURLSpec"%>
如果嵌入的文件经常需要更换,建议使用操作指令,因为它是动态的include指令。
8.JSP的7个动作指令
8.1. 编译指令和动作指令的区别
编译指令是通知Servlet引擎的处理消息,而动作指令只是运行时的动作。
编译指令在将JSP编译成Servlet是起作用,而动作指令通常可以被JSP脚本替换,他只是JSP脚本的标准化写法。
8.2. JSP动作指令主要有如下7个:
>>jsp:forward:执行页面的转向,将请求的处理转发到下一个页面;
>>jsp:param:用于传递参数,必须与其他支持参数的标签一起使用;
>>jsp:include:用于动态引入一个JSP页面;
>>jsp:plugin:用于下载JavaBean或Applet到客户端执行;
>>jsp:useBean:创建一个JavaBean的实例;
>>jsp:setProperty:设置JavaBean实例的属性值;
>>jsp:getProperty:输出JavaBean实例的属性值。
9.JSP脚本中的9内置对象
这9个内置对象都是Servlet API接口的实例,只是JSP规范对它们进行了默认初始化(由JSP页面的Servlet的_jspService方法来创建这些对象),也就是说,他们已经是对象了,可以直接使用。
>>application:javax.servlet.ServletContext的实例,该实例代表JSP所属的Web应用本身,可用于JSP页面或者在Servlet之间交换信息。常用的方法有getAttribute(String attName);
>>config:javax.servlet.ServletConfig的实例,该实例代表JSP的配置信息。事实上,JSP页面无需配置,该内置对象更多的用在Servlet中;
>>exception:java.lang.Throwable的实例,该实例代表其他页面中的错误和异常;
>>out:javax.servlet.jsp.JspWriter的实例,该实例代表JSP页面的输出流,用于输出内容,形成HTMl页面;
>>page:代表该页面本身,通常没有太大用处,也就是Servlet中的this,其类型就是生成的Servlet类,能用page的地方就能用this;
>>pageContext:javax.servlet.jsp.PageContext的实例,该对象代表JSP页面的上下文,使用该对象可以访问页面*享的数据。常用的方法有:getServletCotext()和getServletConfig();
>>request:javax.servlet.http.HttpServletRequest的实例,该对象封装了一次请求,客户端的请求参数都被封装在该对象中,获取客户端请求参数必须使用该对象。常用的方法有:setAttribute(String attrName, Object attrValue),getAttribute(String attrName),getParametet(String paramName),getParameterValues(String paramName),setCharacterEncoding(String env);
>>response:javax.servlet.http.HttpServletResponsse的实例,该实例代表服务器对客户端的响应。通常很少使用该对象直接响应,而是使用out对象,除非需要生成非字符响应。response对象常用于重定向,常用的方法:getRedirect(java.lang.StringLocation),getOutputStream();
>>session:javax.servlet.http.HttpSeesion的实例,该实例代表一次会话。当客户端浏览器与站点建立连接时会话开始;当客户端关闭浏览器时,会话结束。常用的方法:setAttribute(String attrName, Object attrValue),getAttribute(String attrName)。
JSP内置对象的实质:它们要么是_jspService()方法的形参,要么是_jspService()方法的局部变量,所以我们可以直接在JSP脚本(脚本将对应Servlet的_jspService()方法部分)中调用这些对象,而无需创建他们。
9.1. application对象
在介绍application对象之前,我们先来简单了解一下Web服务器的实现原理。
抛开Web应用直接看Web服务器和客户端浏览器,对于大部分浏览器而言,他们通常负责三件事情:
>>向远程服务器发送请求;
>>读取远程服务器返回的字符串数据;
>>负责根据字符串数据渲染出一个页面。(浏览器最大的技术难点)
Web服务器运行机制中总是先由客户端浏览器发送请求,服务器接受请求后送回响应,所以也将这种架构称作“请求/响应”架构。
Web服务器大致需要如下几步完成对客户端浏览器的请求响应:
>>启动单独的线程;<%-- 通用 --%>
>>使用I/O流读取用户的请求数据;<%-- 通用 --%>
>>从请求数据中解析参数;<%-- Web服务器调用Servlet的_jspService()方法处理 --%>
>>处理用户请求;<%-- Web服务器调用Servlet的_jspService()方法处理 --%>
>>生成响应;<%-- Web服务器调用Servlet的_jspService()方法处理 --%>
>>使用I/O流向客户端发送响应数据。<%-- 通用 --%>
当我们编写JSP页面时,页面中的静态内容、JSP脚本都会转换成_jspService()方法的执行代码,这些代码负责完成解析参数、处理用户的请求、生成响应等业务功能,而Web服务器负责完成多线程、网络通行等底层功能。
Web服务器在执行了第3步解析请求参数后,将利用这些请求参数来创建HttpServletRequest、HttpServletResponse等对象,作为调用_jspService()方法的参数,实际上一个Web服务器必须为Servlet API中绝大部分接口提供实现类。
从上面的介绍可以看出,Web应用中的JSP页面、Servlet等程序都是由Web服务器来调用,JSP和Servlet之间通常不会相互调用,那么JSP和Servlet之间如何交换数据?
为了解决这个问题,几乎所有Web服务器都会提供4个类似Map的结构,分别是:application、session、request、page,并允许JSP和Servlet将数据放进这4个类似Map的结构中,并允许可以从这4个类似Map的结构中取出数据。这4个类似Map的结构的区别是范围不同。
>>application:整个Web应用有效。一旦JSP、Servlet将数据放入application,该数据将可以被应用下的其他所有的JSP、Servlet访问;
>>session:仅限一次会话有效。一旦JSP、Servlet将数据放入session,该数据将可以被该次会话下的其他所有的JSP、Servlet访问;
>>request:仅对本次请求有效,一旦JSP、Servlet将数据放入request,该数据将可以被该次请求的其他所有的JSP、Servlet访问;
>>page:仅对当前页面有效,一旦JSP、Servlet将数据放入page,该数据只能被当前页面的JSP脚本、声明部分访问。
把数据放入application、session、request、page中,就相当于是扩大了该数据的作用范围。
JSP中application、session、request、pageContext4个内置对象用于操作application、session、request、page范围中的数据。
application对象代表Web应用本身,因此使用application来操作Web应用相关数据。application对象通常有如下两个作用:
>>在整个Web应用的多个JSP、Servlet之间共享数据;setAttribute(String attrName,Object values)、getAttribute(String attrName)这两个方法用于共享数据。需要指出的是,由于application代表整个Web应用,所以不要仅仅为了JSP、Servlet之间共享数据,就将数据放入application中,通常将Web应用的状态数据放入application中。
>>访问Web应用的配置参数。
9.2. config对象
config对象代表当前JSP页面配置信息,但JSP页面通常无需配置,因此也就不存在配置信息。该对象在JSP页面中很少使用,但在Servlet中用处较大,因为Servlet需要在web.xml文件中进行配置,可以指定配置参数。
如果希望通过JSP页面获取web.xml配置文件中的配置信息,那么就需要将JSP页面当成Servlet来配置,并通过为该JSP页面配置的路径来访问该页面才能让配置参数起作用。
9.3. exception对象
exception对象是Throwable的实例,代表JSP脚本中产生的错误和异常,是JSP页面机制中的一部分。
在JSP脚本中无需处理异常,即使该异常是checked异常。事实上,JSP脚本包含的所有的可能出现的异常都可以交给错误处理页面处理。
exception对象仅仅在异常处理页面有效。
JSP脚本和静态HTML部分都会转化为_jspService()方法中的可执行代码,这就是JSP页面无需处理异常的原因,因为这些脚本已经处在try块中,一旦try块中捕捉到JSP脚本的异常,并且_jspx_page_context部位null,就会由该对象来处理异常。
当JSP页面page指令的isErrorPage属性为true时,该页面就会提供exception内置对象。
9.4. out对象
out对象代表一个页面输出流,通常用于在页面上输出变量值和常量。一般在使用输出表达式的地方,都可使用out对象来达到同样效果。
out.print(...)
<%=...%>表达式的本质就是:out.write(...)
9.5. pageContext对象
这个对象代表页面上下文,该对象主要用于访问JSP之间的共享数据。
使用pageContext可以访问page、request、sssion、application范围中的变量。
pageContext对象是PageContext类的实例,他提供了两个方法来访问page、request、sssion、application范围中的变量。
>>getAttribute(String name):取得page范围内的name属性
>>getAttribute(String name, int scope):取得指定范围内的name属性,其中scope可以使以下4个值:
PageContext.PAGE_SCOPE、PageContext.REQUEST_SCOPE、PageContext.SESSION_SCOPE、PageContext.APPLICATION_SCOPE
与此对应的有2个setAttribute()方法。(没有指定范围时,默认在page范围中)
一旦在JSP、Servlet中获取了pageContext对象,就可通过他提供的方法获取其他的内置对象。
9.6. request对象
request对象是JSP中重要的对象,每个request对象封装着一次用户请求,其中的请求参数也在其中,因此request对象是获取请求参数的重要途径。除此之外,request对象可代表本次请求范围,因此可以操作request范围的属性。
9.6.1. 获取请求头/请求参数
浏览器发送请求时通常会附带一些请求头及请求参数,服务器端负责解析请求头及请求参数的就是JSP或Servlet,而JSP或Servlet获取请求参数的途径就是request。
request对象是HttpServletRequest接口的实例,他提供了如下几个方法来获取请求参数:
->String getParameter(String paramName):获取paramName请求参数的值
->Map getParameterMap():获取所有请求参数名和参数值所组成的Map对象
->Enumeration getParameterNames():获取所有请求参数名所组成的Enumeration对象
->String[] getParameterValues(String name):获取所有请求参数值所组成的数组
提供如下的方法来访问请求头:
->String getHeader(String name):根据指定请求头的值
->java.util.Enumeration getHeaderNames():获取所有请求头的名称
->java.util.Enumeration getHeaders(String name):获取指定头的多个值
->int getIntHeader(String name):获取指定请求头的值,并将该值转化为整数值
对于开发人员而言,请求头和请求参数都是由用户发送到服务器的数据,请求头通常由浏览器自动添加,因此一次请求通常包含还几个请求头;而请求参数则通常需要开发人员控制添加。
让客户端发送请求参数通常分2中情况:
>>GET方式:GET方式的请求会将请求参数的名和值直接转换为字符串,并附加在原url之后,因此可以在地址栏中看到请求参数名和值,GET请求传送的数据一般不能大于2kb。(form元素的method属性为get,或不设置)
>>POST方式:这种方式通常使用提交表单的方式发送,且需要设置form元素的method属性为post。通常认为post请求参数的数据量大小不受限制,但往往取决于服务器的限制,post方式发送的请求参数放置在HTML HEADER中传递,在地址栏看不见请求参数,安全性相对较高。
比较以上两种请求方式,我们通常采用POST方式发送请求。
表单用于收集用户信息,一旦用户提交请求,表单中的数据将会提交给对应的处理程序。
并不是每个表单域都会生成请求参数,而是有name属性的表单域才会生成请求参数。关于表单域和请求参数的关系遵循以下四点:
>>每个有name属性的表单域对应一个请求参数
>>如果有多个表单域有相同的name属性,则多个表单域只生成一个请求参数,只是该请求参数中有多个值。
>>表单域的name属性指定请求参数名,value指定请求参数值
>>如果某个表单域设置了disabled="disabled"属性,则该表单域不再生成请求参数。
9.6.2. 操作request范围的属性
HttpServletRequest提供如下两个方法,用于设置和获取request范围的属性;
->setAttribute(String attrName, Object attValue):将attValue设置为request范围的属性attrName的值
->Object getAttribute(String attrName):获取request范围名为attrName的属性
当forward用户请求时,请求的参数和属性都不会丢失。(即可携带参数)
9.6.3. 执行foreard或include
->forward(ServletRequest request, ServletResponse response)
->include(ServletRequest request, ServletResponse response)
以上的两个方法都是先执行方法:getRequestDispatcher(String path)以后再调用。
9.7. response对象
out生成字符串响应。
response生成非字符串响应,还可用于重定向请求,以及用于向客户端增加cookie。
9.7.1. response响应生成非字符串响应
response是HttpServletResponse接口的实例,该接口提供了一个getOutputStream()方法,该方法返回响应输出字节流。
9.7.2. 重定向
与foward不同的是,重定向会丢失所有请求参数和request范围中的属性,因为重定向将生成第二次请求,与第一次请求不在同一个request范围内,所以导致第一次的所有请求参数和request范围中的属性丢失。
sendRedirect(String path)方法用于重定向到path资源。
forward与重定向的区别:
--------------------------------------------------------+------------------------------------------------------
转发(forward) | 重定向(redirect)
执行forward之后依然是上一次请求 |执行redirect之后生成第二次请求
原请求参数和request范围内的属性保留 |原请求参数和request范围内的属性丢失
地址栏的url不会变化 |地址栏的url变化
--------------------------------------------------------+-----------------------------------------------------
9.7.3. 增加cookie
Cookie通常用户网站记录客户的某些信息。
Cookie与session不同的是,session会随着浏览器的关闭而失效,而Cookie会一直保存在客户端机器上,除非超出了Cookie的生命周期。
response 的方法void addCookie(Cookie cookie)用于增加Cookie
*-?-* 详细介绍请百度 *-?-*
9.8. session对象
session对象代表一次会话,一次会话的含义是:从客户端浏览器链接服务器开始,到客户端浏览器与服务器断开为止。
session通常用于跟踪用户的会话信息,如判断用户是否登录系统,或者购物车是否存在商品等。
session范围内的数据可以在多个页面之间跳转共享。一旦浏览器关闭,即session结束,那么session范围中的属性也立即丢失。
session是HttpSession的实例,常用的方法有如下两个:
->setAttribute(String attName, Object attValue):设置session范围内的属性attName的值为attValue
->getAttribute(String attName):获取session范围内的名为attName的属性的值
考虑session本身的目的,通常只把与用户会话状态相关的信息放入session范围内。不要仅仅为了两个页面之间交换信息,就将该信息放入session范围内。如果仅仅是为了两个页面之间交换信息,可以将信息放入request范围内,然后forward请求即可。
session的属性值可以是任何可序列化的Java对象。
10.servlet介绍
JSP的本质就是Servlet,开发者把编写好的JSP部署到Web容器中之后,Web容器就会将JSP编译成对应的Servlet。
自从MVC规范出现以后,Servlet的责任开始明确下来,仅仅做为控制器使用。
10.1. Servlet的开发
Servlet通常被称为“服务器端小程序”,是运行在‘服务器端的程序’,用来处理来自客户端的请求及响应来自客户端的请求。
Servlet是个特殊的Java类,这个类必须继承HttpServlet。Servlet提供了不同的方法用于响应来自客户端的请求。
>>doGet:用于响应客户端的get请求
>>doPost:用于响应客户端的post请求
>>doPut:用于响应客户端的put请求
>>doDelete:用于响应客户端的delete请求
事实上,客户端的请求只有get和post两种,Servlet为了响应这两种请求,必须重写doGet()和doPost()两个方法。大部分的时候,Servlet对于所有的请求的响应都是完全一样的,可以采用重写一个方法来代替上面几个方法:只需要重写service()方法即可响应客户端的所有请求。
另外,HttpServlet还提供了两个方法:
>>init(ServletConfig config):创建Servlet实例时,调用该方法以初始化Servlet资源
>>destroy():销毁Servlet实例时,自动调用该方法回收资源
通常无需重写init()和destroy()方法。
Servlet和JSP的区别在于:
->Servlet中没有内置对象,JSP中的内置对象都是由程序显示创建的;
->对于静态的HTML标签,Servlet都必须使用输出流逐行输出。
普通Servlet类的service()方法的作用,完全等同于JSP生成Servlet类的_jspService()方法。
原JSP声明中的内容,对应生成的Servlet类中的成员变量和成员方法。
10.2. Servlet配置
编辑好的Servlet源文件并不能直接响应客户端的请求,还必须将其编译成class文件,放置在WEB-INF/classes路径下,并且在web.xml文件中配置Servlet。
配置Servlet有两种方法(只能选择其中一种配置,不能同时配置):
>>在Servlet类中使用 @WebServlet Annotation进行配置
>>通过在web.xml文件进行配置
10.2.1. 使用Annotation进行配置
注意两点:
->不要在web.xml文件的根元素()中指定metadata-complete="true"。
->不要再web.xml文件中配置该Servlet
常用属性:
@WebServlet Annotation(
name//制定该Servlet的名称
asyncSupported//指定该Servlet是否支持异步操作模式
displayName//指定该Servlet的显示名
initParams//用于为该Servlet配置参数
loadOnStartup//用于将该Servlet配置成load-on-startup的Servlet
urlPatterns//指定该Servlet处理的URL
value//指定该Servlet处理的URL
)
10.2.2. 使用web.xml文件进行配置
两个部分:
... ...
... ...
... ...
/... ...
10.3. JSP/Servlet的生命周期
开发者编写的JSP由Web容器编译成对应的Servlet后,运行在Web容器(服务器端)之中,其实例的创建和销毁由Web容器进行控制。
创建Servlet实例有两种时机:
->客户端第一次请求某个Servlet时,系统创建该Servlet的实例。(绝大部分Servlet采用这种)
->Web应用启动时立即创建Servlet实例,即:load-on-startup Servlet。
Servlet生命周期:
->创建Servlet实例
->Web容器调用Servlet的init()方法初始化Servlet
->Servlet初始化之后,一直存在于Web容器中,用于响应客户端的请求。客户端若是get请求,则调用doGet(),反之亦然 ...
->Web容器决定销毁Servlet,首先调用destroy()方法。通常在关闭Web应用之前销毁Servlet。
10.4. load-on-startup Servlet
应用启动时立刻创建Servlet,通常用于某些后台服务的Servlet,或者需要拦截很多请求的Servlet,这种Servlet通常作为应用的基础Servlet使用,提供重要的后台服务。
配置load-on-startup Servlet的两种方式;
->web.xml文件中通过元素的子元素进行配置
->@WebServlet Annotation的loadOnStartup属性指定(@WebServlet(loadOnStartup=1)单位是:min)
10.5. 访问Servlet的配置参数
配置Servlet时,还可以为Servlet添加其他的配置参数。方法有两种:
>>通过 @WebServlet的initParams属性来指定
>>通过web.xml文件的元素中添加子元素来指定
访问Servlet配置参数的方法是通过ServletConfig对象完成的,ServletConfig对象提供以下方法:
>>java.lang.String getInitParameter(java.lang.String name):用于获取初始化参数
注意:JSP中的config内置对象就是这里的ServletConfig
【示例】:
@WebServlet:
@WebServlet(name="testServlet",
urlPatterns={"/testServlet"},
initParams={
@WebInitParam(name="driver", value="com.masql.jdbc.Driver"),
@WebInitParam(name="url", value="jdbc:masql://localhost:3306/javaee"),
@WebInitParam(name="username", value="root"),
@WebInitParam(name="password", value="root")
}
)
web.xml:
driver
com.masql.jdbc.Driver
... ...
//获取ServletConfig对象
ServletConfig sConfig = getServletConfig();
//通过ServletConfig对象获取配置参数:driver、url、username、password
String driver = sConfig.getInitParameter("driver");
String url = sConfig.getInitParameter("url");
String username = sConfig.getInitParameter("username");
String password = sConfig.getInitParameter("password");
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, username, paaword);
... ...
ServletConfig是获取当前Servlet的配置参数,而ServletContext是获取整个Web应用的配置参数。
10.6. 使用Servlet作为控制器
使用Servlet作为表现层的工作量太大。
Java EE应用架构遵循MVC模式,所以Servlet仅作为控制器使用,JSP仅作为表现层使用。
使用JSP作为表现层有下面两个作用:
>>负责收集用户的请求参数
>>将应用的处理结果,状态参数呈现给用户
Servlet的作用类似于调度员,所有用户的请求都必须发送给Servlet,由Servlet调用Model来处理用户的请求,并调用JSP来呈现处理结果;或者Servlet直接调用JSP将应用的状态数据呈现给用户。
Model通常由JavaBean来充当,所有的业务逻辑、数据访问逻辑都在Model中实现。实际上隐藏在Model下的可能还有很多丰富的组件:例如DAO组件,POJO组件... ...
控制器负责接收客户端的请求,他既不能直接对客户端输出响应,也不能处理请求,只能调用JavaBean来处理用户请求。
11.JSP2的自定义标签
11.1. 使用标签库
在JSP页面中确定制定的标签库需要两点;
>>标签库uri:确定使用哪个标签库
>>标签名:确定使用哪个标签
使用标签库需要两个步骤:
>>导入标签库:使用taglib编译指令导入标签库
>>使用标签:在JSP页面中使用自定义标签
<%@ taglib uri="tagliburi" prefix="tagPrefix" %>
12.Filter介绍
Filter可以认为是Servlet的一种“加强版”,他主要对用户的请求HttpServletRequest进行预处理,也可以对响应HttpServletResponse进行后处理,是一个典型的处理链。
使用Filter完整的流程是:Filter对用户的请求进行预处理,接着将预处理后的请求交给Servlet进行处理并生成响应,最后Filter再对服务器进行后处理。
Filter有如下几个用处:
>>在HttpServletRequest到达Servlet之前,拦截来自客户的HttpServletRequest
>>根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据
>>在HttpServletResponse到达客户端之前,拦截来自服务器的HttpServletResponse
>>根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据
Filter有如下几个种类;
>>用户授权的Filter:该Filter负责检查用户请求,过滤用户的非法请求
>>日志Filter:详细记录某些特殊的用户请求
>>负责解码的Filter:包括对非标准编码的请求解码
>>能改变XML内容的XSLT Filter等
>>一个Filter可以负责拦截多个请求或响应:一个请求或响应也可以被多个Filter拦截
创建一个Filter只需要两步:
>>创建一个Filter处理类
>>在web.xml文件中配置该Filter
12.1. 创建Filter类
创建Filter必须实现javax.servlet.Filter接口。该接口中定义了如下三个方法:
->void innit(FilterConfig config):用于完成Filter的初始化
->void destroy():用于Filter销毁前,完成某些资源的回收
->void doFilter(ServletRequest request, ServletResponse response, FilterChain chain):实现过滤功能
12.2. 配置Filter
配置Filter有如下两个部分:
>>配置Filter名
>>配置Filter拦截URL模式
配置Filter和Servlet的无别在于:Servlet通常只需要配置一个URL,而Filter可以同时拦截多个请求的URL。因此,在配置Filter的URL模式时通常采用模式字符串,使得Filter可以拦截多个请求。
配置Filter有如下两种方式:
>>在Filter类中通过Annotation进行配置
>>在web.xml文件中进行配置
12.2.1. 使用Annotation进行配置
注意两点:
->不要在web.xml文件的根元素()中指定metadata-complete="true"。
->不要再web.xml文件中配置该Servlet
常用属性:
@WebFilter Annotation(
name//制定该Filter的名称
dispatcherTypes//制定该Filter仅对那种dispatcher模式的请求进行过滤
asyncSupported//指定该Filter是否支持异步操作模式
displayName//指定该Filter的显示名
initParams//用于为该Filter配置参数
servletNames//指定该Filter仅对这几个Servlet执行过滤
urlPatterns//指定该Filter处理的URL
value//指定该Filter处理的URL
)
12.2.2. 使用web.xml文件进行配置
两个部分:
... ...
... ...
... ...
/... ...
实际上,Filter和Servlet极其相似,只是Filter的doFilter()方法中多了一个FilterChain的参数,通过该参数可以控制是否放行用户的请求。在实际项目开发中,Filter里doFilter()方法中的代码就是从多个Servlet的service()方法里面抽取的通用代码,通过使用Filter可以提高代码的复用性。
由于Filter和Servlet极其相似,所以Filter具有和Servlet相同的生命周期行为。
Filter也可以通过元素或 @WebFilter的initParams属性来配置初始化参数,获取Filter的初始化参数则使用FilterConfig的getInitParameter()方法。
12.3. 使用 URL Rewrite 实现网站的伪静态
为什么要使用伪静态网站?
对于以JSP为表现层开发的动态网站来说,用户访问的URL通常是如下形式:
xxx.jsp?param=value...
大部分搜索引擎都会优先收集静态HTML页面,而不是这种动态的*.jsp、*.php页面,所以大部分网站都会考虑使用伪静态。
对于Java Web应用而言,如何实现网站伪静态?
可以通过Filter拦截所有发向*.html的请求,然后按照某种规则将请求forward(转发)到实际的*.jsp或*.php页面即可。
可以使用《URL Rewrite》实现网站的伪静态,具体参见网络。
1.Web应用和web.xml文件
JSP、Servlet、Listener和Filter等都必须运行在Web应用中。
1.1. 构建Web应用
下面我们将‘徒手’建立一个Web应用:
(1):建立webDemo文件夹;
(2):在webDemo文件夹中建立WEB-INF文件夹;
(3):在其他任何一个Web应用下的WEB-INF文件夹中将web.xml文件复制到第二步中我们建立的WEB-INF文件夹下;
(4):修改复制到的web.xml文件,将该文件修改成只有一个根元素的XML文件,修改后的文件如下所示:
-=程序清单:wenDemo\WEB-INF\web.xml=-
xsi:schemaLocation="https://java.sun.com/xml/ns/javaee"
https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd
version="3.0">
(5):在WEB-INF路径下,新建两个文件夹:classes和lib,这两个文件夹的作用完全一样:都是保存Web应用所需要的Java类文件,区别是classes保存单个*.class文件,而lib保存打包后的JAR文件。
经过以上五个步骤已经建立了一个空的Web应用。将该Web应用复制到Tomcat的webapps路径下,该Web应用将可以自动部署在Tomcat中。
通常我们只需要将JSP放在Web应用的根目录下,然后就可以通过浏览器来访问这些页面了。
根据以上的介绍,我们可以发现Web应用应该具有以下的文件结构:
|—WEB-INF
| |—classes
| |—lib
| |—web.xml
|—jsp... ...="">————这里存放多个JSP页面(名称可以改变)
1.2. 配置描述符web.xml
web.xml文件对于Web应用十分重要,而且必须放置在WEB-INF文件夹下。
对于Servlet3.0而言,web.xml文件不再是必须的,但是通常还是建议保留该配置文件。
对于Java Web应用而言,WEB-INF是一个特殊的文件夹,Web容器会包含该文件夹下的内容,但是客户端浏览器不会访问WEB-INF文件夹下的任何内容。
Servlet2.5规范之前,Java Web应用的绝大部分组件都是通过web.xml文件来配置管理,Servlet3.0规范可以通过Annotation来配置管理Web组件,因此web.xml文件可以变得更加简洁。
web.xml文件的根元素是
在Servlet3.0规范中,新添加了metadata-complete属性,该属性接受true和false两个属性值。为true时,应用不会加载Annotation。
在web.xml文件中,使用welcome-file-list元素及其子元素welcome-file,来配置一个首页。
每个Web容器都会提供一个系统的web.xml文件,用于描述所有Web应用共同的配置属性。Tomcat的系统web.xml放置在conf路径下。
2.JSP的基本原理
JSP的本质是Servlet(一个特殊的Java类),当用户向指定Servlet发送请求时,Servlet利用输出流动态生成HTML页面,包括每一个静态的HTML标签和所有的HTML页面中出现的内容。
JSP页面的内容由以下两部分组成:
>>静态部分:静态HTML页面;
>>动态部分:受Java程序控制的内容,这部分内容由Java程序来动态生成。(Java脚本,代码放置于<%...%>之间)
对于Tomcat而言,JSP生成的Servlet(*_jsp.java类文件)放在work路径下的Web应用下,该Java类主要包含如下三个方法:
>>init():初始化JSP/Servlet的方法;
>>destroy():销毁JSP/Servlet之前的方法;
>>service():对于用户的请求生成响应的方法。
JSP页面中的所有内容都由*_jsp.java文件的页面输出流来生成。
依据JSP页面的工作原理,可以得到以下四个结论:
>>JSP文件必须在JSP服务器内运行;
>>JSP文件必须被编译生成Servlet才能执行;
>>每个JSP页面的第一个访问者的访问速度很慢,因为必须等待JSP文件被编译成Servlet文件;
>>JSP文件的访问者,无需安装任何客户端,甚至不需要可以运行Java的运行环境,因为JSP页面输送给客户端的是标准HTML页面。
3.JSP注释
JSP注释的格式:<%-- 注释内容 --%>
HTML注释的格式:
4.JSP声明
JSP声明用于声明变量和方法。在JSP声明中,似乎不需要定义类就可直接定义方法,方法似乎可以脱离类独立存在,实际上,JSP声明会转换成对应的Servlet的成员变量和成员方法,因此JSP声明依然复合Java语法。
JSP声明的语法格式:<%! 声明部分 %>
5.输出JSP表达式
JSP提供了一种输出表达式值的简单方法,输出表达式值得语法格式:<%=表达式%>
6.JSP脚本
JSP脚本里面可以包含任何可执行的Java代码。通常来说,所有可执行的Java代码都可以通过JSP脚本嵌入到HTML页面里。
JSP脚本里面不能定义方法。
7.JSP的3个编译指令
JSP的编译指令是通知JSP引擎的消息,他不直接生成输出。编译指令都有默认值,开发人员不需要为每个编译指令设置值。
常见的编译指令有如下3个:
>>page:针对当前页面的指令;
>>include:用于指定包含另一个页面;
>>taglib:用于定义和访问自定义标签。
使用编译指令的语法格式:<%@ 编译指令名 属性名="属性值"... ...%>
7.1. page指令
page指令通常位于JSP页面的顶部,一个JSP页面可以使用多条page指令。
page编译指令的语法格式如下:
<%@ page
[language="java"] <%-- 声明当前JSP页面使用的脚本语言 --%>
[extends="package.class"]<%-- 指定JSP页面编译后所产生的Java类所继承的父类,或所实现的接口 --%>
[import="package.class | package.*,......"]<%-- 导入包 --%>
[session="true | false"] <%-- 用于设定JSP页面是否需要HTTP Session --%>
[buffer="none | 8KB | size KB"] <%-- 指定输出缓冲区的大小 --%>
[autoFlush="true | false"] <%-- 当缓冲区即将溢出时,是否需要强制输出缓冲区的内容 --%>
[isThreadSafe="true | false"]<%-- 设置该JSP页面是否线程安全 --%>
[info="text"]<%-- 设置该JSP程序的说明 --%>
[errorPage="relativeURL"]<%-- 设置错误处理页面(实质是JSP的异常处理机制,JSP脚本不要求强制处理异常) --%>
[contentType="mimeType[;charset=characterSet]" | "text/html;charSet=ISO-8859-1"]<%-- 用于设定生成网页的文件格式和编码字符集 --%>
[pageEncoding="ISO-8859-1"]<%-- 生成网页的编码字符集 --%>
[isErrorPage="true | false"]<%-- 设置该JSP页面是否为错误处理页面 --%>
%>
7.2 include指令
include指令,可以将一个外部文件嵌入到当前的JSP文件中,同时解析这个页面中的JSP语句(如果有的话)。
include既可以包含静态的文本,也可包含动态的JSP页面。静态的include编译指令会将被包含的页面加入到本页面,融合成一个页面,因此被包含的页面甚至不需要是一个完整的页面。需要指出的是,静态包含还会将被包含页面的编译指令也包含进来,如果两个页面的编译指令冲突,那么页面将会出错。
include编译指令的语法格式:<%@ include file="relativeURLSpec"%>
如果嵌入的文件经常需要更换,建议使用
8.JSP的7个动作指令
8.1. 编译指令和动作指令的区别
编译指令是通知Servlet引擎的处理消息,而动作指令只是运行时的动作。
编译指令在将JSP编译成Servlet是起作用,而动作指令通常可以被JSP脚本替换,他只是JSP脚本的标准化写法。
8.2. JSP动作指令主要有如下7个:
>>jsp:forward:执行页面的转向,将请求的处理转发到下一个页面;
>>jsp:param:用于传递参数,必须与其他支持参数的标签一起使用;
>>jsp:include:用于动态引入一个JSP页面;
>>jsp:plugin:用于下载JavaBean或Applet到客户端执行;
>>jsp:useBean:创建一个JavaBean的实例;
>>jsp:setProperty:设置JavaBean实例的属性值;
>>jsp:getProperty:输出JavaBean实例的属性值。
9.JSP脚本中的9内置对象
这9个内置对象都是Servlet API接口的实例,只是JSP规范对它们进行了默认初始化(由JSP页面的Servlet的_jspService方法来创建这些对象),也就是说,他们已经是对象了,可以直接使用。
>>application:javax.servlet.ServletContext的实例,该实例代表JSP所属的Web应用本身,可用于JSP页面或者在Servlet之间交换信息。常用的方法有getAttribute(String attName);
>>config:javax.servlet.ServletConfig的实例,该实例代表JSP的配置信息。事实上,JSP页面无需配置,该内置对象更多的用在Servlet中;
>>exception:java.lang.Throwable的实例,该实例代表其他页面中的错误和异常;
>>out:javax.servlet.jsp.JspWriter的实例,该实例代表JSP页面的输出流,用于输出内容,形成HTMl页面;
>>page:代表该页面本身,通常没有太大用处,也就是Servlet中的this,其类型就是生成的Servlet类,能用page的地方就能用this;
>>pageContext:javax.servlet.jsp.PageContext的实例,该对象代表JSP页面的上下文,使用该对象可以访问页面*享的数据。常用的方法有:getServletCotext()和getServletConfig();
>>request:javax.servlet.http.HttpServletRequest的实例,该对象封装了一次请求,客户端的请求参数都被封装在该对象中,获取客户端请求参数必须使用该对象。常用的方法有:setAttribute(String attrName, Object attrValue),getAttribute(String attrName),getParametet(String paramName),getParameterValues(String paramName),setCharacterEncoding(String env);
>>response:javax.servlet.http.HttpServletResponsse的实例,该实例代表服务器对客户端的响应。通常很少使用该对象直接响应,而是使用out对象,除非需要生成非字符响应。response对象常用于重定向,常用的方法:getRedirect(java.lang.StringLocation),getOutputStream();
>>session:javax.servlet.http.HttpSeesion的实例,该实例代表一次会话。当客户端浏览器与站点建立连接时会话开始;当客户端关闭浏览器时,会话结束。常用的方法:setAttribute(String attrName, Object attrValue),getAttribute(String attrName)。
JSP内置对象的实质:它们要么是_jspService()方法的形参,要么是_jspService()方法的局部变量,所以我们可以直接在JSP脚本(脚本将对应Servlet的_jspService()方法部分)中调用这些对象,而无需创建他们。
9.1. application对象
在介绍application对象之前,我们先来简单了解一下Web服务器的实现原理。
抛开Web应用直接看Web服务器和客户端浏览器,对于大部分浏览器而言,他们通常负责三件事情:
>>向远程服务器发送请求;
>>读取远程服务器返回的字符串数据;
>>负责根据字符串数据渲染出一个页面。(浏览器最大的技术难点)
Web服务器运行机制中总是先由客户端浏览器发送请求,服务器接受请求后送回响应,所以也将这种架构称作“请求/响应”架构。
Web服务器大致需要如下几步完成对客户端浏览器的请求响应:
>>启动单独的线程;<%-- 通用 --%>
>>使用I/O流读取用户的请求数据;<%-- 通用 --%>
>>从请求数据中解析参数;<%-- Web服务器调用Servlet的_jspService()方法处理 --%>
>>处理用户请求;<%-- Web服务器调用Servlet的_jspService()方法处理 --%>
>>生成响应;<%-- Web服务器调用Servlet的_jspService()方法处理 --%>
>>使用I/O流向客户端发送响应数据。<%-- 通用 --%>
当我们编写JSP页面时,页面中的静态内容、JSP脚本都会转换成_jspService()方法的执行代码,这些代码负责完成解析参数、处理用户的请求、生成响应等业务功能,而Web服务器负责完成多线程、网络通行等底层功能。
Web服务器在执行了第3步解析请求参数后,将利用这些请求参数来创建HttpServletRequest、HttpServletResponse等对象,作为调用_jspService()方法的参数,实际上一个Web服务器必须为Servlet API中绝大部分接口提供实现类。
从上面的介绍可以看出,Web应用中的JSP页面、Servlet等程序都是由Web服务器来调用,JSP和Servlet之间通常不会相互调用,那么JSP和Servlet之间如何交换数据?
为了解决这个问题,几乎所有Web服务器都会提供4个类似Map的结构,分别是:application、session、request、page,并允许JSP和Servlet将数据放进这4个类似Map的结构中,并允许可以从这4个类似Map的结构中取出数据。这4个类似Map的结构的区别是范围不同。
>>application:整个Web应用有效。一旦JSP、Servlet将数据放入application,该数据将可以被应用下的其他所有的JSP、Servlet访问;
>>session:仅限一次会话有效。一旦JSP、Servlet将数据放入session,该数据将可以被该次会话下的其他所有的JSP、Servlet访问;
>>request:仅对本次请求有效,一旦JSP、Servlet将数据放入request,该数据将可以被该次请求的其他所有的JSP、Servlet访问;
>>page:仅对当前页面有效,一旦JSP、Servlet将数据放入page,该数据只能被当前页面的JSP脚本、声明部分访问。
把数据放入application、session、request、page中,就相当于是扩大了该数据的作用范围。
JSP中application、session、request、pageContext4个内置对象用于操作application、session、request、page范围中的数据。
application对象代表Web应用本身,因此使用application来操作Web应用相关数据。application对象通常有如下两个作用:
>>在整个Web应用的多个JSP、Servlet之间共享数据;setAttribute(String attrName,Object values)、getAttribute(String attrName)这两个方法用于共享数据。需要指出的是,由于application代表整个Web应用,所以不要仅仅为了JSP、Servlet之间共享数据,就将数据放入application中,通常将Web应用的状态数据放入application中。
>>访问Web应用的配置参数。
9.2. config对象
config对象代表当前JSP页面配置信息,但JSP页面通常无需配置,因此也就不存在配置信息。该对象在JSP页面中很少使用,但在Servlet中用处较大,因为Servlet需要在web.xml文件中进行配置,可以指定配置参数。
如果希望通过JSP页面获取web.xml配置文件中的配置信息,那么就需要将JSP页面当成Servlet来配置,并通过为该JSP页面配置的路径来访问该页面才能让配置参数起作用。
9.3. exception对象
exception对象是Throwable的实例,代表JSP脚本中产生的错误和异常,是JSP页面机制中的一部分。
在JSP脚本中无需处理异常,即使该异常是checked异常。事实上,JSP脚本包含的所有的可能出现的异常都可以交给错误处理页面处理。
exception对象仅仅在异常处理页面有效。
JSP脚本和静态HTML部分都会转化为_jspService()方法中的可执行代码,这就是JSP页面无需处理异常的原因,因为这些脚本已经处在try块中,一旦try块中捕捉到JSP脚本的异常,并且_jspx_page_context部位null,就会由该对象来处理异常。
当JSP页面page指令的isErrorPage属性为true时,该页面就会提供exception内置对象。
9.4. out对象
out对象代表一个页面输出流,通常用于在页面上输出变量值和常量。一般在使用输出表达式的地方,都可使用out对象来达到同样效果。
out.print(...)
<%=...%>表达式的本质就是:out.write(...)
9.5. pageContext对象
这个对象代表页面上下文,该对象主要用于访问JSP之间的共享数据。
使用pageContext可以访问page、request、sssion、application范围中的变量。
pageContext对象是PageContext类的实例,他提供了两个方法来访问page、request、sssion、application范围中的变量。
>>getAttribute(String name):取得page范围内的name属性
>>getAttribute(String name, int scope):取得指定范围内的name属性,其中scope可以使以下4个值:
PageContext.PAGE_SCOPE、PageContext.REQUEST_SCOPE、PageContext.SESSION_SCOPE、PageContext.APPLICATION_SCOPE
与此对应的有2个setAttribute()方法。(没有指定范围时,默认在page范围中)
一旦在JSP、Servlet中获取了pageContext对象,就可通过他提供的方法获取其他的内置对象。
9.6. request对象
request对象是JSP中重要的对象,每个request对象封装着一次用户请求,其中的请求参数也在其中,因此request对象是获取请求参数的重要途径。除此之外,request对象可代表本次请求范围,因此可以操作request范围的属性。
9.6.1. 获取请求头/请求参数
浏览器发送请求时通常会附带一些请求头及请求参数,服务器端负责解析请求头及请求参数的就是JSP或Servlet,而JSP或Servlet获取请求参数的途径就是request。
request对象是HttpServletRequest接口的实例,他提供了如下几个方法来获取请求参数:
->String getParameter(String paramName):获取paramName请求参数的值
->Map getParameterMap():获取所有请求参数名和参数值所组成的Map对象
->Enumeration getParameterNames():获取所有请求参数名所组成的Enumeration对象
->String[] getParameterValues(String name):获取所有请求参数值所组成的数组
提供如下的方法来访问请求头:
->String getHeader(String name):根据指定请求头的值
->java.util.Enumeration
->java.util.Enumeration
->int getIntHeader(String name):获取指定请求头的值,并将该值转化为整数值
对于开发人员而言,请求头和请求参数都是由用户发送到服务器的数据,请求头通常由浏览器自动添加,因此一次请求通常包含还几个请求头;而请求参数则通常需要开发人员控制添加。
让客户端发送请求参数通常分2中情况:
>>GET方式:GET方式的请求会将请求参数的名和值直接转换为字符串,并附加在原url之后,因此可以在地址栏中看到请求参数名和值,GET请求传送的数据一般不能大于2kb。(form元素的method属性为get,或不设置)
>>POST方式:这种方式通常使用提交表单的方式发送,且需要设置form元素的method属性为post。通常认为post请求参数的数据量大小不受限制,但往往取决于服务器的限制,post方式发送的请求参数放置在HTML HEADER中传递,在地址栏看不见请求参数,安全性相对较高。
比较以上两种请求方式,我们通常采用POST方式发送请求。
表单用于收集用户信息,一旦用户提交请求,表单中的数据将会提交给对应的处理程序。
并不是每个表单域都会生成请求参数,而是有name属性的表单域才会生成请求参数。关于表单域和请求参数的关系遵循以下四点:
>>每个有name属性的表单域对应一个请求参数
>>如果有多个表单域有相同的name属性,则多个表单域只生成一个请求参数,只是该请求参数中有多个值。
>>表单域的name属性指定请求参数名,value指定请求参数值
>>如果某个表单域设置了disabled="disabled"属性,则该表单域不再生成请求参数。
9.6.2. 操作request范围的属性
HttpServletRequest提供如下两个方法,用于设置和获取request范围的属性;
->setAttribute(String attrName, Object attValue):将attValue设置为request范围的属性attrName的值
->Object getAttribute(String attrName):获取request范围名为attrName的属性
当forward用户请求时,请求的参数和属性都不会丢失。(即可携带参数)
9.6.3. 执行foreard或include
->forward(ServletRequest request, ServletResponse response)
->include(ServletRequest request, ServletResponse response)
以上的两个方法都是先执行方法:getRequestDispatcher(String path)以后再调用。
9.7. response对象
out生成字符串响应。
response生成非字符串响应,还可用于重定向请求,以及用于向客户端增加cookie。
9.7.1. response响应生成非字符串响应
response是HttpServletResponse接口的实例,该接口提供了一个getOutputStream()方法,该方法返回响应输出字节流。
9.7.2. 重定向
与foward不同的是,重定向会丢失所有请求参数和request范围中的属性,因为重定向将生成第二次请求,与第一次请求不在同一个request范围内,所以导致第一次的所有请求参数和request范围中的属性丢失。
sendRedirect(String path)方法用于重定向到path资源。
forward与重定向的区别:
--------------------------------------------------------+------------------------------------------------------
转发(forward) | 重定向(redirect)
执行forward之后依然是上一次请求 |执行redirect之后生成第二次请求
原请求参数和request范围内的属性保留 |原请求参数和request范围内的属性丢失
地址栏的url不会变化 |地址栏的url变化
--------------------------------------------------------+-----------------------------------------------------
9.7.3. 增加cookie
Cookie通常用户网站记录客户的某些信息。
Cookie与session不同的是,session会随着浏览器的关闭而失效,而Cookie会一直保存在客户端机器上,除非超出了Cookie的生命周期。
response 的方法void addCookie(Cookie cookie)用于增加Cookie
*-?-* 详细介绍请百度 *-?-*
9.8. session对象
session对象代表一次会话,一次会话的含义是:从客户端浏览器链接服务器开始,到客户端浏览器与服务器断开为止。
session通常用于跟踪用户的会话信息,如判断用户是否登录系统,或者购物车是否存在商品等。
session范围内的数据可以在多个页面之间跳转共享。一旦浏览器关闭,即session结束,那么session范围中的属性也立即丢失。
session是HttpSession的实例,常用的方法有如下两个:
->setAttribute(String attName, Object attValue):设置session范围内的属性attName的值为attValue
->getAttribute(String attName):获取session范围内的名为attName的属性的值
考虑session本身的目的,通常只把与用户会话状态相关的信息放入session范围内。不要仅仅为了两个页面之间交换信息,就将该信息放入session范围内。如果仅仅是为了两个页面之间交换信息,可以将信息放入request范围内,然后forward请求即可。
session的属性值可以是任何可序列化的Java对象。
10.servlet介绍
JSP的本质就是Servlet,开发者把编写好的JSP部署到Web容器中之后,Web容器就会将JSP编译成对应的Servlet。
自从MVC规范出现以后,Servlet的责任开始明确下来,仅仅做为控制器使用。
10.1. Servlet的开发
Servlet通常被称为“服务器端小程序”,是运行在‘服务器端的程序’,用来处理来自客户端的请求及响应来自客户端的请求。
Servlet是个特殊的Java类,这个类必须继承HttpServlet。Servlet提供了不同的方法用于响应来自客户端的请求。
>>doGet:用于响应客户端的get请求
>>doPost:用于响应客户端的post请求
>>doPut:用于响应客户端的put请求
>>doDelete:用于响应客户端的delete请求
事实上,客户端的请求只有get和post两种,Servlet为了响应这两种请求,必须重写doGet()和doPost()两个方法。大部分的时候,Servlet对于所有的请求的响应都是完全一样的,可以采用重写一个方法来代替上面几个方法:只需要重写service()方法即可响应客户端的所有请求。
另外,HttpServlet还提供了两个方法:
>>init(ServletConfig config):创建Servlet实例时,调用该方法以初始化Servlet资源
>>destroy():销毁Servlet实例时,自动调用该方法回收资源
通常无需重写init()和destroy()方法。
Servlet和JSP的区别在于:
->Servlet中没有内置对象,JSP中的内置对象都是由程序显示创建的;
->对于静态的HTML标签,Servlet都必须使用输出流逐行输出。
普通Servlet类的service()方法的作用,完全等同于JSP生成Servlet类的_jspService()方法。
原JSP声明中的内容,对应生成的Servlet类中的成员变量和成员方法。
10.2. Servlet配置
编辑好的Servlet源文件并不能直接响应客户端的请求,还必须将其编译成class文件,放置在WEB-INF/classes路径下,并且在web.xml文件中配置Servlet。
配置Servlet有两种方法(只能选择其中一种配置,不能同时配置):
>>在Servlet类中使用 @WebServlet Annotation进行配置
>>通过在web.xml文件进行配置
10.2.1. 使用Annotation进行配置
注意两点:
->不要在web.xml文件的根元素(
->不要再web.xml文件中配置该Servlet
常用属性:
@WebServlet Annotation(
name//制定该Servlet的名称
asyncSupported//指定该Servlet是否支持异步操作模式
displayName//指定该Servlet的显示名
initParams//用于为该Servlet配置参数
loadOnStartup//用于将该Servlet配置成load-on-startup的Servlet
urlPatterns//指定该Servlet处理的URL
value//指定该Servlet处理的URL
)
10.2.2. 使用web.xml文件进行配置
两个部分:
10.3. JSP/Servlet的生命周期
开发者编写的JSP由Web容器编译成对应的Servlet后,运行在Web容器(服务器端)之中,其实例的创建和销毁由Web容器进行控制。
创建Servlet实例有两种时机:
->客户端第一次请求某个Servlet时,系统创建该Servlet的实例。(绝大部分Servlet采用这种)
->Web应用启动时立即创建Servlet实例,即:load-on-startup Servlet。
Servlet生命周期:
->创建Servlet实例
->Web容器调用Servlet的init()方法初始化Servlet
->Servlet初始化之后,一直存在于Web容器中,用于响应客户端的请求。客户端若是get请求,则调用doGet(),反之亦然 ...
->Web容器决定销毁Servlet,首先调用destroy()方法。通常在关闭Web应用之前销毁Servlet。
10.4. load-on-startup Servlet
应用启动时立刻创建Servlet,通常用于某些后台服务的Servlet,或者需要拦截很多请求的Servlet,这种Servlet通常作为应用的基础Servlet使用,提供重要的后台服务。
配置load-on-startup Servlet的两种方式;
->web.xml文件中通过
->@WebServlet Annotation的loadOnStartup属性指定(@WebServlet(loadOnStartup=1)单位是:min)
10.5. 访问Servlet的配置参数
配置Servlet时,还可以为Servlet添加其他的配置参数。方法有两种:
>>通过 @WebServlet的initParams属性来指定
>>通过web.xml文件的
访问Servlet配置参数的方法是通过ServletConfig对象完成的,ServletConfig对象提供以下方法:
>>java.lang.String getInitParameter(java.lang.String name):用于获取初始化参数
注意:JSP中的config内置对象就是这里的ServletConfig
【示例】:
@WebServlet:
@WebServlet(name="testServlet",
urlPatterns={"/testServlet"},
initParams={
@WebInitParam(name="driver", value="com.masql.jdbc.Driver"),
@WebInitParam(name="url", value="jdbc:masql://localhost:3306/javaee"),
@WebInitParam(name="username", value="root"),
@WebInitParam(name="password", value="root")
}
)
web.xml:
... ...
//获取ServletConfig对象
ServletConfig sConfig = getServletConfig();
//通过ServletConfig对象获取配置参数:driver、url、username、password
String driver = sConfig.getInitParameter("driver");
String url = sConfig.getInitParameter("url");
String username = sConfig.getInitParameter("username");
String password = sConfig.getInitParameter("password");
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, username, paaword);
... ...
ServletConfig是获取当前Servlet的配置参数,而ServletContext是获取整个Web应用的配置参数。
10.6. 使用Servlet作为控制器
使用Servlet作为表现层的工作量太大。
Java EE应用架构遵循MVC模式,所以Servlet仅作为控制器使用,JSP仅作为表现层使用。
使用JSP作为表现层有下面两个作用:
>>负责收集用户的请求参数
>>将应用的处理结果,状态参数呈现给用户
Servlet的作用类似于调度员,所有用户的请求都必须发送给Servlet,由Servlet调用Model来处理用户的请求,并调用JSP来呈现处理结果;或者Servlet直接调用JSP将应用的状态数据呈现给用户。
Model通常由JavaBean来充当,所有的业务逻辑、数据访问逻辑都在Model中实现。实际上隐藏在Model下的可能还有很多丰富的组件:例如DAO组件,POJO组件... ...
控制器负责接收客户端的请求,他既不能直接对客户端输出响应,也不能处理请求,只能调用JavaBean来处理用户请求。
11.JSP2的自定义标签
11.1. 使用标签库
在JSP页面中确定制定的标签库需要两点;
>>标签库uri:确定使用哪个标签库
>>标签名:确定使用哪个标签
使用标签库需要两个步骤:
>>导入标签库:使用taglib编译指令导入标签库
>>使用标签:在JSP页面中使用自定义标签
<%@ taglib uri="tagliburi" prefix="tagPrefix" %>
12.Filter介绍
Filter可以认为是Servlet的一种“加强版”,他主要对用户的请求HttpServletRequest进行预处理,也可以对响应HttpServletResponse进行后处理,是一个典型的处理链。
使用Filter完整的流程是:Filter对用户的请求进行预处理,接着将预处理后的请求交给Servlet进行处理并生成响应,最后Filter再对服务器进行后处理。
Filter有如下几个用处:
>>在HttpServletRequest到达Servlet之前,拦截来自客户的HttpServletRequest
>>根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据
>>在HttpServletResponse到达客户端之前,拦截来自服务器的HttpServletResponse
>>根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据
Filter有如下几个种类;
>>用户授权的Filter:该Filter负责检查用户请求,过滤用户的非法请求
>>日志Filter:详细记录某些特殊的用户请求
>>负责解码的Filter:包括对非标准编码的请求解码
>>能改变XML内容的XSLT Filter等
>>一个Filter可以负责拦截多个请求或响应:一个请求或响应也可以被多个Filter拦截
创建一个Filter只需要两步:
>>创建一个Filter处理类
>>在web.xml文件中配置该Filter
12.1. 创建Filter类
创建Filter必须实现javax.servlet.Filter接口。该接口中定义了如下三个方法:
->void innit(FilterConfig config):用于完成Filter的初始化
->void destroy():用于Filter销毁前,完成某些资源的回收
->void doFilter(ServletRequest request, ServletResponse response, FilterChain chain):实现过滤功能
12.2. 配置Filter
配置Filter有如下两个部分:
>>配置Filter名
>>配置Filter拦截URL模式
配置Filter和Servlet的无别在于:Servlet通常只需要配置一个URL,而Filter可以同时拦截多个请求的URL。因此,在配置Filter的URL模式时通常采用模式字符串,使得Filter可以拦截多个请求。
配置Filter有如下两种方式:
>>在Filter类中通过Annotation进行配置
>>在web.xml文件中进行配置
12.2.1. 使用Annotation进行配置
注意两点:
->不要在web.xml文件的根元素(
->不要再web.xml文件中配置该Servlet
常用属性:
@WebFilter Annotation(
name//制定该Filter的名称
dispatcherTypes//制定该Filter仅对那种dispatcher模式的请求进行过滤
asyncSupported//指定该Filter是否支持异步操作模式
displayName//指定该Filter的显示名
initParams//用于为该Filter配置参数
servletNames//指定该Filter仅对这几个Servlet执行过滤
urlPatterns//指定该Filter处理的URL
value//指定该Filter处理的URL
)
12.2.2. 使用web.xml文件进行配置
两个部分:
实际上,Filter和Servlet极其相似,只是Filter的doFilter()方法中多了一个FilterChain的参数,通过该参数可以控制是否放行用户的请求。在实际项目开发中,Filter里doFilter()方法中的代码就是从多个Servlet的service()方法里面抽取的通用代码,通过使用Filter可以提高代码的复用性。
由于Filter和Servlet极其相似,所以Filter具有和Servlet相同的生命周期行为。
Filter也可以通过
12.3. 使用 URL Rewrite 实现网站的伪静态
为什么要使用伪静态网站?
对于以JSP为表现层开发的动态网站来说,用户访问的URL通常是如下形式:
xxx.jsp?param=value...
大部分搜索引擎都会优先收集静态HTML页面,而不是这种动态的*.jsp、*.php页面,所以大部分网站都会考虑使用伪静态。
对于Java Web应用而言,如何实现网站伪静态?
可以通过Filter拦截所有发向*.html的请求,然后按照某种规则将请求forward(转发)到实际的*.jsp或*.php页面即可。
可以使用《URL Rewrite》实现网站的伪静态,具体参见网络。
上一篇: jsp内置对象pageContext如何在Servlet中获取值?
下一篇: JSP页面的访问控制