- 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.ServletConfigServlet 配置信息接口(接口)jakarta.servlet.ServletContextServlet 上下文接口(接口)jakarta.servlet.ServletRequestServlet 请求接口(接口)jakarta.servlet.ServletResponseServlet 响应接口(接口)jakarta.servlet.ServletExceptionServlet 异常(类)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目录之外。