使用 PHP 在 CICS 上构建 REST 服务

CICS® Transaction Server® (TS) 是一个强大的事务管理器,它的特点是能够快速处理大量数据。SupportPac CA1S 借助 IBM WebSphere® sMash 技术,使用 PHP 脚本功能和与 REST 相关的特性增强 CICS TS。本教程演示如何使用 PHP 快速轻松地处理 CICS 程序,并将其公开到 Web。如果您是 PHP 开发人员,那么想想如何利用您的技术在 CICS 中与企业资产进行交互;如果您是 CICS 开发人员,那么看看 PHP 如何为管理现有资源提供一种简单便捷的方式。

Robin Fernandes, 软件开发人员, IBM

/developerworks/i/p-rfernandes.jpgRobin Fernandes 在 2003 年从 Imperial College 毕业之后,就加入位于英国 Hursley 的 IBM Java Technology Centre,从事软件开发。他目前主要研究针对 PHP 的基于 Java 的运行时,该运行时用于 CA1S SupportPac 和 WebSphere sMash。他还定期在 php.net 上发表测试用例和补丁,并且喜欢在空闲时间研究音频软件。



Jonathan Lawrence, 软件开发人员, IBM

/developerworks/i/p-jlawrence.jpgJonathan Lawrence 在位于英国 Hursley 的 Software Services 部门做了 4 年的 CICS 和跨平台集成专家之后,于 2006 年加入 IBM 在 Hursley 的 Java Technology Centre,从事软件开发。他设计 CA1S SupportPac 的 CICS 集成。



2009 年 6 月 22 日

开始之前

本教程展示如何使用 CICS SupportPac CA1S 和 PHP 快速在 Web 上公开 CICS COMMAREA 程序。PHP 是一种简单强大的语言,用于快速开发 Web 应用程序。您将使用 REST 和 JavaScript Object Notation (JSON) 创建一个 Web 服务,并确保各种客户端能够方便地使用它,比如 Asynchronous JavaScript and XML (Ajax) 前端、其他 Web 服务和混搭应用程序。

本教程的示例 CICS COMMAREA 程序(见 下载)是一个用 COBOL 编写的简单书库应用程序。它在 VSAM 文件中包含一个图书列表,您可以在这个列表上添加、删除条目,或将图书标记为已借出或已返还。

在本教程中您将:

  • 在 CICS 系统上设置书库应用程序。
  • 了解如何通过 PHP 调用 CICS COMMAREA 程序。
  • 了解 CA1S 中能够简化 REST 式 Web 服务创建的特性。
  • 将书库程序公开为 REST 式 Web 服务。

先决条件

为了从本教程获取最大收益,您应该具有 PHP 语言的基础知识,并熟悉 CICS 管理或 CICS 程序的开发。如果要详细了解 CICS,请访问 CICS TS 3.2 Information Center。您应该阅读 CA1S 用户指南的介绍部分,它简单概括了 CA1S 的用途和 REST 的原则。(从 参考资料 部分可以获得这些指南和文档的链接)。

CICS 环境

为了完成本教程的示例,您需要一个 CICS 环境,并且必须满足 CA1S 下载页面 列出的条件。

根据 CA1S 用户指南 提供的说明,下载并安装 CA1S SupportPac。根据指南中的说明,调用 HelloCICS.php 脚本检测您的安装。

工具

  • 所有文本编辑器都可以用来编写 PHP 脚本。您可以使用 IDE,比如 Eclipse PDT。
  • 您需要一个将 PHP 脚本从工作台传输到 CICS 服务器的机制,比如一台 FTP 客户机或针对 Eclipse 的 Target Management 插件。
  • 为了测试 REST 式 Web 服务,您需要一个简单的 REST 客户端(比如 Poster add-on for Mozilla Firefox),用于发出 GETPOSTPUTDELETE HTTP 请求。

可以从 参考资料 小节找到并下载提到的所有工具。


在 CICS 中设置书库应用程序

这个部分概述在 CICS 中安装示例 LIBRARY 应用程序所需的管理任务,并描述如何从客户端上对该程序使用 COMMAREA 接口。必须使用这个接口编写用于访问书库程序的 PHP 脚本。

设置书库应用程序的步骤

书库应用程序要求创建并填充一个 VSAM 文件,并编译一个 COBOL 程序。同时也需要该文件和程序的 CICS 资源定义。下面详细描述这些步骤。假设您具有关于 CICS 配置流程的基础知识。

除了 PHP 之外(后文将就此进行讨论),还没有其他可以调用 LIBRARY 程序的机制(尽管您可以开发一个)。因此,用于验证文件和程序是否正确安装的方法还很少。由于这个原因,设置说明建议使用 CEMT 手动打开文件和加载程序,这样做可以检查这些定义。

创建和定义 VSAM 文件

示例书库程序需要一个 VSAM KSDS,用于保存目录内容。代码归档中的 library/jcl/LIBFILE 文件包含用于删除和重新创建所需数据集的示例 JCL,并使用适合的原始数据填充数据集。这个 JCL 必须传输到 z/OS® 系统的适当位置,并做出以下更改:

  • 使用适合您的环境的 JOB 卡替换原来的 JOB 卡。
  • 使用适合您的系统的数据集名称替换原来的数据集名称的所有实例(P8BUILD.CICS650.LIBRARY.LIBFILE)。在后面的 CICS FILE 定义中需要用到这里选择的名称。
  • 可选。您可以编辑书库的原始数据,保持一致性和完整性(见下面的解释)。

下面的步骤将完成 VSAM 文件的创建和定义:

  1. 提交前面修改的 LIBFILE JCL,并检查是否成功执行。
  2. 登录 CICS,并使用带有以下属性的 CEDA(或其他机制)创建一个 CICS FILE 定义:

    表 1. 创建 VSAM FILE 定义时使用的属性
    属性
    FILE LIBFILE
    GROUP LIBRARY
    DSName <As specified in LIBFILE JCL>
    RECORD FORMAT F
    ADD Yes
    BROWSE Yes
    DELETE Yes
    READ Yes
    UPDATE Yes
  3. 安装 LIBFILE 定义,并检查是否成功。
  4. 可选。使用 CEMT,或打开 LIBFILE 并检查是否成功打开:
    CEMT SET FILE(LIBFILE) OPEN

    建议使用这个步骤检查是否正确创建和定义文件,因为设置的检查可能不全面。

编译和定义 COBOL 程序

