Servlet 开发基础
Servlet 简介
狭义上的 Servlet 是一种接口,如果开发者想要开发一个动态的 Web 资源,只需要:
编写一个实现了 Servlet 接口的类。
把开发好的 Java 类部署到服务器中。
广义上来讲,我们就把实现了 Servlet 接口的程序也称之为一个 Servlet。
Servlet 生命周期
当服务器接收到了某个 Servlet 程序的请求的时候,会执行以下过程:
服务器会先判断是否拥有当前 Servlet 实例,如果有,跳到第四步。
调用 Servlet 的构造方法实例化 Servlet 获取对象。
调用 Servlet 实例的 init() 方法来初始化此对象。
创建此 HTTP 请求的 ServletRequest 和 ServletResponse 实例,并传入调用的 service(ServletRequest,ServletResponse) 方法。
当 Web 程序停止/重启,会调用对应实例的 destroy() 方法
创建 Servlet
我们在创建一个 Servlet 类的时候,一般会直接继承 HttpServlet ,里面提供了很多强大的功能,它已经写好了 service() 方法,并对请求分流到 doGet() 和 doPost() 方法。所以我们只需要重写这两个方法来分别处理 Get 和 Post 请求即可。
创建 Servlet 之后,需要进行 Servlet-URL 进行映射,来确定在访问哪些 URL 的时候,让对应的 Servlet 去处理。这里有两种方法,一种是在 IDEA 创建 Servlet 的 Java 文件的时候,勾选 Create Java EE 6+ Annotated class
选项使用注解来注册 Servlet ,然后生成的 Servlet 代码的类前面会有注解: @WebServlet(name = "XXXX", value = "XXXX")
name 表示 Servlet 服务名称,value 表示对应映射的 URL。
或者不勾选哪个选项,然后自己在 web.xml 配置文件中添加 servlet 信息:
1 | <servlet> <!-- 这里注册 servlet --> |
这里创建映射的时候,可以使用通配符 * ,比如 /*
和 /XXXX/*.txt
等等。而对于一个路径有多个 Servlet 对应,那么路径映射返回越大的 Servlet 优先级越低。
如果有路径映射为 /
的 Servlet,那么这个 Servlet 就会成为默认 Servlet,所有找不到路径映射的访问都会指向这个 Servlet 去处理。
Servlet 线程安全
需要注意,一个 Servlet 程序在运行中只会创建一个实例,所以面对并发访问的时候,Tomcat 会创建新的线程去运行 service() 方法,但所有线程运行的 service() 都是属于同一个 Servlet 对象的。所以一旦涉及到非 service() 方法本地的访问与调用,就有可能牵扯到线程安全问题。
所以一定要小心 service() doGet() doPost() 方法所有的外部调用,避免出现线程安全问题,
ServletConfig
在 web.xml 文件的 servlet 标签下面可以设置此 Servlet 程序的初始化配置参数 <init-param>
。
1 | <servlet> |
然后可以调用 父类 GenericServlet 的方法 getServletConfig() 获取一个 ServletConfig 实例,此实例的 getInitParameterNames() 和 getInitParameter() 可以获取 Servlet 配置里面的初始化参数。
1 | public void showInitPara() { |
ServletContext
概念
ServletContext 对象是所有的 Web 应用都会有的一个单列实例,这个单列实例可以被这个 Web 应用的所有 Servlet 访问并修改内容,我们可以通过这个单列实例完成很多事情。
获取 Web 应用的初始化参数
和 ServletConfig 可以访问到 Servlet 的配置信息 <init-param>
一样,对于 Web 应用级别的 ServletContext 对象可以访问 Web 应用的配置信息 <context-param>
,这个标签在 web.xml 中和 <servlet>
同级别。我们可以设置一些这样的 Context 属性。
1 | <web-app> |
获取 ServletContext 除了调用父类的 getServletContext() 以外,还可以调用 ServletConfig 实例的 getServletContext() 方法(因为它内部封装了 ServletContext 的实例,可以调用出来)。然后剩下的步骤和 ServletConfig 读取初始化参数一样了。
1 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { |
Servlet 数据共享
因为 ServletContext 是所有 Servlet 都能能访问的单列实例,所以就可以利用这个实例才存储一些数据,从而使不同的 Servlet 之间可以共享这些数据。
共享的方法就是将数据存储到实例的属性值中,使用方法 setAttribute(Name,Value) 和 getAttribute(Name) 来存取数据,实现不同 Servlet 之间的交流。
获取工程的绝对路径
使用 ServletContext 的 getReadPath(String) 来返回路径字符串,其中参数填写相对路径即可,比如 "./"
,然后返回项目在电脑中的绝对路径。
Servlet 请求转发
请求转发使用的是一个请求调度器 RequestDispatcher 里面的 forward(resquest,response) 可以将信息转发。而获取请求调度器的方法有几种:
通过 ServletContext 的 getRequestDispatcher(String) 获取
通过请求 HttpServletRequest 的 getRequestDispatcher(String) 获取
其中参数为目标 Servlet 的映射地址。
获取 RequestDispatcher 之后,使用 forward() 转发请求即可:
1 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { |