Java之Servlet学习笔记(更新中...)
Servlet是什么
Servlet是Server Applet的缩写,即“服务器端小程序”,是一种使用Java语言开发动态网站的技术。它可以接收客户端发送过来的请求,并响应数据给客户端。
Servlet具有以下特点:
1、Servlet提供了可被服务器动态加载并执行的程序代码,为来自客户端的请求提供服务;
2、Servlet完全使用Java语言编写,运行Servlet的服务器须支持Java语言;
3、Servlet是一种在服务器端运行的小程序,不依赖于浏览器,不管是浏览器是否支持Java语言,都能请求你方法服务器端的Servlet。
Servlet是一种规范
所有的 Servlet 功能都是通过一个名为 jakarta.servlet.Servlet 的接口(Interface)向外暴露的,该接口的源码如下:
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
可以看到,Servlet 接口仅提供了 5 个抽象方法,并未给出任何方法实现,这是因为 Servlet 其实只是一种 Java Web 开发的规范,或者说是一套 Java Web 开发的技术标准。仅仅有规范是无法做任何事的,必须要有人去实现这个 Servlet 接口并重写其中方法,实现 Servlet 规范提到的各种功能才行。
直接实现 Servlet 接口比较麻烦,需要实现多个方法,所以 Servlet 规范又提供了两个抽象类,分别是 GenericServlet 类和 HttpServlet 类,它们各自都实现了 Servlet 接口的很多常用功能。和 GenericServlet 类相比,HttpServlet 类更加方便,所以实际开发中一般都继承自 HttpServlet 类。
Servlet 规范是开放的,除了 Sun 公司之外,其它公司也可以实现 Servlet 规范,目前常见的实现了 Servlet 规范的产品包括 Tomcat、Weblogic、Jetty、Jboss、WebSphere 等,它们都被称为“Servlet 容器”。
Servlet容器
我们知道,Servlet 用于生成动态网页的,一个动态网页对应一个 Servlet。编写一个 Servlet,实际上就是按照 Servlet 规范编写一个 Java 类。
但 Servlet 类中是没有 main() 方法的,不能独立运行。它必须被部署到 Servlet 容器中,由容器来实例化和调用 Servlet 的方法。Servlet 容器可以在 Servlet 的生命周期内对 Servlet 进行保存和管理:
从上图可知,Web 服务器是整个动态网站的“大门”,用户的 HTTP 请求首先到达 Web 服务器,Web 服务器会判断该请求是静态资源还是动态资源:如果是静态资源就直接返回,此时相当于用户下载了一个服务器上的文件;如果 Web 服务器接收到的是一个指向 Servlet 等动态资源的请求,那么 Web 服务器并不会把这个请求直接交给 Servlet 本身,而是转交给部署该 Servlet 的容器。
Servlet 容器接收到请求以后,会根据配置文件(web.xml)找到对应的 Servlet 类,将它加载并实例化,然后调用其中的方法来处理用户请求。处理结束后,Servlet 容器会将处理结果再转交给 Web 服务器,由 Web 服务器将处理结果进行封装,并以 HTTP 响应的形式发送给用户的浏览器进行展示。
Tomcat 是最常用、最流行的 Servelt 容器之一。
一般情况下,Servlet 容器具有如下功能:
- 容器提供了各种方法,使得 Servlet 可以实现与 Web 服务器对话。开发人员只需要专注于如何在 Servlet 中实现业务逻辑即可,至于 Servlet 与 Web 服务器对话的细节则不必理会。
- 容器能够控制 Servlet 的生命周期。容器负责加载、实例化和初始化 Servlet、调用 Servlet 方法、销毁 Servlet 实例。
- 容器支持多线程管理。容器接收 Servlet 请求时,容器自动为其创建新线程,运行完成时,容器结束线程。
- 容器为 Servlet 的可移植性提供了可能。利用容器,可以使用 XML 部署描述文件来配置和修改安全性,不需将其编码写到 Servlet 类代码中。
- 容器负责将一个 JSP 文件转译成一个 Servlet。
Servlet三种创建方式
我们在开发属于自己的 Servlet 类时,既可以直接实现 Servlet 接口,也可以通过继承 GenericServlet 抽象类或 HttpServlet 抽象类(HttpServlet是GenericServlet的子类)实现。
1、实现 Servlet 接口
我们可以通过编写一个 Java 类实现(implements)Servlet 接口,并重写 Servlet 接口中全部 5 个方法的方式来创建一个 Servlet 类
public class MyServlet implements Servlet {...}
2、继承 GenericServlet 抽象类
Servlet API 中还提供了一个名为 GenericServlet 的抽象类,与 Servlet 接口一样,GenericServlet 也位于 jakarta.servlet 包下。GenericServlet 实现了 Servlet 接口,并为除了 service() 方法外的其他四个方法,都提供了与任何网络协议都无关的通用实现,因此我们在通过继承 GenericServlet 创建 Servlet 时,只需要重写 service() 方法即可,大大减少了创建 Servlet 的工作量。
示例代码如下:
import jakarta.servlet.GenericServlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author C语言中网 http://c.biancheng.net
* 继承 GenericServlet 接口,重写 service()方法,创建 Servlet
*/
public class MyGenericServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//设置字符集
servletResponse.setContentType("text/html;charset=UTF-8");
//使用PrintWriter.write()方法向前台页面输出内容
PrintWriter writer = servletResponse.getWriter();
writer.write("C语言中文网:http://c.biancheng.net");
writer.close();
}
}
3、继承 HttpServlet 抽象类
HttpServlet 类位于 jakarta.servlet.http 包下,它是 GenericServlet 抽象类的子类。
HttpServlet 类为 Servlet 接口提供了与 HTTP 协议相关的通用实现,十分适合开发基于 HTTP 协议的 Servlet 程序。由于 Servlet 主要用来处理 HTTP 的请求和响应,因此我们所编写的 Servlet 类通常都继承自 HttpServlet。
我们知道,在 HTTP/1.1 协议中共定义了 7 种请求方式,即 GET、POST、HEAD、PUT、DELETE、TRACE 和 OPTIONS。
HttpServlet 针对每一种请求方式提供了一个相应的服务方法,例如 doGet()、doPost()、doHead()、doPut()、doDelete()、doTrace() 和 doOptions(),并为这些 doXxx() 方法都提供了默认的实现。
HttpServlet 在 GenericServlet 的基础上对 Servlet 接口中的 service() 方法进行了重写,该方法会先获取客户端的请求方式,然后根据请求方式调用对应 doXxx() 方法。因此,我们在通过继承 HttpServlet 抽象类创建 Servlet 类时,只需要根据客户端的请求方式重写指定的 doXxx() 方法即可。
由于我们使用的请求方式主要是 GET 和 POST,所以通过继承 HttpServlet 类创建 Servlet 时,只需要重写 doGet 或者 doPost 方法,代码如下。
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author C语言中网 http://c.biancheng.net
* 继承 HttpServlet 接口,重写doXxx方法,创建 Servlet
*/
public class MyHttpServlet extends HttpServlet {
/**
* 重写 doGet() 方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//使用PrintWriter.write()方法向前台页面输出内容
resp.setContentType("text/html;charset=UTF-8");
PrintWriter writer = resp.getWriter();
writer.write("C语言中文网:http://c.biancheng.net");
writer.close();
}
/**
* 重写 doPost() 方法
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//使用PrintWriter.write()方法gaifang向前台页面输出内容
PrintWriter writer = resp.getWriter();
writer.write("C语言中文网:http://c.biancheng.net");
writer.close();
doGet(req, resp);
}
}
Servlet部署及应用
我们知道,Servlet 中是没有 main() 方法的,因此它不能像其他的 Java 程序一样独立运行,而是必须以 JavaWeb 组件的形式部署到 Servlet 容器中,由容器对它实例化,调用其中的方法。
JavaWeb应用
所谓 JavaWeb 应用,就是使用 Java 语言开发的 Web 站点(网站)。它由一组 Servlet/JSP、HTML 文件、相关 Java 类以及其他的资源组成,它可以在由各种供应商提供的 Servlet 容器中运行。从定义可知, Servlet 是 JavaWeb 应用的一个组件。
为了让 Servlet 容器顺利地找到 JavaWeb 应用的各个组件,Servlet 规范规定:JavaWeb 应用必须采用固定的目录结构,即每种组件在 JavaWeb 应用中都有固定的存放目录。
以 Tomcat 为例,JavaWeb 应用通常都需要存放到 Tomcat 的 webapps 目录下。webapps 目录中的每一个子目录都是一个独立的 Web 应用,子目录的名字就是 Web 应用的名字,也被称为 Web 应用的上下文根。用户可以通过这个上下文根来访问 JavaWeb 应用中的资源。
webapps 的目录结构如下图。
利用IntelliJ IDEA创建Servlet项目
先正常创建一个Java项目,如MyServletProject,然后右键项目名,在下拉菜单中选择 Add Framework Support...,为这个 Java 项目添加支持,如下图。
#Java##Servlet#
