一、ServletConfig讲解
首先看ServletConfig API文档
1.1、配置Servlet初始化参数
在Servlet的配置文件web.xml
中,可以使用一个或多个<init-param>
标签为servlet配置一些初始化参数。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<servlet>
<servlet-name>ServletConfigDemo1</servlet-name>
<servlet-
class
>gacl.servlet.study.ServletConfigDemo1</servlet-
class
>
<!--配置ServletConfigDemo1的初始化参数 -->
<init-param>
<param-name>name</param-name>
<param-value>gacl</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>
123
</param-value>
</init-param>
<init-param>
<param-name>charset</param-name>
<param-value>UTF-
8
</param-value>
</init-param>
</servlet>
|
1.2、通过ServletConfig获取Servlet的初始化参数
当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init
方法时,将ServletConfig对象传递给servlet
。进而,我们通过ServletConfig对象就可以得到当前servlet的初始化参数信息。
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
package
gacl.servlet.study;
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 {
/**
* 定义ServletConfig对象来接收配置的初始化参数
*/
private
ServletConfig config;
/**
* 当servlet配置了初始化参数后,web容器在创建servlet实例对象时,
* 会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,
* 将ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以
* 得到当前servlet的初始化参数信息。
*/
@Override
public
void
init(ServletConfig config)
throws
ServletException {
this
.config = config;
}
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
//获取在web.xml中配置的初始化参数
String paramVal =
this
.config.getInitParameter(
"name"
);
//获取指定的初始化参数
response.getWriter().print(paramVal);
response.getWriter().print(
"<hr/>"
);
//获取所有的初始化参数
Enumeration<String> e = config.getInitParameterNames();
while
(e.hasMoreElements()){
String name = e.nextElement();
String value = config.getInitParameter(name);
response.getWriter().print(name +
"="
+ value +
""
);
}
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
this
.doGet(request, response);
}
}
|
运行结果如下:
二、ServletContext对象
WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext
方法获得ServletContext对象,但是还有更简洁的this.getServletContext()
方法;
<font color=”red”>由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象:1,是一个容器 2。作用范围是应用程序范围。
三、ServletContext的应用
3.1、多个Servlet通过ServletContext对象实现数据共享
范例:ServletContextDemo1
和ServletContextDemo2
通过ServletContext
对象实现数据共享
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package
gacl.servlet.study;
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 =
"xdp_gacl"
;
/**
* ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,
* 可以通过ServletConfig.getServletContext方法获得ServletContext对象。
*/
ServletContext context =
this
.getServletConfig().getServletContext();
//获得ServletContext对象
context.setAttribute(
"data"
, data);
//将data存储到ServletContext对象中
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
doGet(request, response);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package
gacl.servlet.study;
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
ServletContextDemo2
extends
HttpServlet {
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
ServletContext context =
this
.getServletContext();
String data = (String) context.getAttribute(
"data"
);
//从ServletContext对象中取出数据
response.getWriter().print(
"data="
+data);
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
doGet(request, response);
}
}
|
先运行ServletContextDemo1
,将数据data存储到ServletContext
对象中,然后运行ServletContextDemo2
就可以从ServletContext
对象中取出数据了,这样就实现了数据共享,如下图所示:
3.2、获取WEB应用的初始化参数
如果想在所有的Servlet应用中都要配置并读取初始化参数,则可以在web.xml
文件的<web-app>
中使用<context-param>
标签配置WEB应用的初始化参数,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<?xml version=
"1.0"
encoding=
"UTF-8"
?>
<web-app version=
"3.0"
xmlns=
"http://java.sun.com/xml/ns/javaee"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http:
//java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name></display-name>
<!-- 配置WEB应用的初始化参数 -->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql:
//localhost:3306/test</param-value>
</context-param>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
|
获取Web应用的初始化参数,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package
gacl.servlet.study;
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();
//获取整个web站点的初始化参数
String contextInitParam = context.getInitParameter(
"url"
);
response.getWriter().print(contextInitParam);
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
doGet(request, response);
}
}
|
运行结果:
3.3、用servletContext实现请求转发
实现Servlet的转发。
- ServletContextDemo4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package
gacl.servlet.study;
import
java.io.IOException;
import
java.io.PrintWriter;
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 {
String data =
"<h1><font color='red'>abcdefghjkl</font></h1>"
;
response.getOutputStream().write(data.getBytes());
ServletContext context =
this
.getServletContext();
//获取ServletContext对象
RequestDispatcher rd = context.getRequestDispatcher(
"/servlet/ServletContextDemo5"
);
//获取请求转发对象(RequestDispatcher)
rd.forward(request, response);
//调用forward方法实现请求转发
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
}
}
|
- ServletContextDemo5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package
gacl.servlet.study;
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(
"servletDemo5"
.getBytes());
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
this
.doGet(request, response);
}
}
|
运行结果:
访问的是ServletContextDemo4,浏览器显示的却是ServletContextDemo5的内容,这就是使用ServletContext实现了请求转发
3.4、利用ServletContext对象读取资源文件
利用ServletContext对象读取资源文件,因为文件的位置不同,所有读取的方式也不同,一般来说分为两种情况:
- 在Servlet的context域中读取文件,工程目录下的src目录发布到服务器中,会映射到“/WEB-INF/classes”文件夹下。所以要一一对应。而且这个是相对目录,相对于web服务器的目录。如果要用传统的文件读取文件,则要使用绝对路劲
1
2
3
4
5
6
|
PrintWriter out = response.getWriter();
ServletContext context =
this
.getServletContext();
String path = context.getRealPath(
"/WEB-INF/classes/itcast.properties"
);
InputStream in =
new
FileInputStream(path);
Properties pro =
new
Properties();
pro.load(in);
|
- 如果是非servlet中读取配置文件,则要使用类加载器去读取。稍后讲到
项目目录结构如下:
代码范例:使用servletContext读取资源文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
package
gacl.servlet.study;
import
java.io.FileInputStream;
import
java.io.FileNotFoundException;
import
java.io.IOException;
import
java.io.InputStream;
import
java.text.MessageFormat;
import
java.util.Properties;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
/**
* 使用servletContext读取资源文件
*
* @author gacl
*
*/
public
class
ServletContextDemo6
extends
HttpServlet {
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
/**
* response.setContentType("text/html;charset=UTF-8");目的是控制浏览器用UTF-8进行解码;
* 这样就不会出现中文乱码了
*/
response.setHeader(
"content-type"
,
"text/html;charset=UTF-8"
);
readSrcDirPropCfgFile(response);
//读取src目录下的properties配置文件
response.getWriter().println(
"<hr/>"
);
readWebRootDirPropCfgFile(response);
//读取WebRoot目录下的properties配置文件
response.getWriter().println(
"<hr/>"
);
readPropCfgFile(response);
//读取src目录下的db.config包中的db3.properties配置文件
response.getWriter().println(
"<hr/>"
);
readPropCfgFile2(response);
//读取src目录下的gacl.servlet.study包中的db4.properties配置文件
}
/**
* 读取src目录下的gacl.servlet.study包中的db4.properties配置文件
* @param response
* @throws IOException
*/
private
void
readPropCfgFile2(HttpServletResponse response)
throws
IOException {
InputStream in =
this
.getServletContext().getResourceAsStream(
"/WEB-INF/classes/gacl/servlet/study/db4.properties"
);
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"
);
response.getWriter().println(
"读取src目录下的gacl.servlet.study包中的db4.properties配置文件:"
);
response.getWriter().println(
MessageFormat.format(
"driver={0},url={1},username={2},password={3}"
,
driver,url, username, password));
}
/**
* 读取src目录下的db.config包中的db3.properties配置文件
* @param response
* @throws FileNotFoundException
* @throws IOException
*/
private
void
readPropCfgFile(HttpServletResponse response)
throws
FileNotFoundException, IOException {
//通过ServletContext获取web资源的绝对路径
String path =
this
.getServletContext().getRealPath(
"/WEB-INF/classes/db/config/db3.properties"
);
InputStream in =
new
FileInputStream(path);
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"
);
response.getWriter().println(
"读取src目录下的db.config包中的db3.properties配置文件:"
);
response.getWriter().println(
MessageFormat.format(
"driver={0},url={1},username={2},password={3}"
,
driver,url, username, password));
}
/**
* 通过ServletContext对象读取WebRoot目录下的properties配置文件
* @param response
* @throws IOException
*/
private
void
readWebRootDirPropCfgFile(HttpServletResponse response)
throws
IOException {
/**
* 通过ServletContext对象读取WebRoot目录下的properties配置文件
* “/”代表的是项目根目录
*/
InputStream in =
this
.getServletContext().getResourceAsStream(
"/db2.properties"
);
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"
);
response.getWriter().println(
"读取WebRoot目录下的db2.properties配置文件:"
);
response.getWriter().print(
MessageFormat.format(
"driver={0},url={1},username={2},password={3}"
,
driver,url, username, password));
}
/**
* 通过ServletContext对象读取src目录下的properties配置文件
* @param response
* @throws IOException
*/
private
void
readSrcDirPropCfgFile(HttpServletResponse response)
throws
IOException {
/**
* 通过ServletContext对象读取src目录下的db1.properties配置文件
*/
InputStream in =
this
.getServletContext().getResourceAsStream(
"/WEB-INF/classes/db1.properties"
);
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"
);
response.getWriter().println(
"读取src目录下的db1.properties配置文件:"
);
response.getWriter().println(
MessageFormat.format(
"driver={0},url={1},username={2},password={3}"
,
driver,url, username, password));
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
this
.doGet(request, response);
}
}
|
运行结果如下:
使用类装载器读取资源文件
我们在非servlet中读取资源文件时(比如在数据库的dao层读取配置文件),采用类装载器 classLoader,你可以先采用servlet服务先读取,然后在把servlet传递给dao,这样虽然可以实现,但是,这样损坏了我们编代码的设计原则,就是层之间不能有交织在一起的东西。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
package
gacl.servlet.study;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
java.io.InputStream;
import
java.io.OutputStream;
import
java.text.MessageFormat;
import
java.util.Properties;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
/**
* 用类装载器读取资源文件
* 通过类装载器读取资源文件的注意事项:不适合装载大文件,否则会导致jvm内存溢出
* @author gacl
*
*/
public
class
ServletContextDemo7
extends
HttpServlet {
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
/**
* response.setContentType("text/html;charset=UTF-8");目的是控制浏览器用UTF-8进行解码;
* 这样就不会出现中文乱码了
*/
response.setHeader(
"content-type"
,
"text/html;charset=UTF-8"
);
test1(response);
response.getWriter().println(
"<hr/>"
);
test2(response);
response.getWriter().println(
"<hr/>"
);
//test3();
test4();
}
/**
* 读取类路径下的资源文件
* @param response
* @throws IOException
*/
private
void
test1(HttpServletResponse response)
throws
IOException {
//获取到装载当前类的类装载器
ClassLoader loader = ServletContextDemo7.
class
.getClassLoader();
//用类装载器读取src目录下的db1.properties配置文件
InputStream in = loader.getResourceAsStream(
"db1.properties"
);
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"
);
response.getWriter().println(
"用类装载器读取src目录下的db1.properties配置文件:"
);
response.getWriter().println(
MessageFormat.format(
"driver={0},url={1},username={2},password={3}"
,
driver,url, username, password));
}
/**
* 读取类路径下面、包下面的资源文件
* @param response
* @throws IOException
*/
private
void
test2(HttpServletResponse response)
throws
IOException {
//获取到装载当前类的类装载器
ClassLoader loader = ServletContextDemo7.
class
.getClassLoader();
//用类装载器读取src目录下的gacl.servlet.study包中的db4.properties配置文件
InputStream in = loader.getResourceAsStream(
"gacl/servlet/study/db4.properties"
);
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"
);
response.getWriter().println(
"用类装载器读取src目录下的gacl.servlet.study包中的db4.properties配置文件:"
);
response.getWriter().println(
MessageFormat.format(
"driver={0},url={1},username={2},password={3}"
,
driver,url, username, password));
}
/**
* 通过类装载器读取资源文件的注意事项:不适合装载大文件,否则会导致jvm内存溢出
*/
public
void
test3() {
/**
* 01.avi是一个150多M的文件,使用类加载器去读取这个大文件时会导致内存溢出:
* java.lang.OutOfMemoryError: Java heap space
*/
InputStream in = ServletContextDemo7.
class
.getClassLoader().getResourceAsStream(
"01.avi"
);
System.out.println(in);
}
/**
* 读取01.avi,并拷贝到e:\根目录下
* 01.avi文件太大,只能用servletContext去读取
* @throws IOException
*/
public
void
test4()
throws
IOException {
// path=G:\Java学习视频\JavaWeb学习视频\JavaWeb\day05视频\01.avi
// path=01.avi
String path =
this
.getServletContext().getRealPath(
"/WEB-INF/classes/01.avi"
);
/**
* path.lastIndexOf("\\") + 1是一个非常绝妙的写法
*/
String filename = path.substring(path.lastIndexOf(
"\\"
) +
1
);
//获取文件名
InputStream in =
this
.getServletContext().getResourceAsStream(
"/WEB-INF/classes/01.avi"
);
byte
buffer[] =
new
byte
[
1024
];
int
len =
0
;
OutputStream 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 {
this
.doGet(request, response);
}
}
|
运行结果如下:
使用类装载器读取资源文件,存在的问题是;类装载器,每次只会装载一次。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
//如果读取资源文件的程序不是servlet的话,
//就只能通过类转载器去读了,文件不能太大
//用传递参数方法不好,耦合性高
public
class
UserDao {
private
static
Properties dbconfig=
new
Properties();
static
{
InputStream in=UserDao.
class
.getClassLoader().getResourceAsStream(
"db.properties"
);
try
{
dbconfig.load(in);
}
catch
(IOException e) {
throw
new
ExceptionInInitializerError(e);
}
//上面代码类装载器只装载一次,下面代码用类装载方式得到文件位置
URL url=UserDao.
class
.getClassLoader().getResource(
"db.properties"
);
String str=url.getPath();
//file:/C:/apache-tomcat-7.0.22/webapps/day05/WEB-INF/classes/db.properties
try
{
InputStream in2=
new
FileInputStream(str);
try
{
dbconfig.load(in2);
}
catch
(IOException e) {
throw
new
ExceptionInInitializerError(e);
}
}
catch
(FileNotFoundException e1) {
throw
new
ExceptionInInitializerError(e1);
}
}
public
void
update() {
System.out.println(dbconfig.get(
"url"
));
}
}
|
四、在客户端缓存Servlet的输出
对于不经常变化的数据,在servlet中可以为其设置合理的缓存时间值,以避免浏览器频繁向服务器发送请求,提升服务器的性能。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package
gacl.servlet.study;
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
ServletDemo5
extends
HttpServlet {
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
String data =
"abcddfwerwesfasfsadf"
;
/**
* 设置数据合理的缓存时间值,以避免浏览器频繁向服务器发送请求,提升服务器的性能
* 这里是将数据的缓存时间设置为1天
*/
response.setDateHeader(
"expires"
,System.currentTimeMillis() +
24
*
3600
*
1000
);
response.getOutputStream().write(data.getBytes());
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
this
.doGet(request, response);
}
}
|