文章目录
ServletConfig
ContextPath
一个Web工程,如名为 Learning-Servlet,访问的路径 http://localhost:8080/servletWeb/XXXX
- 这整个 web 应用就成为一个 Context
- 路径
/servletWeb
被称为上下文路径, 即ContextPath
。可以通过请求对象request.getContextPath()
获取
ServletConfig 详解
Servlet 初始化配置加载(配置见博客文章 Servlet Web.xml配置)
ServletConfig
是处理装载 Servlet 初始化参数的。init-param
标签配置的数据.如:
<servlet>
<servlet-name>ServletConfigServlet</servlet-name>
<servlet-class>com.learning.select2.config.ServletConfigServlet</servlet-class>
<init-param>
<param-name>user</param-name>
<param-value>Sam</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ServletConfigServlet</servlet-name>
<url-pattern>/servletConfigServlet</url-pattern>
</servlet-mapping>
- 当
Servlet
配置了初始化参数后,web
容器在创建Servlet
实例对象时,会自动将这些初始化参数封装到ServletConfig
对象中,并在调用servlet
的init()
方法时,将ServletConfig
对象传递给 servlet。进而,通过ServletConfig
对象就可以得到当前servlet的初始化参数。GenericServlet
中源码如下:
public void init() throws ServletException {
}
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
- SpringMvc 的配置,就是使用
ServletConfig
初始化参数处理配置文件加载
API 使用
- 服务器会自动封装在
ServletConfig
中,我们利用init()
或者init(ServletConfig config)
方法,可以只获取一次ServletConfig
对象。如果要重写init
方法,需要小心,见注意事项。 - 通过
getInitParameter()
方法,获取配置好的参数。这个方法父类通过ServletConfig.getInitParameter()
,或者使用GenericServlet
封装好的。 ServletConfig
对象也可以直接通过父类GenericServlet
封装好的getServletConfig()
方法获取
public String getInitParameter(String name) {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getInitParameter(name);
}
public ServletConfig getServletConfig() {
return config;
}
- 通过
getInitParameterNames()
,可以获取枚举类型的所有初始化参数
public Enumeration getInitParameterNames() {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getInitParameterNames();
}
- 实际项目中,参数放在xml与properites文件中更灵活,写程序获取即可。
注意事项
- 如果要重写
init
方法,推荐使用不带参数的init()方法 - 如果重写父类带参数的
init()
方法,这句一定写,super.init(config)
,不然ServletConfig
对象空指针。原因在于,父类中代参的init()
实现的时候,先this.config = config;
然后调用无参this.init()
。其实你复写两个init()
方法后,输出的顺序也解释了这一点。
代码如下
public class ServletConfigServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("带参数的init方法,先调用");
// 这句一定要写,不然不会装载 ServletConfig 对象
super.init(config);
}
@Override
public void init() throws ServletException {
System.out.println("无参的init方法,后调用");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取 ContextPath
String contextPath = req.getContextPath();
System.out.println("上下文路径 contextPath: " + contextPath);
// 直接通过父类封装的 getInitParameter 方法
String user = getInitParameter("user");
System.out.println("ServletConfigServlet 初始化参数 user 的值: " + user);
// 使用 ServletConfig 内部的 getInitParameter 方法
String user1 = getServletConfig().getInitParameter("user");
System.out.println("ServletConfigServlet 初始化参数 user 的值: " + user1);
Enumeration parameterNames = getInitParameterNames();
while (parameterNames.hasMoreElements()) {
String thisName = parameterNames.nextElement().toString();
System.out.println("初始化参数 : " + thisName);
}
}
}
ServletContext
简介
- 生命周期:Web容器在启动时,它会为每个 Web 应用程序都创建一个对应的
ServletContext
对象,它代表当前Web应用。ServletContext
对象只在Web应用被关闭时才被销毁;不同的Web应用,ServletContext
各自独立存在 - api 获取:
SevletConfig
对象中维护了ServletContext
对象的引用,通过SevletConfig.getServletContext()
方法获取ServletContext
对象。- 直接调用父类封装好的
getServletContext()
方法即可获取
- 作用域:由于一个Web应用中的所有 Servlet 共享同一个
ServletContext
对象,因此 Servlet 对象之间可以通过ServletContext
对象来实现通讯。ServletContext
对象通常也对称之为 context 域对象 - Spring 就是使用
ServletContext
, 上下文参数处理配置文件的加载
应用
上下文参数
- 获取上下文参数。
context-param
标签配置得参数是供 web 应用共享的,所有的servlet都可以访问。
<context-param>
<param-name>context_user</param-name>
<param-value>Admin</param-value>
</context-param>
// 获取 ServletConfig 配置,最对某个 Servlet 有效
String servlet_user = getInitParameter("servlet_user");
System.out.println("本 Servlet 私有的配置: " + servlet_user);
// 获取 ServletContext 配置,最对所有 Servlet 有效
ServletContext servletContext = getServletContext();
String context_user = servletContext.getInitParameter("context_user");
System.out.println("所有的 Servlet 共有的配置: " + context_user);
- 利用
ServletContext
,实现 Servlet 对象之间通讯。 主要是4个有关Attribute
的方法:setAttribute()、getAttribute()、removeAttribute()、getAttributeNames()
// 所有servlet实现通信,使用 上下文 Context 域
ServletContext servletContext = getServletContext();
servletContext.setAttribute("new_user", "");
String new_user = (String) servletContext.getAttribute("new_user");
System.out.println("所有servlet实现通信: " + new_user);
servletContext.removeAttribute("new_user");
servletContext.getAttributeNames();
利用 ServletContext 获取资源文件
- 环境:基本 Maven 工程,有文件两个,路径如下
Learning-Servlet/servlet-2x/src/main/resources/file.properties # resources 下的资源编译的时候放入 classes 目录(classpath根目录)
Learning-Servlet/servlet-2x/src/main/webapp/downLoad/file2.properties # webapp 下的资源编译的时候会直接放入根目录
ServletContext
获取资源地址的方法有三个:默认从 Web 应用根目录下取资源,Tomcat下 path 是否以 ‘/’ 开头无所谓, 建议加上’/’, 和具体的容器有关
- servletContext.getResourceAsStream(): 直接获取流对象
- servletContext.getResource():获取URL对象,然后再次获取path与数据流
- servletContext.getRealPath():获取绝对路径
// 直接获取流对象
InputStream resourceAsStream = servletContext.getResourceAsStream("/downLoad/file.properties");
getProperties(resourceAsStream);
// 获取绝对路径
String realPath = servletContext.getRealPath("downLoad/file.properties");
System.out.println(realPath);
InputStream stream = new FileInputStream(realPath);
getProperties(stream);
// 获取URL对象,然后再次获取path与数据流
URL resource = servletContext.getResource("downLoad/file.properties");
String path = resource.getPath();
System.out.println(path);
InputStream inputStream = resource.openStream();
getProperties(inputStream);
- 根目录 与 classPath 目录的不同处理方式
// 这种情况Spring 是可以很好处理的, 见博客文章 Spring 分类
// 使用 ServletContext 不怎么好处理(毕竟 classes 是编译以后生成的),可以使用类加载器(ClassLoader)处理
String realPath2 = servletContext.getRealPath("/WEB-INF/classes/file2.properties");
System.out.println(realPath2);
InputStream stream2 = new FileInputStream(realPath2);
getProperties(stream2);
// 默认则是从 ClassPath 根下获取,path不能以'/'开头,最终是由 ClassLoader 获取资源。
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("file2.properties");
getProperties(resourceAsStream);
利用 ClassLoader 获取资源文件
getClassLoader().getResourceAsStream
: 默认是从 ClassPath 根下获取,path不能以’/'开头,最终是由 ClassLoader 获取资源getClass().getResourceAsStream
: path 不以’/‘开头时默认是从此类所在的包下取资源,以’/'开头则是从ClassPath(Src根目录)根下获取
// 默认则是从 ClassPath 根下获取,path不能以'/'开头,最终是由 ClassLoader 获取资源。
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("file2.properties");
getProperties(resourceAsStream);
// path 不以'/'开头时默认是从此类所在的包下取资源,以'/'开头则是从ClassPath(Src根目录)根下获取。
// 其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。
resourceAsStream = getClass().getResourceAsStream("/file2.properties");
getProperties(resourceAsStream);