内容


使用 Java、Ajax 和 Cloudant 构建一个 Hangman 游戏

Comments

您是否玩过 Hangman 游戏,一个用纸和铅笔的猜测游戏?现在您将学习如何编写自己的在线 Hangman 游戏,该应用程序在游戏中模拟您的对手。我将介绍如何使用 IBM® Bluemix™ 中的两个服务(Liberty for Java™ 运行时和 Cloudant NoSQL 数据库)来构建该应用程序的步骤。

完成您的应用程序的前提条件

运行应用程序获取代码

您将创建该应用程序的后端和前端,并修改 web.xml 文件。

如果只想了解使用 Bluemix 服务有多么轻松,那么您可以获取这些代码并执行第 1、2、3 和 5 步。要想更有趣一些,可以执行第 4 步,了解该应用程序如何使用 JSP 技术、servlet、Ajax、CSS、JavaScript 和 Cloudant 连接。

第 1 步:在 Bluemix 中创建一个 Java Web 应用程序

  1. 登录到 Bluemix
  2. 在目录中,单击 Runtimes 下的 Liberty for Java
  3. 选择并输入应用程序名称和主机名,然后选择 Default 作为您的计划。单击 Create
  4. 在目录中,单击 Data Management 下的 Cloudant NoSQL DB。从列表中选择您的应用程序,然后选择 Shared 作为您的计划。单击 Create
  5. 在仪表板中,单击应用程序转到它的概述页面:Bluemix 仪表板中的 Hangman 应用程序条目的屏幕截图
    Bluemix 仪表板中的 Hangman 应用程序条目的屏幕截图

第 2 步:填充 Cloudant NoSQL DB 数据库

  1. 在应用程序概述页面中,单击 Development Services 下的 Cloudant NoSQL DB 服务。
  2. 单击 Launch 启动 Cloudant 控制台。
  3. 单击菜单中的 Databases 并单击 Add New Database 添加两个名为 categoryword 的数据库。
  4. 使用 New > Document 菜单项,将以下文档(逐个)添加到 category 数据库中:
    {"_id":"0","name":"Animals"}
    {"_id":"1","name":"Food"}
    {"_id":"2","name":"Music"}
    {"_id":"3","name":"Movies"}
    {"_id":"4","name":"Names"}
    {"_id":"5","name":"Video Games"}
  5. 将以下文档(逐个)添加到 word 数据库中:
    {"name":"CAIMAN","category_id":"0"}
    {"name":"BEAR","category_id":"0"}
    {"name":"CARROTS","category_id":"1"}
    {"name":"AVOCADO","category_id":"1"}
    {"name":"LEOPOLDO","category_id":"4"}
    {"name":"ISMAEL","category_id":"4"}
    {"name":"LOREN","category_id":"4"}
    {"name":"SPACE RUN","category_id":"5"}
    {"name":"WATCH DOG","category_id":"5"}

第 3 步:下载入门应用程序包

  1. 在应用程序概述页面中,单击 VIEW QUICK STARTView Quick Start 按钮的屏幕截图
    View Quick Start 按钮的屏幕截图
  2. 单击 Download the starter application package 链接并将该文件保存在本地 PC 中。

第 4 步:构建您的应用程序

在这一步中,您将创建该应用程序的后端和前端,并修改 web.xml 文件。(单击本教程开头的获取代码按钮下载完整的 CSS 文件、JavaScript 文件、Java 类和该应用程序所需的所有文件。)

准备好要用的环境

  1. 在您的 IDE 中创建一个新的 Java 动态 Web 项目。
  2. 将入门应用程序包导入到项目中。
  3. 将 org.ektorp.jar 文件添加到项目的库文件夹中 (WEB-INF/lib)。另外,还需要添加库依赖关系。所有这些库都可以通过本教程的获取代码按钮从 DevOps Services 获得。

