读取web.xml参数

  上篇文章ImageServlet里只设置了JPG,GIF,DOC类型文件的Content-Type。如果这时候需求变化了,需要增加Excel文件格式的Content-Type,就得修改ImageServlet源代码,重新编译class文件,然后重新部署。一个看起来很微小的改动却带来了大量的工作,很让人心烦。

  现在在Java Web开发中,这种常量信息更倾向于写在某个配置文件里。需求变化时只需要修改一下配置文件就可以了,而不会修改源程序,也不会重新编译,维护起来相当方便。web.xml提供了设置初始化参数的功能,可以将这些信息配置在web.xml中。

  初始化参数(init-param)

  web.xml中配置Servlet的时候,标签<servlet>中可以包含标签<init-param>来配置初始化参数。一个Servlet可以配置0到多个初始化参数。接下来的例子InitParamServlet中配置了3个初始化参数。

  1. <servlet>
  2. <servlet-name>InitParamServlet</servlet-name>
  3. <servlet-class>
  4. com.helloweenvsfei.servlet.InitParamServlet
  5. </servlet-class>
  6. <init-param>
  7. <param-name>helloween</param-name>
  8. <param-value>password</param-value>
  9. </init-param>
  10. <init-param>
  11. <param-name>admin</param-name>
  12. <param-value>admin</param-value>
  13. </init-param>
  14. <init-param>
  15. <param-name>babyface</param-name>
  16. <param-value>babyface</param-value>
  17. </init-param>
  18. </servlet>

  配置完毕后,Servlet中提供方法getInitParameter(String param)来获取初始化参数值。如果配置了名为param的参数,则返回参数值,否则返回null。在这段配置中,getInitParameter("helloween")将返回password,getInitParameter("Cobain")将返回null。还可以使用getInitParameterNames()方法返回所有的参数名称,返回结果为枚举类型(Enumeration)。

  这些初始化的参数也可以由ServletConfig对象取得。Servlet提供getServletConfig()这个ServletConfig对象。由ServletConfig取初始化参数与Servlet直接取方式一样。

  看一例子。公司要在网站上颁布一个机密文件notice.html,要求仅有少数几个人能够浏览到。我们来实现这种权限控制。

  (1)把notice.html放在/WEB-INF文件夹下面。因为Java Web应用程序的WEB-INF文件夹有这个特性,任何人都不能通过浏览器直接获取下面的文件,即使他知道文件的准确位置及名称。WEB-INF下的文件是受保护的,这样就保证了文件的安全性。如果浏览器中输入http://localhost:8080/servlet/WEB-INF/notice.html,服务器会报404 Error,尽管这个文件地址是对的。

  (2)编写一个程序InitParamServlet,提示用户输入用户名密码。如果密码验证通过,则通过程序转到notice.html上。虽然WEB-INF下的文件不能通过浏览器直接获取到,但是仍然可以通过程序读取到。程序如下:

  1. package com.helloweenvsfei.servlet;
  2.  
  3. import java.io.IOException;
  4. import java.io.PrintWriter;
  5. import java.util.Enumeration;
  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 InitParamServlet extends HttpServlet {
  13.  
  14. private static final long serialVersionUID = 7298032096933866458L;
  15.  
  16. public void doGet(HttpServletRequest request, HttpServletResponse response)
  17. throws ServletException, IOException {
  18.  
  19. response.setCharacterEncoding("UTF-8");
  20. request.setCharacterEncoding("UTF-8");
  21.  
  22. response.setContentType("text/html");
  23.  
  24. PrintWriter out = response.getWriter();
  25. out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
  26. out.println("<HTML>");
  27. out.println(" <HEAD><TITLE>请登录查看 Notice 文件</TITLE></HEAD>");
  28. out.println("<style>body, td, div {font-size:12px; }</style>");
  29. out.println(" <BODY>");
  30.  
  31. out.println("<form action='" + request.getRequestURI() + "' method='post'>");
  32. out.println("帐号:<input type='text' name='username' style='width:200px; '> <br/>");
  33. out.println("密码:<input type='password' name='password' style='width:200px; '> <br/><br/>");
  34. out.println("<input type='submit' value=' 登录 '>");
  35. out.println("</form>");
  36.  
  37. if(true){
  38. out.println("<br/><br/><br/><br/><br/><br/><br/>用户名、密码为:<br/>");
  39. Enumeration params = this.getInitParameterNames();
  40. while(params.hasMoreElements()){
  41. String usernameParam = (String)params.nextElement();
  42. String passnameParam = this.getInitParameter(usernameParam);
  43. out.println("[" + usernameParam + ", " + passnameParam + "], ");
  44. }
  45. }
  46.  
  47. out.println(" </BODY>");
  48. out.println("</HTML>");
  49. out.flush();
  50. out.close();
  51. }
  52.  
  53. public void doPost(HttpServletRequest request, HttpServletResponse response)
  54. throws ServletException, IOException {
  55. // 提交的 username 参数
  56. String username = request.getParameter("username");
  57. // 提交的 password 参数
  58. String password = request.getParameter("password");
  59. // 取所有的初始化参数名称
  60. Enumeration params = this.getInitParameterNames();
  61. while(params.hasMoreElements()){
  62. String usernameParam = (String)params.nextElement();
  63. // 取参数值
  64. String passnameParam = this.getInitParameter(usernameParam);
  65. // 如果 username 匹配且 password 匹配. username 大小写不敏感,password大小写敏感
  66. if(usernameParam.equalsIgnoreCase(username)
  67. && passnameParam.equals(password)){
  68. // 显示文件。/WEB-INF 下的文件不能通过浏览器访问到,因此是安全的
  69. request.getRequestDispatcher("/WEB-INF/notice.html").forward(request, response);
  70. return;
  71. }
  72. }
  73. // username,password 不匹配,显示登录页面
  74. this.doGet(request, response);
  75. }
  76.  
  77. }

  登陆前后的效果如图3.6所示。Servlet显示/WEB-INF/下的文件。

  一个月后,公司要求增加Peter为可以浏览该机密文件的人选,同时禁止babyface的账号。由于没有将这些信息写在源程序里而是写在了web.xml里,因此改动相当简单。在参数配置里添加一个Peter,删掉babyface就可以了。

  初始化参数的好处是可以把某些变量拿到web.xml中配置,需要修改时只需要修改web.xml文件并重启服务器即可,而不需要修改Servlet类。

  上下文参数(context-param)

  由于init-param是配置在<servlet>标签里的,只能由这个Servlet来读取,因此它不是全局的参数,不能被其他的Servlet读取。

  如果需要配置一个所有Servlet都能够读取的参数,就需要用到上下文参数(Context-Param),或者叫文档参数。上下文参数使用标签<context-param>配置,代码如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  5. http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  6.  
  7. <context-param>
  8. <param-name>upload folder</param-name>
  9. <param-value>attachment</param-value>
  10. </context-param>
  11. <context-param>
  12. <param-name>allowed file type</param-name>
  13. <param-value>.gif,.jpg,.bmp</param-value>
  14. </context-param>

  获取context-param可以使用ServletContext对象。Servlet中通过getServletConfig().getServletContext()来获取一个ServletContext对象,使用ServletContext的getInitParameter()方法来获取指定名称的参数,通过getInitParameterNames()获取所有的context-param参数名称。下面是一个例子:

  1. package com.helloweenvsfei.servlet;
  2.  
  3. import java.io.IOException;
  4. import java.io.PrintWriter;
  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 ContextParamServlet extends HttpServlet {
  13.  
  14. private static final long serialVersionUID = 3194071196406358461L;
  15.  
  16. public void doGet(HttpServletRequest request, HttpServletResponse response)
  17. throws ServletException, IOException {
  18.  
  19. response.setCharacterEncoding("UTF-8");
  20. response.setContentType("text/html");
  21. PrintWriter out = response.getWriter();
  22. out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
  23. out.println("<HTML>");
  24. out.println(" <HEAD><TITLE>读取文档参数</TITLE></HEAD>");
  25. out.println(" <link rel='stylesheet' type='text/css' href='../css/style.css'>");
  26. out.println(" <BODY>");
  27. out.println("<div align=center><br/>");
  28. out.println("<fieldset style='width:90%'><legend>所有的文档参数</legend><br/>");
  29.  
  30. ServletContext servletContext = this.getServletConfig().getServletContext();
  31.  
  32. String uploadFolder = servletContext.getInitParameter("upload folder");
  33. String allowedFileType = servletContext.getInitParameter("allowed file type");
  34.  
  35. out.println("<div class='line'>");
  36. out.println(" <div align='left' class='leftDiv'>上传文件夹</div>");
  37. out.println(" <div align='left' class='rightDiv'>" + uploadFolder + "</div>");
  38. out.println("</div>");
  39.  
  40. out.println("<div class='line'>");
  41. out.println(" <div align='left' class='leftDiv'>实际磁盘路径</div>");
  42. out.println(" <div align='left' class='rightDiv'>" + servletContext.getRealPath(uploadFolder) + "</div>");
  43. out.println("</div>");
  44.  
  45. out.println("<div class='line'>");
  46. out.println(" <div align='left' class='leftDiv'>允许上传的类型</div>");
  47. out.println(" <div align='left' class='rightDiv'>" + allowedFileType + "</div>");
  48. out.println("</div>");
  49.  
  50. out.println("</fieldset></div>");
  51.  
  52. out.println(" </BODY>");
  53. out.println("</HTML>");
  54. out.flush();
  55. out.close();
  56. }
  57. }

  运行效果如图:

  初始化参数与上下文参数只能配置简单的字符串类型的参数。如果需要配置更多更灵活的参数,更推荐把参数配置写到xml文件或者properties文件里,然后编写程序读取这些文件。

  资源注射(@Resource)

  上面的例子都是在Servlet里编写程序代码读取web.xml初始参数。Java EE 5提供了一种新的方案叫做资源注射(Resource Injection),或者叫资源注入。也就是说,不需要Servlet主动去读取资源,Tomcat启动的时候会把web.xml里配置的信息主动“注射”到Servlet里。这个过程是运行时自动完成的,不需要编写任何代码,不需要做任何工作。

  资源注射是通过注解(Annotation)完成的。注解是Java 5.0里引入的新特性。注解是一种特殊的接口,以“@”符号为标志。用法如下:

  1. @Resource(name="messageNameInWebXml")
  2. private String message;

  使用@Resource标注字符串变量message,表示message的值会在Servlet运行时动态注入。然后在web.xml中配置一个名为messageNameInWebXml的参数就可以了。注解以及变量可以写在一行代码中,看起来更简洁一些;

  1. private @Resource(name="messageNameInWebXml") String message;

  看一个实例

  1. package com.helloweenvsfei.servlet;
  2.  
  3. import java.io.IOException;
  4. import java.io.PrintWriter;
  5.  
  6. import javax.annotation.Resource;
  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 InjectionServlet extends HttpServlet {
  13.  
  14. private static final long serialVersionUID = -8526907492073769090L;
  15.  
  16. // 注入的 字符串
  17. private @Resource(name="hello") String hello;
  18. // 注入的 整数
  19. private @Resource(name="i") int i;
  20.  
  21. // 注入更常见的写法
  22. @Resource(name="persons")
  23. private String persons;
  24.  
  25. public void doGet(HttpServletRequest request, HttpServletResponse response)
  26. throws ServletException, IOException {
  27.  
  28. response.setCharacterEncoding("UTF-8");
  29. request.setCharacterEncoding("UTF-8");
  30.  
  31. response.setContentType("text/html");
  32. PrintWriter out = response.getWriter();
  33. out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
  34. out.println("<HTML>");
  35. out.println(" <HEAD><TITLE>资源注入</TITLE></HEAD>");
  36. out.println("<style>body {font-size:12px; }</style>");
  37.  
  38. out.println("<b>注入的字符串</b>:<br/>&nbsp;&nbsp;-&nbsp;" + hello + "<br/>");
  39. out.println("<b>注入的整数</b>:<br/>&nbsp;&nbsp;-&nbsp;" + i + "<br/>");
  40. out.println("<b>注入的字符串数组</b>:<br/>");
  41.  
  42. for(String person : persons.split(",")){
  43. out.println("&nbsp;&nbsp;-&nbsp;" + person + "<br/>");
  44. }
  45.  
  46. out.println(" <BODY>");
  47. out.println(" </BODY>");
  48. out.println("</HTML>");
  49. out.flush();
  50. out.close();
  51. }
  52.  
  53. }

  web.xml中使用标签<env-entry>来配置资源。<env-entry>仅能配置java.lang包下的标准类型的变量,如String,Integer,Double等。配置后的代码如下:

  1. <env-entry>
  2. <env-entry-name>hello</env-entry-name>
  3. <env-entry-type>java.lang.String</env-entry-type>
  4. <env-entry-value>
  5. Hello, Welcome to the JavaEE Resource Injection.
  6. </env-entry-value>
  7. </env-entry>
  8.  
  9. <env-entry>
  10. <env-entry-name>i</env-entry-name>
  11. <env-entry-type>java.lang.Integer</env-entry-type>
  12. <env-entry-value>30</env-entry-value>
  13. </env-entry>
  14.  
  15. <env-entry>
  16. <env-entry-name>persons</env-entry-name>
  17. <env-entry-type>java.lang.String</env-entry-type>
  18. <env-entry-value>
  19. Helloween, Cobain, Roses, Axl,
  20. </env-entry-value>
  21. </env-entry>

  程序运行效果:

  使用JNDI获取资源

  资源注射的工作原理是JNDI(Java命名与目录接口,Java Naming and Directory Interface)。InjectionServlet实例中使用<env-entry>配置了名为hello, i, persons的JNDI资源,然后使用@Resource将指定名称的JNDI资源注射到InjectionServlet里。

  如果不使用@Resource,通过查找JNDI同样可以获取到这三个资源,代码如下:

  1. Context ctx = new InitialContext(); //实例化一个Context对象
  2. String message = (String)ctx.lookup("message"); //查找资源message
  3. Integer i = (Integer)ctx.lookup("i"); //查找资源i
  4. String persons = (String)ctx.lookup("persons"); //查找资源persons

  注射数据源

  Servlet中不仅可以注射String,Integer等类型的变量,还可以注入自定义的Java Bean以及数据源等复杂类型变量。例如,下面的代码将会注射一个数据源。读者只需要在Tomcat中配置好数据源,然后使用下列代码就可以获取到数据源变量。这是相当方便的:

  1. @Resource(name="dataBase") //声明数据源名称,数据源配置在Tomcat中
  2. javax.sql.DataSource dataSource; //注射到dataSource属性上
  3.  
  4. public void getConnection(){ //方法中直接使用dataSource
  5. Connection conn = dataSource.getConnection();
  6. return conn;
  7. }

  注射是利用@注解实现的。JDK5以上支持@注解。资源注射需要服务器的支持,Tomcat 6是支持的,但在某些其它Web服务器或者低版本的Tomcat可能不支持。

