Servlet
第一:Servlet是一个运行在web服务端的java小程序
第二:它可以用于接收和响应客户端的请求
第三:要想实现Servlet功能,可以实现Servlet接口,继承GenericServlet或者HttpServlet
第四:每次请求都会执行service方法
第五:Servlet还支持配置
概述
Servlet 作用
1)接收客户端的请求
2)处理业务逻辑
3)响应给浏览器客户端
Servlet类视图
快速入门
步骤
1.创建web项目
2.导入servlet依赖
<!--导入依赖-->
<dependencies>
<!--导入servlet依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
</dependencies>
3.在创建的web项目中自定义类实现Servlet接口
4.在自定义类中实现Servlet接口中的所有的抽象方法
5.在实现Servlet接口的service方法体中书写代码处理业务逻辑
void service(ServletRequest req, ServletResponse res)
6.在web项目的核心配置文件web.xml中配置访问servlet的路径。
说明:这样配置是告知tomcat有具体的Servlet类需要被访问。
7.启动tomcat
8.在浏览器中访问servlet类
实现
1.创建maven的web项目
2.导入servlet的依赖
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<!--编译 测试需要,运行时不需要-->
<scope>provided</scope>
</dependency>
2.在创建的web项目中自定义类实现Servlet接口
3.在自定义类中实现Servlet接口中的所有的抽象方法
4.在实现Servlet接口的service方法体中书写代码处理业务逻辑
import javax.servlet.*;
import java.io.IOException;
/*
2.在创建的web项目中自定义类实现Servlet接口
*/
public class HelloWorldServlet implements Servlet{
//3.在自定义类中实现Servlet接口中的所有的抽象方法
//4.在实现Servlet接口的service方法体中书写代码处理业务逻辑
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service....");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
5.在web项目的核心配置文件web.xml中配置访问servlet的路径。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!--
5.在web项目的核心配置文件web.xml中配置访问servlet的路径。
说明:这样配置是告知tomcat有具体的Servlet类需要被访问。
-->
<!--
1.<servlet> 表示将当前Servlet类注册到tomcat中,告知tomcat有一个类要被访问
-->
<servlet>
<!--
表示当前要被访问类的标识,在当前web.xml中要唯一,helloWorldServlet属于标识符
-->
<servlet-name>helloWorldServlet</servlet-name>
<!--
配置要访问 的servlet类,必须是类的全路径:包名.类名。
说明:tomcat底层通过获取这里的类全路径使用反射技术调用当前类的无参构造方法创建对象
-->
<servlet-class>com.test.HelloWorldServlet</servlet-class>
</servlet>
<!--
配置要访问的servlet类的映射路径
-->
<servlet-mapping>
<!--这里要和上面的servlet-name文本值一致,这里找到上面的servlet-name-->
<servlet-name>helloWorldServlet</servlet-name>
<!--浏览器上地址栏上输入的映射路径及访问路径,这里必须加/-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
6.启动tomcat
7.在浏览器中访问servlet类
Servlet的执行原理
【1】执行流程
【2】原理
1.当我们点击run运行的时候,tomcat之所以会启动,是因为程序入口(main方法)在tomcat中
2.tomcat开始运行,会加载web项目里面的配置文件web.xml(xml解析,读取数据)
主要是根据url-pattern 找到对应的servlet-class
3.然后tomcat进入等待状态(永不停止,除非手动关闭)
4.当用户在浏览器中输入地址:http://localhost:8080/hello就会定位到tomcat的访问的项目下面的某个servlet中
5.tomcat会根据 /hello 的servlet的虚拟路径 找到HelloServlet的全限定名
6.tomcat底层通过反射创建HelloServlet的对象,并调用HelloServlet的service方法:
Class clazz = Class.forName("全限定名");
Servlet servlet = clazz.newInstance();//实际上HelloServlet对象,向上转型
servlet.service();
实现 Servlet 功能的 3 种途径
第一种:实现 Servlet 接口,接口中的方法必须全部实现。
使用此种方式,表示接口中的所有方法在需求方面都有重写的必要。此种方式支持最大程度的自定义。
第二种:继承 GenericServlet,service方法必须重写,其他方法可根据需求,选择性重写。
使用此种方式,表示只在接收和响应客户端请求这方面有重写的需求,而其他方法可根据实际需求选择性重写,使我们的开发Servlet变得简单。但是,此种方式是和HTTP协议无关的。
第三种:继承HttpServlet,它是 javax.servlet.http 包下的一个抽象类,是 GenericServlet 的子类。如果我们选择继承HttpServlet时,只需要重写doGet和doPost方法,不要覆盖service方法。
使用此种方式,表示我们的请求和响应需要和 HTTP 协议相关。也就是说,我们是通过 HTTP 协议来访问的。那么每次请求和响应都符合 HTTP 协议的规范。请求的方式就是 HTTP 协议所支持的方式(目前我们只知道GET和POST,而实际HTTP协议支持7种请求方式,GET POST PUT DELETE TRACE OPTIONS HEAD )。
Servlet 生命周期
创建:请求第一次到达 Servlet 时,对象就创建出来,并且初始化成功。只创建一次,就放到内存中。
执行:服务器提供服务的整个过程中,该对象一直存在,每次只是执行 service 方法。
销毁:当服务停止时,或者服务器宕机时,对象消亡。
通过分析 Servlet 的生命周期我们发现,它的实例化和初始化只会在请求第一次到达 Servlet 时执行,而销毁只会在 Tomcat 服务器停止时执行,由此我们得出一个结论,Servlet对象只会创建一次,销毁一次。所以,Servlet 对象只有一个实例。如果一个对象实例在应用中是唯一的存在,那么我们就说它是单实例的,即运用了单例模式。
生命周期的API :
// 1. servlet对象创建完毕,使用对象调用此方法,初始化方法,只有在第一次访问的时候执行一次
public void init(ServletConfig servletConfig);
// 2. 用户访问servlet时,调用此方法 (每次访问都会调用一次)
public void service(ServletRequest servletRequest, ServletResponse servletResponse);
// 3. servlet对象销毁时,调用此方法
public void destroy();
创建 默认情况下 用户第一次访问时,创建servlet,执行init方法
运行(提供服务) 用户每次访问时,都执行service方法
销毁 服务器正常关闭时,销毁servlet,执行destroy方法
Servlet 的线程安全
其实每一个浏览器端发送请求,就代表是一个线程,那么多个浏览器就是多个线程,所以测试的结果说明了多个线程会共享 Servlet 类成员中的数据,其中任何一个线程修改了数据,都会影响其他线程。因此,我们可以认为 Servlet 它不是线程安全的。
分析产生这个问题的根本原因,其实就是因为 Servlet 是单例,单例对象的类成员只会随类实例化时初始化一次,之后的操作都是改变,而不会重新初始化。
解决这个问题也非常简单,就是在 Servlet 中定义类成员要慎重。如果类成员是共用的,并且只会在初始化时赋值,其余时间都是获取的话,那么是没问题。如果类成员并非共用,或者每次使用都有可能对其赋值,那么就要考虑线程安全问题了,把它定义到 doGet 或者 doPost 方法里面去就可以了。
ServletConfig
基本概念
它是Servlet的配置参数对象,在Servlet规范中,允许为每个Servlet都提供一些初始化配置。所以,每个Servlet都一个自己的ServletConfig。它的作用是在Servlet初始化期间,把一些配置信息传递给Servlet。
生命周期
由于它是在初始化阶段读取了web.xml中为Servlet准备的初始化配置,并把配置信息传递给Servlet,所以生命周期与Servlet相同。这里需要注意的是,如果Servlet配置了1,那么ServletConfig也会在应用加载时创建。
常用方法
ServletContext
基本介绍
ServletContext对象,它是应用上下文对象。每一个应用有且只有一个ServletContext对象。它可以实现让应用中所有Servlet间的数据共享。
生命周期
出生——活着——死亡
出生: 应用一加载,该对象就被创建出来了。一个应用只有一个实例对象。(Servlet和ServletContext都是单例的)
活着:只要应用一直提供服务,该对象就一直存在。
死亡:应用被卸载(或者服务器挂了),该对象消亡。
域对象概念
域对象的概念,它指的是对象有作用域,即有作用范围。
域对象的作用,域对象可以实现数据共享。不同作用范围的域对象,共享数据的能力不一样。
在Servlet规范中,一共有4个域对象。今天我们讲解的ServletContext就是其中一个。它也是我们接触的第一个域对象。它是web应用中最大的作用域,叫application域。每个应用只有一个application域。它可以实现整个应用间的数据共享功能。
ServletContext的使用
ServletContext介绍
ServletContext 是应用上下文对象。每一个应用中只有一个 ServletContext 对象。
作用:可以获得应用的全局初始化参数和达到 Servlet 之间的数据共享。
生命周期:应用一加载则创建,应用被停止则销毁。
域对象
域对象指的是对象有作用域。也就是有作用范围。域对象可以实现数据的共享。不同作用范围的域对象,共享数据的能力也不一样。
在 Servlet 规范中,一共有 4 个域对象。ServletContext 就是其中的一个。它也是 web 应用中最大的作用域,也叫 application 域。它可以实现整个应用之间的数据共享!
ServletContext常用方法
public class ServletContextDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取ServletContext对象
ServletContext context = getServletContext();
//获取全局配置的globalEncoding
String value = context.getInitParameter("globalEncoding");
System.out.println(value);
//获取应用的访问虚拟目录
String contextPath = context.getContextPath();
System.out.println(contextPath);
//根据虚拟目录获取应用部署的磁盘绝对路径
//获取b.txt文件的绝对路径
String b = context.getRealPath("/b.txt");
System.out.println(b);
//获取c.txt文件的绝对路径
String c = context.getRealPath("/WEB-INF/c.txt");
System.out.println(c);
//获取a.txt文件的绝对路径
String a = context.getRealPath("/WEB-INF/classes/a.txt");
System.out.println(a);
//向域对象中存储数据
context.setAttribute("username","zhangsan");
//移除域对象中username的数据
//context.removeAttribute("username");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}