文章目录
1. Java Web
1.1基本概念
web简单理解就是网页的意思,例如 www.baidu.com。在java中,动态web资源开发的技术统称为Java Web。
1.2 web的分类
-
静态web
提供给用户的数据始终不会发生改变,例如:
- html、css、js
- 优点:如果服务器上一直存在这些东西,我们可以直接进行读取;
- 缺点:
- web页面无法动态更新,所有用户都是看到同一页面(轮播图、伪动态、js……);
- 无法和数据库交互,使得数据库无法持久化。
- html、css、js
-
动态web
提供给用户的数据始终会发生改变,每个人在不同的时间、不同的地点看到的信息各不相同,例如:
- 几乎所用的网站:淘宝、京东……
-
技术栈:
- ASP:微软公司的,国内最早流行,页面业务代码极其混乱,维护成本高。
- PHP:简单、功能强大、跨平台、开发速度快,局限性在于无法承载大访问量。
- Servlet/JSP:sun公司主推B/S架构,基于Java语言,可承受三高(高并发、高可用、高性能),语法像ASP(加强市场强度)。
-
优点:
- 可以动态更新,所有用户看到的都不是同一个页面;
- 可以与数据库交互,实现数据持久化。
-
缺点:
加入服务器的动态web资源出现了错误的时候,我们需要重写更正后台程序(甚至停机维护),重新发布。
-
- 几乎所用的网站:淘宝、京东……
1.3 web应用程序
web应用程序,即可以提供浏览器访问的程序。一个web应用程序应该由多部分组成(静态web、动态web):
- html、css、js;
- jsp、servlet;
- java程序;
- jar包;
- 配置文件(properties、xml)。
1.4 web服务器
web服务器,即发布及运行Web应用的容器,只有将开发的Web项目放置到该容器中,才能使网络中的所有用户通过浏览器进行访问。开发Java Web应用所采用的服务器主要是与JSP/Servlet兼容的Web服务器,比较常见的有Tomcat、Resin、JBoss、WebSphere 和 WebLogic 等 。
-
Tomcat 服务器
目前最为流行的Tomcat服务器是Apache-Jarkarta开源项目中的一个子项目,是一个小型、轻量级的支持JSP和Servlet 技术的Web服务器,因为Tomcat 技术先进、性能稳定,而且免费,所以也是初学者学习开发JSP应用的首选。Tomcat 实际上运行JSP页面和Servlet。Tomcat下载后有几个文件夹:
-
bin目录
该目录下存放的是二进制可执行文件。
- 如果是安装版,那么这个目录下会有两个exe文件: tomcat9.exe、tomcat9w.exe,前者是在控制台下启动Tomcat,后者是弹出UGI窗口启动Tomcat;
- 如果是解压版,那么会有startup.bat和shutdown.bat文件,startup.bat用来启动Tomcat,但需要JDK的配置,shutdown.bat用来停止Tomcat。
-
conf目录
这是一个非常非常重要的配置文件目录,这个目录下有四个最为重要的文件:
- server.xml:配置整个服务器信息。例如修改端口号,添加虚拟主机等;
- tomcat-users.xml:存储tomcat用户的文件,这里保存的是tomcat的用户名及密码,以及用户的角色信息。可以按着该文件中的注释信息添加tomcat用户,然后就可以在Tomcat主页中进入Tomcat Manager 页面了;
- web.xml:部署描述符文件,这个文件中注册了很多MIME类型,即文档类型。这些MIME类型是客户端与服务器之间说明文档类型的,如用户请求一个html网页,那么服务器还会告诉客户端浏览器响应的文档是text/html类型的,这就是一个MIME类型。客户端浏览器通过这个MIME类型就知道如何处理它了。 当然是在浏览器中显示这个html文件了。但如果服务器响应的是一个exe文件,那么浏览器就不可能显示它,而是应该弹出下载窗⼝才对。MIME就是用来说明文档的内容是什么类型的!
- context.xml:对所有应用的统一配置,通常我们不会去配置它。
-
lib目录
Tomcat的类库,里面是一大堆jar文件。如果需要添加Tomcat依赖的jar文件,可以把它放到这个目录中,当然也可以把应用依赖的jar文件放到这个目录中,这个目录中的jar所有项目都可以共享之, 但这样你的应用放到其他Tomcat下时就不能再共享这个目录下的Jar包了,所以建议只把Tomcat需要的 Jar包放到这个目录下;
-
logs目录
这个目录中都是日志文件,记录了Tomcat启动和关闭的信息,如果启动Tomcat时有错误,那么异常也会记录在日志文件中。
-
temp目录
存放Tomcat的临时文件,这个目录下的东西可以在停下Tomcat后删除!
-
webapps目录
存放web项目的目录,其中每个文件夹都是一个项目;如果这个目录下已经存在了目录,那么都是tomcat自带的项目。其中ROOT是一个特殊的项目,在地址栏中没有给出项目目录时,对应的就是ROOT项目。
http://localhost:8080/examples,进入示例项目。其中examples就是项目名,即文件夹的名字。
-
work目录
运行时生成的文件,最终运行的文件都在这里,通过webapps中的项目生成的!可以把这个目录下的内容删除,再次运行时会再次生成work目录。当客户端用户访问⼀一个JSP文件时,Tomcat会通过JSP生成Java文件,然后再编译Java文件生成class文件,生成的java和class文件都会存放到这个目录下。
JSP本质上就是一个Servlet。
-
LICENSE:许可证。
-
NOTICE:说明文件。
-
-
Resin 服务器
Resin是Caucho公司的产品,是一个非常流行的支持Servlet和JSP的服务器,速度非常快。Resin本身包含了一个支持HTML的Web服务器,这使它不仅可以显示动态内容,而且显示静态内容的能力也毫不逊色,因此许多网站都是使用Resin服务器构建 。
-
JBoss服务器
JBoss是一个遵从JavaEE规范的、开放源代码的、纯Java的EJB服务器,对于J2EE有很好的支持。 JBoss采用JML API实现软件模块的集成与管理,其核心服务器是提供EJB服务器,不包含Servlet和JSP的 Web容器,不过它可以和Tomcat完美结合。
-
WebSphere 服务器
WebSphere是IBM公司的产品,可进一步细分为 WebSphere Performance Pack、Cache Manager 和WebSphere Application Server等系列,其中WebSphere Application Server 是基于Java 的应用环境,可以运行于 Sun Solaris、Windows NT 等多种操作系统平台,用于建造、部署和管理 Internet和Intranet Web应用程序。
-
WebLogic 服务器
WebLogic 是BEA公司的产品(现在已经被Oracle收购),可进一步细分为 WebLogic Server、 WebLogic Enterprise 和 WebLogic Portal 等系列,其中 WebLogic Server 的功能特别强大。WebLogic 支持企业级的、多层次的和完全分布式的Web应用,并且服务器的配置简单、界面友好。对于那些正在寻求能够提供Java平台所拥有的一切应用服务器的用户来说,WebLogic是一个十分理想的选择。
2. Http协议简介
2.1 基本概念
超文本传输协议(HyperText Transfer Protocol,HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。
HTTP的发展是由蒂姆·伯纳斯-李于1989年在欧洲核心研究组织(CERN)所发起。HTTP的标准制定由万维网协会(World Wide Web Consortium,W3C)和互联网工程任务组(Internet Engineering Task Force,IETF)进行协调,最终发布了一系列的RFC,其中最著名的是1999年6月公布的 RFC 2616,定义了HTTP协议中现今广泛使用的一个版本——HTTP 1.1。
-
http1.0 时代
- HTTP/1.0:客户端可以与web服务器连接后,只能获得一个web资源。
-
http2.0 时代
- HTTP/1.1:客户端可以与web服务器连接后,可以获得多个web资源。
-
HTTP:是一个简单的请求-响应协议,默认端口为80,它通常运行在TCP之上。
-
Https:在HTTP 的基础上加入SSL(HTTP与TCP之间增加一个加密/身份验证层),更安全,默认端口是443。
2.2 网站的访问
下面以访问 www.baidu.com 为例。
2.2.1 访问的简要过程
-
打开浏览器,输入网站的域名( www.baidu.com);
-
DNS域名解析(将域名转换成对应的ip地址):
-
浏览器首先搜索浏览器自身缓存的DNS记录(不同的浏览器自定义的缓存时间不同),如果存在就返回;
-
如果浏览器缓存中没有找到需要的记录或记录已经过期,则搜索本地hosts文件;
C:\Windows\System32\drivers\etc\hosts
-
如果在hosts文件中没有找到需要的记录或记录已经过期,则向域名解析服务器发送解析请求;
-
-
经过域名解析后,如果解析成功,会返回这个域名的ip地址给客户端(通常是浏览器),然后通过TCP三步握手建立连接;
-
客户端发送HTTP请求;
-
服务器解析请求报文,如果接受了,就定位请求资源,返回HTTP响应(将资源副本写到TCP套接字中,由客户端读取);
-
浏览器解析得到响应数据,进行浏览器渲染;
-
释放TCP连接。
2.2.2 http请求
客户端 --> 发送请求(Request) --> 服务器
2.2.2.1 请求行(General,不属于headers,只用于收集请求url和响应的status等信息)
Request URL:https://www.baidu.com/ //请求地址
Request Method:GET //get方法(⼋种请求⽅法)
Status Code:200 OK //状态码:200
Remote Address:14.215.177.39:443 //远程地址 ip:端口号
HTTP/1.1协议中共定义了八种请求方法(也叫“动作”)来以不同方式操作指定的资源:
-
GET(常用)
向指定的资源发出显示请求。请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全,但高效。请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用&连接。URL的编码格式采用的是ASCII编码,而不是unicode,即是说所有的非ASCII字符都要编码之后再传输。
-
HEAD
与GET方法一样,都是向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分。它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中关于该资源的信息(元信息或称元数据)。
-
POST(常用)
请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效。
-
PUT
向指定资源位置上传其最新内容。
-
DELETE
请求服务器删除Request-URI所标识的资源。
-
TRACE
回显服务器收到的请求,主要用于测试或诊断。
-
OPTIONS
这个方法可使服务器传回该资源所支持的所有HTTP请求方法。用’*'来代替资源名称,向Web服务器发送 OPTIONS请求,可以测试服务器功能是否正常运作。
-
CONNECT
2.2.2.2 请求头(Request Headers)
Accept:text/html //告诉服务器,它所支持的数据类型
Accept-Encoding:gzip, deflate, br //支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1
Accept-Language:zh-CN,zh;q=0.9 //告诉服务器,它的语言环境
Cache-Control:max-age=0 //缓存控制
Connection:keep-alive //告诉服务器,请求完成是断开还是保持连接,这里是长连接(从HTTP/1.1起,默认使长连接,即在保持时间内有效,由于TCP通信需要进行3次握手,所以可以建立一定程度上的持续性连接,减少进行3次握手的次数,提高通讯性能)
HOST: //主机
.....
2.2.3 Http响应
2.2.3.1 响应头(Response Headers)
Cache-Control: private //缓存机制
Connection: keep-alive //告诉浏览器,请求完成是断开还是保持连接
Content-Encoding: gzip //告诉浏览器,它的编码格式
Content-Type: text/html;charset=utf-8 //内容类型
.....
2.2.3.2 响应状态码
- 200:
- 请求响应成功 200
- ……
- 3xx:请求重定向
- 重定向:你重新到我给你新位置去;
- ……
- 4xx:找不到资源
- 资源不存在 404;
- ……
- 5xx:
- 服务器代码错误 500
- 网关错误 502
- ……
3. Servlet
3.1 什么是Servlet?
Servlet(Server Applet),全称Java Servlet,是用Java编写的服务器端程序,其主要功能在于交互式地浏览和修改数据,生成动态Web内容。Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
3.2 Servlet的工作模式
- 客户端发送请求给服务器;
- 服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器;
- 服务器将响应返回客户端。
3.3 开发Servlet的步骤
-
编写一个类,实现Servlet接口或者继承HttpServlet都可;
public class LoginServlet 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 { //处理get/post请求的⽅法 } @Override public String getServletInfo() { return null; } @Override public void destroy() { //销毁的⽅法 } }
-
在web.xml文档中配置映射关系;
<servlet> <servlet-name>自定义名称</servlet-name> <servlet-class>处理请求的类的完整路径</servlet-class> </servlet> <servlet-mapping><!-- mapping 表示映射 --> <servlet-name>自定义名称,与上保持一致</servlet-name> <url-pattern>请求名</url-pattern> </servlet-mapping>
-
把开发好的java类部署到web服务器中。
注意:
- 一个Servlet可以指定一个甚至多个映射路径, 一个Servlet可以指定通用映射路径(*);
- 可以自定义后缀实现请求映射,但是*前面不能加项目映射的路径;
- 指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求;
- 例如:/user/.do、/.do、test*.do都是非法的,启动时候会报错
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
<!--默认请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<!--自定义后缀请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.x</url-pattern>
</servlet-mapping>
3.4 服务器程序处理请求的大致过程
- 页面发送请求(例如”test“);
- 服务器接受请求后,访问web.xml;
- 请求(“test”)与servlet-mapping标签中url-pattern标签中的内容(/test)进行匹配;
- 匹配成功后,根据url-pattern标签对应的servlet-name去匹配servlet标签中的servlet-name;
- 再次匹配成功后,根据servlet标签中的servlet-class找到正确处理该请求的Servlet类的完整路径;
- 根据提交的请求方法去匹配对应的处理方法来处理这个请求(反射)。
3.5 Servlet工作原理
-
Servlet接口定义了Servlet与Servlet容器之间的契约;
这个契约是:Servlet容器将Servlet类载入内存,并产生Servlet实例和调用它具体的方法。
但是要注意的是,在一个应用程序中,每种Servlet类型只能有一个实例(单例模式)。
-
用户请求致使Servlet容器调用Servlet的service()方法,并传入一个ServletRequest对象和一个ServletResponse对象;
ServletRequest对象和ServletResponse对象都是由Servlet容器(例如 TomCat)封装好的,并不需要程序员去实现,程序员可以直接使用这两个对象。
-
ServletRequest中封装了当前的Http请求,ServletResponse表示当前用户的Http响应;
因此,开发人员不必解析和操作原始的Http数据;程序员只需直接操作ServletResponse对象就能把响应轻松的发回给用户。
-
对于每一个应用程序,Servlet容器还会创建一个ServletContext对象,它代表着当前的web应用;
ServletContext context = this.getServletContext();
这个对象中封装了上下文 (应用程序)的环境详情,每个应用程序只有一个ServletContext,它的作用在于:
-
共享数据
在这个Servlet中保存的数据,可以在另外一个servlet中拿到。
-
获取初始化参数
context.getInitParameter("参数名")
-
请求转发
context.getRequestDispatcher("请求转发的路径").forward(req,resp);
-
-
每个Servlet对象也都有一个封装 Servlet配置的ServletConfig对象。
3.6 Servlet的生命周期
-
当客户端发送请求后,由容器(即web服务器,例如tomcat)去解析请求, 根据请求找到对应的servlet;
即第3.4小节服务器程序处理请求过程的第六个步骤的扩展
-
判断该类的对象是否存在;
- 不存在则创建servlet实例,并调取init()方法进行初始化(即第一次进行这一步操作);
- 存在则不操作。
-
调取 service()方法,由service()方法判断客户端的请求方式,根据请求方式调用对应的处理方法(doget、dopost……);
-
将结果响应给客户端(至此单次请求处理完毕);
-
当服务器关闭时调取destroy()方法进行销毁。
3.7 请求Request
HttpServletRequest表示Http环境中的Servlet请求。它继承于ServletRequest类,扩展于javax.servlet.ServletRequest接口。
3.7.1 常用方法
无论前台页面传递的是什么类型的数据,后台都是使用String接收的。
-
String getParameter(String name)
根据表单组件名称获取提交数据,返回值是String,服务器在接收数据时使用字符串统一接收。
-
String[ ] getParameterValues(String name)
获取表单组件对应多个值时的请求数据。
-
void setCharacterEncoding(String charset)
指定每个请求的编码。
tomcat8 以后针对post请求才起作用,8以前get也要去设置一下防止乱码。
-
RequestDispatcher getRequestDispatcher(String path)
返回一个RequestDispatcher对象,该对象的forward( )方法用于请求转发。
request.getRequestDispatcher("../success.jsp").forward(request,response);
-
存值,request.setAttribute(“key”,value);
用于存值,单次请求有效,可以将数据返回给前端页面。
-
取值,request.getAttribute(“key”);
取值后需要向下转型(返回类型为Object)。
3.7.2 前端页面发送请求的方式
-
通过表单 get/post提交;
-
通过a标签发送数据(get提交);
<a href="/login?a=10&name=abc&pass=123">
-
通过地址栏直接拼接-get请求;
-
js提交数据-get请求。
location.href="请求?key=value&key=value"
-
ajax请求。
3.8 响应Response
在Service API中,定义了一个HttpServletResponse接口,它继承子ServletResponse接口,门用来封装HTTP响应消息。 在HttpServletResponse接口中定义了向客户端发送响应状态码、响应消息头、响应消息体的方法。
3.8.1 常用方法
-
void addCookie(Cookie var1)
给这个响应添加一个cookie。
-
void sendRedirect(String var1)
发送一条响应码,将浏览器跳转到指定的位置。
-
PrintWriter getWriter()
获得字符流,通过字符流的write(String s)方法可以将字符串设置到 response 缓冲区中,随后Tomcat会将response缓冲区中的内容组装成Http响应返回给浏览器端。
-
void setContentType()
设置响应内容的类型
3.8.2 请求转发与重定向区别
重定向:response.sendRedirect()
转发:request.getRequestDispatcher("…/success.jsp").forward(request,response);
-
相同点
- 都能实现页面跳转。
- Session中的值都是不会丢失的。
-
不同点
- 重定向时地址栏会改变,request中存储的数据会丢失;转发时地址栏显示的是请求页面的地址,request数据可以保存。
- 转发属于一次请求一次响应,重定向属于两次请求(地址栏修改了两次)两次响应。
-
如何选择转发还是重定向?
-
如果要操作到了request域中的数据,那么就只能使用转发;
-
如果当前需要访问外部web应用程序的资源,那么就只能使用重定向;
-
如果请求中有比较重要的数据,不能重复提交(比如提交表单),建议使用重定向;
因为如果是使用转发,用户多次刷新页面可能导致同一数据多次提交,导致不必要的错误发生,而将当前页面重定向到另一个页面后,这个页面任意重新加载没有副作用。
-
如果使用哪种方式都无所谓的话,建议使用转发。
重定向的速度比转发慢,因为浏览器还得发出一个新的请求。
-
4. 会话
背景:request存的值只能在单次请求中保存,保存的数据不能跨页面;当重定向时,request存的值会丢失。
通俗意义上来说,从打开浏览器到关闭浏览器,期间访问服务器就称为一次会话,因为默认关闭浏览器就会自动清除cookie。严谨地说,只要服务器端的session和客户端cookie都有效,且sessionIId能匹配上,就称为同一次会话。
保存会话的两种技术(会话跟踪技术):cookie和session。
4.1 Session
Session通过在服务器端记录信息确定用户身份,Session的数据可以在多个页面中共享,即使重定向页面,数据也不会丢失,Session中可以包含n个request。
4.1.1 常用方法
-
HttpSession getSession()
获取Session对象。
-
void setAttribute(String key,Object value)
以key/value的形式保存对象值,将数据存储在服务器端。
-
Object getAttribute(String key)
通过key获取对象值。
-
void invalidate()
设置session对象失效。
-
String getId()
获取sessionId,当第一次登录成功后,Session会产生一个唯一的id,浏览器之后访问时如果发现id值还是之前id,那么说明当前访问的属于同一个会话。
-
void setMaxInactiveInterval(int interval)
设定session的非活动时间,默认是30分钟,单位是秒。
-
int getMaxInactiveInterval()
获取session的有效非活动时间(以秒为单位)。
-
void removeAttribute(String key)
从session中删除指定名称(key)所对应的对象。
-
boolean isNew()
判断session是否是新建的。
-
long getCreationTime()
返回Session的创建日期。返回类型为long,常被转化为Date类型。
4.1.2 Session的生命周期
-
Session存储在哪?
为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简(只存重要的信息即可)。
-
Session什么时候创建?
Session在用户第一次访问服务器的时候自动创建。需要注意只有访问JSP、Servlet等程序时才会创建 Session,只访问HTML、IMAGE等静态资源并不会创建Session。如果尚未生成Session,也可以使 request.getSession(true)强制生成Session。Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session活跃(active) 了一次。
-
Session什么时候删除?
为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。
-
可以通过对应的setMaxInactiveInterval方法对保持时间进行设置;
-
可以在web.xml文件中进行设置。
<session-config> <session-timeout>30</session-timeout> </session-config>
-
4.2 Cookie
Cookie通过在客户端记录信息确定用户身份, Cookie是客户端(一般指浏览器)请求服务器后,服务器发给客户端的一个辨认标识,保存在客户端,当客户端再次向服务器发送请求时,会携带着这个辨认标识,服务器就可以通过这个标识来识别客户端的身份或状态等。
4.2.1 Cookie的常见作用
-
保持登录
将用户的信息保存到Cookie中,并发送给浏览器,并且将有效时间设置为一个较长的时间(默认是关闭浏览器就清除Cookie),这样浏览器在以后访问网站时,都会带着该Cookie,服务器以此来辨识用户,用户就不再需要输入用户名和密码等信息。
-
记录用户名
一旦用户登录成功以后,下次再登录时,直接将Cookie中的用户名读取并显示出来,这样用户就不需要再次输入用户名,只输入密码即可(浏览器已经自动实现)。
4.2.2 Cookie的设置、获取以及有效时间
-
通过HttpServletResponse.addCookie的方式设置Cookie
Cookie cookie = new Cookie("key","value"); response.addCookie(cookie);//如果是我们创建sseion的时候,其实服务器隐含了帮我们把SessionId存进cookie并携带响应了
-
服务端通过HttpServletRequest获取客户端携带的cookie
Cookie[] cookies = request.getCookies(); String value =""; if(cookies != null) for(Cookie c : cookies){ String name = c.getName();//获取Cookie名称key if("key".equals(name)){ value = c.getValue();//获取Cookie的值value break; } }
-
Cookie的有效时间
//setMaxAge⽤来设置Cookie的最⼤有效时间,需要int型的参数,代表有效的秒数 cookie.setMaxAge(秒数); //(1)会话Cookie,即在当前会话有效,退出浏览器后会话Cookie自动清除 //当参数小于0时,和不设置是一样的(即等价于默认设置) cookie.setMaxAge(-100); //当参数等于0时,浏览器不会保存Cookie,Cookie立即失效(可以看作是删除Cookie) cookie.setMaxAge(0); //(2)持久Cookie/硬盘Cookie,在保持时间内持久性存储到用户的硬盘中,直到过期后清除。 //当参数大于0时,会设置为指定的秒数 cookie.setMaxAge(30);
4.3 Session与Cookie的区别
Session技术是依赖于Cookie技术的, Session是由应用服务器维持的一个服务器端的存储空间,用户在连接服务器时,会由服务器生成一个唯一的SessionID,并使用该SessionID 作为标识符来存取服务器端的Session存储空间。之后,SessionID这一数据则会响应到客户端,用Cookie保存的,用户提交请求时,会将这一SessionID提交到服务器端来存取 Session数据。
一旦客户端禁用Cookie,那么Session也会失效(就像钥匙和锁,钥匙都没了,也就找不到对应的锁了,Session技术也就没用了)。
- Session(底层是基于Cookie实现的)
-
Session把用户的数据写到用户独占Session中,服务器端保存 ,相对安全一些;
-
Session对象由服务器创建;
-
Session可以保存很多数据,但是过多会导致内存溢出;
因为通常是存在服务器的内存里,所以一般只用来保存重要的信息,减少服务器资源的浪费。
-
Session调用特有方法设置保持时间,时间一过即失效。
-
- Cookie
- Cookie是把用户的数据写给用户的浏览器,浏览器保存,相对不安全一些;
- 一个Cookie只能保存一个信息(不超过4kb),一个web站点可以给浏览器发送多个cookie(大多数浏览器限制一个站点最多存放20个cookie);
- 不设置有效期(会话Cookie默认在关闭浏览器后自动失效,设置了的话会保存到硬盘里);
- 设置有效期时间为 0 (不保存)。
5. 设置与获取初始化参数
5.1 局部初始化参数
-
在web.xml中,直接在某一Servlet标签中配置参数,只对当前Servlet的处理有效。
<servlet> <servlet-name>名称</servlet-name> <servlet-class>路径</servlet-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </servlet>
-
servlet中获得初始化参数,重写init()方法
public void init(ServletConfig config) throws ServletException { encoding= config.getInitParameter("encoding"); }
5.2 全局初始化参数
-
在web.xml中,context-param标签与servlet标签同级,单独添加这样的一个标签并配置参数,可以对所有servlet的处理有效。
<context-param> <param-name>参数名</param-name> <param-value>参数值</param-value> </context-param>
-
获得数据
// 请求->init()->service()->doget/dopost->destory(); @Override public void init(ServletConfig config) throws ServletException { 参数名=config.getServletContext().getInitParameter("参数名"); }
5.3 会话失效时间
web.xml中设置。
<!--设置Session默认的失效时间-->
<session-config>
<!--15分钟后Session自动失效,以分钟为单位-->
<session-timeout>15</session-timeout>
</session-config>
6. Servlet3.0注解
从Servlet3.0开始,配置Servlet支持注解方式(Servlet类上使用@WebServlet注解进行配置),但还是保留了配置web.xml方式。
下例是通过注解方式配置,web.xml中不需要配置该Servlet,相当于把xml里该配置的东西通过注解的方式搬过来了。
@WebServlet(name = "myUserServlet",
urlPatterns = "/user/test",
loadOnStartup = 1,
initParams = {
@WebInitParam(name="name", value="啊明"),
@WebInitParam(name="pwd", value="123456")
}
)
public class UserServlet extends HttpServlet {
//……
}
-
@WebServlet
属性 类型 是否必选 使用说明 name String 否 指定Servlet名称 urlPatterns/value String[] 否 这两个属性作用相同,指定Servlet处理的url,斜杠必须,可以多个 loadOnStartup int 否 标记容器是否在应用启动时就加载这个 Servlet,等价于配置文件中的标签,0或正数代表应用启动时就加载这个 Servlet,正数越小优先级越高 initParams webInitParam[] 否 配置初始化参数 displayName String 否 指定Servlet显示名称 asyncSupported boolean 否 指定Servlet是否支持异步操作模式 -
@WebInitParam
属性 类型 使用说明 name String 指定参数名称 value String 指定参数对应值
7. 过滤器Filter
7.1 过滤器的概念
过滤器实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或Servlet处理,通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理。
7.2 过滤器的使用
-
创建一个类实现Filter接口
public class CharSetFilter implements Filter{}
-
重写接口中的方法
public void destroy() { //销毁的方法 } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { //过滤方法 主要是对request和response进行一些处理,然后交给下一个过滤器,没有下一个了就交给Servlet处理 chain.doFilter(req, resp);//执行过滤器链 } public void init(FilterConfig config) throws ServletException { /*服务器一启动就会执行初始化方法(单例模式) 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置*/ }
-
在web.xml文件中配置
使用多个过滤器的时候,web.xml中的配置顺序就是过滤器执行的顺序。(先执行的过滤器最后结束,和递归return一样)
<filter> <filter-name>过滤器名称</filter-name> <filter-class>过滤器所在的路径</filter-class> </filter> <filter-mapping> <filter-name>过滤器名称</filter-name> <url-pattern>需要过滤的资源</url-pattern> </filter-mapping>
7.3 过滤器的生命周期
程序启动时调用Filter的init()方法(唯一 一次),程序停止时调用Filter的destroy()方法(唯一 一次),doFilter()方法每次的访问请求如果符合拦截条件都会调用。
如果是程序第一次运行,会在servlet调用init()方法以后调用;不管第几次,都在调用doGet(),doPost()方法之前。同时,过滤器的生命周期可以类比一下servlet的生命周期。
7.4 过滤器使用场景
- 防止用户未登录就执行后续操作
- 设置编码方式
- 非法文字筛选
- 下载资源的限制
- 可以在servlet之前和之后执行特定的操作
- ……
8. 监听器Listener
8.1 监听器的相关概念
-
事件源:
被监听的对象(三个域对象 request、session、servletContext) 。
-
监听器:
监听器就是监听某个域对象的的状态变化的组件,监听事件源对象、事件源对象的状态的变化都会触发监听器。
-
注册监听器:
将监听器与事件源进行绑定 。
-
响应行为:
监听器监听到事件源的状态变化时所涉及的功能代码(程序员编写代码)。
8.2 监听器的分类
- ServletContext域
- 监听域对象的创建与销毁:ServletContextListener;
- 初始化的工作:初始化对象、初始化数据(加载数据库驱动、连接池的初始化)
- 监听域对象的属性变化:ServletContextAttributeListener。
- 监听域对象的创建与销毁:ServletContextListener;
- HttpSession域
- 监听域对象的创建与销毁:HttpSessionListener;
- 监听域对象的属性变化:HttpSessionAttributeListener。
- ServletRequest域
- 监听域对象的创建与销毁:ServletRequestListener;
- 监听域对象的属性变化:ServletRequestAttributeListener。
8.3 监听器的使用(以HttpSession域的监听器为例)
-
编写一个监听器类去实现监听器接口
//监听创建和销毁 public class SessionListener implements HttpSessionListener{} //监听操作域对象的属性 public class SessionListener implements HttpSessionAttributeListener{}
-
实现对应监听器的方法
//监听创建和销毁 @Override public void sessionCreated(HttpSessionEvent httpSessionEvent){ //代码 } @Override public void sessionDestroyed(HttpSessionEvent httpSessionEvent){ //代码 }
//监听操作域对象的属性 @Override public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent){//增加 //代码 } @Override public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent){//删除 //代码 } @Override public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent){//更改 //代码 }
-
在web.xml中进行配置
<listener> <listener-class>监听器所在的路径</listener-class> </listener>
8.4 监听器的生命周期与作用
- ServletContext域
- 生命周期:
- 何时创建:服务器启动创建
- 何时销毁:服务器关闭销毁
- contextInitialized在容器启动时被调用(在ServletContext被实例化后执行);
- contextDestroyed 在容器销毁时调用(在ServletContext被销毁前执行)。
- 主要作用:
- 初始化的工作:初始化对象、初始化数据(加载数据库驱动、连接池的初始化)
- 加载一些初始化的配置文件(spring的配置文件)
- 任务调度(定时器—Timer/TimerTask)
- 统计网站访问量
- ……
- HttpSession域
- 生命周期:
- 何时创建:第一次用request.getSession时创建
- 何时销毁:服务器关闭销毁、session过期、手动销毁
- sessionCreated 在HttpSession创建后调用;
- sessionDestroyed 在HttpSession销毁前调用。
- 主要作用:
例如,由于每次访问网站都会默认创建session对象(jsp开头的page指令中的session属性默认为 true,即被访问时创建session),可以以于计数网站在线的人。 - ServletRequest域
- 生命周期:
- requestDestroyed 在request对象创建后调用(发起请求);
- requestInitialized 在request对象销毁前调用(请求结束)。
- 主要作用:监听每次请求中的创建、增删改、销毁。
9. Servlet、过滤器Filter、监听器Listener加载的先后顺序
参考文章:
https://blog.youkuaiyun.com/wang_shuyu/article/details/53572046
https://www.cnblogs.com/caijh/p/7683007.html
- 服务器启动;
- 服务器创建ServletContext对象;
- 创建监听器对象(监听器对象的创建顺序按照配置顺序依次往下);
- ServletContextListener执行contextInitialized()方法;
- 创建过滤器对象(过滤器对象的创建顺序按照配置顺序依次往下);
- 创建Servlet对象(设置了服务器启动就创建的Servlet)
- ---------------------------开始请求(1-n)------------------------------------
- 每次请求,服务器会创建一个Request对象;
- ServletRequestListener执行requestInitialized()方法;
- 第一次被访问到的、还没有创建实例的Servlet进行实例化并执行init()方法;
- 过滤器链开始执行;
- 创建Session对象;
- HttpSessionListener执行sessionCreated()方法;
- 执行Servlet中的service()方法(doPost、doGet……);
- 过滤器链执行完毕;
- ServletRequestListener执行requestDestroyed()方法;
- Request对象销毁;
- ---------------------------请求结束-----------------------------------
- 过滤器对象销毁;
- ServletContextListener执行contextDestroyed()方法;
- ServletContext对象销毁;
- 服务器关闭。
注意:
(1)ServletContextAttributeListener、HttpSessionAttributeListener、ServletRequestAttributeListener只有触发对应操作时执行对应监听方法;
(2)注意session的是否销毁(时间到期、手动销毁),不然不会看到HttpSessionListener执行对应的监听销毁的方法。
web.xml中的加载顺序:context-param -> ServletContext -> Listener -> Filter -> Servlet 详细介绍