Servlet原理

[1]简介

    > Server + let
    > 意为:运行在服务器端的小程序。
    > Servlet实际上就是一个接口。
        - 狭义上的Servlet,指的就是Servlet接口
        - 广义上的我们认为凡是实现Servlet接口的类,我们都称他是一个Servlet *****
    > Servlet的作用:
        1.接收用户发送的请求
        2.调用其他的java程序来处理请求
        3.根据处理结果,返回给用户一个页面

    > Servlet的HelloWorld
        1.创建一个类并实现Servlet接口
        2.在web.xml文件中对Servlet进行配置
            <servlet>
                <servlet-name>别名</servlet-name>
                <servlet-class>全类名</servlet-class>
            </servlet>
            <servlet-mapping>
                <servlet-name>别名</servlet-name>
                <url-pattern>需要servlet处理的请求地址</url-pattern>
            </servlet-mapping>

    > Servlet的三个名字:
        <servlet-name>
            - Servlet的别名,程序员通过别名对Servlet进行配置
        <servlet-class>
            - Servlet的全类名,服务器通过全类名来创建Servlet的实例
        <url-pattern>
            - Servlet映射的请求地址,用户通过该地址访问Servlet

[2] Servlet的生命周期

    > Servlet的生命周期,指Servlet的对象从被创建到被销毁的过程。
    > Servlet的生命周期方法:
        1.构造器:
            - Servlet第一次处理请求时,会调用构造器,来创建Servlet实例。
            - 只会调用一次,Servlet是单例模式,他是以多线程的方式调用service()方法.
            - Servlet不是线程安全,所以尽量不要再service()方法中操作全局变量。

        2.init()方法:
            - 构造器调用之后马上被调用,用来初始化Servlet,只会调用一次。

        3.service()方法:
            - Servlet每次处理请求时都会调用service()方法,用来处理请求,会调用多次。

        4.destroy()方法:
            - Servlet对象销毁前(WEB项目卸载时)调用,用来做一些收尾工作,释放资源。

[3] 相关接口

    ①ServletConfig
        代表:当前Servlet的配置信息,每一个Servlet都有其唯一对应的ServletConfig。
            <servlet>
                <servlet-name>AServlet</servlet-name>
                <servlet-class>com.atguigu.servlet.AServlet</servlet-class>
                <init-param>
                    <param-name>user</param-name>
                    <param-value>root</param-value>
                </init-param>
                <init-param>
                    <param-name>password</param-name>
                    <param-value>123123</param-value>
                </init-param>
            </servlet>

        获取:由Tomcat服务器创建,最终作为参数传递到init()方法中,我们可以在init()方法直接使用。
        当我们通过继承HttpServlet创建Servlet时,由于父类已经实现ServletConfig接口,所以我们可以在Servlet中直接调用ServletConfig的方法。

        功能:
            【1】 获取Servlet的别名
            【2】 获取当前Servlet的初始化参数。
                    <init-param>
                        <param-name>user</param-name>
                        <param-value>root</param-value>
                    </init-param>
                    <init-param>
                        <param-name>password</param-name>
                        <param-value>123123</param-value>
                    </init-param>
            【3】 获取当前WEB应用的ServletContext对象。

    ②ServletContext
        代表:当前的WEB应用,一个WEB应用对应一个唯一的ServletContext对象,
              ServletContext对象在项目启动时创建,在项目卸载时销毁。

        获取:通过ServletConfig的getServletContext()方法获取。

        功能:
            【1】 可以获取整个WEB应用的初始化参数
                <context-param>
                    <param-name>phone</param-name>
                    <param-value>1388888888</param-value>
                </context-param>
            【2】 可以获取资源的真实路径(物理路径),主要在文件的上传和下载时使用。
            【3】 可以作为一个域对象在不同的web资源之间共享数据。(下回分解)

[4] GenericServlet

    - 通用Servlet的父类
    - 相比Servlet接口GenericServlet更加简单一些,但是我们最终实际上使用的HttpServlet

[5] HttpServlet

    - HttpServlet继承了GenericServlet,而GenericServlet实现Servlet接口
    - 所以我们可以同构继承HttpServlet来创建一个Servlet。
    - HttpServlet重写service()方法:
        1.在该方法中先将ServletRequest和ServletResponse
            强转为了HttpServletRequest和HttpServletResponse。
        2.然调用重载的service()方法,并将刚刚强转得到对象传递到重载的方法中。
    - 重载service(HttpServletRequest request , HttpServletResponse response)
        1.在方法中获取请求的方式(get或post)
        2.在根据不同的请求方式去调用不同的方法:
            如果是GET请求,则调用doGet(HttpServletRequest request , HttpServletResponse response)
            如果是post请求,则调用doPost(HttpServletRequest request , HttpServletResponse response)
    - 结论:
        当通过继承HttpServlet来创建一个Servlet时,我们只需要根据要处理的请求的类型,来重写不同的方法。
            处理get请求,则重写doGet()
            处理post请求,则重写doPost()

