- void init(ServletConfig servletConfig):Servlet对象创建之后马上执行的初始化方法,只执行一次;
- void service(ServletRequest servletRequest, ServletResponse servletResponse):每次处理请求都是在调用这个方法,它会被调用多次;
- void destroy():在Servlet被销毁之前调用,负责释放Servlet对象占用的资源的方法;
特性:
- 单例,一个类只有一个对象,当然可能存在多个Servlet类
- 线程不安全的,所以它的效率高。
Servlet类由自己编写,但对象由服务器来创建,并由服务器来调用相应的方法。
/** * Servlet接口方法介绍 * 类由我们自己创建(可变部分),Servlet中的方法大多数由Tomcat来调用,并且Servlet对象也由Tomcat来创建。 */ public class AServlet implements Servlet { /* * 它是生命周期方法 * 它会在Servlet对象创建之后马上执行,并只执行一次。 * 负责Servlet初始化工作。 */ @Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println("init()..."); } /* * 用来获取Servlet的配置信息 */ @Override public ServletConfig getServletConfig() { System.out.println("getServletConfig()..."); return null; } /* * 它是生命周期方法 * 它会被调用多次 * 每次处理请求都是在调用这个方法 */ @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException { System.out.println("service()..."); } /* * 获取Servlet的信息 */ @Override public String getServletInfo() { System.out.println("getServletInfo()..."); return null; } /* * 它是生命周期方法 * 它会在Servlet被销毁之前调用,负责释放Servlet对象占用的资源,并且它只会被调用一次。 */ @Override public void destroy() { System.out.println("destroy()..."); } }
- 不要在Servlet中创建成员,创建局部变量变量即可!
- 可以创建无状态成员!
- 可以创建有状态的成员,但状态必须位为只读的!
1 public class Servlet extends HttpServlet { 2 //无状态成员 3 /*public class User { 4 public void hello() { 5 System.out.println("Hello"); 6 } 7 }*/ 8 //创建有状态的成员,但状态必须位为只读的 9 /*public class User { 10 private String name = "zhangsan"; 11 public String getName() { 12 return name; 13 } 14 }*/ 15 private User user = new User(); 16 17 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 18 System.out.println("doPost()..."); 19 } 20 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 21 System.out.println("doGet()..."); 22 } 23 }
2、让服务器在启动时就创建Servlet对象
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 5 version="3.1"> 6 <servlet> 7 <servlet-name>Servlet</servlet-name> 8 <servlet-class>web.servlet.Servlet</servlet-class> 9 <load-on-startup>0</load-on-startup> 10 </servlet> 11 <servlet-mapping> 12 <servlet-name>Servlet</servlet-name> 13 <url-pattern>/Servlet</url-pattern> 14 </servlet-mapping> 15 <servlet> 16 <servlet-name>Servlet2</servlet-name> 17 <servlet-class>web.servlet.Servlet2</servlet-class> 18 <load-on-startup>1</load-on-startup> 19 </servlet> 20 <servlet-mapping> 21 <servlet-name>Servlet2</servlet-name> 22 <url-pattern>/Servlet2</url-pattern> 23 </servlet-mapping> 24 </web-app>
第9、18行作用:用于指定Servlet被加载的时机和顺序,值必须为一个整数。如果这个值是一个负数或没有设定这个元素,Servlet容器将在客户端首次请求这个Servlet时加载它。如果设置此元素,值越小,越先被加载。
3、<url-pattern>
用来指定Servlet的访问路径,即URL。必须以“/”开头。
1)可以在<servlet-mapping>中给出多个<url-pattern>,即一对多,如
<servlet-mapping> <servlet-name>Servlet2</servlet-name> <url-pattern>/Servlet2</url-pattern> <url-pattern>/Servlet3</url-pattern> </servlet-mapping>
此功能已被Filter替代。
2)还可以在<url-pattern>中使用通配符“*”,可以匹配任何URL前缀或后缀。
- <url-pattern>/servlet/*</url-pattern>:/servlet/a、/servlet/b,都匹配/servlet/*;
- <url-pattern>*.do</url-pattern>:/abc/def/gif.do、/a.do,都匹配*.do;
- <url-pattern>/*</url-pattern>:匹配所有URL;
注意:通配符不能出现URL中间位置,也不能只有通配符且只能出现一个,如“/*.do”、"*.*"都是错误的
优先匹配更具体的路径。
二、web.xml文件的继承(了解)
每个完整的JavaWeb应用中都需要有web.xml,但我们不知道所有的web.xml都有一个共同的父文件,他在Tomcatd的conf/web.xml中。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 5 version="3.1"> 6 <servlet> 7 <servlet-name>default</servlet-name> 8 <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> 9 <init-param> 10 <param-name>debug</param-name> 11 <param-value>0</param-value> 12 </init-param> 13 <init-param> 14 <param-name>listings</param-name> 15 <param-value>false</param-value> 16 </init-param> 17 <load-on-startup>1</load-on-startup> 18 </servlet> 19 </web-app>
第7行,表示它的优先级最低,如果一个请求没有人处理,那么它来处理,显示404。
第8行,当访问路径不存在时,会执行该Servlet!我访问index.html时也执行这个Servlet。
三、ServletContext接口
1)ServletContext接口概述
服务器会为每个应用(项目)创建一个ServletContext对象:
-
- ServletContext对象的创建是在服务器启动时完成的。
- ServletContext对象的销毁是在服务器关闭时完成的。
ServletContext对象的作用是在整个Web应用的动态资源之间共享数据。例如在AServlet中向ServletContext对象中保存一个值,然后再BServlet中就可以获取这个值,这就是共享数据了。
2)获取ServletContext
- ServletConfig#getServletContext();
- GenericServlet#getServletContext();
- HttpSessin#getServletContext();
- ServletContextEvent#getServletContext();
在Servlet中获取ServletContext对象:
- 在void init(ServletConfig config)中:ServletContext context = config.getServletContext();
ServletConfig类的getServletContext()可以获取ServletContext对象;
在GenericeServlet或HttpServlet中获取ServletContext对象;
- GenericServlet类有getServletContext()方法,所以可以直接使用this.getServletContext()来获取;
3)域对象的功能
- 域对象就是用来在多个Servlet中传递数据。
- 域对象必须有存数据功能。
- 域对象必须要有取数据功能。
ServletContext是JavaWeb四大域对象之一:PageContext、ServletRequest、HttpSession、ServletContext;
所有域对象都有存取数据的功能,因为域对象内部都有一个Map,用来储存数据,下面是ServletContext对象用来操作数据的方法:
- void setAttribute(String name, Object value):用来储存一个对象,也称之为存储一个域属性,例如:servletContext.setAttribute("xxx","XXX"),在ServletContext中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。请注意,如果多次调用该方法,并使用相同的name,那么会覆盖上一次的值,与Map特性相同。
- Object getAttribute(String name):用来获取ServletContext中的数据,当前在获取之前需要先去存储才行。例如:String value = (String) servletContext.getAttribute("xxx"),获取名为xxx的域属性。
- void removeAttribute(String name):用来移除ServletContext中的域属性,如果参数name指定的域属性不存在,那么方法什么都不做;
- Eumeration getAttributeNames():获取所有域属性的名称。
4)获取应用初始化参数
Servlet也可以获取初始化参数,但它是局部的参数;也就是说,一个Servlet只能获取自己的初始化参数,不能获取别人的,即初始化参数只为一个Servlet准备。
可以配置公共的初始化参数,为所有Servlet而用,这需要ServletContext才能使用。
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_3_1.xsd" version="3.1"> <servlet> <servlet-name>CServlet</servlet-name> <servlet-class>web.servlet.CServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>CServlet</servlet-name> <url-pattern>/CServlet</url-pattern> </servlet-mapping> <context-param> <param-name>context-param</param-name> <param-value>context-value</param-value> </context-param> </web-app>
Java文档
public class CServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /*1、得到ServletContext * 2、调用它的getInitParameter(String)得到初始化参数 * */ ServletContext application = this.getServletContext(); String value = application.getInitParameter("context-param"); System.out.println(value); } }
启动Tomcat,访问localhost:8080/CServlet,控制台输出“context-value”。
5)获取相关资源
1 /* 2 *使用ServletContext获取资源路径 3 * */ 4 @WebServlet(name = "DServlet") 5 public class DServlet extends HttpServlet { 6 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 7 /* 8 * 得到的是绝对路径 9 * /Users/Shared/练习/day_03/out/artifacts/day_03_war_exploded/index.jsp 10 * */ 11 String path = this.getServletContext().getRealPath("index.jsp"); 12 System.out.println(path); 13 /* 14 * 获取资源的路径后,再创建出输入流对象 15 * */ 16 InputStream input = this.getServletContext().getResourceAsStream("index.jsp"); 17 /* 18 *获取当前路径下所有资源的路径 19 * */ 20 Set<String> paths = this.getServletContext().getResourcePaths("/WEB-INF"); 21 System.out.println(paths); 22 } 23 }
6)访问量统计小练习
一个项目中所有的资源被访问都要对访问量进行累加。
创建一个int类型的变量,用来保存访问量,然后把它保存到ServletContext的域中,这样可以保存所有的Servlet都可以访问到。
- 最初时,ServletContext中没有保存访问量相关的属性
- 当本站第一次被访问时,创建一个变量,设置其值为1;保存到ServletContext中;
- 当以后的访问时,就可以从ServletContext中获取这个变量,然后再其基础上加1.
- 获取ServletContext对象,查看是否存在名为count的属性,如果存在,说明不是第一次访问,如果不存在,说明是第一次访问。
1、第一次访问:调用ServletContext的setAttribute()传递一个属性,名为count,值为1;
2、第2~n次访问,调用ServletContext的getAttribute()方法获取原来的访问量,给访问量加1,再调用ServletContext的setAttribute()方法完成设置。
/** * 统计访问量 */ @WebServlet(name = "Servlet") public class Servlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext app = this.getServletContext(); Integer count = (Integer) app.getAttribute("count"); if (count==null){ app.setAttribute("count",1); }else { app.setAttribute("count",count+1); } /* * 向浏览器输出 * 需要使用响应对象 * */ PrintWriter pw = response.getWriter(); pw.print("<h1>"+count+"</h>"); } }
注:当服务器关闭,计数重新开始。
7、获取类路径下的资源
获取类路径资源,类路径对一个JavaWeb项目而言,就是/WEB-INF/classes和/WEB-INF/lib每个jar包。
Class、ClassLoader
/* * 演示获取类路径下的资源 * */ @WebServlet(name = "Servlet",urlPatterns = "/Servlet") public class Servlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * 1、得到ClassLoader * 先得到Class,再得到ClassLoader * 2、调用器getResourceAsStream(),得到一个InputStream * */ // ClassLoader c1 = this.getClass().getClassLoader(); //相对/class // InputStream input = c1.getResourceAsStream("a.txt"); Class c = this.getClass(); //相对当前.class文件所在目录 InputStream input = c.getResourceAsStream("a.txt"); String str = IOUtils.toString(input,"utf-8");//问题所在之处,如何解决? System.out.println(str); } }