介绍
官网:Servlet 3.1 API Documentation - Apache Tomcat 8.0.53
为什么需要?
提出需求: 请用你现有的html css javascript,开发网站,比如可以让用户留言/购物/支付?
引入我们动态网页(能和用户交互)技术===>Servlet
是什么?
处理请求和发送响应的过程是由一种叫做Servlet的程序来完成的,并且Servlet是为了解决实现动态页面而衍生的东西。
Tomcat 是Web应用服务器,是一个Servlet/JSP容器。 Tomcat 作为Servlet容器,负责处理客户请求,把请求传送给Servlet,并将Servlet的响应传送回给客户。而Servlet是一种运行在支持Java语言的服务器上的组件。 Servlet最常见的用途是扩展Java Web服务器功能,提供非常安全的,可移植的,易于使用的CGI替代品。【Tomcat部分详见Java Web(七)__Tomcat(二)-CSDN博客和Java Web(七)__Tomcat(一)-CSDN博客 】
Java Servlet API 是Servlet容器(tomcat)和servlet之间的接口,它定义了serlvet的各种方法,还定义了Servlet容器传送给Servlet的对象类,其中最重要的就是ServletRequest和ServletResponse。所以说我们在编写servlet时,需要实现Servlet接口,按照其规范进行操作。
注:
Servlet 类没有 main() 函数,不能独立运行,只能作为一个模块被载入到 Servlet 容器,然后由 Servlet 容器来实例化,并调用其中的方法;
一个动态页面对应一个 Servlet 类,开发一个动态页面就是编写一个 Servlet 类;【当用户请求到达时,Servlet 容器会根据配置文件(web.xml)来决定调用哪个类】
浏览器访问 Servlet 流程分析
注:
servlet3.0 前使用 web.xml
servlet3.0 版本以后(包括 3.0)支持注解, 同时支持 web.xml。
手动编写Servlet
实现Servlet接口
需求:
1、开发一个 HelloServlet
2、当浏览器 访问 http://localhost:8080/web 应用名/helloServlet 时,后台输出 "hiHelloServelt"
实现:
1、编写类HelloServlet,实现 Servlet 接口
- 1.创建javaweb工程,并配置好Tomcat
- 2.添加servlet.jar(在Tomcat/lib)到工程web/WEB-INF/lib中
- 3.在src 下 包 com.hspedu.servlet.HelloServlet.java ,并实现Servlet接口
2、实现 service 方法,处理请求,并响应数据
package com.lhyedu.servlet;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* 1. 开发一个Servlet 需要 实现Servlet接口
* 2. 实现Servlet接口的方法5个
*/
public class HelloServlet02 implements Servlet {
/**
* 1.初始化 servlet
* 2.当创建HelloServlet 实例时,会调用init方法
* 3. 该方法只会被调用一次
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
/**
* 返回ServletConfig 也就是返回Servlet的配置
*/
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 1. service方法处理浏览器的请求(包括get/post)
* 2. 当浏览器每次请求Servlet时,就会调用一次service
* 3. 当tomcat调用该方法时,会把http请求的数据封装成实现ServletRequest接口的request对象
* 4. 通过servletRequest 对象,可以得到用户提交的数据
* 5. servletResponse 对象可以用于返回数据给tomcat->浏览器
*/
@Override
public void service(ServletRequest servletRequest,
ServletResponse servletResponse) throws ServletException, IOException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String method = httpServletRequest.getMethod();
if("GET".equals(method)) {
doGet(); //用doGet() 处理GET请求
} else if("POST".equals(method)) {
doPost(); //用doPost() 处理POST请求
}
}
/**
* 用于响应get请求的
*/
public void doGet() {
System.out.println("doGet() 被调用..");
}
/**
* 用于响应post请求的
*/
public void doPost() {
System.out.println("doPost() 被调用..");
}
/**
* 返回servlet信息,使用较少
*/
@Override
public String getServletInfo() {
return null;
}
/**
* 1. 该方法是在servlet销毁时,被调用
* 2. 只会调用一次
*/
@Override
public void destroy() {
System.out.println("destroy() 被调用...");
}
}
3、在 web.xml 中去配置 servlet 程序的访问地址,即:给hello.servlet提供对外访问的地址。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--web.xml主要用来配置该web应用使用到的Servlet-->
<!-- 配置HelloServlet -->
<!--servlet标签: 给tomcat配置Servlet程序-->
<servlet>
<!--servlet-name标签: 给Servlet程序取一个别名(程序员决定), 该名字唯一;一般跟写的Servlet类名相同-->
<!--servlet-class标签:Servlet的全限定类名,即Servlet类的位置: Tomcat在反射生成该Servlet需要使用。-->
<servlet-name>HelloServlet</servlet-name>
<servlet-class>HelloServlet</servlet-class>
<!--load-on-startup 表示在tomcat 启动时,会自动的加载servlet实例-->
<!--<load-on-startup>1</load-on-startup>-->
</servlet>
<!--servlet-mapping标签: 给Servlet程序配置方位地址-->
<servlet-mapping>
<!--servlet-name标签:告诉服务器,当前配置的地址给哪个Servlet使用-->
<!--url-pattern标签:对外提供访问Servlet的url地址:http://ip[域名]:port/工程路径/helloServlet
取名是程序员决定的,相当于项目名。【/符号一定要加上】-->
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/helloServlet</url-pattern>
</servlet-mapping>
执行步骤:
【1】首先浏览器通过http://localhost:8080/servletDemo/helloServlet来找到web.xml中的url-pattern;
【2】匹配到url-pattern后,就会找到servlet的名字helloServlet;
【3】通过servlet-name找到servlet-class【即servlet的位置】,然后到其中找到对应的处理方式进行处理。
4、通过浏览器访问HelloServlet ,进行验证;
- 浏览器输入:http://localhost:8080/web/HelloServlet
- 服务后台输出: hi,helloservlet......
实现HttpServlet类__推荐方式
示意图:
package com.hspedu.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class OKServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//可以写自己的业务处理代码
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//可以写自己的业务处理代码
}
}
【1】热加载选项说明
on update action
- 表示当我们更新操作时, Tomcat 会自动更新类和资源
- 当jsp/html 文件修改时,可以生效;但是如果你修改的 java 文件,需要 Redepoly 才会生效。
on frame deactivation
- 表示 IDEA 失去焦点(比如最小化),也会导致 jsp/html 发生更新
- 但是 java 修改了,还是需要 redeploy
【2】端口修改
只会影响到当前的项目,而不是去修改 server.xml。
DOS部署
在默认情况下,Tomcat 会自动加载 webapps 目录下的 JavaWeb 应用,并把它发布到名为 localhost 的虚拟主机中。
部署 JavaWeb 应用最快捷的方式:直接将 JavaWeb 应用的所有文件复制到 Tomcat 的 /webapps 目录下
运行方式:
- 开放式目录结构(只编译不打包);在开发阶段采用,方便调试
- 打包文件(WAR 文件):产品发布阶段时,应该将整个应用打包成 WAR 文件,再进行部署。Tomcat 启动时也会将 WAR 文件自动展开为开放式的目录结构。
开放式目录结构__部署步骤
1. 进入 Windows DOS 命令行窗口
- 使用快捷键 “Windows + R”,打开运行对话框
- 在对话框输入cmd,点击“确定”,进入 Windows 系统命令行窗口
2. 引入 javax.servlet 包
先在命令行中输入set classpath=,然后将 servlet-api.jar 文件拖进命令行内,回车执行 。
- 命令:set classpath = path
- path 表示引入 jar 包的路径
- set classpath命令用来为当前窗口设置临时环境变量,只在当前窗口下有效。
3. 编译 Servlet
- 1)在命令提示符中使用 cd命令进入 MyServlet.java 所在的目录
- 2)使用 javac -encoding UTF-8 -d . MyServlet.java 命令进行编译
- 3)进入 MyServlet.java 文件所在的目录,可发现新增了编译后的目录和 .classes 字节码文件,即完成对 Servlet 的编译工作
4. 创建目录结构
依照 JavaWeb 应用的固定目录结构,在 Tomcat 中为该 Servlet 创建目录。
- 目录
- 在 Tomcat 的 webapps 目录中创建 servletDemo(web 应用的名字,由自己定义)文件夹;
- 在 servletDemo 文件夹内创建 WEB-INF 文件夹;
- 在 WEB-INF 内创建 classes 文件夹;
- 在 WEB-INF 内创建配置文件 web.xml(可以复制 \webapps\ROOT\WEB-INF 中的 web.xml 使用)
5. 将 Servlet 移动到 Tomcat 目录中
- 编译好的字节码和目录移动到 Tomcat\webapps\servletDemo\WEB-INF\classes 目录下
6. 配置 web.xml
- 对 webapps\servletDemo\WEB-INF 目录的 web.xml 中进行配置
7、访问
- 进入 Tomcat\bin 目录下双击 startup.bat,启动 Tomcat。
- 浏览器的地址栏中输入“http://localhost:8080/servletDemo/MyServlet”,访问 MyServlet
Servlet的生命周期
Servlet 的生命周期由 Servlet 容器管理;在 javax.servlet.Servlet 接口中定义3 个方法:init()、service()、destory(),它们分别在 Servlet 生命周期的不同阶段被 Servlet 容器调用。
【1】初始化阶段
Servlet 容器(比如: Tomcat)加载 Servlet,加载完成后,Servlet 容器会创建一个 Servlet 实例并调用init()方法,init()方法只会调用一次。
(1)加载和实例化Servlet
加载成功后,容器会通过反射对 Servlet 进行实例化【编写 Servlet 类时,需要一个无参构造方法】;
Servlet 容器装载 Servlet的情形:
- 当容器启动或首次请求某个 Servlet 时,容器会读取 web.xml 或 @WebServlet 中的配置信息,对指定的 Servlet 进行加载;
- Servlet 重新装载时,浏览器再向 Servlet 发送请求的第 1 次;比如 tomcat 进行 redeploy;【redeploy 会销毁所有的Servlet 实例】。
通过在 web.xml 文件中添加<load-on-startup>1</load-on-startup>
1 表示装载的顺序,默认值为0;
load-on-startup 是 web.xml 中的一个节点,是 servlet 元素的子元素,用来标记 Servlet 容器启动时是否初始化当前 Servlet,以及当前 Servlet 的初始化顺序
(2)调用init()方法初始化Servlet实例
在 Servlet 的整个生命周期内,init() 方法只能被调用一次。
初始化期间,Servlet 实例可以通过 ServletConfig 对象获取在 web.xml 或者 @WebServlet 中配置的初始化参数。
【2】处理浏览器请求阶段(service 方法)
当初始化完成后,Servlet 容器会将该实例保存在内存中,通过调用它的 service() 方法,为接收到的请求服务。
每收到一个 http 请求,服务器就会产生一个新的线程去处理;对于 Servlet 的每一次请求,Servlet 容器都会调用一次 service() 方法,并创建新的 ServletRequest 和 ServletResponse 对象;即 service() 方法在 Servlet 的整个生命周期中会被调用多次。
Servlet 容器接收到来自客户端请求时,容器会针对该请求分别创建一个 ServletRequst 对象和 ServletResponse 对象,将它们以参数的形式传入 service() 方法内,并调用该方法对请求进行处理;
- ServletRequst 对象获取客户端的相关信息和请求信息;
- ServletResponse 对象将响应信息进行包装,返回给客户端;
- 当 Servlet 容器将响应信息返回给客户端后,ServletRequst 对象与 ServletResponse 对象就会被销毁。
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//count值,在不断的累计,说明HelloServlet是单例的
count++;
//tomcat每处理一次http请求,就生成一个新的线程
System.out.println("hi,helloservlet......" + count + Thread.currentThread().getId());
}
注:执行 service() 方法前,init() 方法必须已成功执行;
【3】终止阶段 destory 方法(体现 Servlet 完整的生命周期)
当web 应用被终止,或者Servlet 容器终止运行,或者Servlet 类重新装载时,会调用destroy()方法,释放该实例使用的资源;
比如重启tomcat ,或者 redeploy web 应用;例如:关闭数据库连接,关闭文件的输入流和输出流等,随后该实例被 Java 的垃圾收集器所回收。
对于每个 Servlet 实例来说,destory() 方法只能被调用一次;
注:要看到 destory 效果,需要保证 servlet 实例被创建过或者 Servlet 重新装载时(比如 redeploy)。
其他
部署动态网站
一般至少需要三个组件,分别是 Web 服务器、脚本语言运行时和数据库。例如,部署 PHP 网站一般选择「Apache + PHP 运行时 + MySQL」的组合。
【1】web服务器
一种对外提供 Web 服务的软件,可以接收浏览器的 HTTP 请求,并将处理结果返回给浏览器。
- 运行 PHP 网站一般选择 Apache 或者 Nginx;
- 运行 ASP/ASP.NET 网站一般选择 IIS;
- 运行 Python 网站一般选择内置的 WSGI 服务器模块——wsgiref
通常所说的 Web 服务器,功能往往都比较单一,一般只能提供 http(s) 服务,让用户访问静态资源(HTML 文档、图片、CSS 文件、JavaScript 文件等)。它们不能执行任何编程语言,也不能访问数据库,更不能让用户注册和登录。
若只有 Web 服务器,那您只能部署静态网站,不能部署动态网站。
【2】运行环境(运行时)
习惯将以上各种支持脚本语言运行的部件统称为运行环境,或者运行时(Runtime)。开发网站使用的编程语言一般都是脚本语言(比如 PHP、ASP、Python)。
部署网站时都是将源代码直接扔到服务器上,然而源代码自己并不能运行,必须要有解释器的支持。当用户访问动态页面时,解释器负责分析、编译和执行源代码,然后得到处理结果。
解释器:执行脚本语言的核心部件。包含如下辅助性的部件:
- 垃圾回收器:负责及时释放不需要的内存,腾出资源供其它页面使用
- 标准库:任何编程语言都会附带标准库;它们提供了很多通用性的功能,极大地提高了开发效率,避免重复造轮子
【3】数据库
Web 服务器不带数据库,编程语言也不带数据库。数据库是一款独立的软件,若要实现用户注册、发布文章、提交评论等功能,就必须安装一款数据库。
- 比如 MySQL、Oracle、SQL Server 等。