Java 语言指南

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

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

除了简要介绍 Sites Data API 的功能外,本指南还提供了使用 Java 客户端库与该 API 互动的示例。如需有关设置客户端库的帮助,请参阅Google Data Java 客户端库使用入门。如果您有兴趣详细了解 Java 客户端库用于与传统版 Google 协作平台 API 互动的底层协议,请参阅协议指南

受众群体

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

使用入门

Google 协作平台使用 Google 账号或 G Suite 账号进行身份验证。如果您已有账号,则无需进行任何操作。 否则,您可以创建一个新账号

安装库

如需有关设置和安装客户端库的帮助,请参阅Google Data Java 客户端库使用入门。如果您使用的是 Eclipse,该文章还会介绍如何使用 Google Data APIs 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 版是指传统版 Google 协作平台 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 子目录中。您还可以通过“Source”(来源)标签页访问 SVN 代码库,在 /trunk/java/sample/sites/ 中找到相应来源。SitesDemo.java 允许用户执行多项操作,以演示如何使用 Sites API。

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

开始自己的项目

提示:如需使用我们的 Eclipse 插件快速完成设置,请参阅将 Eclipse 与 Google Data API 搭配使用一文。

根据应用的需求,您需要进行多项导入。建议您先导入以下内容:

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 对象,该对象表示与 Sites API 的客户端连接:

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

applicationName 实参应采用以下格式:company-applicationname-version。此参数用于日志记录目的。

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

向传统版 Google 协作平台 Sites API 进行身份验证

Java 客户端库可用于处理公开 Feed 或私密 Feed。Sites Data API 可提供对私密和公开 Feed 的访问权限,具体取决于 Google 协作平台的权限以及您尝试执行的操作。例如,您可能可以读取公开网站的内容 Feed,但无法对其进行更新,而更新需要经过身份验证的客户端。您可以通过 ClientLogin 用户名/密码身份验证、AuthSubOAuth 来完成此操作。

如需详细了解 AuthSub、OAuth 和 ClientLogin,请参阅 Google Data API 身份验证概览

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

用于网络应用程序的 AuthSub

需要对用户进行身份验证以访问 Google 账号的客户端应用应使用 AuthSub 身份验证(适用于 Web 应用)。该运算符不需要访问 Google 协作平台用户的用户名和密码,只需要 AuthSub 令牌。

查看有关将 AuthSub 纳入 Web 应用的说明

请求一次性令牌

当用户首次访问您的应用时,需要进行身份验证。通常,开发者会打印一些文字和一个链接,引导用户前往 AuthSub 批准页面,以对用户进行身份验证并请求访问用户的文档。Google Data 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 处理程序使用的查询参数相对应):

  • 下一个网址 - 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 纳入已安装应用的说明

适用于已安装/移动应用的 ClientLogin

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

查看有关将 ClientLogin 纳入已安装应用的说明

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

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

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

如需详细了解如何在 Java 应用中使用 ClientLogin,请参阅将 ClientLogin 与 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() 方法,可以预配新网站。

此示例创建了一个采用主题“slate”(可选设置)的全新网站,并提供了网站名称(必需)和说明(可选):

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。例如,在上面的示例中,有三个 webAddressMapping 指向网站 http://sites.google.com/site/myOtherTestSite

修改网址映射

注意:在处理网址映射时,所有 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 或 ClientLogin 令牌进行身份验证。请参阅向 Google 协作平台服务进行身份验证

返回页首

修订版本 Feed

如需提取任何内容条目的修订历史记录,请向相应条目的修订链接发送 HTTP GET

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

此示例查询内容 Feed,然后提取第一个内容条目的修订版本 Feed:

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 或 ClientLogin 令牌进行身份验证。请参阅向 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 或 ClientLogin 令牌进行身份验证。请参阅向 Google 协作平台服务进行身份验证

内容 Feed 查询示例

您可以使用一些标准 Google Data API 查询参数以及特定于传统版 Google 协作平台 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 下创建,并具有“新网页标题”的网页标题。也就是说,网址的 <atom:title> 已归一化为 new-webpage-title。 如需自定义网页的网址路径,您可以设置 <sites:pageName> 元素。

此示例创建了一个新 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. <atom:title>,如果未提供 pageName,则不得为 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 weekend”。

页面模板

创建页面模板

创建网页模板的流程与创建新商品/网页创建子网页的流程相同。不同之处在于,前者添加了 category,并将 term 和 label 分别设置为“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' 指向网页模板的自链接)来从模板实例化新网页。

此示例会创建一个新的 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"));

Web 附件

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

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

此示例会在用户的内容 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 内容

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

以下示例展示了如何更新 ListPageEntry 并进行以下更改:

  • 标题已修改为“更新后的标题”
  • 网页的 HTML 内容已更新为“<p>Updated HTML Content</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() 方法在同一次调用中更新附件的元数据及其内容。您可以仅更新文件内容、仅更新元数据,也可以同时更新这两者。

此示例将附件的标题更改为“New Title”,更新其说明,并将其文件内容替换为新的 .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 Feed

共享权限 (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 Feed

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);
}

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

群组级和网域级共享

与单个用户共享网站类似,您可以与 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 参考指南

返回页首