A pleasant journey to Servlet - 20,000 words explaining Servlet in detail


1. Getting to know Servlet first

1.1 What are Servlets

Servlet is a server-side program written in Java, which is used to process the request sent by the client (usually a browser) and return a response to the client . It is part of the Java EE specification and provides a way to dynamically generate content on the server.

Servlet is implemented based on Java, so it is cross-platform and can run on different operating systems. It follows the safety and reliability of Java, and can also take full advantage of the advantages of the Java language, such as object-oriented programming and rich class libraries.

Servlets are mainly used to develop web applications, such as websites, web services, web application backends, etc. When the Tomcat container receives the request, it will pass it to the corresponding Servlet class for processing . At the same time, Servlet can dynamically generate HTML, XML, JSON and other content according to request parameters, session state, database query, etc., and then send the response to the client.

All in all, Servlet is a technology for realizing dynamic pages, and it is a set of APIs provided by Tomcat to developers to help developers develop Web programs simply and efficiently.

1.2 The main work of Servlet

Servlet is mainly responsible for the following tasks in Java Web development:

  1. Register the Servlet class and handle HTTP requests:

    • Servlets allow programmers to register a Java class and execute code in that class when Tomcat (or other Java Servlet containers) receive specific HTTP requests. web.xmlAssociate a servlet with a specific URLor by configuring the servlet mapping in the file or using annotations URL.
    • When a client sends a matching HTTP request, the Servlet container will instantiate and invoke the corresponding Servlet to handle the request. Developers can write business logic in Servlet, obtain parameters from requests, perform database operations, generate dynamic content, etc., and generate HTTP responses to return to the client.
  2. Parse the HTTP request:

    • Servlet helps programmers parse HTTP requests, and parses the HTTP request sent by the client from a string into an HttpRequestobject. HttpRequestThe object provides various methods, enabling developers to easily obtain HTTP request methods (GET, POST, etc.), request headers, request parameters, session information, etc.
  3. Construct the HTTP response:

    • Servlet helps programmers to construct HTTP response, so that developers only need to set HttpResponsethe attribute field of the specified object, Servlet will automatically construct an HTTP response string according to the HTTP protocol, and write it back to the client through Socket.
    • HttpResponseThe object provides methods for setting response status code, response header, response content, etc. Developers can set according to business needs, and the Servlet will return the set response information to the client.

In general, Servlet, as a Java server-side technology, helps developers process HTTP requests and responses, allows registration and execution of specific Java classes, parses HTTP requests, and constructs HTTP responses based on set HttpResponseobjects. This enables Java developers to easily develop dynamic, interactive Web applications.

1.3 Relationship between Servlet and Tomcat

There is a close relationship between Servlet and Tomcat. It can be said that they are an inseparable combination . The following is an explanation of the relationship between them:

  1. Tomcat is the container of Servlet, which provides the execution environment and support of Servlet, so that Servlet can run on Tomcat server .
  2. When a Web application is deployed on Tomcat, Tomcat will be responsible for loading and initializing the Servlet object, and when receiving an HTTP request, call the corresponding Servlet object to process the request and generate a response .
  3. Tomcat also provides the function of managing and monitoring Web applications. You can manage deployed Servlets and Web applications through Tomcat's management interface.

To sum up, Servlet is a server-side program written in Java, and Tomcat is a container that can execute and manage Servlet. Together, they form the infrastructure for Java Web applications, enabling developers to build dynamic, interactive Web applications.

Second, the first Servlet program

2.1 Create a Maven project

What is Maven:

Maven projects are Java projects based on the Apache Maven build tool. Maven is a popular project management and build tool designed to simplify and standardize the build process for Java projects . With Maven, developers can more easily manage project dependencies, build projects, run unit tests, generate project documentation, and more.

A typical Maven project usually includes the following important parts:

  1. pom,xmlFile : pom.xmlIt is the core configuration file of the Maven project, which is located in the root directory of the project. pom.xmlThe file is used to describe the project's metadata information (such as the project's name, version, description, etc.), define the project's dependencies (required third-party libraries and plug-ins), configure the project's build process (compile, package, etc.), and Other project related configuration.

  2. srcDirectory : This directory is the root directory for the project's source code and resource files . Usually contains two subdirectories:

    • src/main: contains the main source code and resource files;
    • src/test: Contains unit test code and resources.
  3. targetDirectory : This directory is the output directory generated by the Maven build, which contains the output files generated by the built project , such as compiled class files, packaged JARfiles, and WARdocumentation.

  4. Maven lifecycle and plugins : Maven defines a standard set of lifecycles and plugins for performing different tasks during the build process. Developers can pom.xmldefine the tasks performed by the project at different construction stages through configuration files, such as compilation, testing, packaging, deployment, etc.

Use IDEA to create a Maven project:

  1. Create a new project in IDEA, Build Systemselect Maven in the options, and pay attention to the project path without Chinese or other special symbols.

  1. The following interface appears, indicating that the creation is successful

2.2 Introducing dependencies

When the Maven project is created, a pom.xmlfile will be automatically generated, and we need to pom.xmlintroduce the package that the Servlet API depends on in the file JAR.

  1. Search in the central warehouse (https://mvnrepository.com)servlet , usually the first result is the API we need.


2. Select the version, here I choose 3.1.0the version.

Regarding the matching of Servlet and Tomcat versions:

  1. Maven xmlCopy-paste the one provided by the central repository pom.xmlinto the file


Note that to add a new dependencieslabel, copy it into this label:

2.3 Create directory

After creating the Maven project, IDEA will automatically generate the following directory structure for us:

In these directories:

  • srcIndicates the directory where the source code is located;
  • main/javaIndicates the root directory of the source code, and the subsequent created .javafiles will be placed in this directory;
  • main/resourcesIndicates the directory where some resource files of the project are located;
  • test/javaIndicates the root directory of the test code.

有了这些目录还不够,我们还需要创建以下新的目录和文件。

1. Create webappdirectory

Under mainthe directory, create a directory javaparallel to the directory , which is used to store the web resources of the web application, such as HTML pages, JSP files, CSS styles, JavaScript scripts, etc.webapp

2. Create WEB-INFa directory
Under webappthe directory, create a WEB-INFdirectory named . This directory is a special directory in the web application that holds the configuration and protected resources of the web application .

3. Create web.xmlthe file

In WEB-INFthe directory, create a web.xmlfile named , which is the deployment descriptor of the Java Web application, and is used to configure Web components such as Servlet, Filter, Listener, and other application-related configuration information .

4. Write web.xmlthe document

Copy the following code into web.xmlthe file:

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>

2.4 Writing code

javaCreate a class in the directory HelloServletwith the following code:

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // super.doGet(req, resp);
        System.out.println("hello world");
        resp.getWriter().write("hello world");
    }
}

Explanation of this code:

  • Create a class that inherits HttpServletfrom HelloServlet;
  • Annotations added above this class @WebServlet("/hello")are used to specify the Servlet URLmapping . In this example, the Servlet will be mapped to URLthe path as and will be invoked /hellowhen the client initiates /helloan HTTP request to .HelloServlet
  • doGetThe overridden methoddoGet has two parameters, which respectively represent the received HTTP request and the HTTP response to be constructed. This method will be GETtriggered to be automatically called by Tomcat when Tomcat receives a request .
  • HttpServletRequestRepresents an HTTP request. Tomcat converts the request in string format into an HttpServletRequestobject according to the format of the HTTP request . The subsequent information in the request (such as method, url, header, bodyetc.) is obtained through this object.
  • HttpServletResponseTo represent an HTTP response, the programmer needs to construct this object in the code (such as constructing the status code of the response, header, bodyetc.).
  • resp.getWriter()A character stream object will be obtained Writer, and some data can be written through this stream object , and the written data will be constructed as bodypart of an HTTP response, Tomcat will convert the entire response into a string, and socketwrite it back to the client through .

Although these few lines of code are few, they contain a lot of information:

  1. In the code of the Servlet program, there is no need to write mainthe method as the entry point of the program, because mainthe method is already included in Tomcat, and the code we write will be called by Tomcat when appropriate .
  2. The code we write is not a complete program, but a small part of the logic of the Tomcat program. If you want to be called by Tomcat correctly at the right time, you need to meet the following three conditions: 1) The created class needs to inherit
    from HttpServletclass;
    2) This class needs to use @WebServletannotations to associate an HTTP path;
    3) This class needs to implement doXXXthe method.

2.5 Packager

  1. You can use Maven for packaging in IDEA. Generally, you can see the Maven window on the right side of IDEA. If you can’t see it, you can View -> View -> Tool Window -> Mavenopen it with .

  1. Expand Lifecycleand packagedouble-click to package

When the following information appears, it means that the packaging is successful:

After the packaging is successful, you can see that a package targetis generated under the directory :JAR

However, such JARa package is not what we need, what Tomcat needs to recognize is another WARform of package. And the name of this package is too complicated, we hope to have a simple name.

  1. Modify pom.xmlthe configuration file to generate WARthe package and modify WARthe package name

  • pom.xmlAdd a new tag in , packingindicating that the packaging method is to pack a WARpackage;
  • Add another buildtag, and a built-in finalNametag, indicating that the name of the output WARpackage is hello_servlet.
  1. Re-use Maven for packaging

2.6 Deployment procedure

WARCopy the package file formed by the above packaging to webappsthe directory of Tomcat:

run Tomcat, it will be automatically decompressed, and the deployment is completed at this time.

2.7 Verification procedure

