JAVAEE
JAVAEE
J2EE简介
JavaEE(Java Enterprise Edition )是一个用于企业级web开发平台。最早由Sun公司定制并发布,后由Oracle负责维护。JavaEE平台规范了在开发企业级web应用中的技术标准。
在JavaEE平台共包含了13个技术规范(随着JavaEE版本的变化所包含的技术点的数量会有增多)。它们分别是:JDBC、JNDI、EJB、RMI、Servlet、JSP、XML、JMS、Java IDL、JPA、JTA、JavaMail和JAF。

各版本变化:

JavaEE应用服务器(JavaEE Application Server)
应用服务器是JavaEE规范的具体实现,可以执行/驱动基于JavaEE平台开发的web项目。绝大部分的应用服务器都是付费产品。
常见的应用服务:
| 应用服务 | 公司 | 收费情况 |
|---|---|---|
| Weblogic | Oracle | 收费 |
| Webshpere | IBM | 收费 |
| JBoss | RedHad | 收费 |
| Resin | Caucho | 收费 |
| JRun | BEA Oracle | 收费 |
| Weblogic | Macromedia | 收费 |
Web容器(Web Server)
只实现了JavaEE平台下部分技术标准,如Servlet,Jsp,JNDI,JavaMail。Web容器是开源免费的。
| 应用服务 | 公司 | 收费情况 |
|---|---|---|
| Tomcat | Apache | 开源免费 |
| Jetty | Jetty | 开源免费 |
HTTP
HTTP协议
超文本传输协议:超文本是用超链接的方法,将各种不同空间的文字信息组织在一起的网状文本。超文本更是一种用户界面范式,用以显示文本及与文本之间相关的内容。(html页面上全是文字,但是浏览器解析之后,展现出来的页面是非常丰富的。)
HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,HTTP是万维网(WWW:World Wide Web)的数据通信的基础。
HTTP是一个简单的请求 - 响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。
HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件,图片文件,查询结果等)
Http协议特点:
支持客户/服务器模式
HTTP协议支持客户端服务端模式,需要使用浏览器作为客户端来访问服务端。
简单快速
客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、POST等。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
灵活
HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type(Content-Type是HTTP包中用来表示内容类型的标识)加以标记。
无连接
每次请求一次,释放一次连接。所以无连接表示每次连接只能处理一个请求。优点就是节省传输时间,实现简单。我们有时称这种无连接为短连接,对应的就有了长链接,长连接专门解决效率问题。当建立好了一个连接之后,可以多次请求。但是缺点就是容易造成占用资源不释放的问题。当HTTP协议头部中字段Connection:keep-alive表示支持长链接。
单向性
服务端永远是被动的等待客户端的请求。
无状态
HTTP协议是无状态协议,无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。为了解决HTTP协议无状态,于是,两种用于保持HTTP连接状态的技术就应运而生了,一个是Cookie,而另一个则是Session。
HTTP版本
Http1.0
最早在1996年在网页中使用,内容简单,所以浏览器的每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立即断开TCP连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态),请求只能由客户端发起(单向性)。
Http1.1
到1999年广泛在各大浏览器网络请求中使用,HTTP/1.0中默认使用Connection: close。在HTTP/1.1中已经默认使用Connection:keep-alive(长连接),避免了连接建立和释放的开销,但服务器必须按照客户端请求的先后顺序依次回送相应的结果,以保证客户端能够区分出每次请求的响应内容。通过Content-Length字段来判断当前请求的数据是否已经全部接收。不允许同时存在两个并行的响应。
HTTP1.1中最重要的一个特点是支持“长连接”,即“一次连接可以多次请求”。

HTTP1.1支持持久连接(HTTP/1.1的默认模式使用带流水线的持久连接),在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。一个包含有许多图像的网页文件的多个请求和应答可以在一个连接中传输,但每个单独的网页文件的请求和应答仍然需要使用各自的连接。HTTP1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间。
Http2.0
长连接
在HTTP/2中,客户端向某个域名的服务器请求页面的过程中,只会创建一条TCP连接,即使这页面可能包含上百个资源。单一的连接应该是HTTP2的主要优势,单一的连接能减少TCP握手带来的时延。HTTP2中用一条单一的长连接,避免了创建多个TCP连接带来的网络开销,提高了吞吐量。
多路复用(Multiplexing)
HTTP2.0中所有加强性能的核心是二进制传输,在HTTP1.x中,我们是通过文本的方式传输数据。在HTTP2.0中引入了新的编码机制,所有传输的数据都会被分割,并采用二进制格式编码。

多路复用,连接共享。不同的request可以使用同一个连接传输(最后根据每个request上的id号组合成正常的请求)。
HTTP2.0中,有两个概念非常重要:帧(frame) 和流(stream) 。
帧是最小的数据单位,每个帧会标识出该帧属于哪个流,流是多个帧组成的数据流。所谓多路复用,即在一个TCP连接中存在多个流,即可以同时发送多个请求,对端可以通过帧中的表示知道该帧属于哪个请求。在客户端,这些帧乱序发送,到对端后再根据每个帧首部的流标识符重新组装。通过该技术,可以避免HTTP旧版本的队头阻塞问题,极大提高传输性能。

