一、Servlet概述
1.什么是Servlet
Servlet是JavaWeb的三大组件之一,它属于动态资源。Servlet的作用是处理请求,服务器会把接收到的请求交给Servlet来处理,在Servlet中通常需要:
接收请求数据;
处理请求;
完成响应。
例如客户端发出登录请求,或者输出注册请求,这些请求都应该由Servlet来完成处理!Servlet需要我们自己来编写,每个Servlet必须实现javax.servlet.Servlet接口。
2.Servlet的生命周期
(1)服务器启动时或者第一次请求该servlet时,就会初始化一个Servlet对象,执行初始化方法init(ServletConfig conf)。
(2) 该servlet对象每次处理客户端请求,都会调用方法 service(ServletRequest req,ServletResponse res)。
(3)最后服务器关闭时,才会销毁这个servlet对象,执行方法destroy()。

3.实现Servlet的方式(手动编写)
实现Servlet有三种方式:(1)实现javax.servlet.Servlet接口;
(2)继承javax.servlet.GenericServlet类;
(3)继承javax.servlet.http.HttpServlet类;
通常我们会去继承HttpServlet类来完成我们的Servlet,但学习Servlet还要从javax.servlet.Servlet接口开始学习。
特性:
(1)单例,一个类只有一个对象;当然可能存在多个Servlet类!
(2)线程不安全,所以它的效率高!
(3)Servlet中的方法大多数不由我们来调用,而是由服务器来调用。并且Servlet的对象也不由我们来创建,由服务器来创建!
public interface Servlet{
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}

二、Servlet接口
1.Servlet接口方法中的参数
ServletRequest:service() 方法的参数,它表示请求对象,它封装了所有与请求相关的数据,它是由服务器创建的;
ServletResponse:service()方法的参数,它表示响应对象,在service()方法中完成对客户端的响应需要使用这个对象;
ServletConfig:init()方法的参数,它表示Servlet配置对象,它对应Servlet的配置信息,那对应web.xml文件中的<servlet>元素。
2.SercletConfig
一个ServletConfig对象对应一段web.xml文件中的<servlet配置信息。
<servlet>
<servlet-name>One</servlet-name>
<servlet-class>cn.yfy.servlet.OneServlet</servlet-class>
<init-param>
<param-name>paramName1</param-name>
<param-value>paramValue1</param-value>
</init-param>
<init-param>
<param-name>paramName2</param-name>
<param-value>paramValue2</param-value>
</init-param>
</servlet>ServletConfig对象是由服务器创建的,然后传递给Servlet的init()方法,可以在init()方法中使用它!
ServletConfig接口中的方法:
String getServletName():获取Servlet在web.xml文件中的配置名称,即<servlet-name>指定的名称;
ServletContext getServletContext():用来获取ServletContext对象,ServletContext会在后面讲解;
String getInitParameter(String name):用来获取在web.xml中配置的初始化参数,通过参数名来获取参数值;
Enumeration getInitParameterNames():用来获取在web.xml中配置的所有初始化参数名称;
三、GenericServlet
1.GenericServlet概述
GenericServlet是Servlet接口的实现类,我们可以通过继承GenericServlet来编写自己的Servlet。下面是GenericServlet类的源代码:
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 "";
}
//实现了Servlet的init(ServletConfig)方法,把参数config赋给了本类的成员config,然后再调用本类自己的无参的init()方法。
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
//这个方法是GenericServlet自己的方法,而不是从Servlet继承下来的。
//当我们自定义Servlet时,如果想完成初始化作用就不要再重复init(ServletConfig)方法了,而是应该去重写init()方法。
//因为在GenericServlet中的init(ServletConfig)方法中保存了ServletConfig对象,
//如果覆盖了保存ServletConfig的代码,那么就不能再使用ServletConfig了。
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();
}
}2.GenericServlet的init()方法
在GenericServlet中,定义了一个ServletConfig config实例变量,并在init(ServletConfig)方法中把参
数ServletConfig赋给了实例变量。然后在该类的很多方法中使用了实例变量config。
如果子类覆盖了GenericServlet的init(StringConfig)方法,那么this.config=config这一条语句就会被覆盖了,也就是说GenericServlet的实例变量config的值为null,那么所有依赖config的方法都不能使用了。如果真的希望完成一些初始化操作,那么去覆盖GenericServlet提供的init()方法,它是没有参数的init()方法,它会在init(ServletConfig)方法中被调用。
3.实现了ServletConfig接口
GenericServlet还实现了ServletConfig接口,所以可以直接调用getInitParameter()、getServletContext()等ServletConfig的方法。
四、HttpServlet
1.HttpServlet概述
HttpServlet类是GenericServlet的子类,它提供了对HTTP请求的特殊支持,所以通常我们都会通过继承HttpServlet来完成自定义的Servlet。
2.HttpServlet的时序图

