JavaWeb的三大组件之一Servlet
javaWeb的三大组件指的是Filter Servlet Listener 分别是(过滤器 服务程序 监听器)
1 什么是Servlet
Servlet是JavaWeb的三大组件之一,它属于动态资源。Servlet的作用是处理请求,服务器会把接收到的请求交给Servlet来处理,在Servlet中通常需要:
l 接收请求数据;
l 处理请求;
l 完成响应。
例如客户端发出登录请求,或者输出注册请求,这些请求都应该由Servlet来完成处理!Servlet需要我们自己来编写,每个Servlet必须实现javax.servlet.Servlet接口。
2 实现Servlet的三种方式(有我们自己来写)
l 实现javax.servlet.Servlet接口;
l 继承javax.servlet.GenericServlet类;
l 继承javax.servlet.http.HttpServlet类;(重要)
HttpServlet类是GenericServlet的子类,他提供了对HTTP请求的特殊支持 所有我们通常都会通过继承HttpServlet来完成自定义的Servlet
在HttpServlet的service(HttpServletRequest,HttpServletResponse)方法会去判断当前请求是GET还是POST,如果是GET请求,那么会去调用本类的doGet()方法,如果是POST请求会去调用doPost()方法,这说明我们在子类中去覆盖doGet()或doPost()方法即可
在web.xml 中配置Servlet(这里内容也很重要)
|
|
3 Servlet的生命周期
所谓xxx的生命周期,就是说xxx的出生、服务,以及死亡。Servlet生命周期也是如此!与Servlet的生命周期相关的方法有:
l void init(ServletConfig);
l void service(ServletRequest,ServletResponse);
l void destroy();
(1)Servlet的出生
当客户端浏览器第一次访问的Servlet的时候 init() 方法被执行 此时Servlet诞生
(2)Servlet的服务
当服务器每次接收到请求时,都会去调用Servlet的service()方法来处理请求。服务器接收到一次请求,就会调用service() 方法一次,所以service()方法是会被调用多次的。正因为如此,所以我们才需要把处理请求的代码写到service()方法中!
(3)Servlet的离去
Servlet是不会轻易离去的,通常都是在服务器关闭时Servlet才会离去!在服务器被关闭时,服务器会去销毁Servlet,在销毁Servlet之前服务器会先去调用Servlet的destroy()方法,我们可以把Servlet的临终遗言放到destroy()方法中,例如对某些资源的释放等代码放到destroy()方法中。
4 ServletConfig对象
ServletConfig对象对应web.xml文件中的<servlet>元素。例如你想获取当前Servlet在web.xml文件中的配置名,那么可以使用servletConfig.getServletName()方法获取!
ServletConfig对象是由服务器创建的,然后传递给Servlet的init()方法,你可以在init()方法中使用它!
l String getServletName():获取Servlet在web.xml文件中的配置名称,即<servlet-name>指定的名称;
l ServletContext getServletContext():用来获取ServletContext对象,ServletContext会在后面讲解;
l String getInitParameter(String name):用来获取在web.xml中配置的初始化参数,通过参数名来获取参数值;
l Enumeration getInitParameterNames():用来获取在web.xml中配置的所有初始化参数名称;
在<servlet>元素中还可以配置初始化参数:
5 Servlet细节
Servlet特性 :Servlet是单例 线程异步 所以线程不安全 但效率高
因为一个类型的Servlet只有一个实例对象,那么就有可能会现时出一个Servlet同时处理多个请求,那么Servlet是否为线程安全的呢?答案是:“不是线程安全的”。这说明Servlet的工作效率很高,但也存在线程安全问题!
所以我们不应该在Servlet中随意创建成员变量,因为可能会存在一个线程对这个成员变量进行写操作,另一个线程对这个成员变量进行读操作。
线程异步出现数据安全问题(解决)
l 不要在Servlet中创建成员!创建局部变量即可!
l 可以创建无状态成员!(定义的属性成员没有相应的get() set() 方法)
l 可以创建有状态的成员,但状态必须为只读的!(没有set() 方法)
6 Servlet的创建时机
默认情况下,服务器会在浏览器第一次访问Servlet时创建
也可以在web.xml中对Servlet进行配置 让服务器启动时就创建Servlet
在<servlet>元素中配置<load-on-startup>元素可以让服务器在启动时就创建该Servlet,其中<load-on-startup>元素的值必须是大于等于0的整数,它的使用是服务器启动时创建Servlet的顺序。上例中,根据<load-on-startup>的值可以得知服务器创建Servlet的顺序为Hello1Servlet、Hello2Servlet、Hello3Servlet。
7 URL的映射路径
<url-pattern>
<url-pattern>是<servlet-mapping>的子元素,用来指定Servlet的访问路径,即URL。它必须是以“/”开头!
1) 可以在<servlet-mapping>中给出多个<url-pattern>,例如:
<servlet-mapping> <servlet-name>AServlet</servlet-name> <url-pattern>/AServlet</url-pattern> <url-pattern>/BServlet</url-pattern> </servlet-mapping> |
那么这说明一个Servlet绑定了两个URL,无论访问/AServlet还是/BServlet,访问的都是AServlet。
2) 还可以在<url-pattern>中使用通配符,所谓通配符就是星号“*”,星号可以匹配任何URL前缀或后缀,使用通配符可以命名一个Servlet绑定一组URL,例如:
l <url-pattern>/servlet/*<url-patter>:/servlet/a、/servlet/b,都匹配/servlet/*;
l <url-pattern>*.do</url-pattern>:/abc/def/ghi.do、/a.do,都匹配*.do;
l <url-pattern>/*<url-pattern>:匹配所有URL;
请注意,通配符要么为前缀,要么为后缀,不能出现在URL中间位置,也不能只有通配符。例如:/*.do就是错误的,因为星号出现在URL的中间位置上了。*.*也是不对的,因为一个URL中最多只能出现一个通配符。
注意,通配符是一种模糊匹配URL的方式,如果存在更具体的<url-pattern>,那么访问路径会去匹配具体的<url-pattern>。例如:
<servlet> <servlet-name>hello1</servlet-name> <servlet-class>cn.itcast.servlet.Hello1Servlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello1</servlet-name> <url-pattern>/servlet/hello1</url-pattern> </servlet-mapping> <servlet> <servlet-name>hello2</servlet-name> <servlet-class>cn.itcast.servlet.Hello2Servlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello2</servlet-name> <url-pattern>/servlet/*</url-pattern> </servlet-mapping> |
当访问路径为http://localhost:8080/hello/servlet/hello1时,因为访问路径即匹配hello1的<url-pattern>,又匹配hello2的<url-pattern>,但因为hello1的<url-pattern>中没有通配符,所以优先匹配,即设置hello1。
8 ServletContext对象
(1)特点:
一个项目只有一个ServletContext对象!
我们可以在N多个Servlet中来获取这个唯一的对象,使用它可以给多个Servlet传递数据!
(2)生命周期 : 和WEB容器一样长
服务器启动时创建
服务器关闭时销毁
(3)获得方式
l ServletConfig#getServletContext();
l GenericServlet#getServletContext();
l HttpSession#getServletContext()
l ServletContextEvent#getServletContext()
(4)作用
(1)域对象的功能
ServletContext是JavaWeb四大域对象之一:
l PageContext;
l ServletRequest;
l HttpSession;
l ServletContext;
所有域对象都有存取数据的功能,因为域对象内部有一个Map,用来存储数据,下面是ServletContext对象用来操作数据的方法:
setAttribute("attName","attVal"); 存储数据设置属性名 属性值
getAttribute("attName"); 通过属性名获得属性值
remaveAttribute("attName");通过属性名移除属性
getAttributeNames(); 返回的是一个枚举类型 所有的属性名称
案例 :记录网站访问的次数
(2)获取应用初始化参数
l Servlet也可以获取初始化参数,但它是局部的参数;也就是说,一个Servlet只能获取自己的初始化参数,不能获取别人的,即初始化参数只为一个Servlet准备!
l 可以配置公共的初始化参数,为所有Servlet而用!这需要使用ServletContext才能使用!
首先应用级别初始化参数的配置
使用ServletContext来获取在web.xml文件中配置的应用初始化参数!注意,应用初始化参数与Servlet初始化参数不同:
方法:getInitParameter("paramName"); 返回参数名称对应的参数值
getInitParameterNames(); 获得所有参数的名称 返回的是枚举
(3)获取应用资源
还可以使用ServletContext对象来获取Web应用下的资源,例如在hello应用的根目录下创建a.txt文件,现在想在Servlet中获取这个资源,就可以使用ServletContext来获取。
(3.1)获取真实路径
获取a.txt的真实路径:String realPath = servletContext.getRealPath(“/a.txt”) //路径相对于当前的web应用程序
获取b.txt的真实路径:String realPath =servletContext.getRealPath(“/WEB-INF/b.txt”); //路径相对于当前的web应用程序
(3.2)获取资源流
不只可以获取资源的路径,还可以通过ServletContext获取资源流,即把资源以输入流的方式获取:
获取a.txt资源流:InputStream in =servletContext.getResourceAsStream(“/a.txt”);//路径相对于当前的web应用程序
获取b.txt资源流:InputStream in =servletContext.getResourceAsStream(“/WEB-INF/b.txt”);//路径相对于当前的web应用程序
(3.3)获取指定目录下的所有资源路径
还可以使用ServletContext获取指定目录下所有资源路径,例如获取/WEB-INF下所有资源的路径:
方法:getResourcePaths("/");
Set set =context.getResourcePaths("/WEB-INF"); //返回的是set集合
注意:本方法必须以“/”开头!!!