精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

在Google Java App Engine上實現文檔存儲和搜索

原創
開發 開發工具 后端
Google App Engine的Java支持已于今年4月發布,對于Java開發者而言這是極大的好處:App Engine具有伸縮性強,管理界面強大等特點,而且對于小型應用來說是完全免費的。本文演示了如何在App Engine上編寫實現文檔的存儲和搜索功能。

【51CTO技術譯文】為什么Java程序員要考慮使用Google的Java App Engine呢,主要有以下幾點原因:只要你的頁面訪問量每月不超過500萬,Google就免費向你提供空間。如果訪問量超過了這一限額,你也可以隨時通過升級為付費用戶取消這一限制。

◆Google的App Engine 平臺(包括Java和Python版本)讓你不用做什么額外工作就有很強的伸縮性

◆App Engine 提供了一個功能很強的管理界面,你可以通過它查看錯誤日志,瀏覽你所保存的數據,分析程序的性能(例如請求響應時間等),還可以實時監控你所部署的應用。即便是和Amazon的EC2這樣優秀的Web控制臺比起來,Google的Web應用程序管理功能也毫不遜色。

◆只要你愿意,你也可以通過App Engine SDK 把App Engine 上的應用遷移到你自己的服務器上,當然,這樣就會損失一些伸縮性(scalability)了。

◆因為在App Engine上開發程序時使用的都是標準的 API,所以當你要把應用移植部署到其它平臺上時,就只需要對程序作非常小的改動了。不過反過來做就不是這么簡單了。比如說如果你的程序調用大量的J2EE API函數,或者說依賴于關系型數據庫等等,那么把這些程序移植到App Engine上就非常麻煩。

◆那些用J2EE寫Web程序的開發者們可能一開始會覺得App Engine 的種種限制讓人覺得很不適應,但是這樣做的好處也是很明顯的,服務器的花費將大大減少。如果你想要更大的自由度和伸縮性,那么你還可以考慮Amazon的EC2服務(我是既用App Engine,也用EC2)。

本文接下來將介紹Java開發者如何使用Google應用程序引擎。它演示了如何在App Engine上編寫實現文檔的存儲和搜索功能。本文還探討了Java App Engine文檔里的一些有用技術和應用程序示例。

你需要作的準備 

◆Eclipse或IntelliJ IDEA開發環境 

◆一個App Engine 帳號,如果還沒有的話,在這里申請(沒有App Engine 帳號的開發者可以通過在你自己電腦上安裝App Engine SDK體驗它) 

◆下載App Engine SDK 供本地開發時使用 

◆安裝Eclipse的或IntelliJ 的Java App Engine 插件。  
 
示例工程里的文件

示例工程里的文件 

圖1 示例工程里的文件

許多Java開發人員使用 Lucene (或基于Lucene的框架)來實現搜索功能。但是,在App Engine環境下使用Lucene的內存索引模式沒有什么好處。我們的這個示例工程另辟蹊徑在App Engine平臺上實現了搜索功能。

App Engine的持久性數據存儲效率是非常高的,但它不使用關系模型,也沒有Hibernate這樣的對象關系映射(Object Relational Mapping ,ORM)框架。不過,App Engine還是提供了對一些標準的持久性API,如JDO,JPA,以及JCache。我們的示例程序使用JDO實現數據持久(data persistence)。

這個程序部署在這里。每個使用這個演示程序的人都可以把數據清空從頭再來,所以你這次添加的信息下次可以就會看不到了。

作者注:這個程序演示了JDO的使用以及如何用JDO實現搜索,為了突出重點,程序沒有增加對多用戶這些功能的支持。

圖1顯示了這個Java App Engine項目所包含的文件。后續的章節將詳細介紹packagecom.kbsportal.model 里的模型類和 com.kbsportal.persistence 里的持久類PMF。由于packagecom.kbsportal.util這個包里的各種類和App Engine里的差別較大,我們就不在這里作過多討論了。如果要詳細了解這些,你可以看看我們的源代碼以及JSP文件(在 war/WEB-INF目錄里)。我們也會對JSP文件里某些Java代碼片段加以解釋。

使用JDO實現數據持久化

JDO是一個用于持久化Java對象的古老API。起初,為了實現持久化存儲,JDO要求開發者必須編寫和維護XML文件,以提供Java類的數據映射屬性。Google使用 DataNucleus 工具自動完成這一過程。你只需要在你的Java模型類里面加以注解,DataNucleus工具就會自動為你維護正確的數據映射關系。如果使用了Eclipse的或IntelliJ IDEA的App Engine插件,當你編寫持久類時,DataNucleus工具就會自動在后臺作用。

警告:JDO和App Engine放到一起有時候會產生兼容性問題。如果你是在本地用Eclipse開發,只要刪除目錄 WEBAPP /war/WEB-INF/ appengine-generated/ local_db.bin里的文件。 如果你的Web應用已經部署上去了而且要修改模型類,那么你只需在App Engine控制臺中把已有的索引文件刪除即可

