1_Servlet简介

  • Servlet 介绍

    • Servlet 是 Server Applet 的简称,称为服务端小程序,是 JavaEE 平台下的技术标准,基于 Java 语言编写的服务端程序

    • Web 容器或应用服务器实现了 Servlet 标准所以 Servlet 需运行在 Web 容器或应用服务器中

    • Servlet 主要功能在于能在服务器中执行并生成数据

  • Servlet 技术特点

    • Servlet 使用单进程多线程方式运行

      在这里插入图片描述

    • Servlet 在应用程序中的位置

      在这里插入图片描述

    • 静态资源和动态资源区分

      • 静态资源
        • 每次访问都不需要运算, 直接就可以返回的资源, 如HTML CSS JS 多媒体文件等等, 每次访问获得的资源都是一样的
      • 动态资源
        • 每次访问都需要运算代码生成的资源, 如 Servlet JSP , 每次访问获得的结果可能都是不一样的
      • Servlet 作为一种动态资源技术, 是我们后续学习框架的基础
  • Servlet 在程序中到底处于一个什么地位?

    • Servlet 是可以接受 Http 请求并作出相应的一种技术, 是JAVA语言编写的一种动态资源

    • Servlet 是前后端衔接的一种技术, 不是所有的JAVA类都可以接收请求和作出相应, Servlet可以

    • 在 MVC 模式中, Servlet 作为 Controller 层 (控制层) 主要技术, 用于和浏览器完成数据交互, 控制交互逻辑


2_Servlet初识

  • 了解 Servlet 开发流程

    • 在后台随机生成一个整数

    • 当浏览器请求一个 Servlet 时

    • 如果生成的是奇数, 返回 “happy new year”

    • 如果生成的是偶数, 返回 “happy birthday”

  • 创建一个 JAVAWEB 项目, 并在项目中开发一个自己的 Servlet , 继承 HttpServlet 类

    在这里插入图片描述

    • 一定要查看External Libraries 中有 Tomcat中的两个JAR jsp-api servlet-api

  • 在 MyServlet 类中重写 service 方法

    • 如果我们想获得请求中的信息, 就要通过 HttpServetRequest 对象获得

    • 如果我们想给浏览器响应一些信息, 就要通过 HttpServletResponse 对象响应

  • 在 service 方法中定义具体的功能代码

    • 代码展示

      package com.xxxxx.servlet;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.io.PrintWriter;
      import java.util.Random;
      
      public class MyServlet extends HttpServlet {
          /*
          * 可以接收浏览器的请求
          * 并作出运算和响应
          * service Servlet服务方法
          *
          */
          @Override
          protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              // 动态生成数据
              int num = new Random().nextInt();
              String message = num % 2 == 0 ? "happy birthday" : "happy new year";
              // 对浏览器作出响应
              PrintWriter writer = response.getWriter();  // 该打印流指向了浏览器
              writer.write(message);
          }
      }
      
  • 在 web.xml 中配置 Servlet 的映射路径

    在这里插入图片描述

  • 打开浏览器请求Servlet资源

    在这里插入图片描述


