第五章:Servlet

定义:

Servlet简介:

  Servlet是sun公司提供的一门用于开发动态web资源的技术。

  Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:  1、编写一个Java类,实现servlet接口。  2、把开发好的Java类部署到web服务器中。

按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet。

总的来讲:运行在Servlet容器中的Java类,可以接受请求并产生响应,是MVC思想的控制层=

那Servlet和我们之前编写的do_XXX.jsp有啥区别?

如Test.jsp在运行时首先解析成一个Java类Test_jsp.java,而这个Test_jsp.java继承于org.apache.jasper.runtime.HttpJspBase类,而HttpJspBase又是继承自HttpServlet的类,由此可以得出一个结论,就是JSP在运行时会被Web容器翻译为一个Servlet

也可以打开Servlet源码来查看一下基础关系图:

[面试题]:

jsp和Servlet有啥区别?

jsp页面继承于org.apache.jasper.runtime.HttpJspBase类,而HttpJspBase又是继承自HttpServlet的类,由此可以得出一个结论,就是JSP在运行时会被Web容器翻译为一个Servlet,他们本质上都是同一个东西,只不过jsp注重页面的显示,Servlet更注重流程的控制。

servlet体系结构:

servlet的生命周期:

![](images\servlet2.png)

Servlet运行过程图:

servlet接口里面的方法:

servlet的生命周期:

servlet体系结构:

![](images\servlet5.png)

其中,init( ),service( ),destroy( )是Servlet生命周期的方法。代表了Servlet从“出生”到“工作”再到“死亡 ”的过程。Servlet容器(例如TomCat)会根据下面的规则来调用这三个方法:

1.init( ),当Servlet第一次被请求时,Servlet容器就会开始调用这个方法来初始化一个Servlet对象出来,但是这个方法在后续请求中不会在被Servlet容器调用,就像人只能“出生”一次一样。我们可以利用init( )方法来执行相应的初始化工作。调用这个方法时,Servlet容器会传入一个ServletConfig对象进来从而对Servlet对象进行初始化。

2.service( )方法,每当请求Servlet时,Servlet容器就会调用这个方法。就像人一样,需要不停的接受老板的指令并且“工作”。第一次请求时,Servlet容器会先调用init( )方法初始化一个Servlet对象出来,然后会调用它的service( )方法进行工作,但在后续的请求中,Servlet容器只会调用service方法了。

3.destory,当要销毁Servlet时,Servlet容器就会调用这个方法,就如人一样,到时期了就得死亡。在卸载应用程序或者关闭Servlet容器时,就会发生这种情况,一般在这个方法中会写一些清除代码。

