文章目录
1.整体结构
2.常用方法
2.1Servlet常用方法
void init(ServletConfig config)
:初始化void service(ServletRequest request, ServletResponse response)
:服务 处理业务逻辑void destroy()
:销毁- ServletConfig getServletConfig() :获取当前servlet的配置对象
2.2 GenericServlet常用方法
- 除了
service
方法没有具体实现,其余都实现了 空参的Init() 若我们自己想对servlet进行初始化操作,重写这个init()方法即可
- 查看该
init()
方法的源码- 1.进入HttpServlet
- 2.进入 GenericServlet
- 3.找到
init
方法
- 1.进入HttpServlet
2.3HttpServlet常用方法
-
service
做了实现,把参数进行强制转换,调用了重载的service方法 -
重载的
servide
方法获取请求的方式,根据请求的不同调用相应的doGet()/doPost()
方法 -
查看源码
-
public void service(ServletRequest req, ServletResponse res)
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { //强转 request = (HttpServletRequest)req; response = (HttpServletResponse)res; } catch (ClassCastException var6) { throw new ServletException("non-HTTP request or response"); } //调用这个重载的方法 this.service(request, response); }
-注意参数类型
- 进入重载的
service
protected void service(HttpServletRequest req, HttpServletResponse resp)
- 注意参数类型
- 先获取请求的方法
GET/POST
- 然后根据方法做判断
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
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")) {
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);
}
}
3.Servlet生命周期(重要)
定义一个类
LifeServlet
,继承Servlet
接口,实现init(),service(),destroy()
方法,来说明servlet的生命周期
3.1定义一个类LifeServlet
package com.zqx.c_life;
import javax.servlet.*;
import java.io.IOException;
/**
* 20190810
* 实现Servlet接口
* 说明 Servlet的生命周期
*/
public class LifeServlet implements Servlet {
/**
* 初始化方法
* 执行者:服务器
* 执行次数:一次
* 执行时机:默认第一次访问的时候
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("5555555555555555");
}
/**
* 服务
* 执行者:服务器
* 执行次数:请求一次执行一次
* 执行时机:请求来的时候
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("666666666666666");
}
/**
* 销毁
* 执行者:服务器
* 执行次数:只执行一次
* 执行时机:当servlet被移除的时候或者服务器正常关闭的时候
*/
@Override
public void destroy() {
System.out.println("4444444444444444");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
}
3.2html页面
<a href="/servlet/life?name=tom">生命周期</a>
3.3web.xml
<servlet>
<servlet-name>LifeServlet</servlet-name>
<servlet-class>com.zqx.c_life.LifeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LifeServlet</servlet-name>
<url-pattern>/life</url-pattern>
</servlet-mapping>
3.4观察结果
3.5小结
void init(ServletConfig config):初始化
- 初始化方法
- 执行者:服务器
- 执行次数:一次
- 执行时机:
默认
(说明可以自己设置)第一次访问的时候 - 只执行一次说明一个Servlet在内存中只存在一个对象,Servlet是单实例的
- 当多个用户访问一个Servlet中的全局变量时,可能存在线程安全问题
- 解决:尽量不要再Servlet中定义全局变量,即使定义了,也不要修改值,只对其访问即可
void service(ServletRequest request,ServletResponse response):服务 处理业务逻辑
- 服务
- 执行者:服务器
- 执行次数:请求一次执行一次
- 执行时机:请求来的时候
void destroy():销毁
- 销毁
- 执行者:服务器
- 执行次数:只执行一次
- 执行时机:当servlet被移除的时候或者服务器正常关闭的时候
servlet是单线程多实例,默认第一次访问的时候,服务器创建servlet,并调用init方法实现初始化,并调用一次service方法, 每当有新的请求,服务器创建一个线程,调用service方法来执行自己的业务逻辑,当当serlvet被移除的时候服务器正常关闭的时候,服务器调用servlet的destroy方法实现销毁操作.
4.url-pattern配置
创建一个servlet后,这个servlet要被访问到,必须在web.xml中进行配置,其中有一个
<url-pattern>
的标签确定访问一个servlet的路径
4.1一个servlet可以被多个路径映射
<servlet>
<servlet-name>LifeServlet</servlet-name>
<servlet-class>com.zqx.c_life.LifeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LifeServlet</servlet-name>
<url-pattern>/life</url-pattern>
</servlet-mapping>
<!--一个servlet可以被不同的路径映射-->
<servlet-mapping>
<servlet-name>LifeServlet</servlet-name>
<url-pattern>/life01</url-pattern>
</servlet-mapping>
- 上述例子说明
com.zqx.c_life.LifeServlet
可以被路径/life
和/life01
访问到
4.2的三种写法
完全匹配:必须以”/”开始,例如: /hello /a/b/c
目录匹配:必须"/"开始 以"*"结束 例如: /a/* /*
后缀名匹配 以"*"开始 以字符结尾 例如: *.jsp *.do *.action
优先级:完全匹配>目录匹配>后缀名匹配
4.3测试
假设:
- Servlet1 映射到 /abc/*
- Servlet2 映射到 /*
- Servlet3 映射到 /abc
- Servlet4 映射到 *.do
问: - 当请求URL为“/abc/a.html”,“/abc/”和“/”都匹配,哪个servlet响应
- 完全匹配>目录匹配
- Servlet引擎将调用Servlet1。
- 当请求URL为“/abc”时,“/*”和“/abc”都匹配,哪个servlet响应
- 完全匹配 > 目录匹配
- Servlet引擎将调用Servlet3。
- 当请求URL为“/abc/a.do”时,“/abc/”和“.do”都匹配,哪个servlet响应
- 目录匹配> 后缀匹配
- Servlet引擎将调用Servlet1。
- 当请求URL为“/a.do”时,“/”和“.do”都匹配,哪个servlet响应
- 目录匹配>后缀匹配
- Servlet引擎将调用Servlet2.
- 当请求URL为“/xxx/yyy/a.do”时,“/”和“.do”都匹配,哪个servlet响应
- 目录匹配>后缀匹配
- Servlet引擎将调用Servlet2。
4.4tomcat中的tomcat/conf/web.xml
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
- 只要访问时后缀名是jsp或jspx就会执行名称叫jsp的servlet内容,这是一个很典型的扩展名匹配效果
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
这时<url-pattern>它的值就是”/”那么这时它就是一个默认(缺省)的servlet.。 默认的servlet其作用是用于处理其它的servlet处理不了的请求。
5.load-on-satrtup
前面说到一个servlet的生命周期的时候,
init
方法的执行时间是默认
第一次访问的时候,通过对某个Servlet的配置,可以改变这个方法的执行时间
5.1基础
load-on-startup
是servlet标签下的一个子标签- 用来修改servlet的初始化时间
- 值为负数时,第一次访问时创建
- 值为正整数,在服务器启动的时候就被创建,
值越小优先级越高
- 实例:
<servlet> <servlet-name>LifeServlet</servlet-name> <servlet-class>com.zqx.c_life.LifeServlet</servlet-class> <load-on-startup>3</load-on-startup> </servlet>
- 效果
- 可以看到,在服务器启动的时候,
LifeServlet
的init
方法就已经被调用了 - 适用于在项目启动的时候,需要做一些初始化的操作,可以通过这样的方式来设置
5.2 tomcat中的web.xml
5.2.1访问项目里不存在的资源
- 首先,一个有趣的例子,当我们在浏览器访问一个项目中没有进行配置过的路径
- 虽然返回的是404,但是这个页面仍然是有内容的和响应消息,这个内容是谁发送到这里的呢?
就是tomcat
服务器 - 那么这个过程是如何响应的呢?
tomcat
服务器是如何完成这个响应的呢? - 查看
tomcat/conf/web.xml
,发现有这一段配置信息:
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
- 访问一个路径的时候,当项目中的配置文件没有指定配置的时候,
会查找tomcat的web.xml
- 这说明项目中的
web.xml
和tomcat的web.xml
直接存在一种继承关系
,优先查找项目里的web.xml,如果没有找到,就会去tomcat的web.xml中查找
5.2.2访问index.html
- 同样我们没有对index这个路径进行过配置吗,但是仍然访问可以出现页面
- 这也是因为tomcat的web.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>
6.路径的写法
- 相对路径
- 当前路径:
./
或者 不写 - 上一级路径:
../
- 当前路径:
- 绝对路径:
- 带主机的和协议的绝对路径:
http://www.baidu.com
- 不带主机和协议的绝对路径:
/servlet/hello
经常使用
- 带主机的和协议的绝对路径: