Java 语言指南

重要提示:本文档是在 2012 年之前撰写的。本文档中所述的身份验证选项(OAuth 1.0、AuthSub 和 CMEK)自 2012 年 4 月 20 日起已被正式弃用,不再提供。我们建议您尽快迁移到 OAuth 2.0

通过 Google 协作平台数据 API,客户端应用可以在 Google 协作平台内访问、发布和修改内容。 您的客户端应用还可以请求近期活动列表、提取修订历史记录以及下载附件。

除了介绍一些有关协作平台数据 API 功能的背景信息外,本指南还提供了使用 Java 客户端库与该 API 进行交互的示例。如果在设置客户端库方面需要帮助,请参阅 Google 数据 Java 客户端库使用入门。如果您有兴趣详细了解 Java 客户端库在与传统版 协作平台 API 交互时使用的底层协议,请参阅协议指南

受众群体

本文档适用于想要使用 Google 数据 Java 客户端库编写与 Google 协作平台交互的客户端应用的开发者。

开始使用

Google 协作平台使用 Google 帐号或 G Suite 帐号进行身份验证。如果您已经有帐号,就大功告成了。 如果不是,您可以创建一个新帐号

安装库

如需有关设置和安装客户端库的帮助,请参阅 Google 数据 Java 客户端库使用入门。如果您使用的是 Eclipse,这篇文章还介绍了如何使用 Google Data API Eclipse 插件设置项目。在开始之前,您需要做好以下准备:

  1. 安装 Java 1.5 或更高版本
  2. 下载客户端库(最新版本的 gdata-src.java.zip
  3. 下载依赖项列表
  4. 下载示例应用(最新版 gdata-samples.java.zip

安装 .jar 文件后,您需要在项目中包含以下内容:

  1. java/lib/gdata-sites-2.0.jar - 此处的 2.0 版适用于传统版 协作平台 API 的 1.4 版。
  2. java/lib/gdata-core-1.0.jar
  3. java/lib/gdata-client-1.0.jar
  4. java/lib/gdata-spreadsheet-3.0.jar(如果使用列表页面 / 列表项)

此外,请务必添加依赖项 jar(gdata-media-1.0.jarmail.jargoogle-collect....jar)。

运行示例应用

一个完整的示例应用位于 gdata-samples.java.zip 下载内容的 /java/sample/sites 子目录中。您也可以在 SVN 代码库(可通过“源代码”标签页访问)的 /trunk/java/sample/sites/ 中找到源代码。借助 SitesDemo.java,用户可以执行多种操作,了解如何使用传统版 协作平台 API。

请注意,您需要添加 java/sample/util/lib/sample-util.jar 才能运行示例。

启动您自己的项目

提示:请参阅将 Eclipse 与 Google Data API 配合使用一文,了解如何快速使用我们的 Eclipse 插件。

根据您的应用的需求,您将需要导入多次。我们建议您先执行以下导入:

import com.google.gdata.client.*;
import com.google.gdata.client.sites.*;
import com.google.gdata.data.*;
import com.google.gdata.data.acl.*;
import com.google.gdata.data.media.*;
import com.google.gdata.data.sites.*;
import com.google.gdata.data.spreadsheet.*;  // If working with listpages / listitems
import com.google.gdata.util.*;

接下来,您还需要设置 SitesService 对象,用来表示与传统版 协作平台 API 的客户端连接:

SitesService client = new SitesService("yourCo-yourAppName-v1");

applicationName 参数应遵循 company-applicationname-version 格式。此参数用于日志记录。

注意:本指南的其余部分假定您在变量 client 中创建了 SitesService

使用传统版协作平台 API 进行身份验证

Java 客户端库可用于处理公共 Feed 或私有 Feed。协作平台 Data API 支持访问不公开 Feed 和公开 Feed,具体取决于协作平台的权限以及您尝试执行的操作。例如,您可能可以读取公开网站的内容 Feed,但不能更新它,而这需要一个经过身份验证的客户端。这可以通过 ClientLogin 用户名/密码身份验证、AuthSubOAuth 完成。

请参阅 Google 数据 API 身份验证概览,了解有关 AuthSub、OAuth 和 CMEK 的详细信息。

提示:该 API 支持 SSL (HTTPS)。如果您使用的是 AuthSub/OAuth,请务必指定 https://sites.google.com/feeds/ 范围,以便通过 SSL 请求 Feed。另请注意,对于 G Suite 网域,API 遵循管理控制台中的“需要 SSL”设置。您可以通过调用 client.useSsl(); 强制所有 API 请求通过 HTTPS。

用于网络应用程序的 AuthSub

如果客户端应用需要向 Google 帐号验证其用户身份,则应使用适用于 Web 应用的 AuthSub 身份验证。运营商不需要访问 Google 协作平台用户的用户名和密码,只需 AuthSub 令牌即可。

查看关于将 AuthSub 整合到您的 Web 应用的说明

请求一次性令牌

用户首次访问您的应用时,需要进行身份验证。通常,开发者会输出一些文本和一个链接,用于将用户引导至 AuthSub 批准页面,以对用户进行身份验证并请求访问其文档。Google 数据 Java 客户端库提供了用于生成此网址的函数。以下代码设置了指向 AuthSubRequest 页面的链接。

import com.google.gdata.client.*;

String nextUrl = "http://www.example.com/welcome.jsp";
String scope = "https://sites.google.com/feeds/";
boolean secure = true;
boolean session = true;
String authSubUrl = AuthSubUtil.getRequestUrl(nextUrl, scope, secure, session);

如果您想对 G Suite 托管网域中的用户进行身份验证,请按以下步骤操作:

import com.google.gdata.client.*;

String hostedDomain = "example.com";
String nextUrl = "http://www.example.com/welcome.jsp";
String scope = "https://sites.google.com/feeds/";  // SSL is also supported
boolean secure = true;
boolean session = true;
String authSubUrl = AuthSubUtil.getRequestUrl(hostedDomain, nextUrl, scope, secure, session);

getRequestUrl() 方法接受几个参数(对应于 AuthSubRequest 处理程序使用的查询参数):

  • next 网址 - 用户登录帐号并授予访问权限后 Google 将重定向到的网址;上例中的 http://www.example.com/welcome.jsp
  • 作用域 - 上述示例中的 https://sites.google.com/feeds/
  • 一个布尔值,表示是否要在注册模式下使用令牌;上述示例中的 false
  • 第二个布尔值,用于指明稍后是否将令牌交换为会话令牌;上述示例中的 true

升级为会话令牌

请参阅将 AuthSub 与 Google Data API 客户端库搭配使用

检索有关会话令牌的信息

请参阅将 AuthSub 与 Google Data API 客户端库搭配使用

撤消会话令牌

请参阅将 AuthSub 与 Google Data API 客户端库搭配使用

适用于 Web 应用或已安装/移动应用的 OAuth

OAuth 可用作 AuthSub 的替代方案,适用于 Web 应用。OAuth 类似于使用 AuthSub 安全和注册模式,因为所有数据请求都必须进行数字签名,并且您必须注册自己的网域。

查看关于将 OAuth 加入到已安装的应用的说明

已安装/移动应用的 CMEK

需要向 Google 帐号验证用户身份的已安装应用或移动应用应使用 ClientLogin。首次运行时,您的应用会提示用户输入其用户名/密码。在后续请求中,系统会引用身份验证令牌。

查看有关将 CMEK 合并到已安装的应用的说明

如需使用 ClientLogin,请调用 SitesService 对象的 setUserCredentials() 方法,该方法继承自 GoogleService。指定您的客户端代表其发出请求的用户的电子邮件地址和密码。例如:

SitesService client = new SitesService("yourCo-yourAppName-v1");
client.setUserCredentials("example@gmail.com", "pa$$word");

提示:您的应用在首次成功对用户进行身份验证后,请将身份验证令牌存储在数据库中,以便日后重新调用。您无需在每次运行应用时都提示用户输入密码。如需了解详情,请参阅撤回身份验证令牌

如需详细了解如何在 Java 应用中使用 CMEK,请参阅将 CMEK 与 Google Data API 客户端库配合使用

返回页首

网站 Feed

网站 Feed 可用于列出用户拥有或有权查看的 Google 网站。 它还可用于修改现有网站的名称。对于 G Suite 网域,它还可用于创建和/或复制整个网站。

列出网站

要查询网站 Feed,请向网站 Feed 网址发送 HTTP GET

https://sites.google.com/feeds/site/site/

在 Java 客户端中,您可以使用 SiteFeedSiteEntry 类来处理网站 Feed:

public String getSiteFeedUrl() {
  String domain = "site";  // OR if the Site is hosted on G Suite, your domain (e.g. example.com)
  return "https://sites.google.com/feeds/site/" + domain + "/";
}

public void getSiteFeed() throws IOException, ServiceException {
  SiteFeed siteFeed = client.getFeed(new URL(getSiteFeedUrl()), SiteFeed.class);
  for (SiteEntry entry : siteFeed.getEntries()){
    System.out.println("title: " + entry.getTitle().getPlainText());
    System.out.println("site name: " + entry.getSiteName().getValue());
    System.out.println("theme: " + entry.getTheme().getValue());
    System.out.println("");
  }
}

以上代码段会输出网站标题、网站名称和网站主题。其他 getter 可用于访问 Feed 中的其他属性。

创建新网站

注意:此功能仅适用于 G Suite 网域。

您可以通过创建新的 SiteEntry 并在网站 Feed 上调用客户端的 insert() 方法来配置新网站。

下面的示例创建了一个主题为“可选广告”(可选设置)的全新网站,并提供了网站名称(必填)和说明(选填):

public String getSiteFeedUrl() {
  String domain = "example.com";
  return "https://sites.google.com/feeds/site/" + domain + "/";
}

public SiteEntry createSite(String title, String summary, String theme, String tag)
    throws MalformedURLException, IOException, ServiceException {
  SiteEntry entry = new SiteEntry();
  entry.setTitle(new PlainTextConstruct(title));
  entry.setSummary(new PlainTextConstruct(summary));

  Theme tt = new Theme();
  tt.setValue(theme);
  entry.setTheme(tt);

  entry.getCategories().add(new Category(TagCategory.Scheme.TAG, tag, null));

  return client.insert(new URL(getSiteFeedUrl()), entry);
}

SiteEntry newSiteEntry = createSite("My Site Title", "summary for site", "slate", "tag");

上述请求会在 G Suite 网域 example.com 下创建一个新网站。因此,该网站的网址将是 https://sites.google.com/a/example.com/my-site-title。

如果网站成功创建,服务器将使用 SiteEntry 对象进行响应,并在其中填充服务器添加的元素:指向网站的链接、指向网站的 acl Feed 的链接、网站名称、标题、摘要等等。

复制网站

注意:此功能仅适用于 G Suite 网域。

复制网站与创建新网站类似。不同之处在于,您需要在新的 SiteEntry 上设置链接,其中包含要复制的网站的自链接。以下示例展示了如何复制在创建新网站部分创建的网站:

public SiteEntry copySite(String title, String summary, String sourceHref)
    throws MalformedURLException, IOException, ServiceException {
  SiteEntry entry = new SiteEntry();
  entry.setTitle(new PlainTextConstruct(title));
  entry.setSummary(new PlainTextConstruct(summary));
  entry.addLink(SitesLink.Rel.SOURCE, Link.Type.ATOM, sourceHref);

  return client.insert(new URL(getSiteFeedUrl()), entry);
}

String sourceHref = newSiteEntry.getLink(SitesLink.Rel.SOURCE, Link.Type.ATOM).getHref();
SiteEntry myTwin = copySite("Duplicate Site", "A copy", sourceHref);

要点:

  • 只能复制经过身份验证的用户拥有的网站和网站模板。
  • 也可以复制网站模板。如果在 Google 协作平台设置页面中选中了“将此网站发布为模板”设置,则相应网站就是模板。
  • 您可以从其他网域复制网站,但系统会将您列为源网站的所有者。

更新网站的元数据

若要重命名网站,更改其主题背景、类别标记或摘要,您需要先获取包含相关网站的 SiteEntry,修改一个或多个属性,然后调用 SiteEntryupdate() 方法。下例修改了上一个网站的主题,并重命名了网站:

myTwin.setTitle(new PlainTextConstruct("better-title"));

Theme theme = myTwin.getTheme();
theme.setValue('iceberg');
myTwin.setTheme(theme);

myTwin.getCategories().add(new Category(TagCategory.Scheme.TAG, "newTag", null));

SiteEntry updatedSiteEntry = myTwin.update();

System.out.println(updatedSiteEntry.getTitle().getPlainText();

网址映射

借助网址映射,Google 协作平台用户可以将自己的网域映射到 Google 协作平台。例如,您可以使用 http://www.mydomainsite.com 代替 http://sites.google.com/a/domain.com/mysite。根据网站的托管位置,您可以手动修改网站的网址映射。如需了解详情,请参阅我们的帮助中心文章。

提取网站的网址映射

若要返回某个网站的网址映射,请使用 with-mappings=true 参数提取网站条目/Feed:

SiteQuery query = new SiteQuery(new URL("https://sites.google.com/feeds/site/siteName"));
query.setWithMappings(true);

SiteFeed feed = service.getFeed(query, SiteFeed.class);
for (SiteEntry entry : feed.getEntries()) {
  System.out.println("Mappings for '" + entry.getSiteName().getValue() + "':");
  for (Link link : entry.getWebAddressMappingLinks()) {
    System.out.println("  " + link.getHref());
  }
}

现有映射将显示为带有 rel='webAddressMapping' 的 link。例如,上面的示例中有三个指向网站 http://sites.google.com/site/myOtherTestSitewebAddressMapping

修改网址映射

注意:在使用网址映射时,所有 GET/POST/PUT 操作都应指定 with-mappings=true 参数。如果该参数不存在,则网站条目 (GET) 中不会返回 webAddressMapping,在更新/移除条目中的 PUT 映射时,系统不会考虑 webAddressMapping

如需添加、更新或删除映射,只需在创建新网站更新网站的元数据时指定、更改或移除此类链接即可。网站 Feed URI 中必须包含 with-mappings=true 参数。注意:要更新地址映射,您必须是网站管理员;如果网站是由 G Suite 托管的,则您必须是网域管理员。

例如,以下请求会将 http://www.mysitemapping.com 映射更新为 http://www.my-new-sitemapping.com,并通过在条目中保留链接来移除 http://www.mysitemapping2.com

SiteEntry entry = client.getEntry(new URL("https://sites.google.com/feeds/site/site/siteName?with-mappings=true"), SiteEntry.class);

// Modify mappings (remove all mappings, add some of them again, add modified mappings)
entry.removeLinks(SitesLink.Rel.WEBADDRESSMAPPING, Link.Type.HTML);
entry.addLink(SitesLink.Rel.WEBADDRESSMAPPING, Link.Type.HTML, "http://www.my-new-sitemapping.com");

// Update the entry with the mappings.
entry.update();

请注意,也可以在创建/复制网站时指定网址映射。

返回页首

活动 Feed

您可以通过提取活动 Feed 来获取网站的近期活动(更改)。活动 Feed 中的每个条目都包含对网站所做更改的相关信息。

如需查询活动供稿,请向活动供稿网址发送 HTTP GET

https://sites.google.com/feeds/activity/site/siteName

在 Java 客户端中,使用 ActivityFeed 类返回 ActivityEntry 对象:

public String buildActivityFeedUrl() {
  String domain = "site";  // OR if the Site is hosted on G Suite, your domain (e.g. example.com)
  String siteName = "mySite";
  return "https://sites.google.com/feeds/activity/" + domain + "/" + siteName + "/";
}

public void getActivityFeed() throws IOException, ServiceException {
  ActivityFeed activityFeed = client.getFeed(new URL(buildActivityFeedUrl()), ActivityFeed.class);
  for (BaseActivityEntry<?> entry : activityFeed.getEntries()){
    System.out.println(entry.getSummary().getPlainText());
    System.out.println(" revisions link: " + entry.getRevisionLink().getHref());
  }
}

注意:只有网站的协作者或所有者才能访问此 Feed。 您的客户端必须使用 AuthSub、OAuth 或 CMEK 令牌进行身份验证。请参阅在 Google 协作平台服务中进行身份验证

返回页首

修订版本 Feed

要获取任何内容条目的修订历史记录,请向该条目的修订链接发送 HTTP GET

https://sites.google.com/feeds/revision/site/siteName/CONTENT_ENTRY_ID

该示例会查询内容供稿,然后提取第一个内容条目的修订供稿:

ContentFeed contentFeed = client.getFeed(new URL(buildContentFeedUrl()), ContentFeed.class);
URL revisionFeedUrl = new URL(contentFeed.getEntries().get(0).getRevisionLink().getHref()); // use first entry

public void getRevisionFeed(String revisionFeedUrl) throws IOException, ServiceException {
  RevisionFeed revisionFeed = client.getFeed(revisionFeedUrl, RevisionFeed.class);
  for (BaseContentEntry<?> entry : revisionFeed.getEntries()){
    System.out.println(entry.getTitle().getPlainText());
    System.out.println(" updated: " + entry.getUpdated().toUiString() + " by " +
        entry.getAuthors().get(0).getEmail());
    System.out.println(" revision #: " + entry.getRevision().getValue());
  }
}

注意:您必须是网站的协作者或所有者,才能访问此 Feed。 您的客户端必须使用 AuthSub、OAuth 或 CMEK 令牌进行身份验证。请参阅在 Google 协作平台服务中进行身份验证

返回页首

内容 Feed

检索内容 Feed

内容 Feed 会列出网站的最新内容。可以通过向内容 Feed 网址发送 HTTP GET 来获取该网址:

https://sites.google.com/feeds/content/site/siteName
Feed 参数说明
sitesite”或您的 G Suite 托管网域的域名(例如 example.com)。
siteName您网站的网络空间名称;可在网站的网址中找到(例如 mySite)。

提取内容 Feed 的示例:

public String buildContentFeedUrl() {
  String domain = "site";  // OR if the Site is hosted on G Suite, your domain (e.g. example.com)
  String siteName = "mySite";
  return "https://sites.google.com/feeds/content/" + domain + "/" + siteName + "/";
}

ContentFeed contentFeed = client.getFeed(new URL(buildContentFeedUrl()), ContentFeed.class);

生成的 contentFeed 是一个 ContentFeed 对象,其中包含来自服务器的响应。contentFeed 的每个条目都表示用户网站中的不同网页或项目。ContentFeed 将包含不同类型的对象,这些对象全部继承自 BaseContentEntryListItemEntryListPageEntryAttachmentEntryWebAttachmentEntryFileCabinetPageEntryAnnouncementsPageEntryAnnouncementEntryWebPageEntryCommentEntry

以下示例展示了如何列出 ContentFeed 中不同类型的条目。每种类型的条目都包含不同的属性,但此处并未全部输出。

public String getContentBlob(BaseContentEntry<?> entry) {
 return ((XhtmlTextConstruct) entry.getTextContent().getContent()).getXhtml().getBlob();
}

// Extracts an entry's numeric ID.
private String getEntryId(String selfLink) {
  return selfLink.substring(selfLink.lastIndexOf("/") + 1);
}

public void printContentEntries(ContentFeed contentFeed) {
  System.out.println("Listing all WebPageEntry:");
  for (WebPageEntry entry : contentFeed.getEntries(WebPageEntry.class)) {
    System.out.println(" title: " + entry.getTitle().getPlainText());
    System.out.println(" id: " + getEntryId(entry));
    if (entry.getParentLink() != null) {
      System.out.println(" parent id: " + getEntryId(entry.getParentLink().getHref()));
    }
    System.out.println(" author: " + entry.getAuthors().get(0).getEmail());
    System.out.println(" content: " + getContentBlob(entry));
  }

  System.out.println("Listing all ListPageEntry:");
  for (ListPageEntry entry : contentFeed.getEntries(ListPageEntry.class)) {
    System.out.println(" title: " + entry.getTitle().getPlainText());
    System.out.println(" id: " + getEntryId(entry));
    for (Column col : entry.getData().getColumns()) {
      System.out.print(" [" + col.getIndex() + "] " + col.getName() + "\t");
    }
  }

  for (ListItemEntry entry : contentFeed.getEntries(ListItemEntry.class)) {
    for (Field field : entry.getFields()) {
      System.out.print(" [" + field.getIndex() + "] " + field.getValue() + "\t");
    }
    System.out.println("\n");
  }

  System.out.println("Listing all FileCabinetPageEntry:");
  for (FileCabinetPageEntry entry : contentFeed.getEntries(FileCabinetPageEntry.class)) {
    System.out.println(" title: " + entry.getTitle().getPlainText());
    System.out.println(" id: " + getEntryId(entry));
    System.out.println(" content: " + getContentBlob(entry));
  }

  System.out.println("Listing all CommentEntry:");
  for (CommentEntry entry : contentFeed.getEntries(CommentEntry.class)) {
    System.out.println(" in-reply-to: " + entry.getInReplyTo().toString());
    System.out.println(" content: " + getContentBlob(entry));
  }

  System.out.println("Listing all AnnouncementsPageEntry:");
  for (AnnouncementsPageEntry entry : contentFeed.getEntries(AnnouncementsPageEntry.class)) {
    System.out.println(" title: " + entry.getTitle().getPlainText());
    System.out.println(" id: " + getEntryId(entry));
    System.out.println(" content: " + getContentBlob(entry));
  }

  System.out.println("Listing all AnnouncementEntry:");
  for (AnnouncementEntry entry : contentFeed.getEntries(AnnouncementEntry.class)) {
    System.out.println(" title: " + entry.getTitle().getPlainText());
    System.out.println(" id: " + getEntryId(entry));
    if (entry.getParentLink() != null) {
      System.out.println(" parent id: " + getEntryId(entry.getParentLink().getHref()));
    }
    System.out.println(" draft?: " + entry.isDraft());
    System.out.println(" content: " + getContentBlob(entry));
  }

  System.out.println("Listing all AttachmentEntry:");
  for (AttachmentEntry entry : contentFeed.getEntries(AttachmentEntry.class)) {
    System.out.println(" title: " + entry.getTitle().getPlainText());
    System.out.println(" id: " + getEntryId(entry));
    if (entry.getParentLink() != null) {
      System.out.println(" parent id: " + getEntryId(entry.getParentLink().getHref()));
    }
    if (entry.getSummary() != null) {
      System.out.println(" description: " + entry.getSummary().getPlainText());
    }
    System.out.println(" revision: " + entry.getRevision().getValue());
    MediaContent content = (MediaContent) entry.getContent();
    System.out.println(" src: " + content.getUri());
    System.out.println(" content type: " + content.getMimeType().getMediaType());
  }

  System.out.println("Listing all WebAttachmentEntry:");
  for (WebAttachmentEntry entry : contentFeed.getEntries(WebAttachmentEntry.class)) {
    System.out.println(" title: " + entry.getTitle().getPlainText());
    System.out.println(" id: " + getEntryId(entry));
    if (entry.getParentLink() != null) {
      System.out.println(" parent id: " + getEntryId(entry.getParentLink().getHref()));
    }
    if (entry.getSummary() != null) {
      System.out.println(" description: " + entry.getSummary().getPlainText());
    }
    System.out.println(" src: " + ((MediaContent) entry.getContent()).getUri());
  }
}

注意:此 Feed 可能需要进行身份验证,也可能不需要身份验证,具体取决于网站的共享权限。 如果网站是非公开的,您的客户端必须使用 AuthSub、OAuth 或 CMEK 令牌进行身份验证。请参阅向协作平台服务进行身份验证

内容 Feed 查询示例

您可以使用一些标准 Google Data API 查询参数以及传统版 协作平台 API 专用的查询参数来搜索内容 Feed。如需了解详情以及受支持参数的完整列表,请参阅参考指南

注意:本部分中的示例使用了检索内容 Feed 中的 buildContentFeedUrl() 方法。

检索特定条目种类

如需仅提取特定类型的条目,请使用 kind 参数。此示例仅返回 attachment 条目:

ContentQuery query = new ContentQuery(new URL(buildContentFeedUrl()));
query.setKind("webpage");
ContentFeed contentFeed = client.getFeed(query, ContentFeed.class);
for (AttachmentEntry entry : contentFeed.getEntries(AttachmentEntry.class)) {
  System.out.println(entry.getTitle().getPlainText());
}

如需返回多个条目类型,请使用“,”分隔每个 kind。以下示例返回 filecabinetlistpage 条目:

URL url = new URL(buildContentFeedUrl() + "?kind=filecabinet,listpage");
ContentFeed contentFeed = client.getFeed(url, ContentFeed.class);
for (FileCabinetPageEntry entry : contentFeed.getEntries(FileCabinetPageEntry.class)) {
  System.out.println(" title: " + entry.getTitle().getPlainText());
}
for (ListPageEntry entry : contentFeed.getEntries(ListPageEntry.class)) {
  System.out.println(" title: " + entry.getTitle().getPlainText());
}

按路径检索页面

如果您知道 Google 协作平台中某个网页的相对路径,可以使用 path 参数抓取该特定网页。 以下示例将返回位于 http://sites.google.com/site/siteName/path/to/the/page 的网页:

ContentQuery query = new ContentQuery(new URL(buildContentFeedUrl()));
query.setPath("/path/to/the/page");
ContentFeed contentFeed = client.getFeed(query, ContentFeed.class);
for (BaseContentEntry<?> entry : contentFeed.getEntries()) {
  System.out.println(" title: " + entry.getTitle().getPlainText());
}

检索父页面下的所有条目

如果您知道网页的内容条目 ID(例如下例中的“1234567890”),则可以使用 parent 参数获取该页面的所有子条目(如果有):

ContentQuery query = new ContentQuery(new URL(buildContentFeedUrl()));
query.setParent("1234567890");
ContentFeed contentFeed = client.getFeed(query, ContentFeed.class);

如需了解其他参数,请参阅参考指南

返回页首



创建内容

注意:在为网站创建内容之前,请确保您已在客户端中设置您的网站。
client.site = "siteName";

通过向内容 Feed 发送 HTTP POST,可以创建新内容(网页、列表页、文件箱式页面、公告页等):

https://sites.google.com/feeds/content/site/siteName

如需查看支持节点类型的列表,请参阅参考指南中的 kind 参数。

创建新内容 / 页面

下例在网站的顶级位置下创建一个新的 webpage,为网页正文添加一些 XHTML,并将标题标题设置为“New WebPage Title”:

private void setContentBlob(BaseContentEntry<?> entry, String pageContent) {
  XmlBlob xml = new XmlBlob();
  xml.setBlob(pageContent);
  entry.setContent(new XhtmlTextConstruct(xml));
}

public WebPageEntry createWebPage(String title, String content)
    throws MalformedURLException, IOException, ServiceException {
  WebPageEntry entry = new WebPageEntry();
  entry.setTitle(new PlainTextConstruct(title));

  setContentBlob(entry, content); // Entry's HTML content

  return client.insert(new URL(buildContentFeedUrl()), entry);
}

WebPageEntry createdEntry = createWebPage("New Webpage Title", "<b>HTML content</b>");
System.out.println("Created! View at " + createdEntry.getHtmlLink().getHref());

如果请求成功,createdEntry 将包含服务器上创建的条目的副本。

在自定义网址路径下创建项/网页

默认情况下,上一个示例将在网址 http://sites.google.com/site/siteName/new-webpage-title 下创建,页面标题为“New Webpage Title”。也就是说,对于网址的 <atom:title> 标准化为 new-webpage-title。若要自定义网页的网址路径,您可以设置 <sites:pageName> 元素。

此示例创建了一个标题为“File Storage”的新 filecabinet 页面,但通过指定 <sites:pageName> 元素在网址 http://sites.google.com/site/siteName/files(而不是 http://sites.google.com/site/siteName/file-storage)下创建了该页面。

public FileCabinetPageEntry createFileCabinetPage(String title, String content, String customPageName)
    throws MalformedURLException, IOException, ServiceException {
  FileCabinetPageEntry entry = new FileCabinetPageEntry();
  entry.setTitle(new PlainTextConstruct(title));

  setContentBlob(entry, content); // Entry's HTML content

  entry.setPageName(new PageName(customPageName)); // Upload to a custom page path

  return client.insert(new URL(buildContentFeedUrl()), entry);
}

FileCabinetPageEntry createdEntry = createFileCabinetPage("File Storage", "<b>HTML content</b>", "files");
System.out.println("Created! View at " + createdEntry.getHtmlLink().getHref());

服务器使用以下优先规则为网页网址路径命名:

  1. <sites:pageName>(如果存在)。必须满足 a-z, A-Z, 0-9, -, _
  2. 如果 pageName 不存在,<atom:title> 不得为 null。标准化是将空格修剪 + 收起为“-”,并移除与 a-z, A-Z, 0-9, -, _ 不匹配的字符。

创建子页面

要在父页面下创建子页面(子页面),您必须在条目中设置父链接。父节点的自链接的 href 属性。

public AnnouncementEntry postAnnouncement(String title, String content, AnnouncementsPageEntry parentPage)
    throws MalformedURLException, IOException, ServiceException {
  AnnouncementEntry entry = new AnnouncementEntry();
  entry.setTitle(new PlainTextConstruct(title));

  setContentBlob(entry, content); // Entry's HTML content

  // Set the entry's parent link to create the announcement under that page.
  entry.addLink(SitesLink.Rel.PARENT, Link.Type.ATOM, parentPage.getSelfLink().getHref());

  return client.insert(new URL(buildContentFeedUrl()), entry);
}

ContentFeed contentFeed = client.getFeed(new URL(buildContentFeedUrl() + "?kind=announcementspage"), ContentFeed.class);

AnnouncementEntry createdEntry = postAnnouncement("Party!!", "My place, this weekend", contentFeed.getEntries().get(0));
System.out.println("New post by " + createdEntry.getAuthors().get(0).getName());

上面的示例会在用户内容 Feed 中的第一个公告页面下创建一个新的 announcement。公告标题设置为“Party!!”,内容设置为“My place, this week”。

页面模板

创建页面模板

创建页面模板的过程与创建新项/页面创建子页面的过程相同。不同之处在于添加 category,并将术语和标签分别设置为“http://schemas.google.com/g/2005#template”和“template”。

本示例将创建一个新的 webpage 模板。

// The template webpage entry.
WebPageEntry entry = new WebPageEntry();

// Set title and content.
entry.setTitle(new PlainTextConstruct("Page template title"));
XmlBlob xml = new XmlBlob();
xml.setBlob("Content for page template");
entry.setContent(new XhtmlTextConstruct(xml));

// Set the template category
Category TEMPLATE_CATEGORY = new Category(TemplateCategory.Scheme.LABELS,
    TemplateCategory.Term.TEMPLATE, TemplateCategory.Label.TEMPLATE);
entry.getCategories().add(TEMPLATE_CATEGORY);

// Insert the template webpage entry.
WebPageEntry createdEntry = client.insert(new URL("https://sites.google.com/feeds/content/site/siteName"), entry);

通过模板创建页面

与创建页面模板类似,您可以通过添加 <link> 并使 rel='http://schemas.google.com/sites/2008#template' 指向页面模板的 self 链接,从而通过模板实例化新页面。

该示例会创建一个新的 filecabinet 模板,然后通过该模板实例化一个新的 filecabinet 页面。

URL feedUrl = new URL("https://sites.google.com/feeds/content/site/siteName");

// 1. Create file cabinet page template
FileCabinetPageEntry inputTemplateEntry = new FileCabinetPageEntry();
inputTemplateEntry.setTitle(new PlainTextConstruct("File cabinet page template title"));
XmlBlob xml = new XmlBlob();
xml.setBlob("Content for page template");
inputTemplateEntry.setContent(new XhtmlTextConstruct(xml));

// Set the template category
Category TEMPLATE_CATEGORY = new Category(TemplateCategory.Scheme.LABELS,
    TemplateCategory.Term.TEMPLATE, TemplateCategory.Label.TEMPLATE);
inputTemplateEntry.getCategories().add(TEMPLATE_CATEGORY);

// 2. Create file cabinet page template instance
FileCabinetPageEntry templateEntry = client.insert(feedUrl, inputTemplateEntry);

// Specify link to the page template
FileCabinetPageEntry templateInstanceEntry = new FileCabinetPageEntry();
templateInstanceEntry.setTitle(new PlainTextConstruct("File cabinet template instance"));
templateInstanceEntry.addLink(new Link(SitesLink.Rel.TEMPLATE, Link.Type.ATOM, templateEntry.getSelfLink().getHref()));

FileCabinetPageEntry createdFileCabinetFromTemplate =  client.insert(feedUrl, templateInstanceEntry);

请注意:尽管有一个模板定义了 <category>,但仍需要在条目中添加一个。另请注意,如果您添加 <content> 元素,服务器将拒绝该元素。

上传文件

与在 Google 协作平台中一样,该 API 支持将附件上传到文件箱式页面或父页面。

要将附件上传到父级文件夹,请向内容 Feed 网址发送 HTTP POST 请求:

https://sites.google.com/feeds/content/site/siteName

所有附件类型都必须上传到父页面。因此,您需要在尝试上传的 AttachmentEntryWebAttachmentEntry 对象上设置父链接。如需了解详情,请参阅创建子页面

正在上传附件

此示例将 PDF 文件上传到用户内容 Feed 中的第一个 FileCabinetPageEntry 中。创建该附件的标题为“使用入门”和(可选)说明“人力资源包”。

MimetypesFileTypeMap mediaTypes = new MimetypesFileTypeMap();
mediaTypes.addMimeTypes("application/msword doc");
mediaTypes.addMimeTypes("application/vnd.ms-excel xls");
mediaTypes.addMimeTypes("application/pdf pdf");
mediaTypes.addMimeTypes("text/richtext rtx");
// ... See a more complete list of mime types in the SitesHelper.java

public AttachmentEntry uploadAttachment(File file, BasePageEntry<?> parentPage,
    String title, String description) throws IOException, ServiceException {
  AttachmentEntry newAttachment = new AttachmentEntry();
  newAttachment.setMediaSource(new MediaFileSource(file, mediaTypes.getContentType(file)));
  newAttachment.setTitle(new PlainTextConstruct(title));
  newAttachment.setSummary(new PlainTextConstruct(description));
  newAttachment.addLink(SitesLink.Rel.PARENT, Link.Type.ATOM, parentPage.getSelfLink().getHref());

  return client.insert(new URL(buildContentFeedUrl()), newAttachment);
}

ContentFeed contentFeed = client.getFeed(new URL(buildContentFeedUrl() + "?kind=filecabinet"), ContentFeed.class);
FileCabinetPageEntry parentPage = contentFeed.getEntries(FileCabinetPageEntry.class).get(0);

AttachmentEntry attachment = uploadAttachment(
    new File("/path/to/your/file.pdf"), parentPage, "Getting Started", "HR packet");
System.out.println("Uploaded!");

如果上传成功,attachment 将包含已创建的附件条目的副本。

将附件上传到文件夹中

如需将附件上传到 FileCabinetPageEntry 中的现有文件夹,请添加一个类别,并将“term”属性设为文件夹的名称。 例如,在 uploadAttachment() 中添加以下代码行:

newAttachment.getCategories().add(new Category("http://schemas.google.com/sites/2008#folder", "FolderName"));

网络附件

网络附件是一种特殊类型的附件。实质上,它们是指向网络上的其他文件的链接,您可以将这些文件添加到文件箱式列表中。此功能类似于 Google 协作平台界面中的“通过网址添加文件”上传方法。

注意:网络附件只能在文件箱式页面下创建。不能上传到其他类型的网页。

此示例会在用户内容 Feed 中的第一个 FileCabinetPageEntry 下创建一个 WebAttachmentEntry。其标题和(可选)说明分别设置为“GoogleLogo”和“nice colors”。

public WebAttachmentEntry uploadWebAttachment(String contentUrl, FileCabinetPageEntry filecabinet,
    String title, String description) throws MalformedURLException, IOException, ServiceException {
  MediaContent content = new MediaContent();
  content.setUri(contentUrl);

  WebAttachmentEntry webAttachment = new WebAttachmentEntry();
  webAttachment.setTitle(new PlainTextConstruct(title));
  webAttachment.setSummary(new PlainTextConstruct(description));
  webAttachment.setContent(content);
  webAttachment.addLink(SitesLink.Rel.PARENT, Link.Type.ATOM,
      filecabinet.getSelfLink().getHref());

  return client.insert(new URL(buildContentFeedUrl()), webAttachment);
}

ContentFeed contentFeed = client.getFeed(new URL(buildContentFeedUrl() + "?kind=filecabinet"), ContentFeed.class);
FileCabinetPageEntry parentPage = contentFeed.getEntries(FileCabinetPageEntry.class).get(0);

WebAttachmentEntry webAttachment =
    uploadWebAttachment("http://www.google.com/images/logo.gif", parentPage, "Google's Logo", "nice colors");
System.out.println("Web attachment created!");

POST 会在用户的文件箱式页面中创建一个指向“http://www.google.com/images/logo.gif”图片的链接。

返回页首



更新内容

更新网页的元数据和/或 HTML 内容

可以使用条目的 update() 方法修改任何 BaseContentEntry 类型的元数据(标题、pageName 等)和网页内容。此操作会向条目的 edit 链接发送 HTTP PUT 请求。

以下是更新 ListPageEntry 的示例,其中包含以下更改:

  • 标题已修改为“已更新标题”
  • 网页的 HTML 内容更新为“<p>已更新的 HTML 内容</p>”
  • 列表的第一个列标题更改为“所有者”
ContentFeed contentFeed = client.getFeed(
    new URL(buildContentFeedUrl() + "?kind=listpage"), ContentFeed.class);
ListPageEntry listPage = contentFeed.getEntries(ListPageEntry.class).get(0); // Update first list page found

// Update title
listPage.setTitle(new PlainTextConstruct("Updated Title"));

// Update HTML content
XmlBlob xml = new XmlBlob();
xml.setBlob("<p>Updated HTML Content</p>");
listPage.setContent(new XhtmlTextConstruct(xml));

// Change first column's heading
listPage.getData().getColumns().get(0).setName("Owner");

// listPage.setPageName(new PageName("new-page-path"));  // You can also change the page's URL path

ListPageEntry updatedEntry = listPage.update();

System.out.println("ListPage updated!");

正在更新附件文件内容

对于 AttachmentEntry,您还可以通过设置条目的 MediaSource,然后使用条目的 updateMedia(boolean) 方法来更新内容。

以下示例将更新现有附件的内容:

public AttachmentEntry updateFile(AttachmentEntry entry, File newFile)
    throws IOException, ServiceException {
  // See Uploading Attachments for the definition of mediaTypes.
  entry.setMediaSource(new MediaFileSource(newFile, mediaTypes.getContentType(newFile)));
  return entry.updateMedia(false);
}

该示例向条目的 edit-media 链接发送 HTTP PUT 请求。返回的 AttachmentEntry 将包含更新后的内容。

更新附件元数据和内容

您可以使用 updateMedia() 方法在同一调用中更新附件的元数据及其内容。您可以只更新文件内容和/或元数据。

此示例将附件的标题更改为“新标题”,更新了附件的说明,并将其文件内容替换为新的 .zip 文件。 由于请求包含新的文件内容,因此会使用 AttachmentEntryupdateMedia()

public AttachmentEntry updateAttachment(AttachmentEntry entry, File newFile, String newTitle, String newDescription)
    throws IOException, ServiceException  {
  // See Uploading Attachments for the definition of mediaTypes.
  entry.setMediaSource(new MediaFileSource(newFile, mediaTypes.getContentType(newFile)));
  entry.setTitle(new PlainTextConstruct(newTitle));
  entry.setSummary(new PlainTextConstruct(newDescription));

  return entry.updateMedia(true);
}

ContentFeed contentFeed = client.getFeed(
    new URL(buildContentFeedUrl() + "?kind=attachment&max-results=1"), ContentFeed.class);
AttachmentEntry attachment = contentFeed.getEntries(AttachmentEntry.class).get(0); // Update first attachment found

AttachmentEntry updatedAttachment = updateAttachment(attachment, new File("/path/to/file.zip"), "New Title", "better stuff");

返回页首



正在删除内容

若要从 Google 协作平台中移除网页或项,请先检索内容条目,然后调用该条目的 delete()

entry.delete();

您还可以使用服务类的 delete() 方法,只需将相应条目的 edit 链接和 ETag 值传递给该方法即可:

client.delete(entry.getEditLink().getHref(), "*"); // Note: using "*" may overwrite another client's changes.

如果条目已成功删除,服务器会返回 HTTP 200 OK 响应。

返回页首



正在下载附件

如需下载 AttachmentEntry,请向相应条目的内容 src 链接发送 HTTP GET 请求。

此示例会将用户内容 Feed 中找到的第一个 AttachmentEntry 下载到目录“/path/to/save/file/”:

private void downloadFile(String downloadUrl, String fullFilePath) throws IOException, ServiceException {
  System.out.println("Downloading file from: " + downloadUrl);

  MediaContent mc = new MediaContent();
  mc.setUri(downloadUrl);
  MediaSource ms = service.getMedia(mc);

  InputStream inStream = null;
  FileOutputStream outStream = null;

  try {
    inStream = ms.getInputStream();
    outStream = new FileOutputStream(fullFilePath);

    int c;
    while ((c = inStream.read()) != -1) {
      outStream.write(c);
    }
  } finally {
    if (inStream != null) {
      inStream.close();
    }
    if (outStream != null) {
      outStream.flush();
      outStream.close();
    }
  }
}

public void downloadAttachment(AttachmentEntry entry, String directory) throws IOException, ServiceException {
  String url = ((OutOfLineContent) entry.getContent()).getUri();
  downloadFile(url, directory + entry.getTitle().getPlainText()); // Use entry's title for the save filename
}

ContentFeed contentFeed = client.getFeed(
    new URL(buildContentFeedUrl() + "?kind=attachment&max-results=1"), ContentFeed.class);

downloadAttachment(contentFeed.getEntries(AttachmentEntry.class).get(0), "/path/to/save/file/");
System.out.println("Downloaded.");

返回页首

ACL 供稿

共享权限 (ACL) 概览

ACL Feed 中的每个 ACL 条目都代表特定实体的一个访问角色,可以是一个用户、一组用户、一个网域,也可以是默认访问权限(即公共网站)。系统仅针对具有明确访问权限的实体显示条目 - 在 Google 协作平台界面共享屏幕的“有访问权限的人”面板中,每个电子邮件地址会显示一个条目。因此,系统不会显示网域管理员,即使他们具有对网站的隐式访问权限。

角色

角色元素表示实体可以拥有的访问权限级别。gAcl:role 元素有四个可能的值:

  • reader - 查看者(等同于只读访问权限)。
  • writer - 协作者(相当于读取/写入权限)。
  • owner - 通常是网站管理员(相当于读/写权限)。

作用域

作用域元素表示拥有此访问权限级别的实体。gAcl:scope 元素有四种可能的类型:

  • user - 电子邮件地址值,例如“user@gmail.com”。
  • group - Google 群组电子邮件地址,例如“group@domain.com”。
  • domain - G Suite 域名,例如“domain.com”。
  • default - 只能有一个“default”类型的范围,该范围没有值(例如 <gAcl:scope type="default">)。此特定范围用于控制任何用户在公开网站上默认拥有的访问权限。

注意:网域不能将 gAcl:role 值设为“所有者”访问权限,它们只能是读取者或写入者。

检索 ACL 供稿

AclFeedAclEntry 类可用于控制网站的共享权限,并可通过使用服务类的 getFeed() 方法提取。

以下示例会提取给定网站的 ACL Feed,并输出每个 AclEntry 的权限:

public String getAclFeedUrl(String siteName) {
  String domain = "site";  // OR if the Site is hosted on G Suite, your domain (e.g. example.com)
  return "https://sites.google.com/feeds/acl/site/" + domain + "/" + siteName + "/";
}

public void getAclFeed(String siteName) throws IOException, ServiceException {
  AclFeed aclFeed = client.getFeed(new URL(getAclFeedUrl(siteName)), AclFeed.class);
  for (AclEntry entry : aclFeed.getEntries()) {
    System.out.println(entry.getScope().getValue() + " (" + entry.getScope().getType() + ") : " +
                       entry.getRole().getValue());
  }
}

getAclFeed('my-site-name');

如果您要处理 SiteFeed 中的条目,则每个 SiteEntry 都包含指向其 ACL Feed 的链接。例如,以下代码段会提取 SiteEntry 的 acl Feed:

String aclLink = siteEntry.getLink(SitesAclFeedLink.Rel.ACCESS_CONTROL_LIST, Link.Type.ATOM).getHref();
AclFeed aclFeed = client.getFeed(new URL(aclLink), AclFeed.class);

共享网站

注意:某些共享 ACL 可能仅在网域配置为允许此类权限的情况下才能使用(例如,如果针对 G Suite 网域启用了与网域外用户共享内容的功能等)。

如需使用 API 共享 Google 网站,您的客户端需要创建一个新的 AclEntry 并将其 POST 到服务器。

以下是在网站上将“user@example.com”添加为 reader 的示例:

AclRole role = new AclRole("reader");
AclScope scope = new AclScope(AclScope.Type.USER, "user@example.com");
AclEntry aclEntry = addAclRole(role, scope, entry);

public AclEntry addAclRole(AclRole role, AclScope scope, SiteEntry siteEntry)
    throws IOException, MalformedURLException, ServiceException  {
  AclEntry aclEntry = new AclEntry();
  aclEntry.setRole(role);
  aclEntry.setScope(scope);

  Link aclLink = siteEntry.getLink(SitesAclFeedLink.Rel.ACCESS_CONTROL_LIST, Link.Type.ATOM);
  return client.insert(new URL(aclLink.getHref()), aclEntry);
}

请参阅 ACL Feed 概览部分,了解可能的 AclScopeAclRoles 值。

群组和网域级共享

与单个用户共享网站类似,您可以在 Google 群组或 G Suite 网域之间共享网站。

共享至群组电子邮件地址:

AclScope scope = new AclScope(AclScope.Type.GROUP, "group_name@example.com");

与整个网域共享:

AclScope scope = new AclScope(AclScope.Type.DOMAIN, "example.com");

只有 G Suite 网域以及托管网站的网域支持网域级共享。 例如,http://sites.google.com/a/domain1.com/siteA 只能与 domain1.com 共享整个网站,而不能与 domain2.com 共享。未在 G Suite 网域(例如 http://sites.google.com/site/siteB)上托管的网站无法邀请网域。

修改共享权限

如需授予网站上的现有共享权限,请先获取相关 AclEntry,根据需要修改权限,然后调用 AclEntryupdate() 方法以修改服务器上的 ACL。

此示例修改了之前在共享网站部分中的 aclEntry 示例,将“user@example.com”更新为 writer(协作者):

aclEntry.setRole(new AclRole("writer"));
AclEntry updatedAclEntry = aclEntry.update();

// Could also use the client's update method
// client.update(new URL(aclEntry.getEditLink().getHref()), aclEntry);

如需详细了解 ETag,请参阅 Google Data API 参考指南

正在移除共享权限

如需移除共享权限,请先检索 AclEntry,然后调用其 delete() 方法:

aclEntry.delete();

// Could also use the client's delete method
// client.delete(new URL(aclEntry.getEditLink().getHref()), aclEntry);

如需详细了解 ETag,请参阅 Google Data API 参考指南

返回页首

特殊主题

再次检索 Feed 或条目

如果要检索之前检索到的 Feed 或条目,您可以告知服务器仅在自上次检索以来发生了更改时才发送列表或条目,从而提高效率

为了进行这种条件检索,getFeed()getEntry() 方法都提供了一个额外的参数,用于接受 If-Modified-Since 标头的 ETag 值或 DateTime 对象。您可以从 entry.getEtag() 访问条目的 etag。

以下示例会对内容网页条目进行条件检索:

String feedUrl = "https://sites.google.com/feeds/content/site/siteName/123456789";
WebPageEntry entry = client.getEntry(new URL(feedUrl), WebPageEntry.class, "\"GVQHSARDQyp7ImBq\"");

当服务器收到此请求时,它会检查您请求的项是否具有与您指定的 ETag 相同的 ETag。如果 ETag 匹配,则项尚未更改,并且服务器会返回 HTTP 304 NotModifiedException 异常。

如果 ETag 不匹配,则表示自您上次请求以来该项已经过修改,服务器会返回该项。

如需详细了解 ETag,请参阅 Google Data API 参考指南

返回页首