深入分析JavaWeb Item6 — servletConfig 与servletContext详解

一、ServletConfig讲解
首先看ServletConfig API文档

1.1、配置Servlet初始化参数
在Servlet的配置文件web.xml中,可以使用一个或多个标签为servlet配置一些初始化参数。

例如:

ServletConfigDemo1 gacl.servlet.study.ServletConfigDemo1 name gacl password 123 charset UTF-8 1.2、通过ServletConfig获取Servlet的初始化参数 当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,我们通过ServletConfig对象就可以得到当前servlet的初始化参数信息。

例如:
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()方法;

由于一个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应用的初始化参数,如下所示:

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应用的初始化参数,代码如下:

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服务器的目录。如果要用传统的文件读取文件,则要使用绝对路劲

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);
}

}感兴趣的可以点击加扣群 854393687

猜你喜欢

转载自blog.csdn.net/javarrr/article/details/82953572