At this point, when you visit through a browser http://127.0.0.1:8080/hello_servlet/hello, you can see the following results:

At this point, our first Servlet program has been completed. If you see this, you will also believe that this is the most troublesome hello worldprogram to learn so far.

3. Smart Tomcat deployment program

The above process of manually packaging and then copying to Tomcat seems very cumbersome, but IDEA provides us with a more convenient plug-in for packaging and deploying programs. The "Smart Tomcat" plugin was developed to simplify and improve the experience of using Apache Tomcat in IntelliJ IDEA. Using the "Smart Tomcat" plug-in, you can configure and manage the Tomcat server more conveniently, and easily deploy and debug Java Web applications.

3.1 Install the Smart Tomcat plugin

Open on IDEA: File -> Settings -> plugins, then search for Smart Tomcat, and restart IDEA according to the instructions.

3.2 Configuring the Smart Tomcat plug-in

  1. Click "Current File" in the upper right corner of IDEA

  1. Then click "Edit Configurations"

  1. Click "Add new run configurations"

  1. Select "Smart Tomcat"

  1. Then configure as follows

  1. When the configuration is complete, we will find that the initial "Current File" position has changed to "run", and then click the green triangle next to it to automatically run Tomcat and deploy our program.
  2. run


At this point, the Tomcat log will be output in the console of IDEA, and there will be no garbled characters.

  1. access server

4. Reasons for access errors

4.1 404 appears

404 indicates that the resource accessed by the user does not exist, and the path of is most likely URLwritten incorrectly.

Error example 1: The "Context Path" is omitted, and the server is directly accessed through "/hello"

Error example 2: "Servlet Path" is omitted, and the server is directly accessed through "/hello_servlet"

4.2 405 appears

405 means that the corresponding HTTP request method is not implemented.

For example, now comment out the HelloServletoverridden doGetmethod in the class, then restart Tomcat to access the server again

4.3 500 appears

The reason for 500 is often caused by an exception thrown in the Servlet code.

For example, modify the method HelloServletin doGetas follows, then restart Tomcat and access the server.

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
    String s = null;
    resp.getWriter().write(s);
}


At this time, a null pointer exception occurs, indicating that the server has an internal error, so the returned response code is 500.

4.4 "This website cannot be accessed" appears

This situation usually means that Tomcat has not been started or the Tomcat server failed to start.

For example, when the "Servlet Path" is written incorrectly, it will fail to start the Tomcat server.

At this point, when Tomcat is started, an error will occur:


"This website cannot be reached" when accessing the server

Five, Servlet operating principle and life cycle

5.1 Operating principle

Servlets are components in Java that handle web requests and responses. It runs inside the web server and manages its lifecycle and request scheduling through a web container such as Apache Tomcat.