3_Servlet案例开发

  • web.xml 配置欢迎页

    • Tomcat/conf/web.xml这个配置文件中定义了所有的项目的一些默认配置信息

      在这里插入图片描述

    • 其中有一项是关于欢迎页的配置

      在这里插入图片描述

    • 当我们自己的项目没有指定欢迎页时, 就默认遵循这个配置

    • 当我们自己定义欢迎页, 我们的项目就不再遵循 Tomcat/conf/web.xml 中欢迎的配置规则了

      在这里插入图片描述

  • 案例开发需求

    • 准备一个登录页, 可以输入用户名和密码

    • 输入完毕后向后台 Servlet 提交用户名和密码

    • Servlet接收到用户名和密码之后, 校验是否正确

    • 如果正确响应 Success

    • 如果不正确响应 Fail

  • 开发过程如下

    • 项目结构

      在这里插入图片描述

    • 开发登录页

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      </head>
      <body>
      <form method="get" action="loginServlet.do">
          <table style="margin: 0px auto" width="300px" cellpadding="0px" cellspacing="0px" border="1px">
              <tr>
                  <td>用户名</td>
                  <td>
                      <input type="text" name="username">
                  </td>
              </tr>
              <tr>
                  <td>密码</td>
                  <td>
                      <input type="password" name="pwd">
                  </td>
              </tr>
              <tr align="center">
                  <td colspan="2">
                      <input type="submit" value="登录">
                  </td>
              </tr>
          </table>
      </form>
      </body>
      </html>
      
    • 开发后台Servlet

      package com.xxxxx.servlet;
      
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      /**
      * @Auther: xiaowaitao
      * @Date: 2026/5/24 - 05 - 24 - 13:33
      * @Description: com.xxxxx.servlet
      * @Version: 1.0
      */
      public class LoginServlet extends HttpServlet {
          @Override
          protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              System.out.println("login servlet invoked");
              // 获取请求中的数据
              String username = req.getParameter("username");
              String pwd = req.getParameter("pwd");
              // 判断数据
              String message = null;
              if (username.equals("xxxxx") && pwd.equals("123456")) {
                  message = "Success";
              } else {
                  message = "Fail";
              }
              // 作出相应
              resp.getWriter().write(message);
          }
      }
      
    • 配置Servlet

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
              version="4.0">
          <servlet>
              <servlet-name>loginServlet</servlet-name>
              <servlet-class>com.xxxxx.servlet.LoginServlet</servlet-class>
          </servlet>
      
          <servlet-mapping>
              <servlet-name>loginServlet</servlet-name>
              <url-pattern>/loginServlet.do</url-pattern>
          </servlet-mapping>
      
          <welcome-file-list>
              <welcome-file>login.html</welcome-file>
          </welcome-file-list>
      </web-app>
      
    • 运行测试