Servlet学习记录2的更多相关文章

  1. Servlet学习记录4

    带进度条的文件上传 UploadServlet只实现了普通的文件上传,并附带普通文本域的提交.如果需要显示上传进度条,实时显示上传速度等,需要配合使用Ajax技术.这里仍然使用Apache的commo ...

  2. Servlet学习记录3

    提交表单信息 Web程序的任务是实现服务器与客户端浏览器之间的信息交互.客户端提交的信息可能来自表单里的文本框,密码框,选择框,单选按钮,复选框以及文件域.这些表单信息被以参数形式提交到了服务器.Se ...

  3. servlet学习记录:Servlet中的service()方法

    Servlet的生存时间是由init,service,destory方法构成,这里分析一下service这个方法 Servlet接口中定义了一个service()方法,而我们一般是使用HttpServ ...

  4. Servlet学习记录

    个人认为servlet属于一种控制程序,可以处理浏览器的请求并做出对应的回应.我们经常使用的是让一个类去继承HttpServlet,然后在doget或者dopost里面写东西. 目前我个人常在doge ...

  5. 我的Spring学习记录(五)

    在我的Spring学习记录(四)中使用了注解的方式对前面三篇做了总结.而这次,使用了用户登录及注册来对于本人前面四篇做一个应用案例,希望通过这个来对于我们的Spring的使用有一定的了解. 1. 程序 ...

  6. Spring 学习记录8 初识XmlWebApplicationContext(2)

    主题 接上文Spring 学习记录7 初识XmlWebApplicationContext refresh方法 refresh方法是定义在父类AbstractApplicationContext中的. ...

  7. HTTP学习记录

    title: HTTP学习记录 toc: true date: 2018-09-21 20:40:48 HTTP协议,HyperText Transfer Protocol,超文本传输协议,是因特网上 ...

  8. 我的Spring Boot学习记录(二):Tomcat Server以及Spring MVC的上下文问题

    Spring Boot版本: 2.0.0.RELEASE 这里需要引入依赖 spring-boot-starter-web 这里有可能有个人的误解,请抱着怀疑态度看. 建议: 感觉自己也会被绕晕,所以 ...

  9. 学习记录-java基础部分(一)

    学习记录-java基础部分(一) 参考:GitHub上的知名项目:javaGuide : https://github.com/Snailclimb/JavaGuide/blob/master/doc ...

