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 数据 Java 客户端库与 Google 协作平台进行交互的客户端应用的开发者。

使用入门

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

安装库

如需有关设置和安装客户端库的帮助,请参阅 Google Data 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 适用于传统版 Sites 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,用户可以执行一系列操作,以演示如何使用传统版协作平台 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 对象,以表示客户端与传统版 Google 协作平台 API 的连接:

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

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

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

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

Java 客户端库可用于处理公开或私密 Feed。协作平台数据 API 提供对不公开 Feed 和公开 Feed 的访问权限,具体取决于协作平台权限和您尝试执行的操作。例如,您或许可以读取公开网站的内容 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 账号验证身份,则应使用适用于 Web 应用的 AuthSub 身份验证。操作者无需访问 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 处理脚本使用的查询参数):

  • 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 客户端库搭配使用

用于网络或安装版/移动应用的 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 应用中使用 Dialogflow,请参阅将 Dialogflow 与 Google Data API 客户端库搭配使用

返回页首

站点 Feed

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

列出网站

要查询网站 Feed,请将 HTTP GET 发送到网站 Feed 网址:

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 协作平台网站。例如,可以使用 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 参数。如果该参数不存在,系统将不会在网站条目中返回 webAddressMapping(GET),也不会在更新/移除(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 来访问该 API:

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 标准查询参数以及传统版 Sites 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> 元素。

此示例会创建标题为“文件存储空间”的新 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。将通告标题设为“派对!”,将内容设为“本周末,我家”。

页面模板

创建页面模板

创建页面模板的过程与创建新项/页面创建子页面相同。不同之处在于添加了 category ,并且将“term”和“label”分别设置为“http://g/schema0.google.template.google.

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

通过模板创建页面

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

此示例会创建一个新的 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>,但您仍需要在条目中添加一个 <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 协作平台界面中的“通过网址添加文件”上传方法。

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

此示例会在用户的内容 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,请向条目的 content 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 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);

共享网站

注意:只有当网域配置为允许此类权限(例如,为 G Suite 网域启用了网域外共享等)时,才能使用某些共享 ACL。

如需使用此 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 参考指南

返回页首