1.Tomcat(Http服务器,Http Container)
1.对下,实现了HTTP协议,服务器端,可以通过网络和客户端进行通信
2.对上,是实现了java规定的Servlet协议(Java 规定了几个interface)Tomcat定义了这些接口的实现类
2.Web应用的文件结构(docBase) 404 问题
WEB-INF web应用下的配置,类文件,依赖文件
—web.xml --XML格式的,用于web应用的配置
class\ 用户自定义类(业务类)的ClassPath
.calss
lib\一类是.class文件 一类是.jar文件
3.Tomcat(Servlet)中如何区分不同的web应用(webapp)
1.web app | Context | ServletContext
Tomcat通过URL中的第一部份 Http://127.0.0.1:8080/hello/login
Tomcat通过URL中的后面部份 Http://127.0.0.1:8080/hello/login
Servlet对象(动态文档 | 动态文档)
1.根据web.xml中的配置去查找
—1.根据url找到对应的servlet-mapping(映射关系)->servlet
—2.根据servlet名字找到对应的Servlet的类
2.静态文档
直接在docBase为相对路径查找
4.请求是如何从浏览器到你的Servlet的代码的(动态的说是Servlet的对象)
1.结合网络2.结合Tomcat的分用逻辑
Tomcat和Servlet的其他重要信息:
1.Servlet(interface)(主要用于TCP|UDP业务的)
–Servlet(interface)下的一个HttpServlet(abstract class)
2.Servlet
init()初始化用的
service()每次提供服务是调用的
destroy()销毁是使用
Servlrt对象的生命周期:
Tomcat:启动流程
1.读取conf下的配置文件
2.监听8080端口(server.xml)
3.扫描目录(webapps)
读取并解析zhaoyanlong\WEB-INF\web-xml
4.进行Servlet对象的初始化
(每一个Servlet类在进程运行过程中有且仅有一个对象:单例模式)
调用Servlet对象的init()方法
5.定义了Map<url,Servlet名称>
Map<Servlet名称,Servlet对象>
先使用url获取,名称然后再换取到对象。
6.Socket socket =ss.accpet();
为了并发能力,Tomcat使用了多线程处理各个请求
7.每个线程中
1.从socket的inputStream读取内容
2. 按照HTTP协议,解析请求
3.构造一个HttpServletRequest对象
4.构造一个HttpServletResponse对象
5.根据url找对应的Servlet对象去处理
0.根据url中的第一部分,先确定哪一个context(ROOT)无前缀
1.看是否能根据两个Map找到对应的Servlet对象
2.再给一个静态资源的机会,(就是在docBase找文件)
找不到就404了
6.去调用该Servlet对象的service()方法
HttpServlet实现了service方法,根据HTTP方法分别调用
doGET/doPost/doPut/doDelete
7.我们自己做的Servlet中填充response的内容
8.把response按照HTTP协议,发送给socket.outputStream
8.当退出时
遍历所有的的Servlet对象,调用他们的destroy()方法
总结:对于Servlet对象的生命周期(只有一个Servlet对象)
init()/destroy()只会被调用一次
service()每次服务就会调用一次(会被调用多次)
2.使用service的时候,是在多线程环境下工作(考虑线程安全)
Annotation 注解:@WebServlet()
public @interface MyAnnotation {
}
@MyAnnotation
public class MyMain {
}
使用注解后就可以不需要的web.xml文件中配置,会直接获取注解中信息。
Servlet API有以下三个java包:
javax.servlet(重点):其中包含定义Servlet和Servlet容器之间的类和接口
javax.servlet.http(重点):其中包含定义HTTP Servlet和Servlet容器之间的类和接口
javax.servlet.annotation:其中包含标注Servlet,Filter,Listener的注解
disable cache 为了减少服务器的访问量,会在浏览器中有一个缓存池,访问相同连接,会直接从池中读信息,需要注意ctrl+F5
如果使用GET方法不能有请求体个人输入的信息会随着QueryString一起显示出来。
使用post的话,会出现在正文中。
测试代码:
FirstServlet
package com.zhaoyanlong;
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;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;
@WebServlet("/first")
public class FirstServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
out.println("<table>");
out.println("<thead>");
out.println("<tr>");
out.println("<th>名称</th>");
out.println("<th>值</th>");
out.println("</tr>");
out.println("</thead>");
out.println("<tbody>");
String method=req.getMethod();
tr(out, "Method", method);
String pathInfo = req.getPathInfo();
tr(out, "PathInfo",pathInfo);
String pathTranslated = req.getPathTranslated();
tr(out, "PathTranslated",pathTranslated);
String contextPath = req.getContextPath();
tr(out, "ContextPath",contextPath);
String queryString = req.getQueryString();
tr(out,"QueryString" ,queryString);
String requestURI = req.getRequestURI();
tr(out,"RequestURL" ,requestURI );
Map<String, String[]> parameterMap = req.getParameterMap();
for (Map.Entry<String,String[]> entry:parameterMap.entrySet()) {
for (String val:entry.getValue()) {
tr(out, entry.getKey(),val);
}
}
System.out.println(req.getParameter("你好"));
System.out.println(Arrays.toString(req.getParameterValues("你好")));
Enumeration<String> headerNames = req.getHeaderNames();
//只要有更多元素就去遍历
while (headerNames.hasMoreElements()){
//我们可以拿到name
String name=headerNames.nextElement();
//通过name拿到val 现在拿到的还是数组
Enumeration<String>heads=req.getHeaders(name);
while (heads.hasMoreElements()){
//拿到每一个val
String val=heads.nextElement();
tr(out, name,val);
}
}
out.println("</tbody>");
out.println("</table>");
}
private void tr(PrintWriter out,String name,String val){
out.println("<tr>");
out.printf("<td>%s</td>",name);
out.printf("<td>%s</td>",val);
out.println("</tr>");
}
}
LoginServlet
package com.zhaoyanlong;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicInteger;
public class LoginServlet extends HttpServlet {
//统计接口被调用此时
//结合Servlet的生命周期理解多线程中存在共享变量
//private int count=0;错误
private AtomicInteger count=new AtomicInteger();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
//请求就是告诉编码返回时以同类型返回
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
PrintWriter out=resp.getWriter();
out.println("<h1>2020</h1>");
out.printf("<p>被访问次数:%d</p>",count.getAndIncrement());
}
}
SecondServlet
package com.zhaoyanlong;
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;
import java.io.PrintWriter;
@WebServlet("/second")
public class SecondServlet extends HttpServlet {
//通过表单来提交
private void run(HttpServletRequest req, HttpServletResponse resp) throws IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
PrintWriter out=resp.getWriter();
String username=req.getParameter("username");
String password=req.getParameter("password");
out.println("<h1>"+req.getMethod()+"</h1>");
out.println("<p>用户名:"+username+"</p>");
out.println("<p>密码:"+password+"</p>");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
run(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
run(req,resp);
}
}
index.css
h1{
font-size: 50px;
color: aqua;
background: blue;
}
index.js
alert("wansui")
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.zhaoyanlong.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
index.html
<!DOCTYPE html>
<html>
<head>
<title>中华人民</title>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html: char; charset=utf-8"/>
<script src="js/index.js"charset="UTF-8"></script>
<link rel="stylesheet"type="text/css"href="css/index.css">
</head>
<body>
<h1>成立l</h1>
<a href="login">站起来</a>
</body>
</html>
Login.html
<!DOCTYPE html>
<html lang="zh-hans">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form method="post"action="/second">
<label for="username">用户名:</label>
<input type="text"name="username" placeholder="请填写用户名"/>
<label for="password">密码:</label>
<input type="password" name="password" placeholder="请输入密码"/>
<input type="submit"value="登录"/>
</form>
</body>
</html>
table.html
<meta charset="UTF-8"/>
<table>
<thead>
<tr>
<th>姓名</th>
<th>赵</th>
</tr>
</thead>
<tbody>
<tr>
<td>年龄</td>
<td>18</td>
</tr>
<tr>
<td>生日</td>
<td>0101</td>
</tr>
<tr>
<td>爱好</td>
<td>篮球</td>
</tr>
</tbody>
</table>