1. 简介

本文章基于:

  • Eclipse 4.6(NEON)
  • Servlet 3.0
  • Tomcat 9.0

2. Servlet是什么?

Java Servlet是在Web或应用程序服务器上运行的程序,并充当Web浏览器或其他HTTP客户端发出的请求与HTTP服务器上的数据库或应用程序之间的中间层。使用Servlet,可以通过网页表单收集用户的输入,从数据库或其他来源显示记录,并动态创建网页。

Servlet是什么

3. Servlet生命周期

下图说明了Servlet的生命周期。 自创建以来,一直处理用户的请求,直到销毁为止。

Servlet生命周期

Servlet生命周期共有5个步骤:

  • 第1步:加载Servlet类。
  • 第2步:创建Servlet实例。
  • 第3步:调用servlet init()方法。
  • 第4步:调用servlets service()方法。
  • 第5步:调用servlet destroy()方法。

最初加载Servlet时,第1、2和3步仅执行一次。默认情况下,只有在收到第一个请求后才加载servlet。不过,可以在容器启动时强制容器加载servlet。

第4步多次执行 - 对Servlet的每个HTTP请求一次都会执行第4步。当servlet容器销毁servlet时,执行第5步。

可以下图,以更好地了解Servlet的生命周期。

Servlet生命周期

当用户请求Servlet时,Servlet将调用service()方法来满足用户的需求,service()将调用doGet()doPost()
因此,当用户请求Servlet时,Servlet将在第一次请求时创建,并同时调用servlet的init()方法以对其进行初始化,而init()方法仅被调用一次。 destroy()方法用于销毁servlet,在删除Web应用程序的部署(取消部署)或停止Web服务器时,它将仅被调用一次。

4. 安装Tomcat Web服务器

要开始使用Servlet,需要下载Tomcat Web Server并在Eclipse中进行配置。参考以下网址:

5. 在Web项目中创建Servlet

打开Eclipse,选择:File/New/Other,创建一个动态Web项目,如下图所示:

创建Web项目

输入项目名称:ServletTutorial,如下图所示:

点击下一步(Next>),如下图所示:

勾选生成web.xml,点击完成(Finish),如下图所示:

项目创建成功后,目录结构如下所示:

接下来在WebContent目录中创建一个HTML文件:index.html,代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

   <h1>Hello World</h1>

</body>
</html>

6. 配置Eclipse在Tomcat上运行应用

到目前为止,我们只是创建了一个动态Web项目。接下来要对项目进行配置,以便它可以运行Web应用程序。

在Eclipse中,右键单击项目名称:ServletTutorial,选择Properties:

选择运行环境的版本,如下图所示:

运行环境的版本

填写服务器的名称,并选择运行服务器的安装路径,然后点击完成。如下图所示:

返回运行时界面,选择上面配置的服务器(Apache Tomcat v9),如下图所示:

选择服务器

右键单击项目ServletTutorial,选择“Run As / Run on Server”。如下图所示:

选择运行为...

弹出选择服务器,这里选择Tomcat V9 Server,如下图所示:

弹出选择服务器

选择发布项目,如下图所示:
选择发布项目

网站已经在Eclipse浏览器上运行。如下图所示:

运行动态网站

工作原理

当您访问以下URL时:

网站显示index.html页面的内容,这是可以理解的。但是,如果访问URL:

上面URL中并没有指定要访问的页面,因此Web服务器将查找在web.xml中声明的<welcome-file>标记中声明的默认页面以获取答案。

注意:/ServletTutorial称为上下文路径。每个网站都有一个上下文路径,可以为它配置另一个值或将其设置为空。如果为空,则可以通过以下方式访问网站:

过程如下图中所示:

执行过程

7. 加入一些类

下面将向这个示例中加入一些Java类:

文件:Constants.java

package com.xntutor.tutorial.beans;

public class Constants {

    public static final String ATTRIBUTE_USER_NAME_KEY = "ATTRIBUTE_USER_NAME_KEY";

    public static final String SESSION_USER_KEY = "SESSION_USER_KEY";

    public static final String CALLBACK_URL_KEY = "CALLBACK_URL_KEY";

}

文件:UserInfo.java

package com.xntutor.tutorial.beans;

public class UserInfo {

    public String userName;
    private int post;
    private String country;