创建后端

  1. 创建 Category.java 和 Word.java 类,设置以下属性:
    • CategoryString idString revisionString name
    • WordString idString revisionString nameString category_id
  2. 创建 getter 和 setter 方法。使用 @JsonIgnoreProperties@JsonProperty 注释,这会导致忽略对 JSON 属性的处理:
    @JsonIgnoreProperties({"id", "revision"})
    
    public class Category {
       
       @JsonProperty("_id")
       private String id;
       
       @JsonProperty("_rev")
          private String revision;
  3. 创建 CategoryRepository.java 和 WordRepository.java 类。在这些类中,扩展 CouchDbRepositorySupport<T> 类,这是一个一般性的存储库支持类,提供了一个持久性类的所有创建、读取、更新和删除操作。在这些类中,添加了以下构造函数:
    public CategoryRepository(CouchDbConnector db) {
         super(Category.class, db);
    }
  4. 创建 CloudantConnection.java 类。使用来自您的运行时的 VCAP_SERVICES 环境变量设置构造函数中的连接:
    JSONObject obj = new JSONObject(System.getenv("VCAP_SERVICES"));
       String[] names = JSONObject.getNames(obj);
    
       if (names != null) {
       for (String name : names) {
          if (name.equals("cloudantNoSQLDB")) {
          JSONArray val = obj.getJSONArray(name);
          JSONObject serviceAttr = val.getJSONObject(0);
          JSONObject credentials = serviceAttr.getJSONObject("credentials");
          httpClient = new StdHttpClient.Builder()
             .url(credentials.getString("url"))
             .build();
          break;
          }
          }
       }

    可以在 Liberty for Java 运行时概述中找到您的环境变量。VCAP_SERVICES 变量拥有所有数据库信息(用户名、密码、主机、端口和 URL);如果单击 Cloudant 服务下的 Show Credentials,就会看到以下信息: Cloudant 凭据信息的屏幕截图
    Cloudant 凭据信息的屏幕截图
  5. 创建 getCategories()getWords() 方法,以便从 Cloudant 数据库中获取数据。您将使用存储库类来读取数据:
    public List<Word> getWords(){
       CouchDbInstance dbInstance = new StdCouchDbInstance(httpClient);
       CouchDbConnector db = new StdCouchDbConnector("word", dbInstance);
       WordRepository wordRepo = new WordRepository(db);
       return wordRepo.getAll();
    }
  6. 创建 getWordsByCategory()getRandomWordByCategory() 方法,以便按照类别获取单词列表和每个类别中的一个随机单词。在 getWordsByCategory() 方法中,可以调用 getWords() 方法来获取可用的单词,然后迭代该列表,按照类别查找单词。在 getRandomWordByCategory() 中,创建一个随机数来选择将在游戏中使用的单词:
    List<Word> words = this.getWordsByCategory(category_id);
    Random generator = new Random();
    if(words.size()>0){
       int random = generator.nextInt(words.size());
       word = words.get(random);
    }

    我使用 Random 对象(包含在 java.util 包中)随机创建了一个整数值。
  7. 创建 LoadIndex.java servlet,可以使用它将类别信息加载到索引网页中。仅在使用 CloudantConnection 类的地方才需要使用 doGet() 方法:
    CloudantConnection cloudantConnection = new CloudantConnection();
    List<Category> categories = cloudantConnection.getCategories();
    request.setAttribute("categories", categories);   
     request.getRequestDispatcher("index.jsp").forward(request, response);
  8. 创建 LoadGame.java servlet。使用 doPost() 方法并使用这个随机单词来设置 HttpServletResponse。这个随机单词是通过发送到 HttpServlerRequest 中的类别生成的:
    String action = request.getParameter("action");
    String value = request.getParameter("value");
    
    if ((action != null)&&(value != null)) {
     CloudantConnection cloudantConnection = new CloudantConnection();
     Word word = cloudantConnection.getRandomWordByCategory(value);
     if(word!=null){
        response.setContentType("text/html");
        response.getWriter().write(word.getName());
     }
    }

    您将使用此方法来完成 Ajax 实现。

创建前端

  1. 创建 index.jsp 文件并将它导入所需的库:
    <%@ page import="java.util.List" %>
    <%@ page import="com.bluemix.hangman.model.Category" %>
  2. 添加对 CSS 和 JavaScript 文件的引用:
    <link rel="stylesheet" href="style.css" />
    <script src="index.js"></script>
    <script src="dojo.js"></script>
  3. 在主体中,添加 <div> 标记和 <select> 下拉列表。该列表将填入您从 LoadIndex servlet 获得的类别列表。另外添加 <img><table> 标记(它们现在是空的,会动态地得到填充):
    <div id="menu">
          <select onChange="javascript:loadWord(this.value);">
          <option value="">Select category</option>
          <%  List<Category> categories = (List<Category>) request.getAttribute("categories");
          for(int index=0; index<categories.size(); index++){
           %>
          <option value="<%=categories.get(index).getId()%>"
          ><%=categories.get(index).getName() %></option>
          <%
          }
           %>
        </select>
    </div>
    <div id="content">
       <img id="hangmanImage" style="visibility:hidden"><br><br>
       <table id="wordTable"></table><br>
       <table id="lettersTable"></table>
       </div>
  4. 创建 style.css 文件来提供 <table><div><a> 标记的 CSS 样式。样式类将会显示游戏中使用的字母表的字母。(请记住,通过使用 class="myclassname",可以向任何 HTML 元素应用样式类。)
  5. 创建 index.js JavaScript 文件。定义全局变量并将 dojo.js 文件复制到 WebContent 文件夹中。添加 loadWord 函数,可以使用该函数通过 Dojo 功能实现 Ajax。此函数用于从 LoadGame servlet 获取一个单词:
    function loadWord(category) {
       dojo.xhrPost({
          url: "game.do",
          postData: "action=loadWord&value="+category,
          handleAs: "text",
          load: function(text){
                updateWord(text);
          },
          error: function(error){
                alert(error);
          }          
       });
    }

    在对 updateWord 函数的 loadWord 函数调用中,初始化这些 JavaScript 变量,并调用其他函数来动态地填充 index.jsp 文件中定义的 HTML 标记。在这里,<img> 标记是使用 document.getElementById() JavaScript 方法填充的,指示一个新游戏已经开始:
    document.getElementById("hangmanImage").style.visibility = "visible";
    loadWordTable 函数用于在 UI 中添加要猜测的单词。string.split(separator) JavaScript 方法用于统计单词的字符和空格数。loadLettersTable 函数用于打印将在玩游戏时使用的字母表的字母。updateImage 函数用于更新 UI 中的图像。您可以看到,document.getElementById("elementId") 用于访问 HTML 元素并更新它们:
    var table = "<tr>";
    for(var index=0; index<word.split('').length; index++){
       table += "<td ><a id='wordLetter"+index+"' class='wordLetter'>_</a></td>";
    }
    table += "</tr>";
    document.getElementById("wordTable").innerHTML = table;\
  6. 创建函数来控制和更新游戏状态。verifyLetter 函数(在用户单击字母表的一个字母时调用)将会检查还剩多少次机会。updateGame 函数检查该字母是否存在于该单词中并更新图像、字母表的字母和正确的字母状态。再次使用 split(separator) JavaScript 方法来将一个字符串拆分为一个子字符串数组。在本例中,该方法使用一个空字符串作为分隔符,所以原始字符串会在每个字符之后被拆分:
    var wordSplit = globalWord.split('');
    for(var index=0; index<wordSplit.length; index++){
           if(letter == wordSplit[index]){
       document.getElementById("wordLetter"+index).innerHTML = wordSplit[index];
       correctLetters+=1;
       find = true;
        }
    }
  7. 在 WebContent 文件夹中创建 img 文件夹并添加图像。

编辑 web.xml 文件

  1. 在 web.xml 文件中配置 LoadIndexLoadGame servlet:
    <servlet>
        <servlet-name>LoadIndex</servlet-name>
        <servlet-class>com.bluemix.hangman.controller.LoadIndex</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>LoadGame</servlet-name>
        <servlet-class>com.bluemix.hangman.controller.LoadGame</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoadIndex</servlet-name>
        <url-pattern>/play.do</url-pattern>
    </servlet-mapping>
       <servlet-mapping>
        <servlet-name>LoadGame</servlet-name>
        <url-pattern>/game.do</url-pattern>
    </servlet-mapping>
  2. 调用 LoadIndex servlet 来指定 Web 应用程序的默认页面:
    <welcome-file-list>
        <welcome-file>play.do</welcome-file>
    </welcome-file-list>

第 5 步:运行该应用程序

  1. 编译 Java Web 项目并生成 WAR 文件。
  2. 从命令行转至您保存 WAR 文件的目录。
  3. 运行 cf api bluemix_domain 来连接到 Bluemix。
  4. 使用 cf login -u username 登录到 Bluemix,并运行 cf target -o username -s space 来指向您的环境(Bluemix 空间)。
  5. 运行 cf push appname -p appname.war 命令来部署该应用程序。

现在可以在您的 Bluemix 域(比如 http://hangmangame.mybluemix.net)中访问该应用程序并玩这个游戏了:

完成了一部分的游戏的屏幕截图
完成了一部分的游戏的屏幕截图

结束语

通过使用 Bluemix,可以快速部署和管理您的云应用程序。我仅使用了一个运行时和一个服务来在云中部署 Hangman 应用程序,但 Bluemix 中有一个庞大的软件组合可供您使用。立即行动!


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Java technology, Cloud computing
ArticleID=985706
ArticleTitle=使用 Java、Ajax 和 Cloudant 构建一个 Hangman 游戏
publish-date=10162014