Servlet是什么?
Sun公司提供了Servlet这种技术供我们使用,Servlet(Server Applet 运行在服务端的小程序)是一个接口,定义了规范,我们需要去实现这个接口,然后由Tomcat服务器创建并且调用,运行在服务器端。
Servlet接口定义的是一套处理网络请求的规范,所有实现servlet的类,都需要实现它的五个方法,其中最主要init()、service()、destroy()三个方法,也就是说,所有实现servlet接口的类,或者说,所有想要处理网络请求的类,都需要执行这三个步骤!
Servlet工作机制
Tomcat架构
-
server层代表整个servlet容器,用于启动与监听服务端事件
-
service是由一个engine和一个或多个connector组成,这些connector共享一个Engine来处理请求
-
connector将在某个指定端口监听客户的请求,把从socket传送来的数据封装成request传递给Engine,并从Engine处获得响应返回给客户。
- Tomcat通常会用到两种Connector:
- Http Connector 在端口8080处侦听来自客户browser的http请求。
- AJP Connector 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求。
- Tomcat通常会用到两种Connector:
-
Engine负责处理来自相关联的service的所有请求,处理后返回给service,connector作为两者中间媒介出现,engine下可以配置多个虚拟主机,当engine获得一个请求时将这个请求匹配给对应的虚拟主机上处理
-
Host虚拟主机与某个网络域名(domain name)相匹配。一个主机下可以部署一个或者多个web应用,每个应用对应一个context,有一个context path。当host获得一个请求时将这个请求匹配到某个context上,将请求交给context处理,这种方法叫最长匹配。path==“”时即匹配所有无法匹配到context的请求。
-
context对应一个应用,由一个或多个servlet组成。context创建时将根据web.xml载入servlet类。
这是Tomcat的架构,然后介绍Tomcat是怎样启动的。对于engine, host, context来说,它们都属于容器,当接收到客户端请求的时候,请求会被传递到容器中,在一个容器中处理完毕之后,会被传递给下一个容器处理。因此,我们可以这样理解tomcat,总的来说,tomcat就是一种自上而下,一个容器里面又嵌套包含了另一个子容器的结构。所以,在tomcat启动的时候,我们也可以想象,它必定要先启动父容器,然后再启动子容器,在启动每一层容器的时候,还会启动容器中的一些相关组件,当所有的容器与组件都安装启动完毕,那么tomcat就启动完毕了~~
编写Servlet程序
public class Demo1 implements Servlet {
@Override
public void init(ServletConfig config) throw ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException{
System.out.println("service...");
}
@Override
public ServletInfo getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
可以知道有5个方法需要重写:init【初始化】、destroy【销毁】、service【服务】、getServletConfig【Servlet配置】、getServletInfo【Servlet信息】
Tomcat已经帮我们完成复杂的操作了,这样就不需要我们来写底层TCP连接了,Tomcat给我们返回三个对象:ServletConfig、ServletRequest、ServletResponse:
-
ServletConfig:
-
通过反射,将web.xml文件中的
<init-param></init-param>
中的数据打包成ServletConfig对象了
-
-
ServletRequest:
- 将浏览器发送过来的请求报文封装为ServletRequest对象,我们可以使用他的方法来获取报文信息
-
ServletResponse:
-
Tomcat将ServletResponse对象传给Servlet对象时,是空的对象,经过Servlet逻辑处理后得到结果,最终通过response.write()方法,将结果写入response内部的缓冲区。Tomcat会在servlet处理结束后,拿到response,遍历里面的信息,组装成HTTP响应发给客户端。
-
配置Servlet
要想让Tomcat能创建该Servlet对象,需要再在web.xml文件中,配置如下代码,使得Tomcat服务器可以找到这个Servlet类且创建它(Servlet3.0支持使用注解@WebServlet来配置)
<servlet>
<!-- 为Servlet起一个名字(一般是和类名是一样的) -->
<servlet-name>MyServlet</servlet-name>
<!-- 类的存储具体位置,要写上包名 -->
<servlet-class>top.linzeliang.servlet.MyServlet</servlet-class>
</servlet>
<!-- 配置Demo1的映射路径 -->
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<!-- 外界通过访问MyServlet的资源路径 -->
<url-pattern>/MyServlet(这是资源路径,不是虚拟目录)</url-pattern>
</servlet-mapping>
同一个Servlet可以被映射到多个URL上:
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>top.linzeliang.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet2</url-pattern>
</servlet-mapping>
无论是使用/MyServlet1资源路径还是/MyServlet2资源路径,都会创建Demo1的实例
执行原理:
- 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
- 查找web.xml文件中的
<url-pattern>
标签体内容是否与请求的资源路径相同 - 如果有,则通过
servlet-name
在找到对应的<servlet-class>
全类名(src目录下的) - tomcat会将字节码文件加载进内存,并且创建该Servlet的实例
- 然后开始调用Servlet对象的方法
使用Servlet3.0注解@WebServlet来配置Servlet:
// WebServlet注解源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
//相当于<Servlet-name>
String name() default "";
//代表urlPatterns()属性配置
String[] value() default {};
//相当于<url-pattern>
String[] urlPatterns() default {};
//相当于<load-on-startup>
int loadOnStartup() default -1;
WebInitParam[] initParams() default {};
boolean asyncSupported() default false;
String smallIcon() default "";
String largeIcon() default "";
String description() default "";
String displayName() default "";
}
-
@WebServlet
- @WebServlet(urlPatterns="/资源路径") 直接在这里写资源路径即可,因为资源路径是最重要的,所以如果只有一个值的话不需要写参数名
- @WebServlet({"/资源路径1", “/资源路径2”, “/资源路径3”}) 一个Servlet可以定义多个访问路径
- 路径定义规则:
- /xxx:路径匹配
- /* 代表通配符,任何资源路径都可以访问该Servlet
- /xxx/xxx:多重路径匹配
- *.do:扩展名匹配
- /xxx:路径匹配
-
如果
*.扩展名
和正斜杠(/)开头并以“/*”结尾
两种通配符同时出现,匹配的是哪一个?-
看谁的匹配度高,谁就被选择
-
*.扩展名
的优先级最低
-
-
Servlet映射的URL可以使用通配符和Servlet可以被映射到多个URL上的作用:
-
隐藏网站是用什么编程语言写的【.php,.net,.asp实际上访问的都是同一个资源】
-
用特定的后缀声明版权【公司缩写】:
<servlet> <servlet-name>Demo1</servlet-name> <servlet-class>top.linzeliangtop.web.Demo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>Demo1</servlet-name> <url-pattern>*.jsp</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Demo1</servlet-name> <url-pattern>*.net</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Demo1</servlet-name> <url-pattern>*.asp</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Demo1</servlet-name> <url-pattern>*.php</url-pattern> </servlet-mapping>
-
Servlet继承体系结构
继承HttpServlet编写Servlet程序
一般我们开发时候,都是继承HttpServlet抽象类,而不是去实现Servlet接口。然后,一般重写doGet和doPost方法(其他的doXxx方法不常用)
Servlet生命周期
- 加载Servlet,Tomcat在第一次访问时创建Servlet实例
- 当Servlet实例被创建后,Tomcat会调用init方法来初始化对象(init()方法只在创建对象后调用一次)
- 然后Tomcat调用Servlet中的service()方法来处理浏览器的请求
- 当Tomcat关闭时或者检测到Servlet要从Tomcat删除的时候会自动调用destroy()方法(destroy()方法先调用,再销毁Servlet对象),释放掉所占的资源。一个Servlet如果长时间不被使用的话,也会被Tomcat自动销毁。
- 最后Servlet对象被回收
- Servlet的init方法:
- 只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的。当多个用户同时访问时,可能存在线程安全问题。所以尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值
- Servlet对象的创建时机(在
<servlet>
标签下配置):- 第一次被访问时,创建(默认情况下,第一次被访问时,Servlet被创建)
*<load-on-startup>
的值为负整数,可以为-1 - 在服务器启动时,创建
<load-on-startup>
的值为0或正整数
- 第一次被访问时,创建(默认情况下,第一次被访问时,Servlet被创建)
HTTP基础
- 什么是HTTPHyper Text Transfer Protocol 超文本传输协议
- 传输协议:定义了,客户端和服务器端通信时,发送数据的格式
- 特点:
- 基于TCP/IP的高级协议
- 默认端口号:80
- 基于请求/响应模型的:一次请求对应一次响应
- 无状态的:每次请求之间相互独立,不能交互数据
- 历史版本:
- 1.0:每一次请求响应都会建立新的连接
- 1.1:复用连接
- 请求消息数据格式
-
请求行
请求方式 请求url 请求协议/版本
GET /login.html HTTP/1.1- 请求方式:
- HTTP协议有7中请求方式,常用的有2种
- GET:
- 请求参数在请求行中,在url后。
- 请求的url长度有限制的
- 不太安全
- POST:
- 请求参数在请求体中
- 请求的url长度没有限制的
- 相对安全
- GET:
- HTTP协议有7中请求方式,常用的有2种
- 请求方式:
-
请求头:客户端浏览器告诉服务器一些信息
请求头名称: 请求头值- 常见的请求头:
-
User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
- 可以在服务器端获取该头的信息,解决浏览器的兼容性问题
-
Referer:http://localhost/login.html
- 告诉服务器,我(当前请求)从哪里来?
- 作用:
- 防盗链:
- 统计工作:
- 作用:
- 告诉服务器,我(当前请求)从哪里来?
-
- 常见的请求头:
-
请求空行
空行,就是用于分割POST请求的请求头,和请求体的。 -
请求体(正文):
- 封装POST请求消息的请求参数的
- 字符串格式:
POST /login.html HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
-