4_HttpServletRequest

  • 回顾 http 请求:

    • 一个 http 请求可以分为三个部分

      • 请求行

        在这里插入图片描述

      • 请求头

        在这里插入图片描述

      • 请求体
        • get 方式提交的请求数据通过地址栏提交, 没有请求体
        • post 方式提交请求数据单独放到请求体中, 请求时所携带的数据 (post方式)
  • http支持的请求方式:

    在这里插入图片描述

  • post 和 get 方式提交请求的差别 (面试,重要)

    • GET在浏览器回退时是无害的,而POST会再次提交请求

    • GET产生的URL地址可以被Bookmark,而POST不可以

    • GET请求会被浏览器主动cache,而POST不会,除非手动设置

    • GET请求只能进行url编码,而POST支持多种编码方式

    • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留

    • GET请求在URL中传送的参数是有长度限制的,而POST则没有。对参数的数据类型GET只接受ASCII字符,而POST即可是字符也可是字节

    • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息

    • GET参数通过URL传递,POST放在Request body中

  • HttpServletRequest

    • HttpServletRequest 对象代表客户端浏览器的请求,当客户端浏览器通过HTTP协议访问服务器时,HTTP请求中的所有信息都会被 Tomcat 所解析并封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息

    • 1.获取请求行信息

      • req.getRequestURL()
        • 返回客户端浏览器发出请求时的完整URL
      • req.getRequestURI()
        • 返回请求行中指定资源部分
      • req.getRemoteAddr()
        • 返回发出请求的客户机的IP地址
      • req.getLocalAddr()
        • 返回 WEB服务器 的IP地址
      • req.getLocalPort()
        • 返回 WEB服务器 处理 Http协议 的连接器所监听的端口
    • 2.获取请求头信息

      • req.getHeader("headerkey")
        • 根据请求头中的 key 获取对应的 value
        • String headerValue = req.getHeader("headerKey");
      • req.getHeaderNames()
        • 获取请求头中所有的key,该方法返回枚举类型
        • Enumeration<String> headerNames = req.getHeaderNames();
      • 测试代码
      public class Servlet3 extends HttpServlet {
          @override
          protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException) {
              System.out.println(req.getRequestURL());    //返回客户端浏览器发出请求时的完整URL
              System.out.println(req.getRequestURI());    //返回请求行中指定资源部分
              System.out.println(req.getRemoteAddr());    //返回发出请求的客户机的IP地址
              System.out.println(req.getLocalAddr());     //返回WEB服务器的IP地址
              System.out.println(req.getLocalPort());     //返回WEB服务器处理Http协议的连接器所监听的端口
              System.out.println("主机名: " + req.getLocalName());
              System.out.println("客户端PORT: " + req.getRemotePort());
              System.out.println("当前项目部署名: " + req.getContextPath());
              System.out.println("协议名:"+req.getScheme());
              System.out.println("请求方式:"+req.getMethod());
      
              // 根据请求头名或者请求头对应的值
              System.out.println(req.getHeader("Accept"));
              
              // 获得全部的请求头名
              Enumeration<String> headerNames = req.getHeaderNames();
              while (headerNames.hasMoreElements()){
                  String headername = headerNames.nextElement();
                  System.out.println(headername+":"+req.getHeader(headername));
              }
          }
      }
      
    • 3.获取请求数据

      • 在 Servlet 获取请求数据的方式
        • req.getParameter("key")
          • 根据key获取指定value
          • String str = req.getParameter("key");
      • 获取复选框 (checkbox组件) 中的值
        • req.getParameterValues("checkboxkey")
          • 获取复选框 (checkbox组件) 中的值,返回一个 String[]
          • 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中使用的是ISO-8859-1的单字节编码完成字节与字符的转换,所以数据中含有中文就会出现乱码,可以通过 req.setCharacterEncoding(“utf-8”) 方法来对提交的数据根据指定的编码方式重新做编码处理
    • 测试代码:

      • 前端:
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        </head>
        <body>
        <!--
        开发form表单注意事项
        1_ form 不是from
        2_ form表单内部不是所有的标签信息都会提交 一些输入信息  input select textarea ... ...
        3_ 要提交的标签必须具备name属性  name属性的作用是让后台区分数据  id便于在前端区分数据
        4_ 要提交的标签一般都要具备value属性  value属性确定我们要提交的具体的数据
        5_ get post
        get方式 数据是通过URL携带
        提交的数据只能是文本
        提交的数据量不大
        get方式提交的数据相对不安全
        
        post 将数据单独打包放到请求体中
        提交的数据可以是文本可以是各种文件
        提交的数据量理论上没有上限
        post方式提交数据相对安全
        
        当一个表单标签
        readonly只读 也是会提交数据的
        hidden  隐藏 也是会提交数据
        disabled 不可用 显示但是不提交
        
        -->
        <form method="get" action="myServlet">
            <table style="margin: 0px auto" width="300px" cellpadding="0px" cellspacing="0px" border="1px">
            <tr>
                <td>用户名</td>
                <td>
                  <input type="text" name="username" id="in1" value="12345" disabled >
                </td>
            </tr>
            <tr>
                <td>密码</td>
                <td>
                    <input type="password" name="pwd">
                </td>
            </tr>
            <tr>
                <td>性别</td>
                <td>
                    <input type="radio" name="gender" value="1" checked><input type="radio" name="gender" value="0"></td>
            </tr>
            <tr>
                <td>爱好</td>
                <td>
                    <input type="checkbox" name="hobby" value="1">蓝球
                    <input type="checkbox" name="hobby" value="2">足球
                    <input type="checkbox" name="hobby" value="3">羽毛球                
                    <input type="checkbox" name="hobby" value="4">乒乓球
                </td>
            </tr>
            <tr>
                <td>个人简介</td>
                <td>
                    <!--
                    文本域 双标签 页面上显示的文字是双标签中的文本 不是value属性
                    文本域提交的数据不是value属性值,是双标签中的文本
                    -->
                    <textarea name="introduce" >b</textarea>
                </td>
            </tr>
        
            <tr>
                <td>籍贯</td>
                <td>
                    <!--
                    select
                    option没有定义value属性 那么就提交option中间的文字(不推荐)
                    -->
        
                    <select name="provience">
                        <option value="1">a京</option>
                        <option value="2">b津</option>
                        <option value="3">c冀</option>
                    </select>
                </td>
            </tr>
            <tr align="center">
                <td colspan="2">
                    <input type="submit" value="提交数据">
                </td>
            </tr>
            </table>
        </form>
        </body>
        </html>
        
      • Servlet:
        package com.xxxxx.servlet;
        
        import javax.servlet.ServletException;
        import javax.servlet.http.HttpServlet;
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        import java.io.IOException;import java.util.Arrays;
        import java.util.Enumeration;
        import java.util.Map;
        import java.util.Set;
        
        public class MyServlet extends HttpServlet {
            @Override
            protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                // req获取参数
                // 如果 前端发过来的数据由数据名但是没有值, getParameter返回的是一个空字符串  ""
                // 获取的参数在提交的数据中名都没有,getParameter返回的是null
                String username = req.getParameter("username");
                System.out.println("username:"+username);
                System.out.println("password:"+req.getParameter("pwd"));
                System.out.println("gender:"+req.getParameter("gender"));
                // hobby=1&hobby=2&hobby=3 想要获得多个同名的参数 getParameterValues 返回的是一个Sting数组
                String[] hobbies = req.getParameterValues("hobby");
        
                // textarea
                System.out.println("introduce:"+req.getParameter("introduce"));
        
                // select
                System.out.println("provience:"+req.getParameter("provience"));
        
                System.out.println("___________________________");
                // 如果不知道参数的名字?
                // 获取所有的参数名
                Enumeration<String> pNames = req.getParameterNames();
                while(pNames.hasMoreElements()){
                    String pname = pNames.nextElement();
                    String[] pValues = req.getParameterValues(pname);
                    System.out.println(pname+":"+Arrays.toString(pValues));
                }
        
                System.out.println("________________________________");
                Map<String, String[]> pmap = req.getParameterMap();
                Set<Map.Entry<String, String[]>> entries = pmap.entrySet();
                for (Map.Entry<String, String[]> entry : entries) {
                    System.out.println(entry.getKey()+":"+Arrays.toString(entry.getValue()));
                }
            }
        }
        

