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 requestsinitanddestroy, 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">