    public UserInfo(String userName, String country, int post) {
        this.userName = userName;
        this.country = country;
        this.post = post;
    }

    public int getPost() {
        return post;
    }

    public void setPost(int post) {
        this.post = post;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public UserInfo(String userName) {
        this.userName = userName;
    }

    public String getUserName() {
        return this.userName;
    }
}

8. 创建一个Servlet

项目的目录结构如下所示:

创建一个Servlet

文件:HelloServlet.java,完整代码如下:

package com.xntutor.tutorial.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public HelloServlet() {
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        ServletOutputStream out = response.getOutputStream();

        out.println("<html>");
        out.println("<head><title>Hello Servlet</title></head>");

        out.println("<body>");
        out.println("<h3>Hello World</h3>");
        out.println("This is my first Servlet");
        out.println("</body>");
        out.println("<html>");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

}

如果已创建的HelloServlet类代码提示有错误,可能是您还未加入Servlet库。在这里,因为使用Tomcat,因此需要对其进行声明。

在“项目”上单击鼠标右键,选择“属性”:

然后,选择服务器运行时,如下图所示:

选择服务器运行时

选择对应的服务器版本,如下图所示:

选择服务器版本

选择服务器版本2

现在HelloServlet类代码应该没有错误提示了。
接下来,需要在Web.xml中声明HelloServlet和访问它的路径。需要添加以下配置:

<!-- Define servlet, named helloServlet -->
<servlet>
   <servlet-name>helloServlet</servlet-name>
   <servlet-class>com.xntutor.tutorial.servlet.HelloServlet</servlet-class>
</servlet>

<!-- Defines the path to access this Servlet -->
<servlet-mapping>
   <servlet-name>helloServlet</servlet-name>
   <url-pattern>/hello</url-pattern>
</servlet-mapping>

完整的web.xml文件中的代码如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
   id="WebApp_ID" version="3.0">
   <display-name>ServletTutorial</display-name>


   <servlet>
       <servlet-name>helloServlet</servlet-name>
       <servlet-class>com.xntutor.tutorial.servlet.HelloServlet</servlet-class>
   </servlet>

   <servlet-mapping>
       <servlet-name>helloServlet</servlet-name>
       <url-pattern>/hello</url-pattern>
   </servlet-mapping>


   <welcome-file-list>
       <welcome-file>index.html</welcome-file>
       <welcome-file>index.html</welcome-file>
       <welcome-file>index.jsp</welcome-file>
       <welcome-file>default.html</welcome-file>
       <welcome-file>default.html</welcome-file>
       <welcome-file>default.jsp</welcome-file>
   </welcome-file-list>


</web-app>

右键单击项目(ServletTutorial),然后选择:Run As/Run on Server,如下图所示:

右键单击项目

右键单击项目2

服务器启动完成后,使用浏览器访问以下URL:

访问结果

可以根据下面的执行流程图示来了解Servlet的工作原理。

Servlet的工作原理

调用Servlet时,根据客户端的请求方法来调用doGet(..)doPost(..)。在doGet()doPost()中,可以检索ServletOutputStream对象,这是将数据发送到用户浏览器的输出流。调用ServletOutputStream.println(..)将数据写入流中。如下示例代码:

// The output stream to send data to user's browser
ServletOutputStream out = response.getOutputStream();

9. Servlet初始化参数

web.xml中声明servlet时,可以为servlet设置初始化参数。参考以下Servlet实现代码。

文件:InitParamServlet.java

package com.xntutor.tutorial.servlet;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class InitParamServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    private String emailSupport1;

    public InitParamServlet() {
    }

    // This method is always called once after the Servlet object is created.
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        // Get the value of the initialization parameter of the Servlet.
        // (According to the Configuration of this Servlet in web.xml).
        this.emailSupport1 = config.getInitParameter("emailSupport1");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // Get the initialization parameter's value in a different way.
        String emailSupport2 = this.getServletConfig().getInitParameter("emailSupport2");

        ServletOutputStream out = response.getOutputStream();

        out.println("<html>");
        out.println("<head><title>Init Param</title></head>");

        out.println("<body>");
        out.println("<h3>Init Param</h3>");
        out.println("<p>emailSupport1 = " + this.emailSupport1 + "</p>");
        out.println("<p>emailSupport2 = " + emailSupport2 + "</p>");
        out.println("</body>");
        out.println("<html>");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

}