LIBRARY 应用程序的源代码位于 library/cobol/LIBRARY 文件中,用于编译源代码的示例 JCL 位于 library/jcl/LIBCOBOL 文件中,它们都包含在本文提供的示例代码压缩文件中。必须将这些文件传输到您的 z/OS 系统的适当位置,并且需要根据以下说明修改 LIBCOBOL JCL。提供的版本如下所示:

清单 1. 用于编译 LIBRARY 程序的 JCL
//LIBCOBOL JOB USER=P8BUILD,CLASS=A,MSGCLASS=A,NOTIFY=&SYSUID
// JCLLIB ORDER=CTS320.CICS650.SDFHPROC
//COMPCOB EXEC DFHZITCL,
//        PROGLIB=P8BUILD.CICS650.LOAD,
//        LNGPRFX=PP.COBOL390.V340,
//        CBLPARM=('NODYNAM,LIB,ADATA,RENT',  COMPILER OPTIONS
//          'CICS(''COBOL2,SP'')'),       TRANSLATOR OPTIONS
//        INDEX=CTS320.CICS650,
//        LIBPRFX=PP.ADLE370.ZOS190,
//        DSCTLIB=P8BUILD.CICS650.COPY
//COBOL.SYSIN  DD DSN=P8BUILD.CICS650.COBOL(LIBRARY),DISP=SHR
//COBOL.SYSADATA DD DSN=P8BUILD.CICS650.COBADATA(LIBRARY),
//        DISP=SHR
//LKED.SYSIN DD *
   NAME LIBRARY(R)
