Tomcat的使用
Tomcat简介
Tomcat服务器是Apache的一个开源免费的Web容器。它实现了JavaEE平台下部分技术规范,属于轻量级应用服务器。
Tomcat版本说明
Tomcat作用
可以在Tomcat中运行我们所编写的Servlet、JSP。
Tomcat下载与安装
下载
下载地址:http://tomcat.apache.org/
配置环境变量
Tomcat是用Java语言开发的Web容器,所以在使用Tomcat时需要在操作系统中正确配置环境变量。
JAVA_HOME:C:\Program Files\Java\jdk1.8.0_171
PATH:%JAVA_HOME%\bin;
CLASS_PATH:%JAVA_HOME%\lib;
Tomcat目录结构与介绍
bin
bin目录主要是用来存放tomcat的命令文件,主要有两大类,一类是以.sh结尾的(linux命令),另一类是以.bat结尾的(windows命令)。
conf
conf目录主要是用来存放tomcat的一些配置文件。
lib
lib目录主要用来存放tomcat运行需要加载的jar包。
logs
logs目录用来存放tomcat在运行过程中产生的日志文件。
temp
temp目录用户存放tomcat在运行过程中产生的临时文件。(清空不会对tomcat运行带来影响)
webapps
webapps目录用来存放应用程序,当tomcat启动时会去加载
webapps目录下的应用程序。可以以文件夹、war包的形式发布应用。
work
work目录用来存放tomcat在运行时的编译后文件,例如JSP编译后的文件。
Tomcat启动与关闭
Tomcat启动
- 方式一
运行startup.bat文件。 - 方式二
catlina.bat start
其中catlina.bat是命令文件,start是启动Tomcat参数。
Tomcat关闭
- 方式一
运行shutdown.bat文件。 - 方式二
catlina.bat stop
其中catlina.bat是命令文件,stop是关闭Tomcat参数。 - 方式三
直接关闭掉控制台窗口。
访问Tomcat
访问Tomcat的URL格式:
http://ip:port
访问本机Tomcat的URL格式:
http://localhost:8080
Tomcat配置文件介绍
Tomcat 的配置文件由4个xml组成,分别是 context.xml、web.xml、server.xml、tomcat-users.xml。每个文件都有自己的功能与配置方法。
context.xml
context.xml 是 Tomcat 公用的环境配置。 Tomcat 服务器会定时去扫描这个文件。一旦发现文件被修改(时间戳改变了),就会自动重新加载这个文件,而不需要重启服务器 。
web.xml
Web应用程序描述文件,都是关于是Web应用程序的配置文件。所有Web应用的 web.xml 文件的父文件。
server.xml
是 tomcat 服务器的核心配置文件,server.xml的每一个元素都对应了 tomcat中的一个组件,通过对xml中元素的配置,实现对tomcat中的各个组件和端口的配置。
tomcat-users.xml
配置访问Tomcat的用户以及角色的配置文件。
解决控制台乱码
控制台产生乱码的原因是在Tomcat在输出日志中使用的是UTF-8编码,而我们中文的Windows操作系统使用的是GBK编码。由于编码格式不统一,所以出现了乱码。
解决方式:修改conf目录中的logging.properties文件重新指定的编码方式。
java.util.logging.ConsoleHandler.encoding =GBK
修改Tomcat监听端口
Tomcat默认监听端口为8080。可以通过修改server.xml文件来改变Tomcat的监听端口。
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
Tomcat架构讲解
Tomcat工作原理
Tomcat是一个能够处理请求并产生响应的应用程序。Tomcat实现了JavaEE平台下的一些技术规范,所以我们可以在Tomcat中运行我们所编写的Servlet、JSP。
Tomcat架构图
conf/server.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<!-- 连接器监听端口是 8080,默认通讯协议是HTTP/1.1 -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<!-- 名字为 Catalina 的引擎,其默认的虚拟主机是 localhost -->
<Engine name="Catalina"
defaultHost="localhost">
<!-- 名字为 localhost 的虚拟主机,其目录是webapps-->
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
</Host>
</Engine>
</Service>
</Server>
Tomcat组件
Server组件
启动一个server实例(即一个JVM进程),它监听在8005端口以接收shutdown命令。Server的定义不能使用同一个端口,这意味着如果在同一个物理机上启动了多个Server实例,必须配置它们使用不同的端口。
<Server port="8005" shutdown="SHUTDOWN">
port: 接收shutdown指令的端口,默认为8005;
shutdown:发往此Server用于实现关闭tomcat实例的命令字符串,默认为SHUTDOWN;
Service组件
Service主要用于关联一个引擎和与此引擎相关的连接器,每个连接器通过一个特定的端口和协议接收请求并将其转发至关联的引擎进行处理。困此,Service要包含一个引擎、一个或多个连接器。
<Service name="Catalina">
Connector组件
支持处理不同请求的组件,一个引擎可以有一个或多个连接器,以适应多种请求方式。默认只开启了处理Http协议的连接器。如果需要使用其他协议,需要在Tomcat中配置该协议的连接器。
在Tomcat中连接器类型通常有4种:
- HTTP连接器
- SSL连接器
- AJP 1.3连接器
- proxy连接器
<Connector port="8888" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
port:监听的端口
protocol:连接器使用的协议,默认为HTTP/1.1;
connectionTimeout:等待客户端发送请求的超时时间,单位为毫秒;
redirectPort:如果某连接器支持的协议是HTTP,当接收客户端发来的HTTPS请求时,则转发至此属性定义的端口;
maxThreads:支持的最大并发连接数,默认为200个;
Engine组件
Engine是Servlet处理器的一个实例,即servlet引擎,定义在server.xml中的Service标签中。Engine需要defaultHost属性来为
其定义一个接收所有发往非明确定义虚拟主机的请求的Host组件。
<Engine name="Catalina" defaultHost="localhost">
name:Engine组件的名称;
defaultHost:Tomcat支持基于FQDN(Fully Qualified Domain Name 全限定域名)的虚拟主机,这些虚拟主机可以通过在Engine容器中定义多个不同的Host组件来实现;但如果此引擎的连接器收到一个发往非明确定义虚拟主机的请求时则需要将此请求发往一个默认的虚拟主机进行处理,因此,在Engine中定义的多个虚拟主机的主机名称中至少要有一个跟defaultHost定义的主机名称同名;
Host组件
虚拟主机(英语:virtual hosting)或称共享主机(shared web hosting),又称虚拟服务器,是一种在单一主机或主机群上,实现多网域服务的方法,可以运行多个网站或服务的技术。
Host组件位于Engine容器中用于接收请求并进行相应处理的虚拟主机。通过该容器可以运行Servlet或者JSP来处理请求。
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
name:虚拟主机的名称,Tomcat通过在请求URL中的域名与name中的值匹配,用于查找能够处理该请求的虚拟主机。如果未找到则交给在Engine中defaultHost指定的主机处理;
appBase:此Host的webapps目录,即指定存放web应用程序的目录的路径;
autoDeploy:在Tomcat处于运行状态时放置于appBase目录中的应用程序文件是否自动进行deploy;默认为true;
unpackWARs:在启用此webapps时是否对WAR格式的归档文件先进行展开;默认为true;
Context组件
Context是Host的子组件,代表指定一个Web应用,它运行在某个指定的虚拟主机(Host)上;每个Web应用都是一个WAR文件,或文件的目录。
<Context path="/test" docBase="D:\bjsxt\itbaizhan.war" />
path:context path既浏览器访问项目的访问路径。
docBase:相应的Web应用程序的存放位置;也可以使用相对路径,起始路径为此Context所属Host中appBase定义的路径;
Servlet简介
Servlet是Server Applet的简称,称为服务端小程序,是JavaEE平台下的技术标准,基于Java语言编写的服务端程序。 Web 容器或应用服务器实现了Servlet标准所以Servlet需要运行在Web容器或应用服务器中。Servlet主要功能在于能够在服务器中执行并生成数据。
Servlet技术特点
单进程多线程方式运行
Servlet在应用程序中的位置
部署Servlet
Web工程目录结构
Tomcat运行过程
1.用户访问localhost:8888/test/helloword.do,请求被发送到Tomcat,被监听8888端口并处理HTTP/1.1 协议的Connector获得。
2. Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应。
3. Engine获得请求localhost/test/helloword.do,匹配所有的虚拟主机Host。
4. Engine匹配到名为localhost的Host虚拟主机来处理/test/helloword.do请求(即使匹配不到会请求交给默认Host处理)。
5. 匹配到的Context获得请求/helloword.do。
6. 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用HelloWorld的doGet()或doPost().执行业务逻辑、数据存储等程序。
7. Context把执行完之后的结果通过HttpServletResponse对象返回给Host。
8. Host把HttpServletResponse返回给Engine。
9. Engine把HttpServletResponse对象返回Connector。
10. Connector把HttpServletResponse对象返回给客户Browser。
Servlet继承结构
Servlet接口
- init(),创建Servlet对象后立即调用该方法完成一些初始化工作。
- service(),处理客户端请求,执行业务操作,利用响应对象响应客户端请求。
- destroy(),在销毁Servlet对象之前调用该方法,释放资源。
- getServletConfig(),ServletConfig是容器向servlet传递参数的载体。
- getServletInfo(),获取servlet相关信息。
ServletConfig接口
- String getServletName(),返回 Servlet 的名字,即 web.xml 中 元素的值。
- ServletContext getServletContext(),返回一个代表当前 Web 应用的 ServletContext 对象。
- String getInitParameter(String name),根据初始化参数名返回对应的初始化参数值。
- Enumeration getInitParameterNames(),返回一个 Enumeration 对象,其中包含了所有的初始化参数名。
GenericServle抽象类
GenericServlet是实现了Servlet接口的抽象类。在GenericServlet中进一步的定义了Servlet接口的具体实现,其设计的目的是为了和应用层协议解耦,在GenericServlet中包含一个Service抽象方法。
HttpServlet类
继承自 GenericServlet,针对于处理 HTTP 协议的请求所定制。在HttpServlet的service() 方法中已经把 ServletReuqest 和
ServletResponse 转为 HttpServletRequest 和HttpServletResponse。 直接使用 HttpServletRequest 和HttpServletResponse, 不再需要强转。实际开发中, 直接继承HttpServlet, 并根据请求方式复写 doXxx() 方法即可。
Servlet的生命周期
Servlet的生命周期是由容器管理的,分别经历三各阶段:
init():初始化
service():服务
destroy():销毁
当客户端浏览器第一次请求Servlet时,容器会实例化这个Servlet,然后调用一次init方法,并在新的线程中执行service方法处理请求。service方法执行完毕后容器不会销毁这个Servlet而是做缓存处理,当客户端浏览器再次请求这个Servlet时,容器会从缓存中直接找到这个Servlet对象,并再一次在新的线程中执行Service方法。当容器在销毁Servlet之前对调用一次destroy方法。
Servlet处理请求的原理
当浏览器基于get方式请求我们创建Servlet时,我们自定义的Servlet中的doGet方法会被执行。doGet方法能够被执行并处理get请求的原因是,容器在启动时会解析web工程中WEB-INF目录中的web.xml文件,在该文件中我们配置了Servlet与URI的绑定,容器通过对请求的解析可以获取请求资源的URI,然后找到与该URI绑定的Servlet并做实例化处理(注意:只实例化一次,如果在缓存中能够找到这个Servlet就不会再做次实例化处理)。在实例化时会使用Servlet接口类型作为引用类型的定义,并调用一次init方法,由于GenericServlet中重写了该方法所以最终执行的是GenericServlet中init方法(GenericServlet中的Init方法是一个空的方法体),然后在新的线程中调用service方法。由于在HttpServlet中重写了Service方法所以最终执行的是HttpServlet中的service方法。在service方法中通过request.getMethod()获取到请求方式进行判断如果是Get方式请求就执行doGet方法,如果是POST请求就执行doPost方法。如果是基于GET方式提交的,并且在我们的Servlet中又重写了HttpServlet中的doGet方法,那么最终会根据Java的多态特性转而执行我们自定义的Servlet中的doGet方法。
Servlet的作用
- 获取用户提交的数据
- 获取浏览器附加的信息
- 处理数据(访问数据库或调用接口)
- 给浏览器产生一个响应
- 在响应中添加附加信息
在Idea中创建Web工程
三个步骤:
- 创建Web工程
- 添加servlet-api.jar
- 配置Tomcat
Idea中的web项目部署详解
在Idea中默认的并不会把web项目真正的部署到Tomcat的webapps目录中,而是通过为每个web项目创建一个独立的Tomcat副本并在Tomcat副本中通过的Tomcat的Context组件完成项目的目录指定,
在Context组件的docBase属性中会指定Idea对web项目编译后的目录out/artifacts/…。
默认部署方式
Idea会在
C:\Users\Administrator\AppData\Local\JetBrains\IntelliJIdea2020.2\tomcat
中为每个Web项目创建一个独立的Tomcat副本。
在xml文件中指定web项目编译完后的artifacts目录的位置。
<Context path="/servletdemo" docBase="D:\webproject\servletdemo\out\artifacts\servletdemo_war_exploded" />
Idea在启动Tomcat之前会先在操作系统中设置一些临时环境变量,这些变量会被Tomcat的启动脚本所读取。
CATALINA_BASE:是Tomcat副本的工作目录
CATALINA_HOME:是Tomcat的安装目录
在Catalina.bat启动脚本运行时,会先去判断脚本中的CATALINA_HOME以及CATALINA_BASE是否为空,如果为空则使用
Tomcat路径作为默认值。由于Idea在启动Tomcat之前已经设置了临时环境变量,所以tomcat在启动后就会运行部署在Tomcat副本中的web项目。
将web项目部署到Tomcat的webapps中
点击项目结构选项
指定输出artifacts的目录为Tomcat的webapps中的demo目录。
HttpServletRequest对象
HttpServletRequest对象代表客户端浏览器的请求,当客户端浏览器通过HTTP协议访问服务器时,HTTP请求中的所有信息都会被Tomcat所解析并封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息。
获取请求信息
req.getRequestURL()
返回客户端浏览器发出请求时的完整URL。
req.getRequestURI()
返回请求行中指定资源部分。
req.getRemoteAddr()
返回发出请求的客户机的IP地址。
req.getLocalAddr()
返回WEB服务器的IP地址。
req.getLocalPort()
返回WEB服务器处理Http协议的连接器所监听的端口。
获取请求数据
根据key获取指定value
req.getParameter(“key”);
根据key获取对应的value,返回一个字符串。
String str = req.getParameter("key");
获取复选框(checkbox组件)中的值
req.getParameterValues(“checkboxkey”);
获取复选框(checkbox组件)中的值,返回一个字符串数组。
String[] userlikes = req.getParameterValues("checkboxkey");
获取所有提交数据的key
req.getParameterNames()
获取请求中所有数据的key,该方法返回一个枚举类型。
Enumeration<String> parameterNames = req.getParameterNames();
使用Map结构获取提交数据
req.getParameterMap()
获取请求中所有的数据并存放到一个Map结构中,该方法返回一个Map,其中key为String类型value为String[]类型。
Map<String, String[]> parameterMap = req.getParameterMap()
设置请求编码
req.setCharacterEncoding(“utf-8”)
请求的数据包基于字节在网络上传输,Tomcat接收到请求的数据包后会将数据包中的字节转换为字符。
在Tomcat中使用的是ISO8859-1的单字节编码完成字节与字符的转换,所以数据中含有中文就会出现乱码,可以通过req.setCharacterEncoding(“utf-8”)方法来对提交的数据根据指定的编码方式重新做编码处理。
资源访问路径
绝对路径
绝对路径访问资源表示直接以”/”作为项目的Context Path。该方式适用于以”/”作为项目的Context Path。
<form action="/getInfo.do" method="post">
相对路径
相对路径访问资源表示会相对于项目的Context Path作为相对路径。该方式适用于为项目指定的具体的Context Path。
<form action="getInfo.do" method="post">
获取请求头信息
req.getHeader(“headerKey”)
根据请求头中的key获取对应的value。
String headerValue = req.getHeader("headerKey");
req.getHeaderNames()
获取请求头中所有的key,该方法返回枚举类型。
Enumeration<String> headerNames = req.getHeaderNames();
HttpServletRequest对象的生命周期
当有请求到达Tomcat时,Tomcat会创建HttpServletRequest对象,并将该对象通过参数的方式传递到我们Servlet的方法中,当处理请求处理完毕并产生响应后该对象生命周期结束。
HttpServletResponse对象
HttpServletResponse对象代表服务器的响应。这个对象中封装了响应客户端浏览器的流对象,以及向客户端浏览器响应的响应头、响应数据、响应状态码等信息。
设置响应类型
resp.setContentType(“MIME”)
该方法可通过MIME-Type设置响应类型。
设置字符型响应
常见的字符型响应类型:
resp.setContentType(“text/html”)
设置响应类型为文本型,内容含有html字符串,是默认的响应类型
resp.setContentType(“text/plain”)
设置响应类型为文本型,内容是普通文本。
resp.setContentType(“application/json”)
设置响应类型为JSON格式的字符串。
设置字节型响应
常见的字节型响应:
resp.setContentType(“image/jpeg”)
设置响应类型为图片类型,图片类型为jpeg或jpg格式。
resp.setContentType(“image/gif”)
设置响应类型为图片类型,图片类型为gif格式。
设置响应编码
设置响应编码有两种方式
- response.setContentType(“text/html; charset=UTF-8”);
- response.setCharacterEncoding(“UTF-8”);
response.setContentType(“text/html;charset=utf-8”);
不仅发送到浏览器的内容会使用UTF-8编码,而且还通知浏览器使用UTF-8编码方式进行显示。所以总能正常显示中文
response.setCharacterEncoding(“utf-8”);
仅仅是发送的浏览器的内容是UTF-8编码的,至于浏览器是用哪种编码方式显示不管。 所以当浏览器的显示编码方式不是UTF-8的时候,就会看到乱码,需要手动指定浏览器编码。
在响应中添加附加信息
重定向响应
response.sendRedirect(URL地址)
重定向响应会在响应头中添加一个Location的key对应的value是给定的URL。客户端浏览器在解析响应头后自动向Location中的URL发送请求。
重定向响应特点:
- 重定向会产生两次请求两次响应。
- 重定向的URL是由客户端浏览器发送的。
- 浏览器地址栏会有变化。
文件下载
在实现文件下载时,我们需要在响应头中添加附加信息。
response.addHeader(“Content-Disposition”,“attachment; filename=”+文件名);
Content-Disposition:attachment
该附加信息表示作为对下载文件的一个标识字段。不会在浏览器中显示而是直接做下载处理。
filename=文件名
表示指定下载文件的文件名。
解决文件名中文乱码问题
resp.addHeader("ContentDisposition","attachment;filename="+new String(file.getName().getBytes("gbk"),"iso8859-1"));
ServletContext对象
ServletContext对象介绍
ServletContext官方叫Servlet上下文。服务器会为每一个Web应用创建一个ServletContext对象。这个对象全局唯一,而且Web应用中的所有Servlet都共享这个对象。所以叫全局应用程序共享对象。
ServletContext对象的作用
- 相对路径转绝对路径
- 获取容器的附加信息
- 读取配置信息
- 全局容器
相对路径转绝对路径
context.getRealPath(“path”)
该方法可以将一个相对路径转换为绝对路径,在文件上传与下载时需要用到该方法做路径的转换。
获取容器的附加信息
servletContext.getServerInfo()
返回Servlet容器的名称和版本号
servletContext.getMajorVersion()
返回Servlet容器所支持Servlet的主版本号。
servletContext.getMinorVersion()
返回Servlet容器所支持Servlet的副版本号。
获取web.xml文件中的信息
<context-param>
<param-name>key</param-name>
<param-value>value</param-value>
</context-param>
servletContext.getInitParameter(“key”)
该方法可以读取web.xml文件中标签中的配置信息。
servletContext.getInitParameterNames()
该方法可以读取web.xml文件中所有param-name标签中的值。
全局容器
servletContext.setAttribute(“key”,ObjectValue)
向全局容器中存放数据。
servletContext.getAttribute(“key”)
从全局容器中获取数据。
servletContext.removeAttribute(“key”)
根据key删除全局容器中的value。
ServletContext对象生命周期
当容器启动时会创建ServletContext对象并一直缓存该对象,直到容器关闭后该对象生命周期结束。ServletContext对象的生命周期非常长,所以在使用全局容器时不建议存放业务数据。
ServletConfig对象
ServletConfig对象对应web.xml文件中的节点。当Tomcat初始化一个Servlet时,会将该Servlet的配置信息,封装到一个ServletConfig对象中。我们可以通过该对象读取节点中的配置信息
<servlet>
<servlet-name>servletName</servlet-name>
<servlet-class>servletClass</servletclass>
<init-param>
<param-name>key</param-name>
<param-value>value</param-value>
</init-param>
</servlet>
servletConfig.getInitParameter(“key”)
该方法可以读取web.xml文件中标签中标签中的配置信息。
servletConfig.getInitParameterNames()
该方法可以读取web.xml文件中当前标签中所有标签中的值。
Cookie对象与HttpSession对象
Cookie对象与HttpSession对象的作用是维护客户端浏览器与服务端的会话状态的两个对象。由于HTTP协议是一个无状态的协议,所以服务端并不会记录当前客户端浏览器的访问状态,但是在有些时候我们是需要服务端能够记录客户端浏览器的访问状态的,如获取当前客户端浏览器的访问服务端的次数时就需要会话状态的维持。在Servlet中提供了Cookie对象与HttpSession对象用于维护客户端与服务端的会话状态的维持。二者不同的是Cookie是通过客户端浏览器实现会话的维持,而HttpSession是通过服务端来实现会话状态的维持。
Cookie对象的特点
- Cookie使用字符串存储数据
- Cookie使用Key与Value结构存储数据
- 单个Cookie存储数据大小限制在4097个字节
- Cookie存储的数据中不支持中文,Servlet4.0中支持 Cookie是与域名绑定所以不支持跨一级域名访问
- Cookie对象保存在客户端浏览器内存或系统磁盘中 Cookie分为持久化Cooke与状态Cookie
- 浏览器在保存同一域名所返回Cookie的数量是有限的。不同浏览器支持的数量不同,Chrome浏览器为50个
- 浏览器每次请求时都会把与当前访问的域名相关的Cookie在请求中提交到服务端。
Cookie对象的创建
Cookie cookie = new Cookie(“key”,“value”)
通过new关键字创建Cookie对象
response.addCookie(cookie)
通过HttpServletResponse对象将Cookie写回给客户端浏览器。
获取Cookie中的数据
浏览器每次请求时都会把与当前访问的域名相关的Cookie在请求中提交到服务端。通过HttpServletRequest对象获取Cookie,返回Cookie数组。
Cookie[] cookies = request.getCookies()
解决Cookie不支持中文
在Cookie中name的值不能使用中文,Value是可以的。但是在Servlet4.0版本之前Cookie中的Value也是不支持中文存储的,如果存储的数据中含有中文,代码会直接出现异常。我们可以通过对含有中文的数据重新进行编码来解决该问题。在Servlet4.0中的Cookie的Value开始支持中文存储。
java.lang.IllegalArgumentException: Control character in cookie value or attribute.
URLEncoder.encode(“content”,“code”)
将内容按照指定的编码方式做URL编码处理。
URLDecoder.decode(“content”,“code”)
将内容按照指定的编码方式做URL解码处理。
Cookie跨域问题
域名分类:域名分为顶级域、顶级域名(一级域名)、二级域名。
域名等级的区别:一级域名比二级域名更高级,二级域名是依附于一级域名之下的附属分区域名,即二级域名是一级域名的细化分级。例如:baidu.com 为一级域名,news.baidu.com为二级域名。
Cookie不支持一级域名的跨域,支持二级域名的跨域。
状态Cookie与持久化Cookie
状态Cookie:Cookie对象仅会被缓存在浏览器所在的内存中。当浏览器关闭后Cookie对象 也会被销毁。
持久化Cookie:浏览器会对Cookie做持久化处理,基于文件形式保存在系统的指定目录中。在Windows10系统中为了安全问题不会显示Cookie中的内容。
当Cookie对象创建后默认为状态Cookie。可以使用Cookie对象下的cookie.setMaxAge(60)方法设置失效时间,单位为秒。一旦设置了失效时间,那么该Cookie为持久化Cookie,浏览器会将Cookie对象持久化到磁盘中。当失效时间到达后文件删除。
Cookie总结
Cookie对于存储内容是基于明文的方式存储的,所以安全性很低。不要在Cookie中存放敏感数据。在数据存储时,虽然在Servlet4.0中Cookie支持中文,但是建议对Cookie中存放的内容做编码处理,也可提高安全性。
HttpSession对象的特点
- HttpSession保存在服务端
- HttpSession使用Key与Value结构存储数据
- HttpSession的Key是字符串类型,Value则是Object类型
- HttpSession存储数据大小无限制
HttpSession对象的创建
HttpSession对象的创建是通过request.getSession()方法来创建的。客户端浏览器在请求服务端资源时,如果在请求中没有
jsessionid,getSession()方法将会为这个客户端浏览器创建一个新的HttpSession对象,并为这个HttpSession对象生成一个
jsessionid,在响应中通过状态Cookie写回给客户端浏览器,如果在请求中包含了jsessionid,getSession()方法则根据这个ID返回与这个客户端浏览器对应的HttpSession对象。
getSession()方法还有一个重载方法getSession(true|false)。当参数为true时与getSession()方法作用相同。当参数为false时则只去根据jsessionid查找是否有与这个客户端浏览器对应的HttpSession,如果有则返回,如果没有jsessionid则不会创建新的
HttpSession对象。
HttpSession对象的使用
session.setAttribute(“key”,value)
将数据存储到HttpSession对象中
Object value = session.getAttribute(“key”)
根据key获取HttpSession中的数据,返回Object
Enumeration attributeNames = session.getAttributeNames()
获取HttpSession中所有的key,返回枚举类型
session.removeAttribute(“key”)
根据key删除HttpSession中的数据
String id = session.getId()
根据获取当前HttpSession的SessionID,返回字符串类型
HttpSession的销毁方式
HttpSession的销毁方式有两种:
- 通过web.xml文件指定超时时间
- 通过HttpSession对象中的invalidate()方法销毁当前HttpSession对象
我们可以在web.xml文件中指定HttpSession的超时时间,当到达指定的超时时间后,容器就会销该HttpSession对象,单位为分钟。该时间对整个web项目中的所有HttpSession对象有效。时间的计算方式是根据最后一次请求时间作为起始时间。只要用户继续访问,服务器就会更新HttpSession的最后访问时间,并维护该HttpSession。用户每访问服务器一次,无论是否读写
HttpSession,服务器都认为该用户的HttpSession"活跃(active)"了一次,销毁时间则会重新计算。如果有哪个客户端浏览
器对应的HttpSession的失效时间已到,那么与该客户端浏览器对应的HttpSession对象就会被销毁。其他客户端浏览器对应的
HttpSession对象会继续保存不会被销毁。
<session-config>
<session-timeout>1</session-timeout>
</session-config>
我们也可以在Tomcat的web.xml文件中配置HttpSession的销毁时间。如果在Tomcat的web.xml文件中配置了HttpSession的超时时间对应的是Tomcat中所有的Web项目都有效。相当于配置了全局的HttpSession超时时间。如果我们在Web项目中配置了超时时间,那么会以Web项目中的超时时间为准。
nvalidate()方法是HttpSession对象中所提供的用于销毁当前HttpSession的方法。我们通过调用该方法可以销毁当前
HttpSession对象。
HttpSession生命周期
在HttpSession对象生命周期中没有固定的创建时间与销毁时间。何时创建取决于我们什么时候第一次调用了getSession()或
getSession(true)的方法。HttpSession对象的销毁时间取决于超时时间的到达以及调用了invalidate()方法。如果没有超时或者没有调用invalidate()方法,那么HttpSession会一直存储。默认超时时间为30分钟(Tomcat的web.xml文件配置的时间就是默认超时时间)。
HttpSession对象总结
HttpSession与Cookie的区别:
- cookie数据存放在客户的浏览器或系统的文件中,而HttpSession中的数据存放在服务器中。
- cookie不安全,而HttSession是安全的。
- 单个cookie保存的数据不能超过4K,很多浏览器都限制一个域名保存cookie的数量。而HttpSession没有容量以及数量的限制。
自启动Servlet
自启动Servlet特点
自动启动Servlet表示在Tomcat启动时就会实例化这个Servlet,他的实例化过程不依赖于请求,而是依赖容器的启动。
可以通过在web.xml中的标签中通过1配置自启动Servlet。
Servlet线程安全问题
在Servlet中使用的是多线程方式来执行service()方法处理请求,所以我们在使用Servlet时需要考虑到线程安全问题,在多线程中对于对象中的成员变量是最不安全的,所以不要在Servlet中通过成员变量的方式来存放数据,如果一定要使用成员变量存储数据,在对数据进行操作时需要使用线程同步的方式来解决线程安全问题,避免出现数据张冠李戴现象。
Servlet的url-pattern配置
URL的匹配规则
精确匹配
精确匹配是指中配置的值必须与url完全精确匹配。
<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>/demo.do</url-pattern>
</servlet-mapping>
http://localhost:8888/demo/demo.do 匹配
http://localhost:8888/demo/suibian/demo.do 不匹配
扩展名匹配
在允许使用统配符作为匹配规则,“*”表示匹配任意字符。在扩展名匹配中只要扩展名相同都会被匹配和路径无关。注意,在使用扩展名匹配时在中不能使用“/”,否则容器启动就会抛出异常。
<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
http://localhost:8888/demo/abc.do 匹配
http://localhost:8888/demo/suibian/haha.do 匹配
http://localhost:8888/demo/abc 不匹配
路径匹配
根据请求路径进行匹配,在请求中只要包含该路径都匹配。“*”表示任意路径以及子路径。
<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>/suibian/*</url-pattern>
</servlet-mapping>
http://localhost:8888/demo/suibian/haha.do 匹配
http://localhost:8888/demo/suibian/hehe/haha.do 匹配
http://localhost:8888/demo/hehe/heihei.do 不匹配
任意匹配
匹配“/”。匹配所有但不包含JSP页面
<url-pattern>/</url-pattern>
http://localhost:8888/demo/addUser.html 匹配
http://localhost:8888/demo/css/view.css 匹配
http://localhost:8888/demo/addUser.jsp 不匹配
http://localhost:8888/demo/user/addUser.jsp 不匹配
匹配所有
<url-pattern>/*</url-pattern>
http://localhost:8888/demo/suibian.do 匹配
http://localhost:8888/demo/addUser.html 匹配
http://localhost:8888/demo/suibian/suibian.do 匹配
优先顺序
当一个url与多个Servlet的匹配规则可以匹配时,则按照 “ 精确路径> 最长路径 > 扩展名”这样的优先级匹配到对应的Servlet
Servlet的多URL映射方式
在web.xml文件中支持将多个URL映射到一个Servlet中,但是相同的URL不能同时映射到两个Servlet中。
方式一
<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>/suibian/*</url-pattern>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
方式二
<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>
基于注解式开发Servlet
在Servlet3.0以及之后的版本中支持注解式开发Servlet。对于Servlet的配置不在依赖于web.xml配置文件,而是使用
@WebServlet注解完成Servlet的配置。
@WebServlet
属性名 | 类型 作用 | |
---|---|---|
initParams | WebInitParam[] Servlet的init参数 | |
name | String | Servlet的名称 |
urlPatterns | String[] | Servlet的访问URL,支持多个 |
value | String[] | Servlet的访问URL,支持多个 |
loadOnStartup | int | 自启动Servlet |
description | String | Servlet的描述 |
displayName | String | Servlet的显示名称 |
asyncSupported | boolean | 声明Servlet是否支持异步操作模式 |
@WebInitParam
属性名 | 类型 作用 | |
---|---|---|
name | String | param-name |
value | String | param-value |
description | String | description |
文件上传
在Servlet3.0之前的版本中如果实现文件上传需要依赖apache的Fileupload组件,在Servlet3.0以及之后的版本中提供了Part对象处理文件上传,所以不在需要额外的添加Fileupload组件。
在Servlet3.0以及之后的版本中实现文件上传时必须要在Servlet中
开启多参数配置:
web.xml
<multipart-config>
<file-size-threshold></file-sizethreshold>
<location></location>
<max-file-size></max-file-size>
<max-request-size></max-request-size>
</multipart-config>
@MultipartConfig
Part对象中常用的方法
long getSize()
上传文件的大小
String getSubmittedFileName()
上传文件的原始文件名
String getName()
获取<input name=“upload” …>标签中name属性值
InputStream getInputStream()
获取上传文件的输入流
void write(String path)
保存文件至服务器
Filter过滤器
过滤器作用
Filter过滤器是Servlet2.3中所提供的一个过滤请求与响应的对象。
Filter过滤器既可以对客户端向服务器端发送的请求进行过滤,也可以对服务器端向客户端产生的响应进行过滤处理。
Filter对象的创建
创建一个Class实现Filter接口,并实现接口中三个抽象方法。
init()方法:初始化方法,在创建Filter后立即调用。可用于完成初始化动作。
doFilter()方法:拦截请求与响应方法,可用于对请求和响应实现预处理。
destroy()方法:销毁方法,在销毁Filter之前自动调用。可用于完成资源释放等动作。
FilterConfig对象的使用
FilterConfig对象是用来读取中初始化参数的对象。该对象通过参数传递到init方法中,用于读取初始化参数。
filterConfig.getInitParameter(“name”)
通过name获取对应的value。
filterConfig.getInitParameterNames()
返回该Filter中所有中的值。
FilterChain(过滤器链)
Filter技术的特点是在对请求或响应做预处理时,可实现“插拔式”的程序设计。我们可以根据自己需求添加多个Filter,也可以根据需求去掉某个Filter,通过修改web.xml文件即可实现。那么如果有多个过滤器对某个请求及响应进行过滤,那么这组过滤器就称为过滤器链。
Filter执行顺序
则按照在web.xml文件中配置的上下顺序来决定先后。在上的先执
行,在下的后执行。
基于注解式开发Filter
Filter支持注解式开发,通过@WebFilter注解替代web.xml中Filter的配置
属性名 | 类型 作用 | |
---|---|---|
filterName | String | 指定过滤器的 name 属性 |
urlPatterns | String[] | 拦截请求的URL,支持多个 |
value | String[] | 拦截请求的URL,支持多个 |
description | String | 过滤器的描述 |
displayName | String | 过滤器的显示名称 |
initParams | WebInitParam[] | 指定一组过滤器初始化参数,等价于 标签。 |
使用注解式开发Filter时,执行顺序会根据Filter的名称进行排序的结果决定调用的顺序。
Filter的生命周期
Filter的生命周期是由容器管理的。当容器启动时会实例化Filter并调用init方法完成初始化动作。当客户端浏览器发送请求时容器会启动一个新的线程来处理请求,如果请求的URL能够被过滤器所匹配,那么则先调用过滤器中 的doFilter方法,再根据是否有chain.doFilter的指令,决定是否继续请求目标资源。当容器关闭时会销毁Filter对象,在销毁之前会调用destroy方法。
Listener监听器
监听器用于监听web应用中某些对象的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器会自动调用监听器对象中的方法。
监听器分类
按监听的对象划分,可以分为:
- ServletContext对象生命周期监听器与属性操作监听器;
- HttpSession对象生命周期监听器与属性操作监听器;
- ServletRequest对象生命周期监听器与属性操作监听器;
ServletContext对象的生命周期监听器
ServletContextListener接口定义了ServletContext对象生命周期的监听行为。
void contextInitialized(ServletContextEvent sce)
ServletContext对象创建之后会触发该监听方法,并将ServletContext对象传递到该方法中。
void contextDestroyed(ServletContextEvent sce)
ServletContext对象在销毁之前会触发该监听方法,并将ServletContext对象传递到该方法中。
ServletContext对象的属性操作监听器
ServletContextAttributeListener接口定义了对于ServletContext对象属性操作的监听行为。
void attributeAdded(ServletContextAttributeEvent scae)
向ServletContext对象中添加属性时会触发该监听方法,并将ServletContext对象传递到该方法中。触发事件的方法
servletContext.setAttribute(“key”,“value”)。
void attributeRemoved(ServletContextAttributeEvent scae)当从ServletContext对象中删除属性时会触发该监听方法,并将
ServletContext对象传递到该方法中。触发事件方法
servletContext.removeAttribute(“key”)。
void attributeReplaced(ServletContextAttributeEvent scae)当从ServletContext对象中属性的值发生替换时会触发该监听方
法,并将ServletContext对象传递到该方法中。触发事件的方法
servletContext.setAttribute(“key”,“value”)。
HttpSession对象的生命周期监听器
HttpSessionListener接口定义了HttpSession对象生命周期的监听行为。
void sessionCreated(HttpSessionEvent se)
HttpSession对象创建后会触发该监听方法,并将已创建HttpSession对象传递到该方法中。
void sessionDestroyed(HttpSessionEvent se)
HttpSession对象在销毁之前会触发该监听方法,并将要销毁的HttpSession对象传递到该方法中。
HttpSession对象的属性操作监听器
HttpSessionAttributeListener接口定义了对于HttpSession对象属性操作的监听行为。
void attributeAdded(HttpSessionBindingEvent se)
向HttpSession对象中添加属性时会触发该监听方法,并将HttpSession对象传递到该方法中。触发事件的方法
HttpSession.setAttribute(“key”,“value”)。
void attributeRemoved(HttpSessionBindingEvent se)
当从HttpSession对象中删除属性时会触发该监听方法,并将HttpSession对象传递到该方法中。触发事件方法
HttpSession.removeAttribute(“key”)。
void attributeReplaced(HttpSessionBindingEvent se)
当从HttpSession对象中属性的值发生替换时会触发该监听方法,并将HttpSession对象传递到该方法中。触发事件的方法
HttpSession.setAttribute(“key”,“value”)。
HttpServletRequest对象的生命周期监听器
ServletRequestListener接口定义了ServletRequest(是HttpServletRequest接口的父接口类型)对象生命周期的监听行为。
void requestInitialized(ServletRequestEvent sre)
HttpServletRequest对象创建后会触发该监听方法,并将已创建HttpServletRequest对象传递到该方法中。
void requestDestroyed(ServletRequestEvent sre)
HttpServletRequest对象在销毁之前会触发该监听方法,并将要销毁HttpServletRequest对象传递到该方法中。
HttpServletRequest对象的属性操作监听器
ServletRequestAttributeListener接口定义了对于HttpServletRequest对象属性操作的监听行为。
void attributeAdded(ServletRequestAttributeEvent srae)
向HttpServletRequest对象中添加属性时会触发该监听方法,并将HttpServletRequest对象传递到该方法中。触发事件的方法
HttpServletRequest.setAttribute(“key”,“value”)。
void attributeRemoved(ServletRequestAttributeEvent srae)
当从HttpServletRequest对象中删除属性时会触发该监听方法,并将HttpServletRequest对象传递到该方法中。触发事件方法
HttpServletRequest.removeAttribute(“key”)。
void attributeReplaced(ServletRequestAttributeEvent srae)
当从HttpServletRequest对象中属性的值发生替换时会触发该监听方法,并将HttpServletRequest对象传递到该方法中。
触发事件的方法HttpServletRequest.setAttribute(“key”,“value”)。
基于注解式开发监听器
Listener支持注解式开发,通过@WebListener注解替代web.xml中Listener的配置。
Filter与Listener设计模式
“知其然,知其所以然”。
Filter的设计模式
在Servlet的Filter中使用的责任链设计模式。
责任链模式特点
责任链(Chain of Responsibility):责任链模式也叫职责链模式,是一种对象行为模式。在责任链模式里,很多对象由每一个对象对其下一个对象的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不需要知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
责任链的优缺点
优点:
- 降低了对象之间的耦合度。
- 增强了系统的可扩展性。
- 增强了给对象指派职责的灵活性。
- 责任链简化了对象之间的连接。
- 责任分担。每个类只需要处理自己该处理的工作。
缺点: - 不能保证请求一定被接收。
- 对比较长的责任链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
- 可能会由于责任链的错误设置而导致系统出错,如可能会造成循环调用。
Listener的设计模式
在Servlet的Listener中使用的观察者设计模式。
观察者模式的特点
观察者模式(Observer Pattern):观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式的优缺点
优点:
- 观察者和被观察者是抽象耦合的。
- 建立一套触发机制。
缺点: - 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
- 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。