1.1 什么是 Servlet
1、Servlet 是 JavaEE的规范之一。(规范就是接口)
2、Servlet是 三大组件之一。
JavaWeb 三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器。
3、Servlet 是运行在服务器上的一个 java 小程序,它可以接收客户端发送过来的请求,并响应 数据给客户端。
1.2 手动实现 Servlet 程序
1、编写一个类去实现 Servlet 接口
public class HelloServlet implements Servlet
2、实现 service 方法,处理请求,并响应数据
3、到 web.xml 中去配置 servlet 程序的访问地址
- Servlet 程序的示例代码:
public class HelloServlet implements Servlet { @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("Hello Servlet 被访问了"); } }
- web.xml 中的配置:
<?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"> <!-- servlet 标签给 Tomcat 配置 Servlet 程序 --> <servlet> <!--servlet-name 标签 Servlet 程序起一个别名(一般是类名) --> <servlet-name>HelloServlet</servlet-name> <!--servlet-class 是 Servlet 程序的全类名 --> <servlet-class>com.atguigu.servlet.HelloServlet</servlet-class> </servlet> <!--servlet-mapping 标签给 servlet 程序配置访问地址 --> <servlet-mapping> <!--servlet-name 标签的作用是告诉服务器,我当前配置的地址给哪个 Servlet 程序使用 --> <servlet-name>HelloServlet</servlet-name> <!--url-pattern 标签配置访问地址 <br/> / 斜杠在服务器解析的时候,表示地址为: http://ip:port/ 工程路径 <br/> /hello 表示地址为: http://ip:port/ 工程路径 /hello <br/> --> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
执行原理:
- 当服务器接受到浏览器的请求后,会解析URL路径,获取访问的Servlet的资源路径
- 查找web.xml文件,是否有对应的标签体内容。
- 如果有,则在找到对应的全类名
- tomcat会将字节码文件加载进内存,并且创建其对象
- 调用其方法
- 在浏览器中添加指定的标签体内容即hello,就可以在idea控制台中看到Hello Servlet 被访问了这句话。
常见的错误 1:url-pattern 中配置的路径没有以斜杠打头。
常见错误 2:servlet-name 配置的值不存在:
常见错误 3:servlet-class 标签的全类名配置错误:
1.3 url 地址到 Servlet 程序的访问图析
1.4 Servlet 的生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。
以下是 Servlet 遵循的过程:
- Servlet 通过调用 init () 方法进行初始化。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 通过调用 destroy() 方法终止(结束)。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
1.5 GET 和 POST 请求的分发处理
public class HelloServlet implements Servlet { //service 方法是专门用来处理请求和响应的 @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("3 service === Hello Servlet 被访问了"); // 类型转换(因为它有 getMethod() 方法) HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; // 获取请求的方式 String method = httpServletRequest.getMethod(); if ("GET".equals(method)) { doGet(); } else if ("POST".equals(method)) { doPost(); } } //做 get 请求的操作 public void doGet(){ System.out.println("get 请求"); } //做 post 请求的操作 public void doPost(){ System.out.println("post 请求"); } }
1.6 通过继承 HttpServlet 实现 Servlet 程序
一般在实际项目开发中,都是使用继承 HttpServlet 类的方式去实现 Servlet 程序。
以下是使用继承 HttpServlet 类的过程:
1、编写一个类去继承 HttpServlet 类
2、根据业务需要重写 doGet 或 doPost 方法
3、到 web.xml 中的配置 Servlet 程序的访问地址
- Servlet 类的代码:
public class HelloServlet2 extends HttpServlet { // doGet()在 get 请求的时候调用 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException { System.out.println("HelloServlet2 的 doGet 方法"); } // doPost()在 post 请求的时候调用 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException { System.out.println("HelloServlet2 的 doPost 方法"); } }
- web.xml 中的配置:
<servlet> <servlet-name>HelloServlet2</servlet-name> <servlet-class>com.atguigu.servlet.HelloServlet2</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet2</servlet-name> <url-pattern>/hello2</url-pattern> </servlet-mapping>
1.7 使用 IDEA 创建 Servlet 程序
菜单:new ->Servlet 程序
配置 Servlet 的信息:
1.8 Servlet 类的继承体系
2.ServletConfig 类
ServletConfig 类从类名上来看,就知道是 Servlet 程序的配置信息类。
Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建,我们负责使用。
Servlet 程序默认是第一次访问的时候创建,ServletConfig 是每个 Servlet 程序创建时,就创建一个对应的 ServletConfig 对象。
2.1 ServletConfig 类的三大作用
1、可以获取 Servlet 程序的别名 servlet-name 的值
2、获取初始化参数 init-param
3、获取 ServletContext 对象
- web.xml 中的配置:
<!-- servlet 标签给 Tomcat 配置 Servlet 程序 --> <servlet> <!--servlet-name 标签 Servlet 程序起一个别名(一般是类名) --> <servlet-name>HelloServlet</servlet-name> <!--servlet-class 是 Servlet 程序的全类名 --> <servlet-class>com.atguigu.servlet.HelloServlet</servlet-class> <!--init-param 是初始化参数 --> <init-param> <!-- 是参数名 --> <param-name>username</param-name> <!-- 是参数值 --> <param-value>root</param-value> </init-param> <!--init-param 是初始化参数 --> <init-param> <!-- 是参数名 --> <param-name>url</param-name> <!-- 是参数值 --> <param-value>jdbc:mysql://localhost:3306/test</param-value> </init-param> </servlet> <!--servlet-mapping 标签给 servlet 程序配置访问地址 --> <servlet-mapping> <!--servlet-name 标签的作用是告诉服务器,我当前配置的地址给哪个 Servlet 程序使用 --> <servlet-name>HelloServlet</servlet-name> <!-- url-pattern 标签配置访问地址 <br/> / 斜杠在服务器解析的时候,表示地址为: http://ip:port/ 工程路径 <br/> /hello 表示地址为: http://ip:port/ 工程路径 /hello <br/> --> <url-pattern>/hello</url-pattern> </servlet-mapping>
- Servlet 中的代码:
@Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println("2 init 初始化方法"); // 1 、可以获取 Servlet 程序的别名 servlet-name 的值 System.out.println("HelloServlet 程序的别名是:" + servletConfig.getServletName()); // 2 、获取初始化参数 init-param System.out.println(" 初始化参数 username 的值是;" + servletConfig.getInitParameter("username")); System.out.println(" 初始化参数 url 的值是;" + servletConfig.getInitParameter("url")); // 3 、获取 ServletContext 对象 System.out.println(servletConfig.getServletContext()); }
注意点:
3.ServletContext 类
3.1 什么是 ServletContext?
1、ServletContext 是一个接口,它表示 Servlet 上下文对象
2、一个 web 工程,只有一个 ServletContext 对象实例。
3、ServletContext 对象是一个域对象。
4、ServletContext 是在 web 工程部署启动的时候创建。在 web 工程停止的时候销毁。
- 什么是域对象?
域对象,是可以像 Map 一样存取数据的对象,叫域对象。
这里的域指的是存取数据的操作范围,整个 web 工程。
存数据 | 取数据 | 删除数据 | |
Map | put() | get() | remove() |
域对象 | setAttribute() | getAttribute() | removeAttribute(); |
3.2 ServletContext 类的四个作用
1、获取 web.xml 中配置的上下文参数 context-param
2、获取当前的工程路径,格式: /工程路径
3、获取工程部署后在服务器硬盘上的绝对路径
4、像 Map 一样存取数据
- ServletContext 演示代码:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1 、获取 web.xml 中配置的上下文参数 context-param ServletContext context = getServletConfig().getServletContext(); String username = context.getInitParameter("username"); System.out.println("context-param 参数 username 的值是:" + username); System.out.println("context-param 参数 password 的值是:" + context.getInitParameter("password")); // 2 、获取当前的工程路径,格式 : / 工程路径 System.out.println( " 当前工程路径:" + context.getContextPath() ); // 3 、获取工程部署后在服务器硬盘上的绝对路径 /* 斜杠被服务器解析地址为 :http://ip:port/ 工程名 / 映射到 IDEA 代码的 web 目录 <br/> */ System.out.println(" 工程部署的路径是:" + context.getRealPath("/")); System.out.println(" 工程下 css 目录的绝对路径是:" +context.getRealPath("/css")); System.out.println(" 工程下 imgs 目录 1.jpg 的绝对路径是:" + context.getRealPath("/imgs/1.jpg")); }
- web.xml 中的配置:
<!--context-param 是上下文参数 ( 它属于整个 web 工程 )--> <context-param> <param-name>username</param-name> <param-value>context</param-value> </context-param> <!--context-param 是上下文参数 ( 它属于整个 web 工程 )--> <context-param> <param-name>password</param-name> <param-value>root</param-value> </context-param>
ServletContext 像 Map 一样存取数据:
- ContextServlet1 代码:
public class ContextServlet1 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取 ServletContext 对象 ServletContext context = getServletContext(); System.out.println(context); System.out.println(" 保存之前: Context1 取 获取 key1 的值是:"+ context.getAttribute("key1")); context.setAttribute("key1", "value1"); System.out.println("Context1 中获取域数据 key1 的值是:"+ context.getAttribute("key1")); } }
- ContextServlet2 代码:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext context = getServletContext(); System.out.println(context); System.out.println("Context2 中获取域数据 key1 的值是:"+ context.getAttribute("key1"));
Servlet入门篇的总结
执行原理
- 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径。在上图的URL中,获取的资源路径就是/demo01
- 查找web.xml文件,是否有对应的标签体内容。
- 如果有,则在找到对应的全类名,获取到的全路径是:cn.itcast.web.servlet.ServletDemo
- tomcat会将字节码文件加载进内存,并且创建其对象
- 调用其方法(主要调用service方法)
反射(补充)
类:模板,一堆代码的集合,类里面有:属性(字段)、方法等等。
对象:基于类来创建对象,通过对象来描述现实世界。就是要调用对象相关的方法。
创建类对象和调用方法一般用在两种地方:
- 编译时:其实就是在编写代码时候创建类对象,并调用。
// Person为p的编译时类型,Student为p的运行时类型 Person p = new Student();
- 运行时:在运行时,动态创建类对象,调用类方法
- 实现手段:主要通过Java的java.lang.Class类来完成。
- 获取java.lang.Class对象有三种方法:
- 使用Class的forName(String clazzName)方法,传入字符串,传入为类的全限定名。
- 调用某个类的class属性
- 调用getClass方法获得。
- 在反射中,通常采用Class.forName(String clazzName)方法动态获取类对象。
1.调用getClass()
//通过getClass()方法获得 Boolean b = true; Class<?> clazz = b.getClass(); System.out.println(clazz); //输出结果为:java.lang.Boolean
- 2.调用某个类的class属性
//通过class方法获得。 Class<?> clazz = Boolean.class; System.out.println(clazz); //输出结果为:java.lang.Boolean
- 3.通过Class.forName(String clazzName)获得
Class<?> clazz = Class.forName("java.lang.Boolean"); System.out.println(clazz); //输出结果为:java.lang.Boolean
根据字节码文件创建对象
- 根据字节码文件,调用无参构造方法,创建对象
Class<?> clazz = Class.forName("java.lang.Boolean"); System.out.println(clazz); //输出结果为:java.lang.Boolean Object o=clazz.newInstance();
- 根据字节码文件,调用有参数构造方法,创建对象
Class<?> clazz= Class.forName("java.lang.Integer"); System.out.println(clazz); //根据字节码获取构造函数 Constructor con= clazz.getConstructor(int.class); Object o=con.newInstance(10); System.out.println(o);
创建方法
if(args.length!=1){ System.out.println("参数错误"); return; } Class<?> clazz= Class.forName(args[0]); Object o=clazz.newInstance(); Method service=clazz.getMethod("service"); service.invoke(o);
生命周期详解
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。
以下是 Servlet 遵循的过程:
- Servlet 通过调用 init () 方法进行初始化。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 通过调用 destroy() 方法终止(结束)。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
现在让我们详细讨论生命周期的方法。
init() 方法
init 方法被设计成只调用一次。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。因此,它是用于一次性初始化,就像 Applet 的 init 方法一样。
Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。
当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。
init 方法的定义如下:
public void init() throws ServletException { // 初始化代码... }
service() 方法
service() 方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。
每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。
下面是该方法的特征:
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException{ }
service() 方法由容器调用,service 方法在适当的时候调用 doGet、doPost、doPut、doDelete 等方法。所以,您不用对 service() 方法做任何动作,您只需要根据来自客户端的请求类型来重写 doGet() 或 doPost() 即可。
doGet() 和 doPost() 方法是每次服务请求中最常用的方法。下面是这两种方法的特征。
doGet() 方法
GET 请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。
public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { // Servlet 代码 }
doPost() 方法
POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。
public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { // Servlet 代码 }
destroy() 方法
destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。
在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。destroy 方法定义如下所示:
public void destroy() { // 终止化代码... }
架构图
下图显示了一个典型的 Servlet 生命周期方案。
- 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
- Servlet 容器在调用 service() 方法之前加载 Servlet。
- 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。
Servlet的体系结构
Servlet – 接口
|
GenericServlet – 抽象类
|
HttpServlet – 抽象类
- GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
- 将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可
- HttpServlet:对http协议的一种封装,简化操作
- 定义类继承HttpServlet
- 复写doGet/doPost方法
- Servlet相关配置
- urlpartten:Servlet访问路径
- 一个Servlet可以定义多个访问路径 : @WebServlet({“/d4”,“/dd4”,“/ddd4”})
- 路径定义规则:
- /xxx:路径匹配
- /xxx/xxx:多层路径,目录结构
- *.do:扩展名匹配