JavaWeb(1):Servlet入门
参考书籍:Pro Java for Web Apps
注:以下内容需要HTTP
基础,演示所用Java
版本为Java8
,所用容器为Tomcat8.5.51
Servlet
是一个运行在Web
服务器中的Java
小程序,用于接收和响应来自Web
客户端的请求,使用HTTP
进行通信,是所有Web
应用程序的核心类,也是唯一的既可以直接处理和响应用户请求,也可以将处理工作委托给应用中的其他部分的类。
Servlet
只是一个简单的接口,包含了相关的方法。大多数情况下Servlet
都继承自 $javax.servlet.GenericServlet$ 类,该类只包含一个抽象的 $service$ 方法以及一些辅助方法。$service$ 方法会处理所有请求,然后返回对应的响应。我们可以使用$javax.servlet.http.HttpServlet$ 类用于响应HTTP
请求,它继承自 $GenericServlet$ 并实现其 $service$ 方法,而对于响应HTTP
请求的方法只是空实现。在 $HttpServlet$ 类中,HTTP
请求包括 $GET,HEAD,POST,PUT,DELETE,OPTIONS,TRACE$ 对应的响应方法名称为 $do +$ 首字母大写的请求名称。如 $GET$ 对应 $doGet()$ ,$POST$ 对应 $doPost()$ 等。除了响应方法之外,Servlet
类中还包含 $init$ 方法和 $destroy$ 方法,分别在启用和关闭Servlet
时调用,不过通常这些方法什么也不做。
大多数情况下我们的Servlet
类都是继承 $HttpServlet$ 类。对于上述提到的所有方法,它们都接收两个参数,一个是 $javax.servlet.http.HttpServletRequest$ 类型的参数,另一个是 $javax.servlet.http.HttpServletResponse$ 类型。顾名思义,$HttpServletRequest$ 指向客户端请求,对其我们有如下常用方法:
方法 | 作用 |
---|---|
$getParameter$ | 返回参数的单个值 |
$getParameterValues$ | 返回参数的值的数组 |
$getParameterMap$ | 返回一个包含所有参数名值对的$java.util.Map<String, String[\ \ ]>$ |
$getParameterNames$ | 返回所有可用参数的名字的枚举 |
$getContentLength$ | 返回请求正文的长度(小于 $2$ GB) |
$getContentLengthLong$ | 返回请求正文的长度(大于 $2$ GB) |
$getCharacterEncoding$ | 返回请求内容的字符编码 |
$getReader$ | 返回一个 $java.io.BufferedReader$ 类,可以用于读取请求的内容 |
$getRequestURL$ | 返回客户端用于创建请求的完整URL |
$getRequestURI$ | 返回URL 中的服务器路径部分 |
$getServletPath$ | 返回匹配Servlet 映射的URL 部分 |
$getHeader$ | 返回指定名称的第一个值 |
$getHeaders$ | 返回指定名称的所有值的枚举 |
$getHeaderNames$ | 返回请求中所有头数据的名称的枚举 |
$getIntHeader$ | 返回所有值为整型的头数据的一个值 |
$getDateHeader$ | 返回可以识别为有效时间戳的头数据的时间戳 |
而$HttpServletResponse$ 指向服务端响应,我们有如下常用方法:
方法 | 作用 |
---|---|
$getOutputStream$ | 返回一个 $javax.servlet.ServletOutputStream$ 类,向响应中输出二进制数据 |
$getWriter$ | 返回一个 $java.io.PrintWriter$ 类,向响应中输出字符 |
$setContentType$ | 设置响应正文内容的类型 |
$setCharacterEncoding$ | 设置响应内容的编码格式 |
$setHeader$ | 设置指定名称头数据的值 |
$setIntHeader$ | 设置指定值为整型的头数据的值 |
$setDateHeader$ | 设置头数据时间戳 |
$setStatus$ | 设置HTTP 响应状态码 |
$getStatus$ | 判断当前响应的状态 |
$sendError$ | 设置状态码,一条可选的错误消息会输出到响应数据中,重定向到Web 容器为客户端提供的错误页面并清空缓存 |
$sendRedirect$ | 重定向客户端至另一个URL |
通过声明一个 Servlet
类,我们的已经可以接受任何HTTP
请求了,但由于我们并未重写空实现,因此我们无法响应请求,因此我们需要重写方法。
package com.wrox;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("Hello world!");
}
}
$HttpServletResponse$ 中的 $getWriter(\ \ )$ 方法返回一个 $java.io.PrintWriter$ 类,可以将文本输入到输出流中。通过实现了 $doGet(\ \ )$ 方法,我们实现了对 $GET$ 请求的响应。
虽然我们实现了响应请求,但是我们的程序并未部署。为了部署程序,我们要通过 $web.xml$ ,这个文件定义了程序中的监听器、Servlet
、过滤器以及应用程序的设置。在 $WEB-INF$ 目录中创建 $web.xml$ 文件(如果没有的话)。通常我们看到的初始的 $web.xml$ 文件是这样的:
其中标签 $<web-app>$ 部分中的 $version$ 表明了程序所使用的 $Servlet API$ 版本。之后添加的内容均需要在 $<web-app>$ 中添加。
如果我们要创建一个 $Servlet$ 实例,那么我们可以在文件添加如下内容:
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.wrox.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
可以发现 $<servlet-name>$ 中指定了 $Servlet$ 的名称,$<servlet-class>$ 指定了对应的类,而对于 $<load-on-startup>$ ,我们需要先知道,默认情况下 $init$ 方法是只有当接收到请求时才会调用的,而如果我们设置了 $<load-on-startup>$ 那么 $Servlet$ 将会按顺序启动 $Servlet$ ,而不是接收到请求后才启动。
在部署之后,我们还需要告诉服务器我们所部署的 $Servlet$ 响应哪些请求:
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/greeting</url-pattern>
</servlet-mapping>
上面的配置告诉程序所有 $/greeting$ 的请求都由 $helloServlet$ 处理。
在处理完上述步骤之后,我们就可以运行了。我们在 $/greeting$ 上看到 $Hello\ \ world!$ 时,就代表我们的程序运行成功了。
除了上面的方法,我们还可以通过使用 $@WebServlet$ 注解,如下所示:
@WebServlet (
name = "helloServlet",
urlPatterns = {"/greeting"},
loadOnStartup = 1
)
使用注解的缺点就是每次修改参数之后都要重新编译程序。