5_HttpServletResponse

  • http响应部分可以分为三部分

    • 1.响应行

      在这里插入图片描述

      • 响应状态码列表如下
        在这里插入图片描述
    • 2.响应头

      • Content-Type:响应内容的类型(MIME)
        在这里插入图片描述
    • 3.响应实体

      • 概念
        • 服务器响应回来的内容
      • HttpServletResponse
        • HttpServletResponse对象代表服务器的响应
        • 这个对象中封装了响应客户端浏览器的流对象,以及向客户端浏览器响应的响应头、响应数据、响应状态码等信息
  • 响应的设置

    • ContentType响应头

      • resp.setContentType("MIME")
        • 该方法可通过 MIME-Type 设置响应类型
          • MIME的全称是 Multipurpose Internet Mail Extensions,即多用途互联网邮件扩展类型
          • 这是 HTTP协议 中用来定义文档性质及格式的标准
          • 对 HTTP传输内容类型 进行了全面定义
          • 服务器通过MIME告知响应内容类型,而浏览器则通过MIME类型来确定如何处理文档
          Type Meaning (描述)
          application/msword Microsoft Word document
          application/octet-stream Unrecognized or binary data
          application/pdf Acrobat (.pdf) file
          application/postscript PostScript file
          application/vnd.lotus-notes Lotus Notes file
          application/vnd.ms-excel Excel spreadsheet
          application/vnd.ms-powerpoint PowerPoint presentation
          application/x-gzip Gzip archive
          application/x-java-archive JAR file
          application/x-java-serialized-object Serialized Java object
          application/x-java-vm Java bytecode (.class) file
          application/zip Zip archive
          application/json JSON
          audio/basic Sound file in .au or .snd format
          audio/midi MIDI sound file
          audio/x-aiff AIFF sound file
          audio/x-wav Microsoft Windows sound file
          image/gif GIF image
          image/jpeg JPEG image
          image/png PNG image
          image/tiff TIFF image
          image/x-xbitmap X Windows bitmap image
          text/css HTML cascading style sheet
          text/html HTML document
          text/plain Plain text
          text/xml XML
          video/mpeg MPEG video clip
          video/quicktime QuickTime video clip
    • 设置字符型响应

      • 常见的字符型响应类型
        • 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.setCharacterEncoding("utf-8");
        • 设置服务端为浏览器产生响应的响应编码,服务端会根据此编码将响应内容的字符转换为字节
      • response.setContentType("text/html;charset=utf-8");
        • 设置服务端为浏览器产生响应的响应编码,服务端会根据此编码将响应内容的字符转换为字节
        • 同时客户端浏览器会根据此编码方式显示响应内容
    • 在响应中添加附加信息(文件下载)

      • 在实现文件下载时,我们需要修改响应头,添加附加信息
        • response.setHeader("Content-Disposition", "attachment; filename=" + 文件名);
      • Content-Disposition:attachment
        • 该附加信息表示作为对下载文件的一个标识字段
        • 不会在浏览器中显示而是直接做下载处理
        • 解决文件名中文乱码问题
          • resp.addHeader("Content-Disposition","attachment;filename="+new String (file.getName().getBytes("gbk"),"iso-8859-1"));
    • 测试代码

      package com.xxxxx.servlet;
      
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      
      public class MyServlet2 extends HttpServlet {
        @override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          // 设置响应码
          // resp.setStatus(500);
          // resp.setStatus(405, "request method not supported");
      
          // 设置响应头
          // resp.setHeader("Date", "2026-5-25");
      
          // 自定义头
          // resp.setHeader("aaa", "bbb");
          // 高速浏览器响应的数据是什么? 浏览器根据此头决定 数据如何应用
          // 设置MIME类型 json  xml 文件下载  ... ...
          // resp.setHeader("content-type", "type/css");
          resp.setContentType("text/html");   //专门用于设置 Content-Type 响应头
          resp.getWriter().write("<h1>this is tag h1</h1>");
        }
      }
      

