Servlet 体系结构
# 20.Servlet 体系结构
Servlet 只是一个接口规范,我们通常使用一些定义好的实现类来使用,而不是自己从头实现一个 Servlet 接口。
# Servlet 的实现类
看 API 文档,可以看到 Servlet 有两个实现类:
Servlet -- 接口
|
GenericServlet -- 抽象类、实现类,实现了接口 Servlet
|
HttpServlet -- 抽象类、实现类,继承了 GenericServlet
# GenericServlet
GenericServlet:将 Servlet 接口中其他的方法做了默认空实现,只将 service()
方法作为抽象。这是因为我们大多数时候只需用到 service()
方法,其他的都很少用,因此 GenericServlet 对其他方法做了空实现,但如果想要复写也可以自己实现。
将来定义 Servlet 类时,可以继承 GenericServlet,实现 service()
方法即可。
public class GenericServletDemo1 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
}
}
2
3
4
5
6
GenericServlet 源码:
package javax.servlet;
import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
private static final long serialVersionUID = 1L;
private transient ServletConfig config;
public GenericServlet() {
}
public void destroy() {
}
public String getInitParameter(String name) {
return this.getServletConfig().getInitParameter(name);
}
public Enumeration<String> getInitParameterNames() {
return this.getServletConfig().getInitParameterNames();
}
public ServletConfig getServletConfig() {
return this.config;
}
public ServletContext getServletContext() {
return this.getServletConfig().getServletContext();
}
public String getServletInfo() {
return "";
}
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
public void log(String message) {
this.getServletContext().log(this.getServletName() + ": " + message);
}
public void log(String message, Throwable t) {
this.getServletContext().log(this.getServletName() + ": " + message, t);
}
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
public String getServletName() {
return this.config.getServletName();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# HTTPServlet 介绍
我们写 Servlet 是为了做什么? 不外乎就是处理用户的请求,并且大部分是 HTTP 请求,例如客户通过表单送来了账户和密码,要对登录做校验。
收到请求后,我们首先需要判断是 get 还是 post 方式,然后定义方法分别处理 post 请求和 get 请求:
String method = req.getMethod(); //返回 HTTP 请求的方式,get 还是 post
if ("GET".equals(method)){
//get 方式获取数据
doGet();
}else if("POST".equals(method)){
//post 方式获取数据
doPost();
}
public void doGet(){
//.....处理请求
}
public void doPost(){
//.....处理请求
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
而 HTTPServlet,就是封装好了这个操作,不用自己写代码去判断是 get 还是 post,对 http 协议的做了一层简单的封装。API 文档里的描述:
Provides an abstract class to be subclassed to create an HTTP servlet suitable for a Web site. A subclass of HttpServlet
must override at least one method, usually one of these:
doGet
, if the servlet supports HTTP GET requestsdoPost
, for HTTP POST requestsdoPut
, for HTTP PUT requestsdoDelete
, for HTTP DELETE requestsinit
anddestroy
, to manage resources that are held for the life of the servletgetServletInfo
, which the servlet uses to provide information about itself
因此,GenericServlet 较少使用,我们主要是使用 HTTPServlet。
HttpServlet 的 service 方法源码:HTTP 共 7 种请求方式,每个都做了判断
public abstract class HttpServlet extends GenericServlet {
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
.....doGet();
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# HTTPServlet 的使用
定义类继承 HttpServlet,然后复写 doGet/doPost 方法:
package com.peterjxl;
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;
@WebServlet("/httpDemo1")
public class ServletHttpDemo1Hello extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ServletHttpDemo1Hello doGet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ServletHttpDemo1Hello doPost");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
重启 Tomcat,访问 http://localhost:8080/hello/httpDemo1
;浏览器默认是用 get,所以复写了 doGet 方法后,默认会执行 get 方法,输出:"ServletHttpDemo1Hello doGet"
然后我们来测试 post。在 web 目录下新建 ServletHttpDemo1Post.jsp,并用表单发送 post 请求
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>测试post请求</title>
</head>
<body>
<form action="/hello/httpDemo1" method="post">
<span>用户名:</span><input type="text" name="username" placeholder="请输入用户名">
<input type="submit" value="点击发送post请求">
</form>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
访问:http://localhost:8080/hello/ServletHttpDemo1Post.jsp
,随便输入一个用户名,点击按钮;然后可以看到后台输出 ServletHttpDemo1Hello doPost
如果使用的 method 是 get,那么请求参数会拼接在 url 中,这里不再演示
<form action="/hello/httpDemo1" method="get">