Servlet知识点学习笔记CG

目录

一、Servlet简介

二、Servlet API

三、Servlet生命周期

1. 初始化

2. 请求处理

3. 销毁

四、Servlet配置

五、Servlet的请求和响应

六、Servlet的线程安全

1. 什么是线程安全?

2. Servlet 如何保证线程安全?

3. 如何在 Servlet 中实现线程安全?

4. Servlet 线程安全示例

七、Servlet的过滤器

1. 过滤器的生命周期

2. 过滤器的配置

3. 过滤器的实现

八、Servlet的会话管理

1. 获取 HttpSession 对象

2. 向 HttpSession 对象中添加属性

 3. 从 HttpSession 对象中获取属性

 4. 使 HttpSession 失效

5.  设置 HttpSession 的最大不活动时间

 6. HttpSession 的示例

九、Servlet容器

1. 部署Servlet

2. Servlet生命周期

 3. Servlet配置

 4. Servlet上下文

十、Servlet监听器


Servlet 是JavaWeb中最基本的一种动态Web技术,它是运行在Web服务器的Java程序,用于处理客户端请求和生成响应。本篇文章将介绍Servlet所有知识点,并通过代码举例演示。

一、Servlet简介

Servlet是Java Web应用程序中的一种基于Java语言实现的服务器端组件,可以处理来自客户端的HTTP请求并生成响应。Servlet作为Web应用的一部分,它们通过请求-响应模型与客户端Web浏览器交互,动态生成Web内容。

二、Servlet API

Servlet API 是Java Servlet规范的实现,提供了Servlet需要用到的一切资源和接口。在Servlet API中,我们可以使用HttpServletRequest、HttpServletResponse等类,用于获取请求参数、处理响应等操作。

三、Servlet生命周期

Servlet生命周期包括三个阶段:初始化、请求处理和销毁。Servlet容器负责管理Servlet的生命周期,容器在需要Servlet服务的时候创建Servlet实例,并且对其进行初始化。一旦Servlet实例被创建,容器便可以将请求传递给Servlet,并调用它的service()方法来处理请求。在Servlet容器关闭时,容器会调用Servlet的destroy()方法进行资源释放。

1. 初始化

初始化是Servlet生命周期的第一阶段。在这个阶段中,Servlet容器会调用Servlet的init()方法。该方法在Servlet第一次被请求时被调用,以初始化Servlet并为处理请求做好准备。

下面是一个简单的Servlet的初始化方法的实现:

public void init(ServletConfig config) throws ServletException { 
    super.init(config); //初始化代码 
}

2. 请求处理

请求处理是Servlet生命周期的第二个阶段。在这个阶段中,Servlet容器会调用Servlet的service()方法,该方法用于处理客户端的请求。在service()方法中,Servlet容器会将请求和响应对象传递给Servlet。

下面是一个简单的Servlet请求处理的实现:

public void service(HttpServletRequest request, HttpServletResponse response) throws                     ServletException, IOException { 
    // 获取请求参数 
    String name = request.getParameter("name"); 
    // 处理业务逻辑 
    String message = "Hello, " + name; 
    // 将结果写入响应 
    response.getWriter().println(message); 
}

3. 销毁

销毁是Servlet生命周期的最后一个阶段。在这个阶段中,Servlet容器会调用Servlet的destroy()方法,以释放Servlet使用的资源和内存。

下面是一个简单的Servlet销毁方法的实现:

public void destroy() { 
    // 释放资源 
}
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class MyServlet extends HttpServlet {

    public void init() throws ServletException {
        // 初始化代码
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 处理 GET 请求
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 处理 POST 请求
    }

    public void destroy() {
        // 清理资源
    }
}

四、Servlet配置

Servlet 可以通过 web.xml 文件或注解来进行配置。web.xml 文件位于 WEB-INF 目录下,可以配置 Servlet 的 URL 映射、初始化参数等信息。注解可以在 Servlet 类上使用,例如 @WebServlet 注解可以指定 Servlet 的 URL 映射、初始化参数等信息。

