本文由博主本人编写,文中有错误的地方欢迎大家批评指正,您的建议将给予我莫大的帮助!😘
Servlet规范介绍
1.Servlet规范是JavaEE规范的一种
2.作用:
1)在Servlet规范中,指定**动态资源文件**的开发步骤(在本篇文章中介绍)
2)在Servlet规范中,指定Http服务器调用动态资源文件的规则(在本篇中介绍)
3)在Servlet规范中,指定Http服务器管理动态资源文件的规则(实际上就是创建动态资源文件实例对象的过程【Servlet对象的生命周期】https://blog.csdn.net/qq_45930996/article/details/108384399)
*Servlet接口的实现类(动态资源文件)
- 注意:在Servlet规范中认为,Http能调用的动态资源文件必须是Servlet接口的实现类,也就是说,只有Servlet接口的实现类才是动态资源文件
- Servlet接口是Servlet规范下的一个接口,这个接口存在于Http服务器提供的jar包
- 在Tomcat服务器下的lib文件中,有一个servlet-api.jar的jar包,里面存放着Servlet接口(javax.servlet.Servlet接口)
由上面的叙述可以看出来,在Servlet规范中,动态资源文件其实就是Servlet接口的实现类
动态资源文件的开发步骤
首先创建一个类,这个类要继承自HttpServlet类,从而实现Servlet接口
代码如下:
package com.hubu.controller;
import javax.servlet.http.HttpServlet;
public class ServletTest extends HttpServlet {
}
注意以下这里的包名,一般我们将动态资源文件存放在controller这个包下
大家可能会有疑问,为什么这里要继承HttpServlet,而不是直接实现Servlet接口,关于这个问题,建议大家先跳到下面介绍Http服务器调用动态资源文件的规则部分,将会有详细的讲解
请大家阅读了下面的规则再接着看哦,否则看不懂的
重写HttpServlet父类中的doGet()和doPost方法
问题又来了,刚刚规则里(Http服务器调用动态资源文件的规则 ☟ 没看的小伙伴快去看看)明明调用的是service方法,为啥要实现doGet()和doPost()方法呢?而且这两个方法是干什么用的呢?
还记得在规则里面说过service()方法是交给HttpServlet来实现的吗,是时候看看他的源码了,下面的代码比较多,大家不用全看,只需要看我标注出来的部分
/*
HttpServlet对于service()方法的实现
*/
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//这里:定义了一个method变量,用于获取用户请求这个动态资源文件的方式
//方式包括:get,post,head,put,delete,options,trace
//一般用到的是get和post
String method = req.getMethod();
long lastModified;
//这里是如果请求方式是get的话
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
//这里就会调用当前对象doGet()方法
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);
}
//这里是如果请求方式是post的话
else if (method.equals("POST")) {
//就会调用当前对象的doPost()方法
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);
}
}
标注的已经比较清楚了,HttpServlet已经帮我们实现了service()方法,在它实现的service()方法中实际用到了doGet()、doPost()、doHead()等方法,所以在自己的类中,只需要重写这些方法就可以了
代码如下:
package com.hubu.controller;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("浏览器正通过get请求的方式访问该动态资源文件");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("浏览器正通过post请求的方式访问该动态资源文件");
}
}
将Servlet接口实现类的信息【注册】到Tomcat服务器中
在当前网站项目下的web文件夹下WEB-INF文件夹下的web.xml中进行配置
当前网站 —> web —> WEB-INF —> web.xml
<!-- Servlet接口实现类类路径交给Tomcat服务器 -->
<servlet>
<!--为该动态文件放在一个变量上面-->
<servlet-name>testServlet</servlet-name>
<!--动态资源文件的类路径-->
<servlet-class>com.hubu.controller.ServletTest</servlet-class>
</servlet>
<!-- 为Servlet接口实现类提供简短的别名 -->
<servlet-mapping>
<!--指定的变量名-->
<servlet-name>testServlet</servlet-name>
<!--别名,注意这里,别名必须以"/"开头-->
<url-pattern>/test</url-pattern>
</servlet-mapping>
Http服务器调用动态资源文件的规则
以Tomcat服务器为例
Tomcat服务器调用Servlet服务器的规则:
- Tomcat服务器有权创建Servlet接口实现类的实例对象
Servlet oneServlet = new OneServlet();
- Tomcat服务器根据实例对象调用service()方法
onServlet.service();
对于上面我们遗留了一个问题,为什么Servlet接口实现类选择继承HttpServlet而不是直接实现Servlet接口
这里我们首先看一下HttpServlet类的源码
可以看到它是继承自GenericServlet,然后我们看一下GenericServlet的源码
可以看到他是实现了Servlet接口的
因此,类通过继承HttpServlet类相当于实现了Servlet接口
重点:
我们再看一下Servlet接口的源码
package javax.servlet;
import java.io.IOException;
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
可以看到,这个接口里面有五个方法,而上面介绍的Tomcat服务器调用动态资源文件的规则中,他只用到了service()方法
如果我们选择直接实现Servlet接口,那五个抽象方法我们都要实现,这样难度还是很大的
所以开发者为我们提供了抽象类,预先实现了这些不太重要的抽象方法,这里我们首先看一下GenericServlet这几个抽象方法的实现
/*
这是GenericServlet中几个方法的源码
*/
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public ServletConfig getServletConfig() {
return this.config;
}
public String getServletInfo() {
return "";
}
public void destroy() {
}
//注意这里的service方法,并没有被实现,他将在HttpServlet类中实现
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
这里的service方法,并没有被实现,他将在HttpServlet类中实现
所以这就解释了为什么我们选择继承HttpServlet类的方式而不是直接实现Servlet接口的方式创建动态资源文件
另外在这里讲一下抽象类的作用,大家学了抽象类可能并不知道他有什么作用哈哈哈:
抽象类作用:
-
降低接口实现类对接口实现过程中的开发难度
-
将接口中不需要使用抽象方法交给抽象类完成
-
这样接口实现类只需要对接口必要的方法进行重写
好了大家可以回去继续阅读啦
测试
创建好了一个动态资源文件后我们来测试一下
-
启动Tomcat服务器
-
用get请求该动态资源文件
可以看到服务器端运行了doGet()方法,打印了一段信息
-
用post请求该动态资源文件
可以看到服务器端运行了doPost()方法,打印了一段信息