随机推荐

  1. 自己写的C#三层代码生成器

    思来想去用T4生成代码要学习它的语法,C#本身能很简单地生成txt文件,为啥不直接批量替换模板方式自己写个的三层代码生成器.说干就干,2个小时搞定.当然各层还可以做的更精细,比如DAL层的Add方法I ...

  2. java数据结构之链表(java核心卷Ⅰ读书笔记)

    1.链表 数组和ArrayList的一个重大缺陷就是:从中间位置删除一个元素要付出很大的代价,因为在这个元素删除之后,所有的元素都要向前端移动,在中间的某个位置插入一个元素也是这个原因. (小感悟:s ...

  3. 多个字符串有相同的hashcode(没见到大于8的时候转成红黑树)

    public static void main(String[] a){ byte[] b1 = {33 , 123 ,124}; byte[] b2 = {33 , 124 , 93}; byte[ ...

  4. day04 迭代器&生成器&装饰器

    目录   1.迭代器 2.生成器 3.推导式 4.匿名函数 5.内置函数 6.递归 7.闭包 8.装饰器 一.迭代器 特点: 1. 省内存 2. 只能向前. 不能反复 3. 惰性机制 让不同的数据类型 ...

  5. form表单提交数据,页面必定会刷新,ajax提交数据不会刷新,做到悄悄提交,多选删除,ajax提交实例

    很多页面用到的模态对话框,如知明网站https://dig.chouti.com/的登录页都是模态对话框, 当点登录时,是用的ajax提交,因为输入错了信息,有返回消息,而页面没有刷新. jquery ...

  6. [蓝桥杯]PREV-27.历届试题_蚂蚁感冒

    问题描述 长100厘米的细长直杆子上有n只蚂蚁.它们的头有的朝左,有的朝右. 每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒. 当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行. 这些蚂蚁中,有1只蚂 ...

  7. Linux 调试打印时间和颜色

    Linux调试打印时间和颜色 #include <sys/time.h> #include <unistd.h> void print_time(void) { struct ...

  8. python之路——23

    复习 1.类定义 函数--方法--动态属性 必须传self 变量--类属性--静态属性 __init__方法--初始化方法2.实例化 1.使用:对象 = 类() 2.实例和对象没有区别 3.对象调用方 ...

  9. vscode中使用beautify插件格式化vue文件

    1.点击设置,找到beautify.language并在html一栏里加上vue "beautify.language": { "js": { "ty ...

  10. WPF 播放声音 百度文字转声音

    https://developer.baidu.com/vcast  google浏览器可下载 https://www.cnblogs.com/maruko/archive/2013/04/19/WP ...