/*

需要做出以下更改:

  • 提供一个适合的 JOB 卡。
  • 更改所有数据集名称和前缀,让它们适合您的 z/OS 和 CICS。
  • 确保 COBOL.SYSADATA DD 定义指向一个带有可变长度记录的 PDS 成员,它适合保存 ADATA 输出。请参考 COBOL 编译器文档了解更多细节。

通过以下步骤完成 LIBRARY 应用程序的编译和安装:

  1. 提交前面修改的 LIBCOBOL JCL,并检查是否成功执行。
  2. 登录 CICS 并使用 CEDA(或其他机制)创建一个具有以下属性的 CICS PROGRAM:

    表 2. CICS PROGRAM 属性
    属性
    PROGRAM LIBRARY
    GROUP LIBRARY
    Language COBOL
  3. 安装 LIBRARY 程序定义并检查是否成功。
  4. 可选。对 LIBRARY 程序使用 CEMTNEWCOPY,并检查它是否加载:
    CEMT SET PROGRAM(LIBRARY) NEWCOPY

    建议使用这个步骤检查该程序是否正确编译和定义,因为设置的检查可能不全面。

如何使用 COBOL Library 应用程序

CICS COMMAREA 应用程序的一个约定是,当被调用时,将向它传递一个包含输入数据的储存区域,有时也包含需要执行的操作的说明。在处理完成之后,将使用输出数据和来自该操作的响应代码覆盖存储区域。COMMAREA 存储区域的格式通常在一个 COBOL Copybook 中定义,后者包含在目标程序及其调用方中。

要使用这样的 CICS 程序,您不仅要了解该程序输入输出时所需的 COMMAREA 格式,还需要了解它支持的操作、期望的输入输出数据和响应代码。在 CA1S 中,由 JZOS 生成的记录类执行 COMMAREA 的数据结构的构建和解释。不过,PHP 应该负责设置所需的输入字段,并使用 JZOS 生成的 API 提取合适的输出数据。

本文提供的示例 Library 应用程序遵循这个标准模式,因此 PHP 程序员需要了解生成的 JZOS 记录类和 COMMAREA 接口的使用,以便能够从 PHP 脚本正确地调用 Library 应用程序。

书库的 COMMAREA 格式

下面展示了定义书库应用程序使用的 COMMAREA 格式的 COBOL 数据定义:

清单 2. 书库应用程序的 COBOL 数据定义
      01 DFHCOMMAREA.                                             
     *    LIBRARY COMMAREA structure                              
          03 LIB-REQUEST-TYPE          PIC X(6).                  
          03 LIB-RETURN-CODE           PIC 9(2).                  
          03 LIB-ITEM-COUNT            PIC 9(4).                  
          03 LIB-BOOK-ITEM OCCURS 24 TIMES.                       
              05 BOOK-ITEM-REF          PIC 9(4).                 
              05 BOOK-TITLE             PIC X(20).                
              05 BOOK-AUTHOR            PIC X(20).                
              05 BOOK-LOAN-STATUS       PIC 9(2).                 
                 88 BOOK-ONLOAN VALUE 1.                          
                 88 BOOK-UNLENT VALUE 0.                          
              05 BOOK-BORROWER          PIC X(20).                
              05 FILLER                 PIC X(14).

JZOS 记录生成器工具(随后介绍)将清单 2 中的定义转换成可以从 PHP 使用的 API,以从 COMMAREA 获取或设置字段。COBOL 中使用的字段名和 PHP 方法之间有一个直观的映射,因此可以将它们关联起来。

书库应用程序的使用

您只需了解目标 CICS 程序所需的 COMMAREA 格式,就能够正确调用该程序。此外,还需要程序的使用信息,比如程序支持什么操作,如何在 COMMAREA 中指定它们,每个操作的其他输入和输出,以及可能的结果和响应。清单 3 给出了书库应用程序的参考使用信息。

因为本文提供了调用书库应用程序所需的示例 PHP 脚本,所以您在首次设置时不需要这些信息,但您在理解、修改和重新实现脚本时,必须参考这些信息。

LIB-REQUEST-TYPE 是一个包含 6 个字符的文本字段,它决定书库应用程序将要执行的操作。在调用书库应用程序之前,必须将这个字段设置为以下值之一:

表 3. 书库应用程序的 LIB-REQUEST-TYPE 字段
LIB-REQUEST-TYPE书库操作
LIST通过数组 LIB-BOOK-ITEM 返回一个列出库中所有图书的列表。
库的最大容量最多只能包含 24 个元素。每个项都包含相关图书的完整细节。现有的图书数目由 LIB-ITEM-COUNT 返回。
QUERY 在第一个元素 LIB-BOOK-ITEM(1) 中返回指定图书的细节。
BOOK-ITEM-REF(1) 中输入所请求的图书的索引(参考)。
ADD向书库添加一本新书;在 LIB-BOOK-ITEM(1) 中提供细节。假设库中还有空间(最大图书储存数为 24 本),新书的索引由 BOOK-ITEM-REF(1) 返回。
DELETE从库中(如果存在的话)删除由 BOOK-ITEM-REF(1) 标识的图书。
BORROW将由 BOOK-ITEM-REF(1) 指定的图书标记为正在借阅,并向这本书的记录中添加借阅者的名称(BOOK-BORROWER(1))。
RETURN将指定的书标记为未借阅,并从这本书的记录中删除借阅者的名字。由 BOOK-ITEM-REF(1) 标识将要返回的图书。

对于图书返回,书库应用程序根据请求操作的结果将 LIB-RETURN-CODE 设置为 2 位数字值:

表 4. 书库应用程序的返回代码
LIB-RETURN-CODE含义
LIB-RETURN-CODE含义
文件名操作条件
LIBRARY-OK0All成功完成。
LIBRARY-NOTFOUND1All except LIST, ADD在库中未找到指定的图书。
LIBRARY-ONLOAN2BORROW图书已经借出。
LIBRARY-DUPLICATE3Not used不应该发生。
LIBRARY-INVREQ 4 All 无效的用户请求。
LIBRARY-FULL 5ADD书库已满(最多只能储存 24 本书!)
LIBRARY-ERROR 99 All 意外处理错误。

在书库应用程序的 level-01 数据部分 (LIBRARY-CONSTANTS) 定义可用的请求类型和返回代码,这意味着可以通过 JZOS 记录生成器在 PHP 脚本中使用它们,实现方法与 COMMAREA 数据类似。

总体而言,如果要从 PHP 调用 CICS 程序,PHP 程序员需要具有等价于表 4 的信息,这些信息通常由维护该程序的 CICS 程序员以适当的形式提供。


从 PHP 调用书库应用程序

使 PHP 可以访问 COMMAREA

在 COBOL 程序中定义 COMMAREA 并生成 ADATA 之后,下一步就是创建用于表示 COMMAREA 的 Java™ 类。这些类使 PHP 脚本可以访问 COMMAREA。

这些 Java 类仅需生成一次:只要 CA1S 可以使用这些类,就可以编写任意脚本通过它们与 COBOL 程序交互。然而,如果修改 COBOL 程序导致改变了 COMMAREA,那么就要重新生成 ADATA 和 Java 类,并根据需要修改 PHP 脚本。

下面的步骤需要使用 Java SDK,并假设在系统 PATH 上可以使用 javajavac 命令。您可以在工作台上执行它们,或直接在 CICS 系统上执行它们。

1. 生成 COMMAREA 类的源代码

java -cp jzos_recgen.jar com.ibm.jzos.recordgen.cobol.RecordClassGenerator genCache=false 
adataFile=LIBRARY symbol=DFHCOMMAREA class=Library_Commarea package=library outputDir=.

我们看看以上命令的各部分的作用:

java -cp jzos_recgen.jar com.ibm.jzos.recordgen.cobol.RecordClassGenerator

这将调用 JZOS 记录生成器,这是一个包含在 jzos_recgen.jar 文件中的 Java 程序。这个文件包含在 CA1S 中,在 alphaWorks 的 IBM JZOS Batch Toolkit for z/OS SDKs 站点上可以找到最新的版本(见 参考资料)。

为什么运行 JZOS 记录生成器时遇到 Java 异常?

在使用 FTP 获取 ADATA 之前,记得运行命令 quote site rdwbin

要了解更多信息,请阅读 JZOS 文档 “Running the COBOL RecordClassGenerator”,即 CA1S 包中的 “JZOS Cobol Record Generator Users Guide.pdf”。

genCache=false

这个选项确保生成的 Java 代码不尝试缓存 COMMAREA 字段的值。CA1S 需要用这个选项与生成的类正确地进行交互。

adataFile=LIBRARY

这指定前一小节中的 ADATA 文件的路径。

symbol=DFHCOMMAREA

这指定需要为它生成类的 COMMAREA 的名称。

class=Library_Commarea

这指定生成的 Java 类的名称。

package=library

这指定生成的 Java 类所在的包。

outputDir=.

这指定在文件系统上写入 Java 类的路径。

2. 为表示 COBOL 常量的类生成 Java 源代码

在示例书库应用程序中,COBOL 程序使用的常量(对于操作名和响应代码)是在 WORKING-STORAGE 部分的数据结构中定义的。这意味着可以生成表示这些常量的 Java 类,并以类似于表示 COMMAREA 类的方式从 PHP 使用它们。在这个例子中,是为了在需要时获取已定义常量的值。

java -cp jzos_recgen.jar com.ibm.jzos.recordgen.cobol.RecordClassGenerator genCache=false 
adataFile=LIBRARY symbol=LIBRARY-CONSTANTS class=Library_Constants package=library 
outputDir=.

这种方法的优势是可以使用 PHP 反射检查可用的常量名,因此 PHP 程序员不需要直接引用在 COBOL 中定义的值。记住,可以对 LIBRARY 应用程序执行该操作,这是由定义常量的方式决定的,并且不能保证始终可用;例如,在 COBOL 源代码中嵌入了硬编码的值。

在本文提供的 PHP 脚本中,采用一种混合的方法,其中一些常量以字面的形式使用(比如操作名),另一些常量则使用生成的 Java 类提取(数字响应代码)。

3. 通过编译 .java 源文件创建 Java 类文件

生成的 Java 源文件将储存在前面指定的 outputDir 的子目录中(与包名对应)。使用 javac 按以下方式编译源文件:

javac -cp jzos_recgen.jar library/*

4. 使 CA1S 可以使用类文件

现在,library 目录已经包含已编译的类。这些类必须在 Java 类路径中,CA1S 才能使用它们。如果您在工作台中生成这些类,则需要将目录转移到服务器(例如使用 FTP)。

Java 类路径由 CA1S 使用的 JVMPROFILE 的 CLASSPATH_SUFFIX 属性决定。CA1S 中默认的 JVMPROFILE(名为 CA1SJVMP)已经配置为在 CLASSPATH_SUFFIX 中包含 ca1s/work/classes/ 目录:

CLASSPATH_SUFFIX=/u/p8build/ca1s/config/ini:\
                 /u/p8build/ca1s/p8/jars/p8api.jar:\
                 /u/p8build/ca1s/p8/jars/p8.jar:\
                 /u/p8build/ca1s/p8/jars/p8cics.jar:\
                 /u/p8build/ca1s/work/classes:\
                 /usr/lpp/db2910/classes/db2jcc.jar:\
                 /usr/lpp/db2910/classes/db2jcc_javax.jar:\
                 /usr/lpp/db2910/classes/db2jcc_license_cisuz.jar

因此,如果您使用 JVMPROFILE CA1SJVMP,那么需要将 library 目录复制到 ca1s/work/classes/。或者更改 CLASSPATH_SUFFIX,使其包含一个包含 library 目录的目录或 JAR 文件。

注意,表示包名的目录结构必须位于类路径位置之下。因此,如果您使用 ca1s/work/classes/,则需要复制 library 目录,使类位于 ca1s/work/classes/library 之下(而不是 ca1s/work/classes/)。

最后,退出 JVM 以确保 CA1S 能够使用新的类。

从 PHP 代码访问书库程序

代码

调用 COMMAREA 程序包含 3 个步骤:

  1. 在链接到程序之前准备好 COMMAREA。
  2. 链接到程序。
  3. 从 COMMAREA 获取链接的结果。

为了进行演示,清单 3 的脚本通过调用书库程序获取图书列表,然后打印它们:

清单 3. 从 PHP 调用 CICS Commarea 程序
<?php
// Step 1: create and prepare the COMMAREA instance
java_import('library.Library_Commarea');
$COMMAREA = new Library_Commarea();
$COMMAREA->setLibRequestType('LIST');

// Step 2: create the program instance and invoke it using the COMMAREA
$program = new CICSProgram('LIBRARY');
try {
  $program->link($COMMAREA);
} catch (CICSException $e) {
  echo 'Error: ' . $e->getMessage();
  return;
}

// Step 3: retrieve the result of the link from the COMMAREA
$totalBooks = $COMMAREA->getLibItemCount();
echo "Total number of books: $totalBooks <br/>";

for ($i=0; $i<$totalBooks; $i++) {
  $book = $COMMAREA->getLibBookItem($i);
  $title = $book->getBookTitle();
  $author = $book->getBookAuthor();
  echo "Book $i is '$title' by '$author'. <br/>";
}
?>

为何在浏览器中访问脚本时看到的是乱码?

如果在错误的编码页面中编码脚本将发生这种错误。默认情况下,CA1S 中的 PHP 运行时被配置为使用 UTF-8 编码。因此,如果您在 Windows® 或 Linux® 工作台和 CICS 服务器之间传输脚本,一定要设置为 “binary” 模式,这样脚本就不会在传输期间被转换为 EBCDIC 编码页面。要更多地了解 CA1S 中的编码注意事项和配置选项,请阅读 CA1S 文档

在示例脚本下载中提供的脚本为 library/scripts/library.php。如果您将这个脚本传输到 CICS 系统的 ca1s/work/scripts/library.php 中,并从浏览器访问它,您将看到一个图书列表:

Total number of books: 18
Book 0 is 'PHP for Beginners ' by 'Rob Nicholson '. 
Book 1 is 'Project Management ' by 'A N IBMer '. 
Book 2 is 'Easy Z Specification' by 'Jonathan '. 
Book 3 is 'REST Protocol Design' by 'Zoe, Ant & Rob '.  
etc...

现在,我们仔细查看代码中包含的 3 个步骤。

准备 COMMAREA
java_import('library.Library_Commarea');

在 CA1S 中为 PHP 运行时内置的 java_import() 函数将加载一个 Java 类,从而使这个类可以在 PHP 中使用。在上面的代码中,我们将加载表示前面创建的书库 COMMAREA 类的 Java 类。

$COMMAREA = new Library_Commarea();

然后,创建这个类的一个实例。这个实例被用作调用的输入和输出数据的容器。

$COMMAREA->setLibRequestType('LIST');

最后,在第三行代码中,我们在 COMMAREA 上设置一些输入数据。setLibRequestType 方法特定于表示本教程的 COBOL 程序的 COMMAREA 的 Java 类:它定义我们希望对书库执行的操作,在这个例子中,是获取一个包含所有图书的列表(LIST)。查看 使用反射研究 COMMAREA,了解如何使用 PHP 发现关于 Java 类的所有方法。

链接到程序
$program = new CICSProgram('LIBRARY');

首先,我们创建内置类 CICSProgram 的一个实例,它表示我们将要与之交互的 CICS 程序。CICS 程序的名称指定为构造器的参数,在这个例子中为 “LIBRARY”。如果重命名程序,那么也要更改这个参数。

为什么看到的不是我想要的结果,而是 “com.ibm.cics.server.InvalidProgramIdException: CICS PGMIDERR Condition”?

仔细检查传递到 CICSProgram 构造器的参数(表示安装在 CICS 系统的 COBOL 程序的名称)。

$program->link($COMMAREA);

CICSProgram 类的 link 方法触发 CICS 程序的执行。如果提供单一的 COMMAREA 参数(如本例),它将被 CICS 程序用作输入和输出数据的容器。您也可能提供两个不同的 COMMAREA 参数,对于这种情况,第一个参数用于包含输入数据,第二个参数用于包含输出数据。此外,也可以不提供参数,当 CICS 程序没有输入和输出时,这种做法很有用。

try / catch block

如果链接失败,或被链接的程序异常终止,那么 link 方法将抛出一个 CICSException。异常对象中的 getMessage() 方法描述失败细节,包括基本 Java 异常的类型。例如,如果将一个无效程序名指定为 CICSProgram 构造器的参数,以上代码将输出:

Error: com.ibm.cics.server.InvalidProgramIdException: CICS PGMIDERR Condition
Retrieving data from the COMMAREA
$totalBooks = $COMMAREA->getLibItemCount();

link() 成功返回之后,COMMAREA 就包含调用的输出。在上面的 PHP 脚本的步骤 3 中,我们使用各种特定于 Library_Commarea 类的方法来获取图书的总数,然后遍历图书列表,并输出每本书的标题和作者。

使用 PHP 反射研究 COMMAREA

如果要在链接之前在 COMMAREA 上设置输入数据,随后从 COMMAREA 获取输出数据,那么需要了解 COMMAREA 类的 setter 和 getter 方法。如果您没有这些方法,可以通过 PHP 反射轻松获得。

例如,下面的脚本使用 PHP 反射类(见 参考资料)获取在 Library_Commarea 类中可用的方法列表:

清单 4. 使用反射,第 1 部分
<?php
java_import('library.Library_Commarea');
$COMMAREA = new Library_Commarea();
$rc = new ReflectionObject($COMMAREA);
foreach ($rc->getMethods() as $method) {
	echo $method->getName() . '<br/>';
}
?>

清单 4 中的脚本的输出为:

Library_Commarea
__tostring
setLibItemCount
getLibReturnCode
setLibRequestType
setLibReturnCode
getByteBuffer
getLibRequestType
getLibBookItemgetLibItemCount

除了 Library_Commarea() 方法(构造器)和 getByteBuffer() 方法(提供对包含 COMMAREA 数据的原始字节数组的访问)之外,其他方法都是 COMMAREA 字段的 getter 和 setter 方法。在最初脚本中使用的方法用粗体表示。

一些 getter 方法返回复杂的数据结构,比如以上的 getLibBookItem() 方法,它返回一个表示一本书的对象。可以将这种技术用于这些数据结构中,找到可以访问的字段。例如,在这里我们使用 PHP 函数 get_class_methods()(见 参考资料)确定一本书的哪些字段是可以访问的:

清单 5. 使用反射,第 2 部分
<?php
// Step 1: create and prepare the COMMAREA instance
java_import('library.Library_Commarea');
$COMMAREA = new Library_Commarea();
$COMMAREA->setLibRequestType('LIST');

// Step 2: create the program instance and invoke the program using the COMMAREA
$program = new CICSProgram('LIBRARY');
$program->link($COMMAREA);

// Investigate the fields available on a book object
$book = $COMMAREA->getLibBookItem(0);
print_r(get_class_methods($book));
?>

清单 5 中的脚本的输出为:

Array
(
    [0] => LibBookItem
    [1] => getBookTitle
    [2] => setBookItemRef
    [3] => isBookOnloan
    [4] => getBookAuthor
    [5] => isBookUnlent
    [6] => getByteBuffer
    [7] => setBookAuthor
    [8] => setBookBorrower
    [9] => getBookLoanStatus
    [10] => getByteBufferOffset
    [11] => getBookBorrower
    [12] => __tostring
    [13] => getFiller_1
    [14] => getBookItemRef
    [15] => setBookTitle
    [16] => setFiller_1
    [17] => setBookLoanStatus
)

使用 phpinfo() 诊断类路径

如果您看到表示找不到 COMMAREA 类的警告或错误,请检查 Java 类路径是否正确,它必须具有一个包含 library 目录(包含生成的类)的 JAR 文件或目录。

这可以使用 PHP phpinfo() 函数直接完成:

<?php 
phpinfo();
?>

在浏览器中访问这个脚本能够显示很多信息,包括完整的类路径:

图 1. 使用 phpinfo() 检查 Java 类路径
显示不同变量设置的示例输出屏幕

classpath.png

phpinfo() 的最常见用法是检查 PHP 环境,它是一个非常有用的工具。


CA1S 中的 REST 基础

SupportPac CA1S 中的 REST 式事件处理程序

概述

WebSphere sMash 引入了一组约定,它们简化了 REST 式 Web 服务的创建(要了解更多信息,请从 参考资料 中阅读 WebSphere sMash 文档)。SupportPac CA1S 采用了这些约定的其中一部分,并且在 CA1S 文档中详细描述(见 参考资料),但可概括为:

  • 可将 CA1S 配置为以 REST 方式处理某些路径的请求。在默认的 CA1S 安装中,这个特性适用于 /ca1s/resources 下的路径。
  • 当在这种路径上的请求被处理时,将按照以下方式从 URI 发出关于目标源的信息:
http://<host>/ca1s/resources/<resourceName>[/<resourceID>[/<…more/resource/info…>]]
  • 将查找与资源名称对应的资源处理程序脚本。PHP 引擎将执行该脚本,然后尝试在脚本内部调用一个特定的方法,这取决于请求的 HTTP 方法和 URI 是否在资源名称之后包含一个标识符。

表 5 显示了从 HTTP 请求类型到将要调用的方法的映射,假设资源的名称为 “book”:

表 5. REST 式事件处理程序方法
请求 URI HTTP Method Handler method invoked in ca1s/work/resources/book.php
集合 URI,例如
http://<host>/ca1s/resources/book
GET book::onList()
 POSTbook::onCreate()
  PUT book::onPutCollection()
  DELETE book::onDeleteCollection()
成员 URI,例如
http://<host>/ca1s/resources/book/10
GET book::onRetrieve()
  POST book::onPostMember()
 PUT book::onUpdate()
 DELETEbook::onDelete()

资源处理程序脚本不需要实现表 5 中的所有方法。如果没有找到特定事件的方法,也不会引起错误。最常实现的事件处理程序是与资源上的 List、Create、Retrieve、Update 和 Delete(LCRUD)操作对应的事件的处理程序,在表 5 中用粗体表示它们。

示例

清单 6 中的示例为每个事件输出不同的字符串:

清单 6. 资源处理程序脚本的主体结构
<?php
class book {
	function onList() {
	  echo 'LIST all books!';
	}
	
	function onCreate() {
	  echo 'CREATE a book!';
	}
	
	function onRetrieve() {
	  echo 'RETRIEVE a book!';
	}
	
	function onUpdate() {
	  echo 'UPDATE a book!';
	}
	
	function onDelete() {
	  echo 'DELETE a book!';
	}	
}
?>

如果要测试它,请将以上的脚步复制到您的 CICS 系统的 ca1s/work/resources/book.php(注意,在脚本中声明的类名必须与脚本文件名匹配)。然后使用 REST 客户端(比如 Poster add-on for Firefox)通过不同的 HTTP 方法访问它(是否对 URI 使用标识符)。您将看到事件处理程序被正确触发。例如:

图 2. 图书资源中带有标识符的 GET 请求触发 onRetrieve() 事件处理程序
Poster add-on for Firefox 屏幕快照描绘了实际运行中的 onRetrieve() 事件。Response 为:RETRIEVE a book!
图 3. 图书资源中不带标识符的 POST 请求触发 onCreate() 事件处理程序
另一个 Poster add-on for Firefox 屏幕快照描绘了实际运行中的 oncreate() 事件。Response 为:CREATE a book!

事件处理程序未被调用?

确认以下所有表述都是相同的(它们都表示资源名):

  • 在 ‘ca1s/resources/’ 前缀之后的请求 URI 的第一个路径组件
  • 针对 .php 扩展的资源处理程序脚本的文件名
  • 在脚本中定义的类的名称

使用 zget() 访问请求数据

脚本可能使用 CA1S 内置的 zget() 函数访问入站请求的各种属性。其中的例子包括:

  • 入站请求的主体作为字符串,从请求编码转换为 PHP 运行时编码:
$data = zget('/request/input/transcoded');
  • 查询字符串参数(以及 POST 和 PUT 参数,如果它们经过了格式编码):
		$value = zget('/request/params/<paramName>');
  • 在入站 URI 指定的请求资源的 ID:
		$id = zget('/request/params/<resourceName>Id');
  • 资源 ID 之后的 URI 部分(如果可用的话):
		$data = zget('/event/pathInfo');

如果要使用 zget(),请按照以下方式修改 book.php 中的 method book::onUpdate()

function onUpdate() {
  $id = zget('/request/params/bookId');
  $data = zget('/request/input/transcoded');
  echo "You attempted to update book $id with data $data";
}

然后,使用 PUT 请求访问一个特定的图书资源,以触发更新事件。

图 4. 使用 Poster 测试 zget
Poster add-on for Firefox 屏幕快照描绘了实际运行中的 zget()。用红色线条圈出了 Actions: PUT 字段和 Content to Send:Hello World 字段。Response 为:You attempted to update book 40 with data: Hello World!

zget() 函数基于 WebSphere sMash 中的 Global Context 特性(见 参考资料)。CA1S 文档描述了 zget() 在 CA1S 中提供的完整函数,并且与 WebSphere sMash 中的版本进行了比较。您还可以使用 PHP 的标准机制访问请求数据,比如 $_GET superglobal 和 php://input 流等等。

使用 JSON 作为服务数据的交换格式

REST 为将资源公开为服务定义了一个简单一致的接口,但它没有为服务的输入输出数据指定某种格式 — 这由实现者决定。JSON 是一个很受欢迎的选择,因为它很简单、可读性强,并且受许多客户端和服务器端语言的支持。

将 PHP 变量编码为 JSON 数据

下面的代码清单显示了 onRetrieve() 处理程序如何发送编码为 JSON 字符串的图书资源。注意,在这个例子中,为了保持简单性,我们将图书细节硬编码到处理程序中。在下一小节中,您将看到如何从 COBOL 书库程序获取该信息。

function onRetrieve() {
  $id = zget('/request/params/bookId');
  // ... establish that book with ID $id is Heart of Darkness ...
  $book['title'] = 'Heart of Darkness';
  $book['author'] = 'Joseph Conrad';
  echo json_encode($book);
}

向成员 URI(比如 /ca1s/resources/book/10)发出的 GET 请求的响应体包含:

{"author":"Joseph Conrad","title":"Heart of Darkness"}

解码 JSON 数据

那么,onCreate() 处理程序如何处理在请求中编码为 JSON 的输入数据呢?在这里,为了保持简单,我们仅仅输出解码后的数据;在实际场景中,我们将使用该数据创建一个新的资源。

function onCreate() {
  $inputData = zget('/request/input/transcoded');
  $book = json_decode($inputData, true);
  // ... Create new book resource based on data in $book ...
  // Dump out the variable to illustrate:
  var_dump($book); 
}

在 POST 请求体中将类似于

{"author":"Margaret Atwood","title":"Oryx and Crake"}

的数据发送到集合 URI ca1s/resources/book 中,这将返回:

array(2) {
  ["author"]=>
  string(15) "Margaret Atwood"
  ["title"]=>
  string(14) "Oryx and Crake"
}

综合学过的知识

到目前为止,您已经:

  • 了解如何通过 PHP 与 CICS COMMAREA 程序交互
  • 了解一些能够帮助构建 REST 式 Web 服务的 CA1S 约定和函数

我们将使用这些知识将书库程序公开为 REST 式 Web 服务。

REST 式 设计

资源

第一步是定义我们希望公开的资源。在这个场景中,我们使用惟一的资源类型 “书”,它有 4 个属性:

book {
  string: title,   // The title of the book
  string: author,	 // The author of the book
  boolean: onLoan, // Whether the book is on loan
  string: borrower // The person who borrowed the book
                   // if it is on loan, null otherwise.
}

方法

接下来,我们简单描述每个受支持方法的输入/输出数据:

表 6. 集合 URI (/ca1s/resources/book) 上的请求
HTTP 方法在 book.php 中调用的处理程序方法描述
GET book::onList()返回用 JSON 编码的图书及其所有属性的列表。
POSTbook::onCreate()向书库添加一本书。
这个请求必须提供用 JSON 编码的新书属性 titleauthor。这将返回一条消息,表明书已添加。
PUT book::onPutCollection()不支持
DELETEbook::onDeleteCollection()不支持
表 7. 成员 URI (/ca1s/resources/book/10) 上的请求
HTTP 方法在 book.php 中调用的处理程序方法描述
GET book::onRetrieve()返回使用 JSON 编码的书及其所有属性。如果要请求某个属性(例如,book/10/title),将仅返回该属性(用 JSON 编码)。
POSTbook::onPostMember()不支持
PUT book::onUpdate()将图书标记为已借出或已归还。这个请求必须提供一个包含 onLoanborrower 属性的 JSON 对象。不支持更新书的作者和标题。这将返回一条消息,表明书已添加。
DELETEbook::onDelete()从书库中将书永久删除。这将返回一条消息,表明书已删除。

任何错误都将导致服务返回一个相应的 HTTP 状态码,以及在 JSON 对象属性 errorMessage 中返回一条错误消息。例如,尝试获取 ID 为 909 的图书时,如果不存在这本书的话,将返回 HTTP 404 响应,其内容体为:

{"errorMessage":"Could not retrieve book 909 as it was not found."}

实现

最后,让我们根据以上的设计实现资源处理程序 book.php。resources/book.php 中的示例代码包包含了完整的脚本。

对所有事件通用的代码

脚本 book.php 包含的 book 类带有 LCRUD 处理程序方法,同时还包含除类定义之外的代码。在调用恰当的处理程序方法之前,将对所有请求执行这个代码。

在我们使用的场景中,在类定义之外导入表示 COMMAREA 和程序常量的 Java 类非常重要,因为它们是最常用的。我们还使用 PHP functionheader() 将响应内容类型设置为 text/json,因为所有数据都以 JSON 格式返回:

清单 7. 所有请求类型都使用的引导代码
// Load the Java classes
java_import('library.Library_Commarea');
java_import('library.Library_Constants');
// All responses will be JSON, so always set response content-type to text/json.
header('Content-Type: text/json');

我们还在一个全局函数中打包程序链接操作及其异常处理。这个函数对所有事件处理程序都是可用的。如果书库程序意外终止,脚本的执行将暂停,并且向客户端返回一条错误消息。

清单 8. 程序链接的包装器函数
/**
 * Invoke the library program with the supplied COMMAREA.
 * Notify the client if an error occurs.
 */