以下各節將介紹兩個持久類的實現并探討這些基于JDO實現的代碼。

#p#

文檔模型類

Eclipse或IntelliJ IDEA的App Engine插件與JDO以及DataNucleus工具的組合非常好用。使用這個組合設計和實現你自己的模型文件,并添加必須的注解,這些對你來說應該不成問題。不過你還是要注意DataNucleus工具在后臺運行時所提示的錯誤信息。

在開始設計實現自己的持久類前,不妨先看看下面這個模型類,它是用來反映一個文件模型的。這個類在定義時會引入所需的JDO 類(實際上你的編輯器會自動幫你填寫這些包含語句)。第一行注釋聲明了這個類是持久的。這個類被標識為APPLICATION,這樣你就可以為那些創建后就將持久存在的對象分配ID。如果你要為數據存儲對象分配ID,那么你可以把類型指定為DATASTORE。

  1. package com.kbsportal.model;  
  2.  
  3. import javax.jdo.annotations.IdentityType;  
  4. import javax.jdo.annotations.PersistenceCapable;  
  5. import javax.jdo.annotations.Persistent;  
  6. import javax.jdo.annotations.PrimaryKey;  
  7.  
  8. @PersistenceCapable(identityType=IdentityType.APPLICATION)  
  9. public class Document {  
  10.  

這段代碼聲明了把成員變量uri作為在數據存儲里查找Document對象時的主鍵。JDO的索引主鍵也被設為URI。本文的示例文本存儲在IndexToken這個類里面使用了這個主鍵(IndexToken類將在下一節進一步討論)。這段代碼還特別說明了title, content以及numWords這幾個成員變量要持久保存。

  1. @PrimaryKey private String uri;  
  2. @Persistent private String title;  
  3. @Persistent private String content;  
  4. @Persistent private int numWords; 

類聲明里的其它部分則不包含JDO具體說明。

  1. public Document(String uri, String title, String content) {  
  2.     super();  
  3.     setContent(content);  
  4.     this.title = title;  
  5.     this.key = uri;  
  6.   }  
  7.   public String getUri() { return key; }  
  8.   public String getTitle() { return title; }  
  9.   public void setTitle(String title) { this.title = title; }  
  10.   public String getContent() { return content; }  
  11.   public void setContent(String content) {  
  12.     this.content = content;  
  13.     this.numWords = content.split("[\\ \\.\\,\\:\\;!]").length;  
  14.     System.out.println("** numWords = " + numWords + " content: "+content);  
  15.   }  
  16.   public int getNumWords() { return numWords; }  
  17. }  

注意在內容字符串上所作的長度限制;GoogleApp Engine的數據存儲限制字符串不得超過500個字符。(使用com.google.appengine.api.datastore.Textfors可以獲得沒有長度限制的字串。 )

#p#

IndexToken模型類

該IndexToken類基于JDO實現了搜索功能。這個類有兩種工作模式:整詞索引、整詞及詞前綴索引。在源文件的頭部你可以通過一個常量指定它的工作模式:

  1. package com.kbsportal.model;  
  2.  
  3. import java.util.ArrayList;  
  4. import java.util.Collections;  
  5. import java.util.Comparator;  
  6. import java.util.HashMap;  
  7. import java.util.List;  
  8.  
  9. import javax.jdo.PersistenceManager;  
  10. import javax.jdo.annotations.IdGeneratorStrategy;  
  11. import javax.jdo.annotations.IdentityType;  
  12. import javax.jdo.annotations.Index;  
  13. import javax.jdo.annotations.PersistenceCapable;  
  14. import javax.jdo.annotations.Persistent;  
  15. import javax.jdo.annotations.PrimaryKey;  
  16.  
  17. import com.kbsportal.persistence.PMF;  
  18. import com.kbsportal.util.NoiseWords;  
  19. import com.kbsportal.util.Pair;  
  20. import com.kbsportal.util.SearchResult;  
  21.  
  22. @PersistenceCapable(identityType=IdentityType.APPLICATION)  
  23. public class IndexToken {  
  24.   static boolean MATCH_PARTIAL_WORDS = true;  // package visibility  

把這個標志設置為true,就會開啟單詞的前綴匹配功能,類似于搜索關鍵字自動校正功能。

現在我們該看看如何建立索引片段(可能還包括單詞前綴的索引片段)以及如何確定每個索引片段的匹配度。以下是具體的代碼(來自IndexToken.java包里的源文件,它是作為一個單獨的局部類實現的,以方便在其他項目重復使用) :

  1. class StringPrefix {  
  2.   public List getPrefixes(String str) {  
  3.     List ret = new ArrayList();  
  4.     String[] toks = str.toLowerCase().split("[\\ \\.\\,\\:\\;\\(\\)\\-\\[\\]!]");  
  5.     for (String s : toks) {  
  6.       if (!(NoiseWords.checkFor(s))) {  
  7.         if (!IndexToken.MATCH_PARTIAL_WORDS) { // exact words only  
  8.           ret.add(new Pair(s, 1f));  
  9.         } else { // or, also match word prefixes  
  10.           int len = s.length();  
  11.           if (len > 2) {  
  12.             ret.add(new Pair(s, 1f));  
  13.             if (len > 3) {  
  14.               int start_index = 1 + (len / 2);  
  15.               for (int i = start_index; i < len; i++) {  
  16.                 ret.add(new Pair(s.substring(0, i), (0.25f * (float) i) / (float) len));  
  17.               }  
  18.             }  
  19.           }  
  20.         }  
  21.       }  
  22.     }  
  23.     return ret;  
  24.   }  
  25. }  

應用中的一些理念

通過使用 Peter Norvig的拼寫檢查算法可以實現更完整的拼寫檢查功能。使用相對較低的相關系數可以生成錯誤的拼寫序列和IndexToken實例。在我所寫的書"Practical Artificial Intelligence Programming in Java"的第9章里有一個Java版本的 Norvig算法實現。

#p#

其它實現方法

我在另一個大項目里使用了這些代碼,那個項目需要一個彈出式的文字補全提示;我們存儲的這些前綴起到了“雙重作用”。本文主要講解基于JDO的文件存儲和搜索,但你可以簡單地使用一個JavaScript庫,例如 Prototype或GWT實現彈出的提示菜單。另外,你也可以只把詞干作為 IndexToken實例保存。點擊此處查看相關Java詞根提取程序。
 
Pair這個類是在com.kbsportal.util包里實現的,這個包里面還有另外兩個類: NoiseWords和SearchResults 。我們在此不再追究這些類的細節。今后我們將深入這些源文件。

要完成IndexToken,以及示例程序的其余部分,我們要用到JDO的API,首先是在類屬性說明里加入這些注解:

  1. @PrimaryKey 
  2. @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)  
  3. private Long id;  
  4. @Persistent @Index private String textToken;  
  5. @Persistent private String documentUri;  
  6. @Persistent private Float ranking;  

@Persistent 標示這個成員在整個對象被保存時要被插入到數據存儲里去。valueStrategy的值是可選的,按上面這樣設置是表明你希望數據存儲為你這個類的ID屬性自動賦值。@PrimaryKey 注釋讓DataNucleus工具知道,在查找數據存儲區里的這種對象時要以該參數為主鍵。

作者注:通常情況下都是通過主鍵獲取對象。然而,在我們這個程序里,我們將要通過IndexToken類的參數值 textToken 來查找對象。但是我們不能使用參數textToken 作為主鍵,因為這樣有可能導致在數據存儲區里有主鍵一樣的不同實例出現。

下面這個成員方法能獲取文件ID(文件的URI)以及文件中的一段文字,實例化一個IndexToken類:

  1. public static void indexString(String document_id, String text) {  
  2.     PersistenceManager pm = PMF.get().getPersistenceManager();  
  3.     List lp = new StringPrefix().getPrefixes(text);  
  4.     for (Pair p : lp) {  
  5.         if (p.str.length() > 0 && !Character.isDigit(p.str.charAt(0))) {  
  6.           pm.makePersistent(new IndexToken(document_id, p.str, p.f));  
  7.         }  
  8.     }     
  9.   }  

這段代碼用到了StringPrefix 類。另外還使用了工具類PMF(等下我們就會更詳細地去了解它)來獲得一個App Engine持久管理器(persistence manager)的實例。這類似于一個JDBC 連接對象。

在IndexToken里還有一個值得一提的地方就是search這個靜態方法.

  1. public static List search(String query) {  
  2.     List< SearchResult> ret = new ArrayList< SearchResult>();  
  3.     PersistenceManager pm = PMF.get().getPersistenceManager();  
  4.     String [] tokens = query.toLowerCase().split(" ");  
  5.     HashMap matches = new HashMap();  

此方法返回SearchResult類的實例。查詢字符串被轉換為小寫并被分割。對于每一個片段,你都將再次用StringPrefix計算前綴(以及原始單詞) ,計算結果將用于查找包含這些關鍵詞的文件:

  1. for (String token : tokens) {  
  2.       List lp = new StringPrefix().getPrefixes(token);  
  3.       for (Pair p : lp) {  
  4.         String q2 = "select from " + IndexToken.class.getName() + "  where textToken == '" + p.str + "'";  
  5.         @SuppressWarnings("unchecked")  
  6.         List itoks = (List) pm.newQuery(q2).execute();  

這個查詢字符串可能看起來會覺得有點像標準的SQL語句 ,但不是。其實它們是JDO的查詢語言( JDOQL ) 。它從一個在數據存儲區持久化了的類里面取數據,而不是像SQL語句那樣通過一個數據庫的表名來提取數據。TextToken就是IndexToken 的一個持久化參數。這個JDOQL能返回數據存儲區中所有textToken成員參數與查詢關鍵字匹配的IndexToken實例。(51CTO編者注:JDOQL是JDO的查詢語言;它有點象SQL,但卻是依照Java的語法的。)

搜索功能的其它部分實現起來就沒有什么難點了。只需要保存所有的文件匹配以及根據匹配度計算出的排名權重。

  1. for (IndexToken it : itoks) {  
  2.           Float f = matches.get(it.getDocumentUri());  
  3.           if (f == null) f = 0f;  
  4.           f += it.getRanking();  
  5.           matches.put(it.getDocumentUri(), f);  
  6.         }  
  7.       }     
  8.     }  

這樣我們就建立好了查詢關鍵字與文件之間的映射關系,還知道了這些文件的URI以及排名權重。我們只需要把匹配結果從數據存儲區里取出來就可以了(只有這樣我們才有結果可顯示), 然后把這些與關鍵字相匹配的文檔按匹配度從高到低排列,就形成了搜索結果。

  1. for (String s : matches.keySet()) {  
  2.       String q2 = "select from " + Document.class.getName() + "  where uri == '" + s + "'";  
  3.       @SuppressWarnings("unchecked")  
  4.       List itoks = (List) pm.newQuery(q2).execute();  
  5.       if (!itoks.isEmpty()) {  
  6.         int num_words = itoks.get(0).getNumWords();  
  7.         ret.add(new SearchResult(s, matches.get(s) / (float)(num_words), itoks.get(0).getTitle()));  
  8.       }  
  9.     }  
  10.     Collections.sort(ret, new ValueComparator());  
  11.     return ret;  
  12.   }  

ValueComparato這個類是在源文件IndexToken.java里定義的,作用就是對搜索結果進行排序。

  1. static class ValueComparator implements Comparator {  
  2.     public int compare(SearchResult o1, SearchResult o2) {  
  3.       return (int)((o2.score - o1.score) * 100);  
  4.     }  
  5.   }  

處理持久性數據存儲:PMF類

我們這里所展示的PMF類代碼是從Google的文檔里復制過來的。這個類創建了一個私有的PersistenceManagerFactory實例并重用它。

  1. package com.kbsportal.persistence;  
  2. import javax.jdo.JDOHelper;  
  3. import javax.jdo.PersistenceManagerFactory;  
  4.  
  5. public final class PMF {  
  6.     private static final PersistenceManagerFactory pmfInstance =  
  7.         JDOHelper.getPersistenceManagerFactory("transactions-optional");  
  8.     private PMF() {}  
  9.     public static PersistenceManagerFactory get() {  
  10.         return pmfInstance;  
  11.     }  
  12. }  

#p#

示例程序的JSP頁面

在寫JSP頁面時,我通常最開始是把Java代碼嵌入到JSP頁面里,到最后,我再把一些公用代碼提取出來放到自定義的JSP標簽庫里,再給模型類添加上額外的行為。在這個程序里,我就不演示最后這幾步清理工作了。

作為首頁顯示的index.jsp頁面是用來顯示系統里所有的文件的。它也包含了一些可選的調試代碼(我通常會把這些調試代碼注釋掉),可以列出所有IndexToken類的實例(見 圖2 ) 。index.jsp 這個文件最開頭的部分引入了一些必要的類,定義了HTML頭信息,然后還引入了menu.jsp,這個文件是用來作分頁條的。

  1. < %@ page import="javax.jdo.*, java.util.*,   
  2.     com.kbsportal.model.*,com.kbsportal.persistence.PMF" %> 
  3. < %@ page language="java" contentType="text/html; charset=ISO-8859-1" 
  4.     pageEncoding="ISO-8859-1"%> 
  5. < !DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   
  6.    "http://www.w3.org/TR/html4/loose.dtd"> 
  7. < html> 
  8. < head> 
  9. < meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> 
  10. < title>KBSportal Java App Engine Search Demo< /title> 
  11. < /head> 
  12. < body> 
  13. < %@ include file="menu.jsp" %> 

列出所有文件 

圖2 列出所有文件:調試代碼列出了所有IndexToken 實例,并顯示了一些索引片段。

