备注:该技术博客的内容是我根据技术视频整理与总结的(并非复制粘贴)。原视频源于黑马JavaWeb课程
Servlet再Javaweb中显得特别重要,整个Javaweb核心知识体系都是围绕servlet转的。一定要重点掌握。虽然很重要,但是并不难。
首先介绍一下什么是servlet:
servlet是由两个单词拼接而成(server applet)直译过来就是运行在服务器端的小程序,servlet就是一个接口(定义了一些方法),定义了Java类被浏览器访问到(tomcat识别)的规则。将来我们自定义一个类实现这个servlet接口重写它的方法,就可以被tomcat识别。我们将这个类称为Servlet
public class ServletDemo1 implements Servlet
怎么配置Serlvet呢?当然是在web-xml文件中的根标签(web-app) 中配置:
<servlet>
<servlet-name>demo1servlet-name> (随便起个名字)
<servlet-class>cn.itcast.web.servlet.ServletDemo1servlet-class> (全类名)
servlet>
<servlet-mapping> (做一个映射)
<servlet-name>demo1servlet-name> (对应上面的名字)
<url-pattern>/demo1url-pattern> (资源路径)
servlet-mapping>
配置完成之后我们重新连接Tomcat服务器运行,然后在页面中输出:http://localhost:8080/demo1
回到控制台可以发现,自动调用了service方法。
讲解完Servlet快速入门之后,我们发现我们定义一个类,这个类我们并没有创建对象,也没有调用它的方法,它竟然自动被执行了。为什么?
我们已画图的方式来讲解:
首先我们通过localhost:8080找到了具体某个主机,以及某个应用程序(根据8080找到Tomcat)
通过day13_tomcat可以找到当前tomcat下部署的这个项目(根据虚拟目录找到项目)。找到项目后接下来跟个资源名称 /demo1 。tomcat内部会做一个检索的操作,会查找web.xml文件中是否有url-patten 是/demo1,它会自己解析xml文件。
突然发现找到/demo1了,发现资源路径是一样的。然后通过/demo1这个路径找到了servlet-name的demo1 ,进而找到全类名(cn.itcast.web.servlet.ServletDemo1)。只要看到全类名在配置文件中存在,第一件事就要想到反射。
接下来tomcat进行了一些操作:
那么Tomcat怎么知道这个类中一定有一个方法叫做service呢?因为我们实现了Servlet接口,这个接口一定会有service方法。如果我们不重写service方法,这个类编译都不会通过的。tomcat一定知道这个类中有service方法,所以调用service方法。
所以我们以后不需要创建Servlet实现类对象,也不需要调方法。我们只需要按照人家规定的方法结构,把方法实现了,在里面编写我们想要的逻辑就可以了。(对象的创建,方法的调用都是由Tomcat服务器执行的)
也就是说,Servlet的运行要依赖web容器(tomcat就是一个web容器)。不在这个容器中,就没人帮Servlet创建对象,调用方法,就没法运行了。这就是我们所说的Servlet实现原理。
分析完执行原理之后,接下来聊聊Servlet中的方法。这个方法会涉及到Servlet中的知识点,就是Servlet中的生命周期方法。
package cn.itcast.web.servlet;
import javax.servlet.*;
import java.io.IOException;
//Servlet的方法
public class ServletDemo2 implements Servlet {
/**
* 初始化方法
* 在Servlet被创建时,执行。只会执行一次
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init....");
}
/**
* 获取ServletConfig对象(了解即可)
* ServletConfig:Servlet的配置对象
* @return
*/
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 提供服务方法
* 每一次Servlet被访问时候执行。执行多次
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service....");
}
/**
* 获取Servlet的一些信息,版本,作者等...(了解即可)
* @return
*/
@Override
public String getServletInfo() {
return null;
}
/**
* 销毁方法
* 在服务器正常关闭时候执行,执行一次
*/
@Override
public void destroy() {
System.out.println("destroy....");
}
}
介绍了Servlet中5个方法,我们重点介绍了生命周期相关的三个方法。接下来我们就对生命周期中一些特点,做一个阐述:
多个用户同时访问时,可能存在线程安全问题。(不能用锁机制,性能影响严重)
解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对其修改值。
Servlet什么时候创建?
默认情况下,第一次被访问时,Servlet被创建
我们可以去配置指定Servlet创建时机,在servlet标签下配置load-on-startup
<servlet>
<servlet-name>demo2servlet-name>
<servlet-class>cn.itcast.web.servlet.ServletDemo2servlet-class>
<load-on-startup>-5load-on-startup>
servlet>
提供服务:执行service方法,执行多次
每次访问Servlet时,service方法都会被调用一次
被销毁:执行destroy方法,执行一次(因为Servlet只会被杀死一次)
Servlet被销毁之前,执行destory方法,一般用于释放资源。
服务器被关闭时,Servlet被销毁。
只有服务器正常关闭时,才会执行destory方法。
我们可以发现快速入门中的第四步配置Servlet很麻烦,将来写一个Servlet就要配置一次。但是一个项目可能会有几百个Servlet,需要在web.xml配置文件中配很多,而且非常的混乱。
所以要解决这个问题,官方给我提供一个新的标准:就是Servlet3.0
3.0版本最大的好处就是支持注解配置。可以不需要web.xml了。
步骤:
@WebServlet(“资源路径(也就是url-patten)”)
将来我们写具体Servlet代码时候,就使用注解配置,别去用配置文件web.xml
介绍完使用注解方式对Servlet进行配置,接下来说一下idea与tomcat相关配置。
讲这个配置是为了方便大家后期更好的使用IDEA和Tomcat集成。
查看控制台的log:
Using CATALINA_BASE: “C:\Users\XuZhibin\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat_untitled8_2”
tomcat真正访问的是Tomcat部署的web项目,这个项目对应着工作空间项目的web目录下的所有资源
WEB-INF目录下的资源不能被浏览器直接访问
Servlet接口有两个实现类(GenericServlet,HttpServlet)
GenericServlet实现了Servlet接口,它是一个抽象类
HttpServlet继承了GenericServlet,它也是一个抽象类
首先来说GenericServlet。将来如果我去写一个Servlet,我可以不去实现这个Servlet接口,直接继承GenericServlet也是可以的。
1.GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象。
也就是说将来定义Servlet类时,可以继承GenericServelt类,实现service()方法即可。
@WebServlet("/demo2")
public class ServletDemo2 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("demo2.....");
}
}
这是第二种方式,但是我们还是不用(第一种方式实现Servlet接口)。
2.我们用HttpServlet类
将来如果想去屏蔽GET/POST请求方式的处理逻辑,我们可以去继承HttpSerlet类,并且去重写doGet方法和doPost方法就可以了。因为将来都是调用service方法,该方法会做方法分发,你是get就调用doGet,你是post就会调用doPost。
HttpServlet类:对http协议的一种封装,简化操作。
使用步骤如下:
@WebServlet("/demo3")
public class ServletDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet.....");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost.....");
}
}
一个Servlet可以定义多个访问路径
@WebServlet({"/d4","/dd4","/ddd4"})
路径的定义规则:
- /xxx
- /xxx/xxx :多层路径,目录结构
- *.do