function runLibraryProgram($COMMAREA) {
  $program = new CICSProgram('LIBRARY');
  try {
    $program->link($COMMAREA);
  } catch (CICSException $e) {
    header('HTTP/1.1 500 Internal Server Error');
    $error['errorMessage'] = 
              'Exeption when linking with CICS program:' . $e->getMessage();
    echo json_encode($error);
    exit;
  }
}

最后,在调用任何处理程序之前调用类构造器,因此我们可以使用它设置所有方法都可以使用的属性。

清单 9. 图书资源处理程序构造器
  /**
   * The constructor is invoked before event handlers.
   */
  function __construct() {
    $this->COMMAREA = new Library_Commarea();
    $this->constants = new Library_Constants();
  }

接下来,我们看看每个事件处理程序的实现。

onList

onList() 处理程序实现类似于 library.php 脚本(我们使用它了解如何从 PHP 调用 COMMAREA)的逻辑:它使用 LIST 命令调用书库程序,然后遍历图书集合。然而,这个版本不仅输出图书的标题和作者,而且还构建一个表示图书的关联数组,然后将其序列化为 JSON。它还检查调用书库返回的代码,如果出现问题,将向客户端发送一条错误消息。

清单 10. onList 处理程序
  /**
   * Respond with a JSON-encoded list of books.
   */
  function onList() {
    // Attempt to get book list
    $this->COMMAREA->setLibRequestType('LIST');
    runLibraryProgram($this->COMMAREA);

    // Process return code
    switch ($this->COMMAREA->getLibReturnCode()) {
      case $this->constants->getLibraryOk():
        // Return the list of books
        $books = array();
        for ($i = 0; $i<$this->COMMAREA->getLibItemCount(); $i++) {
          $CICSbook = $this->COMMAREA->getLibBookItem($i);
          $bookId = $CICSbook->getBookItemRef();
          $books[$bookId]['title'] = trim($CICSbook->getBookTitle());
          $books[$bookId]['author'] = trim($CICSbook->getBookAuthor());
          $books[$bookId]['onLoan'] = $CICSbook->isBookOnloan();
          $books[$bookId]['borrower'] = $books[$bookId]['onLoan'] ?
          trim($CICSbook->getBookBorrower()) : null;
        }
        echo json_encode($books);
        break;
      default:
        // Notify client of internal error
        header('HTTP/1.1 500 Internal Server Error');
        $error['errorMessage'] = 'Unexpected return code when listing books: ' 
                                        . $this->COMMAREA->getLibReturnCode();
        echo json_encode($error);
    }
  }

