跳转到内容

WebObjects/Web 应用程序/开发/生成静态页面

来自 Wikibooks,开放世界中的开放书籍

从 WebObjects 构建静态网站

[编辑 | 编辑源代码]

上周 WWDC 上,一位观众在 WebObjects 会议上问到如何使用 WebObjects 从动态网站创建静态页面。据我回忆,Bill Bumgarner 回答了这个问题。这是在提出任何类型的动态网站时反复出现的一个问题。曾经,在线 WebObjects 文档的编程主题中包含了如何处理此问题的简要说明,由为 BBC 设置初始网站的苹果员工编写;该说明没有在网站的多次清除中幸存下来 - 这很好,因为它非常简短和肤浅。

从动态引擎创建静态网站有很多原因;BBC 选择这样做是为了担心 WebObjects 的性能。更合理的理由是使用 html 作为便携的文档格式;例如,创建在 CD 上分发的公司形象手册。我参与过几个这样做的项目,包括上面提到的两个。

我将完全跳过如何在 WebObjects 中创建动态页面,而专注于如何在页面级组件中创建静态页面。动态内容是一个很容易解决的问题,而且它被多次解决。创建静态页面的问题可以清楚地分为两部分:明显的部分是如何将页面写入 html 文件,这通常被称为“爬取”;不那么明显的部分是,所有页面链接都必须以某种方式从 WebObjects 动态操作转换为静态 URL。

首先,您需要一个机制来访问网站上的每个页面。我通常为此目的在管理应用程序中创建一个操作。我将有一个数据库结构,其中包含要写入的每个页面的记录(企业对象)。这将包含页面子级的关系以及父级的关系。顶层页面可以通过它没有父级来识别;如果需要,此结构也可以扩展为表示单个数据库中的多个网站或顶层页面。我的页面或节点 EO 将有一个方法来将自身写入;要写入的文件系统位置将根据节点路径到当前节点计算,使用 EO 中的文件系统名称来标记路径。

我在组件中使用以下方法来写入页面,该方法从爬取代码中调用;节点是表示页面或节点的 EO,htmlPath 是一个明显的方法。

   public void writeToHtml() {
       WOResponse r = null;
       String c = null;
       try {
           File folder = new File(NSPathUtilities.stringByDeletingLastPathComponent(node().htmlPath()));
           folder.mkdirs();
           BufferedWriter out = new BufferedWriter(new FileWriter(new File(node().htmlPath())));
           r = generateResponse();
           if (r == null) NSLog.debug.appendln("writeHtml: no response");
             c = r.contentString();
           if (c == null) NSLog.debug.appendln("writeHtml: no content");
             out.write(c);
           out.flush();
       } catch (IOException e) {
           System.err.println(e.getMessage());
       } catch (Throwable e) {
           System.err.println("writeToHtml(" + node().htmlPath() + "): " + e.getMessage());
       }
   }

htmlPath() 方法的示例实现如下

   public String htmlPath() {
       return NSPathUtilities.stringByAppendingPathComponent(PLUtilities.defaultForKey(null, "docroot", "/Library/WebServer/Documents").toString(), urlPath());
   }
 
   public String urlPath() {
       String fileName = name() + primaryKeyString(this) + ".html";
       return "/" + NSPathUtilities.stringByAppendingPathComponent(site().name(), fileName);
   }
 
   static public String primaryKeyString(EOEnterpriseObject object) {
       NSDictionary dict = EOUtilities.primaryKeyForObject(object.editingContext(), object);
       String result = "";
       java.util.Enumeration enumerator = dict.objectEnumerator();
       while (enumerator.hasMoreElements()) {
           Object anObject = enumerator.nextElement();
           result += anObject.toString();
       }
       return result;
   }

可能需要更智能的实现,根据节点层次结构构建路径字符串,或者从 EO 属性获取文件名等。

[编辑 | 编辑源代码]

此类网站组件中可以使用唯一的操作是 WOHyperlinks;这些可以转换为静态页面引用,而表单操作等则不能。基本假设是所有页面都将从文件系统而不是 Web 服务器提供服务,因此不支持 cgi。理论上,您可以使用 Javascript 来满足页面的任何动态需求。

由于允许网站以动态网站和静态版本运行非常有用,因此我用以下结构替换了所有 WOHyperlinks(来自 wod 文件)

 Generic1: WOGenericContainer {
   elementName = "a";
   href = nodeHref;
   invokeAction = nodeLink;
 }

这两种方法必须对上下文敏感,并知道何时生成动态的 WOHyperlink 风格链接,何时生成静态链接。在我的管理应用程序中,用于创建和编辑网站,我包含一个根据我们是否正在查看(动态)或生成(静态)网站而设置的标志。

   public String nodeHref() {
       if (sessionViewMode()) return context().componentActionURL();
       return aNode.urlPath();
   }
 
   public CustomTemplate nodeLink() {
       if (aNode != null)
           return pageWithName(aNode.name());
   }

对 pageWithName() 的调用从节点 EO 中获取组件名称;同样,这可以用更智能的调用来替换,该调用在组件中设置值等。

通用容器使用 <A> 标记构建一个 href,该 href 将包含适当的静态 url,或者根据 sessionViewMode() 返回的值完全充当 WOHyperlink。

华夏公益教科书