下面是一个使用注解配置的示例代码:

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import javax.servlet.annotation.WebServlet;

@WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {

    public void init() throws ServletException {
        // 初始化代码
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 处理 GET 请求
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 处理 POST 请求
    }

    public void destroy() {
        // 清理资源
    }
}

Servlet 可以通过 web.xml 文件或注解来配置。以下是一个使用 web.xml 配置 Servlet 的示例:

<servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>com.example.MyServlet</servlet-class>
    <init-param>
        <param-name>myParam</param-name>
        <param-value>myValue</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/myservlet</url-pattern>
</servlet-mapping>

 上面的配置将一个名为 MyServlet 的 Servlet 映射到 /myservlet URL 上,并提供一个初始化参数 myParam=myValue。

以下是一个使用注解配置 Servlet 的示例:

@WebServlet(name = "MyServlet", urlPatterns = "/myservlet",
    initParams = { @WebInitParam(name = "myParam", value = "myValue") })
public class MyServlet extends HttpServlet {
    // Servlet 代码
}

上面的代码使用 @WebServlet 注解将一个名为 MyServlet 的 Servlet 映射到 /myservlet URL 上,并提供一个初始化参数 myParam=myValue。 

五、Servlet的请求和响应

Servlet 可以通过 HttpServletRequest 和 HttpServletResponse 对象来获取请求信息和生成响应。HttpServletRequest 包含了请求的 URL、参数、头部信息等内容。HttpServletResponse 可以设置响应的状态码、头部信息、正文等内容。

下面是一个简单的获取请求信息和生成响应的示例代码:

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class MyServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取参数
        String name = request.getParameter("name");
        
        // 设置响应类型
        response.setContentType("text/html");
        
        // 获取输出流
        PrintWriter out = response.getWriter();
        
        // 输出响应内容
        out.println("<html>");
        out.println("<head><title>Hello World</title></head>");
        out.println("<body>");
        out.println("<h1>Hello " + name + "</h1>");
        out.println("</body></html>");
    }
}

六、Servlet的线程安全

以下是关于 Servlet 线程安全的详细知识点、示例代码和注释:

1. 什么是线程安全?

线程安全是指在多线程环境下,程序能够正确地处理多个线程同时访问共享资源的情况,不会导致数据的不一致或出错。在 Servlet 中,由于多个线程可能同时访问同一个 Servlet 实例,因此需要考虑线程安全的问题。

2. Servlet 如何保证线程安全?

Servlet 容器通过以下两种方式来保证 Servlet 的线程安全:

  • 对于每个请求,Servlet 容器会创建一个新的线程来处理该请求,因此每个请求都有自己的线程,不会出现多个线程同时访问同一个 Servlet 实例的情况。
  • 如果在 Servlet 类中实现了 SingleThreadModel 接口,则容器将确保同一时间内只有一个线程执行 Servlet 实例的 service() 方法,从而避免多线程并发访问的问题。但是,该接口已被标记为不推荐使用,因为它可能导致性能问题。

3. 如何在 Servlet 中实现线程安全?

以下是在 Servlet 中实现线程安全的几种方法:

  • 避免使用实例变量,因为实例变量是共享的,可能会导致线程安全问题。可以将实例变量改为局部变量或方法参数来避免该问题。
  • 将共享资源加锁,以保证同一时间只有一个线程可以访问该资源。可以使用 synchronized 关键字来实现加锁,也可以使用 ReentrantLock 等锁机制。
  • 使用线程安全的数据结构,例如线程安全的集合类 ConcurrentHashMap、CopyOnWriteArrayList 等,可以避免自己实现锁的复杂性和可能的错误。

4. Servlet 线程安全示例

以下是一个简单的 Servlet 线程安全示例,该示例使用 synchronized 关键字来保证对共享资源的访问是线程安全的。

public class ThreadSafeServlet extends HttpServlet {
    private int count;

    public synchronized void incrementCount() {
        count++;
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        incrementCount();
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("Count: " + count);
        out.println("</body></html>");
    }
}