onCreate

onCreate() 处理程序首先从请求获取输入数据并验证该数据,然后采用类似于 onList() 的模式。使用 PHP 函数 header()(见 参考资料)在请求成功后设置恰当的 HTTP 响应代码。

清单 11. onCreate 处理程序
  /**
   * Add book to library based on JSON data in the request body.
   */
  function onCreate() {
    // Check input data for new book
    $book = json_decode(zget('/request/input/transcoded'), true);
    if (!is_array($book) || !isset($book['title'], $book['author'])) {
      header('HTTP/1.1 400 Bad Request');
      $error['errorMessage'] = 'Bad book data: ' . zget('/request/input/transcoded') 
                                        . '. Please specify an author and a title.';
      echo json_encode($error);
      return;
    }

    // Attempt to create book
    $this->COMMAREA->setLibRequestType('ADD');
    $this->COMMAREA->getLibBookItem(0)->setBookTitle($book['title']);
    $this->COMMAREA->getLibBookItem(0)->setBookAuthor($book['author']);
    runLibraryProgram($this->COMMAREA);

    // Process return code
    switch ($this->COMMAREA->getLibReturnCode()) {
      case $this->constants->getLibraryOk():
        header('HTTP/1.1 201 Created');
        $bookId = $this->COMMAREA->getLibBookItem(0)-> getBookItemRef();
        $status['statusMessage'] = "Successfully created book $bookId.";
        echo json_encode($status);
        break;
      case $this->constants->getLibraryFull():
        header('HTTP/1.1 400 Bad Request');
        $error['errorMessage'] = 'Could not create book : Library is full.';
        echo json_encode($error);
        break;
      default:
        header('HTTP/1.1 500 Internal Server Error');
        $error['errorMessage'] = 'Unexpected return code when creating book ' 
                                       . $this->COMMAREA->getLibReturnCode();
        echo json_encode($error);
        break;
    }
  }

