Servlet的作用:获取请求数据、处理请求、完成响应。
通常继承HttpServlet抽象类来写Servlet类,一个Servlet类只创建一个对象,默认在客户端第一次访问Servlet类时创建对象。Servlet是单例的,线程不安全。
<servlet> <servlet-name>hello1</servlet-name> <servlet-class>cn.itcast.servlet.Hello1Servlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>hello1</servlet-name> <url-pattern>/hello1</url-pattern> </servlet-mapping> <servlet> <servlet-name>hello2</servlet-name> <servlet-class>cn.itcast.servlet.Hello2Servlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>hello2</servlet-name> <url-pattern>/hello2</url-pattern> </servlet-mapping> <servlet> <servlet-name>hello3</servlet-name> <servlet-class>cn.itcast.servlet.Hello3Servlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>hello3</servlet-name> <url-pattern>/hello3</url-pattern> </servlet-mapping>
在<servlet>元素中配置<load-on-startup>元素可以让服务器在启动时就创建该Servlet,其中<load-on-startup>元素的值必须是大于等于0的整数,值越小就越先在服务器启动时创建。上例中,服务器启动时,创建Servlet的顺序为Hello1Servlet、Hello2Servlet、Hello3Servlet。
Servlet类由我们来写,但对象由服务器来创建,并且由服务器调用相应的方法。
1.Servlet接口
3个生命周期方法:
init(ServletConfig config):Servlet实例对象创建后,调用此方法。服务器会在Servlet第一次被访问时创建Servlet对象,或者服务器在启动时创建Servlet对象。
service(ServletRequest request, ServletResponse response):每访问一次Servlet,执行一次此方法
destroy():服务器销毁Servlet前,调用此方法
2.GenericServlet抽象类
GenericServlet继承了Servlet接口和ServletConfig接口,ServletConfig接口方法如下:
在GenericServlet中,定义了一个ServletConfig config实例变量,并在init(ServletConfig)方法中把参数ServletConfig赋给了实例变量。然后在该类的很多方法中使用了实例变量config。
public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable { private static final long serialVersionUID = 1L; private transient ServletConfig config; public GenericServlet() {} @Override public void destroy() {} @Override public String getInitParameter(String name) { return getServletConfig().getInitParameter(name); } @Override public Enumeration<String> getInitParameterNames() { return getServletConfig().getInitParameterNames(); } @Override public ServletConfig getServletConfig() { return config; } @Override public ServletContext getServletContext() { return getServletConfig().getServletContext(); } @Override public String getServletInfo() { return ""; } @Override public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } public void init() throws ServletException {} public void log(String msg) { getServletContext().log(getServletName() + ": " + msg); } public void log(String message, Throwable t) { getServletContext().log(getServletName() + ": " + message, t); } @Override public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; @Override public String getServletName() { return config.getServletName(); } }
GenericServlet只有service(ServletRequest request, ServletResponse response)一个抽象方法。
【注意】GenericServlet添加了init()方法,并且在生命周期方法init(ServletConfig)内部调用init()方法。如果子类覆盖了GenericServlet的init(ServletConfig)方法,那么this.config=config这一条语句就会被覆盖了,也就是说GenericServlet的实例变量config的值为null,那么所有依赖config的方法都不能使用了。如果真的希望完成一些初始化操作,应该重写init()方法,而不是生命周期方法init(ServletConfig)。
3.HttpServlet抽象类
HttpServlet是GenericServlet的子类,实现了GenericServlet中的抽象方法。
public abstract class HttpServlet extends GenericServlet { protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { …… } @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) req; response = (HttpServletResponse) res; } catch (ClassCastException e) { throw new ServletException("non-HTTP request or response"); } service(request, response); } …… }
HttpServletservice(ServletRequest, ServletResponse):内部会把ServletRequest强转成HttpServletRequest,把ServletResponse强转成HttpServletResponse,然后调用service(HttpServletRequest,HttpServletResponse)方法。
service(HttpServletRequest,HttpServletResponse):内部通过HttpRequest的getMethod()获取请求方式,然后根据请求方式调用相应的处理方法。例如:请求方式为get时,调用doGet()方法;请求方式是post时,调用doPost()方法。
因此,创建HttpServlet类时,应该重写doGet()或doPost()方法。
4.Servlet在web.xml中的配置
<servlet> <servlet-name>servletName</servlet-name> <servlet-class>servlet的全类名</servlet-class> </servlet> <servlet-mapping> <servlet-name>servletName</servlet-name> <url-pattern>servletPath<url-pattern> </servlet-mapping>
【注意】:
(1)一个<servlet-mapping>中给出多个<url-pattern>
(2)可以在<url-pattern>中使用通配符*
<url-pattern>/*<url-pattern>:表示匹配任何路径
<url-pattern>/do/*<url-pattern>:表示匹配以/do开头的任何路径
<url-pattern>*.do<url-pattern>:表示匹配任何以“.do”结尾的路径
通配符要么在开头,要么在结尾,不能在中间,例如:/*.do就是错误的。
如果不使用通配符,那么必须以“/”开头,例如:<url-pattern>abc</url-pattern>就是错误的。
通配符是一种模糊匹配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/JavaWeb/servlet/hello1时,优先匹配hello1的路径。