1.什么是Servlet?
Servlet(Server Applet)是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
既然Servlet是一个接口,那么我们知道接口作用就是定义规范,所以从某种意义上来说,Servlet就是JAVA中定义的一个处理WEB资源的规范。
2.Servlet的作用是什么?
我们知道Servlet主要是应用于对WEB资源的处理,所以Servlet最大的作用也是在WEB应用上。
我们知道WEB应用是一种C/S模式,即客户端服务器模式,为了更方便理解Servlet的作用,这里我们将客户端向服务器请求WEB资源比作客户向移动公司打电话。这样一来,客户端就对应了使用移动卡的客户,服务器就相当于移动公司,那么Servlet是什么呢?当你的手机卡出了问题,需要询问时,是谁接受了你的请求,并且帮你处理呢?对,就是客服,或者说接线员。Servlet就相当于接线员。接线员的作用是什么?接受客户的请求,并且通过服务器网络,处理客户请求。
比如说,你手机没费了,然后,给客服打电话,这时,就会听到 “您好,这里是XXXX为您服务” “先生您好,有什么可以帮到您的吗?” 然后你问:“我手机没费了,是怎么回事?” 然后客服回应:“先生,请稍等,我们这边帮您查一下。”等了一会:“先生您好。手机没费,是因为您没充钱。” 你:“哦。”
这里开始对比,你给客服打电话这个动作就相当于,客户端向服务器发送了一个请求(通俗点说就是你朝浏览地址栏输入了一行网址等行为),然后,接线员接到电话,这表示Servlet接收了你的请求,后面一步,客服说:“先生稍等,我们这边帮您查一下。”这个动作,就相当于Servlet接收服务器端传来的相应,并处理,然后将结果通知你(显示在浏览器页面或其他)。
3.怎么实现一个Servlet?
我们在前文知道Servlet是一个接口,通过查找API我们发现,Servlet在javax.servlet包下,并且还有两个子类,GenericServlet和httpServlet。
从继承的特点来看,子类的功能一般是多于父类的,所以我们从Servlet开始。
4.javax.servlet.Servlet接口的实现
我们使用myeclipse创建一个java类,去实现Servlet接口,然后重写里面的方法,结果如下。
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class Servlet1 implements Servlet{
@Override
public void destroy() {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void init(ServletConfig config) throws ServletException {
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
}
}
如此看来,ServletConfig还是蛮重要的,但是为什么说getServletConfig方法不重要呢?这个疑问先放在这里。
接下来看getServletInfo方法,此方法返回一个String值,即开发人员对自己创建的Servlet的简单描述,为什么说他不重要呢?这里,举个例子感受一个,你可以在方法中这么写,String s = "这是一个特别厉害的Servlet" 然后return s.看起来像是开玩笑的话,但是是为了说明,这里些什么都可以,这个方法就是开发人员对Servlet的简单描述,没事谁会调用呢?所以说没什么大用处。
下面是三个声明周期方法。
destroy,既然说声明周期方法是被自动调用的,那么此方法什么时候被调用呢?其实看名字就知道,当他Servlet被关掉的时候,结合之前的知识,一般在最后调用的方法是为了释放资源对吧,他的作用就是在所有的线程的service()方法执行完成或者超时后执行,调用这个方法后,容器不会再调用这个servlet的方法,也就是说容器不再把请求发送给这个servlet。这个方法给servlet释放占用的资源的机会,通常用来执行一些清理任务。
service,此方法同为声明周期方法,那么他什么时候被调用呢?即每次客户端向服务器发送请求时,被调用一次。
init方法,此方法是最后一个声明周期方法,也是一个蛮重要的方法,他的调用时间为Servlet被创建的时候。
下面我们写几段代码测试。
我们朝destroy方法中写这么一段代码。
public void destroy() {
System.out.println("请注意,我已经死了");
}
这时我们该注意到,在WebRoot文件夹下的WEB-INF文件夹下有一个web.xml文件,将他打开,博主用的是2017版可能版本不一样会有些许偏差。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>tetx2</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
然后,我们将用不上的部分删去。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>tetx2</display-name>
</web-app>
然后在</web-app>上写这么几段东西。
<servlet>
<servlet-name> </servlet-name>
<servlet-class> </servlet-class>
</servlet>
<servlet-mapping>
<servlet-name></servlet-name>
<url-pattern><url-pattern>
</servlet-mapping>
这些都是什么呢?简单的说,这些配置文件就是为了在浏览器中能访问我们的Servlet.
先看<servlet>,这里面有两个东西,第一个<servlet-name>这是什么呢?这个就是你为你的servlet起的名字,主要是为了区分其他的Servlet,试想一下,在一个大型项目中,肯定不止一个Servlet如果名字都一样,那么不就乱了吗?然后你可能会想,不同的servlet不是路径不同吗?别急,带着这个疑问继续下去。然后是<servlet-class>这里写的是你的servlet的包名.servlet名。例如你的包名为practice,servlet名为myServlet,那么此处应该填practice.servlet.
然后看<servlet-mapping>,同样的这里也有一个<servlet-name>这里的内容需要和上面的<servlet-name>内容一样。然后是<url-pattern>这里需要写的是/你想在浏览器中访问的路径名。例如你的文件名为practice,包名为text,此处填写/AServlet。那么你在浏览器要访问你的Servlet需要填写的是,localhost:8080/Practice/text/AServlet.
好了,然后浏览器是怎么找到你的Servlet的呢?他是首先拿到了你的web.xml的配置文件,然后通过你输入的浏览器路径,定位了servlet-mapping,然后找到了servlet-name,然后去匹配上面的<servlet>中的<servlet-name>,然后再再定位你的<servlet-class>就找到了你的servlet在项目中的位置。
好了,配置完成之后,我们就可以将servlet发布到tomcat上了,此时,将项目部署到tomcat,然后启动tomcat,启动成功后,输入你的serlet地址,你会看到一片空白(如果看到了404请自行查看哪里错了),此时不要急,回到编译器,关闭tomcat,这时你会发现你的控制台打印出了你的那条消息 :“请注意,我已经死了”。
然后是init方法和service方法,我们对他们进行如下改动。
public void init(ServletConfig config) throws ServletException {
System.out.println("init");
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("service");
}
此时重启tomcat,再次向浏览器发送请求,回到你的控制台,会看到
init
service
再次发送请求,会看到再次看到控制台输出service(如果F5一直刷新页面,会一直打出service),但是init方法只出现一次。
好了,现在已经知道了三个方法的生命周期,现在该看一下init这个方法了。
通过观察此方法发现他被传递了ServletConfig config这个参数。 之前我们说过ServletConfig方法中存放着Servlet的初始化参数,那么参数有哪些呢?我们来看一下ServletConfig的方法。
String getServletName() -- 获取当前Servlet在web.xml中配置的名字
String getInitParameter(String name) -- 获取当前Servlet指定名称的初始化参数的值
Enumeration getInitParameterNames() -- 获取当前Servlet所有初始化参数的名字组成的枚举
ServletContext getServletContext() -- 获取代表当前web应用的ServletContext对象
我们来测试。但是测试之前呢我们需要手动对Servlet进行初始化,此时需要在你的web.xml文件中的<servlet>中添加如下信息。
<init-param>
<param-name>username</param-name>
<param-value>admin</param-value>
</init-param>
这就相当于定义了一个名为username的变量,其值为admin,写入后保存,就完成了对servlet的初始化。现在我们测试。
代码如下:
System.out.println(config.getServletName());
System.out.println(config.getInitParameter("username"));
System.out.println(config.getServletContext());
Enumeration<String> e = config.getInitParameterNames();
while(e.hasMoreElements()) {
System.out.println(e.nextElement());
}
测试结果为:
aaa
admin
org.apache.catalina.core.ApplicationContextFacade@1415d904
username