接下来,向web.xml文件添加一些内容:

    <servlet>
        <servlet-name>initParamServlet</servlet-name>
        <servlet-class>com.xntutor.tutorial.servlet.InitParamServlet</servlet-class>

        <init-param>
            <param-name>emailSupport1</param-name>
            <param-value>support1@xntutor.com</param-value>
        </init-param>

        <init-param>
            <param-name>emailSupport2</param-name>
            <param-value>support2@xntutor.com</param-value>
        </init-param>

    </servlet>

完整的web.xml文件内容,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>ServletTutorial</display-name>
    <!-- Define servlet, named helloServlet -->
    <servlet>
        <servlet-name>helloServlet</servlet-name>
        <servlet-class>com.xntutor.tutorial.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>initParamServlet</servlet-name>
        <servlet-class>com.xntutor.tutorial.servlet.InitParamServlet</servlet-class>

        <init-param>
            <param-name>emailSupport1</param-name>
            <param-value>support1@xntutor.com</param-value>
        </init-param>

        <init-param>
            <param-name>emailSupport2</param-name>
            <param-value>support2@xntutor.com</param-value>
        </init-param>

    </servlet>


    <servlet-mapping>
        <servlet-name>initParamServlet</servlet-name>
        <url-pattern>/initParam</url-pattern>
    </servlet-mapping>

    <!-- Defines the path to access this Servlet -->
    <servlet-mapping>
        <servlet-name>helloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
</web-app>

重新运行Web应用程序并访问以下URL:

应该会看到类似下面的结果:

运行结果

10. 使用注释配置Servlet

在Servlet 3.0或更高版本中,可以使用Annotation配置Servlet,在本项目中,我们使用Servlet 3.x版,以便可以使用Annotation进行配置。参考下面的一个例子。

文件:AnnotationExampleServlet.java

package com.xntutor.tutorial.servlet;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// You can configure one or multiple 'URL Patterns' can access this Servlet.
@WebServlet(urlPatterns = { "/annotationExample", "/annExample" }, initParams = {
        @WebInitParam(name = "emailSupport1", value = "support1@xntutor.com"),
        @WebInitParam(name = "emailSupport2", value = "support2@xntutor.com") })
public class AnnotationExampleServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    private String emailSupport1;

    public AnnotationExampleServlet() {
    }

    // In any case, init() is guaranteed to be called
    // before the Servlet handles its first request.
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        this.emailSupport1 = config.getInitParameter("emailSupport1");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String emailSupport2 = this.getServletConfig().getInitParameter("emailSupport2");

        ServletOutputStream out = response.getOutputStream();

        out.println("<html>");
        out.println("<head><title>Init Param</title></head>");

        out.println("<body>");
        out.println("<h3>Servlet with Annotation configuration</h3>");
        out.println("<p>emailSupport1 = " + this.emailSupport1 + "</p>");
        out.println("<p>emailSupport2 = " + emailSupport2 + "</p>");
        out.println("</body>");
        out.println("<html>");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

}

可以通过以下两个链接之一来访问此Servlet:

它们运行的结果相同:

使用注释配置Servlet

上面Servlet不需要在web.xml文件中配置。

11. Servlet URL模式

Servlet URL模式

有四种方法可以配置Servlet的路径:

