在不同的Web应用之间共享数据

原文源自《Servlet与JSP核心编程(第2卷 第2版)》第1章,转载自点击打开链接

1.7  在不同的Web应用之间共享数据(1)

Web应用程序的一个主要功能就是保持数据和功能的独立。每一个Web应用程序都维护着它自己的session表和它自己的servlet上下文。每一个Web应用程序也使用它自己的类加载器;这种做法排除了名称冲突的问题,但同时也意味着静态方法和字段不能够在多个应用程序之间共享。然而,通过使用cookie或者使用特殊URL的ServletContext对象同样能共享数据。这些方法能够满足Web应用程序之间少量信息的共享,但如果打算进行大量数据的共享,则应该考虑让这些应用程序作为一个Web应用程序来运行。下面简要介绍两种数据共享。

cookie  cookie是由浏览器而不是由服务器来维护的(cookie实际上是客户端计算机上的一些文本文件,只能保存少量的信息)。因此,只要被设置成可以应用于任何服务器地址,cookie就可以在多个Web应用程序之间共享。默认情况下,浏览器仅仅把cookie发送某些特定的网页,这些网页的URL前缀和创建这个cookie的网页URL前缀相同。例如,如果服务器的http://host/path1/SomeFile.jsp页面在本地计算机上创建了一个cookie,那么下次请求http://host/path1/SomeOtherFile.jsphttp://host/path1/path2/Anything这两个URL的时候,浏览器会自动把cookie发送给这些网页;而不会把cookie发送给http://host/path3/Anything 。因为每个Web应用程序都有其特定的URL前缀,所以默认建立的cookie是不能在不同Web应用程序之间共享的。

然而,正如我们在第1卷的第8章中讲述的那样,可以使用cookie 类的 setPath 方法来改变这个默认行为。传递一个"/"给这个方法,浏览器便会把这个cookie发送给创建此cookie的URL所在服务器的所有URL地址。

Cookie c = new Cookie("name", "value");  
c.setMaxAge(...);  
c.setPath("/");  
response.addCookie(c); 
特定URL关联的ServletContext对象  在一个servlet内部,可以通过调用servlet的getServletContext方法(继承自GenericServlet)来获得Web应用程序的servlet上下文。在JSP页面中,使用预定义的application变量。使用任何一种方法,都可以获得servlet所匹配的上下文环境或者正在处理请求的JSP页面。然而,也可以调用ServletContext的getContext方法来获得一个servlet上下文环境,这个上下文环境不一定是你的,而是一个指定的URL的。这里也用黑体字列举此方法。

ServletContext myContext = getServletContext();  
String url = "/someWebAppPrefix";  
ServletContext otherContext = myContext.getContext(url);  
Object someData = otherContext.getAttribute("someKey"); 

其实,这两种数据共享的方法都不是很完美。

cookie的缺点是只能存储少量有限的数据。每一个cookie的值都是一个字符串,而且每个字符串的长度限制在4 KB以内。所以,更多的数据共享就需要数据库的支持:可以使用cookie的值作为主键值,然后把实际的值存储在数据库中。

通过servlet上下文来共享数据的首要缺点是,我们必须知道其他Web应用程序正在使用的URL前缀。作为开发人员,肯定希望在改变Web应用程序前缀的时候不需要修改任何与之相关的代码。getContext方法的使用限制了处理的灵活性。第二个缺点就是安全。服务器上的某些Web应用程序可能阻止了对ServletContext的访问。在这种情况下,调用getContext将返回null值。例如,在一些Tomcat版本中,上下文共享默认是启用的,而在其他一些版本中,却需要明确的手动启用。比如,Tomcat 5.5.7中,可以添加crossContext="true"作为tomcat_dir/conf/context.xml中Context元素的一部分,从而把启用上下文共享作为所有部署的Web应用程序的默认设置。如果忽略crossContext属性,将导致Tomcat使用其默认设置,这会阻止在Web应用程序之间共享ServletContext。

