通知 网站从因情语写改为晴雨,这个网站的模板也从calmlog_ex改为 whimurmur

Servlet学习记录2

1245人浏览 / 0人评论 / | 作者:因情语写  | 分类: JAVAWEB  | 标签: java web整合开发王者归来  | 

作者:因情语写

链接:https://www.proprogrammar.com/article/17

声明:请尊重原作者的劳动,如需转载请注明出处


      读取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个初始化参数。

<servlet>
    <servlet-name>InitParamServlet</servlet-name>
    <servlet-class>
        com.helloweenvsfei.servlet.InitParamServlet
    </servlet-class>
    <init-param>
        <param-name>helloween</param-name>
        <param-value>password</param-value>
    </init-param>
    <init-param>
        <param-name>admin</param-name>
        <param-value>admin</param-value>
    </init-param>
    <init-param>
        <param-name>babyface</param-name>
        <param-value>babyface</param-value>
    </init-param>
</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下的文件不能通过浏览器直接获取到,但是仍然可以通过程序读取到。程序如下:

package com.helloweenvsfei.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class InitParamServlet extends HttpServlet {

    private static final long serialVersionUID = 7298032096933866458L;
    
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setCharacterEncoding("UTF-8");
        request.setCharacterEncoding("UTF-8");
        
        response.setContentType("text/html");
        
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
        out.println("<HTML>");
        out.println("  <HEAD><TITLE>请登录查看 Notice 文件</TITLE></HEAD>");
        out.println("<style>body, td, div {font-size:12px; }</style>");
        out.println("  <BODY>");
        
        out.println("<form action='" + request.getRequestURI() + "' method='post'>");
        out.println("帐号:<input type='text' name='username' style='width:200px; '> <br/>");
        out.println("密码:<input type='password' name='password' style='width:200px; '> <br/><br/>");
        out.println("<input type='submit' value='  登录  '>");
        out.println("</form>");
        
        if(true){
            out.println("<br/><br/><br/><br/><br/><br/><br/>用户名、密码为:<br/>");
            Enumeration params = this.getInitParameterNames();
            while(params.hasMoreElements()){
                String usernameParam = (String)params.nextElement();
                String passnameParam = this.getInitParameter(usernameParam);
                out.println("[" + usernameParam + ", " + passnameParam + "], ");
            }
        }
        
        out.println("  </BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 提交的 username 参数
        String username = request.getParameter("username");
        // 提交的 password 参数
        String password = request.getParameter("password");
        // 取所有的初始化参数名称
        Enumeration params = this.getInitParameterNames();
        while(params.hasMoreElements()){
            String usernameParam = (String)params.nextElement();
            // 取参数值
            String passnameParam = this.getInitParameter(usernameParam);
            // 如果 username 匹配且 password 匹配. username 大小写不敏感,password大小写敏感
            if(usernameParam.equalsIgnoreCase(username)
                    && passnameParam.equals(password)){
                // 显示文件。/WEB-INF 下的文件不能通过浏览器访问到,因此是安全的
                request.getRequestDispatcher("/WEB-INF/notice.html").forward(request, response);
                return;
            }
        }
        // username,password 不匹配,显示登录页面
        this.doGet(request, response);        
    }

}

      登陆前后的效果如图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>配置,代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<context-param>
    <param-name>upload folder</param-name>
    <param-value>attachment</param-value>
</context-param>
<context-param>
    <param-name>allowed file type</param-name>
    <param-value>.gif,.jpg,.bmp</param-value>
</context-param>

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

package com.helloweenvsfei.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ContextParamServlet extends HttpServlet {

    private static final long serialVersionUID = 3194071196406358461L;

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
        out.println("<HTML>");
        out.println("  <HEAD><TITLE>读取文档参数</TITLE></HEAD>");
        out.println("  <link rel='stylesheet' type='text/css' href='../css/style.css'>");
        out.println("  <BODY>");
        out.println("<div align=center><br/>");
        out.println("<fieldset style='width:90%'><legend>所有的文档参数</legend><br/>");

        ServletContext servletContext = this.getServletConfig().getServletContext();
        
        String uploadFolder = servletContext.getInitParameter("upload folder");
        String allowedFileType = servletContext.getInitParameter("allowed file type");

        out.println("<div class='line'>");
        out.println("    <div align='left' class='leftDiv'>上传文件夹</div>");
        out.println("    <div align='left' class='rightDiv'>" + uploadFolder + "</div>");
        out.println("</div>");

        out.println("<div class='line'>");
        out.println("    <div align='left' class='leftDiv'>实际磁盘路径</div>");
        out.println("    <div align='left' class='rightDiv'>" + servletContext.getRealPath(uploadFolder) + "</div>");
        out.println("</div>");
        
        out.println("<div class='line'>");
        out.println("    <div align='left' class='leftDiv'>允许上传的类型</div>");
        out.println("    <div align='left' class='rightDiv'>" + allowedFileType + "</div>");
        out.println("</div>");

        out.println("</fieldset></div>");
        
        out.println("  </BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }
}

      运行效果如图:

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

  资源注射(@Resource)

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

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

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

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

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

      看一个实例

package com.helloweenvsfei.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class InjectionServlet extends HttpServlet {

    private static final long serialVersionUID = -8526907492073769090L;

    // 注入的 字符串
    private @Resource(name="hello") String hello;
    // 注入的 整数
    private @Resource(name="i") int i;
    
    // 注入更常见的写法
    @Resource(name="persons")
    private String persons;
    
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setCharacterEncoding("UTF-8");
        request.setCharacterEncoding("UTF-8");
        
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
        out.println("<HTML>");
        out.println("  <HEAD><TITLE>资源注入</TITLE></HEAD>");
        out.println("<style>body {font-size:12px; }</style>");
        
        out.println("<b>注入的字符串</b>:<br/>  - " + hello + "<br/>");
        out.println("<b>注入的整数</b>:<br/>  - " + i + "<br/>");
        out.println("<b>注入的字符串数组</b>:<br/>");
        
        for(String person : persons.split(",")){
            out.println("  - " + person + "<br/>");
        }
        
        out.println("  <BODY>");
        out.println("  </BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }

}

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

<env-entry>
    <env-entry-name>hello</env-entry-name>
    <env-entry-type>java.lang.String</env-entry-type>
    <env-entry-value>
        Hello, Welcome to the JavaEE Resource Injection.
    </env-entry-value>
</env-entry>

<env-entry>
    <env-entry-name>i</env-entry-name>
    <env-entry-type>java.lang.Integer</env-entry-type>
    <env-entry-value>30</env-entry-value>
</env-entry>

<env-entry>
    <env-entry-name>persons</env-entry-name>
    <env-entry-type>java.lang.String</env-entry-type>
    <env-entry-value>
        Helloween, Cobain, Roses, Axl,
    </env-entry-value>
</env-entry>

      程序运行效果:

      使用JNDI获取资源

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

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

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

      注射数据源

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

@Resource(name="dataBase") //声明数据源名称,数据源配置在Tomcat中
javax.sql.DataSource dataSource;  //注射到dataSource属性上

public void getConnection(){  //方法中直接使用dataSource
      Connection conn = dataSource.getConnection();
      return conn;
}

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


亲爱的读者:有时间可以点赞评论一下

点赞(0) 打赏

全部评论

还没有评论!
广告位-帮帮忙点下广告