onRetrieve

onRetrieve() 类似于 onList(),但它访问的是一本书,而不是完整的列表。另外,对于子路径的请求(比如 book/10/title),它还包含访问图书的某个属性的逻辑。请求的属性由 zget('/event/pathInfo') 决定。

清单 12. onRetrieve 处理程序
  /**
   * Respond with a JSON representation of an individual book, or a specific attribute
   * of a book.
   */
  function onRetrieve() {
    $bookId = zget('/request/params/bookId');
    $this->COMMAREA->setLibRequestType('QUERY');
    $this->COMMAREA->getLibBookItem(0)->setBookItemRef($bookId);
    runLibraryProgram($this->COMMAREA);

    // Process return code
    switch ($this->COMMAREA->getLibReturnCode()) {
      case $this->constants->getLibraryOk():
        $book['title'] = trim($this->COMMAREA->getLibBookItem(0)->getBookTitle());
        $book['author'] = trim($this->COMMAREA->getLibBookItem(0)->getBookAuthor());
        $book['onLoan'] = $this->COMMAREA->getLibBookItem(0)->isBookOnloan();
        $book['borrower'] = $book['onLoan'] ?
                trim($this->COMMAREA->getLibBookItem(0)->getBookBorrower()) : null;
        break;
      case $this->constants->getLibraryNotfound():
        header('HTTP/1.1 404 Not Found');
        $error['errorMessage'] = "Could not retrieve book $bookId as it was not found.";
        echo json_encode($error);
        return;
      default:
        header('HTTP/1.1 500 Internal Server Error');
        $error['errorMessage'] = "Unexpected return code deleting book $bookId: " 
                                           . $this->COMMAREA->getLibReturnCode();
        echo json_encode($error);
        return;
    }

    // Send back appropriate info about the book
    $requestedInfo = zget('/event/pathInfo');
    switch($requestedInfo) {
      case null:
        // return the whole book
        echo json_encode($book);
        break;
      case '/title':
      case '/author':
      case '/onLoan':
      case '/borrower':
        // return just the relevant info
        $requestedInfo = substr($requestedInfo, 1);
        echo json_encode(array($requestedInfo => $book[$requestedInfo]));
        break;
      default:
        header('HTTP/1.1 404 Not Found');
        $error['errorMessage'] = "Could not retrieve book detail $requestedInfo 
                          about book $bookId: don't know what $requestedInfo is.";
        echo json_encode($error);
    }
  }