在上面的代码中,incrementCount() 方法是一个同步方法,使用 synchronized 关键字来保证同一时间只有一个线程可以执行该方法。doGet() 方法调用 incrementCount() 方法来增加计数器,由于 incrementCount() 方法是同步的,因此对 count 的访问是线程安全的。

当多个线程同时调用 doGet() 方法时,只有一个线程可以进入 incrementCount() 方法,其它线程必须等待锁的释放。这可以确保计数器 count 的自增操作是原子的,不会出现并发问题。

需要注意的是,虽然使用 synchronized 关键字可以保证线程安全,但它也可能会降低性能,因为每个线程都需要获得锁才能执行同步代码块。因此,如果不是必须使用 synchronized 关键字来保证线程安全,最好使用其他更高效的线程安全机制,例如使用线程安全的集合类。

七、Servlet的过滤器

Servlet 过滤器是一个 Java 类,用于在 Servlet 容器中拦截 HTTP 请求和响应,对它们进行处理或转换。下面是 Servlet 过滤器的一些重要知识点,以及一个简单的例子,该例子演示了如何使用过滤器来记录请求信息。

1. 过滤器的生命周期

过滤器的生命周期由 Servlet 容器管理,它包括以下三个阶段:

  • 初始化阶段:在过滤器实例化后,容器会调用其 init() 方法来进行初始化,这个方法只会在过滤器的生命周期中被调用一次。
  • 处理请求阶段:在处理每个请求之前,容器会调用过滤器的 doFilter() 方法,该方法对请求进行处理或转换。如果需要将请求传递给下一个过滤器或 Servlet,则需要调用 FilterChain 对象的 doFilter() 方法,否则请求将被截断。
  • 销毁阶段:当容器关闭 Web 应用程序时,会调用过滤器的 destroy() 方法来释放资源,这个方法只会在过滤器的生命周期中被调用一次。

2. 过滤器的配置

在 web.xml 文件中,可以使用 <filter> 元素来定义一个过滤器,使用 <filter-mapping> 元素来将过滤器映射到 Servlet 或 URL。以下是一个示例配置:

<filter>
  <filter-name>RequestLoggingFilter</filter-name>
  <filter-class>com.example.RequestLoggingFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>RequestLoggingFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

这个配置定义了一个名为 RequestLoggingFilter 的过滤器,它的实现类是 com.example.RequestLoggingFilter。然后将该过滤器映射到了所有的 URL 上。

3. 过滤器的实现

以下是一个简单的过滤器实现,它记录了每个请求的 IP 地址、时间戳、请求方法和请求 URL。

public class RequestLoggingFilter implements Filter {

    @Override
    public void init(FilterConfig config) throws ServletException {
        // 过滤器初始化
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String ip = req.getRemoteAddr();
        String url = req.getRequestURL().toString();
        String method = req.getMethod();
        long timestamp = System.currentTimeMillis();

        System.out.printf("[%d] %s %s %s\n", timestamp, ip, method, url);

        // 将请求传递给下一个过滤器或 Servlet
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // 过滤器销毁
    }
}

在这个实现中,init() 和 destroy() 方法都没有做任何操作。在 doFilter() 方法中,首先将 ServletRequest 强制转换为 HttpServletRequest,以便获取更多有关请求的信息。然后使用 getRemoteAddr() 方法获取请求的 IP 地址,使用 getRequestURL() 方法获取请求的 URL,使用 getMethod() 方法获取请求的方法(GET、POST 等),最后使用 System.currentTimeMillis() 方法获取当前时间戳,然后将这些信息输出到控制台中。这个过滤器的作用是记录请求信息,可以方便地进行调试和分析。

八、Servlet的会话管理

1. 获取 HttpSession 对象

在 Servlet 中,可以使用 HttpServletRequest 的 getSession() 方法来获取 HttpSession 对象。如果当前请求已经存在 HttpSession,则返回该 HttpSession;否则,创建一个新的 HttpSession 对象并返回。

HttpSession session = request.getSession();

2. 向 HttpSession 对象中添加属性

可以使用 HttpSession 的 setAttribute() 方法来向 HttpSession 对象中添加属性