public class MyFirstServlrt implements Servlet {    @Override    public void init(ServletConfig servletConfig) throws ServletException {        System.out.println("Servlet正在初始化");    }    @Override    public ServletConfig getServletConfig() {        return null;    }    @Override    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {        //专门向客服端提供响应的方法        System.out.println("Servlet正在提供服务");    }    @Override    public String getServletInfo() {        return null;    }    @Override    public void destroy() {        System.out.println("Servlet正在销毁");    }}      

然后在xml中配置正确的映射关系,在浏览器中访问Servlet,第一次访问时,控制台输出了如下信息:

然后,我们在浏览器中刷新3遍:

控制台输出的信息变成了下面这样:

接下来,我们关闭Servlet容器:

控制台输出了Servlet的销毁信息,这就是一个Servlet的完整生命周期。

Servlet 的其它两个方法

getServletInfo( ),这个方法会返回Servlet的一段描述,可以返回一段字符串。

getServletConfig( ),这个方法会返回由Servlet容器传给init( )方法的ServletConfig对象。

相关其他接口:

GenericServlet抽象类

前面我们编写Servlet一直是通过实现Servlet接口来编写的,但是,使用这种方法,则必须要实现Servlet接口中定义的所有的方法,即使有一些方法中没有任何东西也要去实现,并且还需要自己手动的维护ServletConfig这个对象的引用。因此,这样去实现Servlet是比较麻烦的。幸好,GenericServlet抽象类的出现很好的解决了这个问题。本着尽可能使代码简洁的原则,GenericServlet实现了Servlet和ServletConfig接口。

其中,GenericServlet抽象类相比于直接实现Servlet接口,有以下几个好处:

1.为Servlet接口中的所有方法提供了默认的实现,则程序员需要什么就直接改什么,不再需要把所有的方法都自己实现了。2.提供方法,包围ServletConfig对象中的方法。

HttpServlet抽象类

HttpServlet抽象类是继承于GenericServlet抽象类而来的。使用HttpServlet抽象类时,还需要借助分别代表Servlet请求和Servlet响应的HttpServletRequest和HttpServletResponse对象。

HttpServletRequest接口扩展于javax.servlet.ServletRequest接口,HttpServletResponse接口扩展于javax.servlet.servletResponse接口。

HttpServlet抽象类覆盖了GenericServlet抽象类中的Service( )方法,并且添加了一个自己独有的Service(HttpServletRequest request,HttpServletResponse方法

让我们来具体的看一看HttpServlet抽象类是如何实现自己的service方法吧:

我们看到是一个抽象方法,也就是HttpServlet要自己去实现这个service方法,我们在看看HttpServlet是怎么覆盖这个service方法的:

 protected void service(HttpServletRequest req, HttpServletResponse resp)        throws ServletException, IOException {        String method = req.getMethod();        if (method.equals(METHOD_GET)) {            long lastModified = getLastModified(req);            if (lastModified == -1) {                // servlet doesn't support if-modified-since, no reason                // to go through further expensive logic                doGet(req, resp);            } else {                long ifModifiedSince;                try {                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);                } catch (IllegalArgumentException iae) {                    // Invalid date header - proceed as if none was set                    ifModifiedSince = -1;                }                if (ifModifiedSince < (lastModified / 1000 * 1000)) {                    // If the servlet mod time is later, call doGet()                    // Round down to the nearest second for a proper compare                    // A ifModifiedSince of -1 will always be less                    maybeSetLastModified(resp, lastModified);                    doGet(req, resp);                } else {                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);                }            }        } else if (method.equals(METHOD_HEAD)) {            long lastModified = getLastModified(req);            maybeSetLastModified(resp, lastModified);            doHead(req, resp);        } else if (method.equals(METHOD_POST)) {            doPost(req, resp);        } else if (method.equals(METHOD_PUT)) {            doPut(req, resp);        } else if (method.equals(METHOD_DELETE)) {            doDelete(req, resp);        } else if (method.equals(METHOD_OPTIONS)) {            doOptions(req,resp);        } else if (method.equals(METHOD_TRACE)) {            doTrace(req,resp);        } else {            String errMsg = lStrings.getString("http.method_not_implemented");            Object[] errArgs = new Object[1];            errArgs[0] = method;            errMsg = MessageFormat.format(errMsg, errArgs);            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);        }    }

我们会发现在service方法中还是没有任何的服务逻辑,但是却在解析HttpServletRequest中的方法参数,并调用以下方法之一:doGet,doPost,doHead,doPut,doTrace,doOptions和doDelete。这7种方法中,每一种方法都表示一个Http方法。doGet和doPost是最常用的。所以,如果我们需要实现具体的服务逻辑,不再需要覆盖service方法了,只需要覆盖doGet或者doPost就好了

总之,HttpServlet有两个特性是GenericServlet所不具备的:

1.不用覆盖service方法,而是覆盖doGet或者doPost方法。在少数情况,还会覆盖其他的5个方法。

2.使用的是HttpServletRequest和HttpServletResponse对象。

HttpServletRequest接口

HttpServletRequest表示Http环境中的Servlet请求。它扩展于javax.servlet.ServletRequest接口,并添加了几个方法。如图:

常用方法:

String getContextPath();//返回请求上下文的请求URI部分Cookie[] getCookies();//返回一个cookie对象数组String getHeader(String var1);//返回指定HTTP标题的值String getMethod();//返回生成这个请求HTTP的方法名称String getQueryString();//返回请求URL中的查询字符串HttpSession getSession();//返回与这个请求相关的会话对象

HttpServletResponse接口

它继承自ServletResponse接口,专门用来封装HTTP响应消息。 由于HTTP请求消息分为状态行,响应消息头,响应消息体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码,响应消息头,响应消息体的方法。

常用方法:

void addCookie(Cookie var1);//给这个响应添加一个cookievoid addHeader(String var1, String var2);//给这个请求添加一个响应头void sendRedirect(String var1) throws IOException;//发送一条响应码,讲浏览器跳转到指定的位置void setStatus(int var1);//设置响应行的状态码

Response的乱码问题:

由于计算机中的数据都是以二进制形式存储的,因此,当传输文本时,就会发生字符和字节之间的转换。字符与字节之间的转换是通过查码表完成的,将字符转换成字节过程称为编码,将字节转换成字符的过程为解码,如果编码和解码使用的码表不一致,就会导致乱码问题。

解决方式1:

response缓存区的默认编码是ISO-8859-1,此码表没有中文。所以需要更改response的编码方式:

response.setCharacterEncoding("UTF-8");

通过更改response的编码方式为UTF-8,任然无法解决乱码问题,因为发送端服务端虽然改变了编码方式为UTF-8,但是接收端浏览器端仍然使用GB2312编码方式解码,还是无法还原正常的中文,因此还需要告知浏览器端使用UTF-8编码去解码。所以还需加上:

response.setHeader("Content-Type","text/html;charset=utf-8");

上面通过调用两个方式分别改变服务端对于Response的编码方式以及浏览器的解码方式为同样的UTF-8编码来解决编码方式不一样发生乱码的问题。

解决方式2:

response.setContentType("text/html;charset=UTF-8")这个方法包含了上面的两个方法的调用,因此在实际的开发中,只需要调用一个response.setContentType("text/html;charset=UTF-8")方法即可.

response.setContentType("text/html;charset=UTF-8");

ServletConfig接口

当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init( )方式传入一个ServletConfig对象.

方法如下:

ServletContext接口

获取Web应用上下文,与Servlet容器进行通信

ServletContext对象表示Servlet应用程序。每个Web应用程序都只有一个ServletContext对象。在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机上的Web应用都会有一个ServletContext对象。

通过在ServletConfig中调用getServletContext方法,也可以获得ServletContext对象。

那么为什么要存在一个ServletContext对象呢?存在肯定是有它的道理,因为有了ServletContext对象,就可以共享从应用程序中的所有资料处访问到的信息,并且可以动态注册Web对象。前者将对象保存在ServletContext中的一个内部Map中。保存在ServletContext中的对象被称作属性。

常用方法:

方法名称 功能描述
String getInitParameter (              String name ) 获取名为name的系统范围的初始化参数值,系统范围的初始化参数可在部署描述符中使用param>元素定义**
void setAttribute (  String name, Object object ) 设置名称为name的属性
Object getAttribute (              String name ) 获取名称为name的属性
String getRealPath (               String path ) 返回参数所代表目录的真实路径
void log ( String message ) 记录一般日志信息

上机案例:

案例1:

package com.servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class MyServlet extends HttpServlet {    private static final long serialVersionUID = 1L;          @Override    public void init() throws ServletException {        super.init();        System.out.println("初始化Servlet");}    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {     doPost(request, response);}    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        System.out.println("正在执行业务....");}    @Override    public void destroy() {        System.out.println("销毁Servlet...");        super.destroy();}}

注意:这里的关闭服务器,一定要在tomcat/bin目录下,shutDown.sh下关闭才能实现

还有就是Eclipse2020版默认是使用注解方式,如果需要编写Servlet后自动配置web.xml文件你就需要把这个项目编写的版本调到3.0一下就可以。

如图:

案例2:

xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">  <display-name>ServletDemo2display-name>  <welcome-file-list>    <welcome-file>index.jspwelcome-file>  welcome-file-list>  <servlet>    <servlet-name>MyServletservlet-name>    <servlet-class>com.servlet.MyServletservlet-class>    <init-param>        <param-name>initParamparam-name>        <param-value>Hello Servletparam-value>    init-param>  servlet>  <servlet-mapping>    <servlet-name>MyServletservlet-name>    <url-pattern>/myServleturl-pattern>  servlet-mapping>web-app>
package com.servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class MyServlet extends HttpServlet {    private static final long serialVersionUID = 1L;    protected void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        doPost(request, response);}    protected void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        System.out.println("处理请求时,doGet()方法被调用。");        String initParam = getInitParameter("initParam");        System.out.println(initParam);}}

案例3:

xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">  <display-name>ServletDemo2display-name>  <context-param>    <param-name>contextParamparam-name>    <param-value>ContextParamValueparam-value>  context-param>    <servlet>    <servlet-name>MyServletservlet-name>    <servlet-class>com.servlet.MyServletservlet-class>    <init-param>        <param-name>initParamparam-name>        <param-value>Hello Servletparam-value>    init-param>  servlet>  <servlet-mapping>    <servlet-name>MyServletservlet-name>    <url-pattern>/myServleturl-pattern>  servlet-mapping>      <welcome-file-list>      <welcome-file>myServletwelcome-file>   welcome-file-list>web-app>
public void doGet(HttpServletRequest request,                     HttpServletResponse response)                   throws ServletException, IOException {       System.out.println("处理请求时,doGet()方法被调用。");       String initParam = getInitParameter("initParam");       String contextParam =            this.getServletContext().getInitParameter("contextParam");       System.out.println("Servlet初始化参数" + initParam);       System.out.println("上下文参数" + contextParam);    }

Servlet注解:

Servlet3.0通过注解实现Servlet,简化web.xml的配置,后期我们的框架技术都是可以通过注解来简化配置,大大提高开发效率。

@WebServlet(name = "MyServlet",urlPatterns ="/myServlet" )public class MyServlet extends HttpServlet {    private static final long serialVersionUID = 1L;          @Override    public void init() throws ServletException {        super.init();        System.out.println("初始化Servlet");}    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {     doPost(request, response);}    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        System.out.println("正在执行业务....");}    @Override    public void destroy() {        System.out.println("销毁Servlet...");        super.destroy();}}

@WebServlet属性列表:

属性名 类型 描述
name String 指定Servlet 的 name 属性,等价于 。如果没有显式指定,则该 Servlet 的取值即为类的全限定名。
value String[] 该属性等价于 urlPatterns 属性。两个属性不能同时使用。
urlPatterns String[] 指定一组 Servlet 的 URL 匹配模式。等价于标签。
loadOnStartup int 指定 Servlet 的加载顺序,等价于 标签。
initParams WebInitParam[] 指定一组 Servlet 初始化参数,等价于标签。
asyncSupported boolean 声明 Servlet 是否支持异步操作模式,等价于 标签。
description String 该 Servlet 的描述信息,等价于 标签。
displayName String 该 Servlet 的显示名,通常配合工具使用,等价于 标签。

jsp调用servlet_宇宙最全Servlet详解!!相关推荐