6_关于乱码问题

  • 控制台乱码

    • 设置 Tomcat 中 conf 下 logging.properties 中所有的 UTF-8 编码为 GBK 即可

  • post请求乱码

    • 通过 HttpServletRequest 设置请求编码

      • req.setCharacterEncoding("UTF-8");
  • get请求乱码

    • 需要手动进行编码解码, 或者设置 tomcat 中的 server.xml 中的URI编码

    • tomcat9 已经解决了该问题

      在这里插入图片描述
  • 响应乱码

    • 通过 HttpServletResponse 设置响应编码

      在这里插入图片描述

7_Servlet的继承结构

在这里插入图片描述

  • Servlet 接口

    • init()

      • 创建 Servlet 对象后立即调用该方法完成其他初始化工作
    • service()

      • 处理客户端请求,执行业务操作,利用响应对象响应客户端请求
    • destroy()

      • 在销毁 Servlet对象 之前调用该方法,释放资源
    • getServletConfig()

      • ServletConfig 是容器向 servlet 传递参数的载体
    • getServletInfo()

      • 获取 servlet 相关信息
  • ServletConfig 接口

    • Servlet 运行期间,需要一些辅助信息,这些信息可以在 web.xml 文件中,使用一个或多个元素,进行配置

    • 当Tomcat初始化一个 Servlet 时,会将该 Servlet 的配置信息,封装到一个 ServletConfig 对象中,通过调用 init(ServletConfig config) 方法,将 ServletConfig 对称传递给 Servlet

  • GenericServlet 抽象类

    • GenericServlet 是实现了 Servlet 接口的抽象类

    • 在 GenericServlet 中进一步的定义了 Servlet 接口的具体实现,其设计的目的是为了和应用层协议解耦,在 GenericServlet 中包含一个 Service 抽象方法

    • 我们也可以通过继承 GenericServlet 并实现 Service 方法实现请求的处理,但是需要将ServletReuqest 和 ServletResponse 转为 HttpServletRequest 和 HttpServletResponse

  • HttpServlet

    • 继承自 GenericServlet, 针对于处理 HTTP 协议的请求所定制

    • 在 HttpServlet 的 service() 方法中已经把 ServletReuqest 和 ServletResponse 转为 HttpServletRequest 和 HttpServletResponse

    • 直接使用 HttpServletRequest 和 HttpServletResponse, 不再需要强转

    • 实际开发中, 直接继承 HttpServlet, 并根据请求方式复写 doXxx() 方法即可

      在这里插入图片描述

    • 在我们自定义的 Servlet 中, 如果想区分请求方式, 不同的请求方式使用不同的代码处理, 那么我么重写 doGet doPost 即可

    • 如果我们没有必要区分请求方式的差异, 那么我们直接重写 service 方法即可

    • 要么重写 doGet doPost 要么重写 service, 必须二选一, 而且必须进行重写

      在这里插入图片描述

      在这里插入图片描述