第1种方式: /*,示例如下:

  • http://example.com/contextPath
  • http://example.com/contextPath/status/abc

第2种方式: /status/abc/*,示例如下:

  • http://example.com/contextPath/status/abc
  • http://example.com/contextPath/status/abc/mnp
  • http://example.com/contextPath/status/abc/mnp?date=today

第3种方式: *.map,示例如下:

  • http://example.com/contextPath/status/abc.map
  • http://example.com/contextPath/status.map?date=today

第4种方式: /,这是默认的Servlet。

当用户在浏览器上输入链接时,它将被发送到WebContainerWebContainer必须决定是否
Servlet将处理来自用户的请求。

下图说明了WebContainer如何决定使用Servlet来响应来自客户端的请求。

响应客户端的请求

例如,创建一个带有星号的Servlet url-pattern:

  • url-pattern = "/any/*";

文件:AsteriskServlet.java

package com.xntutor.tutorial.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = { "/any/*" })
public class AsteriskServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public AsteriskServlet() {
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        ServletOutputStream out = response.getOutputStream();

        out.println("<html>");
        out.println("<head><title>Asterisk</title></head>");

        out.println("<body>");

        out.println("<h3>Hi, your URL match /any/*</h3>");

        out.println("</body>");
        out.println("<html>");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

}

以下URL由AsteriskServlet(/any/*)提供服务:

  • http://localhost:8080/ServletTutorial/any/path1/a.html
  • http://localhost:8080/ServletTutorial/any/something
  • http://localhost:8080/ServletTutorial/any

访问上面URL,可以看到以下结果:

默认的Servlet

默认Servlet

作为默认Servlet,Servlet将用于处理路径与应用程序中声明的Servlet的url-pattern不匹配的请求。下面来看看默认servlet的示例:

文件:MyDefaultServlet.java

package com.xntutor.tutorial.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = { "/" })
public class MyDefaultServlet extends HttpServlet {

   private static final long serialVersionUID = 1L;

   public MyDefaultServlet() {
   }

   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
           throws ServletException, IOException {

       ServletOutputStream out = response.getOutputStream();

       out.println("<html>");
       out.println("<head><title>Page not found</title></head>");

       out.println("<body>");
       out.println("<h3>Sorry! Page not found</h3>");
       out.println("<h1>404</h1>");
       out.println("Message from servlet: " + this.getClass().getName());
       out.println("</body>");
       out.println("<html>");
   }

   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponse response)
           throws ServletException, IOException {
       this.doGet(request, response);
   }

}

重新运行Web应用程序,并访问URL:

  • http://localhost:8080/ServletTutorial/news/someonewho

上面的链接servletPath = /news/tomAndJerry,与声明的url模式不匹配。但是“默认Servlet”满足该请求。

默认Servlet

12. 获取Servlet的基本信息

有时因为某种需要,想了解Servlet实例提供的时间有关的信息,这些信息包括:

  • 来自客户端的信息请求。
  • 服务器信息。
  • 客户资料。
  • 标头信息按要求发送。

创建一个Servlet类文件:ExampleInfoServlet.java

package com.xntutor.tutorial.servlet;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/other/exampleInfo")
public class ExampleInfoServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public ExampleInfoServlet() {
        super();
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        ServletOutputStream out = response.getOutputStream();

        out.println("<style> span {color:blue;} </style>");

        String requestURL = request.getRequestURL().toString();
        out.println("<br><span>requestURL:</span>");
        out.println(requestURL);

        String requestURI = request.getRequestURI();
        out.println("<br><span>requestURI:</span>");
        out.println(requestURI);

        String contextPath = request.getContextPath();
        out.println("<br><span>contextPath:</span>");
        out.println(contextPath);

        out.println("<br><span>servletPath:</span>");
        String servletPath = request.getServletPath();
        out.println(servletPath);

        String queryString = request.getQueryString();
        out.println("<br><span>queryString:</span>");
        out.println(queryString);

        String param1 = request.getParameter("text1");
        out.println("<br><span>getParameter text1:</span>");
        out.println(param1);

        String param2 = request.getParameter("text2");
        out.println("<br><span>getParameter text2:</span>");
        out.println(param2);

        // Server Infos
        out.println("<br><br><b>Server info:</b>");

        out.println("<br><span>serverName:</span>");
        String serverName = request.getServerName();
        out.println(serverName);

        out.println("<br><span>serverPort:</span>");
        int serverPort = request.getServerPort();
        out.println(serverPort + "");

        // Client Infos
        out.println("<br><br><b>Client info:</b>");

        out.println("<br><span>remoteAddr:</span>");
        String remoteAddr = request.getRemoteAddr();
        out.println(remoteAddr);

        out.println("<br><span>remoteHost:</span>");
        String remoteHost = request.getRemoteHost();
        out.println(remoteHost);

        out.println("<br><span>remoteHost:</span>");
        int remotePort = request.getRemotePort();
        out.println(remotePort + "");

        out.println("<br><span>remoteUser:</span>");
        String remoteUser = request.getRemoteUser();
        out.println(remoteUser);

        // Header Infos
        out.println("<br><br><b>headers:</b>");

        Enumeration<String> headers = request.getHeaderNames();
        while (headers.hasMoreElements()) {
            String header = headers.nextElement();
            out.println("<br><span>" + header + "</span>: " + request.getHeader(header));
        }

        // Servlet Context info:
        out.println("<br><br><b>Servlet Context info:</b>");
        ServletContext servletContext = request.getServletContext();

        // Location of web application in hard disk
        out.println("<br><span>realPath:</span>");
        String realPath = servletContext.getRealPath("");
        out.println(realPath);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

}

请参阅下图以了解一些您感兴趣的信息:
感兴趣的信息

重新运行Web应用程序并访问链接:

得到以下结果:

获取Servlet的基本信息

13. Servlet转发

转发(Forward):向Servlet发送请求时,它可以将请求转发到另一个页面(或另一个Servlet)。 用户浏览器上的地址仍然是第一页的链接,但是内容是由转发的页面创建的。

请求的页面被转发到位于Web应用程序上的页面(或servlet)。使用转发,可以使用request.setAttribute()将数据从第1页传输到第2页。

Servlet转发

创建一个Servlet类文件:ForwardDemoServlet.java

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.xntutor.tutorial.beans.Constants;

@WebServlet("/other/forwardDemo")
public class ForwardDemoServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    // Request:
    // http://localhost:8080/ServletTutorial/other/forwardDemo?forward=true
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // Get value of parameter on URL.
        String forward = request.getParameter("forward");

        if ("true".equals(forward)) {
            System.out.println("Forward to ShowMeServlet");

            // Set data to attribute of the request.
            request.setAttribute(Constants.ATTRIBUTE_USER_NAME_KEY, //
                    "Hi, I'm Tom come from Walt Disney !");

            RequestDispatcher dispatcher //
                    = request.getServletContext().getRequestDispatcher("/showMe");
            dispatcher.forward(request, response);

            return;
        }
        ServletOutputStream out = response.getOutputStream();
        out.println("<h3>Text of ForwardDemoServlet</h3>");
        out.println("- servletPath=" + request.getServletPath());
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

}

重新运行Web应用并分别访问以下2个URL:

情况1: 没有转发,页面的数据由ForwardDemoServlet生成。如下图所示:
ForwardDemoServlet

情况2:向前转移到ShowMeServlet。在这种情况下,页面上的URL不变,而页面的数据是由ShowMeServlet生成的。如下图所示:
ShowMeServlet

在某些情况下(例如,当用户请求Servlet-A时)通常使用转发。但是,此页面必须先登录。Servlet-A会检查用户的登录,如果尚未登录,它将移至Servlet-Login。回到RequestDispatcher,有两种获取RequestDispatcher对象的方法。

RequestDispatcher对象

request.getServletContext ().getRequestDispatcher(url)返回RequestDispatcher对象,它是位于相对于contextPath(相对于网站根目录的位置)。

request.getRequestDispatcher(url)返回RequestDispatcher对象,它是相对于当前页面位置。

注意:

  • 重定向允许导航到网站以外的页面。
  • 转发仅允许移动到网站内的页面,并且可以通过request.setAttribute在两个页面之间传输数据。

14. Servlet重定向

重定向:当用户向Servlet(页面A)发出请求时,Servlet可以将请求重定向到另一个页面(页面B),并结束其任务。 页面被重定向到应用程序中的页面,也可以Web应用以外是任何页面。

不同与转发,使用重定向不能使用request.setAttribute(..)将数据从页面A传输到页面B。

重定向

创建一个Servlet类文件:ShowMeServlet.java

package com.xntutor.tutorial.servlet.other;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.xntutor.tutorial.beans.Constants;


@WebServlet("/showMe")
public class ShowMeServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // Get value of an attribute of the request.
        String value = (String) request.getAttribute(Constants.ATTRIBUTE_USER_NAME_KEY);

        ServletOutputStream out = response.getOutputStream();

        out.println("<h1>ShowMeServlet</h1>");
        out.println(value);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

}

创建另一个Servlet类文件:RedirectDemoServlet.java

package com.xntutor.tutorial.servlet.other;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/other/redirectDemo")
public class RedirectDemoServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    // Request:
    // http://localhost:8080/ServletTutorial/other/redirectDemo?redirect=true
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // Get the value of parameter on the URL.
        String redirect = request.getParameter("redirect");

        if ("true".equals(redirect)) {
            System.out.println("Redirect to ShowMeServlet");

            // contextPath: Is an empty string "" or non-empty.
            // If it is non-empty, it always starts with /
            // and does not ends with /
            String contextPath = request.getContextPath();

            // ==> /ServletTutorial/showMe
            response.sendRedirect(contextPath + "/showMe");
            return;
        }

        ServletOutputStream out = response.getOutputStream();
        out.println("<h3>Text of RedirectDemoServlet</h3>");
        out.println("- servletPath=" + request.getServletPath());
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

}

重新运行服务器并在浏览器中分别访问以下2个URL:

访问第一个URL显示内容如下:
第一个URL

访问第二个URL,请求将重定向到ShowMeServlet。在浏览器上看到的URL是Servlet ShowMeServlet的路径。显示内容如下:

第二个URL

15. Servlet会话

HttpSession对象代表一个用户会话。 用户会话包含有关多个HTTP请求的用户信息。当用户首次进入网站时,Servlet会为用户提供唯一的ID来标识其会话依据。 此ID通常存储在cookie或请求参数中。

下面是访问会话对象的方式:

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

   HttpSession session = request.getSession();
}

可以将值存储在会话对象中,并在以后检索(读取)它们。首先,让我们看看如何在会话对象中存储值:

// Get the HttpSession object.
HttpSession session = request.getSession();

// Suppose user has successfully logged.
UserInfo loginedInfo = new UserInfo("Maxsu", "China", 5);

// Store user information into a Session attribute.
// You can retrieve this information using the getAttribute method.
session.setAttribute(Constants.SESSION_USER_KEY, loginedInfo);

并检索(读取)存储在Session中特定页面的信息。

// Get the HttpSession object.
HttpSession session = request.getSession();

// Get the UserInfo object stored to the session 
// after the user login successfully.
UserInfo loginedInfo 
    = (UserInfo) session.getAttribute(Constants.SESSION_USER_KEY);

下面通过一个完整的示例,演示创建使用会话。

Servlet类文件:LoginServlet.java

package com.xntutor.tutorial.servlet.session;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.xntutor.tutorial.beans.Constants;
import com.xntutor.tutorial.beans.UserInfo;

@WebServlet(urlPatterns = { "/login" })
public class LoginServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public LoginServlet() {
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        ServletOutputStream out = response.getOutputStream();

        // Get HttpSession object
        HttpSession session = request.getSession();

        // Suppose a user has successfully logged.
        UserInfo loginedInfo = new UserInfo("Maxsu", "China", 5);

        // Storing user information in an attribute of Session.
        session.setAttribute(Constants.SESSION_USER_KEY, loginedInfo);

        out.println("<html>");
        out.println("<head><title>Session example</title></head>");

        out.println("<body>");
        out.println("<h3>You are logined!, info stored in session</h3>");

        out.println("<a href='userInfo'>View User Info</a>");
        out.println("</body>");
        out.println("<html>");
    }

}

Servlet类文件:LoginServlet.java

package com.xntutor.tutorial.servlet.session;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.xntutor.tutorial.beans.Constants;
import com.xntutor.tutorial.beans.UserInfo;

@WebServlet(urlPatterns = { "/userInfo" })
public class UserInfoServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public UserInfoServlet() {
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        ServletOutputStream out = response.getOutputStream();

        // Get HttpSession object.
        HttpSession session = request.getSession();

        // Get UserInfo object stored in session after user login successful.
        UserInfo loginedInfo = (UserInfo) session.getAttribute(Constants.SESSION_USER_KEY);

        // If not logined, redirect to login page (LoginServlet).
        if (loginedInfo == null) {
            // ==> /ServletTutorial/login
            response.sendRedirect(this.getServletContext().getContextPath() + "/login");
            return;
        }

        out.println("<html>");
        out.println("<head><title>Session example</title></head>");

        out.println("<body>");

        out.println("<h3>User Info:</h3>");

        out.println("<p>User Name:" + loginedInfo.getUserName() + "</p>");
        out.println("<p>Country:" + loginedInfo.getCountry() + "</p>");
        out.println("<p>Post:" + loginedInfo.getPost() + "</p>");

        out.println("</body>");
        out.println("<html>");
    }

}

重新运行服务器并在浏览器中以下URL:

运行结果

点击上面链接查看登录的用户信息,结果如下所示:

查看登录的用户信息