IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope:Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  WebSphere  >

对 WebSphere Studio Page Designer 可视化定制标记进行编程

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

Kaoru Hosokawa (hosokawa@jp.ibm.com), 技术领导人,WebSphere Studio Page Designer, IBM 日本

2003 年 7 月 01 日

IBM WebSphere Studio Page Designer(PD)是一个用于编辑 HTML 页面和 JSP 页面的类似字处理器的编辑器。本文描述了编写用于 VCT 的可视化的编程模型。最终,我们将编写用于数据库访问标记和其他标记的可视化器。

© Copyright International Business Machines Corporation 2003. All rights reserved.

Copyright IBM Corporation 2003. All rights reserved.

引言

IBM® WebSphere® Studio Page Designer(PD)是一个用于编辑 HTML 页面和 JSP 页面的类似字处理器的编辑器。HTML 页面在 PD 中的样子与在浏览器中非常相像。但是,在 PD 的前一个版本中,JSP 页面中的 JSP 定制标记却显示为图标,对于在编辑过程中想看看页面在浏览器中的样子的 Web 设计人员来说,这非常不方便。在 WebSphere Studio V5 中,PD 得到了加强,以便定制的标记显示为它们在浏览器中显示的样子,而不是显示为图标。这些定制标记称为可视化定制标记(visual custom tag,VCT),在设计视图中显示它们需要一个称为可视化器(visualizer)的 Java™ 类。可视化器的输出是一组 HTML 标记,这组标记是定制标记的可视化表示。下面的图显示了一个带有 VCT 的 JSP 页面在有可视化器和没有可视化器的环境中的显示情况:

本文描述了编写用于 VCT 的可视化器的编程模型。最终,我们将编写用于数据库访问标记和其他标记的可视化器。欲参阅用于开发可视化器的一组 API,请参阅 附录:可视化器 API 参考

VCT 在 Page Designer V5 中是受到支持的,后者是一个在 WebSphere Studio Site Developer for Linux 和 Windows®,V5.0、WebSphere Studio Application Developer for Linux 和 Windows,V5.0 中都有提供的插件。这些可视化器是用 WebSphere Studio Application Developer for Linux 和 Windows,V5.0 的 Page Designer V5 开发和测试的。

下一节将向您说明如何编写可视化器以及如何可以在 PD 中使用这个可视化器。





回页首


用 WebSphere Studio 开发可视化器

对可视化器的描述

我们将开发一个用于 <date> JSP 定制标记的可视化器,当在服务器上运行时,它将显示当前日期和时间。我们还想在 PD 设计视图中显示当前日期和时间。

我们必须继承 CustomTagVisualizer 类以实现可视化器。可视化器还必须实现和覆盖 doStart() 方法或 doEnd() 方法 - 我们选择 doEnd() 方法:

import java.util.*;
import org.w3c.dom.*;
import com.ibm.etools.webedit.vct.*;
public class DateTimeTagVisualizer extends CustomTagVisualizer {
 public VisualizerReturnCode doEnd(Context context) {
  Date now = new Date();
  context.putVisual(now.toString());
  return VisualizerReturnCode.OK;
 }
}
    

我们用 putVisual() 将当前日期和时间存储在上下文中,并生成一个 VisualizerReturnCode.OK 返回代码以表示 PD 可以使用视觉进行显示。

导入 Page Designer 插件

在开始开发可视化器之前,必须将 Page Designer 插件导入工作区:

  1. 从菜单中选择 Window => Preferences。Preferences 对话框打开。
  2. 选择 Plug-In Development,再选择 Show plug-in objects in editors and dialogs using中的 Presentation names

  3. 单击 OK
  4. 从菜单中选择 File => ImportImport向导打开。
  5. 选择 External Plug-ins and Fragments并单击 NextImport Plug-ins and Fragments -- Import External Plug-ins向导页面打开。
  6. 选择 NextImport Plug-ins and Fragments -- Selection向导页面打开。
  7. 从 Plug-ins and Fragments Found: 列表中选择 IBM Web Tooling HTML Editor (5.0.1)IBM Web Tooling HTML Editor Core (5.0.1)。单击 Add Required Plug-ins

  8. 单击 Finish。现在已经导入了 Page Designer 插件和相关的插件。