清单1.5和清单1.6的SetSharedInfo和ShowSharedInfo这两个servlet展示了这两种数据共享方法。这些servlet 被映射为清单1.7所示的部署描述文件中的URL地址。SetSharedInfo servlet在session对象和servlet上下文中创建了一些自定义的项。同时,它也设置了两个Cookie:(一个拥有默认路径,默认路径说明cookie只应该发送到与原请求的URL前缀相同的那些URL地址。另一个cookie的路径被设置为"/",说明cookie会被应用于远程主机的所有URL。最后,SetSharedInfo Servlet把客户端重定向到ShowSharedInfo servlet,这个servlet将显示所有session的属性名称、所有当前servlet上下文的属性、所有以/shareTest1为前缀的URL的servlet 上下文属性以及所有的cookie。

清单1.5  SetSharedInfo.java

package coreservlets;  
 
import java.io.*;  
import javax.servlet.*;  
import javax.servlet.http.*;  
 
public class SetSharedInfo extends HttpServlet {  
  public void doGet(HttpServletRequest request,  
                       HttpServletResponse response)  
    throws ServletException, IOException {  
    HttpSession session = request.getSession(true);  
    session.setAttribute("sessionTest", "Session Entry One");  
    ServletContext context = getServletContext();  
    context.setAttribute("servletContextTest",  
                             "Servlet Context Entry One");  
    Cookie c1 = new Cookie("cookieTest1", "Cookie One");  
    c1.setMaxAge(3600); // One hour  
    response.addCookie(c1); // Default path  
    Cookie c2 = new Cookie("cookieTest2", "Cookie Two");  
    c2.setMaxAge(3600); // One hour  
    c2.setPath("/"); // Explicit path: all URLs  
    response.addCookie(c2);  
    String url = request.getContextPath() +  
                    "/servlet/coreservlets.ShowSharedInfo";  
    // In case session tracking is based on URL rewriting.  
    url = response.encodeRedirectURL(url);  
    response.sendRedirect(url);  
  }  
} 

清单1.6  ShowSharedInfo.java

package coreservlets;  
 
import java.io.*;  
import javax.servlet.*;  
import javax.servlet.http.*;  
import java.util.*;  
 
public class ShowSharedInfo extends HttpServlet {  
  public void doGet(HttpServletRequest request,  
                       HttpServletResponse response)  
      throws ServletException, IOException {  
    response.setContentType("text/html");  
    PrintWriter out = response.getWriter();  
    String title = "Shared Info";  
    out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " +  
                  "Transitional//EN\">" +  
                  "<HTML>\n" +  
                  "<HEAD><TITLE>" + title + "</TITLE></HEAD>\n" +  
                  "<BODY BGCOLOR=\"#FDF5E6\">\n" +  
                  "<H1 ALIGN=\"CENTER\">" + title + "</H1>\n" +  
                  "<UL>\n" +  
                  " <LI>Session:");  
        HttpSession session = request.getSession(true);  
        Enumeration attributes = session.getAttributeNames();  
        out.println(getAttributeList(attributes));  
        out.println(" <LI>Current Servlet Context:");  
        ServletContext application = getServletContext();  
        attributes = application.getAttributeNames();  
        out.println(getAttributeList(attributes));  
        out.println(" <LI>Servlet Context of /shareTest1:");  
        application = application.getContext("/shareTest1");  
        if (application == null) {  
             out.println("Context sharing disabled");  
        } else {  
             attributes = application.getAttributeNames();  
             out.println(getAttributeList(attributes));  
        }  
        out.println(" <LI>Cookies:<UL>");  
        Cookie[] cookies = request.getCookies();  
        if ((cookies == null) || (cookies.length == 0)) {  
            out.println(" <LI>No cookies found.");  
        } else {  
          Cookie cookie;  
          for(int i=0; i<cookies.length; i++) {  
             cookie = cookies[i];  
             out.println(" <LI>" + cookie.getName());  
        }  
      }  
      out.println(" </UL>\n" +  
                    "</UL>\n" +  
                    "</BODY></HTML>");  
  }  
private String getAttributeList(Enumeration attributes) {  
    StringBuffer list = new StringBuffer(" <UL>\n");  
    if (!attributes.hasMoreElements()) {  
      list.append(" <LI>No attributes found.");  
    } else {  
      while(attributes.hasMoreElements()) {  
        list.append(" <LI>");  
        list.append(attributes.nextElement());  
        list.append("\n");  
      }  
    }  
    list.append(" </UL>");  
    return(list.toString());  
  }  
} 