session.setAttribute("name", "value");

 3. 从 HttpSession 对象中获取属性

可以使用 HttpSession 的 getAttribute() 方法从 HttpSession 对象中获取属性。

String value = (String) session.getAttribute("name");

 4. 使 HttpSession 失效

可以使用 HttpSession 的 invalidate() 方法使 HttpSession 失效。

session.invalidate();

5.  设置 HttpSession 的最大不活动时间

可以使用 HttpSession 的 setMaxInactiveInterval() 方法设置 HttpSession 的最大不活动时间。如果在指定的时间内没有活动, HttpSession 将被认为已过期并被销毁。

session.setMaxInactiveInterval(60 * 60); // 60 minutes

 6. HttpSession 的示例

以下是一个简单的 HttpSession 示例,该示例使用 HttpSession 对象来存储和检索用户的名称:

public class MyServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession();

        // 从 HttpSession 中获取用户的名称
        String name = (String) session.getAttribute("name");

        if (name == null) {
            // 如果用户的名称不存在,则显示一个表单来输入名称
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println("<html><body>");
            out.println("<form method='post'>");
            out.println("Name: <input type='text' name='name' /><br/>");
            out.println("<input type='submit' value='Submit' />");
            out.println("</form>");
            out.println("</body></html>");
        } else {
            // 如果用户的名称存在,则显示一个欢迎消息
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println("<html><body>");
            out.println("Welcome back, " + name + "!");
            out.println("</body></html>");
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession();

        // 从表单中获取用户输入的名称
        String name = request.getParameter("name");

        // 将用户的名称存储到 HttpSession 中
        session.setAttribute("name", name);

        // 显示一个欢迎消息
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("Welcome, " + name + "!");
        out.println("</body></html>");
    }
}

在上面的代码中,doGet() 方法检查 HttpSession 中是否存在名为 "name" 的属性。如果该属性不存在,则显示一个表单来输入名称;否则,显示一个欢迎消息。doPost() 方法将用户输入的名称存储到 HttpSession 中,并显示一个欢迎消息。

九、Servlet容器

Servlet容器是指用于运行Servlet的软件平台。常见的Servlet容器有Tomcat、Jetty、Resin等。下面是Servlet容器的一些常见知识点:

1. 部署Servlet

要在Servlet容器中部署Servlet,首先需要创建一个实现Servlet接口的Java类。然后,将这个Java类打包成一个WAR文件(Web Archive,即Web应用程序归档文件)。最后,将这个WAR文件上传到Servlet容器中,Servlet容器会自动解压缩WAR文件,并将其中的Servlet部署到服务器上。

2. Servlet生命周期

Servlet生命周期包括三个阶段:初始化、服务和销毁。在初始化阶段,Servlet容器会调用Servlet的init()方法,用于初始化Servlet的一些资源。在服务阶段,Servlet容器会调用Servlet的service()方法,用于处理客户端请求。在销毁阶段,Servlet容器会调用Servlet的destroy()方法,用于释放Servlet占用的资源。

下面是一个示例代码:

import javax.servlet.*;
import java.io.*;

public class HelloWorldServlet implements Servlet {
  private ServletConfig config;

  public void init(ServletConfig config) throws ServletException {
    this.config = config;
  }

  public ServletConfig getServletConfig() {
    return config;
  }

  public void service(ServletRequest request, ServletResponse response)
      throws ServletException, IOException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("<html>");
    out.println("<head>");
    out.println("<title>Hello World!</title>");
    out.println("</head>");
    out.println("<body>");
    out.println("<h1>Hello World!</h1>");
    out.println("</body>");
    out.println("</html>");
  }

  public String getServletInfo() {
    return "HelloWorldServlet";
  }

  public void destroy() {
    // Clean up any resources here
  }
}

 3. Servlet配置

Servlet配置可以使用web.xml文件或Servlet注解进行配置。web.xml是一个XML文件,位于Web应用程序的WEB-INF目录下。它包含了Web应用程序的配置信息,如Servlet配置、过滤器配置、URL映射等。下面是一个使用web.xml文件配置Servlet的示例代码:

