(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上。
文本:html,字符串,…
超文本:图片,音乐,视频,定位,地图.……
端口:80
客户端——>发请求(Request)——>服务器
服务器——>响应——>客户端
Servlet是运行在服务器上的一个java小程序,它可以接收客户端发送过来的请求,并响应数据给客户端
开发一个Servlet程序需要完成两个步骤:
编写一个类,实现Serlet接口
把开发好java类部署到web服务器中
Servlet三大组件:
Servlet程序
Filter过滤器
Listener监听器
一个Servlet只能完成一个业务处理
每个Servlet的配置信息至少8行
利用HttpServletRequest是获取客户端参数唯一方法, 并且获取的参数类型都是String, 可能需要做转换处理
Servlet处理用户的请求类型比较单一(doGet/doPost)
构建一个普通的Maven Web,项目,选择模板时勾选maven-archetype-webapp,删除src目录,pom.xml配置如下:
构建新module:HelloWorldServlet
编写Servlet程序,继承Servlet接口的实现类javax.servlet.GenericServlet来实现
修改HelloWorldServlet.web.xml
编写Servlet的映射
配置Tomcat服务器,运行程序
部署Web应用服务,利用Tomcat启动应用程序,此时Tomcat作为Servlet容器,会创建并初始化Servlet;
通过浏览器访问Web应用服务器,利用Http通讯协议传递数据;
当访问到达时,Servlet容器创建HttpServletRequest和HttpServletResponse对象,并且将请求数据放入HttpServletRequest中;
Servlet容器根据传递的url通过匹配web.xml中配置的Servlet路径,找到对应的Servlet,传递请求和响应对象;
Servlet中根据请求方式调用doGet或doPost方法,处理请求数据,将响应数据放入HttpServletResponse,返回给Servlet容器;
Servlet容器解析响应数据,根据HTTP通讯协议,返回给浏览器,浏览器解析并展示数据;
浏览器向服务器发出GET请求(请求服务器ServletA)
服务器上的容器逻辑接收到该url,根据该url判断为Servlet请求,此时容器逻辑将产生两个对象:请求对象(HttpServletRequest)和响应对象(HttpServletResponce)
容器逻辑根据url找到目标Servlet(本示例目标Servlet为ServletA),且创建一个线程A
容器逻辑将刚才创建的请求对象和响应对象传递给线程A
容器逻辑调用Servlet的service()方法
service()方法根据请求类型(本示例为GET请求)调用doGet()(本示例调用doGet())或doPost()方法
doGet()执行完后,将结果返回给容器逻辑
线程A被销毁或被放在线程池中
注意:
在容器中的每个Servlet原则上只有一个实例
每个请求对应一个线程
多个线程可作用于同一个Servlet(这是造成Servlet线程不安全的根本原因)
每个线程一旦执行完任务,就被销毁或放在线程池中等待回收
其中:
init() 方法:init() 方法是在创建 Servlet 对象时被调用,而且只能被调用一次,用于 Servlet 对象在整个生命周期内的唯一一次初始化。只有在 init() 方法调用成功后,Servlet 才会处于服务状态,才能够去处理客户端的请求。
service() 方法:service() 方法是 Servlet 工作的核心方法。当客户端请求访问 Servlet 时,Servlet 容器就会调用 service() 方法去处理来自客户端的请求,并把处理后的响应返回给客户端。
destroy() 方法:destory() 方法是 Servlet 容器回收 Servlet 对象之前调用的,且只会调用一次,而此时的服务器处于停止状态或者访问资源已经被移除。
当用户第一次向 Servlet 容器发出 HTTP 请求要求访问某个 Servlet 时,Servlet 容器会在整个容器中搜索该 Servlet 对象,发现这个 Servlet 对象没有被实例化,于是创建这个 Servlet 对象,然后调用该对象的 init() 方法完成初始化。 当用户第二次访问这个 Servlet 时,Servlet 容器仍然在容器中搜索该 Servlet 对象,结果找到了该对象的实例,则不去创建而直接使用该对象。 找到了对应的 Servlet 对象,随后 Servlet 进入到运行阶段。 需要注意的是,在 Servlet 的整个生命周期内,它的 init() 方法只被调用一次。
这是 Servlet 生命周期中最核心的阶段。在该阶段中,Servlet 容器会为当前的请求创建一个 ServletRequest 对象和一个 ServletResponse 对象(它们分别代表 HTTP 请求和 HTTP 响应),并将这两个对象作为参数传递给 Servlet 的 service() 方法。 service() 方法从 ServletRequest 对象中获得用户的详细请求信息并处理该请求,通过 ServletResponse 对象生成响应结果。 需要强调的是,在 Servlet 的整个生命周期内,用户每次请求访问 Servlet 时,Servlet 容器都会调用一次 Servlet 的 service() 方法,并且创建新的 ServletRequest 和 ServletResponse 对象。
当服务器停止时,Servlet 容器需要回收 Servlet 对象所占用的内存,在回收之前,会自动调用该对象的 destroy() 方法做好回收内存前的准备,辟如关闭后台线程。 和 init() 方法类似,destroy() 方法也只会被调用一次。
注意:Servlet 对象一旦创建就会驻留在内存中一直等待客户端的访问,直到服务器关闭或项目被移除出容器时,Servlet 对象才会被销毁。
总结:
Servlet 对象被创建之后执行 init() 方法,并且 init() 方法只执行一次,其主要目的是完成 Servlet 对象的初始化工作。
对于 Servlet 对象的 service() 方法,只要用户请求一次,那么 service() 方法就执行一次。
Servlet 对象被回收之前,destroy() 方法会被调用,该方法只执行一次,执行的时候 Servlet 对象还在。
HttpServlet是Servlet接口的一个实现类,并且它是一个抽象类,servlet.http包中定义了采用HTTP通信协议(一个无状态协议)的HttpServlet类。HttpServlet继承了GenericServlet,而GenericServlet实现Servlet接口,所以我们可以同构继承HttpServlet来创建一个Servlet。
Web客户向Servlet容器发出Http请求
Servlet容器解析Web客户的Http请求
Servlet容器创建一个HttpRequest对象,在这个对象中封装Http请求信息
Servlet容器创建一个HttpResponse对象
Servlet容器调用HttpServlet的service方法,把HttpRequest和HttpResponse对象作为service方法的参数传给HttpServlet对象
HttpServlet调用HttpRequest的有关方法,获取HTTP请求信息
HttpServlet调用HttpResponse的有关方法,生成响应数据
Servlet容器把HttpServlet的响应结果传给Web客户
其中HttpServlet首先必须读取Http请求的内容,Servlet容器负责创建HttpServlet对象,并把Http请求直接封装到HttpServlet对象中。
继承HttpServlet抽象类
重写HttpServlet的部分方法,如doGet()或doPost()方法
获取HTTP请求信息。通过HttpServletRequest对象来检索HTML表单所提交的数据或URL上的查询字符串
生成HTTP响应结果。通过HttpServletResponse对象生成响应结果
创建HttpServlet_HelloWorld具体实现类
配置xml
配置Tomcat,运行程序
在 web.xml 文件中,一个
Servlet 的多重映射指同一个 Servlet 可以被映射成多条虚拟路径。也就是说,客户端可以通过多条路径实现对同一个 Servlet 的访问。
a、配置多个
启动Tomcat
b、配置多个
在 web.xml 文件中对 TestServlet01 的
启动Tomcat
在实际开发过程中,开发者有时会希望某个目录下的所有路径都可以访问同一个 Servlet,这时,可以在 Servlet 映射的路径中使用通配符*。通配符的格式有两种,具体如下。
格式为“*.扩展名”,例如 *.do 匹配以 .do 结尾的所有 URL 地址。
格式为 /*,例如 /abc/* 匹配以 /abc 开始的所有 URL 地址。
需要注意的是,这两种通配符的格式不能混合使用,例如,/abc/*.do 是不合法的映射路径。另外,当客户端访问一个 Servlet 时,如果请求的 URL 地址能够匹配多条虚拟路径,那么 Tomcat 将采取最具体匹配原则查找与请求 URL 最接近的虚拟映射路径。例如,对于如下所示的一些映射关系:
/abc/* 映射到 Servlet1 /* 映射到 Servlet2 /abc 映射到 Servlet3 *.do 映射到 Servlet4
当请求 URL 为 /abc/a.html,/abc/* 和 /* 都可以匹配这个 URL,Tomcat 会调用 Servlet1。
当请求 URL 为 /abc、/*、/abc/* 和 /abc 都可以匹配这个 URL,Tomcat 会调用 Servlet3。
当请求 URL 为 /abc/a.do、/*、*.do 和 /abc/* 都可以匹配这个 URL,Tomcat 会调用 Servlet1。
当请求 URL 为 /a.do,/* 和 *.do 都可以匹配这个 URL,Tomcat 会调用 Servlet2。
当请求 URL 为 /xxx/yyy/a.do,*.do 和 /* 都可以匹配这个 URL,Tomcat 会调用 Servlet2。
如果某个 Servlet 的映射路径仅仅是一个正斜线(/),那么这个 Servlet 就是当前 Web 应用的默认 Servlet。Servlet 服务器在接收到访问请求时,如果在 web.xml 文件中找不到匹配的
当 URL 地址和 TestServlet01 的虚拟路径不匹配时,浏览器仍然可以正常访问HelloWorldServlet 。
代表当前Servlet在web.xml中的配置信息(用的不多)
String getServletName() -- 获取当前Servlet在web.xml中配置的名字
String getInitParameter(String name) -- 获取当前Servlet指定名称的初始化参数的值
Enumeration getInitParameterNames() -- 获取当前Servlet所有初始化参数的名字组成的枚举
ServletContext getServletContext() -- 获取代表当前web应用的ServletContext对象
在Servlet的配置文件中,可以使用一个或多个
当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息。
这样做的好处是:如果将数据库信息、编码方式等配置信息放在web.xml中,如果以后数据库的用户名、密码改变了,则直接很方便地修改web.xml就行了,避免了直接修改源代码的麻烦。
新建一个名为ServletConfigTest的Servlet,然后在web.xml中的
然后在代码中获取上面的两个参数。代码实现如下:
运行程序,后台打印日志如下:
代表当前web应用(非常重要)
WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。
由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
应用:
域对象:在一个可以被看见的范围内共享数据用到对象
作用范围:整个web应用范围内共享数据
生命周期:当服务器启动web应用加载后创建出ServletContext对象后,域产生。当web应用被移除出容器或服务器关闭,随着web应用的销毁域销毁。
servletcontext01.java
servletcontext02.java
我们在servletcontext0中给Context加一个参数name(16行),然后就能在servletcontext02中得到这个参数了(16行)。
context中常用的方法有:
void setAttribute(String,Object);
Object getAttribute(String);
void removeAttribute(String);
我们在第一段中,通过
在web.xml中为整个web应用添加初始化参数:用户名、密码。代码位置如下:
servlet注册
ServletContext03.java
运行程序
请求重定向:302+Location(两次请求两次响应)
请求转发:服务器内不进行资源流转 (一次请求一次响应,来实现资源流转)
注:上方括号中的内容是二者的区别。打个比方,假如你找我借钱,如果是请求重定向的话,那你再去找别人借;如果是请求转发的话,那我去找别人借,然后再借给你。
ServletContext04.java
通过19行代码拿到转发器dispatcher,这个转发器指向ServletTest05(参数中写虚拟路径),然后一旦执行完20行代码,就会跳到ServletTest05中去执行。
ServletContext05.java
web.xml
运行