清单1.7  web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>  
<!-- web.xml from the app-blank template Web app  
      from http://courses.coreservlets.com/Course-Materials/.  
      Includes two standard elements: welcome-file list  
      and a servlet-mapping to disable the invoker servlet.-->  
<Web-app xmlns="http://java.sun.com/xml/ns/j2ee" 
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
           xsi:schemaLocation=  
             "http://java.sun.com/xml/ns/j2ee  
             http://java.sun.com/xml/ns/j2ee/Web-app_2_4.xsd"  
           version="2.4">  
 
<!-- Your entries go here. -->  
  <servlet>  
  <servlet-name>setSharedInfoServlet</servlet-name>  
<servlet-class>coreservlets.SetSharedInfo</servlet-class>  
</servlet>  
<servlet-mapping>  
  <servlet-name>setSharedInfoServlet</servlet-name>  
  <url-pattern>/setSharedInfo</url-pattern>  
</servlet-mapping>  
<servlet>  
  <servlet-name>showSharedInfoServlet</servlet-name>  
  <servlet-class>coreservlets.ShowSharedInfo</servlet-class>  
</servlet>  
<servlet-mapping>  
<servlet-name>showSharedInfoServlet</servlet-name>  
<url-pattern>/showSharedInfo</url-pattern>  
</servlet-mapping>  
 
<!-- Disable the invoker servlet. -->  
<servlet>  
  <servlet-name>NoInvoker</servlet-name>  
  <servlet-class>coreservlets.NoInvokerServlet</servlet-class>  
</servlet>  
<servlet-mapping>  
  <servlet-name>NoInvoker</servlet-name>  
  <url-pattern>/servlet/*</url-pattern>  
</servlet-mapping>  
<!-- If URL gives a directory but no file name, try index.jsp  
      first and index.html second. If neither is found,  
      the result is server-specific (e.g., a directory  
      listing).  
-->  
  <welcome-file-list>  
    <welcome-file>index.jsp</welcome-file>  
    <welcome-file>index.html</welcome-file>  
  </welcome-file-list>  
</Web-app> 

运行这个示例的时候,确保只调用了shareTest1应用程序的SetSharedInfo servlet。在此之后,调用shareTest1和shareTest2的ShowSharedInfo servlet。不要调用shareTest2的ShowSharedInfo servlet,因为它不能表现两个应用程序之间的数据共享。

图1.9显示了用户从前缀为/shareTest1的Web应用程序内部访问SetSharedInfo和SharedInfo所得的结果。ShowSharedInfo显示了以下内容。

自定义的会话属性。

默认servlet上下文的自定义(由SetSharedInfo这个servlet显式创建)和标准属性(由服务器自动创建)。

getContext("/shareTest1")返回的servlet上下文的自定义属性和标准属性。

两个显式创建的cookie和系统创建的用于后台session跟踪的cookie。


 
图1.9  从一个Web应用访问两个servlet所得到的结果

图1.10显示了随后用户访问安装于前缀为shareTest2的Web应用程序中的ShowSharedInfo副本的结果。这个servlet显示了以下内容。

默认servlet上下文中包含的标准属性。

getContext("/shareTest1")返回的servlet上下文的自定义和标准属性(本例中不同于默认servlet上下文)

两个cookie:一个是显式创建的,以"/" 作为路径,一个是系统创建的,用于后台session跟踪cookie(也是以"/" 作为其路径)。

 
图1.10  在一个Web应用程序中访问SetSharedInfo servlet
和在另一个不同的Web应用程序中访问ShowSharedInfo servlet的结果

这个servlet没有显示以下内容。

它的session对象中的任何属性。

任何默认servlet上下文中的自定义属性。

显式创建的使用默认路径的cookie。




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值