跳转到内容

Jakarta EE 编程/Servlet

50% developed
来自 Wikibooks,开放世界中的开放书籍

Servlet 是在服务器端运行的 Java 类,它接收 HTTP 数据,并在遵循 HTTP 协议的约束条件下进行处理或执行其他操作。

Servlet 示例

[编辑 | 编辑源代码]
package servlet;

import java.io.IOException;
import java.io.PrintWriter;

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

/**
 * Servlet implementation class Hello
 */
@WebServlet("/Hello")
public class Hello extends HttpServlet {

    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public Hello() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)              
                                               throws ServletException, IOException {
 
        // TODO Auto-generated method stub
       
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            out.println("Hello World");
        } finally {
            out.close();
        }
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub

        doGet(request,response);
    }
}

我们注意到这个类中有两个方法:doGet()doPost()。第一个方法通过 HTTP 响应对 GET 请求的接收,第二个方法响应对 POST 请求的接收。由于我们希望在两种情况下 Servlet 都能处理请求,因此 doPost() 会转发到 doGet()

在 Tomcat 上部署

[编辑 | 编辑源代码]
  • 将编译后的类及其包放入工作 Web 目录的 WEB-INF 中的 classes 目录中(这里:webTest
  • 通过添加以下内容来编辑 WEB-INF 中的 web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0"
  metadata-complete="true">  

  <!-- Beginning here -->

    <servlet>
      <servlet-name>Hello</servlet-name><!-- Class name -->
      <servlet-class>servlet.Hello</servlet-class><!-- Class tree: with the package -->
    </servlet>
    <servlet-mapping>
        <servlet-name>Hello</servlet-name><!-- Class name -->
        <url-pattern>/Hello</url-pattern><!-- Class pattern in the URL-->
    </servlet-mapping>

   <!-- End here -->

<web-app>

因此 WEB-INF 包含

   WEB-INF
     web.xml
     classes
       servlet
         Hello.class

调用 Servlet

[编辑 | 编辑源代码]

https://127.0.0.1:999/webTest/Hello

浏览器中的结果

Hello World

URL 的分解

[编辑 | 编辑源代码]

[协议://][DNS]:[端口]/[根目录]/[Servlet 名称]

关于 URL 的信息方法

[编辑 | 编辑源代码]
// Returns the server name
request.getServerName();

// Returns the server port
request.getServerPort();

// Returns the name of the application hosting the servlet
request.getContextPath();

// Returns the servlet path
request.getServletPath();

// Returns the type of the HTTP request used
request.getMethod();

// Returns the parameters sent in the URL
request.getQueryString();

// Returns the URL used to contact the servlet
request.getRequestURL();

// Returns the local address
request.getLocalAddr();

// Returns the local name
request.getLocalName();

// Returns the local port
request.getLocalPort();

// Returns the remote address
request.getRemoteAddr();

// Returns the remote host
request.getRemoteHost();

Servlet 中的示例

package servlet;

import java.io.IOException;
import java.io.PrintWriter;

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

/**
 * Servlet implementation class Hello
 */
@WebServlet("/Hello")
public class Hello extends HttpServlet {

  private static final long serialVersionUID = 1L;
   
  /**
   * @see HttpServlet#HttpServlet()
   */
  public Hello() {
    super();
    // TODO Auto-generated constructor stub
  }

  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    try {
      out.println(request.getServerName());
      out.println("<br/>");
      out.println(request.getServerPort());
      out.println("<br/>");
      out.println(request.getContextPath());
      out.println("<br/>");
      out.println(request.getServletPath());
      out.println("<br/>");
      out.println(request.getMethod());
      out.println("<br/>");
      out.println(request.getQueryString());
      out.println("<br/>");
      out.println(request.getRequestURL());
      out.println("<br/>");
      out.println(request.getLocalAddr());
      out.println("<br/>");
      out.println(request.getLocalName());
      out.println("<br/>");
      out.println(request.getLocalPort());
      out.println("<br/>");
      out.println(request.getRemoteAddr());
      out.println("<br/>");
      out.println(request.getRemoteHost());
    } finally {
      out.close();
    }
  }
   
  /**
   * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
   */
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
   
    processRequest(request, response);
  }

  /**
   * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
   */
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
    // TODO Auto-generated method stub

    processRequest(request, response);
  }
}

相关调用:https://127.0.0.1:999/webTest/Hello

localhost
999
/webTest
/Hello
GET
null
https://127.0.0.1:999/webTest/Hello
127.0.0.1
localhost
999
127.0.0.1
127.0.0.1

参数读取方法

[编辑 | 编辑源代码]
// Parameter retrieving by the "parameterName"
request.getParameter(parameterName);

// Returns an enumeration of all the parameters of a request
request.getParameterNames();

// Returns all the parameter values of "parameterName"
request.getParameterValues(parameterName);

// Returns an iteration of the parameter names
request.getParameterMap();

头信息读取方法

[编辑 | 编辑源代码]
// Returns the header names
request.getHeaderNames();

// Returns the headers
request.getHeaders();

// Returns the number of bytes of the request
request.getContentLength();

// Returns the content type of the request
request.getContentType();

// Returns the default language
request.getLocale();

// Returns the list of languages
request.getLocales();

// Returns the header date
request.getDateHeader(String name);

// Returns the header specified by the "name"
request.getHeader(String name);

// Returns the headers specified by the "name"
request.getHeaders(String name);

