一、servletConfig对象
在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。比如:
<servlet>
<servlet-name>ConfigDemo1</servlet-name>
<servlet-class>cn.itcast.servletConfig.ConfigDemo1 </servlet-class>
<init-param>
<param-name>xxx</param-name>
<param-value>123</param-value>
</init-param>
</servlet>
注意:针对每个servlet,我们需要为其单独配置,而在servlet元素外面使用标签<context-param>配置的初始化信息是对所有的servlet共享的。
现在我们在servlet中使用初始化信息(工程ConfigAndContext):
packagecn.itcast.servletConfig;
importjava.io.IOException;
importjavax.servlet.ServletConfig;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
public class ConfigDemo1 extends HttpServlet{
private ServletConfig config;
public void init(ServletConfig config)throws ServletException{
String value=config.getInitParameter("xxx");
System.out.println(value);
}
public void doGet(HttpServletRequestrequest, HttpServletResponseresponse)
throws ServletException,IOException{
}
public void doPost(HttpServletRequestrequest, HttpServletResponseresponse)
throws ServletException,IOException{
doGet(request,response);
}
}
当我们使用地址 http://localhost:8080/ConfigAndContext/servlet/ConfigDemo1 访问时在窗口中会打印出123这个初始化信息。我们也可以在doGet方法中使用:
package cn.itcast.servletConfig;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ConfigDemo1 extends HttpServlet {
private ServletConfig config;
public void init(ServletConfig config) throws ServletException{
//在初始化方法中使用
/*String value = config.getInitParameter("xxx");
System.out.println(value);*/
this.config = config;//在doGet方法中使用
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到初始化参数
String value = config.getInitParameter("xxx");
//会将得到的初始化参数打印在网页中,注意输出方式
response.getOutputStream().write(value.getBytes());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
当然我们也可以配置多个初始化参数,并通过名字得到相关的值:
package cn.itcast.servletConfig;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ConfigDemo1 extends HttpServlet {
private ServletConfig config;
public void init(ServletConfig config) throws ServletException{
//在初始化方法中使用
/*String value = config.getInitParameter("xxx");
System.out.println(value);*/
this.config = config;//在doGet方法中使用
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到初始化参数
String value = config.getInitParameter("xxx");
//会将得到的初始化参数打印在网页中,注意输出方式
response.getOutputStream().write(value.getBytes());
//得到多个初始化参数
Enumeration e = config.getInitParameterNames();
while(e.hasMoreElements()){
String name = (String) e.nextElement();
value = config.getInitParameter(name);
response.getOutputStream().write((name + "=" + value).getBytes());
}
//得到码表
String charset = this.config.getInitParameter("charset");
//得到链接数据库
String url = this.config.getInitParameter("url");
String username = this.config.getInitParameter("username");
String password = this.config.getInitParameter("password");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
其配置信息如下:
<servlet>
<servlet-name>ConfigDemo1</servlet-name>
<servlet-class>cn.itcast.servletConfig.ConfigDemo1</servlet-class>
<init-param>
<param-name>xxx</param-name>
<param-value>yyy</param-value>
</init-param>
<init-param><!--配置码表-->
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!--配置数据库-->
<init-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://3305/test</param-value>
</init-param>
<init-param><!--配置用户名-->
<param-name>username</param-name>
<param-value>root</param-value>
</init-param>
<init-param><!--配置密码-->
<param-name>password</param-name>
<param-value>walp1314</param-value>
</init-param>
</servlet>
当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象就可以得到当前servlet的初始化参数信息。也就是说我们不需要自己定义一个ServletConfig字段,直接使用即可。
package cn.itcast.servletConfig;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ConfigDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//我们直接得到ServletConfig对象
ServletConfig config = this.getServletConfig();
System.out.println("aaa" + config.getInitParameter("xx"));
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
二、ServletContext对象(context域对象)
(1)ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。
(2)由于一个web应用中的所有servlet共享同一个ServletContext对象,因此servlet对象之间可以通过ServletContext对象来实现通讯,ServletContext对象通常也被称之为context域对象。
我们先将数据通过servlet存入context域对象中:
package cn.itcast.context;
//多个servlet通过servletContext实现数据共享
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//将数据存到context对象之中
public class ContextDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = "aaa";
ServletContext context = this.getServletConfig().getServletContext();
context.setAttribute("data", data);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
然后从context域中取出我们存入的数据:
package cn.itcast.servletConfig;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ConfigDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//我们直接得到ServletConfig对象
ServletConfig config = this.getServletConfig();
System.out.println("aaa" + config.getInitParameter("xx"));
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
web容器在启动时,它会为每个web应用程序都创建一个对应的ServletContext对象,它代表当前的web应用。即ServletContext对象可以对整个web应用中所有的servlet使用,同时一般不在其中一个<servlet>标签中定义,而是在外部定义。如:
<web-app>
<context-param>
<param-name>1111</param-name>
<param-value>2222</param-value>
</context-param>
。。。。。。
这里我们通过context对象获得整个站点的初始化资源:
package cn.itcast.context;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ContextDemo3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//注意:这里我们其实可以直接取得context对象,而不需要通过ServletConfig对象
ServletContext context = this.getServletContext();
String name = context.getInitParameter("1111");
System.out.println(name);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
实现servlet之间的转发
我们访问ContextDemo4这个servlet,然后这个servlet将请求转发给ContextDemo5进行处理:
package cn.itcast.context;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ContextDemo4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.注意:字符串是不会在浏览器中输出的,因为我们在转发后,ContextDemo5这个
//servlet会将response中的数据全部清掉
response.getOutputStream().write("1111".getBytes());
//2.这种情况我们强制关闭流会自动清理缓存,也就是说会将字符串输出到浏览器中
//但是此时转发请求会出错,因为流已经关闭了.
OutputStream out = response.getOutputStream();
out.write("1111".getBytes());
out.close();
ServletContext context = this.getServletContext();
RequestDispatcher rd = context.getRequestDispatcher("/servlet/ContextDemo5");
rd.forward(request, response);
//3.这行代码是会执行的,会在窗口打印出字符串
System.out.println("Hello");
//4.这行代码虽然会执行,但是不会发到浏览器中,因为此时在请求转发之后相当于
//整个操作已经结束了,数据就不会发送到浏览器中了。
response.getOutputStream().write("Hello".getBytes());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
注意上面四种特殊情况。
ContextDemo5进行处理转发的请求:
package cn.itcast.context;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ContextDemo5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getOutputStream().write("ContextDemo5".getBytes());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在web工程中我们用到资源文件时一般就是.xml文件或者.properties文件,一般较为复杂的资源文件使用.xml,简单文件使用.properties文件。
资源文件(db1.properties)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3305/test
username=root
password=walp1314
下面看操作资源文件:
package cn.itcast.context;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ContextDemo6 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try{
test1();
}catch(Exception e){
e.printStackTrace();
}
}
//使用传统方式读取资源文件
public void test1() throws Exception{
FileInputStream fin = new FileInputStream("db1.properties");
System.out.println(fin);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
注意:这里的test1方法中我们采用传统的方式去读取资源文件。但是如果这样读取资源文件我们将资源文件放在工程中的任何目录都是访问不了的,因为这个程序是右tomcat去调用java虚拟机执行,所以我们如果将资源文件放在工程中,那么路径就要写这个资源文件路径(如果是在src下,那么路径就是classes)相对于tomcat的bin目录的地址。这显然很麻烦,当然我们也可以将资源文件直接放在tomcat的bin目录中,此时直接写上文件名即可,但是这在实际开发中显然是行不通的。
方式二:使用ServletContext对象读取资源文件(1)
//使用ServletContext对象读取资源文件(1)
public void test2() throws Exception{
//此时我们将配置文件放在src下,部署之后此文件在/WEB-INF/classes下。
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db1.properties");
//读取properties文件需要使用Properties对象
Properties properties = new Properties();
properties.load(in);
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");
System.out.println(driver);
}
方式三:使用ServletContext对象读取资源文件(2)
//使用ServletContext对象读取资源文件(2)
public void test3() throws IOException{
//这里我们得到资源文件的绝对路径,此时资源文件放在src下
String path = this.getServletContext().getRealPath("/WEB-INF/classes/db1.properties");
//之后就可以采用传统方式进行读取
FileInputStream fin = new FileInputStream(path);
Properties properties = new Properties();
properties.load(fin);
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");
System.out.println(driver);
}
方式四:读取WebRoot目录下的资源文件
//读取WebRoot目录下的资源文件
public void test4() throws IOException{
//注意此时资源文件是在webRoot下的,也就是在web工程下面,可以直接读取
InputStream in = this.getServletContext().getResourceAsStream("/db2.properties");
Properties properties = new Properties();
properties.load(in);
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");
System.out.println(driver);
}
下面看使用类装载器读取资源文件(一定要注意:虽然都放在src目录下,但是路径写法不同)
package cn.itcast.context;
//使用类装载器读取资源文件
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ContextDemo7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try{
test1();
}catch(Exception e){
e.printStackTrace();
}
}
public void test1() throws IOException{
ClassLoader loader = ContextDemo7.class.getClassLoader();
//注意:这里的资源文件也是放在src目录下面,但是和之前的写法却不同
InputStream in = loader.getResourceAsStream("db1.properties");
//说明:这个类装载器装载src下的class文件,当然也可以装载资源文件,而资源文件刚好
//在src下,所有资源文件和类装载器在同一个目录中
Properties properties = new Properties();
properties.load(in);
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");
System.out.println(driver);
}
//读取类路径下(包下)的资源文件
public void test2() throws IOException{
ClassLoader loader = ContextDemo7.class.getClassLoader();
InputStream in = loader.getResourceAsStream("cn/itcast/context/db1.properties");
Properties properties = new Properties();
properties.load(in);
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");
System.out.println(driver);
}
//但是通过类装载器读取资源文件在资源文件很大的时候容易造成虚拟机内存溢出
//所以使用类装载器的方式不适合读取较大的资源文件
//下面读取较大的资源文件
public void test3() throws IOException{
//读取db.mp4并拷贝到E:\根目录下
//path路径有两种情况:1.path=C:\aaa\bbb\db.mp4; 2.path=db.mp4
String path = this.getServletContext().getRealPath("WEB-INF/classes/db.mp4");
//资源文件放在src下,这里我们是需要从路径中截取出文件名
String filename = path.substring(path.lastIndexOf("\\") + 1);
//这里表示从最后一个\的后面一个字符开始截取
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.mp4");
byte buffer[] = new byte[1024];//开辟一个缓冲区
int len = 0;
FileOutputStream out = new FileOutputStream("e:\\" + filename);
while((len = in.read(buffer)) > 0){
out.write(buffer, 0, len);
}
out.close();
in.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
普通java类通过servlet读取资源文件
package cn.itcast.dao;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;
//在普通java类中取得(或写入)资源文件中的相关数据只能功过类装载器来实现
public class Dao {
public void run() throws IOException{
//这里资源文件在src下,注意:这里不能使用getResourceAsStream方法,原因在后面说明
URL url_s = Dao.class.getClassLoader().getResource("db1.properties");
//结果是file:/E:/apache/tomcat/tomcat/webapps/ConfigAndContext/WEB-INF/classes/db1.properties
//System.out.println(url_s);
//得到资源的绝对路径
String path = url_s.getPath();
//结果是/E:/apache/tomcat/tomcat/webapps/ConfigAndContext/WEB-INF/classes/db1.properties
//System.out.println(path);
FileInputStream in = new FileInputStream(path);
//注意:new一个FileOutputStream时如果不设置布尔值就会将文件清空
FileOutputStream out = new FileOutputStream(path, true);
Properties properties = new Properties();
properties.load(in);
System.out.println(properties.getProperty("driver"));
System.out.println(properties.getProperty("url"));
System.out.println(properties.getProperty("username"));
System.out.println(properties.getProperty("password"));
//第一次访问的时候值是null,第二次才会有值
System.out.println(properties.getProperty("name"));
properties.setProperty("name", "yj");
//将相关内容写入到文件中去
properties.store(out, "");
}
}
package cn.itcast.context;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.itcast.dao.Dao;
public class ContextDemo8 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Dao dao = new Dao();
dao.run();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
说明:这里之所以不使用getResourceAsStream方法是因为如果这样那么第一次访问时类装载器就会将资源文件加载进去,但是如果我们想程序后面那样对文件进行写入操作后,之后的访问还是不会得到相关的值,和上面不同,上面只是第一次没有值,但是之后就会有值。这是因为类加载器在每次加载的时候会先看内存中是否有这个资源文件,如果有就不会再次加载,所以如果使用getResourceAsStream方法,那么我们每次访问的资源文件都是第一次加载的那个,而不会更新。除非关掉web服务器,这显然不现实。但是我们通过其路径每次都new一个输入输出流则会每次都去更新资源文件。
缓存一些不经常变化的资源到浏览器中,提升服务器性能
package cn.itcast.context;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ContextDemo9 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = "aaa";
//缓存一天
response.setDateHeader("expires", System.currentTimeMillis() + 24*3600*1000);
response.getOutputStream().write(data.getBytes());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
注意:这里我们在试验时可以在Internet选项中常规-设置-查看文件里面可以查看到缓存的文件,同时我们不能使用刷新查看试验结果,因为只要是刷新都会想服务器请求数据,所以这里我们可以使用超链接进行试验。