[6] HttpServletRequest

    代表:浏览器发送给服务器的请求报文。
    获取:该对象由Tomcat服务器创建,最终作为参数传递到doGet或doPost方法中,我们可以在这两个方法中直接使用。
    功能:
        【1】获取用户发送的请求参数
            request.getParameter("username");
        【2】获取项目的名字(用来设置绝对路径)
            request.getContextPath();
        【3】作为一个域对象,在不同的WEB资源之间共享数据。
        【4】请求的转发
            request.getRequestDispatcher("target.html").forward(request, response);

[7] HttpServletResponse

    代表:服务器发送给浏览器的响应报文。
    获取:该对象由Tomcat服务器创建,最终作为参数传递到doGet或doPost方法中,我们可以在这两个方法中直接使用。
    功能:
        【1】响应给浏览器一个网页或者是网页片段(设置的是响应报文的响应体)
            response.getWriter("");
        【2】请求的重定向
            response.sendRedirect("target.html");

转发和重定向:(掌握)

                        转发                重定向
    请求的次数:          1                      2
    发生的位置            服务器内部            浏览器
    浏览器地址栏        不改变                改变
    浏览器的感知        不知道                知道   

[8] 字符编码

    > 当用户通过表单向Servlet发送中文请求参数时,Servlet获取到内容会产生乱码,
        当Servlet向浏览器响应中文内容时,也会产生乱码。
    > 浏览器和服务器之间通信时,中文内容时不能直接发送的,需要对中文进行编码。
    > 编码:
        - 将字符转换为二进制码的过程叫编码。
    > 解码:
        - 将二进制码转换为普通字符的过程叫解码。
    > 编码和解码所采用的规则我们称为字符集。

    > 产生乱码问题的根本原因:
        编码和解码所采用的字符集不同。

    > 解决方法:
        统一编码和解码的字符集为UTF-8。

    > 常见字符集:
        1.ASCII
        2.ISO8859-1
        3.GBK
        4.GB2312
        5.UTF-8

    > 请求编码
        - 请求是浏览器发送给服务器的。
        - 浏览器 --> 服务器
        - 浏览器 编码
            > 浏览器的会自动使用网页的字符集对参数进行编码
              UTF-8的张三:%E5%BC%A0%E4%B8%89
              GBK的张三:%D5%C5%C8%FD

            > 所以我们只需要统一网页的字符集为UTF-8即可。

        - 服务器 解码
            post请求
                > request解码时默认字符集时iso8859-1,但是iso压根就不支持中文
                > post请求在servlet中解码,所以我们只需要指定request的字符集即可。
                > 我们可以通过如下方法,来设置request的字符集:
                    request.setCharacterEncoding("utf-8");
                > 注意:
                    该方法要在request.getParameter()第一次调用之前调用

            get请求
                > get请求是通过url地址传递请求参数,url中的请求参数将会被Tomcat服务器自动解码。
                > Tomcat的默认编码是iso8859-1,但是iso压根就不支持中文,所以必然乱码。
                > 只需要修改Tomcat的解码的默认字符集,修改配置文件server.xml
                > 在server.xml的Connector标签中(改端口号的那个标签)添加如下属性:
                    URIEncoding="utf-8"
                > 修改完配置文件以后,get请求的编码就不用再处理的,但是post请求还是老样子。

    > 响应编码
        - 响应是服务器发送给浏览器
        - 服务器 --> 浏览器
        - 服务器 编码
            > 指定服务器的编码字符集为UTF-8。
            > 指定response的字符集
                response.setCharacterEncoding("utf-8");
            > 虽然我们已经指定了response的字符集为utf-8,但是浏览器并不是用utf-8解码。
                浏览器默认使用gb2312解码的,所以依然乱码,只不过没有那么乱。

        - 浏览器 解码
            > 浏览器的解码字符集可以通过浏览器来设置(不靠谱)
            > 我们可以通过服务器来告诉浏览器,我们的内容的编码格式为utf-8
            > 我们可以通过一个响应头来告诉浏览器,内容的编码格式:
                Content-Type:text/html;charset=utf-8
            > 通过response的方法,来设置响应头:
                response.setHeader("Content-Type", "text/html;charset=utf-8");

        解决方案:
            1.设置响应头
                response.setHeader("Content-Type", "text/html;charset=utf-8");
            2.设置response的编码格式
                response.setCharacterEncoding("utf-8");

            > 当我们设置Content-Type这个响应头时,服务器会自动使用响应头中的字符集为内容编码。

            > 最终方案:
                response.setContentType("text/html;charset=utf-8");

    总结:
        post请求:
            - 在request.getParameter()方法第一次调用之前,调用如下代码:
                request.setCharacterEncoding("utf-8");
        get请求:
            - 修改server.xml配置文件
            - <Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

        响应:
            - 设置一个Content-Type响应头
                response.setContentType("text/html;charset=utf-8");