3.HttpServlet覆盖了Service()方法
HttpServlet类中提供了service(HttpServletRequest,HttpServletResponse)方法,这个方法是HttpServlet自己的方法,不是从Servlet继承来的。
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); //调用上面service()方法
}
……
}4.doGet()和doPost()方法
在HttpServlet的service(HttpServletRequest,HttpServletResponse)方法会去判断当前请求是GET还是POST,如果是GET请求,那么会去调用本类的doGet()方法,如果是POST请求会去调用doPost()方法,这说明我们在子类中去覆盖doGet()或doPost()方法即可。
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("hello doGet()...");
}
}
public class BServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("hello doPost()...");
}
}五、Servlet细节
1.Servlet与线程安全
因为一个类型的Servlet只有一个实例对象,那么就有可能会现时出一个Servlet同时处理多个请求,那么Servlet是否为线程安全的呢?答案是:“不是线程安全的”。这说明Servlet的工作效率很高,但也存在线程安全问题!
所以我们不应该在Servlet中创建成员变量,因为可能会存在一个线程对这个成员变量进行写操作,另一个线程对这个成员变量进行读操作。
不要在Servlet中创建成员!创建局部变量即可!
可以创建无状态成员!
可以创建有状态的成员,但状态必须为只读的!
2.让服务器在启动时就创建Servlet
默认情况下,服务器会在某个Servlet第一次收到请求时创建它。也可以在web.xml中对Servlet进行配置,使服务器启动时就创建Servlet。
<servlet>
<servlet-name>hello1</servlet-name>
<servlet-class>cn.itcast.servlet.Hello1Servlet</servlet-class>
<load-on-startup>0</load-on-startup>//在<servlet>中配置<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> load-on-startup的值越小,优先级越高,先创建。3.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,例如:
<url-pattern>/servlet/*<url-patter>:/servlet/a、/servlet/b,都匹配/servlet/*; //路径匹配
<url-pattern>*.do</url-pattern>:/abc/def/ghi.do、/a.do,都匹配*.do; //拓展名匹配
<url-pattern>/*<url-pattern>:匹配所有URL; //匹配所有url
注意:
(1)通配符要么为前缀,要么为后缀,不能出现在URL中间位置,也不能只有通配符。例如:/*.do就是错误的,因为星号出现在URL的中间位置上了。*.*也是不对的,因为一个URL中最多只能出现一个通配符。
(2)通配符是一种模糊匹配URL的方式,如果存在更具体的<url-pattern>,那么访问路径会去匹配具体的<url-pattern>。
六、ServletContext
1.ServletContext概述
服务器会为每个应用创建一个ServletContext对象:
ServletContext对象的创建是在服务器启动时完成的;
ServletContext对象的销毁是在服务器关闭时完成的。
ServletContext对象的作用是在整个Web应用的动态资源之间共享数据!例如在AServlet中向ServletContext对象中保存一个值,然后在BServlet中就可以获取这个值,这就是共享数据了。
2.获取ServletContext
(1)在Servlet中获取ServletContext对象:
在void init(ServletConfig config)中:ServletContext context = config.getServletContext();
ServletConfig类的getServletContext()方法可以用来获取ServletContext对象;
(2)在GenericeServlet或HttpServlet中获取ServletContext对象:GenericServlet类有getServletContext()方法,所以可以直接使用this.getServletContext()来获取;
3.域对象
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指定的域属性不存在,那么本方法什么都不做;
Enumeration getAttributeNames():获取所有域属性的名称;
4.获取应用初始化参数
可以使用ServletContext来获取在web.xml文件中配置的应用初始化参数!
<context-param>
<param-name>paramName1</param-name>
<param-value>paramValue1</param-value>
</context-param>
<context-param>
<param-name>paramName2</param-name>
<param-value>paramValue2</param-value>
</context-param> // 获取ServletContext对象
ServletContext context = this.getServletContext();
// 通过参数名,获取参数值
String value1 = context.getInitParameter("paramName1");
String value2 = context.getInitParameter("paramName2");
System.out.println(value1 + ", " + value2);
// 获取所有应用初始化参数名称
Enumeration names = context.getInitParameterNames();
while (names.hasMoreElements()) {
System.out.println(names.nextElement());
}5.获取资源相关方法
(1)获取真实路径
获取a.txt的真实路径:String realPath = servletContext.getRealPath(“/a.txt”);
获取b.txt的真实路径:String realPath = servletContext.getRealPath(“/WEB-INF/b.txt”);
(2)获取资源流
获取a.txt资源流:InputStream in = servletContext.getResourceAsStream(“/a.txt”);
获取b.txt资源流:InputStream in = servletContext.getResourceAsStream(“/WEB-INF/b.txt”);
(3)获取指定路径下所有资源路径
例如获取/WEB-INF下所有资源的路径:
ServletContext servletContext=this.getServletContext();
Set set = servletContext.getResourcePaths("/WEB-INF");
System.out.println(set);[/WEB-INF/lib/, /WEB-INF/classes/, /WEB-INF/b.txt, /WEB-INF/web.xml]注意,本方法必须以“/”开头!
6.获取类路径下资源

InputStream in = this.getClass().getResourceAsStream("/xxx.txt");
System.out.println(IOUtils.toString(in)); InputStream in = this.getClass().getClassLoader()
.getResourceAsStream("xxx.txt");
System.out.println(IOUtils.toString(in)); Class类的getResourceAsStream(String path): 路径以“/”开头,相对classes路径;
路径不以“/”开头,相对当前class文件所有路径,例如在cn.itcast.servlet.MyServlet中执行,那么相对/classes/cn/itcast/servlet/路径;
相对classes路径;
本文详细介绍了Servlet的概念、生命周期、实现方式及细节等内容,包括如何处理HTTP请求、线程安全问题及配置等。
1990

被折叠的 条评论
为什么被折叠?