创建插件项目

可视化器是一个 Page Designer 插件,因此我们在插件项目中开发我们的可视化器。这里是创建插件项目的步骤。(欲了解更多有关插件开发的信息,请参阅 Eclipse 文章 Your First Plug-in

  1. 从菜单中选择 File => New => ProjectNew Project向导打开。
  2. 选择 Plug-in DevelopmentPlug-in Project,然后单击 NextNew Plug-in Project页面打开。
  3. 输入一个项目名称(如 sample ),然后单击 NextNew Plug-in Project - Plug-in Project Structure页面打开。
  4. 单击 NextNew Plug-in Project -Plug-in Code Generators页面打开。选择 Create a blank plug-in project复选框。

  5. 单击 Finish。这样便创建了插件项目。

创建 plugin.xml 文件

我们需要向 plugin.xml 文件另外添加一些信息。向 plugin.xml 添加以下代码,请添加在 <runtime> 标记后。

<requires>
  <samp><import plugin="org.apache.xerces"/></samp>
  <samp><import plugin="com.ibm.etools.webedit.core"/>
</requires>
<extension point="com.ibm.etools.webedit.core.visualCustomTag"></samp>
  <samp><vtaglib uri="/WEB-INF/lib/sample.jar"></samp>
    <samp><vtag name="date"
      class="com.ibm.etools.webedit.vct.sample.DateTimeTagVisualizer"
      description="Dynamically outputs current date and time"/></samp>
  <samp></vtaglib>
</extension></samp>
    

这个插件需要其他插件才能工作。需要使用 <requires><import> 元素指定所需的插件。这里我们导入 org.apache.xerces 插件和 com.ibm.etools.webedit.core 插件。 <extension> 元素将指定这个插件提供的内容。这个插件将连接到由 <extension> 元素的 point 属性指定的扩展点。

<vtaglib> 元素与 <taglib> 相似,并指定了可用的 VCT。 <vtaglib> 元素的 uri 属性可以用作 VCT 的标识符。当 PD 发现一个定制标记时,它便会查找声明这个定制标记的 taglib 伪指令。它会获得 taglib 伪指令的 uri 属性并试图将这个属性与 <vtaglib> 元素的 uri 属性匹配。当找到一个匹配时,那个插件便用来对定制标记进行可视化。因此,为了让可视化器工作, <vtaglib> 元素的 uri 属性必须与在 JSP 页面的 taglib 伪指令中指定的 uri 相同。

<vtag> 元素将指定 VCT 的名称和可视化器 Java 类。在这个示例中,标记为 date ,得到执行的可视化器为 com.ibm.etools.webedit.vct.sample.DateTimeTagVisualizer 。您可以在 description 属性中编写一些注释。

现在,我们要更新 Java 类路径,使它包含已导入的插件类 org.apache.xercescom.ibm.etools.webedit.core

  1. Package Explorer中用鼠标右键单击 plug-in project 并从弹出菜单中选择 Update ClasspathJava Classpath对话框打开。
  2. 单击 Finish。对插件项目的 Java 类路径进行了更新,从而包含了这两个插件。

在运行时工作台中运行可视化器

要使用运行时工作台创建 JSP 文件,必须另外添加一些插件:

  1. 从菜单中选择 Window => PreferencesPreferences对话框打开。
  2. 从列表中选择 Plug-in Development => Target Platform。单击 Not In Workspace

  3. 单击 OK

这里是在 Run-time Workbench 中运行可视化器的步骤。

  1. 从菜单中选择 Run => RunLaunch Configurations向导页面打开。
  2. 选择 Run-time Workbench并单击 New

  3. 单击 Run。运行时工作台打开。
  4. 使用 PD 创建一个 Web 项目和一个带有 VCT 的 JSP 文件。请确保有一个 taglib 伪指令。(但是不需要实际的 TLD 文件。)例如:
    <%@taglib uri="/WEB-INF/lib/sample.jar" prefix="vct" %>
                

    请将下面这个标记添加到要显示当前日期和时间的 JSP 文件中:

    <vct:date/>
                

    这里是一个样本 JSP 页面:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <HTML>
    <HEAD>
    <%@ taglib uri="/WEB-INF/lib/sample.jar" prefix="vct" %>
    <%@ page
    language="java"
    contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"
    %>
    <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <META name="GENERATOR" content="IBM WebSphere Studio">
    <META http-equiv="Content-Style-Type" content="text/css">
    <LINK href="theme/Master.css" rel="stylesheet" type="text/css">
    <TITLE>index.jsp</TITLE>
    </HEAD>
    <BODY>
    The current date and time is:
    <vct:date/>
    </BODY>
    </HTML>
                

  5. 从菜单中选择 JSP => Show Visual Custom Tags。显示出定制标记:

  6. 完成之后,从菜单中选择 File => Exit来关闭运行时控制台。




回页首


<large> 标记可视化器

<large> 标记有以下格式:

<vct:large>Hello World Wide Web</vct:large>
    

这个标记仅仅将大字体大小应用到主体内容。我们想开发一个能让我们在设计视图中对主体内容进行编辑的可视化器。为了做到这一点,我们需要开发基于节点的可视化器。创建一个名为 myfirstvisualizer 的新的插件项目,并 在其中 创建 LargeTagVisualizer

package myfirstvisualizer;
import org.w3c.dom.*;
import com.ibm.etools.webedit.vct.*;
public class LargeTagVisualizer extends CustomTagVisualizer {
 private final String FONT_TAG = "FONT";
 private final String SIZE_ATTR = "SIZE";
 private final String SIZE_VALUE = "+4";
 public boolean isReadOnlyVisual() {
  return false;
 }
 public VisualizerReturnCode doEnd(Context context) {
  // get body content
  Node self = context.getSelf();
  NodeList body = self.getChildNodes();
  // create <samp><FONT></samp> element
  Document doc = context.getDocument();
  Element font = doc.createElement(FONT_TAG);
  font.setAttribute(SIZE_ATTR, SIZE_VALUE);
  // Attach body content to <samp><FONT></samp> element and return
  appendChildren(font, body);
  context.putVisual(font);
  return VisualizerReturnCode.OK;
 }
 private void appendChildren(Element parent, NodeList children) {
  for (int i = 0; i <samp><</samp> children.getLength(); i++)
   parent.appendChild((Node) children.item(i));
 }
}
    

首先,我们声明这个可视化器将通过覆盖 isReadOnlyVisual() 生成可编辑的内容。然后我们来实现 doEnd() 方法。我们要对 <large> 标记的主体内容进行检索,并将其包含在 HTML 的 <FONT> 标记中。我们从 context 获得 <large> 标记节点并对主体内容进行检索。接下来,我们创建 <FONT> 标记元素并将其 size 属性设置为 +4 。我们使用 appendChildren() 将主体附加到字体,然后将产生的字体元素存储在 context 中并返回。您需要编写以下 plugin.xml 以获得这个由 PD 识别的可视化器:

<?xml version="1.0" encoding="UTF-8" ?>
<plugin id="myfirstvisualizer"
 name="myfirstvisualizer"
 version="1.0.0">
<runtime>
 <library name="myfirstvisualizer.jar"/>
</runtime>
<requires>
 <import plugin="org.apache.xerces"/>
 <import plugin="com.ibm.etools.webedit.core"/>
</requires>
<extension point="com.ibm.etools.webedit.core.visualCustomTag">
 <vtaglib uri="/WEB-INF/lib/myfirstvisualizer.jar">
  <vtag name="large"
   description="Enlarge text by increasing font size"
   class="myfirstvisualizer.LargeTagVisualizer"/>
 </vtaglib>
</extension>
</plugin>
    

下面是当它被可视化时的显示情况:

您可以在设计视图中对文本进行修改,例如更改文本颜色:

<large> 标记创建属性视图

在 PD 中,您可以使用属性视图对 HTML 标记的属性值进行更改。定制标记也有属性,您可以通过为定制标记创建属性视图来对它们进行更改。 <large> 标记有一个 size 属性,这个属性对主体内容的字体大小进行控制。我们将创建一个能让您对 size 属性值进行更改的属性视图。

首先,我们需要再覆盖 CustomTagVisualizer 的三个方法来创建属性视图。第一个方法是 useCustomAttributeView() 。我们返回 true 以表示 <large> 标记具有属性视图。

public boolean useCustomAttributeView() {
 return true;
}
    

接下来我们覆盖 createCustomAttributeView() 。它会被调用一次,这里我们通过将 SWT 窗口部件放在 Composite 的顶部来创建属性视图。这个 Composite 被当作参数进行传递:

public void createCustomAttributeView(Composite parent) {
 parent.setLayout(new FillLayout());
 GridLayout grid = new GridLayout();
 grid.numColumns = 2;
 Composite base = new Composite(parent, SWT.BORDER);
 base.setLayout(grid);
 Label label = new Label(base, SWT.NONE);
 label.setText("Font Size: ");
 text = new org.eclipse.swt.widgets.Text(base, SWT.BORDER);
 text.addModifyListener(new TextModifyListener(this));
}
    

如果想对窗口部件的变化进行监视,我们可以给它们附加侦听器。这里我们将向文本窗口部件附加一个 TextModifyListener ,以便我们可以在其值被用户编辑时对所做的更改进行监视。 TextModifyListener 会对文本窗口部件的更改进行监视。

package myfirstvisualizer;
import org.eclipse.swt.events.*;
import org.eclipse.swt.widgets.*;
public class TextModifyListener implements ModifyListener {
 private LargeTagVisualizer visualizer;
 public TextModifyListener(LargeTagVisualizer visualizer) {
  this.visualizer = visualizer;
 }
 public void modifyText(ModifyEvent e) {
  Object source = e.getSource();
  if (source instanceof Text) {
   Text text = (Text) source;
   String value = text.getText();
   visualizer.setAttribute(value);
  }
 }
}
    

modifyText() 被调用时,文本值便被检索并通过使用 setAttribute() 被设置成节点。这是 LargeTagVisualizer 的公用方法,它将更新 <large> 标记节点的属性值。

public void setAttribute(String value) {
 if (node instanceof Element) {
  Element element = (Element) node;
  element.setAttribute(SIZE_ATTR, value);
  fontSize = value;
  context.refresh();
 }
}
    

最后一个要覆盖的方法是 updateCustomAttributeView() ,当属性值更改时(如用户用源代码编辑器编辑属性时),这个方法会被调用。Node 将被作为一个参数传递。可以使用这个节点查找属性中的更改并将它们反映到视图中:

public void updateCustomAttributeView(Node node) {
 this.node = node;
 if (node instanceof Element) {
  Element element = (Element) node;
  Attr attr = element.getAttributeNode(SIZE_ATTR);
  if (attr != null)
   text.setText(attr.getValue());
 }
}
    

下面是最终的 LargeTagVisualizer (新的、修改过的部分是粗体)。

package myfirstvisualizer;
        import org.eclipse.swt.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import org.w3c.dom.*;
import com.ibm.etools.webedit.vct.*;
import com.ibm.etools.webedit.vct.sample.*;
public class LargeTagVisualizer extends CustomTagVisualizer {
 
        private String fontSize = "+4";
 private org.eclipse.swt.widgets.Text text;
 private Node node;
 private Context context;
 public boolean isReadOnlyVisual() {
  return false;
 }
 public VisualizerReturnCode doEnd(Context context) {
  
        this.context = context;
  // get body content
  Node self = context.getSelf();
  NodeList body = self.getChildNodes();
  // create <samp><FONT></samp> element
  Document doc = context.getDocument();
  Element font = doc.createElement("FONT");
  font.setAttribute("SIZE", fontSize);
  // Attach body content to <samp><FONT></samp> element and return
  appendChildren(font, body);
  context.putVisual(font);
  return VisualizerReturnCode.OK;
 }
 
        public boolean useCustomAttributeView() {
  return true;
 }
 public void createCustomAttributeView(Composite parent) {
  parent.setLayout(new FillLayout());
  GridLayout grid = new GridLayout();
  grid.numColumns = 2;
  Composite base = new Composite(parent, SWT.BORDER);
  base.setLayout(grid);
  Label label = new Label(base, SWT.NONE);
  label.setText("Font Size: ");
  text = new org.eclipse.swt.widgets.Text(base, SWT.BORDER);
  text.addModifyListener(new TextModifyListener(this));
 }
 public void updateCustomAttributeView(Node node) {
  this.node = node;
  if (node instanceof Element) {
   Element element = (Element) node;
   Attr attr = element.getAttributeNode("size");
   if (attr != null)
    text.setText(attr.getValue());
  }
 }
 public void setAttribute(String value) {
  if (node instanceof Element) {
   Element element = (Element) node;
   element.setAttribute("size", value);
   fontSize = value;
   context.refresh();
  }
 }
 private void appendChildren(Element parent, NodeList children) {
  for (int i = 0; i <samp><</samp> children.getLength(); i++)
   parent.appendChild((Node) children.item(i));
 }
}
    
      

当我们启动运行时工作台时,我们会获得如下所示的结果。 <large> 标记的属性视图位于左下角。

显示 <large> 标记属性视图的运行时工作台。





回页首


结束语

本文描述了如何使用 WebSphere Studio Page Designer V5 开发可视化器,可视化器是一些 Java 程序,它们会显示 JSP 定制标记以便这些标记看上去与在浏览器中一样。





回页首


附录:API 参考

Context 类

描述

Context 类的实例会作为 doStart() 方法和 doEnd() 方法的参数被传送。这个类由一些从 Page Designer 检索信息并将信息返回到 Page Designer 的方法组成。

package com.ibm.etools.webedit.vct;
public class Context {
 public Document getDocument();
 public Node getSelf();
 public String getSelfString();
 public CustomTagVisualizer getParentVisualizer();
 public void putVisual(Node visual);
 public void putVisual(String visual);
 public String getRealPath(String fileName);
 public Node include(String uri);
 public void setAttribute(String name, Object object);
 public Object getAttribute(String name);
}
    

方法


public Document getDocument();
该方法返回一个 Document 对象。可以使用这个对象来创建与 DOM 相关的对象,如 Element 对象。
public Node getSelf();
该方法返回一个 Node 对象。这个对象是 VCT 的节点表示。
public String getSelfString();
该方法返回一个 String 对象。这个对象是 VCT 的字符串表示。
public String getSelfString();
该方法返回一个 String。这个对象是 VCT 的字符串表示。
public CustomTagVisualizer getParentVisualizer();
该方法返回这个 VCT 父代的 CustomTagVisualizer 对象。父代即是这个 VCT 最近的 VCT 祖先。
public void putVisual(Node visual);
该方法用来返回这个 VCT 的可视化表示。视觉被表示为一个节点对象。这个视觉用来在设计时间视图中显示 VCT。
public void putVisual(List visuals);
该方法用来返回这个 VCT 的可视化表示。这个视觉被表示为一个 List 对象。这个方法用在将要返回 DOM NodeList 时。列表的元素是 DOM 节点。
public void putVisual(String visual);
该方法用来返回这个 VCT 的可视化表示。这个视觉被表示为 String。在 doStart() 和 doEnd() 中返回的视觉被并置并用于在设计时间视图中显示 VCT。
public String getMyPath();
该方法返回一个 String 对象。这个字符串是这个文件的绝对路径。这个文件包含定制标记。如果没有保存文件,那么将会返回一个空字符串,即 ""。
public String getRealPath(String fileName);
该方法返回一个 String 对象。这个字符串并置了 Web 应用程序的绝对路径和文件名。
public Node include(String uri);
该方法返回一个表示 uri 指定的 HTML/JSP 文件的 Node 对象。返回的 Node 对象是 <BODY> 标记的子节点。uri 指定的文件中包含的 VCT 会被处理。
public void setAttribute(String name, Object object);
该方法用来存储一个具有名称的对象。如果一个对象所具有的名称已在上下文中存在,那么它将会被这个新的对象覆盖。可以使用 getAttribute() 对已存储的对象进行检索。可以使用这些方法在标记间传递值。
public Object getAttribute(String name);
该方法用于使用名称检索对象。如果没有找到对象,便会返回空(null)。可以使用 setAttribute() 将对象存储在上下文中。

VisualizerReturnCode 类

描述

返回码用来表示上下文中的视觉是否将被用作处理。这些返回码是由 doStart() 方法和 doEnd() 方法返回的。

package com.ibm.etools.webedit.vct;
public class VisualizerReturnCode {
 public final VisualizerReturnCode ERROR;
 public final VisualizerReturnCode OK;
 public final VisualizerReturnCode IGNORE;
}
    


public final VisualizerReturnCode ERROR;
在 doStart() 方法和 doEnd() 方法中有错误发生时返回这些代码。
public final VisualizerReturnCode OK;
当上下文中的视觉将被处理时返回这些代码。
public final VisualizerReturnCode IGNORE;
当上下文中的视觉将被忽略时返回这些代码。

CustomTagVisualizer 类

描述

通过继承 CustomTagVisualizer 类可以编写定制标记可视化器。当在 JSP 文件中首先遇到 VCT 时, doStart() 方法会被调用。当 VCT 的子节点完成处理时, doEnd() 方法会被调用。如果子节点也是 VCT,那么则调用它的 doStart() 方法和 doEnd() 方法。

package com.ibm.etools.webedit.vct;
public class CustomTagVisualizer {
 public VisualizerReturnCode doStart(Context context);
 public VisualizerReturnCode doEnd(Context context);
 public boolean isReadOnlyVisual();
 public boolean useCustomAttributeView();
 public void createCustomAttributeView(Composite parent);
 public void updateCustomAttributeView();
}
    

方法


public VisualizerReturnCode doStart(Context context);
当要在执行这个节点的子节点之前执行处理时,需要覆盖这个方法。如果没有覆盖这个方法,那么缺省的 doStart() 方法将会被调用。缺省的 doStart() 方法只返回 VisualizerReturnCode.IGNORE。
public VisualizerReturnCode doEnd(Context context);
当想在执行这个节点的子节点之后执行处理时,需要覆盖这个方法。如果没有覆盖这个方法,那么缺省的 doEnd() 方法将会被调用。缺省的 doEnd() 方法只返回 VisualizerReturnCode.IGNORE。
public boolean isReadOnlyVisual();
该方法在 doStart() 方法前曾被调用过。当您想生成可编辑的可视化器时,需要覆盖这个方法。如果没有覆盖这个方法,那么缺省的 isReadOnlyVisual() 方法将会被调用。缺省的 isReadOnlyVisual() 方法只返回 true。
public boolean useCustomAttributeView();
该方法在 doStart() 方法前曾被调用过。当想创建属性视图时,需要覆盖这个方法。如果没有覆盖这个方法,那么缺省的 useCustomAttributeView() 方法将会被调用。缺省的 useCustomAttributeView() 方法只返回 false。
public boolean createCustomAttributeView();
如果 useCustomAttributeView() 的返回值为 true,那么这个方法将被调用。覆盖这个方法以创建属性视图。如果这个方法没有被覆盖,那么缺省的 createCustomAttributeView() 方法将会被调用。缺省的 createCustomAttributeView() 方法只会创建一个空的属性视图。
public boolean updateCustomAttributeView();
如果 useCustomAttributeView() 的返回值为 true,那么这个方法会被调用。需要覆盖这个方法以更新属性视图。如果没有覆盖这个方法,那么缺省的 updateCustomAttributeView() 方法将会被调用。缺省的 updateCustomAttributeView() 方法不会更新属性视图。使用 Context#getSelf() 或 Context#getSelfString(),检查节点的属性,并反映属性视图的任何更改。

免责声明:本文中描述的应用程序编程接口(Application Programming Interfaces,API)在 WebSphere Studio V5 Page Designer HTML/JSP 编辑器中受到支持。IBM 保留对这些 API 进行添加、修改、修订和/或删除的权利。IBM 并不承诺支持这些 API 并保留撤销对这些 API 的支持的权利。使用这些 API 编写的代码可能需要做大量的修改以适应 Page Designer 未来的版本和/或 API 未来的版本。



关于作者

Kaoru Hosokawa是 WebSphere Studio Page Designer 和 Web Site Designer 的技术领导人。在此之前,他从事一种称为 Perfect Photo 的客户图形产品的工作。他的主要专业领域是面向对象编程(object-oriented programming)。您可以通过 hosokawa@jp.ibm.com与他联系。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?




回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款