<servlet>
  <servlet-name>HelloWorldServlet</servlet-name>
  <servlet-class>com.example.HelloWorldServlet</servlet-class>
  <init-param>
    <param-name>greeting</param-name>
    <param-value>Hello, World!</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>HelloWorldServlet</servlet-name>
  <url-pattern>/hello</url-pattern>
</servlet-mapping>

 4. Servlet上下文

Servlet上下文是指一个Web应用程序的环境。每个Web应用程序都有自己的Servlet上下文。Servlet上下文包含了Web应用程序的配置信息,如上下文路径、Servlet配置、过滤器配置等。可以使用ServletContext对象来访问Servlet上下文。ServletContext对象可以通过ServletConfig对象的getServletContext()方法获取。下面是一个使用ServletContext对象获取Web应用程序信息的示例代码:

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;

public class MyServlet extends HttpServlet {
  private ServletContext context;

  public void init(ServletConfig config) throws ServletException {
    super.init(config);
    context = config.getServletContext();
  }

  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    // 获取Web应用程序的名称
    String appName = context.getServletContextName();

    // 获取Web应用程序的上下文路径
    String contextPath = context.getContextPath();

    // 获取Web应用程序的真实路径
    String realPath = context.getRealPath("/");

    response.setContentType("text/html");
    response.getWriter().println("<html><body>");
    response.getWriter().println("<h2>Web应用程序信息</h2>");
    response.getWriter().println("<p>名称:" + appName + "</p>");
    response.getWriter().println("<p>上下文路径:" + contextPath + "</p>");
    response.getWriter().println("<p>真实路径:" + realPath + "</p>");
    response.getWriter().println("</body></html>");
  }
}

 在这个示例中,我们通过实现doGet()方法来获取Web应用程序的一些信息,比如名称、上下文路径和真实路径。在init()方法中,我们使用ServletConfig对象的getServletContext()方法获取ServletContext对象,以便在doGet()方法中使用。通过ServletContext对象,我们可以访问Web应用程序的配置信息,如上下文路径、Servlet配置、过滤器配置等。

十、Servlet监听器

Servlet监听器(Servlet Listener)用于监听Web应用程序中的事件,比如ServletContext、HttpSession、ServletRequest等对象的创建、销毁、属性修改等事件。Servlet监听器通常用于执行一些初始化或清理工作,或者在特定的事件发生时执行一些操作。下面是一个简单的示例代码,演示如何使用ServletContextListener监听器获取Web应用程序的上下文路径和名称。

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyServletContextListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
        // 获取ServletContext对象
        ServletContext context = event.getServletContext();
        // 获取Web应用程序的上下文路径和名称
        String contextPath = context.getContextPath();
        String contextName = context.getServletContextName();
        // 输出Web应用程序的上下文路径和名称
        System.out.println("Web应用程序的上下文路径:" + contextPath);
        System.out.println("Web应用程序的名称:" + contextName);
    }

    public void contextDestroyed(ServletContextEvent event) {
        // 在Web应用程序销毁时执行一些清理工作
    }
}

在这个示例中,我们实现了ServletContextListener接口,并重写了contextInitialized()和contextDestroyed()方法。在contextInitialized()方法中,我们通过ServletContextEvent对象获取ServletContext对象,并使用它获取Web应用程序的上下文路径和名称。在contextDestroyed()方法中,我们可以执行一些清理工作。需要注意的是,当Web应用程序启动时,容器会自动创建并初始化ServletContextListener实例,并调用其contextInitialized()方法;当Web应用程序关闭时,容器会调用所有已注册的ServletContextListener实例的contextDestroyed()方法。因此,我们需要在web.xml文件中将这个监听器注册为一个ServletContextListener,如下所示:

<listener>
    <listener-class>MyServletContextListener</listener-class>
</listener>

这样,当Web应用程序启动时,容器会自动创建并初始化MyServletContextListener实例,并在contextInitialized()方法中输出Web应用程序的上下文路径和名称。

猜你喜欢

转载自blog.csdn.net/m0_62110645/article/details/129915402