BS架构
B/S结构
- 使用B/S结构的程序,在开发时只需要开发服务器端即可,这种结构的优势在于开发的压力比较小,不需要维护客户端。工作中用的主要也是这类开发模式。
- b/s结构下是基于浏览器的,绝大多数的Web开发,都是构建在HTTP协议之上的Web应用。
HTTP协议
协议、请求与应该参照上一部分内容
-
思考问题:
1.服务端如何获取到客户端请求的版本信息?
2.服务端如何获取客户端请求的IP?
一般获取客户端的IP地址的方法是:request.getRemoteAddr();但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。
原因:由于在客户端和服务之间增加了中间代理,因此服务器无法直接拿到客户端的IP,服务器端应用也无法直接通过转发请求的地址返回给客户端。 -
接着我们来看一下http请求头,X-Forwarded-For 是一个 HTTP 扩展头部,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP
X-Forwarded-For: client, proxy1, proxy2
可以看到,XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。
如果一个 HTTP 请求到达服务器之前,经过了三个代理 Proxy1、Proxy2、Proxy3,IP 分别为 IP1、IP2、IP3,用户真实 IP 为 IP0,那么按照 XFF 标准,服务端最终会收到以下信息:
X-Forwarded-For: IP0, IP1, IP2
Proxy3 直连服务器,它会给 XFF 追加 IP2,表示它是在帮 Proxy2 转发请求。列表中并没有 IP3,IP3 可以在服务端通过 Remote Address 字段获得。我们知道 HTTP 连接基于 TCP 连接,HTTP 协议中没有 IP 的概念,Remote Address 来自 TCP 连接,表示与服务端建立 TCP 连接的设备 IP,在这个例子里就是 IP3。
这里需要注意的是Remote Address 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求。
那么我们来看一个实际例子, 在直接访问服务,不经过代理服务器的情况下:
curl http://t1.imququ.com:9009/ -H ‘X-Forwarded-For: 1.1.1.1’ -H ‘X-Real-IP: 2.2.2.2’
remoteAddress: 114.248.238.236
x-forwarded-for: 1.1.1.1
x-real-ip: 2.2.2.2如果我们通过nginx访问服务,并且在nginx增加了如下配置:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
那么我们得到的请求头是这样的:
curl http://t1.imququ.com/ -H ‘X-Forwarded-For: unknown, <>”1.1.1.1’
remoteAddress: 127.0.0.1
x-forwarded-for: unknown, <>”1.1.1.1, 114.248.238.236
x-real-ip: 114.248.238.236如果用户真的是通过代理访问 Nginx,
X-Forwarded-For
最后一节以及X-Real-IP
得到的是代理的 IP,安全相关的场景只能用这个,但有些场景如根据 IP 显示所在地天气,就需要尽可能获得用户真实 IP,这时候X-Forwarded-For
中第一个 IP 就可以派上用场了,可以认为是用户IP,但须获取后验证IP格式后才能使用,否则可能会有SQL 注入或 XSS 等安全漏洞问题。 -
需要注意的是X-Forwarded-For和X-Real-IP都不是http的正式协议头,而是squid等反向代理软件最早引入的,之所以tomcat能拿到,是因为NGINX里一般缺省都会这么配置转发的http请求:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
PS:如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串ip值,究竟哪个才是真正的用户端的真实IP呢?
答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130, 192.168.1.100
用户真实IP为: 192.168.1.110
html与javascript
html(超文本标记语言)结构包括“头”部分(英语:Head)、和“主体”部分(英语:Body),其中“头”部提供关于网页的信息,“主体”部分提供网页的具体内容。
常用标签:a form img table button等等.
JavaScript一种直译式脚本语言,广泛用于客户端的脚本语言,最早是在HTML(标准通用标记语言下的一个应用)网页上使用,用来给HTML网页增加动态功能。
cookie
由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
注意:Cookie功能需要浏览器的支持。如果浏览器不支持Cookie(如大部分手机中的浏览器)或者把Cookie禁用了,Cookie功能就会失效。
Cookie具有不可跨域名性.
Cookie具有很多属性,比如domain(可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”,否则只有默认的域能访问);
Cookie的maxAge决定着Cookie的有效期,单位为秒(Second)。Cookie默认的maxAge值为–1。
详细面试题可参考不要再问我cookie了
1.Cookie是什么?★☆
2.Cookie能做什么?★☆
3.Cookie是怎么分类的?★☆
4.Cookie的工作原理?★★★
5.Cookie是怎么存储的?★☆
6.每次访问网站时,是不是将所有的cookie都发送所有的站点?★
7.cookie与缓存怎么取舍?★★
8.cookie的缺点?★★
9.如何使用cookie?★★★
几点需要强调:
- cookie是什么:浏览器端存储的,服务器特有的一些信息。
- cookie的原理(影射到网站的自动登录):
- 用户首次访问网站,Web一无所知
- Web服务器通过Set-Cookie,将cookie存放到浏览器中(自己域名下),内容一般是服务器给每个浏览器创建的一个特定的识别码
- 将来用户再次访问同一站点,浏览器会将特定信息再传回服务器,这时让服务器能够识别该浏览器
- 于是,服务器端就可以通过这种操作,积累用户的持续行为,比如购物历史或者人物肖像等。
- cookie特点:
- Cookie具有不可跨域名性
- Cookie具有很多属性
- Cookie过期时间设定
java web基础讲解
java web应用结构
Java Web应用的核心技术是Java Server Page和Servlet。此外,开发一个完整的Java Web应该涉及一下几种概念及技术。java web应用的结构如下
Servlet组件
Servlet运行于Servlet容器中,可以被Servlet容器动态加载,来扩展服务器的功能,并提供特定的服务。Servlet按照请求/响应的方式工作。
Servlet响应用户请求的过程:
jsp组件
在传统的HTML文件中加入Java程序片段和JSP标签,就构成了JSP网页。
当JSP容器接收到Web用户的一个JSP文件请求时,它对JSP文件进行语法分析并生成Java Servlet源文件,然后对其编译。一般情况下。Servlet源文件的生成和编译仅在初次调用JSP时发生。如果原始的JSP文件被更新,JSP容器将检测所做的更新,在执行它之前重新生成Servlet并进行编译。
JSP容器初次执行JSP的过程:
共享数据在Web应用中的范围
共享数据在Web应用中的范围:
- Page:共享数据的有效范围是用户请求访问的当前页面。
- Request:共享数据的有效范围为“用户请求访问的当前Web组件,以及和当前Web组件共享同一个用户请求的其他Web组件。
- Session:共享数据存在于整个HTTP会话的生存周期内,同一个HTTP会话中的Web组件共享它。Session范围内的共享数据实际上是存放在HttpSession对象中。 session失效方法【客户端关闭浏览器后会话过期;服务器端调用了HttpSession的invalidate()方法 】
- Application:共享数据存在月整个Web应用的生命周期内,Web应用中的所有Web组件都能共享它,共享数据实际上存放在ServletCntext对象中。
javabean组件
JavaBean是一种符合特定规范的JAVA 对象。在JAVABean中定义了一系列的属性,并提供了访问和设置这些属性的公用方法。JavaBean可以作为共享数据,存放在page,request,session,application范围内。在JSP文件中,可以通过专门的标签来定义和范围JavaBean。如:
<jsp:useBean id="calendar" scope="page/request/session/application" class="employee.Calendar" />
<h2>
Calendar of <jsp:getProperty name="calendar" property="username" />
</h2>
JSP标签
JSTL全名JspServer Pages Standdard Tag Library(Jsp标准标签库),它是sun公司发布的一个针对JSP开发的新组件,它允许使用标签开发Jsp页面.
JSTL是一个标准的已制定好的标签库,它可以应用到很多领域. 如:基本输入输出、流程控制、循环、XML文件剖析、数据库查询及国际化和文字格式标准化的应用等。
JSTL所提供的标签库主要分为五大类:
JSTL | 前置名称 | URI | 范例 |
---|---|---|---|
核心标签库 | c | http://java.sun.com/jsp/jstl/core | |
I18N格式标签库 | fmt | http://java.sun.com/jsp/jstl/fmt | |
SQL标签库 | sql | http://java.sun.com/jsp/jstl/sql | |
XML标签库 | Xml | http://java.sun.com/jsp/jstl/xml | |
函数标签库 | fn | http://java.sun.com/jsp/jstl/functions |
很多框架也提供了各自的标签库,我们也可以直接自定义标签
EJB组件
EJB组件是基于标准分布式对象技术,CORBA和RMI的服务端JAVA组件,EJB组件和JavaBean组件一样,都用于实现企业应用的业务逻辑,它们的根本区别在于,EJB组件总是分布式的,EJB组件运行于EJB服务器中,而JavaBean组件可以和Servlet或JSP运行于同一JAVA虚拟机中。
EJB组件太重,实际项目中已经被淘汰,实际项目都是基于JavaBean来实现分布式的。
XML语言
XML文件常用于做各种软件应用的配置文件,比如web.xml用于配置Web应用
Web服务器和应用服务器
比如Tomcat,Resin等
Web组件的三种关联关系
Web组件的三种关联关系:
- 请求转发
- URL重定向
- 包含
请求转发
请求转发允许把请求转发给同一应用中的其他Web组件。这种技术通常用于Web应用控制层的Servlet流程控制器,它检查HTTP请求数据,并将请求转发到合适的目标组件,目标组件执行具体的请求处理操作,并生成响应结果。
一个Servlet把请求转发给另一个JSP组件的过程:
如果在Servlet组件转发请求给一个JSP组件,可以在Servlet的service()
方法中执行以下代码:
request.getRequestDispatcher("hello.jsp").forward(request.response);
如果在JSP页面中,可以使用标签来转发请求,例如:
<jsp:forward page=”hello.jsp”/>
对于请求转发,转发的源组件和目标组件共享request范围内的数据。
URL重定向
请求重定向类似请求转发,但是有一些重要区别:
Web组件可以将请求重定向到任一URL,而不进进是同一应用中的URL。
重定向的元组件和目标组件之间不共用同一个HttpServletRequest对象,因此不能共享request范围内的共享数据。
显示一个Servlet把请求重定向给另一个JSP组件的过程:
如果当前应用的Servlet组件要把请求转发给URL。可以在Servlet.service()
方法中执行:
response.sendRedirect(URL);
如果在JSP页面中,可以使用标签来重定向
<c:redirect url="url"/>
URL重定向后用户浏览器看到的地址会变化
包含
包含关系允许一个Web组件聚集来自同一个应用中的其他Web组件的输出数据,并使用被聚集的数据来创建响应结果。这种技术通常用于模板处理器,它可以控制网页的布局。模板中每个页面区域的内容都来自不同的URL,从而组成单个页面。
显示了一个Servlet包含另一个JSP��件的过程:
Servlet类使用javax.servlet.RequestDispatcher.include()方法包含其他的Web组件。
例如:当前Servlet组件包含了JSP文件:header.jsp,则在Servlet.service()
方法中执行如下代码:
req.getRequestDispatcher("/header.jsp").include(req,res);
在JSP文件中,可以通过指令来包含其他的Web资源,例如:
<%@include file="file url"%>
JSP动作
<jsp:include page="file url" flush="true|false"/>
【jsp 静态引用和动态引用的区别】:
- 静态:先包含再执行。包含的页面发生变化时包含页面将重新编译。
- 动态:先执行页面代码,再包含页面。包含页面发生变化时不重新编译。
java web项目目录结构
一个Java Web项目要运行,它首先要放在tomcat之类的容器中,该JavaWeb项目的构成一定要包含下面几种文件以及文件夹:
- META-INF : 存放一些meta information相关的文件的这么一个文件夹, 一般来说尽量不要自己手工放置文件到这个文件夹。
- WEB-INF
- classes:用于存放java字节码文件
- lib:用于存放该工程用到的库,例如servlet-api.jar等等
- web.xml:web工程的配置文件,完成用户请求的逻辑名称到真正���servlet类的映射
- JSP文件以及静态资源文件
【备注,如果有自定义文件的话,也是放在WEB-INF下面,目录名称是tags】
一般结构如下:
Servlet和HTTP的对应关系
- Servlet 是 J2EE 最重要的一部分,有了 Servlet 你就是 J2EE 了,J2EE 的其他方面的内容择需采用。而 Servlet 规范你需要掌握的就是 servlet 和 filter 这两项技术。绝大多数框架不是基于 servlet 就是基于 filter,如果它要在 Servlet 容器上运行,就永远也脱离不开这个模型。另外Listener也需要了学会。
- 为什么 Servlet 规范会有两个包,javax.servlet 和 javax.servlet.http ,早先设计该规范的人认为 Servlet 是一种服务模型,不一定是依赖某种网络协议之上,因此就抽象出了一个 javax.servlet ,同时在提供一个基于 HTTP 协议上的接口扩展。但是从实际运行这么多年来看,似乎没有发现有在其他协议上实现的 Servlet 技术。
Servlet介绍
Servlet生命周期
Servlet也遵循严格的生命周期。在每个Servlet实例的生命中有三种类型的事件,这三种事件分别对应于由Servlet引擎所唤醒的三个方法:
-
init()。当Servlet第一次被装载时,Servlet引擎调用这个Servlet���init()方法,只调用一次。如果某个Sevlet需要特殊的初始化需要。那么Servlet编写人员可以重写该方法来执行初始化任务。这是一个可选的方法。如果某个Servlet不需要初始化,那么默认情况下将调用它父类的init方法。系统保证,在init方法成功完成以前,是不会调用Servlet去处理任何请求的。
-
service()。这是Servlet最重要的方法,是真正处理请求的地方。对于每个请求,Servlet引擎将调用Servlet的service方法,并把Servlet请求对象和Servlet响应对象最为参数传递给它。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。
-
destroy()。这是相对于init的可选方法,当Servlet即将被卸载时由Servlet引擎来调用,这个方法用来清除并释放在init方法中所分配的资源。
怎样理解Servlet的单实例多线程
不同的用户同时对同一个业务(如注册)发出请求,那这个时候容器里产生的有是几个servlet实例呢?
答案是:只有一个servlet实例。一个servlet是在第一次被访问时加载到内存并实例化的。同样的业务请求共享一个servlet实例。不同的业务请求一般对应不同的servlet。由于Servlet/JSP默认是以多线程模式执行的,所以,在编写代码时需要非常细致地考虑多线程的安全性问题。
servlet、genericservlet、httpservlet之间的区别
GenericServlet 是一个抽象类,实现了 Servlet 接口,并且对其中的 init() 和 destroy() 和 service() 提供了默认实现。在 GenericServlet 中,主要完成了以下任务:
- 将 init() 中的 ServletConfig 赋给一个类级变量,可以由 getServletConfig 获得;
- 为 Servlet 所有方法提供默认实现;
- 可以直接调用 ServletConfig 中的方法;
HttpServlet 也是一个抽象类,它进一步继承并封装了 GenericServlet,使得使用更加简单方便,由于是扩展了 Http 的内容,所以还需要使用 HttpServletRequest 和 HttpServletResponse,这两个类分别是 ServletRequest 和 ServletResponse 的子类。
常见对象
-
ServletConfig对象
getServletName(); //获取servlet的名称,也就是我们在web.xml中配置的servlet-name getServletContext(); //获取ServletContext对象,该对象的作用看下面讲解 getInitParameter(String); //获取在servlet中初始化参数的值。这里注意与全局初始化参数的区分。这个获取的只是在该servlet下的初始化参数
在GenericServlet中,已经帮我们获取了这些数据,所以可以不用先获得ServletConfig,然后在获取其各种参数,可以直接使用其方法,比如上面我们用的ServletConfig().getServletName();可以直接写成getServletName()
-
ServletContext对象
tomcat为每个web项目都创建一个ServletContext实例,tomcat在启动时创建,服务器关闭时销毁,在一个web项目中共享数据,管理web项目资源,为整个web配置公共信息等,通俗点讲,就是一个web项目,就存在一个ServletContext实例,每个Servlet读可以访问到它。
1. web项目中共享数据,getAttribute(String name)、setAttribute(String name, Object obj)、removeAttribute(String name) - setAttribute(String name, Object obj) 在web项目范围内存放内容,以便让在web项目中所有的servlet读能访问到 - getAttribute(String name) 通过指定名称获得内容 - removeAttribute(String name) 通过指定名称移除内容 2. 整个web项目初始化参数 - getInitPatameter(String name) //通过指定名称获取初始化值 - getInitParameterNames() //获得枚举类型 3. 获取web项目资源 - 获取web项目下指定资源的路径:getServletContext().getRealPath(“/WEB-INF/web.xml”) - 获取web项目下指定资源的内容,返回的是字节输入流。InputStream getResourceAsStream(java.lang.String path)
-
request对象
我们知道,request就是将请求文本封装而成的对象,所以通过request能获得请求文本中的所有内容,请求头、请求体、请求行
其中获取请求头、请求体和请求行的api就不赘述了。
request.getRequestDispatcher("/2.html").forward(request, response); //path:转发后跳转的页面,这里不管用不用"/"开头,都是以web项目根开始,因为这是请求转发,请求转发只局限与在同一个web项目下使用,所以这里一直都是从web项目根下开始的。
转发特点:浏览器中url不会改变,也就是浏览器不知道服务器做了什么,是服务器帮我们跳转页面的,并且在转发后的页面,能够继续使用原先的request,因为是原先的request,所以request域中的属性都可以继续获取到。
-
response对象
这里最重要的一个常用方法是重定向,往往和请求转发放在一起问。
重定向(页面跳转):
response.sendRedirect("http://www.baidu.com");
特点:服务器告诉浏览器要跳转的页面,是浏览器主动去跳转的页面,浏览器知道,也浏览器的地址栏中url会变,是浏览器重新发起一个请求到另外一个页面,所以request是重新发起的,跟请求转发不一样。
注意:response.sendRedirect(path);
第一种:response.sendRedirect(“/test01/MyServlet01”); //使用了”/“开头,说明是从web站点根开始,所以需要写test01/MyServlet01 第二种:response.sendRedirect(“MyServlet01”); //没有使用”/“开头,说明不是从web项目根开始,那么就无需写test01了。
重定向没有任何局限,可以重定向web项目内的任何路径,也可以访问别的web项目中的路径,并且这里就用”/“区分开来,如果使用了”/“开头,就说明我要重新开始定位了,不访问刚才的web项目,自己写项目名,如果没有使用”/“开始,那么就知道是访问刚才那个web项目下的servlet,就可以省略项目名了。就是这样来区别。
Spring中的请求分发
从图中可以看到 web 服务器此时已经不用考虑分发请求的问题了,它只需要把请求发送给 DispatcherServlet 即可。请求分发的任务将落到 DispatcherServlet 身上。
而 DispatchServlet 也不再是把请求分发给其他 Servlet,而是根据请求路径分发给对应的 Controller,然后再分发到 Controller 中对应的处理方法。
下面给出一个迷你简写版的 DispatchServlet 代码:
public class DispatcherServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
for(MappingHandler mappingHandler : HandlerManager.mappingHandlerList){
try{
if (mappingHandler.handle(servletRequest, servletResponse)){
return;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {}
}
从上面的代码可以看到 DispatcherServlet 处理请求的逻辑也很简单,就是根据请求路径找到对应可以处理的处理器。
至于 MappingHandler 是怎么初始化的,这就涉及到 Spring 框架中控制反转和依赖注入的知识了。简单来说就是,在开发的过程中,我们不再把请求路径配置在 web.xml 里面,而是通过注解的方式配置在每一个个处理方法的上方。当 spring 框架启动后,会根据注解把每个处理方法初始化为一个个 MappingHandler(里面包括请求路径和处理逻辑),供 DispatcherServlet 调配使用。
方法上面的注解,类似如下,加载后生成MappingHandler
@RequestMapping("/ability/showAssessContent.do")
@PostMapping("clazz/list/custom")
这样的请求分发方式无疑比 Serlvet 时期的请求分发更加灵活,强大。它把请求分发的工作从 web 服务器上移植到框架中,可扩展性更强。而且配合 spring 框架的控制反转机制,把处理逻辑类的初始化及生命周期控制交给框架管理,更加安全高效。
Filter和Listener
Filter介绍
过滤器:可以在一个请求到达servlet之前,将其截取进行逻辑判断,然后决定是否放行到请求的servlet
应用场景:
- 用户授权 - 负责判断用户是否有权限请求该页面,给予过滤判断
- 日志 - 截取某个用户在本网站上的所有请求,记录轨迹
- 负责解码 - 规定处理本次请求的解码方式
ServletAPI中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。
通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。简单说,就是可以实现web容器对某资源的访问前截获进行相关的处理,还可以在某资源向web容器返回响应前进行截获进行处理。
下图是filter调用关系的UML图:
一个filter必须实现javax.servlet.Filter。实现init,doFilter,destroy方法
filter常常用于网站过滤敏感词汇、设置字符集、日志等比较“公共性”的事件处理中。
Filter实现拦截的原理
Filter接口中有一个doFilter方法,当开发人员编写好Filter类实现doFilter方法,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前(服务器内部对资源的访问机制决定的),都会先调用一下filter的doFilter方法。
对于FilterChain接口,代表当前Filter链的对象。由容器实现,容器将其实例作为参数传入过滤器对象的doFilter()方法中。
过滤器对象使用FilterChain对象调用过滤器链中的下一个过滤器,或者目标Servlet 程序去处理,也可以直接向客户端返回响应信息,或者利用RequestDispatcher的forward()和include()方法,以及HttpServletResponse的sendRedirect()方法将请求转向到其他资源。
这个方法的请求和响应参数的类型是 ServletRequest和ServletResponse,也就是说,过滤器的使用并不依赖于具体的协议。
Filter生命周期
Servlet一样,Filter的创建和销毁也是由WEB服务器负责。不同的是:
- 在应用启动的时候就进行装载Filter类而servlet是在请求时才创建(但filter与Servlet的load-on-startup配置效果相同)。
- 容器创建好Filter对象实例后,调用init()方法。接着被Web容器保存进应用级的集合容器中去了等待着,用户访问资源。
- 当用户访问的资源正好被Filter的url-pattern拦截时,容器会取出Filter类调用doFilter方法,下次或多次访问被拦截的资源时,Web容器会直接取出指定Filter对象实例调用doFilter方法(Filter对象常驻留Web容器了)。
- 当应用服务被停止或重新装载了,则会执行Filter的destroy方法,Filter对象销毁。
Filter解疑
Filter其实就是AOP的思想,即面向切面编程。之前讲的基于反射的动态代理,也是一种符合AOP的一种提现。动态代理和Filter处理问题的区别在哪里呢?
从表现形式上来说,两者确实很相似,同样可以在你写的jsp、servlet代码的前后加入其它的动作,但是两者是有本质区别的:
- filter基于回调函数,我们需要实现的 filter接口中doFilter方法就是回调函数,而动态代理则基于java本身的反射机制,如果对这种形式不了解,可以去看看动态代理实现过程,这是aop的基础。这是两者最本质的区别。
- filter是依赖于servlet容器的,即只能在servlet容器中执行,很显然没有servlet容器就无法来回调doFilter方法。而动态代理与servlet容器无关。
Java监听器Listener使用说明
监听器也叫Listener,是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。
Listener接口分类
- ServletContextListener监听ServletContext对象
- ServletContextAttributeListener监听对ServletContext属性的操作,比如增加、删除、修改
- HttpSessionListener监听Session对象
- HttpSessionActivationListener监听HTTP会话的active和passivate情况,passivate是指非活动的session被写入持久设备(比如硬盘),active相反。
- HttpSessionAttributeListener监听Session中的属性操作
- ServletRequestListener监听Request对象
- ServletRequestAttributeListener监听Requset中的属性操作
javax.servlet 和 javax.servlet.http 核心类
javax.servlet 和 javax.servlet.http 这两个包总共加起来也不过是三十四个接口和类,你熟知每个类和接口的具体意思。特别是下面几个接口必须熟知每个方法的意思和用途:
- HttpServlet
- ServetConfig
- ServletContext
- Filter
- FilterConfig
- FilterChain
- RequestDispatcher
- HttpServletRequest
- HttpServletResponse
- HttpSession
- 一些 Listenser 类