8_Servlet的生命周期

  • 概念

    • Servlet的生命周期是由容器管理的,分别经历四各阶段

      阶段 次数 时机
      创建 1次 第一次请求
      初始化 1次 实例化之后
      执行服务 多次 每次请求
      销毁 1次 停止服务
      • new:实例化
      • init():初始化
      • service():执行服务
      • destroy():回收销毁
    • 当客户端浏览器第一次请求 Servlet 时,容器会实例化这个 Servlet,然后调用一次 init 方法,并在新的线程中执行 service 方法处理请求

    • service 方法执行完毕后容器不会销毁这个 Servlet 而是做缓存处理,当客户端浏览器再次请求这个 Servlet 时,容器会从缓存中直接找到这个 Servlet 对象,并再一次在新的线程中执行 Service 方法

    • 当容器在销毁 Servlet 之前对调用一次 destory 方法

    • 在 Servlet 中我们一般不要轻易使用成员变量!!!

      • 可能会造成线程安全问题
    • 如果要使用的话, 应该尽量避免对成员变量产生修改

    • 如果要产生修改, 我们应该注意线程安全问题

    • 如果我们自己添加线程安全编码处理, 会严重影响效率

    • 综上所述:

      • 原则, 能不用成员变量就不用!!!
  • Servlet代码

    package com.xxxxx.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class MyServlet4 extends HttpServlet {
      // 成员变量
      public MyServlet4()   {// 构造一个Servlet对象的方法
        System.out.println("MyServlet4 Constructor invoked");
        try {
          Thread.sleep(5000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    
      @Override
      public void init() throws ServletException {// 初始化
        System.out.println("MyServlet4 init invoked");
        try {
          Thread.sleep(5000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    
      @Override
      protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 执行服务
        System.out.println("MyServlet4 service invoked");
      }
    
      @Override
      public void destroy() {// 销毁
        System.out.println("MyServlet4 destory invoked");
      }
    }
    
  • 配置Servlet

    <servlet>
      <servlet-name>myServlet4</servlet-name>
      <servlet-class>com.xxxxx.servlet.MyServlet4</servlet-class>
      <load-on-startup>6</load-on-startup>
    </servlet>
    
    <servlet-mapping>
      <servlet-name>myServlet4</servlet-name>
      <url-pattern>/myServlet4.do</url-pattern>
    </servlet-mapping>
    
    • 多次请求 servlet 并查看控制台输出即可印证上述结论, 值得注意的是, 如果需要 Servlet 在服务启动时就实例化并初始化, 我们可以在 servlet 的配置中添加 load-on-startup 配置启动顺序, 配置的数字为启动顺序, 应避免冲突且应>6

      在这里插入图片描述
  • Servlet处理请求的过程

    • 当浏览器基于 get方式 请求我们创建 Servlet 时,我们自定义的 Servlet 中的 doGet 方法会被执行

    • doGet方法 能够被执行并处理 get请求 的原因是,容器在启动时会解析 web工程 中 WEB-INF 目录中的 web.xml 文件,在该文件中我们配置了 Servlet 与 URI 的绑定,容器通过对请求的解析可以获取请求资源的 URI,然后找到与该 URI 绑定的 Servlet 并做实例化处理 (注意:只实例化一次,如果在缓存中能够找到这个 Servlet 就不会再做次实例化处理)

    • 在实例化时会使用 Servlet接口类型 作为引用类型的定义,并调用一次 init方法 ,由于 HttpServlet 中重写了该方法所以最终执行的是 HttpServlet 中 init方法 (HttpServlet 中的 Init方法 是一个空的方法体),然后在新的线程中调用 service方法

    • 由于在 HttpServlet 中重写了 Service方法 所以最终执行的是 HttpServlet 中的 service方法

    • 在 service方法 中通过 request.getMethod() 获取到请求方式进行判断如果是 Get方式 请求就执行 doGet方法,如果是 POST请求 就执行 doPost方法

    • 如果是基于 GET方式 提交的,并且在我们自定义的 Servlet 中又重写了 HttpServlet 中的 doGet方法,那么最终会根据 Java的多态特性 转而执行我们自定义的 Servlet 中的 doGet方法

      在这里插入图片描述

9_ServletConfig 和 ServletContext

  • ServletContext对象介绍

    • ServletContext官方 叫 Servlet上下文

    • 服务器会为每一个 Web应用 创建一个 ServletContext对象

    • 这个对象全局唯一,而且 Web应用 中的所有 Servlet 都共享这个对象

    • 所以叫全局应用程序共享对象

  • ServletContext对象作用

    • 相对路径 转 绝对路径

    • 获取 容器的附加信息

    • 读取 配置信息

    • 全局容器

  • ServletContext对象的使用

    • 获取项目的部署名

      • context.getContextPath()
        • 相对路径转绝对路径(文件上传下载时需要注意)
      • context.getRealPath("Path")
        • 该方法可以将一个相对路径转换为绝对路径,在文件上传与下载时需要用到该方法做路径的转换
    • 获取容器的附加信息

      • servletContext.getServletInfo()
        • 返回Servlet容器的名称和版本号
      • servletContext.getMajorVersion()
        • 返回Servlet容器所支持Servlet的主版本号
      • servletContext.getMinorVersion()
        • 返回Servlet容器所支持Servlet的副版本号
    • 获取web.xml文件中的信息

      在这里插入图片描述

      • servletContext.getInitParameter("key")
        • 该方法可以读取 web.xml文件 中 <context-param>标签 中的配置信息
      • 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文件 中的 <servlet>节点

    • 当 Tomcat 初始化一个 Servlet 时,会将该 Servlet的配置信息,封装到一个 ServletConfig对象 中

    • 我们可以通过该对象读取节点中的配置信息

      在这里插入图片描述

    • servletConfig.getInitParameter("key");

      • 该方法可以读取 web.xml文件 中 <servlet>标签<init-param> 标签中的配置信息
    • servletConfig.getInitParameterNames();

      • 该方法可以读取 web.xml文件 中当前 <servlet>标签 中所有 <init-param>标签 中的值
  • 测试代码

    • Servlet1

      package com.xxx.testServlet;
      
      import javax.servlet.ServletContext;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;import java.io.IOException;
      import java.util.ArrayList;
      import java.util.Collections;
      import java.util.List;
      
      public class Servlet1 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          // 获取Servlet对象的方式
          // 通过req对象
          ServletContext servletContext1 = req.getServletContext();
          // 通过继承的方法
          ServletContext servletContext2 = this.getServletContext();
          System.out.println(servletContext1 == servletContext2);
          // 获取当前项目的部署名
          String contextPath = servletContext1.getContextPath();
          System.out.println("contextPath"+contextPath);
          // 将一个相对路径转化为项目的绝对路径
          String fileUpload = servletContext1.getRealPath("fileUpload");
          System.out.println(fileUpload);
      
          String serverInfo = servletContext1.getServerInfo();
          System.out.println("servletInfo"+serverInfo);
          
          int majorVersion = servletContext1.getMajorVersion();
          int minorVersion = servletContext1.getMinorVersion();
          System.out.println(majorVersion+":"+minorVersion);
      
          // 获取web.xml中配置的全局的初始信息
          String username = servletContext1.getInitParameter("username");
          String password = servletContext1.getInitParameter("password");
          System.out.println(username+":"+password);
      
          //向ServletContext对象中增加数据 域对象
          List<String> data = new ArrayList<>();
          Collections.addAll(data,"张三","李四","王五");
          servletContext1.setAttribute("list", data);
          servletContext1.setAttribute("gender", "boy");
        }
      }
      
    • Servlet2

      package com.xxx.testServlet;
      
      import javax.servlet.ServletContext;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.util.Enumeration;
      import java.util.List;
      
      public class Servlet2 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          ServletContext servletContext = this.getServletContext();
          // 获取web.xml中配置的全局的初始信息
          Enumeration<String> pnames = servletContext.getInitParameterNames();
          while(pnames.hasMoreElements()){
            String e = pnames.nextElement();
            System.out.println(e+":"+servletContext.getInitParameter(e));
          }
      
          List<String> list = (List<String>) servletContext.getAttribute("list");
          System.out.println(list);
          String gender = (String)servletContext.getAttribute("gender");
          System.out.println(gender);
        }
      }
      
    • Servlet3

      package com.xxx.testServlet;
      
      import javax.servlet.ServletConfig;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      
      public class Servlet3 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          ServletConfig servletConfig = this.getServletConfig();
          System.out.println(servletConfig.getInitParameter("brand"));        
          System.out.println(servletConfig.getInitParameter("screen"));    
        }
      }
      
    • Servlet4

      package com.xxx.testServlet;
      
      import javax.servlet.ServletConfig;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      
      public class Servlet4 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          ServletConfig servletConfig = this.getServletConfig();
          System.out.println(servletConfig.getInitParameter("pinpai"));
          System.out.println(servletConfig.getInitParameter("pingmu"));
        }
      }
      
    • web.xml配置

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
               version="4.0">
      
          <context-param>
              <param-name>username</param-name>        
              <param-value>xxx</param-value>
          </context-param>
      
          <context-param>
              <param-name>password</param-name>        
              <param-value>123456</param-value>
          </context-param>
      
          <servlet>
              <servlet-name>servlet1</servlet-name>        
              <servlet-class>com.xxx.testServlet.Servlet1</servlet-class>
          </servlet>    
          <servlet>
              <servlet-name>servlet2</servlet-name>        
              <servlet-class>com.xxx.testServlet.Servlet2</servlet-class>
          </servlet>
      
          <servlet>
              <servlet-name>servlet3</servlet-name>
              <servlet-class>com.xxx.testServlet.Servlet3</servlet-class>
              <init-param>
                  <param-name>brand</param-name>            
                  <param-value>ASUS</param-value>
              </init-param>
          </servlet>
          <servlet>
              <servlet-name>servlet4</servlet-name>
              <servlet-class>com.xxx.testServlet.Servlet4</servlet-class>
              <init-param>
                  <param-name>pinpai</param-name>            
                  <param-value>联想</param-value>
              </init-param>
              <init-param>            
                  <param-name>pingmu</param-name>            
                  <param-value>京东方</param-value>        
              </init-param>
          </servlet>
      
          <servlet-mapping>
              <servlet-name>servlet1</servlet-name>
              <url-pattern>/servlet1.do</url-pattern>
          </servlet-mapping>
          <servlet-mapping>        
              <servlet-name>servlet2</servlet-name>        
              <url-pattern>/servlet2.do</url-pattern>    
          </servlet-mapping>
          
          <servlet-mapping>        
          <servlet-name>servlet3</servlet-name>        
          <url-pattern>/servlet3.do</url-pattern>    
          </servlet-mapping>
          <servlet-mapping>        
          <servlet-name>servlet4</servlet-name>        
          <url-pattern>/servlet4.do</url-pattern>    
          </servlet-mapping>
      </web-app>
      

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