The main principles of Servlet operation are as follows:

  1. Web container initialization : When the Web server starts, the Web container loads and initializes the Servlet. During initialization, the Web container creates a Servlet instance and invokes its init()methods. In this method, the Servlet can perform some initialization operations, such as loading configuration information, establishing a database connection, and so on.

  2. Receive HTTP requestsURL : Web HTTP` requests when a user visits one in a browser 服务器接收到.

  3. Request distribution : The Web container determines which Servlet should handle the request based on the request's URLand the configuration information in the deployment descriptor ( ).web.xml

  4. Invoking the Servlet's service()method : Once it has determined which servlet is to handle the request, the web container invokes the method on the servlet instance service(), passing it the request and response objects as parameters.

  5. Servlet processing request : In service()the method, the Servlet executes the corresponding logic according to the HTTP request type (GET, POST, PUT, etc.), processes the request and generates a response.

  6. Return HTTP response : After processing the request, the servlet will write the generated HTTP response back to the response object.

  7. Destroy : When the Web server is shut down or the Servlet is no longer needed, the Web container will call the Servlet's destroy()method to give it a chance to release and clean up some resources.

5.2 Life cycle

The life cycle of Servlet mainly includes the following three stages:

  1. Initialization (Initialization) :

    • When the servlet container starts, it reads the deployment descriptor ( web.xmlor annotation configuration) and loads the servlet class.
    • Create a Servlet instance and call its init(ServletConfig config)method to initialize.
    • init()The method will only be called once when the Servlet is loaded for the first time , and is used to perform some initialization operations, such as loading configuration information, establishing a database connection, and so on.
  2. Request Handling :

    • Once a servlet is initialized, it is in a serviceable state and can handle client requests.
    • When the client sends a request to the server and matches the Servlet to process the request, the Servlet container will call the method on the same Servlet instance service(ServletRequest request, ServletResponse response).
    • service()The method calls the corresponding doXXX()method (for example doGet(), , doPost()etc. ) according to the request type (GET, POST, PUT, doPut()etc.) to process the request.
  3. Destruction :

    • When the Servlet container is closed or the Servlet is no longer needed, it will destroy the Servlet instance.
    • Before being destroyed, the Servlet container will call destroy()the methods of the Servlet to perform some resource release and cleanup operations.
    • destroy()The method will only be called once before the Servlet is unloaded, and is used to perform some aftermath work, such as closing the database connection, releasing resources, and so on.

The entire Servlet life cycle is shown in the following figure:

Notice:

  • The Servlet container is responsible for managing the life cycle of the Servlet, and developers do not need to manually create and destroy Servlet instances.
  • A Servlet may be instantiated multiple times throughout its lifetime, but init()the and destroy()methods are only called once.
  • During request processing, each request will call the method on a separate thread service(), and multiple requests can access the same Servlet instance concurrently, so developers should ensure the thread safety of Servlet.

6. Servlet API

Servlet API is a collection of interfaces and classes used to develop Java Servlet programs. It provides a standardized way to handle Web requests and responses , enabling developers to write Java-based Web applications.

The Servlet API is in the Java EE specification, and developers can learn the details of these interfaces and classes through the Java Servlet specification. In Java, the Servlet API usually consists of javax.servletpackages and javax.servlet.httpthe classes and interfaces within the package .

The following are some core classes and interfaces in the Servlet API and their brief descriptions:

class/interface illustrate
javax.servlet.Servlet Servlet interface, all Servlet classes must implement this interface.
javax.servlet.GenericServlet The Servlet abstract class implements most of the methods of the Servlet interface.
javax.servlet.http.HttpServlet The HttpServlet class is used to handle HTTP-related requests and responses.
javax.servlet.ServletConfig Interface, used to obtain the initialization parameters of the Servlet.
javax.servlet.ServletContext Interfaces for sharing information throughout a web application.
javax.servlet.ServletException Exception class, the base class for exceptions that may be thrown by a servlet.
javax.servlet.ServletRequest Interface, used to represent the object requested by the client.
javax.servlet.ServletResponse Interface, used to represent the response object of the Servlet.
javax.servlet.http.HttpServletRequest An interface representing HTTP requests, extended from ServletRequest.
javax.servlet.http.HttpServletResponse An interface representing an HTTP response, extended from ServletResponse.
javax.servlet.http.HttpSession Interface for maintaining state between client and server.
javax.servlet.RequestDispatcher Interface for forwarding requests to other resources (Servlets, JSPs, etc.).
javax.servlet.Filter Filter interface for performing filtering operations between requests and responses.
javax.servlet.FilterChain Filter chains for passing requests and responses between multiple filters.

6.1 HttpServlet class

HttpServletIs an abstract class in the Java Servlet API that extends GenericServletthe class and provides more convenient methods for handling requests and responses based on the HTTP protocol. HttpServletIs a common base class for writing HTTP-based Servlets .

The following are HttpServletcommonly used methods in the class:

method illustrate
void init(ServletConfig config) Called immediately after the Servlet instance is created to initialize the Servlet.
void destroy() Called when the Servlet container shuts down normally to release resources and cleanup operations.
void doGet(HttpServletRequest request, HttpServletResponse response) Handles HTTP GET requests.
void doPost(HttpServletRequest request, HttpServletResponse response) Handles HTTP POST requests.
void doPut(HttpServletRequest request, HttpServletResponse response) Handles HTTP PUT requests.
void doDelete(HttpServletRequest request, HttpServletResponse response) Handles HTTP DELETE requests.
void service(HttpServletRequest request, HttpServletResponse response) According to the HTTP method of the request, call the corresponding doXXX method for processing.
ServletConfig getServletConfig() Get the configuration information of the current Servlet.
String getServletInfo() Get the description information of Servlet.
String getInitParameter(String name) Gets the initialization parameter value for the specified name.
Enumeration<String> getInitParameterNames() Get an enumeration of all initialization parameter names.
ServletContext getServletContext() Get the Servlet context object, which is used to access the information of the Servlet environment.
String getServletName() Get the name of the servlet.
void log(String msg) Log messages to the Servlet container's logging system.
void log(String msg, Throwable throwable) Record exception information to the log system of the Servlet container.
void setInitParameter(String name, String value) Set the value of the initialization parameter.
boolean isAsyncSupported() Checks if the servlet supports asynchronous processing.
void startAsync() Start asynchronous processing.
void startAsync(ServletRequest request, ServletResponse response) Starts asynchronous processing with the specified request and response.

Here are HttpServletsome important characteristics of the class:

  1. Inheritance relationship : HttpServletInherited from GenericServlet, so it has GenericServletsome common features in , but it is specialized in handling HTTP requests and responses.

  2. Provide HTTP request processing methods : HttpServletProvide processing methods for different HTTP request methods (GET, POST, PUT, DELETE, etc.), these methods can be rewritten by subclasses to handle specific request types.

  3. 默认实现HttpServlet 中这些 HTTP 请求处理方法默认实现是返回 HTTP 状态码 405(Method Not Allowed),表示不支持对应的请求方法。因此,子类需要根据需要重写这些方法以提供自定义的请求处理逻辑

  4. 获取请求信息HttpServletRequest 参数提供了访问客户端 HTTP 请求信息的方法,如获取请求 URL、请求参数、请求头、会话信息等。

  5. 设置响应信息HttpServletResponse 参数提供了设置 HTTP 响应内容、响应状态码、响应头等的方法。

由于 HttpServlet 是一个抽象类,不能直接实例化,开发者需要编写具体的子类来继承 HttpServlet,然后实现相应的请求处理方法,根据业务逻辑处理不同类型的 HTTP 请求,并生成相应的 HTTP 响应

6.2 HttpServletRequest 接口

HttpServletRequest 是Java Servlet API 中的一个接口,用于表示客户端发起的 HTTP 请求。它提供了访问客户端请求信息的方法,开发者可以通过该接口获取请求的各种属性、参数、头信息等。该接口继承自 ServletRequest接口,专门用于处理 HTTP 请求。

6.2.1 核心方法

以下是一些常用的 HttpServletRequest 接口的方法:

1. 获取请求信息

方法 说明
String getMethod() 获取 HTTP 请求方法,例如 GET、POST、PUT 等。
String getRequestURI() 获取请求的 URI(Uniform Resource Identifier)部分,即去除协议、主机、端口号后的路径部分。
String getQueryString() 获取请求的查询字符串,即 URL 中 “?” 后面的部分。
String getProtocol() 获取请求使用的协议,如 “HTTP/1.1”。
String getContextPath() 获取应用程序的上下文路径(Context Path),即应用程序的根路径。

2. 获取请求参数

方法 说明
String getParameter(String name) 获取指定名称的请求参数值。
Enumeration<String> getParameterNames() 获取所有请求参数名称的枚举。
String[] getParameterValues(String name) 获取指定名称的请求参数值数组,用于处理同名参数。

3. 获取请求头信息

方法 说明
String getHeader(String name) 获取指定名称的请求头信息。
Enumeration<String> getHeaderNames() 获取所有请求头名称的枚举。

4. 获取会话信息

方法 说明
HttpSession getSession() 获取与该请求关联的 HttpSession 对象,如果没有会话,则创建一个新的会话。
HttpSession getSession(boolean create) 根据指定的 create 参数决定是否创建新的会话。true代表创建,false代表不创建。

5. 获取客户端信息

方法 说明
String getRemoteAddr() 获取客户端的 IP 地址。
String getRemoteHost() 获取客户端的主机名。
int getRemotePort() 获取客户端连接的端口号。

6. 其他常用方法

方法 说明
Cookie[] getCookies() 获取客户端发送的所有 Cookie。
Locale getLocale() 获取客户端的首选语言环境。
Enumeration<Locale> getLocales() 获取客户端支持的所有语言环境的枚举。

通过使用 HttpServletRequest 接口提供的这些方法,开发者可以在 Servlet 中获取请求的各种信息,从而更好地处理和响应客户端的请求。

6.2.2 获取请求信息

创建一个 ShowHeaderServlet 类, 用于获取请求信息并返回响应。它可以响应 HTTP GET 请求,并将请求的一些信息以及请求头信息返回到客户端。

@WebServlet("/show")
public class ShowHeaderServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        resp.setContentType("text/html; charset=utf8");
        StringBuilder respBody = new StringBuilder();
        respBody.append(req.getProtocol());
        respBody.append("<br>");
        respBody.append(req.getMethod());
        respBody.append("<br>");
        respBody.append(req.getRequestURL());
        respBody.append("<br>");
        respBody.append(req.getContextPath());
        respBody.append("<br>");
        respBody.append(req.getQueryString());
        respBody.append("<br>");

        respBody.append("<h3> headers: <h3>");
        Enumeration<String> headerNames = req.getHeaderNames();
        while (headerNames.hasMoreElements()){
    
    
            String headerName = headerNames.nextElement();
            respBody.append(headerName).append(": ").append(req.getHeader(headerName));
            respBody.append("<br>");
        }

        resp.getWriter().write(respBody.toString());
    }
}

访问服务器,可以发现响应内容如下:

6.2.3 获取 GET 请求中的参数

创建一个 GetParameterServlet 类用于获取 GET 请求中的参数。

GET 方法的查询字符串说明:

  • 在 HTTP 请求中,GET 方法通过将参数附加到 URL 的查询字符串(Query String)部分来传递数据查询字符串是在 URL 的问号(?)后面的部分,用于向服务器传递键值对参数。它的格式通常为: http://example.com/path/to/resource?key1=value1&key2=value2&key3=value3...

代码如下:

@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 期待收到的请求:http://localhost:8080/hello_servlet/getParameter?studentId=10&classId=20
        resp.setContentType("text/html; charset=utf8");

        String studentId = req.getParameter("studentId");
        String classId = req.getParameter("classId");
        resp.getWriter().write("studentId: " + studentId + ", classId: " + classId);
    }
}

访问服务器结果:

6.2.4 通过 form 表单获取 POST 请求中的参数

1. 首先约定前后端的交互接口

POST /postParameter

2. 前端创建页面testPost.html,里面创建一个 form 表单

    <form action="postParameter" method="post">
        <input type="text" name="studentId">
        <input type="text" name="classId">
        <input type="submit" value="提交">
    </form>

3. 后端创建一个 PostParameterServlet 类,用于接收 form表单提交的数据

@WebServlet("/postParameter")
public class PostParameterServlet extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        resp.setContentType("text/html; charset=utf8");

        String studentId = req.getParameter("studentId");
        String classId = req.getParameter("classId");
        resp.getWriter().write("studentId: " + studentId + ", classId: " + classId);
    }
}

4. 访问服务器页面,然后提交参数


5. 提交数据后会自动跳转至响应页面

6. 通过 Fiddler工具抓包,可以发现通过 POST 方法传递的参数在 body

6.2.5 通过 JSON 获取 POST 请求中的参数

1. 约定前后端交互接口

POST /jsonPostParameter

2. 后端获取 body 并通过 Jackson 解析 JSON 字符串

在Java代码中,需要引入 Jackson 这个库,完成对 JSON 的解析工作:

  1. 在中央仓库中搜索 jackson,选择 “JackSon Databind”:
  2. 把中央仓库中的依赖拷贝到 pom.xml文件中,形如:

创建一个JsonPostServlet 类:

class Student {
    
    
    public String studentId;
    public String classId;
}

@WebServlet("/jsonPostParameter")
public class JsonPostParameterServlet extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        ObjectMapper objectMapper = new ObjectMapper();
        Student student = objectMapper.readValue(req.getInputStream(), Student.class);
        resp.getWriter().write("studentId: " + student.studentId + ", classId: " + student.classId);
    }
}

其中,Student类用于储存 JSON 解析出来的数据。

3. 启动服务器,然后通过 Postman 工具发送 JSON 格式的数据


4. 服务器响应内容

6.3 HttpServletResponse 接口

HttpServletResponse 也是 Java Servlet API 中的一个接口,它表示用于发送 HTTP 响应给客户端的对象。通过这个接口,Servlet 可以设置响应的内容、响应头、状态码等,以便向客户端发送适当的响应。

6.3.1 核心方法

下面是 HttpServletResponse 接口的核心方法及其说明:

1. 设置响应头和状态码

方法 说明
void setStatus(int sc) 设置响应的状态码。
void setStatus(int sc, String sm) 设置响应的状态码和描述信息。
int getStatus() 获取响应的状态码。
String getHeader(String name) 获取指定名称的响应头的值。
Collection<String> getHeaderNames() 获取所有响应头名称的集合。
Collection<String> getHeaders(String name) 获取指定名称的响应头的所有值的集合。
void setHeader(String name, String value) 设置指定名称的响应头的值。
void addHeader(String name, String value) 添加指定名称的响应头的值(可以多次调用)。
void setIntHeader(String name, int value) 设置指定名称的整数响应头的值。
void addIntHeader(String name, int value) 添加指定名称的整数响应头的值(可以多次调用)。

2. 设置响应内容

方法 说明
PrintWriter getWriter() 获取用于发送字符文本的 PrintWriter 对象。
ServletOutputStream getOutputStream() 获取用于发送二进制数据的 ServletOutputStream 对象。
void setContentLength(int len) 设置响应内容的长度。
void setContentType(String type) 设置响应内容的 MIME 类型。
String getContentType() 获取响应内容的 MIME 类型。
void setCharacterEncoding(String charset) 设置响应内容的字符编码。

3. 缓存控制

方法 说明
void setDateHeader(String name, long date) 设置指定名称的日期型响应头的值。
void addDateHeader(String name, long date) 添加指定名称的日期型响应头的值(可以多次调用)。
void setExpires(long expires) 设置响应的过期时间。
void addCookie(Cookie cookie) 添加一个 Cookie 到响应中。

4. 重定向和错误处理

方法 说明
void sendRedirect(String location) 重定向到另一个 URL
void sendError(int sc) 发送一个错误状态码。
void sendError(int sc, String msg) 发送一个错误状态码和描述信息。
void reset() 重置响应对象,清除所有设置的响应数据。

5. 其他方法

方法 说明
void setBufferSize(int size) 设置响应缓冲区的大小。
int getBufferSize() 获取响应缓冲区的大小。
void flushBuffer() 强制将缓冲区中的数据发送到客户端。
boolean isCommitted() 检查是否已经提交响应。
void resetBuffer() 重置响应缓冲区。
void setLocale(Locale loc) 设置响应内容的区域设置。

这些方法提供了处理 Servlet 响应的各种操作和设置,开发人员可以根据需要使用这些方法来构建定制化的 HTTP 响应。

6.3.2 设置状态码

创建一个 StutasServlet类,用于接收一个状态码参数,然后在响应中设置该状态码:

@WebServlet("/status")
public class StatusServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 期待收到请求:http://localhost:8080/hello_servlet/status?status=200
        String statusStr = req.getParameter("status");
        int status = Integer.parseInt(statusStr);
        resp.setStatus(status);
        resp.getWriter().write("status: " + status);
    }
}


通过 Fiddler 工具抓包查看设置的响应状态码:

6.3.3 设置自动刷新

创建一个 AutoRefreshServlet 类,当浏览器访问时会每隔一秒自动刷新一次页面,并显示当前的时间戳。

@WebServlet("/autoRefresh")
public class AutoRefreshServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        resp.setHeader("refresh", String.valueOf(1));
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        resp.getWriter().write("timestamp: " + timestamp.toString());
    }
}

其中,通过 HTTP 响应报头中的 Refresh 字段,可以控制浏览器自动刷新的时机。

6.3.4 设置重定向

创建一个RedirectServlet类,返回一个重定向 HTTP 请求,自动跳转到另一个页面。

@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        resp.sendRedirect("https://csdn.net");
    }
}

启动程序,通过 URL: http://localhost:8080/hello_servlet/redirect访问,可以看到页面自动跳转到 CSDN 主页了。

通过 Fiddler 抓包可以看到,响应设置了 302 重定向状态码,重定向的位置就是 https://csdn.net

七、Cookie 和 Session

7.1 什么是 Cookie 和 Session

Cookie:

  • Cookie 是一种在客户端(浏览器)存储小型数据的机制,以便在客户端和服务器之间传递数据。
  • 服务器可以在 HTTP 响应头中通过 Set-Cookie 标头发送一个或多个 Cookie 到客户端,客户端会将这些 Cookie 存储在本地。
  • 之后,当客户端再次请求同一个服务器,它会将之前存储的 Cookie 自动包含在请求头中的 Cookie 标头内,从而将相关数据传递给服务器。

Session:

  • Session 是一种服务器端存储数据的机制,用于跟踪用户在网站上的状态和活动
  • 当用户首次访问网站时,服务器会为每个用户创建一个唯一的会话标识(通常是一个长随机字符串),并将其存储在 Cookie 中,发送到客户端。
  • 之后,客户端的每个请求都会自动包含会话标识,服务器通过会话标识识别用户,并在服务器端的会话存储中保存用户的状态和数据

7.2 深入理解会话机制

服务器在同一时刻一般都会收到很多请求,因此就需要区分清楚哪一个请求是属于哪一个用户(客户端)的,所有就要求服务器与每一个用户都维持一个会话,并且这个会话中包含了这个用户的唯一标识以及与用户信息的对应关系

因此,会话的本质就是一个 “哈希表”,其中的key就是对用户的唯一标识(sessionId),value就是客户端信息(可以根据需求灵活设置)。

  • sessionId 是由服务器生成的一个 “唯一性字符串”,用来唯一标识用户的身份信息。
  • 从 Session 机制的角度来看,这个唯一性字符串称为 sessionId,但是站在整个登录流程中看待,也可以把这个唯一性字符串称为 token
  • sessionIdtoken 可以理解成是同一个东西在不同视角的不同叫法。
  • 例如:

服务端与客户端维持会话的基本流程:

  1. 当用户登录的时候,服务器会在 Session 中新增一条新的记录,并把生成的 sessionId 通过 Set-Cookie字段返回给客户端,然后将其保存在浏览器中。
  2. 客户端后续再向服务端发起请求的时候,都会在请求中将 Cookie 中的 sessionId 通过 Cookie 字段发送给服务器。
  3. 服务器在收到用户请求后,会根据请求中的 sessionId 在 Session 中找到与这个用户对应的用户信息,维持与该用户的会话,并处理请求任务。

另外,Servlet 中的 Session 默认是保存到内存中的,那么就意味着:如果重启服务器则 Session 数据就会消失。为了避免这个问题,可以使用其他方式存储 Session 数据,如数据库或分布式缓存。

7.3 实现用户登录案例

在用户登录案例中,通常的流程如下:

  1. 用户在登录页面输入用户名和密码,点击登录按钮提交表单。
  2. 服务器接收表单提交的数据,验证用户身份。
  3. 如果验证成功,服务器创建一个 Session,将用户信息存储在其中,并生成一个会话标识(Session ID)。
  4. 服务器通过 Set-Cookie 响应头将会话标识发送给客户端,存储在客户端的 Cookie 中。
  5. 客户端在后续的每个请求中自动包含会话标识的 Cookie,以便服务器识别用户。
  6. 服务器通过会话标识从会话存储中取出用户信息,识别用户身份,实现用户的登录状态。

以下是简单的登录案例:

这个代码中主要是通过 HttpSession 类完成,并不需要我们手动操作 Cookie 对象。

  1. 创建 LoginServlet 类,用于实现登录逻辑。
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        req.setCharacterEncoding("utf8");
        resp.setContentType("text/html; charset=utf8");

        // 1. 获取输入的用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        // 2. 判断用户名和密码是否合法
        if(!username.equals("admin") || !password.equals("123456")){
    
    
            resp.getWriter().write("用户名或密码错误!");
            return;
        }

        // 3. 登录成功,设置 Session
        HttpSession session = req.getSession(true); // Session 不存在则创建
        session.setAttribute("username", username);
        session.setAttribute("loginCount", 0);

        // 4. 重定向到 index
        resp.sendRedirect("index");
    }
}
  1. 创建 IndexServlet 类,用于判断用户是否登录,如果登录则显示用户信息。
@WebServlet("/index")
public class IndexServlet extends HttpServlet {
    
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        req.setCharacterEncoding("utf8");
        resp.setContentType("text/html; charset=utf8");

        // 1. 获取 Session,判断用户是否登录
        HttpSession session = req.getSession(false);  // Session 不存在也不创建
        if(null == session){
    
    
            // 用户没有登录,重定向到 login.html
            resp.sendRedirect("login.html");
            return;
        }

        // 2. 已经登录,获取 Session 中保存的用户名和登录次数
        String username = (String)session.getAttribute("username");
        Integer loginCount = (Integer) session.getAttribute("loginCount");

        loginCount += 1;
        session.setAttribute("loginCount", loginCount);

        // 3. 展示用户信息到页面上
        StringBuilder respBody = new StringBuilder();
        respBody.append(String.format("<div>用户名:%s</div>", username));
        respBody.append(String.format("<div>loginCount: %d</div>", loginCount));
        resp.getWriter().write(respBody.toString());
    }
}

  1. webapp目录下创建 login.html,用于提交登录用户名和密码。
<form action="login" method="post">
    <input type="text" name="username">
    <input type="password" name="password">
    <input type="submit" value="登录">
</form>
  1. 运行程序

访问 http://localhost:8080/hello_servlet/index,由于没有登录,跳转至 login.html

正确输入用户名和密码:

成功登录,跳转至 index,成功显示 Session 中设置的用户信息:

八、上传文件操作

文件上传是 Web 开发中常见的操作,Java Servlet 提供了处理文件上传的支持。在 Java Servlet 中,文件上传通常使用 javax.servlet.http.Part 类或 javax.servlet.http.HttpServletRequest 的相关方法来实现。

8.1 核心方法

HttpServletRequest 接口相关方法:

方法 说明
Part getPart(String name) 获取请求中给定的 name 文件
Collection<Part> getParts() 获取所有文件

Part类相关方法:

方法 说明
String getSubmittedFileName() 获取提交的文件名
String getContentType() 获取提交的文件类型
long getSize() 获取文件的大小
void write(String path) 把提交的文件数据写入磁盘文件

8.2 提交图片到服务器

1. 在 webapp目录下,创建 upload.html用于提交图片文件。

<body>
    <form action="upload" enctype="multipart/form-data" method="post">
        <input type="file" name="image">
        <input type="submit" value="提交图片">
    </form>
</body>

上传文件一般通过 POST 请求的 form 表单实现,并且在 form 标签中要加上 multipart/form-data 字段。

2. 创建 UploadServlet类,用于处理客户端提交图片的请求。

@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 1. 获取图片文件
        Part image = req.getPart("image");
        // 2. 打印图片信息
        System.out.println("图片名称:" + image.getSubmittedFileName());
        System.out.println("图片类型:" + image.getContentType());
        System.out.println("图片大小:" + image.getSize());

        // 3. 将图片保存到磁盘
        image.write("D:/image/tomcat.jpg");

        resp.getWriter().write("upload OK!");
    }
}

注意事项:

  1. 需要给 UploadServlet 加上 @MultipartConfig 注解,否则服务器代码无法使用 getPart 方法。
  2. getPart 的参数需要和 form 表单中 input 标签的 name 属性对应。
  3. 客户端一次可以提交多个文件(使用多个 input 标签),此时服务器可以通过 getParts 获取所有的 Part 对象。

3. 运行程序,并提交一张图片。

此时发现 IDEA 控制台打印的信息:

D盘的 image 目录下多了一张图片:

Guess you like

Origin blog.csdn.net/qq_61635026/article/details/131964807