您的位置:首页 > Web前端 > JavaScript

【S2HS学习笔记】第二章节:JSP/Servlet及相关技术详解

2016-05-10 15:06 513 查看
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=-

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee"
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd
version="3.0">

</web-app>

(5):在WEB-INF路径下,新建两个文件夹:classes和lib,这两个文件夹的作用完全一样:都是保存Web应用所需要的Java类文件,区别是classes保存单个*.class文件,而lib保存打包后的JAR文件。

经过以上五个步骤已经建立了一个空的Web应用。将该Web应用复制到Tomcat的webapps路径下,该Web应用将可以自动部署在Tomcat中。

通常我们只需要将JSP放在Web应用的根目录下,然后就可以通过浏览器来访问这些页面了。

根据以上的介绍,我们可以发现Web应用应该具有以下的文件结构:

<webDemo>————这是Web应用的名称(名称可以改变)

|—WEB-INF

| |—classes

| |—lib

| |—web.xml

|—<a.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文件的根元素是<web-app.../>元素。

在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"%>

如果嵌入的文件经常需要更换,建议使用<jsp:include>操作指令,因为它是动态的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<String> getHeaderNames():获取所有请求头的名称

-> java.util.Enumeration<String> 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文件的根元素(<web-app.../>)中指定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文件进行配置

两个部分:

<servlet>

<!-- 指定Servlet的名称 -->

<servlet-name>... ...</servlet-name>

<!-- 指定Servlet的实现类 -->

<servlet-class>... ...</servlet-class>

</servlet>

<servlet-mapping>

<!-- 指定Servlet的名称 -->

<servlet-name>... ...</servlet-name>

<!-- 指定Servlet映射的URL地址 -->

<url-pattern>/... ...</url-pattern>

</servlet-mapping>

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文件中通过<servlet.../>元素的<load-on-startup.../>子元素进行配置

-> @WebServlet Annotation的loadOnStartup属性指定(@WebServlet(loadOnStartup=1)单位是:min)

10.5. 访问Servlet的配置参数

配置Servlet时,还可以为Servlet添加其他的配置参数。方法有两种:

>> 通过 @WebServlet的initParams属性来指定

>> 通过web.xml文件的<servlet.../>元素中添加<init-param.../>子元素来指定

访问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:

<servlet>

<init-param>

<param-name>driver</param-name>

<param-value>com.masql.jdbc.Driver</param-value>

</init-param>

</servlet>

... ...

//获取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" %>

<!-- 其中uri确定一个标签库,prefix属性指定标签库的前缀 -->

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-app.../>)中指定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>

<!-- 指定filter的名称 -->

<filter-name>... ...</filter-name>

<!-- 指定filter的实现类 -->

<filter-class>... ...</filter-class>

</filter>

<filter-mapping>

<!-- 指定filter的名称 -->

<filter-name>... ...</filter-name>

<!-- 指定filter需要拦截的URL -->

<url-pattern>/... ...</url-pattern>

</filter-mapping>

实际上,Filter和Servlet极其相似,只是Filter的doFilter()方法中多了一个FilterChain的参数,通过该参数可以控制是否放行用户的请求。在实际项目开发中,Filter里doFilter()方法中的代码就是从多个Servlet的service()方法里面抽取的通用代码,通过使用Filter可以提高代码的复用性。

由于Filter和Servlet极其相似,所以Filter具有和Servlet相同的生命周期行为。

Filter也可以通过<init-param.../>元素或 @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》实现网站的伪静态,具体参见网络。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: