ServletContext配置上下文信息
ServletContext接口是Tomcat服务器提供的org.apache.catalina.core.ApplicationContextFacade给实现的
- 不同的服务器输出ServletContext对象的时候包名类名可能不一样, 但是他们都实现了ServletContext规范
ServletContext被翻译为Servlet对象的上下文对象(应用域)是Servlet规范中的一员,全类名jakarta.servlet.ServletContext
- Tomcat是一个容器可以放多个webapp,对于一个webapp来说ServletContext对象只有一个,一个ServletContext对象通常对应的是一个web.xml文件
- 只要在同一个webapp当中,所有的Servlet对象获取的都是同一个ServletContext对象即共享同一个应用域中的数据
- 如果你的配置信息想对当前web.xml文件中的所有的Servlet都起作用,需要配置到context-param标签当中,使用ServletContext对象来获取这些配置信息
ServletContext对象创建和销毁时机(生命周期)
- ServletContext对象是WEB服务器在启动的时候创建, 在web服务器关闭的时候销毁
获取ServletContext对象
第一种方式:先获取ServletConfig对象,然后调用Config对象的getServletContext方法获取ServletContext对象
public class ContextTestServlet1 extends GenericServlet {
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
// 获取ServletConfig对象
ServletConfig config = this.getServletConfig();
// JSP的内置对象的变量名就叫application
ServletContext application = config.getServletContext();
// org.apache.catalina.core.ApplicationContextFacade@19187bbb
out.print("<br>" + application);
}
}
第二种: 直接使用this调用父类GenericServlet提供的getServletContext方法,底层是让父类帮我们调用ServletConfig对象的getServletContext方法
public class ContextTestServlet2 extends GenericServlet {
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
// 这里调用父类GenericServlet提供的getServletContext方法
ServletContext application2 = this.getServletContext();
// org.apache.catalina.core.ApplicationContextFacade@19187bbb
out.print("<br>" + application2);
}
}
只要在同一个webapp当中,所有的Servlet对象通过getServletContext方法获取的都是同一个ServletContext对象即它们共享同一个ServletContext对象的数据
- ContextTestServlet1对象对应的ServletContext对象是org.apache.catalina.core.ApplicationContextFacade@19187bbb
- ContextTestServlet2对象对应的ServletContext对象是org.apache.catalina.core.ApplicationContextFacade@19187bbb
获取信息记录日志方法
获取应用级的配置信息即一个项目中共享的配置信息和记录日志的方法(日志信息都记录到了IDEA创建的这些Tomcat服务器副本中的logs目录中)
- IDEA参照Tomcat服务器安装目录中的资源, 创建了多个Tomcat服务器副本 , 这些服务器都存储在idea的相关目录下(CATALINA_BASE)
# 服务器端的java程序运行的控制台信息
catalina.2021-11-05.log
# ServletContext对象的log方法记录的日志信息存储到这个文件中
localhost.2021-11-05.log ServletContext
# 访问日志
localhost_access_log.2021-11-05.txt
方法名 | 功能 |
---|---|
String getInitParameter(String name) | 通过context-param标签中的 name 获取value |
Enumeration< String > getInitParameterNames() | 获取所有context-param标签中的name |
String getContextPath() | 动态获取应用的根路径即/项目名 , 实际开发中不要将应用的根路径写死,因为你永远都不知道这个应用在最终部署的时候该起一个什么名字 |
String getRealPath(String path) | 获取文件的绝对路径即在服务器中的真实路径,不加参数获取的是web工程部署到服务器上的路径 |
void log(String message) | 纪录信息到日志中,控制台上不会显示 ,如果没有使用idea工具这个日志会自动记录到CATALINA_HOME/logs目录下 |
void log(String message, Throwable t) | 将异常对象记录到日志当中, 控制台上异常不会发生 |
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<!--以下的配置信息属于应用级的配置信息(一个项目中共享的配置信息),可以通过ServletContext对象的方法获取这些信息-->
<!--配置上下文的初始化信息,对当前web.xml文件中的所有的Servlet都起作用-->
<context-param>
<param-name>pageSize</param-name>
<param-value>10</param-value>
</context-param>
<context-param>
<param-name>startIndex</param-name>
<param-value>0</param-value>
</context-param>
<servlet>
<servlet-name>configTest</servlet-name>
<servlet-class>com.bjpowernode.javaweb.servlet.ConfigTestServlet</servlet-class>
<!--配置一个Servlet对象的初始化信息的,只对当前的Servet起作用-->
<init-param>
<param-name>driver</param-name>
<param-value>com.mysql.cj.jdbc.Driver</param-value>
</init-param>
<init-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/bjpowernode</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>configTest</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
</web-app>
测试ServeltContext对象获取配置信息和记录日志的方法
public class AServlet extends GenericServlet {
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
// 通过this获取ServletContext对象
ServletContext application = this.getServletContext();
out.print("ServletContext对象是:" + application + "<br>");
// 调用ServletContext对象的方法获取上下文的初始化参数
Enumeration<String> initParameterNames = application.getInitParameterNames();
while(initParameterNames.hasMoreElements()){
String name = initParameterNames.nextElement();
String value = application.getInitParameter(name);
out.print(name + "=" + value + "<br>");
}
// 获取应用上下文的根即/项目名
String contextPath = application.getContextPath();
out.print(contextPath + "<br>");
// 获取某个文件的绝对路径,默认从从web的根下开始找该文件,“/”代表的是web的根不加也可以
String realPath = application.getRealPath("/index.html");
String realPath2 = application.getRealPath("index.html");
out.print(realPath + "<br>");
// 记录信息到日志文件当中
application.log("今天天气真好!");
// 当年龄小于18岁的时候表示非法,程序出现异常并记录到日志文件当中,控制台上不显示
int age = 17;
if(age < 18) {
application.log("对不起,您未成年,请绕行!", new RuntimeException("小屁孩,快走开,不适合你!"));
}
}
}
应用域中存储数据方法
ServletContext对象也叫应用域(类似缓存), 缓存中的数据下次使用的时候可以直接取,不需要从数据库中(硬盘)再次获取,减少了IO的操作提高执行效率
应用域中数据的特点: 所有的用户共享, 数据量占用内存较小, 数据很少的被修改(一般都是只读的)
- ServletContext这个对象只有一个, 只有共享的数据放进去才有意义
- ServletContext 对象生命周期较长在服务器关闭的时候才会被销毁, 大数据量会太占用堆内存影响服务器的性能
- 所有用户共享的数据,如果涉及到修改操作,必然会存在线程并发所带来的安全问题
方法名 | 功能 |
---|---|
void setAttribute(String name, Object value) | 以 Object 的形式向 ServletContext 应用域中存数据 , 类似 map.put(k, v) |
Object getAttribute(String name) | 从 ServletContext 应用域中取数据 , 默认返回Object类型 ,类似 map.get(k) |
void removeAttribute(String name) | 删除ServletContext应用域中的数据 , 类似map.remove(k) |
实体类User
public class User {
private String name;
private String password;
public User() {
}
public User(String name, String password) {
this.name = name;
this.password = password;
}
//属性的setter和getter方法以及toString方法
}
只要在同一个webapp当中,所有的Servlet对象获取的都是同一个ServletContext对象即共享同一个应用域中的数据
- 在AServlet中向应用域中存的数据 , 可以在BServelt中从应用域取出来
// 在AServlet中向应用域当中存储数据
public class AServlet extends GenericServlet {
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
// 获取ServletContext对象
ServletContext application = this.getServletContext();
out.print("ServletContext对象是:" + application + "<br>");
// 准备数据
User user = new User("jack", "123");
// 向应用域当中存储数据
application.setAttribute("userObj", user);
}
}
// 在BServlet中从应用域中取出AServelt存储的数据
public class BServlet extends GenericServlet {
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
// AServelt和BServllet获取的是同一个ServletContext对象
ServletContext application = this.getServletContext();
out.print("ServletContext对象是:" + application + "<br>");
// 从应用域中取出AServelt存储的数据
Object userObj = application.getAttribute("userObj");
// 将对象输出到浏览器
out.print(userObj + "<br>");
}
}