1. ServletConfig对象
在Servlet的配置文件中,可以使用一个或多个<init-param>标签为Servlet配置一些初始化参数。
当Servlet配置初始化参数后,web容器在创建Servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用Servlet的init()方法时,将ServletConfig对象传递个Servlet。进而程序员通过ServletConfig对象就可以得到当前Servlet的初始化参数信息。
本小节使用的API:
// GenericServlet类 ServletConfig getServletConfig() // 获取ServletConfig对象
// ServletConfig类 String getInitParameter(String name); // 根据初始化参数名获取对应的值 Enumeration<String> getInitParameterNames(); // 获取所有的初始化参数名
1.1 在web.xml中配置初始化参数
<servlet> <servlet-name>ServletConfigDemo</servlet-name> <servlet-class>com.servlet.ServletConfigDemo</servlet-class> <init-param> <param-name>username</param-name> <param-value>schj-bera</param-value> </init-param> <init-param> <param-name>password</param-name> <param-value>123456</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>ServletConfigDemo</servlet-name> <url-pattern>/ServletConfigDemo</url-pattern> </servlet-mapping>
1.2 Servlet中获取ServletConfig,进而获取初始化参数
1 public class ServletConfigDemo extends HttpServlet { 2 3 // 不用再通过下面这种方式获取,因为HttpServlet的父类GenericServlet已经实现了getServletConfig方法来获取,直接调用即可 4 // private ServletConfig config; 5 // 6 // @Override 7 // public void init(ServletConfig config) throws ServletException { 8 // this.config = config; 9 // } 10 11 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 12 13 } 14 15 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 16 ServletConfig config = this.getServletConfig(); 17 // 根据初始化参数名获取对应的值 18 String username = config.getInitParameter("username"); 19 String password = config.getInitParameter("password"); 20 21 OutputStream out = response.getOutputStream(); 22 out.write("Use getInitParameter:\n".getBytes()); 23 out.write(("username = " + username + "\n").getBytes()); 24 out.write(("password = " + password + "\n\n\n").getBytes()); 25 26 out.write("Use getInitParameterNames: \n".getBytes()); 27 // 获取所有的初始化参数名 28 Enumeration<String> dates = config.getInitParameterNames(); 29 while (dates.hasMoreElements()) { 30 String name = dates.nextElement(); 31 String value = config.getInitParameter(name); 32 out.write((name + " = " + value).getBytes()); 33 out.write("\n".getBytes()); 34 } 35 } 36 }
2. ServletContext对象
web服务器在启动时,它会为每个web应用程序都创建一个对应的ServletContext对象,它代表当前的web应用。
ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写Servlet时,可以通过ServletConfig.getServletContext方法获取到ServletContext对象。
由于一个web应用中的所有Servlet共享一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
本小节使用的API:
// GenericServlet类 ServletContext getServletContext() // 获取ServletContext对象
// ServletConfig类 ServletContext getServletContext() // 获取ServletContext对象
// ServletContext类 void setAttribute(String name, Object object)// 将对象绑定到此ServletContext中的给定的属性名称上 Object getAttribute(String name) // 返回给定名称的servlet容器属性,如果该名称没有属性,则返回null String getInitParameter(String name) // 返回指定名称的初始化参数的值,参数不存在返回null Enumeration<String> getInitParameterNames() // 返回所有的初始化参数,没有返回一个空的Enumeration RequestDispatcher getRequestDispatcher(String path) // 返回一个RequestDispatcher对象 InputStream getResourceAsStream(String path) // 以InputStream方式返回资源文件 String getRealPath(String path) // 返回资源文件的绝对路径
2.1 实现数据共享
1 /** 2 * 使用ServletContext对象实现不同Servlet中的数据共享 3 */ 4 @WebServlet(name = "ServletContextDemo1") 5 public class ServletContextDemo1 extends HttpServlet { 6 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 7 8 } 9 10 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 11 String value = "ServletContextDemo1"; 12 /** 13 * 获取ServletContext对象可以使用下面两种方式,推荐使用2 14 * 1. this.getServletConfig().getServletContext() 15 * 2. this.getServletContext() 16 */ 17 this.getServletContext().setAttribute("data", value); // 存储数据 18 19 } 20 }
1 @WebServlet(name = "ServletContextDemo2") 2 public class ServletContextDemo2 extends HttpServlet { 3 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 4 5 } 6 7 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 8 String value = (String) this.getServletContext().getAttribute("data"); // 获取数据 9 System.out.println(value); 10 response.getOutputStream().write(("data=" + value).getBytes()); 11 } 12 }
先运行ServletContextDemo1存储数据,再运行ServletContextDemo2获取数据:
2.2 获取Web应用的初始化参数
应用场景:数据库参数配置
在web.xml中使用<context-param>标签,为整个Web应用配置初始化参数,web服务器启动的时候创建ServletContext对象,会自动把配置的初始化参数封装到ServletContext对象中:
<context-param> <param-name>dbUser</param-name> <param-value>root</param-value> </context-param> <context-param> <param-name>dbPassword</param-name> <param-value>123456</param-value> </context-param>
1 /** 2 * 使用ServletContext获取Web应用配置的初始化参数 3 */ 4 @WebServlet(name = "ServletContextDemo3") 5 public class ServletContextDemo3 extends HttpServlet { 6 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 7 8 } 9 10 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 11 ServletContext context = this.getServletContext(); 12 String dbUser = context.getInitParameter("dbUser"); // 通过参数名获取对应值 13 String dbPassword = context.getInitParameter("dbPassword"); 14 15 OutputStream out = response.getOutputStream(); 16 out.write(("Use function getInitParameter \n").getBytes()); 17 out.write(("dbUser="+ dbUser + "\ndbPassword=" + dbPassword + "\n\n\n").getBytes()); 18 19 out.write(("Use function getInitParameterNames \n").getBytes()); 20 Enumeration<String> names = context.getInitParameterNames(); // 获取所有的参数名,再根据参数名获取对应的值 21 while (names.hasMoreElements()) { 22 String name = names.nextElement(); 23 String value = context.getInitParameter(name); 24 out.write((name + "=" + value + "\n").getBytes()); 25 } 26 } 27 }
2.3 实现servlet的转发
前面已经学过一个重定向,重定向和转发有什么区别:
- 重定向:你找我,我让你自己去找他 客户机发两次请求
- 转发:你找我,我帮你去找他 客户机发一次请求
1 /** 2 * 使用ServletContext实现请求的转发 3 */ 4 @WebServlet(name = "ServletContextDemo4") 5 public class ServletContextDemo4 extends HttpServlet { 6 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 7 8 } 9 10 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 11 RequestDispatcher rd = this.getServletContext().getRequestDispatcher("/ServletContextDemo6"); 12 rd.forward(request, response); 13 } 14 }
1 /** 2 * 设置响应消息头,实现请求重定向 3 */ 4 @WebServlet(name = "ServletContextDemo5") 5 public class ServletContextDemo5 extends HttpServlet { 6 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 7 8 } 9 10 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 11 response.setStatus(302); 12 response.setHeader("location", "ServletContextDemo6"); 13 } 14 }
1 @WebServlet(name = "ServletContextDemo6") 2 public class ServletContextDemo6 extends HttpServlet { 3 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 4 5 } 6 7 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 8 response.getOutputStream().write("ServletContextDemo6".getBytes()); 9 } 10 }
其中ServletContextDemo4实现请求转发,ServletContextDemo5实现请求重定向,两个都转到ServletContextDemo6。
运行结果:
转发只有一次请求
重定向有两次请求
2.4 读取资源文件
1 /** 2 * 使用ServletContext读取资源文件 3 */ 4 @WebServlet(name = "ServletContextDemo7") 5 public class ServletContextDemo7 extends HttpServlet { 6 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 7 8 } 9 10 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 11 12 OutputStream out = response.getOutputStream(); 13 /** 14 * 资源文件路径以Web应用发布的路径为准,src目录在发布后会拷贝到WEB-INF/classes目录中 15 */ 16 17 // 读取src/db.properties 18 String path1 = "/WEB-INF/classes/db.properties"; 19 InputStream in1 = this.getServletContext().getResourceAsStream(path1); 20 String propertiesInfo1 = this.getPropertiesInfo(in1); 21 out.write(propertiesInfo1.getBytes()); 22 out.write("\n\n\n".getBytes()); 23 24 // 读取src/com.servlet/db.properties 25 String path2 = "/WEB-INF/classes/com/servlet/db.properties"; 26 InputStream in2 = this.getServletContext().getResourceAsStream(path2); 27 String propertiesInfo2 = this.getPropertiesInfo(in2); 28 out.write(propertiesInfo2.getBytes()); 29 out.write("\n\n\n".getBytes()); 30 31 // 读取web/db.properties 32 String path3 = "/db.properties"; 33 InputStream in3 = this.getServletContext().getResourceAsStream(path3); 34 String propertiesInfo3 = this.getPropertiesInfo(in3); 35 out.write(propertiesInfo3.getBytes()); 36 out.write("\n\n\n".getBytes()); 37 38 // 通过ServletContext的getRealPath得到资源的绝对路径后,再通过传统方式读取资源文件 39 String realPath = this.getServletContext().getRealPath(path1); 40 InputStream in = new FileInputStream(realPath); 41 String propertiesInfo4 = this.getPropertiesInfo(in); 42 out.write(propertiesInfo4.getBytes()); 43 out.write("\n\n\n".getBytes()); 44 } 45 46 private String getPropertiesInfo(InputStream in) throws IOException { 47 Properties prope = new Properties(); 48 prope.load(in); 49 String path = prope.getProperty("path"); 50 String dbUser = prope.getProperty("dbUser"); 51 String dbPassword = prope.getProperty("dbPassword"); 52 53 return "path=" + path + ", dbUser=" + dbUser + ", dbPassword=" + dbPassword; 54 } 55 56 }
运行结果:
3. WEB应用中的普通Java程序读取资源文件
如果读取资源文件的程序不是Servlet,则只能通过类装载器去读:
- 通过类装载器,不能加载太大的文件,可能会导致java虚拟机内存溢出
- 如果资源文件更新了,服务器没有重启,通过类装载器的方式读取,就不能获取到最新的数据。这时我们可以使用类装载器的方法获取文件路径,再用传统FileInputStream流的方式读取文件,就可以获得更新后的数据。
1 /** 2 * Servlet调用其他程序,在其他程序中如何读取资源文件(通过类装载器) 3 */ 4 @WebServlet(name = "ServletContextDemo8") 5 public class ServletContextDemo8 extends HttpServlet { 6 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 7 8 } 9 10 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 11 UserDao user = new UserDao(); 12 user.update(); 13 } 14 }
1 /** 2 * 如果读取资源文件的程序不是servlet的话; 3 就只能通过类转载器去读了,文件不能太大; 4 用传递参数方法不好,耦合性高 5 */ 6 public class UserDao { 7 8 private static Properties dbconfig = new Properties(); 9 private static String path = ""; 10 private static String path1 = ""; 11 private static String path2 = ""; 12 static { 13 // 类装载器只会加载一次,当db.properties文件修改时,就无法得到更新后的数据 14 // try { 15 // InputStream in = UserDao.class.getClassLoader().getResourceAsStream("db.properties"); 16 // dbconfig.load(in); 17 // } catch (IOException e) { 18 // throw new ExceptionInInitializerError(e); 19 // } 20 21 // 可以通过类加载的方式得到资源文件的路径,再通过传统方式读取文件内容,这样可以获得更新后的数据 22 path = UserDao.class.getClassLoader().getResource("db.properties").getPath(); 23 // path1 = UserDao.class.getClassLoader().getResource("/com/servlet/db.properties").getPath(); // servlet目录下的资源文件 24 // path2 = UserDao.class.getClassLoader().getResource("../../db.properties").getPath(); //Web应用根目录下的资源文件 25 try { 26 path =java.net.URLDecoder.decode(path, "UTF-8"); // 文件路径如果有空格,则需要转码,否则系统会找不到文件 27 path1 =java.net.URLDecoder.decode(path1, "UTF-8"); 28 path2 =java.net.URLDecoder.decode(path2, "UTF-8"); 29 } catch (UnsupportedEncodingException e) { 30 e.printStackTrace(); 31 } 32 33 } 34 public void update() throws IOException { 35 // 读取资源文件数据 36 InputStream in = new FileInputStream(path); 37 dbconfig.load(in); 38 System.out.println("path=" + dbconfig.getProperty("path") 39 + ", dbUser=" + dbconfig.getProperty("dbUser") 40 + ", dbPassword=" + dbconfig.getProperty("dbPassword")); 41 } 42 }
运行结果:
修改修改classes下的配置文件,无须重启服务器,即可获取最新结果: