JavaWeb学习之Servlet(四)----ServletConfig获取配置信息、ServletContext的应用
文章来源:http://www.cnblogs.com/smyhvae/p/4140877.html
【正文】
一、ServletConfig:代表当前Servlet在web.xml中的配置信息(用的不多)
- String getServletName() -- 获取当前Servlet在web.xml中配置的名字
- String getInitParameter(String name) -- 获取当前Servlet指定名称的初始化参数的值
- Enumeration getInitParameterNames() -- 获取当前Servlet所有初始化参数的名字组成的枚举
- ServletContext getServletContext() -- 获取代表当前web应用的ServletContext对象
在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。
当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息。
这样做的好处是:如果将数据库信息、编码方式等配置信息放在web.xml中,如果以后数据库的用户名、密码改变了,则直接很方便地修改web.xml就行了,避免了直接修改源代码的麻烦。
代码举例:
新建一个名为ServletConfigTest的Servlet,然后在web.xml中的<servlet>标签下,通过<init-param>标签为这个servlet配置两个初始化参数:
<servlet> <servlet-name>ServletConfigTest</servlet-name> <servlet-class>com.vae.servlet.ServletConfigTest</servlet-class> <init-param> <param-name>name1</param-name> <param-value>value1</param-value> </init-param> <init-param> <param-name>encode</param-name> <param-value>utf-8</param-value> </init-param> </servlet>
然后在代码中获取上面的两个参数。代码实现如下:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 import java.util.Enumeration; 5 6 import javax.servlet.ServletConfig; 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 public class ServletConfigTest extends HttpServlet { 13 14 public void doGet(HttpServletRequest request, HttpServletResponse response) 15 throws ServletException, IOException { 16 17 ServletConfig config = this.getServletConfig(); //拿到init方法中的ServletConfig对象 18 19 // --获取当前Servlet 在web.xml中配置的名称(用的不多) 20 String sName = config.getServletName(); 21 System.out.println("当前Servlet 在web.xml中配置的名称:"+sName); 22 23 // --获取当前Servlet中配置的初始化参数(只能获取一个)经常用到 24 // String value = config.getInitParameter("name2"); 25 // System.out.println(value); 26 27 // --获取当前Servlet中配置的初始化参数(全部获取)经常用到 28 Enumeration enumration = config.getInitParameterNames(); 29 while(enumration.hasMoreElements()){ 30 String name = (String) enumration.nextElement(); 31 String value = config.getInitParameter(name); 32 System.out.println(name+":"+value); 33 } 34 } 35 36 public void doPost(HttpServletRequest request, HttpServletResponse response) 37 throws ServletException, IOException { 38 doGet(request, response); 39 } 40 }
核心代码是第17行,通过this.getServletConfig()方法拿到init方法中的ServletConfig对象,然后获取配置信息。
运行程序,后台打印日志如下:
二、ServletContext:代表当前web应用(非常重要)
WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。
由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
ServletContext的应用:
1.做为域对象可以在整个web应用范围内共享数据。
这里涉及到一些概念:
- 域对象:在一个可以被看见的范围内共享数据用到对象
- 作用范围:整个web应用范围内共享数据
- 生命周期:当服务器启动web应用加载后创建出ServletContext对象后,域产生。当web应用被移除出容器或服务器关闭,随着web应用的销毁域销毁。
代码举例:
ServletTest01.java:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletContext; 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 public class ServletTest01 extends HttpServlet { 12 13 public void doGet(HttpServletRequest request, HttpServletResponse response) 14 throws ServletException, IOException { 15 ServletContext context = this.getServletContext(); 16 context.setAttribute("name", "smyhvae"); 17 } 18 19 public void doPost(HttpServletRequest request, HttpServletResponse response) 20 throws ServletException, IOException { 21 doGet(request, response); 22 } 23 24 }
ServletTest02.java:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletContext; 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 public class ServletTest02 extends HttpServlet { 12 13 public void doGet(HttpServletRequest request, HttpServletResponse response) 14 throws ServletException, IOException { 15 ServletContext context = this.getServletContext(); 16 String myName = (String) context.getAttribute("name"); 17 System.out.println(myName); 18 } 19 20 public void doPost(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 doGet(request, response); 23 } 24 25 }
我们在ServletTest01中给Context加一个参数name(16行),然后就能在ServletTest02中得到这个参数了(16行)。
context中常用的方法有:
- void setAttribute(String,Object);
- Object getAttribute(String);
- void removeAttribute(String);
2、获取WEB应用的初始化参数
我们在第一段中,通过<init-param>标签为某一个单独的servlet加配置信息,这种配置信息在其他的Servlet中是无法访问到的。可如果我们使用<context-param>标签(与Servlet标签并列)为整个Web应用配置属性的话,那所有的Servlet就都能访问里面的参数了。例如:可以把数据库的配置信息放在这里。
这里涉及到一些概念不要混淆:
- 请求参数 parameter --- 浏览器发送过来的请求中的参数信息
- 初始化参数 initparameter --- 在web.xml中为Servlet或ServletContext配置的初始化时带有的基本参数
- 域属性 attribute --- 四大作用域中存取的键值对
代码举例:
在web.xml中为整个web应用添加初始化参数:用户名、密码。代码位置如下:
然后接下来我们在代码中来获取这些参数。代码如下:
ServletTest03.java:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 import java.util.Enumeration; 5 6 import javax.servlet.ServletContext; 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 public class ServletTest03 extends HttpServlet { 13 14 public void doGet(HttpServletRequest request, HttpServletResponse response) 15 throws ServletException, IOException { 16 ServletContext context = this.getServletContext(); // 得到上下文对象 17 18 // 获取单个的Context里面的初始化参数 19 String value1 = context.getInitParameter("username"); 20 String value2 = context.getInitParameter("password"); 21 System.out.println(value1 + ";" + value2); 22 System.out.println(); 23 24 // 一次性获取Context里所有的初始化参数 25 Enumeration enumeration = context.getInitParameterNames(); 26 while (enumeration.hasMoreElements()) { 27 String name = (String) enumeration.nextElement(); 28 String value = context.getInitParameter(name); 29 System.out.println(name + ";" + value); 30 31 } 32 33 } 34 35 public void doPost(HttpServletRequest request, HttpServletResponse response) 36 throws ServletException, IOException { 37 doGet(request, response); 38 } 39 40 }
上面的代码可以看到,我们可以通过context.getInitParameter()方法获得初始化参数。
运行效果如下:
3、实现Servlet的转发
这里涉及到一些概念要区分:
- 请求重定向:302+Location(两次请求两次响应)
- 请求转发:服务器内不进行资源流转 (一次请求一次响应,来实现资源流转)
注:上方括号中的内容是二者的区别。打个比方,假如你找我借钱,如果是请求重定向的话,那你再去找别人借;如果是请求转发的话,那我去找别人借,然后再借给你。
代码举例:
ServletTest04.java实现请求转发:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.RequestDispatcher; 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 /** 12 * ServletContext实现请求转发 13 */ 14 public class ServletTest04 extends HttpServlet { 15 16 public void doGet(HttpServletRequest request, HttpServletResponse response) 17 throws ServletException, IOException { 18 RequestDispatcher dispatcher = this.getServletContext() 19 .getRequestDispatcher("/servlet/ServletTest05");// 参数中写虚拟路径 20 dispatcher.forward(request, response); // 执行完这一行代码后,将会跳到ServletTest05中去执行。 21 22 } 23 24 public void doPost(HttpServletRequest request, HttpServletResponse response) 25 throws ServletException, IOException { 26 doGet(request, response); 27 } 28 29 }
通过19行代码拿到转发器dispatcher,这个转发器指向ServletTest05(参数中写虚拟路径),然后一旦执行完20行代码,就会跳到ServletTest05中去执行。
那么ServletTest05.java的代码如下:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 /** 11 * ServletContext实现请求转发 12 */ 13 public class ServletTest05 extends HttpServlet { 14 15 public void doGet(HttpServletRequest request, HttpServletResponse response) 16 throws ServletException, IOException { 17 response.getWriter().write("10000yuan"); 18 } 19 20 public void doPost(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 doGet(request, response); 23 } 24 25 }
在浏览器中输入url,效果如下:
4.加载资源文件:
我们先在WebRoot的根目录下新建一个资源文件config.properties,这里有一个问题需要注意:
4.1在Servlet中读取资源文件时:
如果写相对路径或绝对路径,这个路径指的是【当前程序启动的目录下】里面的路径。所以,在web环境下,就是tomcat启动的目录即tomcat/bin,所以找不到资源。效果如下:
如果写硬盘的路径D:\\apache-tomcat-7.0.57\\webapps\\WebTest\\config.properties,可以找到资源,但是只要一换发布环境,这个硬盘路径很可能是错误的,同样不行。
为了解决这样的问题,ServletContext提供了getRealPath方法,在这个方法中传入一个路径,这个方法的底层会在传入的路径的前面拼接当前web应用的硬盘路径,从而得到当前资源的硬盘路径,这种方式即使换了发布环境,方法的底层也能得到正确的web应用的路径从而永远都是正确的资源的路径。代码如下:
this.getServletContext().getRealPath("config.properties")
代码举例:
先在WebRoot的根目录下新建一个文件为config.properties,里面的参数如下:
config.properties:
username=smyhvae password=007
紧接着,新建一个Servlet,代码如下:
ServletTest06.java:
1 package com.vae.servlet; 2 3 import java.io.FileReader; 4 import java.io.IOException; 5 import java.util.Properties; 6 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 public class ServletTest06 extends HttpServlet { 13 14 public void doGet(HttpServletRequest request, HttpServletResponse response) 15 throws ServletException, IOException { 16 Properties prop = new Properties(); // 注意导的包是import java.util.Properties; 17 prop.load(new FileReader(this.getServletContext().getRealPath("config.properties"))); 18 19 System.out.println(prop.getProperty("username")); 20 System.out.println(prop.getProperty("password")); 21 22 } 23 24 public void doPost(HttpServletRequest request, HttpServletResponse response) 25 throws ServletException, IOException { 26 doGet(request, response); 27 } 28 29 }
核心代码是第17行中的this.getServletContext().getRealPath("config.properties")。
运行效果如下:
4.2 在很多情况下,Servlet中并不会处理大量的逻辑,而是直接调用其他的java代码,那就涉及到了下面的这个问题:
如果在非Servlet环境下要读取资源文件时可以采用类加载器加载文件的方式读取资源:MyService.class.getClassLoader().getResource("../../../config.properties").getPath()
那现在getResource()里面的路径该怎么写呢?只要记住一句话:类加载器从哪里加载类,就从哪里加载资源。这句话有点抽象,我们还是通过代码来看吧:
新建一个Servlet类:
ServletTest07.java:
1 package com.vae.servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 10 import com.vae.service.MyService; 11 12 public class ServletTest07 extends HttpServlet { 13 14 public void doGet(HttpServletRequest request, HttpServletResponse response) 15 throws ServletException, IOException { 16 MyService service = new MyService(); 17 service.method(); 18 } 19 20 public void doPost(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 doGet(request, response); 23 } 24 25 }
在16、17行代码中,调用了MyService类中的方法。下面来定义MyService类,在里面加载资源文件。
MyService.java:
1 package com.vae.service; 2 3 import java.io.FileNotFoundException; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.util.Properties; 7 8 public class MyService { 9 10 public void method() throws FileNotFoundException, IOException{ 11 //在没有ServletContext的环境下,如果想要读取资源,可以使用类加载器以加载类的方式加载资源, 12 //这里要注意,类加载器从哪个目录加载类,就从哪个目录加载资源, 13 //所以此处的路径一定要给一个相对于类加载目录的路径 14 Properties prop = new Properties(); 15 prop.load(new FileReader(MyService.class.getClassLoader().getResource("config.properties").getPath())); 16 System.out.println(prop.getProperty("username")); 17 System.out.println(prop.getProperty("password")); 18 } 19 20 }
在浏览器输入url后,后台输出如下:
【特别注意】第15行代码中getResource()里面的路径。
类加载器从哪个目录加载类,就从哪个目录加载资源,所以此处的路径一定要给一个相对于类加载目录的路径
我们先看一下这个工程发布到tomcat里面的目录:
进入WEB-INF目录下,是下面的样子:
上图中的classes目录和工程文件的src目录等价。
(1)如果config.properties文件放在src目录下,那路径为:getResource("config.properties")
(2)如果config.properties文件的位置如下:
那路径和上面的代码一样:getResource("com/vae/servlet/config.properties")
(3)如果config.properties文件和MyService.java文件并列,那路径为:getResource("com/vae/service/config.properties")
(4)如果config.properties文件的位置如下:
此时config.properties文件和classes文件并列:
那路径为:getResource("../config.properties") 注:"../"表示上一级目录。
(5)如果config.properties文件放在整个工程文件的根目录下,是无效的,因为此时文件并没有发布到Tomcat。
【工程文件】
作者:习惯沉淀
如果文中有误或对本文有不同的见解,欢迎在评论区留言。
如果觉得文章对你有帮助,请点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
扫码关注一线码农的学习见闻与思考。
回复"大数据","微服务","架构师","面试总结",获取更多学习资源!