  1. 【Java网络编程与IO流】Java之Java Servlet详解

    Java网络编程与IO流目录: [Java网络编程与IO流]Java中IO流分为几种?字符流.字节流.缓冲流.输入流.输出流.节点流.处理流 [Java网络编程与IO流]计算机网络常见面试题高频核心考 ...

  2. javaweb(07) Servlet详解

    javaweb(07) Servlet详解 什么是Servlet 简介 从广义上来讲,Servlet规范是Sun公司制定的一套技术标准,包含与web应用相关的一系列接口,是web应用实现方式的宏观解决 ...

  3. 《 Python List 列表全实例详解系列(八)》__随机列表元素

    < Python List 列表全实例详解系列(八)> __随机列表元素 本章目录: 十.随机列表元素 方法1:random.shuffle 方法2:random.sample 十.随机列 ...

  4. Mybatis系列全解(五):全网最全!详解Mybatis的Mapper映射文件

    封面:洛小汐 作者:潘潘 若不是生活所迫,谁愿意背负一身才华. 前言 上节我们介绍了 < Mybatis系列全解(四):全网最全!Mybatis配置文件 XML 全貌详解 >,内容很详细( ...

  5. 史上最全ThreadLocal 详解(一)

    目录 一.ThreadLocal简介 二.ThreadLocal与Synchronized的区别 三.ThreadLocal的简单使用 四.ThreadLocal的原理 4.1 ThreadLocal ...

  6. 《 Python List 列表全实例详解系列(九)》__列表反转(6种方法)

    < Python List 列表全实例详解系列(九)> __列表反转(6种方法) 本章目录: 十一.列表反转的6种方法 (11.1).通过列表的切片操作实现列表反转 (11.2).使用列表 ...

  7. Unity史上最全旋转详解(Rotate,rotation,localEulerAngles,localRotation,万向节锁)

    Unity史上最全旋转详解 前言 旋转的方法Rotate以及五种重载参数的超级详细理解 Rotate(float xAngle, float yAngle, float zAngle); Unity绕 ...

  8. 最全ES6详解及用法

    最全ES6详解及用法 前言 babel babel使用方法 变量的定义 let.const this 和作用域 do 顶层对象 global对象 import class JS中的原型 原型语言 pr ...

  9. css中float详解,CSS浮动属性Float详解?史上最全Float详解

    我们在学习css样式的时候,都知道css是盒概念,并且每一个盒子都是一个元素,下面我们就对CSS浮动属性Float进行详解,让你彻底了解Float. 一:什么是Float浮动? Float浮动是css ...

最新文章

  1. 一星期没完成Ansible任务
  2. mysql表格的代码_mySQL表格内容用代码添加
  3. c++ 和 C语言 中数组语法的比较
  4. 其实,人的核心职场时间是有限的,一定要和高手玩
  5. jquerymobile使用技巧
  6. 【转】SOAR平台初探(一)
  7. python 类方法 函数_Python OOP类中的几种函数或方法总结
  8. 服务器中文件设置密码,共享服务器文件权限怎么设置密码
  9. 介绍一下mysql的存储过程和搜索引擎_MySQL基础(四)—存储过程和存储引擎
  10. cmake编译gtest测试程序(三)
  11. 再次思考 classpath 环境变量 等
  12. 取(2堆)石子游戏 (hdu2177)
  13. android版本4.4.2导航,天敏D8+_rk3288_Android_4.4.2_kiui7_蓝光导航极速版
  14. java学习之路2--简单工厂模式实现饮料自动贩卖机
  15. easywechat6获取微信用户信息(基于公众号)
  16. PDF怎么合并?教你2个免费一键合并PDF的方法
  17. 小红帽 oracle,linux 小红帽 一键安装ffmpeg
  18. yolov5检测小目标(附源码)
  19. 文件格式大全(A-H)
  20. 5. 项目管理之范围管理

热门文章

  1. Application.mk
  2. Software optimization resources
  3. MFC 线程的退出方法
  4. C++ socket编程 实现服务端与客户端的通讯
  5. 程序员基本功09 线性表
  6. 虚拟机ubuntu安装ssh服务器,经过Xshell远程链接虚拟机VMVARE中的Ubuntu
  7. 计算机应用等级考试1,计算机等级考试一级试题
  8. cass块参照怎么改颜色,【干货】新版本CASS符号颜色自定义详解
  9. 关于vscode插件autoprefixer 3.0无法使用的问题
  10. python elasticsearch timeout_Python操作Elasticsearch处理timeout超时