[9] 路径问题

    > URI和URL
        - URL是URI的一种实现,也是URI最常见的实现方式。
        - URI有两种实现方式URL和URN,URN用的很少
        - 我们说URL和URI实际上可以理解为一个意思

    > URL地址的格式
        http://主机名:端口号/项目名/资源路径/资源名

    ①相对路径和绝对路径
        > 相对路径
        - 之前我们使用的路径全都是相对路径:
            - 所谓的相对路径指相对于当前资源所在路径:
                http://主机名:端口号/项目名/资源路径/
        - 由于转发的出现,相对路径会经常发生变化,容易出现错误的链接
            所以在开发中我们一般不使用相对路径,而是使用绝对路径。

        > 绝对路径
        - 绝对路径使用/开头   
        - 由浏览器解析的绝对路径中的/代表的是服务器的根目录:
            http://主机名:端口号/
            注意:需要加上项目名

        - 由服务器解析的绝对路径中的/代表的项目的根目录:
            http://主机名:端口号/项目名/
            注意:不要加项目名

        - 转发的路径由服务器解析,设置绝对路径时不需要加项目名
        - 重定向的路径由浏览器解析,设置绝对路径时需要加上项目名


    ②常见的路径:
        url-pattern:
        转发的路径:
            - url-pattern和转发中的路径都是由服务器解析的,
                根目录是项目的根目录:
                    http://主机名:端口号/项目名/
            - 所以这两个路径不需要加项目名

        重定向的路径:
        页面中的路径:
            - 重定向和页面中的路径(HTML标签中的路径),由浏览器解析的,
                根目录是服务器的根目录:
                    http://主机名:端口号/
            - 所以这个两个路径必须加上项目名

[10]运行的流程

[11]HttpServlet

Servlet 编写过滤器

Servlet 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息。
可以将一个或多个 Servlet 过滤器附加到一个 Servlet 或一组 Servlet。Servlet 过滤器也可以附加到 JavaServer Pages (JSP) 文件和 HTML 页面。调用 Servlet 前调用所有附加的 Servlet 过滤器。
Servlet 过滤器是可用于 Servlet 编程的 Java 类,可以实现以下目的:

  • 在客户端的请求访问后端资源之前,拦截这些请求。
  • 在服务器的响应发送回客户端之前,处理这些响应。

根据规范建议的各种类型的过滤器:

  • 身份验证过滤器(Authentication Filters)。
  • 数据压缩过滤器(Data compression Filters)。
  • 加密过滤器(Encryption Filters)。
  • 触发资源访问事件过滤器。
  • 图像转换过滤器(Image Conversion Filters)。
  • 日志记录和审核过滤器(Logging and Auditing Filters)。
  • MIME-TYPE 链过滤器(MIME-TYPE Chain Filters)。
  • 标记化过滤器(Tokenizing Filters)。
  • XSL/T 过滤器(XSL/T Filters),转换 XML 内容

过滤器通过 Web 部署描述符(web.xml)中的 XML 标签来声明,然后映射到您的应用程序的部署描述符中的 Servlet 名称或 URL 模式。
当 Web 容器启动 Web 应用程序时,它会为您在部署描述符中声明的每一个过滤器创建一个实例。
Filter的执行顺序与在web.xml配置文件中的配置顺序一致,一般把Filter配置在所有的Servlet之前。

Servlet 过滤器方法

1 public void doFilter (ServletRequest, ServletResponse, FilterChain)
该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器。
2 public void init(FilterConfig filterConfig)
web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。
3 public void destroy()
Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。

  • FilterConfig
    Filter 的 init 方法中提供了一个 FilterConfig 对象。
    如 web.xml 文件配置如下:
<filter>
    <filter-name>LoginFilter</filter-name>
    <filter-class>com.runoob.test.LogFilter</filter-class>
    <init-param>
        <param-name>Site</param-name>
        <param-value>菜鸟教程</param-value>
    </init-param>
    </filter>

在 init 方法使用 FilterConfig 对象获取参数:

public void  init(FilterConfig config) throws ServletException {
    // 获取初始化参数
    String site = config.getInitParameter("Site"); 
    // 输出初始化参数
    System.out.println("网站名称: " + site); 
}

Web.xml 中的 Servlet 过滤器映射(Servlet Filter Mapping)

定义过滤器,然后映射到一个 URL 或 Servlet,这与定义 Servlet,然后映射到一个 URL 模式方式大致相同。

