亿度网络 网站建设,网站后台系统使用,南阳锐诚网站建设,淘宝联盟登记新网站板块一 Servlet编程#xff1a;第二节 Servlet的实现与生命周期 一、Servlet相关概念Serlvet的本质 二、中Web项目中实现Servlet规范#xff08;1#xff09;在普通的Java类中继承HttpServlet类#xff08;2#xff09;重写service方法编辑项目对外访问路径 二、Servlet工… 板块一 Servlet编程第二节 Servlet的实现与生命周期 一、Servlet相关概念Serlvet的本质 二、中Web项目中实现Servlet规范1在普通的Java类中继承HttpServlet类2重写service方法编辑项目对外访问路径 二、Servlet工作流程三、其它实现Servlet规范的方式(1)继承自GenericServlet 类(2)实现Servlet接口(3)在HttpServlet中直接重写doGet()和doPost()方法 四、Servlet生命周期 在上一节的内容中我们已经系统的学习了HTTP的相关概念、知道了GET和POST请求在服务器上的运行原理、请求响应在服务器中究竟是怎样运行的从这一节开始我们将系统的学习实现Servlet的完整过程 一、Servlet相关概念
Serlvet的本质
当编写Java程序想要在网上实现聊天、发帖、这样一些的交互功能普通Java技术是非常复杂的试想要从底层搭建出一整个服务层的代码有多复杂并且每个人搭建的底层还不一样为了解决这个问题sun公司就提供了Serlvet这种技术供我们使用。Servlet是Server与Applet的缩写,是服务端小程序的意思本质上就是一个遵循Servlet开发的Java类由服务器调用在服务器端运行它的创建、使用、销毁都由Servlet容器进行管理其常见容器有很多,如Tomcat,Jetty,WebLogic Server,WebSphere,JBoss等等在Tomcat的集成这一节中我们已经详尽的学习了Tomcat更奇怪的是Servlet没有main()方法本质上我们可以想象Servlet通过某种注入和回调方法与Servlet容器取得联系从而代替我们在Servlet中书写main()函数 Servlet与HTTP紧密联系可以处理与HTTP协议相关的所有内容这是Servlet应用广泛的原因之一实际上在运行JSP时服务器底层将JSP编译成一个Java类这个类就是Servlet因此可以说JSP就是Servlet详见JSP追根溯源小节Servlet在 JAVA WEB项目中的位置它就是我们常说的后端 编程学习越往后越是如此,我们能做的其实很有限。大部分工作框架都已经帮我们做了。只 要我们实现xx接口,它会帮我们创建实例,然后搬运(接口注入)到它合适的位置,然后一套既定 的流程下来执行到创建我们需要的实例
二、中Web项目中实现Servlet规范
我们已经在板块零的第二节中创建了Java Web项目又在板块零的第三节中成功把Tomcat集成到IDEA中现在我们就在这个Web项目中实现Servlet规范
1在普通的Java类中继承HttpServlet类
在www.caijiyuan包中创建一个普通的Java类 helloServlet.java 此类继承HttpServlet类还记得继承怎么写吗extends
2重写service方法
在上一节中我们详细学习了请求响应在服务器中究竟是怎样运行的而在Servlet中请求响应就是通过HttpServlet类中的service方法实现的service方法有两个形参Request,Rrsponse分别对应请求、响应 在HttpServlet类中IDEA重写方法的快捷键是CtrlO 但我们发现有两个service它们的区别是什么 先来看第一个HttpServlet的service()方法
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取http request的method参数其实就是html的form标签 //中method属性对应的字符串 String method req.getMethod();long errMsg;//判断请求方式if(method.equals(GET)) {//获取最后被修改时间 errMsg this.getLastModified(req);if(errMsg -1L) {/**如果servlet不支持http request header的if-modified-since属性 * 则继续处理 **/ this.doGet(req, resp);} else {//如果支持这个属性 long ifModifiedSince;try {ifModifiedSince req.getDateHeader(If-Modified-Since);} catch (IllegalArgumentException var9) {ifModifiedSince -1L;}/** * 如果客户端的文件最后修改时间和服务器端的文件最后修改时间一致则返回304不需要修改状态 * 这样服务器就不返回html浏览器读取本地缓存文件否则重新获取服务器端的对应html文件 **/ if(ifModifiedSince errMsg / 1000L * 1000L) {this.maybeSetLastModified(resp, errMsg);this.doGet(req, resp);} else {resp.setStatus(304);}}} else if(method.equals(HEAD)) {errMsg this.getLastModified(req);this.maybeSetLastModified(resp, errMsg);this.doHead(req, resp);} else if(method.equals(POST)) {this.doPost(req, resp);} else if(method.equals(PUT)) {this.doPut(req, resp);} else if(method.equals(DELETE)) {this.doDelete(req, resp);} else if(method.equals(OPTIONS)) {this.doOptions(req, resp);} else if(method.equals(TRACE)) {this.doTrace(req, resp);} else {//如果请求不是以上的所有请求方式该方法就会响应501错误也就是不支持这种请求String errMsg1 lStrings.getString(http.method_not_implemented);Object[] errArgs new Object[]{method};errMsg1 MessageFormat.format(errMsg1, errArgs);resp.sendError(501, errMsg1);}}这是第二个ServletRequest
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {HttpServletRequest request;HttpServletResponse response;try {request (HttpServletRequest)req;response (HttpServletResponse)res;} catch (ClassCastException var6) {throw new ServletException(non-HTTP request or response);}this.service(request, response);
}原来只有第二个 ServletRequest service方法是由Tomcat自动调用它将接收的客户端请求转交给HttpServlet中的第一个HttpServletRequest protected service方法此保护类型的service方法再把将请求分发给doPost()、doGet()方法进行下一步处理 因此这里就Request/Response俩个形参而言重写调用第一个或第二个service方法的效果应该是一样的此处我们直接重写第一个,也就是 HttpServletRequest protected service
编辑项目对外访问路径
我们还应将项目对外访问路径就是在服务器中此项目的站点名更改为自己想要的样子 此处我更改为与包名一致/www.caijiyuan
注意我们还应在类前设置注解WebServlet(/helloServlet)告诉服务器当前资源在站点下的真实路径
helloServlet.java中写入测试内容
package www.caijiyuan;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;WebServlet(/helloServlet)
public class helloServlet extends HttpServlet {Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.service(req, resp);//打印内容在控制台System.out.println(Hello Servlet with terminal);//通过流输出数据到浏览器resp.getWriter().write( Hello Servlet with brower);}
}
启动服务器在浏览器中访问得 在控制台得
二、Servlet工作流程
那么HttpServletRequest request请求是在服务器中是怎样接受到的呢 即是上一节中详解过的请求头的功劳 当请求进入服务器时
服务器会通过请求头键值对中的Host中的localhost找到主机是本机通过8080端口确定本机中占用端口的程序是Tomcat通过请求行中的/www.caijiyuan确定是Tomcat下的哪个站点通过/helloServlet确定是当前站点下的那个资源路径
找到资源路径后如果服务器是第一次被访问就会创建一个Servlet否则就会调用service方法生成request对象来处理会话中的请求接受到请求后经过设定的代码生成response对象保存响应内容返回给客户端浏览器这就是Servlet工作的流程
三、其它实现Servlet规范的方式
(1)继承自GenericServlet 类
对于一个 Servlet 类我们日常最常用的方法是继承自 HttpServlet 类实际上HttpServlet是扩展了GenericServlet 类。GenericServlet 类实现了ServletServletConfig和Serializable接口。它主要完成了这些任务
将 init() 中的 ServletConfig 赋给一个类级变量可以由 getServletConfig 获得为 Servlet 所有方法提供默认实现的接口除了service方法可以直接调用 ServletConfig 中的方法 它的基本结构如下
abstract class GenericServlet implements Servlet,ServletConfig{//GenericServlet通过将ServletConfig赋给类级变量private trServletConfig servletConfig;public void init(ServletConfig servletConfig) throws ServletException {this.servletConfigservletConfig;/*自定义init()的原因是如果子类要初始化必须覆盖父类的init() 而使它无效 这样this.servletConfigservletConfig不起作用 这样就会导致空指针异常 这样如果子类要初始化可以直接覆盖不带参数的init()方法 */this.init();}//自定义的init()方法可以由子类覆盖 //init()不是生命周期方法public void init(){}//实现service()空方法并且声明为抽象方法强制子类必须实现service()方法 public abstract void service(ServletRequest request,ServletResponse response) throws ServletException,java.io.IOException{}//实现空的destroy方法public void destroy(){ }
}可以看到如果继承这个类的话我们必须重写 service() 方法来对处理请求 继承自GenericServlet 类实现Servlet
package www.caijiyuan;import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;WebServlet(/Servlet_Gener)
public class Servlet_Gener extends GenericServlet {Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {//打印内容在控制台System.out.println(Hello Servlet with terminal);//通过流输出数据到浏览器servletResponse.getWriter().write( Hello Servlet with brower);}
}
启动服务器后在浏览器中访问得 (2)实现Servlet接口
除了两个继承抽象类实现Servlet的接口还有一个通过实现interface Servlet来实现Servlet规范的方法 实例 创建类Servlet_imp.java 使其实现Servlet接口 IDEA中使用快捷键AltShiftEnter实现方法在service()方法中添加测试代码并且在类前添上WebServlet()注释
package www.caijiyuan;import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;WebServlet(/Servlet_imp)
public class Servlet_imp implements Servlet {Overridepublic void init(ServletConfig servletConfig) throws ServletException {}Overridepublic ServletConfig getServletConfig() {return null;}Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {//通过流输出数据到浏览器servletResponse.getWriter().write( Hello Servlet with brower);}Overridepublic String getServletInfo() {return null;}Overridepublic void destroy() {}
}
访问浏览器同样可以得到
(3)在HttpServlet中直接重写doGet()和doPost()方法
我们在调用HttpServlet中service方法时底层实际上是判断GET请求还是POST请求从而分别调用doGet()和doPost()方法
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method req.getMethod();long lastModified;if (method.equals(GET)) {lastModified this.getLastModified(req);if (lastModified -1L) {this.doGet(req, resp);} else {long ifModifiedSince;try {ifModifiedSince req.getDateHeader(If-Modified-Since);} catch (IllegalArgumentException var9) {ifModifiedSince -1L;}if (ifModifiedSince lastModified / 1000L * 1000L) {this.maybeSetLastModified(resp, lastModified);this.doGet(req, resp);} else {resp.setStatus(304);}}} else if (method.equals(HEAD)) {lastModified this.getLastModified(req);this.maybeSetLastModified(resp, lastModified);this.doHead(req, resp);} else if (method.equals(POST)) {this.doPost(req, resp);} else if (method.equals(PUT)) {this.doPut(req, resp);} else if (method.equals(DELETE)) {this.doDelete(req, resp);} else if (method.equals(OPTIONS)) {this.doOptions(req, resp);} else if (method.equals(TRACE)) {this.doTrace(req, resp);} else {String errMsg lStrings.getString(http.method_not_implemented);Object[] errArgs new Object[]{method};errMsg MessageFormat.format(errMsg, errArgs);resp.sendError(501, errMsg);}}实例 创建类Servlet_do.java使其继承自HttpServlet然后重写doGet()和doPost()方法 通过上一节我们已经知道了浏览器访问地址是使用GET方法所以我们在doGet()中添加测试代码并且在类前添上WebServlet()注释
package www.caijiyuan;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;WebServlet(/Servlet_do)
public class Servlet_do extends HttpServlet {Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doGet(req, resp);//通过流输出数据到浏览器resp.getWriter().write( Hello Servlet with brower);}Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doPost(req, resp);}
}
访问浏览器同样可以得到
以上三种方式都可以实现Servlet规范使得普通Java类升级成Servlet类但最简便的方式还是第一种也就是继承自HttpServlet类
四、Servlet生命周期
有了以上的知识储备我们就可以梳理一下Servlet的整个生命周期了由于Servlet没有main()方法,不能独立运行,它的运行完全由Servlet引擎来控制和调度所谓生命周期指的就是Servlet容器何时创建 Servlet实例、何时调用其方法进行请求的处理、何时并销毁其实例的整个过程。
实例和初始化时机:当请求到达容器时,容器查找该 Servlet对象是否存在,如果不存在,则会创建实例并进行初始化如果存在则会直接调用service()方法就绪/调用/服务阶段:当有请求到达容器容器调用Servlet对象的 service()方法,此方法在整个生命周期中可以被多次调用;HttpServlet的 service()方法则会依据请求方式来调用doGet()或者doPost()方法。但是,这两个do方法默认情况下会抛出异常,需要子类去override销毁时机当容器关闭时(应用程序停止时)会将程序中的Servlet实例进行销毁。上述的生命周期可以通过Servlet 中的生命周期方法来观察。在Servlet 中有三个生命周期方法不由用户手动调用,而是在特定的时机由容器自动调用
观察这三个生命周期方法即可观察到Servlet的生命周期
init方法,在Servlet 实例创建之后执行(证明该Servlet有实例创建了)
public void init() throws ServletException {System.out.println(创建实例调用);
}service 方法,每次有请求到达某个Servlet 方法时执行,用来处理请求(证明该Servlet 进行服务了)
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println(service方法调用了);
}destroy 方法,Servlet实例销毁时执行(证明该Servlet的实例被销毁了)
public void destroy() {System.out.println(实例被销毁了);
}实例
启动服务器在浏览器中访问项目得 在控制台输出即是在浏览器访问项目时调用了init()方法只会被调用一次init()并且紧接着接受请求调用了service方法 接着关闭Tomcat服务器在控制台输出 Servlet的生命周期,可以更详细的分为四步:Servlet类加载 – 实例化 – 服务 – 销毁 下面我们描述一下Tomcat与Servlet是如何工作的,看看下面的时序图:
Web Client 向Servlet容器(Tomcat)发出Http请求Servlet 容器接收Web Client的请求Servlet 容器创建一个HttpServletRequest对象,将Web Client请求的信息封装到这个对象中Servlet 容器创建一个HttpServletResponse 对象Servlet 容器调HttpServlet对象service 方法,把Request与Response作为参数,传给HttpServletHttpServlet 调用HttpServletRequest对象的有关方法,获取Http请求信息HttpServlet 调用HttpServletResponse对象的有关方法,生成响应数据Servlet 容器把HttpServlet的响应结果传给Web Client
以上就是此小节的所有内容我们系统的学习了Servlet的概念、实现Servlet规范的多个方法、Servlet的工作流程、生命周期等为之后Servlet具体对象学习打下了坚实的基础。从下一节开始我们将学习service方法两个形参之一HttpServletRequest实例的具体操作