首部压缩(Header Compression)
由于1.1中header带有大量的信息,并且得重复传输,2.0使用encoder来减少需要传输的hearder大小。
服务端推送(Server Push)
在HTTP2.0中,服务端可以在客户端某个请求后,主动推送其他资源。可以想象一下,某些资源客户端是一定会请求的,这时就可以采取服务端push的技术,提前给客户端推送必要的资源,就可以相对减少一点延迟时间。在浏览器兼容的情况下也可以使用prefetch。
更安全
HTTP2.0使用了tls的拓展ALPN做为协议升级,除此之外,HTTP2.0对tls的安全性做了近一步加强,通过黑名单机制禁用了几百种不再安全的加密算法。
协议 传输格式 多路复用 部首压缩 服务器推送 请求优先级 http1.1 文本 × × × × http2.0 二进制帧 √ √ √ √
HTTP请求
请求行(Request Line)
GET /course/id/18.html?a=3&b=4 HTTP/1.1
POST /login HTTP/1.1
请求头(Request Header)
请求头用于说明是谁或什么在发送请求、请求源于何处,或者客户端的喜好及能力。服务器可以根据请求头部给出的客户端信息,试着为客户端提供更好的响应。请求头中信息的格式为key:value。
- Host:客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号。
- Connection:连接方式。如果值是close则表示基于短连接方式,如果该值是keep-alive,网络连接就是持久的,在一定时间范围内是不会关闭,使得对同一个服务器的请求可以继续在该连接上完成。
- Upgrade-Insecure-Requests:服务端是否支持https加密协议。
- Cache-Control:指定请求和响应遵循的缓存机制。
- User-Agent:浏览器表明自己的身份(是哪种浏览器)。例如Chrome浏览器:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36。
- Accept: 告诉WEB服务器自己接受什么介质类型, / 表示任何类型,type/* 表示该类型下的所有子类型。
- Accept-Encoding:浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate)。
- Accept-Language:浏览器申明自己接收的语言。语言跟字符集的区别:中文是语言,中文有多种字符集,比如big5,gb2312,gbk等。
- Accept-Charset:浏览器告诉服务器自己能接收的字符集。
- Referer:浏览器向WEB服务器表明自己是从哪个网页URL获得点击当前请求中的网址/URL。
- Refresh:表示浏览器应该在多少时间之后刷新文档,以秒计时。
- Cookie:可向服务端传递数据一种模型。
请求体(Request Body)
客户端传递给服务器的数据。比如:表单使用post方式提交的数据、上传的文件数据.等。

请求方式
- GET:向指定的资源发出“显示”请求。GET请求中会将请求中传递的数据包含在URL中并在浏览器的地址栏中显示。GET请求传递数据时要求数据必须是ASCII字符。GET请求可以被浏览器缓存。
- POST:向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求传递数据时,数据可以试试ASCII字符也可以是字节型数据,默认为字符型。POST请求默认情况下不会被浏览器所缓存。
- HEAD:向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头度中的元信息。
- PUT:向指定资源位置上传其最新内容。
- DELETE:请求服务器删除Request-URI所标识的资源。
- TRACE:回显服务器收到的请求,主要用于测试或诊断。
- OPTIONS:这个方法可使服务器传回该资源所支持的所有HTTP请求方法。用’*’来代替资源名称,向Web服务器发送OPTIONS请求,可以测试服务器功能是否正常运作。
- CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。通常用于SSL加密服务器的链接(经由非加密的HTTP代理服务器)。
GET和POST的区别:
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET产生的URL地址可以被Bookmark,而POST不可以。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的,而POST则没有。对参数的数据类型GET只接受ASCII字符,而POST即可是字符也可是字节。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中。
HTTP响应
响应行(Reponse Line)
HTTP/1.1 200
状态码 英文名 描述 1xx 消息响应 100 Continue 客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。服务器必须在请求完成后向客户端发送一个最终响应。 101 Switching Protocol 服务器已经理解了客户端的请求,并将通过Upgrade消息头通知客户端采用不同的协议来完成这个请求。在发送完这个响应最后的空行后,服务器将会切换到 在Upgrade消息头中定义的那些协议。只有在切换新的协议更有好处的时候才应该采取类似措施。
例如:切换到新的HTTP版本比旧版本更有优势,或者切换到一个实时且同步的协议以传送利用此类特性的资源。2xx 成功响应 200 OK 请求成功。成功的意义根据请求所使用的方法不同而不同。
GET:资源已被提取,并作为响应体传回客户端。
HEAD:实体头已作为响应头传回客户端。
POST:经过服务器处理客户端传来的数据,适合的资源作为响应体传回客户端。
TRACE:服务器收到请求消息作为响应体传回客户端。201 Created 请求成功,而且有一个新的资源已经依据请求的需要而建立,通常这是 PUT 方法得到的响应码。 202 Accepted 服务器已接受请求,但尚未处理。正如它可能被拒绝一样,最终该请求可能会也可能不会被执行。在异步操作的场合下,没有比发送这个状态码更方便的做法了。返回202状态码的响应的目的是允许服务器接受其他过程的请求(例如某个每天只执行一次的基于批处理的操作),而不必让客户端一直保持与服务器的连接直到批处理操作全部完成。在接受请求处理并返回202状态码的响应应当在返回的实体中包含一些指示处理当前状态的信息,以及指向处理状态监视器或状态预测的指针,以便用户能够估计操作是否已经完成。 203 Non-Authoritative Information 服务器已成功处理了请求,但返回的实体头部元信息不是在原始服务器上有效的确定集合,而是来自本地或者第三方的拷贝,如果不是上述情况,使用200状态码才是最合适的。 204 No Content 该响应没有响应内容,只有响应头,响应头也可能是有用的。用户代理可以根据新的响应头来更新对应资源的缓存信息。 205 Reset Content 告诉用户代理去重置发送该请求的窗口的文档视图。 206 Partial Content 当客户端通过使用range头字段进行文件分段下载时使用该状态码。 3xx 重定向 300 Multiple Choice 该请求有多种可能的响应,用户代理或者用户必须选择它们其中的一个。服务器没有任何标准可以遵循去代替用户来进行选择。 301 Moved Permanently 该状态码表示所请求的URI资源路径已经改变,新的URL会在响应的Location头字段里找到。 302 Found 该状态码表示所请求的URI资源路径临时改变,并且还可能继续改变。因此客户端在以后访问时还得继续使用该URI。新的URL会在响应的Location头字段里找到。 303 See Other 服务器发送该响应用来引导客户端使用GET方法访问另外一个URI。 304 Not Modified 告诉客户端,所请求的内容距离上次访问并没有变化。客户端可以直接从浏览器缓存里获取该资源。 305 Use Proxy 所请求的资源必须统过代理才能访问到。由于安全原因,该状态码并未受到广泛支持。 306 unused 这个状态码已经不再被使用,当初它被用在HTTP 1.1规范的旧版本中。 307 Temporary Redirect 服务器发送该响应用来引导客户端使用相同的方法访问另外一个URI来获取想要获取的资源。新的URL会在响应的Location头字段里找到。与302状态码有相同的语义,且前后两次访问必须使用相同的方法(GET POST)。 308 Permanent Redirect 所请求的资源将永久的位于另外一个URI上。新的URL会在响应的Location头字段里找到。与301状态码有相同的语义,且前后两次访问必须使用相同的方法(GET POST)。 4xx 客户端错误 400 Bad Request 因发送的请求语法错误,服务器无法正常读取。 401 Unauthorized 需要身份验证后才能获取所请求的内容,类似于403错误。不同点是,401错误后只要正确输入帐号密码,验证即可通过。 402 Payment Required 该状态码被保留以供将来使用。创建此代码最初的目的是为数字支付系统而用,然而到现在也没投入使用。 403 Forbidden 客户端没有权利访问所请求内容,服务器拒绝本次请求。 404 Not Found 服务器找不到所请求的资源。由于经常发生此种情况,所以该状态码在上网时是非常常见的。 405 Method Not Allowed 该请求使用的方法被服务器端禁止使用,RFC2616中规定 GET 和 HEAD 方法不能被禁止。 406 Not Acceptable 在进行服务器驱动内容协商后,没有发现合适的内容传回给客户端。 407 Proxy Authentication Required 类似于状态码 401,不过需要通过代理才能进行验证。 408 Request Timeout 客户端没有在服务器预备等待的时间内完成一个请求的发送。这意味着服务器将会切断和客户端的连接。在其他浏览器中,这种响应更常见一些。
例如Chrome 和 IE9, 目的是为了使用HTTP预连机制加快浏览速度。同时注意,一些服务器不发送此种响应就直接切断连接。409 Conflict 该请求与服务器的当前状态所冲突。 410 Gone 所请求的资源已经被删除。 411 Length Required 因服务器在本次请求中需要 Content-Length 头字段,而客户端没有发送。所以,服务器拒绝了该请求。 412 Precondition Failed 服务器没能满足客户端在获取资源时在请求头字段中设置的先决条件。 413 Request Entity Too Large 请求实体大小超过服务器的设置的最大限制,服务器可能会关闭HTTP链接并返回Retry-After头字段。 414 Request-URI Too Long 客户端请求所包含的URI地址太长,以至于服务器无法处理。 415 Unsupported Media Type 服务器不支持客户端所请求的媒体类型,因此拒绝该请求。 416 Requested Range Not Satisfiable 请求中包含的Range头字段无法被满足,通常是因为Range中的数字范围超出所请求资源的大小。 417 Expectation Failed 在请求头 Expect 中指定的预期内容无法被服务器满足。 5xx 服务器端错误 500 Internal Server Error 服务器遇到未知的无法解决的问题。 501 Not Implemented 服务器不支持该请求中使用的方法,比如POST 和 PUT。只有GET和HEAD是RFC2616规范中规定服务器必须实现的方法。 502 Bad Gateway 服务器作为网关且从上游服务器获取到了一个无效的HTTP响应。 503 Service Unavailable 由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个Retry-After:头用以标明这个延迟时间。如果没有给出这个Retry-After:信息,那么客户端应当以处理500响应的方式处理它。同时,这种情况下,一个友好的用于解释服务器出现问题的页面应当被返回,并且,缓存相关的HTTP头信息也应该包含,因为通常这种错误提示网页不应当被客户端缓存。 504 Gateway Timeout 服务器作为网关且不能从上游服务器及时的得到响应返回给客户端。 505 HTTP Version Not Supported 服务器不支持客户端发送的HTTP请求中所使用的HTTP协议版本。 响应头(Reponse Header)
响应头用于告知浏览器当前响应中的详细信息,浏览器通过获取响应头中的信息可以知道应该如何处理响应结果。响应头中信息的格式为key:value。
Date:响应的Date使用的是GMT时间格式,表示响应消息送达时间。
Server:服务器通过这个Server告诉浏览器服务器的类型。
Vary:客户端缓存机制或者是缓存服务器在做缓存操作的时候,会使用到Vary头,会读取响应头中的Vary的内容,进行一些缓存的判断。
Content-Encoding:文档的编码(Encode)方式。用gzip压缩文档能够显著地减少HTML文档的响应时间。
Content-Length:表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。
Content-Type:表示响应的文档属于什么MIME类型。
MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
MIME作用:HTTP协议所产生的响应中正文部分可以是任意格式的数据,那么如何保证接收方能看得懂发送方发送的正文数据呢?HTTP协议采用MIME协议来规范正文的数据格式。
在服务端我们可以设置响应头中Content-Type的值来指定响应类型。
Type Meaning application/postscript PostScript file application/vnd.lotus-notes Lotus Notes file application/vnd.ms-excel Excel spreadsheet application/vnd.ms-powerpoint PowerPoint presentation application/x-gzip Gzip archive application/x-java-archive JAR file application/x-java-serialized-object Serialized Java object application/x-java-vm Java bytecode (.class) file application/zip Zip archive audio/basic Sound file in .au or .snd format audio/midi MIDI sound file audio/x-aiff AIFF sound file audio/x-wav Microsoft Windows sound file image/gif GIF image image/jpeg JPEG image image/png PNG image image/tiff TIFF image image/x-xbitmap X Windows bitmap image text/css HTML cascading style sheet text/html HTML document text/plain Plain text text/xml XML video/mpeg MPEG video clip video/quicktime QuickTime video clip application/msword Microsoft Word document application/octet-stream Unrecognized or binary data application/pdf Acrobat (.pdf) file
响应体(Reponse Body)
响应体就是响应的消息体,如果是纯数据就是返回纯数据,如果请求的是HTML页面,那么返回的就是HTML代码,如果是JS就是JS代码,诸如此类。
Servlet
包目录如下:

Servlet是Server Applet的简称,称为服务端小程序,是JavaEE平台下的技术标准,基于Java语言编写的服务端程序。Web容器或应用服务器实现了Servlet标准所以Servlet需运行在Web容器或应用服务器中。Servlet主要功能在于能在服务器中执行并生成数据,是可以接受Http请求并作出相应的一种技术,是JAVA语言编写的一种动态资源。
Servlet技术特点

Servlet在应用程序中的位置

静态资源和动态资源区分
静态资源:每次访问都不需要运算,直接就可以返回的资源, 如HTML、CSS、JS 多媒体文件等等,每次访问获得的资源都是一样的。
动态资源:每次访问都需要运算代码生成的资源,如Servlet JSP,每次访问获得的结果可能都是不一样的。
Servlet UML图

Servlet接口
当客户端浏览器第一次请求Servlet时,容器会实例化这个Servlet,然后调用一次init方法,并在新的线程中执行service方法处理请求。service方法执行完毕后容器不会销毁这个Servlet而是做缓存处理,当客户端浏览器再次请求这个Servlet时,容器会从缓存中直接找到这个Servlet对象,并再一次在新的线程中执行service方法,当容器在销毁Servlet之前对调用一次destory方法。
1
2
3
4
5init();// 创建Servlet对象后立即调用该方法完成其他初始化工作
service();// 处理客户端请求,执行业务操作,利用响应对象响应客户端请求
destroy();// 在销毁Servlet对象之前调用该方法,释放资源
getServletConfig();// ServletConfig是容器向servlet传递参数的载体
getServletInfo();// 获取servlet相关信息生命周期:
阶段 次数 时机 创建 1次 第一次请求 初始化 1次 实例化之后 执行服务 多次 每次请求 销毁 1次 停止服务 ServletContext接口
ServletContext官方叫Servlet上下文。服务器会为每一个Web应用创建一个ServletContext对象。这个对象全局唯一,而且Web应用中的所有Servlet都共享这个对象,所以叫全局应用程序共享对象。

作用:
- 相对路径转绝对路径
- 获取容器的附加信息
- 读取配置信息
- 全局容器
使用:
1
2
3
4
5
6
7
8
9
10servletContext.getContextPath();// 获取项目的部署名
servletContext.getRealPath("path");// 该方法可以将一个相对路径转换为绝对路径,在文件上传与下载时需要用到该方法做路径的转换
servletContext.getServerInfo();// 返回Servlet容器的名称和版本号
servletContext.getMajorVersion();// 返回Servlet容器所支持Servlet的主版本号
servletContext.getMinorVersion();// 返回Servlet容器所支持Servlet的副版本号
servletContext.getInitParameter("key");// 该方法可以读取web.xml文件中<context-param>标签中<param-name>的值,即<param-value>配置信息
servletContext.getInitParameterNames();// 该方法可以读取web.xml文件中所有<context-param>标签中<param-name>的值列表
servletContext.setAttribute("key", ObjectValue);// 向全局容器中存放数据
servletContext.getAttribute("key");// 从全局容器中获取数据
servletContext.removeAttribute("key");// 根据key删除全局容器中的value1
2
3
4
5
6
7
8<context-param>
<param-name>key</param-name>
<param-value>value</param-value>
</context-param>
<context-param>
<param-name>username</param-name>
<param-value>Zane</param-value>
</context-param>生命周期:
当容器启动时会创建ServletContext对象并一直缓存该对象,直到容器关闭后该对象生命周期结束。ServletContext对象的生命周期非常长,所以在使用全局容器时不建议存放业务数据。
ServletConfig接口
Servlet运行期间,需要一些辅助信息,这些信息可以在web.xml文件中,使用一个或多个元素,进行配置。当Tomcat初始化一个Servlet时,会将该Servlet的配置信息,封装到一个ServletConfig对象中,通过调用init(ServletConfig config)方法,将ServletConfig对象传递给Servlet。
ServletConfig对象对应web.xml文件中的
节点。当Tomcat初始化一个Servlet时,会将该Servlet的配置信息,封装到一个ServletConfig对象中。我们可以通过该对象读取 节点中的配置信息 1
2
3
4
5
6
7
8<servlet>
<servlet-name>servletName</servlet-name>
<servlet-class>servletClass</servlet-class>
<init-param>
<param-name>key</param-name>
<param-value>value</param-value>
</init-param>
</servlet>使用:
1
2servletConfig.getInitParameter("key");// 该方法可以读取web.xml文件中当前<servlet>标签中<init-param>标签中的配置信息
servletConfig.getInitParameterNames();// 该方法可以读取web.xml文件中当前<servlet>标签中所有<init-param>标签中的值GenericServlet抽象类
GenericServlet是实现了Servlet接口的抽象类。在GenericServlet中进一步的定义了Servlet接口的具体实现,其设计的目的是为了和应用层协议解耦,在GenericServlet中包含一个Service抽象方法。我们也可以通过继承GenericServlet并实现Service方法实现请求的处理,但是需要将ServletReuqest 和 ServletResponse 转为 HttpServletRequest 和 HttpServletResponse。
HttpServlet
继承自GenericServlet,针对于处理 HTTP 协议的请求所定制。在 HttpServlet的service() 方法中已经把 ServletReuqest 和 ServletResponse 转为 HttpServletRequest 和 HttpServletResponse。 直接使用 HttpServletRequest 和HttpServletResponse,不再需要强转。实际开发中,直接继承 HttpServlet,并根据请求方式复写 doXxx() 方法即可。
Servlet开发
import javax.servlet.http.HttpServlet;
在我们自定义的Servlet中,如果想区分请求方式,不同的请求方式使用不同的代码处理,那么我么重写 doGet doPost 即可。如果我们没有必要区分请求方式的差异,那么我们直接重写service方法即可,要么重写doGet doPost 要么重写 service,必须二选一,而且必须进行重写。
继承HttpServlet类
Tomcat servlet-api.jar 包下
1
2
3
4import javax.servlet.http.HttpServlet;
public class MyServlet extends HttpServlet {
}重写service方法
1
2
3
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}启用方式
注解形式
1
2
3
public class MyServlet extends HttpServlet {
}属性名 类型 作用 initParams WebInitParam[] Servlet的init参数 name String Servlet的名称 value String[] Servlet的访问URL,支持多个 urlPatterns String[] Servlet的访问URL,支持多个 loadOnStartup int 自启动Servlet description String Servlet的描述 displayName String Servlet的显示名称 asyncSupported asyncSupported 声明Servlet是否支持异步操作模式 配置web.xml
F:\Tomcat\apache-tomcat-9.0.109\conf\web.xml会配置默认的欢迎页,如果项目没有配置则使用Tomcat配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14<!-- 向Tomcat声明一个Servlet -->
<servlet>
<servlet-name>myServlet</servlet-name> <!-- 别名 -->
<servlet-class>com.dovesly.test.MyServlet</servlet-class> <!-- 对应的Servlet类 -->
</servlet>
<!-- 给Servlet匹配一个请求的映射路径 -->
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/test.do</url-pattern>
</servlet-mapping>
<!-- Tomacat默认欢迎页配置 -->
<welcome-file-list>
<welcome-file>login.html</welcome-file>
</welcome-file-list>路径匹配规则
精准匹配
精确匹配是指
中配置的值必须与url完全精确匹配 1
2
3
4<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>/demo.do</url-pattern>
</servlet-mapping>扩展名匹配
在
允许使用统配符”“作为匹配规则,”“表示匹配任意字符。在扩展名匹配中只要扩展名相同都会被匹配和路径无关。注意,在使用扩展名匹配时在 中不能使用“/”,否则容器启动就会抛出异常。 1
2
3
4<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>http://localhost:8888/demo/abc.do 匹配
路径匹配
根据请求路径进行匹配,在请求中只要包含该路径都匹配。“*”表示任意路径以及子路径。
1
2
3
4<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>/suibian/*</url-pattern>
</servlet-mapping>http://localhost:8888/demo/suibian/haha.do 匹配
任意匹配
匹配“/”,匹配所有但不包含JSP页面
1
2
3
4<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>http://localhost:8888/demo/suibian.do 匹配
http://localhost:8888/demo/addUser.html 匹配
http://localhost:8888/demo/css/view.css 匹配
匹配所有
1
2
3
4<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>http://localhost:8888/demo/suibian.do 匹配
URL映射方式
在web.xml文件中支持将多个URL映射到一个Servlet中,但是相同的URL不能同时映射到两个Servlet中。
方式一
1
2
3
4
5<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>/suibian/*</url-pattern>
<url-pattern>*.do</url-pattern>
</servlet-mapping>方式二
1
2
3
4
5
6
7
8
9<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>/suibian/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
优先顺序
当一个url与多个Servlet的匹配规则可以匹配时,则按照 “精确路径匹配 > 最长路径匹配 > 扩展名匹配” 这样的优先级匹配到对应的Servlet。
Servlet1映射到 /abc/* -> 路径前缀匹配
Servlet2映射到 /* -> 路径前缀匹配
Servlet3映射到 /abc -> 精确匹配
Servlet4映射到 *.do -> 扩展名匹配
1
2
3
4
5
6
7
8
9当请求URL为“/abc/a.html”,“/abc/*”和“/*“都匹配,Servlet引擎将调用Servlet1。
当请求URL为“/abc”时,“/abc/*”,“/abc”和“/*”都匹配,Servlet引擎将调用Servlet3。
当请求URL为“/abc/a.do”时,“/abc/*”,“/*”和“.do”都匹配,Servlet引擎将调用Servlet1。
当请求URL为“/a.do”时,“/*”和“.do”都匹配,Servlet引擎将调用Servlet2。
当请求URL为“/xxx/yyy/a.do”时,“/*”和“.do”都匹配,Servlet引擎将调用Servlet2。请求URL Servlet1【/abc/*】 Servlet2【/*】 Servlet3【/abc】 Servlet4【*.do】 /abc/a.html √ /abc √ /abc/a.do √ /a.do √ /xxx/yyy/a.do √
HttpServletRequest
import javax.servlet.http.HttpServletRequest;
HttpServletRequest对象代表客户端浏览器的请求,当客户端浏览器通过HTTP协议访问服务器时,HTTP请求中的所有信息都会被Tomcat所解析并封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息。
获取请求行信息
1
2
3
4
5req.getRequestURL();// 返回客户端浏览器发出请求时的完整URL
req.getRequestURI();// 返回请求行中指定资源部分
req.getRemoteAddr();// 返回发出请求的客户机的IP地址
req.getLocalAddr();// 返回WEB服务器的IP地址
req.getLocalPort();// 返回WEB服务器处理Http协议的连接器所监听的端口获取请求头信息
1
2String headerValue = req.getHeader("headerKey");// 根据请求头中的key获取对应的value
Enumeration<String> headerNames = req.getHeaderNames();// 获取请求头中所有的key,该方法返回枚举类型获取请求数据
1
2
3
4
5String str = req.getParameter("key");// 根据key获取指定value
String[] userlikes = req.getParameterValues("checkboxkey");// 获取复选框(checkbox组件)中的值,返回一个String[]
Enumeration<String> parameterNames = req.getParameterNames();// 获取请求中所有数据的key,该方法返回一个枚举类型
Map<String, String[]> parameterMap = req.getParameterMap();// 获取请求中所有的数据并存放到一个Map结构中,该方法返回一个Map,其中key为String类型value为String[]类型
req.setCharacterEncoding("utf-8");// 请求的数据包基于字节在网络上传输,Tomcat接收到请求的数据包后会将数据包中的字节转换为字符。在Tomcat中使用的是ISO-8859-1的单字节编码完成字节与字符的转换,所以数据中含有中文就会出现乱码,可以通过req.setCharacterEncoding("utf-8")方法来对提交的数据根据指定的编码方式重新做编码处理请求乱码问题
1
req.setCharacterEncoding("UTF-8");// 处理post请求乱码
HttpServletResponse
import javax.servlet.http.HttpServletResponse;
HttpServletResponse对象代表服务器的响应,这个对象中封装了响应客户端浏览器的流对象,以及向客户端浏览器响应的响应头、响应数据、响应状态码等信息。
ContentType响应头
MIME的全称是Multipurpose Internet Mail Extensions,即多用途互联网邮件扩展类型。
这是HTTP协议中用来定义文档性质及格式的标准。对HTTP传输内容类型进行了全面定义。
服务器通过MIME告知响应内容类型,而浏览器则通过MIME类型来确定如何处理文档。1
resp.setContentType("MIME");//该方法可通过MIME-Type设置响应类型
Type Meaning application/msword Microsoft Word Document application/octet-stream application/octet-stream application/pdf Acrobat (.pdf) file application/postscript PostScript file application/vnd.lotus-notes Lotus Notes file application/vnd.ms-excel Excel spreadsheet application/vnd.ms-powerpoint PowerPoint presentation application/x-gzip Gzip archive application/x-java-archive JAR file application/x-java-serialized-object Serialized Java object application/x-java-vm Java bytecode (.class) file application/zip Zip archive application/json JSON audio/basic Sound file in .au or .snd format audio/midi MIDI sound file audio/x-aiff AIFF sound file audio/x-wav Microsoft Windows sound file image/gif GIF image image/jpeg image/jpeg image/png PNG image image/tiff TIFF image image/x-xbitmap X Windows bitmap image text/css HTML cascading style sheet text/html HTML document text/plain Plain text text/xml XML video/mpeg MPEG video clip video/quicktime QuickTime video clip 设置字符型响应
1
2
3resp.setContentType("text/html");// 设置响应类型为文本型,内容含有html字符串,是默认的响应类型
resp.setContentType("text/plain");// 设置响应类型为文本型,内容是普通文本
resp.setContentType("application/json");// 设置响应类型为JSON格式的字符串设置字节型响应
1
2resp.setContentType("image/jpeg");// 设置响应类型为图片类型,图片类型为jpeg或jpg格式
resp.setContentType("image/gif");// 设置响应类型为图片类型,图片类型为gif格式响应乱码问题
1
2response.setCharacterEncoding("utf-8");// 设置服务端为浏览器产生响应的响应编码,服务端会根据此编码将响应内容的字符转换为字节
response.setContentType("text/html;charset=utf-8");// 设置服务端为浏览器产生响应的响应编码,服务端会根据此编码将响应内容的字符转换为字节。同时客户端浏览器会根据此编码方式显示响应内容在响应中添加附加信息(文件下载)
在实现文件下载时,我们需要修改响应头,添加附加信息
1
2
3
4
5
6// Content-Disposition:attachment,该附加信息表示作为对下载文件的一个标识字段。不会在浏览器中显示而是直接做下载处理。
// filename=文件名,表示指定下载文件的文件名。
response.setHeader("Content-Disposition", "attachment; filename=" + 文件名);
// 解决文件名中文乱码问题
resp.addHeader("Content-Disposition","attachment;filename=" + new String (file.getName().getBytes("gbk"), "iso-8859-1"));
会话管理
Cookie对象与HttpSession对象的作用是维护客户端浏览器与服务端的会话状态的两个对象。由于HTTP协议是一个无状态的协议,所以服务端并不会记录当前客户端浏览器的访问状态,但是在有些时候我们是需要服务端能够记录客户端浏览器的访问状态的,如获取当前客户端浏览器的访问服务端的次数时就需要会话状态的维持。在Servlet中提供了Cookie对象与HttpSession对象用于维护客户端与服务端的会话状态的维持。二者不同的是Cookie是通过客户端浏览器实现会话的维持,而HttpSession是通过服务端来实现会话状态的维持。
Cookie
import javax.servlet.http.Cookie;
Cookie是一种保存少量信息至浏览器的一种技术,第一请求时,服务器可以响应给浏览器一些Cookie信息,第二次请求浏览器会携带之前的cookie发送给服务器,通过这种机制可以实现在浏览器端保留一些用户信息,为服务端获取用户状态获得依据。
Cookie对于存储内容是基于明文的方式存储的,所以安全性很低。不要在Cookie中存放敏感数据。在数据存储时,虽然在Servlet4.0中Cookie支持中文,但是建议对Cookie中存放的内容做编码处理,也可提高安全性。
Cookie对象的特点
- Cookie使用字符串存储数据
- Cookie使用Key与Value结构存储数据
- 单个Cookie存储数据大小限制在4097个字节
- Cookie存储的数据中不支持中文,Servlet4.0中支持
- Cookie是与域名绑定所以不支持跨一级域名访问
- Cookie对象保存在客户端浏览器内存上或系统磁盘中
- Cookie分为持久化Cookie(保存在磁盘上)与状态Cookie(保存在内存上)
- 浏览器在保存同一域名所返回Cookie的数量是有限的。不同浏览器支持的数量不同,Chrome浏览器为50个
- 浏览器每次请求时都会把与当前访问的域名相关的Cookie在请求中提交到服务端
Cookie对象的创建
1
2Cookie cookie = new Cookie("key","value");// 通过new关键字创建Cookie对象
response.addCookie(cookie);// 通过HttpServletResponse对象将Cookie写回给客户端浏览器Cookie中数据的获取
1
Cookie[] cookies = request.getCookies();// 通过HttpServletRequest对象获取Cookie,返回Cookie数组
Cookie不支持中文解决方案
在Servlet4.0版本之前的Cookie中是不支持中文存储的,如果存储的数据中含有中文,代码会直接出现异常。我们可以通过对含有中文的数据重新进行编码来解决该问题。在Servlet4.0中的Cookie是支持中文存储的。
1
2URLEncoder.encode("content","code");// 将内容按照指定的编码方式做URL编码处理。
URLDecoder.decode("content","code");// 将内容按照指定的编码方式做URL解码处理。持久化Cookie和状态Cookie
当Cookie对象创建后默认为状态Cookie。可以使用Cookie对象下的cookie.setMaxAge(60)方法设置失效时间,单位为秒。一旦设置了失效时间,那么该Cookie为持久化Cookie,浏览器会将Cookie对象持久化到磁盘中,当失效时间到达后文件删除。
- 持久化Cookie:浏览器会对Cookie做持久化处理,基于文件形式保存在系统的指定目录中。在Windows10系统中为了安全问题不会显示Cookie中的内容。
- 状态Cookie:浏览器会缓存Cookie对象,浏览器关闭后Cookie对象销毁。
Cookie跨域问题
域名等级的区别:
一级域名比二级域名更高级,二级域名是依附于一级域名之下的附属分区域名,即二级域名是一级域名的细化分级。
例如:baidu.com 为一级域名,news.baidu.com为二级域名。
Cookie不支持一级域名的跨域(你不能让一个Cookie在完全不同的一级域名之间共享),支持二级域名的跨域(同一个一级域名下的不同二级域名可以共享Cookie)。
例如:网站 taobao.com 设置的Cookie,网站 jd.com 无法读取;www.example.com 可以设置Cookie让 api.example.com 和 shop.example.com 访问
HttpSession
import javax.servlet.http.HttpSession;
HttpSession是一种保存少量信息至服务器端的一种技术,第一请求时,服务器会创建HttpSession,我们可以在HttpSession对象中保存一些关于用户的状态信息,并将HttpSession的JSESSIONID以Cookie形式响应给浏览器,第二次请求,浏览器会携带之前的JSESSIONID的Cookie,发送给服务器,服务器根据JSESSIONID获取对应的HttpSession对象,通过这种技术可以解决HTTP协议本身无法记录用户状态情况。
HttpSession对象是保存在服务端的,所以安全性较高。我们可以在HttpSession对象中存储数据,但是由于HttpSession对象的生命周期不固定,所以不建议存放业务数据。一般情况下我们只是存放用户登录信息。

HttpSession对象的特点
HttpSession保存在服务端
HttpSession可以存储任何类型的数据
HttpSession使用 Key 与 Value 结构存储数据 value 是 Object 类型
HttpSession存储数据大小无限制
HttpSession对象的创建
HttpSession对象的创建是通过request.getSession()方法来创建的。客户端浏览器在请求服务端资源时,如果在请求中没有JSESSIONID,getSession()方法将会为这个客户端浏览器创建一个新的HttpSession对象,并为这个HttpSession对象生成一个JSESSIONID,在响应中通过Cookie写回给客户端浏览器;如果在请求中包含了JSESSIONID,getSession()方法则根据这个ID返回与这个客户端浏览器对应的HttpSession对象。getSession()方法还有一个重载方法getSession(true|false)。当参数为true时与getSession()方法作用相同。当参数为false时则只去根据SessionID查找是否有与这个客户端浏览器对应的HttpSession,如果有则返回,如果没有SessionID则不会创建新的HttpSession对象。
1
2HttpSession session1 = req.getSession();
HttpSession session2 = req.getSession(true);HttpSession中数据的获取
1
2
3
4
5session.setAttribute("key",value);// 将数据存储到HttpSession对象中
Object value = session.getAttribute("key");// 根据key获取HttpSession中的数据,返回Object
Enumeration<String> attributeNames = session.getAttributeNames();// 获取HttpSession中所有的key,返回枚举类型
session.removeAttribute("key");// 根据key删除HttpSession中的数据
String id = session.getId();// 根据获取当前HttpSession的SessionID,返回字符串类型HttpSession的销毁方式
通过web.xml文件指定超时时间(最大不活动时间)
我们可以在web.xml文件中指定HttpSession的超时时间,当到达指定的超时时间后,容器就会销该HttpSession对象,单位为分钟。该时间对整个web项目中的所有HttpSession对象有效。时间的计算方式是根据最后一次请求时间作为起始时间。如果有哪个客户端浏览器对应的HttpSession的失效时间已到,那么与该客户端浏览器对应的HttpSession对象就会被销毁。其他客户端浏览器对应的HttpSession对象会继续保存不会被销毁。
1
2
3<session-config>
<session-timeout>1</session-timeout>
</session-config>我们也可以在Tomcat的web.xml文件中配置HttpSession的销毁时间。如果在Tomcat的web.xml文件中配置了HttpSession的超时时间对应的是Tomcat中所有的Web项目都有效。相当于配置了全局的HttpSession超时时间。如果我们在Web项目中配置了超时时间,那么会以Web项目中的超时时间为准。
1
2
3<session-config>
<session-timeout>30</session-timeout>
</session-config>通过HttpSession对象中的invalidate()方法销毁当前HttpSession对象
1
session.invalidate();// 手动设置HTTPSession不可用
HttpSession生命周期
在HttpSession对象生命周期中没有固定的创建时间与销毁时间。何时创建取决于我们什么时候第一次调用了getSession()或getSession(true)的方法。HttpSession对象的销毁时间取决于超时时间的到达以及调用了invalidate()方法。如果没有超时或者没有调用invalidate()方法,那么HttpSession会一直存储。默认超时时间为30分钟(Tomcat的web.xml文件配置的时间就是默认超时时间)。
Cookie与HttpSession区别
cookie数据存放在客户的浏览器或系统的文件中,而HttpSession中的数据存放在服务器中。
cookie不安全,而HttpSession是安全的。
单个cookie保存的数据不能超过4K,很多浏览器都限制一个域名保存cookie的数量;而HttpSession没有容量以及数量的限制。
域对象
Request域
有效范围
一次请求内有效,请求转发时数据可以传递,除此之外该域没有办法实现数据共享
生命周期
创建:每发生一次请求创建一个独立的请求域
使用:service方法中或者请求转发有效
销毁:请求结束,已经向浏览器响应数据
Session域
有效范围
单次会话内有效,可以跨多个请求
生命周期
创建:会话的产生,第一次发生请求,会话的开始
使用:本次会话之内,浏览器和服务器之间发生多次请求和响应有效
销毁:会话结束,如:浏览器失去JSESSIONID、到达最大不活动时间、手动清除
Application域
有效范围
当前web服务内,跨请求,跨会话
生命周期
创建:项目启动
使用:项目运行任何时间有效
销毁:项目关闭
过滤器(Filter)
Java过滤器指的是在java中起到过滤的作用的一个方法。可以在一个请求到达servlet之前,将其截取进行逻辑判断,然后决定是否放行到请求的servlet;也可以在一个response到达客户端之前,截取结果进行逻辑判断,然后决定是否允许返回给客户端。
Filter也称之为过滤器,它是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp,Servlet,静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能处理编码。它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
过滤器接口(Filter)
import javax.servlet.Filter;
1 | package javax.servlet; |
自定义过滤器
filter也可以通过web.xml进行初始化配置,在初始化时,将参数封装进入 FilterConfig 并在调用 init 方法时作为实参传入,我们可以在init方法中获取参数。
implements javax.servlet.Filter
1 | /** |
配置过滤器
使用注解@WebFilter
1
使用web.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.dscloud.filter.MyFilter</filter-class>
<init-param>
<param-name>email</param-name>
<param-value>12345@qq.com</param-value>
</init-param>
</filter>
<!-- 这里的顺序决定了过滤器的顺序 -->
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
生命周期

初始化
Filter的创建和销毁由WEB服务器负责。 web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter 配置信息的FilterConfig对象。
1
public void init(FilterConfig filterConfig);
使用
这个方法完成实际的过滤操作。当客户请求访问与过滤器关联的URL的时候,Servlet过滤器将先执行doFilter方法,FilterChain参数用于访问后续过滤器。
1
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain);
销毁
Filter对象创建后会驻留在内存,当web应用移除或服务器停止时才销毁,在Web容器卸载 Filter 对象之前被调用,该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。
1
public void destroy();
拦截器(Interceptor)
Java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。
拦截器接口(HandlerInterceptor)
import org.springframework.web.servlet.HandlerInterceptor;
1 | package org.springframework.web.servlet; |
自定义拦截器
implements org.springframework.web.servlet.HandlerInterceptor
1 |
|
配置拦截器
MyInterceptorConfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyInterceptorConfig implements WebMvcConfigurer {
/**
* 配置拦截器
* @param registry /
*/
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor())
.addPathPatterns("/api/ds/**") // 需要拦截的请求
.excludePathPatterns("/api/debug/**"); // 不拦截的请求
}
/**
* 注入拦截器到spring容器
* @return /
*/
public MyInterceptor myInterceptor() {
return new MyInterceptor();
}
}
生命周期
初始化
依赖Spring容器,随容器加载。
使用
1
2
3
4
5
6
7
8
9
10
11
12
13// 控制器方法执行前调用
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
// 控制器方法执行后,视图渲染前调用
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
// 请求完成且视图渲染后调用(资源清理)
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
}销毁
依赖Spring容器,随容器销毁。
过滤器与拦截器对比
| 对比维度 | 过滤器(Filter) | 拦截器(Interceptor) | 异同点 |
|---|---|---|---|
| 所属体系 | 属于 Servlet 规范(JavaEE 标准的一部分)。 | 属于 SpringMVC 框架(Spring 的一部分)。 | 不同:过滤器是 Servlet 规范的一部分,拦截器是 Spring 框架的功能扩展。 |
| 依赖容器 | 依赖 Servlet 容器(如 Tomcat、Jetty)来初始化和管理。 | 依赖 Spring 容器(Spring 的 IOC 容器)来初始化和管理。 | 不同:过滤器依赖 Servlet 容器,而拦截器依赖 Spring 容器。 |
| 核心功能 | 拦截 所有 HTTP 请求,包括静态资源(如 .html、.css、.js)和动态资源(如 Servlet、Controller)。 |
拦截 动态资源请求,即经过 SpringMVC 处理的 Controller 请求。 | 不同:过滤器拦截范围更广,拦截器只作用于 Controller 层的请求。 |
| 核心原理 | 基于 职责链模式,通过回调函数 doFilter 链式执行过滤器链。 |
基于 动态代理与反射机制,通过 SpringMVC 的拦截器链执行(preHandle、postHandle 等)。 |
不同:过滤器基于职责链模式,拦截器基于动态代理机制。 |
| 执行时机 | 在 Servlet 容器解析请求之前 执行,早于请求的参数解析阶段。 | 在 Controller 方法调用前或调用后 执行,作用于业务请求的生命周期。 | 不同:过滤器在更早的阶段执行,拦截器仅作用于业务逻辑相关的请求。 |
| 典型方法 | - init():容器启动时调用,初始化过滤器。- doFilter():每次请求调用,处理过滤逻辑。- destroy():容器关闭时调用,清理资源。 |
- preHandle():Controller 方法前调用。- postHandle():方法后调用,视图渲染前调用。- afterCompletion():请求完成后调用。 |
不同:过滤器方法更简单,拦截器方法更细分,作用于请求生命周期的多个阶段。 |
| 请求频率 | doFilter() 方法在 每次 HTTP 请求 时都会被调用,整个请求生命周期中只执行一次。 |
preHandle()、postHandle() 等方法在 单次请求的多个阶段可能多次调用。 |
不同:过滤器对每个请求只处理一次,而拦截器在请求的多个阶段可能多次调用(如视图渲染后)。 |
| 生命周期 | 生命周期由 Servlet 容器管理: - 初始化: init()。- 请求处理: doFilter()。- 销毁: destroy()。 |
生命周期由 Spring 容器管理: - 初始化:随容器加载。 - 请求处理: preHandle() 等。- 销毁:随容器关闭。 |
相同:都有初始化、请求处理和销毁阶段,但依赖的容器不同,机制也不同。 |
| IOC 集成 | 无法访问 Spring 的 IOC 容器,不能直接注入 Spring 的 Bean(如 Service、Repository 等)。 | 能够访问 Spring 的 IOC 容器,可以通过 @Autowired 注入 Spring Bean,并调用业务逻辑。 | 不同:过滤器不能访问 Spring 容器,拦截器与 Spring 集成紧密。 |
| 配置方式 | - 通过 web.xml 配置过滤器路径(传统方式)。- 使用 @WebFilter 注解(现代方式)。 |
- 通过 SpringMVC 的配置文件(如 WebMvcConfigurer)或注解配置拦截路径规则。 |
不同:过滤器通过 Servlet 配置,而拦截器通过 Spring 配置。 |
| 性能开销 | 性能较高,因为运行在 Servlet 容器底层,直接处理原始 HTTP 请求,开销较小。 | 性能略低,因为依赖 Spring 的动态代理与反射机制,且处理的请求已被封装。 | 不同:过滤器的性能优于拦截器,因为过滤器工作在更底层。 |
| 常见用途 | - 设置编码格式(如 UTF-8)。 - CORS(跨域资源共享)处理。 - 访问日志记录。 - 静态资源拦截。 |
- 权限校验和用户认证。 - 动态数据注入(如公共参数)。 - Controller 前后逻辑处理。 |
不同:过滤器适合通用需求,拦截器适合业务相关的需求。 |
| 静态资源拦截 | 可以,能够拦截静态资源(如 .html、.css、.js 等)。 |
不能,只能拦截动态资源(经由 SpringMVC Controller 处理的请求)。 | 不同:过滤器可以拦截静态资源,拦截器不可以。 |
| 依赖技术栈 | Servlet API(如 javax.servlet.Filter)。 |
SpringMVC(如 HandlerInterceptor)。 |
不同:过滤器依赖 JavaEE 技术栈,拦截器依赖 Spring 技术栈。 |
通俗理解
- 过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。(理解:就是一堆字母中取一个B)
- 拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。(理解:就是一堆字母中,干预它,通过验证的少点,顺便干点别的东西
触发时机
- 过滤器(Filter)是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。
- 拦截器(Interceptor)是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。

流程图解

监听器(Listener)
Request域监听器
- ServletRequestListener (处理request对象创建和销毁)
- ServleRequestAttributeListener (处理域对象中的数据添加,修改,删除)
Session域监听器
- HttpSessionListener (处理session对象创建和销毁)
- HttpSessionAttributeListener (处理session域对象中的数据添加,修改,删除)
- HttpSessionBindingListener (处理session对象监听器绑定和解绑定接口)
- HttpSessionActivationListener (处理session对象钝化和活化状态接口)
Application域监听器
- ServletContextListener (处理application对象创建和销毁)
- ServletContextAttributeListener (处理application域对象中的数据添加,修改,删除)
Request域监听器
ServletRequestListener接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public interface ServletRequestListener extends EventListener {
/**
* 监听HttpServletRequest对象的创建并初始化,项目中任何一个Request对象的创建并初始化都会触发该方法的执行
*
* @param sre /
*/
public void requestInitialized(ServletRequestEvent sre);
/**
* 监听HttpServletRequest对象的销毁,项目中任何一个Request对象的销毁都会触发该方法的执行
*
* @param sre /
*/
public void requestDestroyed(ServletRequestEvent sre);
}ServletRequestAttributeListener接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public interface ServletRequestAttributeListener extends EventListener {
/**
* 任何一个Request对象中调用 request.setAttribute() 方法增加了(原先没有的数据)数据都会触发该方法
*
* @param srae /
*/
public void attributeAdded(ServletRequestAttributeEvent srae);
/**
* 任何一个Request对象中调用 request.removeAttribute() 方法移除了数据都会触发该方法
*
* @param srae /
*/
public void attributeRemoved(ServletRequestAttributeEvent srae);
/**
* 任何一个Request对象中调用 request.setAttribute() 方法修改了(原先已存在的数据)数据都会触发该方法
*
* @param srae /
*/
public void attributeReplaced(ServletRequestAttributeEvent srae);
}自定义ServletRequest监听器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43public class MyRequestListener implements ServletRequestListener, ServletRequestAttributeListener {
public void requestDestroyed(ServletRequestEvent sre) {
// 监听HttpServletRequest对象的销毁 项目中任何一个Request对象的销毁都会触发该方法的执行
ServletRequest servletRequest = sre.getServletRequest();
System.out.println("request" + servletRequest.hashCode() + "对象销毁了");
}
public void requestInitialized(ServletRequestEvent sre) {
// 监听HttpServletRequest对象的创建并初始化 项目中任何一个Request对象的创建并初始化都会触发该方法的执行
ServletRequest servletRequest = sre.getServletRequest();
System.out.println("request" + servletRequest.hashCode() + "对象初始化");
}
public void attributeAdded(ServletRequestAttributeEvent srae) {
// 任何一个Request对象中调用 setAttribute方法增加了数据都会触发该方法
ServletRequest servletRequest = srae.getServletRequest();
String name = srae.getName();
Object value = srae.getValue();
System.out.println("request" + servletRequest.hashCode() + "对象增加了数据:" + name + "=" + value);
}
public void attributeRemoved(ServletRequestAttributeEvent srae) {
// 任何一个Request对象中调用 removeAttribute方法移除了数据都会触发该方法
ServletRequest servletRequest = srae.getServletRequest();
String name = srae.getName();
Object value = srae.getValue();
System.out.println("request" + servletRequest.hashCode() + "对象删除了数据:" + name + "=" + value);
}
public void attributeReplaced(ServletRequestAttributeEvent srae) {
// 任何一个Request对象中调用 setAttribute方法修改了数据都会触发该方法
ServletRequest servletRequest = srae.getServletRequest();
String name = srae.getName();
Object value = srae.getValue();
Object newValue = servletRequest.getAttribute(name);
System.out.println("request" + servletRequest.hashCode() + "对象增修改了数据:" + name + "=" + value + "设置为:" + newValue);
}
}
Session域监听器
HttpSessionListener接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public interface HttpSessionListener extends EventListener {
/**
* 监听HttpSession对象的创建并初始化,项目中任何一个Session对象的创建并初始化都会触发该方法的执行
*
* @param se /
*/
public void sessionCreated(HttpSessionEvent se);
/**
* 监听HttpSession对象的销毁,项目中任何一个Session对象的销毁都会触发该方法的执行
*
* @param se /
*/
public void sessionDestroyed(HttpSessionEvent se);
}HttpSessionAttributeListener接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public interface HttpSessionAttributeListener extends EventListener {
/**
* 任何一个Session对象中调用 session.setAttribute() 方法增加了(原先没有的数据)数据都会触发该方法
*
* @param se /
*/
public void attributeAdded(HttpSessionBindingEvent se);
/**
* 任何一个Session对象中调用 session.removeAttribute() 方法移除了数据都会触发该方法
*
* @param se /
*/
public void attributeRemoved(HttpSessionBindingEvent se);
/**
* 任何一个Session对象中调用 session.setAttribute() 方法修改了(原先已存在的数据)数据都会触发该方法
*
* @param se /
*/
public void attributeReplaced(HttpSessionBindingEvent se);
}HttpSessionBindingListener接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29/**
* 通过setAttribute方法和某个session对象绑定之后,监听单独的某个Session对象
*/
public interface HttpSessionBindingListener extends EventListener {
/**
* 通过session.setAttribute()绑定单独监听某个Session对象,例如
*
* session.setAttribute("mySessionBindingListener", new MySessionBindingListener())
*
* @param event /
*/
public void valueBound(HttpSessionBindingEvent event);
/**
* 解除绑定方法
*
* 1. session.invalidate(); 让session不可用
*
* 2. session到达最大不活动时间,session对象回收 ;
*
* 3. session.removeAttribute("mySessionBindingListener"); 手动解除绑定
*
* @param event /
*/
public void valueUnbound(HttpSessionBindingEvent event);
}HttpSessionActivationListener接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public interface HttpSessionActivationListener extends EventListener {
/**
* session钝化
*
* @param se /
*/
public void sessionWillPassivate(HttpSessionEvent se);
/**
* session活化
*
* @param se /
*/
public void sessionDidActivate(HttpSessionEvent se);
}自定义HttpSessionListener监听器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public class MySessionListener implements HttpSessionListener, HttpSessionAttributeListener {
public void sessionCreated(HttpSessionEvent se) {
System.out.println("任何一个Session对象创建");
}
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("任何一个Session对象的销毁");
}
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println("任何一个Session对象中添加了数据");
}
public void attributeRemoved(HttpSessionBindingEvent se) {
System.out.println("任何一个Session对象中移除了数据");
}
public void attributeReplaced(HttpSessionBindingEvent se) {
System.out.println("任何一个Session对象中修改了数据");
}
}
Application域监听器
ServletContextListener接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public interface ServletContextListener extends EventListener {
/**
* 监听ServletContext对象创建并初始化
*
* @param sce /
*/
public void contextInitialized(ServletContextEvent sce);
/**
* 监听ServletContext销毁
*
* @param sce /
*/
public void contextDestroyed(ServletContextEvent sce);
}ServletContextAttributeListener接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public interface ServletContextAttributeListener extends EventListener {
/**
* ServletContext增加数据回调
*
* @param scab /
*/
public void attributeAdded(ServletContextAttributeEvent scab);
/**
* ServletContext删除数据回调
*
* @param scab /
*/
public void attributeRemoved(ServletContextAttributeEvent scab);
/**
* ServletContext修改数据回调
*
* @param scab /
*/
public void attributeReplaced(ServletContextAttributeEvent scab);
}自定义ServletContext监听器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28public class MyApplicationListener implements ServletContextListener, ServletContextAttributeListener {
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext创建并初始化了");
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext销毁了");
}
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("ServletContext增加了数据");
}
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("ServletContext删除了数据");
}
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("ServletContext修改了数据");
}
}
配置监听器
使用注解@WebListener
1
2
3
4
public class MySessionActivationListener implements HttpSessionActivationListener {
}使用web.xml
1
2
3<listener>
<listener-class>com.dscloud.listener.MyRequestListener</listener-class>
</listener>