用于添加信息的请求方法

[编辑 | 编辑源代码]
// Store an object in the HttpServletRequest object
request.setAttribute(String name, Object o);

// Returns the stored object "name"
request.getAttribute(String name);

// Returns an enumeration of the attribute names
request.getAttributeNames();

// Remove the attribute "name" the attributes of the request
request.removeAttribute(String name);

用于添加头信息的方法

[编辑 | 编辑源代码]

HTTP 头信息为响应添加补充信息。

// Indicates the nature of the information put into the response
response.setContentType(String type);

// Indicates the local language
response.setLocale(Locale loc);

// Adds the header "name" with the value "value"
response.addHeader(String name, String value);

响应主体构建

[编辑 | 编辑源代码]
  • (PrintWriter)getWriter() 允许将文本传输到 HTTP 响应主体。
  • (ServletOutputStream)getOutputStream() 允许将二进制数据传输到 HTTP 响应主体。

切勿同时使用这两种方法,否则会导致 IllegalStateException 异常。

以下是一个二进制发送的示例

package servlet;

import java.io.IOException;

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

/**
 * Servlet implementation class ReponseHttp2
 */
@WebServlet("/HttpResponse2")
public class HttpResponse2 extends HttpServlet {
  private static final long serialVersionUID = 1L;
       
  /**
   * @see HttpServlet#HttpServlet()
   */
  public HttpResponse2() {
    super();
    // TODO Auto-generated constructor stub
  }
   
  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
    response.sendRedirect("images/toto.jpg");
  }
   
  /**
   * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
   */
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    processRequest(request, response);
  }

  /**
   * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
   */
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    processRequest(request, response);
  }

}

在这个示例中,我们使用 processRequest(request, response) 来始终在 GET 或 POST 中获得相同的处理过程。

构建 HTTP 响应

[编辑 | 编辑源代码]

状态码分为 5 类

1XX:信息
2XX:成功
3XX:重定向
4XX:客户端错误
5XX:服务器错误

有关这些代码的详细信息,请访问 http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

  • setStatus(int rc)
  • sendError(int sc, String message)

... 允许设置页面的错误状态。例如,我们将生成一个服务器错误。

package servlet;

import java.io.IOException;
import java.io.PrintWriter;

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

/**
 * Servlet implementation class ReponseHTTP
 */
@WebServlet("/ReponseHTTP")
public class ReponseHTTP extends HttpServlet {

  private static final long serialVersionUID = 1L;
       
  /**
   * @see HttpServlet#HttpServlet()
   */
  public ReponseHTTP() {
    super();
    // TODO Auto-generated constructor stub
  }

  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    try {
      response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "the server is overloaded. Please try later.");
    } finally {
      out.close();
    }
  }
   
  /**
   * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
   */
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    processRequest(request, response);
  }

  /**
   * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
   */
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    processRequest(request, response);
  }
}

其他资源

[编辑 | 编辑源代码]

RequestDispatcher

[编辑 | 编辑源代码]

包含外部资源。

RequestDispatcher rd = null;
rd = getServletContext().getRequestDispatcher("/header.html");
rd.include(request, response);

Servlet 结果传输到另一个资源。

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.HttpServlet;
import javax.servlet.HttpServletRequest;
import javax.servlet.HttpServletResponse;

public class Result extends HttpServlet {
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
       
      response.setContentType("text/html;charset=UTF-8");
      PrintWriter out = response.getWriter();
      try {
        int result = 10;
        RequestDispatcher rd = null;
        rd = getServletContext().getRequestDispatcher("/result.jsp");
        request.setAttribute("theResult", result);
        rd.forward(request, response);
      } finally {
        out.close();
      }
   }
}

目标资源:result.jsp

<%@page contentType="text/html" pageEncoding="UTF-8">
<%@page import="java.text.*" %>
<html>
  <body>
    <%
    theResult = (double) request.getAttribute("theResult");
    %>

    Result: <%= theResult %>
  </body>
</html>

重定向

[编辑 | 编辑源代码]

服务器通知浏览器向给定的 URL 发送 HTTP 请求。

response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // For a 301 HTTP response
response.setHeader("location", "http://www.google.be"); // For a 302 HTTP response
response.sendRedirect("http://www.google.be");

过滤器

[编辑 | 编辑源代码]

过滤器在 HTTP 请求被 Servlet 接收之前或在 HTTP 响应被返回之前添加一个处理过程。

其作用包括:

  • 访问控制
  • 访问日志
  • 数据解压缩
  • 解密
  • 数据转换

可以依次执行多个响应。过滤器类必须实现 javax.servlet.Filter 接口。

Clipboard

待办事项
添加示例。


事件通知应用程序操作,例如对象的实例化和销毁。

  • 应用程序相关事件:由 Servlet 上下文触发的事件。
  • 会话相关事件:这些类必须实现 HttpSessionListenerHttpSessionAttributeListener 接口。

Servlet 同步

[编辑 | 编辑源代码]

这种同步避免了服务器同时使用两个线程,例如当同一个类的两个实例使用两个不同的客户端调用同一个方法时。synchronized(this){} 必须应用于关键进程,例如计数器。

public class ... {
  public void method() {
    out = response.getWriter();
    synchronized(this) {
      counter++;
    }
    out.println("The counter value is " + counter);
  }
}
Clipboard

待办事项
添加练习。


华夏公益教科书