onUpdate

onUpdate() 处理程序检查输入数据的正确性,它可能包含 onLoanborrower 属性。然后通过调用恰当的 CICS 程序将图书标记为 “已借出” 或 “已归还”。和前面的处理程序一样,将对程序的返回代码进行检查,并恰当地处理错误。与 OnRetrieve() 不同,这个处理程序不支持对子路径(例如,book/10/onLoan)的单个属性执行操作;如果您想进一步体验,可以放心添加这个函数!

清单 13. onUpdate 处理程序
  /**
   * Update the status of a book to mark it as borrowed or returned.
   */
  function onUpdate() {
    // Check input data
    $bookId = zget('/request/params/bookId');
    $updateData = json_decode(zget('/request/input/transcoded'), true);
    if (!isset($updateData['onLoan'])) {
      header('HTTP/1.1 400 Bad Request');
      $error['errorMessage'] = 'Bad book update data: ' .
      zget('/request/input/transcoded') . '. Please specify onLoan.';
      echo json_encode($error);
      return;
    }
    if ($updateData['onLoan'] && empty($updateData['borrower'])) {
      header('HTTP/1.1 400 Bad Request');
      $error['errorMessage'] = 'Bad book update data: ' .
      zget('/request/input/transcoded') . '. Please specify a borrower.';
      echo json_encode($error);
      return;
    }

    // Attempt to update book status
    $this->COMMAREA->setLibRequestType($updateData['onLoan'] ? 'BORROW' : 'RETURN');
    $this->COMMAREA->getLibBookItem(0)->setBookItemRef($bookId);
    $this->COMMAREA->getLibBookItem(0)->setBookLoanStatus($updateData['onLoan']);
    if (isset($updateData['borrower'])) {
      $this->COMMAREA->getLibBookItem(0)->setBookBorrower($updateData['borrower']);
    }
    runLibraryProgram($this->COMMAREA);

    // Process return code
    switch ($this->COMMAREA->getLibReturnCode()) {
      case $this->constants->getLibraryOk():
        $status['statusMessage'] =  "Successfully updated status of book $bookId.";
        echo json_encode($status);
        break;
      case $this->constants->getLibraryNotfound():
        header('HTTP/1.1 404 Not Found');
        $error['errorMessage'] = "Could not update book $bookId as it was not found.";
        echo json_encode($error);
        break;
      default:
        header('HTTP/1.1 500 Internal Server Error');
        $error['errorMessage'] = 
        "Unexpected return code when updating status of book $bookId: " 
                                 . $this->COMMAREA->getLibReturnCode();
        echo json_encode($error);
    }
  }

