文章目录
1. Servlet
注意Servlet类是单例模式,即每个对应的Servlet子类只能有一个实例
1.1 Servlet在服务器充当的角色
Servlet运行流程图
1.2 客户端的请求方式分类
1.3 Servlet类的继承关系、以及方法介绍
将处理HTTP请求的Servlet一般需继承该抽象类,因为其有对Http协议的处理
封装HTTP请求报文
封装HTTP回应报文
1.4 ServletContext、ServletConfig、Servlet
- 一个Web项目(也叫Web应用)对应一个ServletContext
- 启动项目时就自动创建ServletContext实例
- 当前项目下的所有Servlet共享这个ServletContext实例 - 意味着同项目下Servlet数据共享
- ServletContext-path:localhost:8080/项目名
- 启动项目时就自动创建ServletContext实例
- 每个ServletConfig对应Servlet
- 存储Web.xml中的 子标签下的键值对、以及Servlet类名
- 存储Servlet的上下文
- 应用:可存储数据库的连接字符串、到时页面请求时可从ServletConfig中直接拿连接字符串即可
- 存储Web.xml中的 子标签下的键值对、以及Servlet类名
- Servlet根据ServletConfig的信息进行实例化
根据上图的信息即是下面代码输出的信息
代码演示
public class ConfigTest extends HttpServlet{
ServletConfig config;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
this.config = config;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(config.getServletName()); // Servlet子类名
List<String> list = Collections.list(config.getInitParameterNames()); // 初始参数名容器
System.out.println(list); // 打印所有初始的参数名
for(String str : list) {
System.out.println(str + ": " + config.getInitParameter(str)); // 返回当前Servlet的参数键值对
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp);
}
}
1.4 客户端、servlet容器、servlet对象 三者间请求回应关系
Servlet容器管理所有的servlet对象 - 故客户端是与服务器的Servlet容器进行交流
如果指定的load-on-startup没有设置,则只有HTTP请求的时候才创建、只要该属性设置了,服务器启动就会自动的实例化该servlet对象
sequenceDiagram
客户端 ->> Servlet容器: 1. HTTP请求
alt servlet寻找不到
Servlet容器 ->> Servlet: 2. 创建实例 - init()
end
Servlet容器 ->> Servlet: 3. HTTP处理 - service()
Servlet ->> Servlet容器: 4. 处理信息
Servlet容器 ->> 客户端: 5. Http报文回复
Servlet容器 ->> Servlet: 6. 销毁Servlet - destory()
1.5 同一Servlet对象多线程访问
2. 客户端请求方式
HTML代码实例
<!--from中的action即将表单的数据送到目的url、method:数据的传输方式-->
<form action="./formProcess.html" method="get">
姓名:<input type="text">
<br/>
密码:<input type="password">
<br/>
<input type="submit">"
</form>
Servlet代码实例
@WebServlet(urlPatterns = "/formProcess.html") // 设定该Servlet对象的访问域名
public class FormProcess extends HttpServlet { // 继承HttpServlet就是Servlet子类
@Override
protected void getRestult(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8"); //
PrintWriter pw = resp.getWriter();
Enumeration<String> ParameterNames = req.getParameterNames();
List<String> list = Collections.list(ParameterNames);
pw.write(list.toString());
pw.write("<br>");
for (String name : list) {
pw.write(name + ":" + req.getParameter(name) + "<br>");
}
pw.close();
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
getRestult(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
getRestult(req, resp);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp);
}
}
1. 当提交上面的表单后即method=“get”,action的URL在地址栏的表现
2. 当修改上面的表单请求方法并提交后即method=“post”,表单内的数据在HTTP请求体里面
3. PrintWriter.close()
一旦关闭,HTTP响应报文不能在更改、已经为提交状态 - 故一般将此方法放在servicec后面
代码测试
1. index2.html页面
<body>
<a href="./close.do">printWriter.close()测试</a>
</body>
2. clsoe.do页面
@WebServlet(
description = "测试printWriter.close()方法",
urlPatterns = { "/close.do" }
)
public class TestClose extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
super.service(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter pw = response.getWriter();
response.setContentType("text/plain"); // 页面显示内容编码第一次更改
pw.write("<h1>I love Tomcat</h1>");
pw.close(); // printWriter提前关闭
response.setContentType("text/html"); // 页面显示内容编码第二次更改
}
}
页面显示结果
1. 点击index2.html页面的超链接 - F12查看Network请求、响应资源信息
2. TestClose中的pw.close()放置doGet()末尾,再重复上述1步骤
4. 重定向、请求分派的区别
Servlet容器的root路径:http://localhost:8080/ 等价于 /
Servlet的上下文路径:http://localhost:8080/项目名 → req.getContextPath()
./ = 直接写子域名:点表示当前地址栏最后一个斜杠前的所有字符串
4.1 重定向
不管你是相对还是绝对URL,系统都会自动帮你转为绝对URL
重定向时序图:客户端请求多次
/:斜杆即是 http://llocalhost:8080
代码实例:resp.sendRedirect( String )
@WebServlet(
name = "RedirectServlet",
urlPatterns = { "/redirect/one.do" }
)
public class Redirect extends HttpServlet {
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req,resp);
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("/JavaWeb_learning/index2.html");
// 重定向可写成地址: ../index2.html 或者 req.getContextPath + "/index2.html"
}
}
运行上述代码步骤
-
地址栏输入:http://localhost:8080/JavaWeb_learning/redirect/one.do
-
然后自动会跳转到 index2.html 页面
-
可看到下图客户端发了两次HTTP请求
4.2 请求分派
path:只能写相对URL
/ : 斜杆即是 http://llocalhost:8080/项目名
代码实例:req.getRequestDispatcher( String ).forward( req, resp )
index2.html页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>分派后的页面</h1>
</body>
</html>
Servlet子类
@WebServlet(urlPatterns = {"/dispatch.do"})
public class Dispatch extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
RequestDispatcher d = req.getRequestDispatcher("./index2.html");
d.forward(req, resp);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp);
}
}
运行上述代码步骤
-
地址栏输入:http://localhost:8080/JavaWeb_learning/dispatch.do
-
然后自动会跳转到 index2.html 页面、并且地址栏依然是1的请求URL
-
可看到下图客户只发出一次HTTP请求、并且返回的内容不是dispatch.do的内容而是 index2.html的内容