在IndexToken實例里我們已經見過JDOQL查詢語句。在這里,查詢語句返回所有文件對象:

  1. < h2>All documents:< /h2> 
  2. < %  
  3.   PersistenceManager pm = PMF.get().getPersistenceManager();   
  4.   Query query = pm.newQuery(Document.class);  
  5.   try {  
  6.        List< Document> results = (List< Document>)   
  7.           query.execute();  
  8.        if (results.iterator().hasNext()) {  
  9.            for (Document d : results) {  
  10.              System.out.println("key: "+d.getUri() +   
  11.                 ", title: "+d.getTitle());  
  12. %> 
  13.                < h3>< %=d.getTitle()%>< /h3> 
  14.                < p>< %=d.getContent()%>< /p> 
  15. < %  
  16.            }  
  17.        }  
  18.   } finally {  
  19.       query.closeAll();  
  20.   }     
  21. %> 

這里我們沒有用JDOQL查詢語句,而是用了一個查詢對象來獲取數據,這樣我們所獲得的查詢結果就在其它JSP文件里也可以使用了,如果你只想獲取某個特定標題的文件,那么通過下面的代碼可以篩選結果:

  1. String title_to_find = "Dogs and Cats" 
  2. query.setFilter("title == " + title_to_find);  

index.jsp這個文件的后半部分也包含一些調試代碼,在調試Web程序時我們可能會需要啟用它。這段代碼與之前那段調試代碼幾乎完全一樣,只不過這段代碼顯示的是所有的IndexToken實例。

  1. query = pm.newQuery(IndexToken.class);  
  2.    try {  
  3.        List results = (List) query.execute();  
  4.        if (results.iterator().hasNext()) {  
  5.            for (IndexToken indexToken : results) { 

用于向數據存儲區添加文件的表單 

圖3  用于向數據存儲區添加文件的表單:這個JSP頁面提供了一個可以向系統增加“文件” 的HTML輸入框

new_document.jsp這個文件提供了一個可以向系統增加“文件” 的HTML輸入框。(見 圖3 ) 。下面的代碼是從new_document.jsp截取出來的,它的作用是頁面請求中是否包含表單數據。如果有的話,就向數據存儲區里插入一個Document實例。

  1. < %  
  2.   String url = request.getParameter("url");  
  3.   String title = request.getParameter("title");  
  4.   String text = request.getParameter("text");  
  5.   if (url!=null && title!=null && text!=null) {  
  6.    PersistenceManager pm =   
  7.       PMF.get().getPersistenceManager();  
  8.    try {  
  9.      Document doc = new Document(url, title, text);  
  10.      pm.makePersistent(doc);  
  11.      IndexToken.indexString(doc.getUri(), doc.getTitle() +   
  12.         " " + doc.getContent());  
  13.    } finally {  
  14.      pm.close();  
  15.    }  
  16.   }  
  17. %> 

makePersistent這個方法會被直接調用并把文件保存到數據存儲區。靜態方法IndexToken.indexString則把根據文件標題和內容生成的片段插入到數據存儲區里。

數據存儲區 

圖4 從數據存儲區里:刪除所有文件和索引片段 示例應用程序需要一個簡單的方法來清空數據存儲區里所有測試“文件”數據

由于此示例程序是公開托管在Google那里,它需要一個簡單的方法來清除文件存儲區里所有的測試“文件”。delete_all.jsp這個jsp文件能從數據存儲里刪除所有的文件和索引片段(參見 圖4 ) 。

  1. PersistenceManager pm = PMF.get().getPersistenceManager();   
  2.   Query query = pm.newQuery(Document.class);  
  3.   try {  
  4.     List results = (List)   
  5.        query.execute();  
  6.     if (results.iterator().hasNext()) {  
  7.         for (Document d : results) {  
  8.             pm.deletePersistent(d);  
  9.         }  
  10.     }  
  11.   } finally {  
  12.     query.closeAll();  
  13.   }   
  14.  
  15.   query = pm.newQuery(IndexToken.class);  
  16.   try {  
  17.     List results = (List) query.execute();  
  18.     if (results.iterator().hasNext()) {  
  19.       for (IndexToken indexToken : results) {  
  20.           pm.deletePersistent(indexToken);  
  21.       }  
  22.     }  
  23.   } finally {  
  24.     query.closeAll();  
  25.   } 

search.jsp的JSP的文件包含了一個HTML搜索框(參見 圖5 ) 。以下是處理搜索操作的代碼:

  1. String query = "";  
  2.    String results = "< b>Results:< /b>< br/>";  
  3.    Object obj = request.getParameter("search");  
  4.    if (obj != null) {  
  5.      query = "" + obj;  
  6.      List hits = IndexToken.search(query);  
  7.      for (SearchResult hit : hits) {  
  8.        results += "< p>" + hit + "< /p>";  
  9.      }  
  10.    } 

搜索結果 

圖5 搜索結果: filesearch.jsp包含有一個HTML搜索框。

SearchResults類里新增的ToString 方法用于格式化搜索結果:

  1. public String toString() { return url +  
  2.    " - " + score + ": " + title; }  

成本低廉的解決方案

Google App Engine為我們提供了一套無成本(或低成本)的解決方案。盡管對于某些Web應用服務來說,它可能并不是最佳的部署平臺,但它絕對值得一試,而且絕對有資格成為我們開發工具箱里的備選項。

【App Engine相關文章推薦】

  1. 手把手教你在Google App Engine上運行PHP
  2. Google App Engine免費配額降低公告
  3. 開始您的第一個Google App Engine應用
  4. Google App Engine:Java SDK 1.2.1發布
  5. Google App Engine對Java支持情況一覽
  6. Google App Engine:堅定的站在Java的中心
責任編輯:yangsai 來源: 51CTO.com
相關推薦

2009-06-12 18:21:46

App Engine上

2009-09-10 10:11:44

Google App Java開發2.0

2009-04-16 09:59:16

Google App PHPJava

2009-09-07 10:42:01

Scala LiftGoogle App

2009-09-15 16:37:06

Google App 持久性

2009-04-13 15:48:54

Google AppJavaSun

2009-04-08 16:47:11

GoogleApp EngineJava

2009-04-09 08:54:07

App EnginegoogleJava

2009-09-04 09:41:34

Google App

2009-09-02 11:34:09

Google App

2009-04-09 09:53:43

GoogleAppEngineJava

2009-05-22 14:52:33

App Engine免費配額

2009-08-11 11:23:41

什么是GAEGoogle App

2010-02-01 09:21:49

GroovyGoogle App Gaelyk

2012-08-01 14:12:45

IBMdW

2009-05-14 09:47:30

GoogleApp EngineJava SDK

2011-09-06 14:53:01

Google App

2009-04-14 11:01:33

GoogleApp EngineGroovy

2012-10-16 09:30:38

谷歌開源云Google App

2009-04-09 11:06:00

GoogleApp EngineJVM
點贊
收藏

51CTO技術棧公眾號

日韩精品一区二区三区在线观看| 99re在线视频这里只有精品| 中文字幕久热精品视频在线| mm131亚洲精品| www国产在线观看 | 深夜福利网站在线观看| 青草青在线视频| 97精品国产露脸对白| 国产精品jvid在线观看蜜臀| 永久免费看mv网站入口| 精品国产一区二区三区成人影院| 欧美性xxxxxxx| 一区一区视频| 天天操天天干天天| 美女诱惑一区二区| 久久久噜噜噜久久| 成年人看的免费视频| 日韩一区二区三区色| 色综合激情五月| 青青视频免费在线| 欧美成人片在线| 国产精品一区二区x88av| 欧美一级片久久久久久久| 成人欧美一区二区三区黑人一 | 亚洲人人精品| 在线播放精品一区二区三区 | 毛片基地在线观看| 亚洲一区二区日韩| 亚洲欧美日韩精品| 在线观看欧美一区二区| 国产a亚洲精品| 精品久久久久久国产91| 正在播放亚洲| 四虎影视精品成人| 粉嫩久久99精品久久久久久夜| 国产成人欧美在线观看| 免费网站观看www在线观| 精品高清在线| 日韩高清不卡av| 男生和女生一起差差差视频| 日韩视频网站在线观看| 亚洲国产日韩一区二区| 在线电影看在线一区二区三区| 香蕉av一区二区三区| 国产在线精品一区二区不卡了 | 日韩欧美精品电影| 午夜精品一区二区三区三上悠亚| 永久久久久久| 最新国产在线观看| 久久精品一区二区三区av| 国产亚洲情侣一区二区无| 国产草草影院ccyycom| 麻豆91精品91久久久的内涵| 欧洲中文字幕国产精品| 日韩精品一区二区三区国语自制| 欧美成人中文| 久久视频免费观看| 蜜桃视频最新网址| 国产一区二区亚洲| 亚洲女成人图区| 变态另类丨国产精品| 亚洲三级av| 日韩欧美亚洲国产精品字幕久久久| 在线观看免费视频高清游戏推荐| **欧美日韩在线观看| 黑人巨大精品欧美一区免费视频 | 性高潮久久久久久久| 伦理一区二区三区| 日韩av综合中文字幕| 日韩成人av影院| 91精品国产自产在线丝袜啪| 日韩欧美国产电影| 无人码人妻一区二区三区免费| 国产一区二区三区精品在线观看 | 色偷偷在线观看| 99在线精品观看| 久久久综合亚洲91久久98| 天堂中文在线8| 久久综合丝袜日本网| 欧美重口乱码一区二区| 成人全视频高清免费观看| 国产精品免费aⅴ片在线观看| 亚洲日本欧美在线| caoporn免费在线视频| 一区二区三区 在线观看视频 | 少妇视频在线| 五月天欧美精品| 欧洲熟妇精品视频| 偷拍自拍亚洲| 亚洲精品一区二区三区精华液| 一女三黑人理论片在线| 精品欧美久久| 免费97视频在线精品国自产拍| 国产亚洲欧美久久久久| 久久九九99| 91精品美女在线| 男人的天堂a在线| 久久亚洲精华国产精华液| 手机看片福利永久国产日韩| a级在线观看| 狠狠爱在线视频一区| 欧美成人福利在线观看| 视频在线观看免费影院欧美meiju| 亚洲国产精品悠悠久久琪琪| 影音先锋男人在线| 欧美精品99| 国产91精品最新在线播放| 99久久久久成人国产免费| 99这里只有精品| 一区二区在线中文字幕电影视频| 91福利在线免费| 欧美日韩综合在线免费观看| 精品1卡二卡三卡四卡老狼| 国产一区二区三区不卡视频网站| 伦伦影院午夜日韩欧美限制| 在线精品免费视| 国产美女主播视频一区| 欧美日韩一区二区三区在线观看免| 久久综合之合合综合久久| 午夜精品在线视频一区| 肉色超薄丝袜脚交| 竹菊久久久久久久| 久久av红桃一区二区小说| 亚洲成熟少妇视频在线观看| 国产精品综合在线视频| 日韩成人在线资源| av中文字幕在线看| 欧美日韩不卡一区二区| asian性开放少妇pics| 欧美不卡视频| 国产美女被下药99| 日本一区二区三区在线观看视频| 日韩美女久久久| 久草福利视频在线| 亚洲精品亚洲人成在线观看| 欧美国产日韩一区二区在线观看| 伊人免费在线观看| 久久人人超碰精品| 波多野结衣乳巨码无在线| 韩国三级大全久久网站| 国产亚洲福利一区| 天堂中文在线网| 成人精品国产一区二区4080| 美女在线免费视频| 婷婷激情成人| 日韩一区二区av| 日韩xxx视频| 久久蜜桃av一区精品变态类天堂| 一卡二卡三卡视频| 日韩区一区二| 精品中文字幕乱| 99在线观看精品视频| 国产精品久久久久精k8| 成年网站在线播放| 国产精品亚洲人成在99www| 国产91精品久久久久久久| 日韩在线视频观看免费| 亚洲成人动漫av| 亚洲啪av永久无码精品放毛片| 欧美欧美全黄| 99视频日韩| 色屁屁www国产馆在线观看| 日韩视频一区二区| 免费在线视频观看| 成人国产在线观看| a在线视频观看| 亚洲香蕉视频| 国产精品免费一区豆花| 日本三级在线视频| 欧美一级xxx| 久久久久久久久99| 99精品1区2区| 成人性做爰aaa片免费看不忠| 久久超碰99| 国产欧美 在线欧美| 精品51国产黑色丝袜高跟鞋| 日韩一区二区免费在线观看| 久草视频免费播放| 不卡视频在线看| 男人日女人bb视频| 欧美日韩一二| 成人免费xxxxx在线观看| 日本小视频在线免费观看| 亚洲第一区第二区| 青青视频在线免费观看| 国产精品三级久久久久三级| theporn国产精品| 在线欧美不卡| 日本一区二区三区四区高清视频| 久久精品国产福利| 欧美激情极品视频| 天堂中文字幕在线| 欧美理论片在线| 精品少妇一二三区| 久久精品视频免费观看| 午夜国产一区二区三区| 欧美日本一区二区高清播放视频| 精品欧美一区二区在线观看视频 | 欧美日韩国产一区在线| 老司机精品免费视频| 国产经典欧美精品| 国产真实乱子伦| 国产精品99久久| 国产综合色一区二区三区| 日韩精品第一| 欧美黑人一级爽快片淫片高清| 青青免费在线视频| 欧美精品亚洲二区| 毛片视频网站在线观看| 亚洲欧美日韩在线| 乐播av一区二区三区| 国产精品自在欧美一区| 欧美黄色免费影院| 欧美区国产区| 色综合视频二区偷拍在线| 99精品国产一区二区三区2021| 国产精品久久久久不卡| 成年男女免费视频网站不卡| 日韩视频免费在线观看| 亚洲aaa在线观看| 欧美一区二区三区免费视频| 亚洲自拍一区在线观看| 亚洲午夜久久久久中文字幕久| 俄罗斯毛片基地| 2021国产精品久久精品| 丰满人妻一区二区三区大胸| 毛片av一区二区| 国产高清精品在线观看| 欧美网站在线| 中文字幕欧美日韩一区二区三区| 国产成人影院| 国产一区二区在线观看免费播放| 精品一区二区三区中文字幕视频| 国产成人精品优优av| 日本午夜大片a在线观看| 九九精品在线播放| 老司机精品视频在线观看6| 亚洲午夜性刺激影院| 亚洲 国产 欧美 日韩| 精品国偷自产国产一区| 国产日韩精品suv| 欧美色电影在线| 精品久久久久久久久久久国产字幕| 精品动漫一区二区三区| 久久一区二区三| 亚洲欧美电影院| 99鲁鲁精品一区二区三区| 久久久五月婷婷| 免费中文字幕av| 337p粉嫩大胆色噜噜噜噜亚洲| 奇米777第四色| 成人免费高清在线| 欧美午夜精品一区二区| 国产激情视频一区二区三区欧美| 在线能看的av网站| 蜜臀av一区二区在线免费观看| 日本新janpanese乱熟| 丝袜亚洲另类欧美综合| 蜜臀av午夜一区二区三区| 国产日韩欧美三区| 国产免费黄视频| 米奇777在线欧美播放| 国产v亚洲v天堂无码久久久| 久久最新视频| 性欧美videossex精品| 久久精品国产精品亚洲红杏| www.se五月| 国产一二三精品| 中国免费黄色片| 99视频热这里只有精品免费| 爱爱免费小视频| 久久久精品免费观看| www.99热| 亚洲日韩欧美一区二区在线| 国产三级国产精品国产国在线观看| 亚洲免费视频成人| 国产乡下妇女做爰| 欧美午夜www高清视频| 久久精品视频2| 欧美日韩精品一区二区天天拍小说 | 日韩免费视频| 亚洲精品偷拍视频| 国产精品99免费看| 热99这里只有精品| 日韩不卡一区二区三区| 国产探花在线观看视频| 成人午夜看片网址| 五月天精品视频| 国产精品国产三级国产aⅴ中文 | aaaaaaaa毛片| 97精品超碰一区二区三区| 欧美黄色一级生活片| 亚洲三级在线免费观看| 亚洲精品77777| 欧美色偷偷大香| 亚洲精品福利网站| 国产亚洲成av人片在线观看桃| 二区在线播放| 欧美亚洲在线播放| www一区二区三区| 精品久久久久久一区| 国产一区二区三区电影在线观看| 波多野结衣 作品| 久久精品麻豆| 久久久精品人妻一区二区三区| www激情久久| 加勒比婷婷色综合久久| 日韩欧美一区视频| av中文在线观看| 国产亚洲精品久久久久久| 羞羞的视频在线观看| 国产精品极品在线| 大型av综合网站| 国产精品夜夜夜爽张柏芝| 亚洲欧美网站| 激情小说欧美色图| 国产精品久久久久久妇女6080| 国产高潮久久久| 日韩视频不卡中文| 成人三级黄色免费网站| 91精品国产91久久久久福利| 国产亚洲观看| 天天综合色天天综合色hd| 亚洲免费高清| 91成人在线观看喷潮蘑菇| 国产午夜精品久久久久久久 | 午夜精品福利一区二区蜜股av| 亚洲视频久久久| 亚洲精品一二区| 123区在线| 国产精品av一区| 欧美在线免费| 午夜xxxxx| 日本一区二区三区四区在线视频 | 91久久国产综合久久蜜月精品| 精品日本12videosex| 97xxxxx| 99精品国产91久久久久久 | 国产专区在线播放| 57pao成人国产永久免费| 国产亚洲成av人片在线观黄桃| 久久天天东北熟女毛茸茸| 激情久久久久久久久久久久久久久久| 变态另类ts人妖一区二区| 一本久久精品一区二区| 欧美女子与性| 国产精品777| 欧美综合另类| 午夜两性免费视频| 国产精品天天看| 一区二区三区免费观看视频| 色悠悠久久久久| 91国拍精品国产粉嫩亚洲一区 | 欧美久久视频| 人妻 丝袜美腿 中文字幕| 亚洲在线视频一区| 亚洲大尺度网站| 欧美激情在线观看| 久久资源综合| 久热免费在线观看| 欧美国产禁国产网站cc| 伊人精品一区二区三区| 久久夜精品va视频免费观看| 日韩精品视频在线看| 欧美成人精品免费| 99久久婷婷国产综合精品| 国产精品视频123| 亚洲欧美国产精品va在线观看| 日韩漫画puputoon| 一区二区视频在线免费| 国产乱妇无码大片在线观看| 国产精品7777| 亚洲欧美综合区自拍另类| 成人一级视频| 久操手机在线视频| 97国产一区二区| 国产精品第6页| 美女黄色丝袜一区| 欧美有码在线| 乌克兰美女av| 亚洲激情在线播放| 岳乳丰满一区二区三区| 国产一区二区三区三区在线观看| а√天堂资源国产精品| 91网站在线观看免费| 极品少妇一区二区| 黄色一级视频免费| 亚洲国产精品99| 久久野战av| 日韩欧美一级在线| 不卡视频在线观看| 中文字幕无线码一区| 超碰91人人草人人干| 一区二区三区视频免费观看| 日本999视频| 天天色图综合网| 国产爆初菊在线观看免费视频网站| 91久久精品美女| 亚洲作爱视频| 国产探花在线免费观看|