• Servlet



    1. 概念

    1. Servlet 是 JavaEE 规范之一。 规范就是接口
    2. Servlet 就 JavaWeb 三大组件之一。 三大组件分别是: Servlet 程序、 Filter 过滤器、 Listener 监
      听器。
    3. Servlet服务于HTTP协议的服务端的一个小程序,"接收请求,解析请求,根据请求执行业务逻辑,
      做出响应

    也就是说 servlet是一个用来处理 请求 做出回应的容器,对于每一个应用程序,Servlet容器还会创建一个ServletContext对象。这个对象中封装了上下文(应用程序)的环境详情。每个应用程序只有一个ServletContext。每个Servlet对象也都有一个封装Servlet配置的ServletConfig对象。

    2.基础案例

    从Servlet3.0开始,配置Servlet支持注解方式,但还是保留了配置web.xml方式,所有使用Servlet有两
    种方式:
    (1)Servlet类上使用@WebServlet注解进行配置
    (2)web.xml文件中配置

    1.基于注解的配置

    这个基于注解的配置关键在于@WebServlet("/hello")这个用来设置虚拟路径然后才有了访问的地址

    @WebServlet常用属性
    在这里插入图片描述

    1. loadOnStartup属性::标记容器是否在启动应用时就加载Servlet,默认不配置或数值为负数时表示客户端第一次请求Servlet时再加载;0或正数表示启动应用就加载,正数情况下,数值越小,加载该Servlet的优先级越高;
    @WebServlet(value="/test1",loadOnStartup=1)
    
    • 1
    1. urlPatterns的常用规则
    • /*或者/:拦截所有(所谓拦截也就是意思只有这个范围下的地址可以被访问)
      如果放行特定的请求比如静态资源html,css,jpg,可以配置如下:
    <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
    </servlet-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • *.do:拦截指定后缀

    • 使用注解时,需要注意

    根元素中不能配置属性metadata-complete=“true”,否则无法加载Servlet。metadata-complete属性表示通知Web容器是否寻找注解,默认不写或者设置false,容器会扫描注解,为Web应用程序构建有效的元数据;metadata-complete=“true”,会在启动时不扫描注解(annotation)。如果不扫描注解的话,用注解进行的配置就无法生效,例如:@WebServlet

    1.引入依赖

    在这里插入图片描述

    2.创建HttpServlet

    @WebServlet("/hello")
    public class HelloServlet extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse
                response) throws ServletException, IOException {
            BufferedReader in = new BufferedReader(new
                    InputStreamReader(request.getInputStream()));
            String line = null;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
            in.close();
        }
    
        @Override
        protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
            System.out.println("queryString = " + request.getQueryString());
            response.getWriter().print(request.getQueryString());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.表单访问

    <h4>get</h4>
    <form action="http://localhost:8080/servlet-demo/hello" method="get">
      <input type="text" name="username" value="mickey"><br>
      <input type="text" name="password" value="123456"><br>
      <input type="submit" value="提交">
    </form>
    <h4>post</h4>
    <form action="http://localhost:8080/servlet-demo/hello" method="post">
      <input type="text" name="username" value="mickey"><br>
      <input type="text" name="password" value="123456"><br>
      <input type="submit" value="提交">
    </form>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.基于XML配置

    这个基于XML配置的关键就在于下面图的资源路径 也就是虚拟路径 这样才可以找到这个页面

    web.xml

    <servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.lxs.demo.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    执行地址到servlet的关系
    在这里插入图片描述

    3.servlet生命周期

    Servlet 是 Java Web 开发中的一种用于处理请求和响应的组件。它具有自己的生命周期,包括以下几个阶段:

    1. 加载:当容器启动首次请求到达时,Servlet 容器会加载 Servlet 类。这个阶段会创建 Servlet 类的实例,并调用其 init() 方法进行初始化。

    2. 初始化:在加载后,Servlet 容器会调用 Servlet 实例的 init() 方法进行初始化。在初始化阶段,可以执行一些必要的设置,例如读取配置文件、建立数据库连接等。init() 方法在 Servlet 的生命周期中只会被调用一次。

    3. 处理请求:在初始化完成后,Servlet 容器会根据每个请求创建一个线程,调用 Servlet 实例的 service() 方法来处理请求。在 service() 方法中,可以根据请求的类型(如 GET、POST 等)执行相应的逻辑,生成响应数据。

    4. 销毁:当容器关闭或者需要卸载 Servlet 时,会调用 Servlet 实例的 destroy() 方法进行清理操作。在该方法中,可以进行资源释放、数据库连接关闭等善后工作。destroy() 方法也只会被调用一次。

    需要注意的是,每次请求都会创建一个单独的线程来处理,而不是每个请求都创建一个新的 Servlet 实例。Servlet 实例是多线程共享的,因此需要在实现中保证线程安全性。

    配置参数解决输出中文乱码问题

    -Dfile.encoding=UTF-8 -Dconsole.encoding=UTF-8
    
    • 1

    在这里插入图片描述

    4.ServletConfig接口

    当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init( )方式传入一个ServletConfig对象。
    配置参数都在web.xml里面配置

    其中几个方法如下

    1. String getServletName():获取当前 Servlet 的名称。

    2. ServletContext getServletContext():获取与当前 Servlet 相关联的 Servlet 上下文对象。

    3. String getInitParameter(String name):根据给定参数名获取相应的初始化参数值。

    4. Enumeration getInitParameterNames():获取所有初始化参数的名称的枚举。

    总之,ServletConfig 接口提供了一种机制,允许 Servlet 访问它的配置信息和初始化参数。这些信息对于 Servlet 的运行时行为和逻辑可能会非常有用。

    5.ServletContext对象

    ServletContext 对象是 Java Web 应用程序中的一个接口,它代表了整个 Web 应用程序的上下文环境。每个 Web 应用程序只有一个 ServletContext 实例,由 Servlet 容器在启动应用程序时创建,并在关闭应用程序时销毁。

    ServletContext 接口提供了一系列方法,用于访问和操作与当前 Web 应用程序相关的信息和资源,包括:

    1. 获取初始化参数:可以使用 getInitParameter(String name) 方法获取部署描述符(如 web.xml 文件)中配置的初始化参数的值。通过 getInitParameterNames() 方法可以获取所有初始化参数的名称。

    2. 获取上下文路径:可以使用 getContextPath() 方法获取当前 Web 应用程序的上下文路径(Context Path)。上下文路径是 Web 应用程序被部署后的访问路径的一部分。

    3. 获取真实路径:可以使用 getRealPath(String path) 方法将给定的相对路径转换为在文件系统中的真实路径。此方法通常用于获取在 Web 应用程序中的资源的物理路径。

    4. 获取资源:可以使用 getResource(String path)getResourceAsStream(String path) 方法获取位于 Web 应用程序中的某个资源的 URL 或输入流。

    5. 设置和获取属性:可以使用 setAttribute(String name, Object value) 方法设置一个在 ServletContext 中的属性。使用 getAttribute(String name) 方法可以获取指定名称的属性的值。

    除了以上几点,ServletContext 还提供了其他一些方法,用于获取 Servlet 注册信息、获取和操作 ServletContext 初始化参数等。通过 ServletContext 对象,可以在整个 Web 应用程序范围内共享数据和资源,以及访问应用程序的配置信息

    6.HttpServlet抽象类

    HttpServlet抽象类是继承于GenericServlet抽象类而来的。使用HttpServlet抽象类时,还需要借助分别代表Servlet请求和Servlet响应 HttpServletRequest和HttpServletResponse对象。
    在这里插入图片描述
    在实现这个抽象类之后我们可以通过重写Service方法来处理请求即可

    HttpServlet 类定义了以下几个主要方法:

    1. void service(HttpServletRequest request, HttpServletResponse response):这是 HttpServlet 的核心方法,用于处理 HTTP 请求和生成 HTTP 响应。在该方法中,可以根据不同的 HTTP 方法(如 GET、POST 等)执行相应的逻辑来处理请求的参数、生成响应内容等。

    2. protected void doGet(HttpServletRequest request, HttpServletResponse response):用于处理 HTTP GET 请求的方法。默认情况下,service() 方法会调用此方法来处理 GET 请求。

    3. protected void doPost(HttpServletRequest request, HttpServletResponse response):用于处理 HTTP POST 请求的方法。默认情况下,service() 方法会调用此方法来处理 POST 请求。

    4. protected void doPut(HttpServletRequest request, HttpServletResponse response):用于处理 HTTP PUT 请求的方法。

    5. protected void doDelete(HttpServletRequest request,HttpServletResponse response):用于处理 HTTP DELETE 请求的方法。

    除了上述方法,HttpServlet 还提供了一些其他的方法,如 doOptions() 用于处理 HTTP OPTIONS 请求,doHead() 用于处理 HTTP HEAD 请求等。这些方法可以根据需要进行覆盖,以实现对不同类型的 HTTP 请求的处理

    7.中文乱码问题

    出现中文乱码问题通常就是编码和解码不一致导致

    1. Get 请求的中文乱码解决:
      get的默认编码utf-8,以前老版本tomcat中get编码是iso-8859-1
    // 获取请求参数
    String username = req.getParameter("username");
    //1 先以 iso8859-1 进行编码
    //2 再以 utf-8 进行解码
    username = new String(username.getBytes("iso-8859-1"), "UTF-8");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. POST 请求的中文乱码解决
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException,
    IOException {
    // 设置请求体的字符集为 UTF-8, 从而解决 post 请求的中文乱码问题
    req.setCharacterEncoding("UTF-8");
    System.out.println("-------------doPost------------");
    // 获取请求参数
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    String[] hobby = req.getParameterValues("hobby");
    System.out.println("用户名: " + username);
    System.out.println("密码: " + password);
    System.out.println("兴趣爱好: " + Arrays.asList(hobby));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. response的乱码解决
      方式1:
    // 设置服务器字符集为 UTF-8
    resp.setCharacterEncoding("UTF-8");
    // 通过响应头, 设置浏览器也使用 UTF-8 字符集
    resp.setHeader("Content-Type", "text/html; charset=UTF-8");
    
    • 1
    • 2
    • 3
    • 4

    解决响应中文乱码方案二(推荐) :

    // 它会同时设置服务器和客户端都使用 UTF-8 字符集, 还设置了响应头
    // 此方法一定要在获取流对象之前调用才有效
    resp.setContentType("text/html; charset=UTF-8");
    
    • 1
    • 2
    • 3

    8.请求转发与重定向

    二者区别:
    一次请求与两次请求!

      1. 定义:请求转发是在服务器内部进行的一种机制,将请求从一个组件(如 Servlet)直接转发给另一个组件。重定向是通过发送特殊的响应状态码和 URL 到客户端浏览器,让浏览器重新发送一个新的请求来达到页面跳转的目的。
      1. 浏览器行为:请求转发是在服务器内部完成的,对浏览器是透明的,浏览器的 URL 不会发生变化。而重定向会向浏览器发送一个新的响应,浏览器会根据响应中的 URL 进行请求的重新发送,因此浏览器的 URL 会发生变化。
      1. 请求次数:请求转发只需要一次请求和响应的往返,所以在网络传输上效率更高。而重定向会导致两次请求和响应的往返,一次是原始请求的响应,一次是重定向后新请求的响应,相对来说会增加一定的网络开销。
      1. 共享数据:请求转发时,可以共享同一个 request 对象,在多个组件之间传递数据。而重定向是两次请求,每个请求都会有一个新的 request 对象,数据不能直接共享,需要使用其他机制(如 URL 参数、Session 等)来传递数据。
      1. 场景应用:请求转发常用于在服务器内部进行组件之间的流转,如多个 Servlet 之间的数据交互,MVC 架构中的控制器转发等。重定向常用于页面的跳转,错误处理,或者需要刷新页面的场景。

    1.请求转发

    请求转发(Request Forwarding)是一种在服务器端将请求从一个 Servlet 转发给另一个 Servlet 或 JSP 页面的机制。在请求转发中,客户端只发送一次请求,而服务器在内部将请求从一个组件传递到另一个组件,然后将响应返回给客户端。

    1. 在要进行请求转发的 Servlet 中,获得 RequestDispatcher 实例,可以使用以下代码:
    RequestDispatcher dispatcher = request.getRequestDispatcher("/targetServlet");
    
    • 1

    其中,/targetServlet 是目标 Servlet 的路径。

    1. 调用 forward() 方法来执行请求转发:
    dispatcher.forward(request, response);
    
    • 1

    其中,request 和 response 分别是当前 Servlet 的 HttpServletRequest 和 HttpServletResponse 对象。

    请求转发的主要优点是

    • 内部流转:客户端对转发过程毫无察觉,URL 保持不变。
    • 资源共享:由于转发操作使用同一个 request 对象,可以方便地在多个组件之间共享数据。
    • 减少网络开销:只有一次请求和响应的往返,减少了网络开销。

    请求转发通常用于以下情况

    • Servlet 之间数据交互:可以将请求从一个 Servlet 转发到另一个 Servlet,以便在它们之间共享数据。
    • MVC 架构中的控制器转发:根据请求的不同,将请求转发到不同的控制器来处理特定的业务逻辑。
    • 错误处理:在出现错误时,转发到专门的错误处理 Servlet 或 JSP 页面来显示错误信息。在这里插入图片描述
      servlet1代码
    package Servlet;
    
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    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("/servlet1")
    public class servlet1 extends HttpServlet {
    
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String username=req.getParameter("username");
            System.out.println(("在Servlet1(柜台1)中查看参数(材料):"+username));
    
            req.setAttribute("key1","柜台1的章");
            RequestDispatcher requestDispatcher =
                    req.getRequestDispatcher("/servlet2");
    
            requestDispatcher.forward(req,resp);
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    servlet2代码

    package Servlet;
    
    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("/servlet2")
    public class servlet2 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String username = req.getParameter("username");
            System.out.println("在Servlet2(柜台2)中查看参数(材料):" + username);
    // 查看 柜台1 是否有盖章
            Object key1 = req.getAttribute("key1");
            System.out.println("柜台1是否有章:" + key1);
    // 处理自己的业务
            System.out.println("Servlet2 处理自己的业务 ");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.请求重定向

    请求重定向是客户端向服务器发送请求后,服务器告诉客户端要通过新的地址进行访问的过程。这个过程中,浏览器的地址栏会发生变化,发生两次请求。与请求转发不同的是,请求重定向不能共享Request域中的数据,也不能直接访问WEB-INF下的资源,但可以访问工程外的资源。123
    在这里插入图片描述
    方式一:

    // 设置响应状态码 302 , 表示重定向, (已搬迁)
    resp.setStatus(302);
    // 设置响应头, 说明 新的地址在哪里
    resp.setHeader("Location", "http://localhost:8080");
    
    • 1
    • 2
    • 3
    • 4

    方式二:

    resp.sendRedirect("http://localhost:8080");
    
    • 1

    servlet3:

    package chongdingxiang;
    
    import javax.servlet.RequestDispatcher;
    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("/servlet3")
    public class servlet3 extends HttpServlet {
    
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String username=req.getParameter("username");
            System.out.println(("在Servlet3(柜台1)中查看参数(材料):"+username));
            this.getServletContext().setAttribute("globalKey", "hello servlet global");
            req.setAttribute("key3","柜台3的章");
    //        resp.sendRedirect("http://localhost:8080/servletdemo1/servlet4");
    
            resp.setStatus(HttpServletResponse.SC_FOUND);
            resp.setHeader("Location","http://localhost:8080/servletdemo1/servlet4");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    servlet4:

    package chongdingxiang;
    
    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("/servlet4")
    public class servlet4 extends HttpServlet {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String username = req.getParameter("username");
            System.out.println("在Servlet4(柜台4)中查看参数(材料):" + username);
            System.out.println(this.getServletContext().getAttribute("globalKey"));
    // 查看 柜台1 是否有盖章
            Object key1 = req.getAttribute("key3");
            System.out.println("柜台3是否有章:" + key1);
    // 处理自己的业务
            System.out.println("Servlet4 处理自己的业务 ");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
  • 相关阅读:
    python爬虫 Appium+mitmdump 京东商品
    【REGEXP】【正则的使用】【正则的使用】
    JavaScript期末大作业:基于HTML+CSS+JavaScript黑色的bootstrap响应式企业博客介绍模板
    kube-scheduler的调度上下文
    Windows桌面便笺 - 置顶任务TODO - 便利贴工具
    【Java八股文总结】之Java基础
    第六章 网络互连与互联网(二)
    如何在【逻辑回归】中优化控制正则化程度的超参数C
    打通“隔墙”!浅析低代码超强的整合能力
    mpvue小程序 vant组件单选
  • 原文地址:https://blog.csdn.net/quzhiyuan9/article/details/132864770