onDelete

最后一个处理程序是 onDelete(),它通过调用 CICS 程序对请求 URI 中的图书 ID 执行 “DELETE” 操作。

清单 14. onDelete 处理程序
  /**
   * Delete a book from the library.
   */
  function onDelete() {
    // Attempt to Delete book
    $bookId = zget('/request/params/bookId');
    $this->COMMAREA->setLibRequestType('DELETE');
    $this->COMMAREA->getLibBookItem(0)->setBookItemRef($bookId);
    runLibraryProgram($this->COMMAREA);

    // Process return code
    switch ($this->COMMAREA->getLibReturnCode()) {
      case $this->constants->getLibraryOk():
        $status['statusMessage'] =  "Successfully deleted book $bookId.";
        echo json_encode($status);
        break;
      case $this->constants->getLibraryNotfound():
        header('HTTP/1.1 404 Not Found');
        $error['errorMessage'] = "Could not delete book $bookId as it was not found.";
        echo json_encode($error);
        break;
      default:
        header('HTTP/1.1 500 Internal Server Error');
        $error['errorMessage'] = "Unexpected return code deleting book $bookId: " 
                                           . $this->COMMAREA->getLibReturnCode();
        echo json_encode($error);
    }
  }

使用 Web 服务

现在,这个书库应用程序已经通过一致的接口公开,并且使用明确定义的 JSON 数据结构进行通信,因此,各种客户端都可以轻松访问它。测试该服务的最简单方法是使用轻量级的 REST 客户端,比如 Poster add-on for Firefox(见 参考资料)。

图 5. 使用简单的客户端测试服务
使用 Poster add-on for Firefox 的 REST 客户端

在示例代码中,我们包含了一个向服务发出 Ajax 请求的 HTML 和 JavaScript 页面。如果您要试用它,可以将 library/scripts/ajaxLibrary.php 复制到您的 CICS 系统的 /ca1s/work/scripts/ajaxLibrary.php 目录下(将 resources/book.php 转移到 /ca1s/work/resources/book.php,如果还没有转移的话),然后在浏览器中访问它。

图 6. 服务的 Ajax 前端
示例书库应用程序的屏幕快照,它显示了几本样例书籍的列表视图

可以通过某个平台(比如 WebSphere sMash)将这个书库服务与其他服务进行混搭。


结束语

在本教程中,您学习了:

  • 如何生成表示 CICS COMMAREA 的 Java 类,并让 CA1S 可以使用它。
  • 如何为 CICS COMMAREA 程序准备输入数据、调用该程序并使用 PHP 代码读取它的输出数据。
  • 如何使用 PHP 反射查找 COMMAREA 对象上可用的字段。
  • 如何使用 WebSphere sMash 式的事件处理程序和 zget() 快速编写用于响应 REST 请求的 PHP 代码。
  • 如何从 PHP 编码和解码 JSON 数据。
  • 如何将 CICS 程序公开为 REST 式 Web 服务。

接下来,您需要探索本教程没有讨论到的其他 CA1S 特性,其中包括:

  • 使用 PDO 访问 DB2 数据库。
  • 使用 Commit/Rollback API 通过 PHP 代码管理工作和事务单元。
  • 使用 PDT 调试 PHP 脚本。

要了解更多信息,请阅读 CA1S 文档。


下载

描述名字大小
示例 zip 文件CA1S.devworks.sampleCode.zip9KB

参考资料

学习

获得产品和技术

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development, Open source
ArticleID=398614
ArticleTitle=使用 PHP 在 CICS 上构建 REST 服务
publish-date=06222009