ServletConfig对象
- 在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。
- 当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息。
- 阅读ServletConfig API,并举例说明该对象的作用:
- 获得字符集编码
- 获得数据库连接信息
- 获得配置文件,查看struts案例的web.xml文件
package cn.mengmei.servlet;
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 ServletConfigDemo1 extends HttpServlet {
private ServletConfig config;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*
//获取指定的初始化参数
String value = config.getInitParameter("xxx");
response.getOutputStream().write((value+"<br/>").getBytes());
//获取全部初始化参数
Enumeration e = config.getInitParameterNames();
while(e.hasMoreElements()){
String name = (String)e.nextElement();
String value1 = config.getInitParameter(name);
response.getOutputStream().write((name+"="+value1+"<br/>").getBytes());
}
//获得字符集编码,用于向浏览器输出中文
String charset = config.getInitParameter("charset");
response.setHeader("Content-Type", "text/html;charset="+charset);
response.getWriter().write("中国");
*/
//获得数据库连接信息
String url = config.getInitParameter("url");
String username = config.getInitParameter("username");
String password = config.getInitParameter("password");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
}
}
web.xml配置文件:
<servlet>
<servlet-name>ServletConfigDemo1</servlet-name>
<servlet-class>cn.mengmei.servlet.ServletConfigDemo1</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://localhost:3306/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>root</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ServletConfigDemo1</servlet-name>
<url-pattern>/servlet/ServletConfigDemo1</url-pattern>
</servlet-mapping>
在开发中,这样获取ServletConfig对象:
package cn.mengmei.servlet;
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 ServletConfigDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//GenericServlet的方法,直接获取ServletConfig对象:
ServletConfig config = this.getServletConfig();
response.getWriter().write(config.getInitParameter("aa"));
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
web.xml配置文件:
<servlet>
<servlet-name>ServletConfigDemo2</servlet-name>
<servlet-class>cn.mengmei.servlet.ServletConfigDemo2</servlet-class>
<init-param>
<param-name>aa</param-name>
<param-value>bb</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ServletConfigDemo2</servlet-name>
<url-pattern>/servlet/ServletConfigDemo2</url-pattern>
</servlet-mapping>
ServletContext
- WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
- ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。
- 由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
- 查看ServletContextAPI文档,了解ServletContext对象的功能。
ServletContext应用
- 多个Servlet通过ServletContext对象实现数据共享。
- 获取WEB应用的初始化参数。
- 实现Servlet的转发。
- 利用ServletContext对象读取资源文件。
- 得到文件路径
- 读取资源文件的三种方式
- .properties文件(属性文件)
package cn.mengmei.servlet;
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 ServletContextDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//产生了数据
String data = "abcdefg";
//得到代表整个应用的ServletContext对象。
ServletContext context = this.getServletContext();
//将数据存到context对象的属性里
context.setAttribute("data", data);
//转给ServletContextDemo2来处理
context.getNamedDispatcher("ServletContextDemo2").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
package cn.mengmei.servlet;
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 ServletContextDemo2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//从ServletContext对象的属性里获取到数据
String data = (String)this.getServletContext().getAttribute("data");
//把数据输出给浏览器
response.getWriter().write(data);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
只需访问ServletContextDemo1就会得到ServletContextDemo2的运行结果。
2. 获取WEB应用的初始化参数。
package cn.mengmei.servlet;
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 ServletContextDemo3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
String username = context.getInitParameter("username");
String password = context.getInitParameter("password");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
web.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" 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">
<display-name>myday05</display-name>
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/test</param-value>
</context-param>
<context-param>
<param-name>username</param-name>
<param-value>root</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>root</param-value>
</context-param>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>ServletContextDemo3</servlet-name>
<servlet-class>cn.mengmei.servlet.ServletContextDemo3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletContextDemo3</servlet-name>
<url-pattern>/servlet/ServletContextDemo3</url-pattern>
</servlet-mapping>
</web-app>
3. 实现Servlet的转发。
package cn.mengmei.servlet;
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 ServletContextDemo4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getOutputStream().write("1111111".getBytes()); //不会输出,请求转发时会清空response。
/*
OutputStream out = response.getOutputStream();
out.write("关掉流,此数据会强制刷给浏览器,但是后面的转发会抛异常:Cannot forward after response has been committed".getBytes());
out.close();
*/
ServletContext context = this.getServletContext();
RequestDispatcher rd = context.getRequestDispatcher("/servlet/ServletContextDemo5"); //
rd.forward(request, response);
System.out.println("haha"); //会执行
response.getOutputStream().write("4444444444".getBytes()); //不会输出。
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
package cn.mengmei.servlet;
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 ServletContextDemo5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getOutputStream().write("ServletContextDemo5".getBytes());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
请求ServletContextDemo4会显示ServletContextDemo5的运行结果。
4. 利用ServletContext对象读取资源文件。
资源放在类目录下时:
package cn.mengmei.servlet;
import java.io.FileInputStream;
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 ServletContextDemo6 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
test1();
}
//读取web工程中资源文件的模板代码
public void test1() throws IOException {
//此代码在web工程中行不通,因为web工程发布以后就没有src目录。
//FileInputStream in = new FileInputStream("src/db.properties"); //相对路径,代码由谁运行它就相对于谁
/*这个web应用由服务器来运行,所以这个java类由服务器调用。
* 服务器运行时靠bin目录下的二进制文件。
* tomcat的bin目录和webapps目录下的web应用的classes目录没有相对关系。
* ServletContext对象代表web应用,所以需要用ServletContext对象来读取。*/
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties"); //用ServletContext读,第一个“/”代表web工程。
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
System.out.println(driver);
}
public void test2() throws IOException {
//这个代码是获取web工程资源在硬盘的绝对路径。
String realPath = this.getServletContext().getRealPath("/WEB-INF/classes/db.properties");
System.out.println(realPath);
//有了web资源在硬盘的绝对路径,就可以使用普通流来读取了:
FileInputStream in = new FileInputStream(realPath);
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
System.out.println(driver);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
资源放在WebRoot目录下时:
package cn.mengmei.servlet;
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 ServletContextDemo7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
InputStream in = this.getServletContext().getResourceAsStream("/db1.properties"); //此“/”代表此web工程
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
System.out.println(driver);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
5. 资源文件放在类目录下时,更专业的方式是:用类加载器来读取。
package cn.mengmei.servlet;
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 ServletContextDemo8 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
test2();
}
//用类装载器 获取src目录下的资源文件
public void test1() throws IOException {
//获取当前类的类装载器:
ClassLoader loader = ServletContextDemo8.class.getClassLoader();
InputStream in = loader.getResourceAsStream("db.properties"); //类装载器就是用来装载classes目录下面所有类的,db.properties正好也在classes目录下。
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
System.out.println(driver);
}
//用类装载器获取src下的某个包下的资源文件
public void test2() throws IOException {
//获取当前类的类装载器:
ClassLoader loader = ServletContextDemo8.class.getClassLoader();
InputStream in = loader.getResourceAsStream("cn/mengmei/servlet/db2.properties"); //类装载器就是用来装载classes目录下面所有类的,db.properties正好也在classes目录下。
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
System.out.println(driver);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
类装载器用装载类的方式装载资源文件,有一个隐患需要注意:
- 它会把整个资源文件都装载到内存中来,并且一直滞留在内存中。如果这个资源文件特别大,java虚拟机会内存溢出。
- 用类装载的方式装载,不适合装载大文件。
6. 用ServletContext对象将src目录下的大文件拷贝到硬盘中:
package cn.mengmei.servlet;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServletContextDemo9 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//用来截取文件名
String realPath = this.getServletContext().getRealPath("/WEB-INF/classes/haha.mp4");
//System.out.println(realPath); //C:\javaweb\apache-tomcat-7.0.42\webapps\myday05\WEB-INF\classes\haha.mp4
String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);
//用ServletContext对象将src目录下的大文件拷贝到硬盘中
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/haha.mp4");
byte[] buffer = new byte[1024];
int len = 0;
FileOutputStream out = new FileOutputStream("C:/javaweb/"+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);
}
}
7.在实际开发中,可能根本就不会用Servlet去读取文件,而是用另外一个类:Dao
package cn.mengmei.servlet;
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.mengmei.dao.Dao;
public class ServletContextDemo10 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);
}
}
package cn.mengmei.dao;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;
public class Dao {
public void run() throws IOException {
//通过类装载器,只是为了获取资源的绝对路径。
URL url = Dao.class.getClassLoader().getResource("db.properties");
String realPath = url.getPath();
//通过传统流来读取,避免了类装载器只装载一次 导致 新写进去的内容读不到的弊端。
FileInputStream in = new FileInputStream(realPath);
Properties prop = new Properties();
//加载
prop.load(in);
System.out.println(prop.getProperty("driver"));
System.out.println(prop.getProperty("url"));
System.out.println(prop.getProperty("username"));
System.out.println(prop.getProperty("password"));
System.out.println(prop.getProperty("name"));
//这条如果写在加载前,会导致整个properties文件被清空。
FileOutputStream out = new FileOutputStream(realPath);
//写入一条数据。
prop.setProperty("name", "mm");
//更新到硬盘。
prop.store(out, "注释不写也行");
}
}
//注意:src下的properties文件只有在文件里修改后,重新发布到服务器才会被重新加载。
src下的db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=root
浏览器,第二次运行:http://localhost:8080/myday05/servlet/ServletContextDemo10 ,会看到更新后的数据。
在客户端缓存Servlet的输出
- 对于不经常变化的数据,在servlet中可以为其设置合理的缓存时间值,以避免浏览器频繁向服务器发送请求,提升服务器的性能。
package cn.mengmei.servlet;
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 ServletDemo4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data = "abcdefg";
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);
}
}
用 HttpWatch 抓取的 http 响应:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Expires: Tue, 20 Jan 2015 15:49:43 GMT
Content-Length: 7
Date: Mon, 19 Jan 2015 15:49:43 GMT
abcdefg