- HTTP协议详解、HttpServlet源码分析
2.HTTP
2.1 ★★★HTTP协议详解
2.1.1 HTTP协议
什么是协议?
- 协议实际上是某些人,或者某些组织提前制定好的一套规范,大家都按照这个规范来,这样可以做到沟通无障碍。
- 协议就是一套规范,就是一套标准。由其他人或其他组织来负责制定的。
- 我说的话你能听懂,你说的话,我也能听懂,这说明我们之间是有一套规范的,一套协议的,这套协议就是:中国普通话协议。我们都遵守这套协议,我们之间就可以沟通无障碍。
什么是 HTTP 协议?
- HTTP 协议:是 W3C 制定的一种超文本传输协议。(通信协议:发送消息的模板提前被制定好。)
- W3C(World Wide Web Consortium):
- 万维网联盟组织
- 负责制定标准的:HTTP、HTML4.0、HTML5、XML、DOM 等规范都是 W3C 制定的。
- 万维网之父:蒂姆·伯纳斯·李
- 什么是超文本?
- 超文本说的就是:不是普通文本,比如流媒体:声音、视频、图片等。
- HTTP协议支持:不但可以传送普通字符串,同样支持传递声音、视频、图片等流媒体信息。
- 这种协议游走在 B 和 S 之间。B 向 S 发数据要遵循 HTTP 协议,S 向 B 发数据同样需要遵循 HTTP 协议。这样 B 和 S 才能解耦合。
- W3C(World Wide Web Consortium):
- 什么是解耦合?
- B 不依赖 S。
- S 也不依赖 B。
- B/S 表示:B/S 结构的系统(浏览器访问 WEB服务器的系统)
- 浏览器 向 WEB服务器 发送数据,叫做:请求(
request
) - WEB服务器 向 浏览器 发送数据,叫做:响应(
response
)
- 浏览器 向 WEB服务器 发送数据,叫做:请求(
- HTTP协议包括:
- 请求协议:浏览器 向 WEB服务器 发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。
- 响应协议:WEB服务器 向 浏览器 发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。
- HTTP协议就是提前制定好的一种消息模板。
- 不管你是哪个品牌的 浏览器,都是这么发。
- 不管你是哪个品牌的 WEB服务器,都是这么发。
- FF浏览器 可以向 Tomcat发送请求,也可以向 Jetty服务器发送请求。浏览器不依赖具体的服务器品牌。
- WEB服务器也不依赖具体的浏览器品牌。可以是FF浏览器,也可以是Chrome浏览器,可以是IE,都行。
- HTTP 协议:是 W3C 制定的一种超文本传输协议。(通信协议:发送消息的模板提前被制定好。)
2.1.2 HTTP的请求协议
HTTP 的请求协议(B –> S)
HTTP 的请求协议包括:4 部分
- 请求行
- 包括三部分:
- 第一部分:请求方式(7种)
- get(常用的)
- post(常用的)
- delete
- put
- head
- options
- trace
- 第二部分:URI
- 什么是 URI? 统一资源标识符。代表网络中某个资源的名字。但是通过 URI 是无法定位资源的。
- 什么是 URL?统一资源定位符。代表网络中某个资源,同时,通过 URL 是可以定位到该资源的。
- URI 和 URL 什么关系,有什么区别?
- URL包括URI
- http://localhost:8080/servlet05/index.html 这是URL
- /servlet05/index.html 这是URI
- 第三部分:HTTP协议版本号
- 第一部分:请求方式(7种)
- 包括三部分:
- 请求头
- 请求的主机
- 主机的端口
- 浏览器信息
- 平台信息
- cookie等信息
- …
- 空白行
- 空白行是用来区分“请求头”和“请求体”
- 请求体
- 向服务器发送的具体数据。
- 请求行
怎么查看的协议内容?
- 使用浏览器:
F12
。然后找到network,通过这个面板可以查看协议的具体内容。
- 使用浏览器:
HTTP 请求协议的具体报文:
GET
请求:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18GET /servlet05/getServlet?username=lucy&userpwd=1111 HTTP/1.1 请求行
Host: localhost:8080 请求头
Connection: keep-alive
sec-ch-ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8080/servlet05/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
空白行
请求体HTTP 请求协议的具体报文:
POST
请求:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22POST /servlet05/postServlet HTTP/1.1 请求行
Host: localhost:8080 请求头
Connection: keep-alive
Content-Length: 25
Cache-Control: max-age=0
sec-ch-ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: http://localhost:8080
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8080/servlet05/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
空白行
username=lisi&userpwd=123 请求体
2.1.3 HTTP的响应协议
HTTP 的响应协议(S –> B)
HTTP 的响应协议包括:4 部分
状态行
三部分组成:
第一部分:协议版本号(HTTP/1.1)
第二部分:状态码(HTTP协议中规定的响应状态号。不同的响应结果对应不同的号码)
200
表示请求响应成功,正常结束。404
表示访问的资源不存在,通常是因为要么是你路径写错了,要么是路径写对了,但是服务器中对应的资源并没有启动成功。总之 404 错误是前端错误。405
表示前端发送的请求方式与后端请求的处理方式不一致时发生:- 比如:前端是 POST 请求,后端的处理方式按照 get 方式进行处理时,发生 405。
- 比如:前端是 GET 请求,后端的处理方式按照 post 方式进行处理时,发生 405。
500
表示服务器端的程序出现了异常。一般会认为是服务器端的错误导致的。
以
4
开始的,一般是浏览器端的错误导致的。以
5
开始的,一般是服务器端的错误导致的。第三部分:状态的描述信息
- ok 表示正常成功结束。
- not found 表示资源找不到。
响应头
- 响应的内容类型
- 响应的内容长度
- 响应的时间
- …
空白行
- 用来分隔“响应头”和“响应体”的。
响应体
- 响应体就是响应的正文,这些内容是一个长的字符串,这个字符串被浏览器渲染,解释并执行,最终展示出效果。
HTTP 响应协议的具体报文:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16200 ok 状态行
Content-Type: text/html;charset=UTF-8 响应头
Content-Length: 160
Date: Mon, 08 Nov 2021 13:19:32 GMT
Keep-Alive: timeout=20
Connection: keep-alive
空白行
<!doctype html> 响应体
<html>
<head>
<title>from get servlet</title>
</head>
<body>
<h1>from get servlet</h1>
</body>
</html>
★思考
怎么向服务器发送
GET
请求,怎么向服务器发送POST
请求?- 到目前为止,只有一种情况可以发送
POST
请求:使用 form 表单,并且 form 标签中的 method 属性值为:method="post"
。 - 其他所有情况一律都是
GET
请求:- 在浏览器地址栏上直接输入 URL,敲回车,属于
get
请求。 - 在浏览器上直接点击超链接,属于
get
请求。 - 使用 form 表单提交数据时,form 标签中没有写 method 属性,默认就是
get
。或者使用 form 的时候,form 标签中 method 属性值为:method="get"
。 - …
- 在浏览器地址栏上直接输入 URL,敲回车,属于
- 到目前为止,只有一种情况可以发送
GET
请求和POST
请求有什么区别?GET
请求:GET
请求发送数据的时候,数据会挂在 URI 的后面,并且在 URI 后面添加一个“?
”,”?
“后面是数据。这样会导致发送的数据回显在浏览器的地址栏上(**GET
请求在“请求行”上发送数据**)。GET
请求只能发送普通的字符串,并且发送的字符串长度有限制,不同的浏览器限制不同,这个没有明确的规范。GET
请求无法发送大数据量。GET
请求在 W3C 中是这样说的:**GET
请求比较适合从服务器端获取数据**。GET
请求是安全的,GET
请求是绝对安全的。为什么?因为GET
请求只是为了从服务器上获取数据,不会对服务器造成威胁。GET
请求支持缓存。- 任何一个
GET
请求最终的“响应结果”都会被浏览器缓存起来。在浏览器缓存当中:- 一个
GET
请求的路径a 对应 一个资源。 - 一个
GET
请求的路径b 对应 一个资源。 - 一个
GET
请求的路径c 对应 一个资源。 - …
- 一个
- 实际上,你只要发送
GET
请求,浏览器做的第一件事都是先从本地浏览器缓存中找,找不到的时候才会去服务器上获取。这种缓存机制目的是为了提高用户的体验。 - 有没有这样一个需求:我们不希望
GET
请求走缓存,怎么办?怎么避免走缓存?我希望每一次这个GET
请求都去服务器上找资源,我不想从本地浏览器的缓存中取。- 只要每一次
GET
请求的请求路径不同即可,例如 - 怎么解决?可以在路径的后面添加一个每时每刻都在变化的“时间戳”,这样,每一次的请求路径都不一样,浏览器就不走缓存了。
- 只要每一次
- 任何一个
POST
请求:POST
请求发送数据的时候,在请求体当中发送,不会回显到浏览器的地址栏上。也就是说POST
发送的数据,在浏览器地址栏上看不到(**POST
在“请求体”当中发送数据**)。POST
请求可以发送任何类型的数据,包括普通字符串,流媒体等信息:视频、声音、图片。POST
请求可以发送大数据量,理论上没有长度限制。POST
请求在 W3C 中是这样说的:**POST
请求比较适合向服务器端传送数据**。POST
请求是危险的。为什么?因为POST
请求是向服务器提交数据,如果这些数据通过后门的方式进入到服务器当中,服务器是很危险的。另外POST
是为了提交数据,所以一般情况下拦截请求的时候,大部分会选择拦截(监听)POST
请求。POST
请求不支持缓存(POST
是用来修改服务器端的资源的)。POST
请求之后,服务器“响应的结果”不会被浏览器缓存起来,因为这个缓存没有意义。
GET
请求和POST
请求如何选择,什么时候使用GET
请求,什么时候使用POST
请求?- 怎么选择
GET
请求和POST
请求呢?衡量标准是什么呢?要看你这个请求是想获取服务器端的数据,还是想向服务器发送数据。如果你是想从服务器上获取资源,建议使用GET
请求,如果你这个请求是为了向服务器提交数据,建议使用POST
请求。 - 大部分的 form 表单提交,都是
POST
方式,因为 form 表单中要填写大量的数据,这些数据是收集用户的信息,一般是需要传给服务器,服务器将这些数据保存/修改等。 - 如果表单中有敏感信息,还是建议使用
POST
请求,因为GET
请求会回显敏感信息到浏览器地址栏上。(例如:密码信息) - 做文件上传,一定是
POST
请求,因为要传的数据不是普通文本。 - 其他情况都可以使用
GET
请求。
- 怎么选择
不管你是
GET
请求还是POST
请求,发送的请求数据格式是完全相同的,只不过位置不同,格式都是统一的:name=value&name=value&name=value&name=value
- name 是什么?
- 以 form 表单为例:form 表单中 input 标签的 name。
- value 是什么?
- 以 form 表单为例:form 表单中 input 标签的 value。
2.2 模板设计模式
什么是设计模式?
- 某类相似问题的固定的解决方案(可以被重复使用)。
什么是模板设计模式?
- 在模板类的模板方法当中定义核心算法骨架,具体的实现步骤可以延迟到子类当中完成。
- 模板类通常是一个抽象类,模板类当中的模板方法定义核心算法,这个方法通常是
final
的(但也可以不是final
的)。 - 模板类当中的抽象方法就是不确定实现的方法,这个不确定怎么实现的事交给子类去做。
- 模板类通常是一个抽象类,模板类当中的模板方法定义核心算法,这个方法通常是
注:在“Java笔记”中有关于“模板设计模式”的阐述。
- 在模板类的模板方法当中定义核心算法骨架,具体的实现步骤可以延迟到子类当中完成。
2.3 ★★★HttpServlet源码分析
HttpServlet
类是专门为 HTTP 协议准备的,比GenericServlet
更加适合 HTTP 协议下的开发。HttpServlet
在哪个包下?jakarta.servlet.http.HttpServlet
到目前为止我们接触了 servlet 规范中哪些接口?
jakarta.servlet.Servlet
核心接口(接口)jakarta.servlet.ServletConfig
Servlet 配置信息接口(接口)jakarta.servlet.ServletContext
Servlet 上下文接口(接口)jakarta.servlet.ServletRequest
Servlet 请求接口(接口)jakarta.servlet.ServletResponse
Servlet 响应接口(接口)jakarta.servlet.ServletException
Servlet 异常(类)jakarta.servlet.GenericServlet
标准通用的 Servlet 类(抽象类)
http 包下都有哪些类和接口呢?
jakarta.servlet.http.HttpServlet
(HTTP 协议专用的 Servlet 类,抽象类)jakarta.servlet.http.HttpServletRequest
(HTTP 协议专用的请求对象)jakarta.servlet.http.HttpServletResponse
(HTTP 协议专用的响应对象)
HttpServletRequest
对象(简称 request 对象)中封装了什么信息?- 封装了请求协议的全部内容。
- Tomcat服务器(WEB服务器)将“请求协议”中的数据(GET、POST请求数据)全部解析出来,然后将这些数据全部封装到 request 对象当中了。
- 也就是说,我们只要面向
HttpServletRequest
,就可以获取请求协议中的数据。
HttpServletResponse
对象是专门用来响应 HTTP 协议到浏览器的。HttpServlet
源码分析:1
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105package com.f.javaweb.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.MessageFormat;
/**
* @author fzy
* @date 2023/11/23 21:44
* 根据创建的Servlet对象的生命周期来分析HttpServlet源码
*/
public class HelloServlet extends HttpServlet {
// 通过无参数构造方法创建对象
/*
public HelloServlet() {
}
*/
// 没有提供init方法,那么必然执行父类HttpServlet的init方法
// HttpServlet类中没有init方法,会继续执行GenericServlet类中的init方法
// 这里的init方法是 init()
// 没有提供service方法,那么必然执行父类HttpServlet的service方法
// 这里的service方法是 service(ServletRequest req, ServletResponse res)
// 而不是 service(HttpServletRequest req, HttpServletResponse resp)
// 而在HttpServlet的service(ServletRequest req, ServletResponse res)中,结尾会调用service(HttpServletRequest req, HttpServletResponse resp)方法
// 下面的这个service就是模板方法,在该方法中定义核心算法骨架,具体的实现步骤延迟到子类中去完成
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求方式
// 注意:request.getMethod()方法获取的是请求方式,可能是七种之一:
// GET POST PUT DELETE HEAD OPTIONS TRACE
String method = req.getMethod();
long lastModified;
// 如果请求方式是GET请求,则执行doGet方法。
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
// 如果请求方式是POST请求,则执行doPost方法。
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);
}
}
/*
通过以上源代码分析:
假设前端发送的请求是get请求,后端程序员重写的方法是doPost,子类没有实现doGet方法,会继续执行父类的doGet方法,父类的doGet方法会报405错误
假设前端发送的请求是post请求,后端程序员重写的方法是doGet
会发生什么呢?
发生405这样的一个错误。
405表示前端的错误,发送的请求方式不对。和服务器不一致。不是服务器需要的请求方式。
通过以上源代码可以知道:**只要HttpServlet类中的doGet方法或doPost方法执行了,必然405**.
怎么避免405的错误呢?
后端重写了doGet方法,前端一定要发get请求。
后端重写了doPost方法,前端一定要发post请求。
这样可以避免405错误。
这种前端到底需要发什么样的请求,其实应该后端说了算。后端让发什么方式,前端就得发什么方式。
有的人,你会看到为了避免405错误,在Servlet类当中,将doGet和doPost方法都进行了重写。
这样,确实可以避免405的发生,但是不建议,405错误还是有用的。该报错的时候就应该让他报错。
如果你要是同时重写了doGet和doPost,那还不如你直接重写service方法好了。这样代码还能
少写一点。
*/
}- 我们编写的
HelloServlet
继承HttpServlet
,直接重写HttpServlet
类的service()
方法行吗?- 可以,只不过你享受不到 405 错误,享受不到 HTTP 协议专属的东西,这些东西写在了
HttpServlet
类的service()
方法中,即上面的“只要HttpServlet类中的doGet方法或doPost方法执行了,必然405”。
- 可以,只不过你享受不到 405 错误,享受不到 HTTP 协议专属的东西,这些东西写在了
- ★到今天我们终于得到了最终的一个 Servlet 类的开发步骤:
- 第一步:编写一个
Servlet
类,直接继承HttpServlet
。 - 第二步:在编写的
Servlet
类中重写doGet
方法或者重写doPost
方法,到底重写谁,javaweb 程序员说了算。 - 第三步:将
Servlet
类配置到web.xml
文件当中。 - 第四步:准备前端的页面(form表单),form表单中指定请求路径即可。
- 第一步:编写一个
- 我们编写的
2.4 关于一个Web站点的欢迎页面
什么是一个 web 站点的欢迎页面?
对于一个 webapp 来说,我们是可以设置它的欢迎页面的。
设置了欢迎页面之后,当你访问这个 webapp 的时候,或者访问这个 web 站点的时候,如果没有指定任何“资源路径”,这个时候会默认访问你的欢迎页面。例如:
我们一般的访问方式是:
- http://localhost:8080/servlet06/login.html 这种方式是指定了要访问的就是
login.html
资源。
- http://localhost:8080/servlet06/login.html 这种方式是指定了要访问的就是
如果我们访问的方式是:
http://localhost:8080/servlet06 如果我们访问的就是这个站点,没有指定具体的资源路径。它默认会访问谁呢?
默认会访问你设置的欢迎页面。
怎么设置欢迎页面呢?
第一步:在 IDEA 工具的 web 目录下新建一个文件
login.html
。第二步:在
web.xml
文件中进行以下的配置:1
2
3
4
5
6
7
8
9
10
11
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<welcome-file-list>
<welcome-file>login.html</welcome-file>
</welcome-file-list>
</web-app>- 注意:设置欢迎页面的时候,这个路径不需要以 “/” 开始。并且这个路径默认是从 webapp 的根下开始查找。
第三步:启动服务器,浏览器地址栏输入地址:http://localhost:8080/servlet07
思考
如果在 webapp 的根下新建一个目录,目录中再给一个文件,那么这个欢迎页该如何设置呢?
在 webapp 根下新建 page1 目录
在 page1 下新建 page2 目录
在 page2 目录下新建
page.html
页面那么在
web.xml
文件中应该这样配置:1
2
3
4
5
6
7
8
9
10
11
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<welcome-file-list>
<welcome-file>page1/page2/page.html</welcome-file>
</welcome-file-list>
</web-app>- 注意:路径不需要以 “/” 开始,并且路径默认从 webapp 的根下开始找。
注意:一个 webapp 是可以设置多个欢迎页面的:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" version="6.0"> <welcome-file-list> <welcome-file>page1/page2/page.html</welcome-file> <welcome-file>login.html</welcome-file> </welcome-file-list> </web-app>
- Tomcat 服务器的全局欢迎页面是:`index.html`、`index.htm`、`index.jsp`。如果你一个 web 站点没有设置局部的欢迎页面,Tomcat 服务器就会以上面几个页面作为 web 站点的欢迎页面。 - 注意原则:局部优先原则(**就近原则**)。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
越靠上的页面优先级越高。找不到的继续向下找。
- 你有没有注意一件事:当我的文件名设置为 `index.html` 的时候,不需要在 `web.xml` 文件中进行配置欢迎页面。这是为什么?
- 这是因为 Tomcat 服务器已经提前配置好了。
实际上配置欢迎页面有两个地方可以配置:
- 一个是在 webapp 内部的 `web.xml `文件中(在这个地方配置的属于局部配置)。
- 一个是在 `CATALINA_HOME/conf/web.xml` 文件中进行配置(在这个地方配置的属于**全局配置**):
```xml
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
欢迎页可以是一个
Servlet
吗?当然可以。
你不要多想,欢迎页就是一个资源,既然是一个资源,那么可以是静态资源,也可以是动态资源。
静态资源:
index.html
、welcome.html
…动态资源:
Servlet
类。步骤:
第一步:写一个
Servlet
:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package com.f.javaweb.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author fzy
* @date 2023/11/24 22:15
*/
public class WelcomeServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.print("<h1>Welcome to Servlet page</h1>");
}
}第二步:在
web.xml
文件中配置servlet
。第三步:在
web.xml
文件中配置欢迎页:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<servlet>
<servlet-name>welcomeServlet</servlet-name>
<servlet-class>com.f.javaweb.servlet.WelcomeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>welcomeServlet</servlet-name>
<url-pattern>/a/b/c/d</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>a/b/c/d</welcome-file>
</welcome-file-list>
</web-app>
关于
WEB-INF
目录:注意:放在
WEB-INF
目录下的资源是受保护的,在浏览器上不能够通过路径直接访问。所以像HTML、CSS、JS、image 等静态资源一定要放到WEB-INF
目录之外。