<filter>
  <filter-name>LogFilter</filter-name>
  <filter-class>com.runoob.test.LogFilter</filter-class>
  <init-param>
    <param-name>Site</param-name>
    <param-value>菜鸟教程</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>LogFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

如果您只想在少数的 Servlet 上应用过滤器,您可以指定一个特定的 Servlet 路径。

过滤器的应用顺序

web.xml 中的 filter-mapping 元素的顺序决定了 Web 容器应用过滤器到 Servlet 的顺序。若要反转过滤器的顺序,您只需要在 web.xml 文件中反转 filter-mapping 元素即可。

Servlet 异常处理

当一个 Servlet 抛出一个异常时,Web 容器在使用了 exception-type 元素的 web.xml 中搜索与抛出异常类型相匹配的配置。
您必须在 web.xml 中使用 error-page 元素来指定对特定异常 或 HTTP 状态码 作出相应的 Servlet 调用。

<!-- error-code 相关的错误页面 -->
<error-page>
    <error-code>404</error-code>
    <location>/ErrorHandler</location>
</error-page>
<error-page>
    <error-code>403</error-code>
    <location>/ErrorHandler</location>
</error-page>

<!-- exception-type 相关的错误页面 -->
<error-page>
    <exception-type>
          javax.servlet.ServletException
    </exception-type >
    <location>/ErrorHandler</location>
</error-page>

<error-page>
    <exception-type>java.io.IOException</exception-type >
    <location>/ErrorHandler</location>
</error-page>

如果您想对所有的异常有一个通用的错误处理程序,那么应该定义下面的 error-page,而不是为每个异常定义单独的 error-page 元素:
<error-page>
<exception-type>java.lang.Throwable</exception-type >
<location>/ErrorHandler</location>
</error-page>

Servlet Session 跟踪

HTTP 是一种"无状态"协议,这意味着每次客户端检索网页时,客户端打开一个单独的连接到 Web 服务器,服务器会自动不保留之前客户端请求的任何记录。
但是仍然有以下三种方式来维持 Web 客户端和 Web 服务器之间的 session 会话:

  • Cookies
    一个 Web 服务器可以分配一个唯一的 session 会话 ID 作为每个 Web 客户端的 cookie,对于客户端的后续请求可以使用接收到的 cookie 来识别。
    这可能不是一个有效的方法,因为很多浏览器不支持 cookie,所以我们建议不要使用这种方式来维持 session 会话。

  • 隐藏的表单字段
    一个 Web 服务器可以发送一个隐藏的 HTML 表单字段,以及一个唯一的 session 会话 ID,如下所示:

  • URL 重写
    您可以在每个 URL 末尾追加一些额外的数据来标识 session 会话,服务器会把该 session 会话标识符与已存储的有关 session 会话的数据相关联。
    例如,http://w3cschool.cc/file.htm;sessionid=12345,session 会话标识符被附加为 sessionid=12345,标识符可被 Web 服务器访问以识别客户端。
    URL 重写是一种更好的维持 session 会话的方式,它在浏览器不支持 cookie 时能够很好地工作,但是它的缺点是会动态生成每个 URL 来为页面分配一个 session 会话 ID,即使是在很简单的静态 HTML 页面中也会如此。

  • HttpSession 对象
    除了上述的三种方式,Servlet 还提供了 HttpSession 接口,该接口提供了一种跨多个页面请求或访问网站时识别用户以及存储有关用户信息的方式。
    Servlet 容器使用这个接口来创建一个 HTTP 客户端和 HTTP 服务器之间的 session 会话。会话持续一个指定的时间段,跨多个连接或页面请求。
    您会通过调用 HttpServletRequest 的公共方法 getSession() 来获取 HttpSession 对象,如下所示:
    HttpSession session = request.getSession();

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,653评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,321评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,833评论 0 324
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,472评论 1 266
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,306评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,274评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,658评论 3 385
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,335评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,638评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,697评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,454评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,311评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,699评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,986评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,254评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,647评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,847评论 2 335

推荐阅读更多精彩内容

  • 这部分主要是与Java Web和Web Service相关的面试题。 96、阐述Servlet和CGI的区别? 答...
    杂货铺老板阅读 1,391评论 0 10
  • Servlet过滤器是 Servlet 程序的一种特殊用法,主要用来完成一些通用的操作,如编码的过滤、判断用户的登...
    重山杨阅读 1,203评论 0 12
  • 本文包括:1、Filter简介2、Filter是如何实现拦截的?3、Filter开发入门4、Filter的生命周期...
    廖少少阅读 7,229评论 3 56
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,680评论 6 342
  • 过滤器 过滤器可以动态的拦截请求和相应,以变换或使用包含在请求或响应中的信息。 过滤器是可用于 Servlet 编...
    Lisy_阅读 586评论 0 0