下面这个Servlet编译、布署,它的response会输出一个html页面,页面上会显示一个Email地址:
package com.example.web;//确保与前面创建的开发结构和部署结构匹配
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class EmailShowServlet extends HttpServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("lyuComputer@163.com");
}
}
- 上面代码属于硬编码,它把以后可能会变动的数据写到程序代码中,这种方式不好。
- 如果将来Email地址将来发生改变,就要修改上面的Servlet中的代码,然后将该Servlet重新编译,重新布署。
- 如果此Email地址是公共服务邮箱,该网站有100个Servlet都要显示这个地址,那么就需要修改100个Servlet,重新编译100个Servlet....
解决之道:把Eamil地址写到Servlet初始化参数中。
- Servlet有初始化参数,可以利用。
- 给定一个参数名和参数值,只要保证把它配置在web.xml的servlet元素就行。
- web.xml代码:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<servlet>
<servlet-name>Chapter5</servlet-name>
<servlet-class>com.example.web.EmailShowServlet</servlet-class>
<init-param>
<param-name>adminEmail</param-name>
<param-value>lyuComputer@163.com</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Chapter5</servlet-name>
<url-pattern>/emailPage</url-pattern>
</servlet-mapping>
</web-app>
- Servlet的代码要改一改,不用最初的硬编码,采用读取配置参数的方式。
以下,是对上面代码的解释:
- 容器初始化一个servlet时,会为这个servlet建一个唯一的ServletConfig对象。
- 容器从web.xml读出servlet初始化参数,并把这些参数交给ServletConfig,然后把ServletConfig传递给servlet的init()方法。
- servlet初始化参数只能读一次,就是在容器初始化servlet的时候。
上面的解决方法前进了一步,但是还有问题:
- 如果想让Web应用的所有部分(注意:我们的日常真正Web应用并不只有一个Servlet)都能访问这个email地址,利用初始化参数,必须在配置文件中为每个servlet都要配置初始化参数。这样太麻烦了,而且可维护性很差。
- 我们需要一个更全局的东西。
解决之道:上下文初始化参数
- 上下文参数与servlet初始化参数很类似,只不过上下文参数对整个Web应用可见,而不只针对一个servlet。
- Web应用的所有servlet和JSP都自动能够访问上下文参数,我们不必操心为每个servlet配置,如果值有变化,只需在一个地方修改就行了。
- web.xml的关键代码,去掉上面的init-param元素,加上context-param元素。
<servlet>
<servlet-name>Chapter5</servlet-name>
<servlet-class>com.example.web.EmailShowServlet</servlet-class>
</servlet>
<context-param>
<param-name>adminEmail</param-name>
<param-value>1125234@qq.com</param-value>
</context-param>
- 在servlet代码中:
response.setContentType("text/html");
PrintWriter out = response.getWriter();
ServletContext sc = getServletContext();
out.println(sc.getInitParameter("adminEmail"));
上面两种方案的小总结:
- 每个Servlet有一个ServletConfig。
- 每个Web应用有一个ServletContext,而且Web应用中的所有部分都能访问它。所以,它是全局的。
上面的配置参数,只能是String类型。ServletContextListener能帮我们做更多的事情。
- 刚才的实验,上下文参数只能是String,有很大的局限性。你不能把一个Dog对象硬塞到web.xml中。
- 可以建立一个单独的类,它能监听ServletContext一生中的两个关键事件,初始化(创建)和撤销。这个类要实现javax.servlet.ServletContextListener。
一个简单的ServletContextListener实现。
- 我们要把String初始化参数转换为一个真正的对象(一个Dog),监听者的任务是得到有关狗品种(Beagle、Poodle等)的上下文初始化参数,然后使用这个String来构造一个Dog对象。监听者再把这个Dog对象存放到一个ServletContext属性中,以便servlet获取。
- 关键是,servlet现在能访问一个共享的应用对象(这是一个共享的Dog),而且不必读取上下文参数。
- 重点是使用初始化参数来创建一个对象,让应用的所有部分都能共享这个对象。
建立和使用一个上下文监听者
- 容器怎样发现和使用监听者?
- 就像告诉容器Web应用其他部分的有关情况一样,要用同样的办法配置监听者。就是通过web.xml。
- 过程:
- 监听者对象向ServletContextEvent对象请求应用ServletContext对象的一个引用。
- 监听者使用这个ServletContext引用得到"breed"的上下文初始化参数,这是一个String,表示狗的品种。
- 监听者使用这个狗品种String构造一个Dog对象。
- 监听者使用ServletContext引用在ServletContext中设置Dog属性。
- 这个Web应用的测试servlet从ServletContext得到Dog对象,并调用这个Dog的getBreed()方法。
建立和使用一个上下文监听者
要监听ServletContext事件,需要编写一个实现ServletContextListener的监听者类,把它放在WEB-INF/classes目录中,并在部署描述文件放一个元素来告诉容器。
监听者对象 类模版如下形式:
package com.example.web;
import javax.servlet.*;
public class MyServletContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent event){
//Code
ServletContext sc = event.getServletContext();
String dogBreed = sc.getInitParameter("breed");
Dog d = new Dog(dogBreed);
sc.setAttribute("dog", d);
}
public void contextDestroyed(ServletContextEvent event){
//Code
}
}
- web.xml加入listener元素
<listener>
<listener-class>
com.example.MyServletContextListener
</listener-class>
</listener>
针对于上面的解决方案,开始正式创建
- 需要3个类和一个web.xml。
- 为了便于编译和测试,我们把所有类都放在同一个包中:com.example
- ServletContextListener.java
- 这个类实现了ServletContextListener,它得到上下文初始化参数,创建Dog,并把Dog设置为上下文属性。
Dog.java
- Dog类只是一个普通的Java类,它的任务是作为一个属性值,由ServletContextListener实例化,并设置在ServletContext中,以便servlet获取。
ListenerTester.java
- 这个类是一个Servlet,它的任务是验证监听者的工作。为此,这个Servlet会从上下文得到Dog属性,然后调用Dog的getBreed(),并把结果打印到响应(以便我们在浏览器上看到)。
package com.example.web;
import javax.servlet.*;
public class MyServletContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent event){
ServletContext sc = event.getServletContext();//由事件得到ServletContext
String dogBreed = sc.getInitParameter("breed");//使用上下文得到初始化参数
Dog d = new Dog(dogBreed);//建立一个新的Dog
sc.setAttribute("dog",d);//使用上下文来设置一个属性,这个属性就是Dog。现在应用的其他部分就能得到这个属性(Dog) 的值
}
public void contextDestroyed(ServletContextEvent event){
//Code
}
}
package com.example.web;
public class Dog{
private String breed;
public Dog(String breed){
this.breed = breed;
}
public String getBreed(){
return breed;
}
}
package com.example.web;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class ListenerTester extends HttpServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException,ServletException{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("test context attribute set by listener<br>");
out.println("<br>");
Dog dog = (Dog)getServletContext().getAttribute("dog");
out.println("Dog's breed is: " + dog.getBreed());
}
}
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<servlet>
<servlet-name>ListenerTester</servlet-name>
<servlet-class>com.example.ListenerTester</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ListenerTester</servlet-name>
<url-pattern>/ListenerTest.do</url-pattern>
</servlet-mapping>
<context-param>
<param-name>breed</param-name>
<param-value>Great Dane</param-value>
</context-param>
<listener>
<listener-class>
com.example.MyServletContextListener
</listener-class>
</listener>
</web-app>
- 上面的代码都写完了,我们要对Servlet进行编译,部署到tomcat中去。
- 然后浏览器访问,看看可不可以。