环境搭建 MAC OS

说明

存证链于2019年10月17日下线,为了得到更好的体验,请使用“合约链”。合约链具备存证链的所有功能,同时性能更佳。

安装配置 Java

  1. 下载 Mac 对应的安装包,进行安装。您可以参考 Oracle 官方文档了解如何 安装 JDK(英文)

    说明

    默认情况下,建议使用 Java 8(英文) 环境。您也可以在 Java 7 或更高版本中使用 ,配置与 Java 8 相同。

  2. 安装Apache Maven,您需要先下载 Apache Maven 3.2.5更高版本(英文),然后在本地进行安装。可参考 Apache Maven 官方文档了解如何 安装 Maven(英文)

  3. 在完成 Maven 安装后,配置以下环境变量:

M2_HOME:配置为 Maven 的安装路径。
PATH:增加 %M2_HOME%/bin 路径。
export M2_HOME=$(/usr/local/Cellar/maven/3.2.2/libexec)
export M2=$M2_HOME/bin
export PATH=$M2:$PATH

安装IDEA

  1. 在 IDEA 官网 下载 IDEA。

  2. 下载完毕后,安装 IDEA。

创建Demo

  1. 准备工作:登录BaaS平台,在左侧导航栏选择 区块链列表,在列表中找到您希望访问的区块链,鼠标选中右侧 更多,并点击 下载签名证书下载SDK,将开发 SDK 压缩包和签名用户证书下载至本地。notary_chain_download

  2. 在 IDEA 中创建一个新的 Maven 项目。maven

  3. 根据下载的 SDK zip 包中的 Readme 说明,对项目进行配置:

    • pom.xml 文件中添加对应的依赖包。

      <dependencies>
      <dependency>
          <groupId>com.alipay.antblockchain</groupId>
          <artifactId>antblockchain-gl-biz-sdk</artifactId>
          <version>0.6.0.3</version>
          <scope>system</scope>
          <systemPath>{libdir}/client-sdk.jar</systemPath>
      </dependency>
      <dependency>
          <groupId>com.alipay.antblockchain.sdk.plus</groupId>
          <artifactId>antblockchain-sdk-plus</artifactId>
          <classifier>jar-with-dependencies</classifier>
          <version>0.6.0.3</version>
          <scope>system</scope>
          <systemPath>{libdir}/sdk-plus.jar</systemPath>
      </dependency>
      <dependency>
          <groupId>javax.validation</groupId>
          <artifactId>validation-api</artifactId>
          <version>1.1.0.Final</version>
      </dependency>
      <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-validator</artifactId>
          <version>5.3.5.Final</version>
      </dependency>
      <dependency>
          <groupId>javax.el</groupId>
          <artifactId>javax.el-api</artifactId>
          <version>2.2.4</version>
      </dependency>
      <dependency>
          <groupId>org.glassfish.web</groupId>
          <artifactId>javax.el</artifactId>
          <version>2.2.4</version>
      </dependency>
      </dependencies>
      说明

      注意:解压从 BaaS 平台下载的 client-sdk.zip 文件,将内含的client-sdk.jar 和 sdk-plus.jar 加入到依赖目录中,务必修改您的 libdir 为真实的路径。

    • sdk.properties 文件进行配置。

       # 客户端连接的主节点地址,主节点必须且只能配置 1 个
      biz.sdk.primary=116.62.111.181:8080
      # 备份节点 API 地址,备份节点可以配置 n 个,n=3f:f=1,2,...
      # 主节点无法连接时,会切换连接备份节点,当主节点恢复时,⾃动切回主节点
      biz.sdk.backups=116.62.111.182:8080;116.62.111.183:8080;116.62.111.184:8080
      # 客户端与节点连接使⽤ TLS 双向认证,需要配置 x509 证书
      # pkcs8 格式的 SSL 私钥文件绝对路径
      biz.sdk.ssl_key=/path/test_key_pkcs8.pem
      # x509 格式的 SSL 证书文件绝对路径
      biz.sdk.ssl_cert=/path/test_cert.pem
      # 创建私钥时设置的 SSL 私钥密码
      biz.sdk.ssl_key_password=******
      # trust store 文件绝对路径
      biz.sdk.trust_store=/path/test_client_trust.keystore
      # trust store 密码,请咨询 BaaS 技术支持人员
      biz.sdk.trust_store_password=******
  4. 完成上述配置之后,在项目的 Main 函数中创建一个 SDK 客户端实例,并且通过区块高度参数获取这个区块的内容。

    import com.alipay.mychain.gl.biz.common.Response;
    import com.alipay.mychain.gl.biz.sdk.Client;
    import com.alipay.mychain.gl.biz.sdk.ClientConfig;
    import com.alipay.mychain.gl.biz.sdk.ClientPropertyConfig;
    import com.alipay.mychain.gl.common.enums.PayloadType;
    import com.alipay.mychain.gl.common.model.builder.TransactionBuilder;
    import com.alipay.mychain.gl.common.model.entity.ContentOnlyNotaryPayloadDO;
    import com.alipay.mychain.gl.common.model.entity.TransactionDO;
    import com.alipay.mychain.gl.common.model.pojo.Block;
    import com.alipay.mychain.sdk.plus.builder.GuestInfoBuilder;
    import com.alipay.mychain.sdk.plus.constants.BizCategory;
    import com.alipay.mychain.sdk.plus.entity.GuestInfo;
    
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.util.Properties;
    import java.util.concurrent.TimeoutException;
    
    public class App {
      public static void main(String[] args ){
          Properties p = new Properties();
          try {
              p.load(App.class.getClassLoader().getResourceAsStream("sdk.properties"));
          }catch (IOException e){
              e.printStackTrace();
          }
          ClientConfig config = new ClientPropertyConfig(p);
          Client client = new Client(config);
    
          // 1. 获取一个 Block Info
          getBlock(client);
    
          // 2. 上传存证数据
          String txHash = sendData(client);
    
          // 3. 获取存证数据
          getData(client, txHash);
    
          client.shutdown();
      }
    
      static String sendData(Client client){
    
          // 构造存证数据
    
          GuestInfoBuilder builder = new GuestInfoBuilder(); byte[] bizData = builder.setUserName("Bob")
                  .setBirthday("2000-01-01")
                  .setEmail("bob@inc.com")
                  .build();
          System.out.println("--> 构造 GuestInfo: UserName: Bob, Birthday: 2000-01-01, Email:bob@inc.com");
    
          // 创建 ContentOnlyNotary Transaction
          TransactionDO tx = TransactionBuilder.getContentOnlyNotaryPayloadBuilder()
                  .setContent(bizData)
                  .setTimestamp(System.currentTimeMillis())//设置业务时间
                  .setCategory(BizCategory.GuestInfo)   //设置业务分类
                  .build();
          Response<TransactionDO> response = null;
          try{
              response = client.sendTransaction(tx);
          }catch (TimeoutException e){
              e.printStackTrace();
          }
          if(response.isSuccess()){
              // 发送成功,业务系统保留 Transaction Hash 与业务数据关联
              System.out.println("--> 上传至区块链返回 txHash: "+ tx.getTxHashValue());
              return tx.getTxHashValue();
          }else{
              // 发送失败,抛异常。业务系统应该重试,RPC 调用失败时区块链的状态是未知的。
              throw new RuntimeException("写⼊区块链失败");
          }
      }
    
      static void getBlock(Client client){
          try {
              Response<Block> res = client.getBlock(8);
              System.out.println(res.getData());
          }catch (TimeoutException e){
              e.printStackTrace();
          }
      }
    
      static void getData(Client client, String txHash){
          System.out.println("链上获取 txHash: "+txHash+" 的存证数据");
          while(true) {
              Response<TransactionDO> response = null;
              try {
                  response = client.getTransaction(txHash);
              } catch (TimeoutException e) {
                  e.printStackTrace();
              }
              if (response.isSuccess()) {
                  if (null != response.getData()) {  // 链上未存在该 Tx
                      TransactionDO tx = response.getData();
                      // 根据交易类型读取具体交易内容
                      if (tx.getType() == PayloadType.TX_TYPE_NOTARY_CONTENT_ONLY.code) {
                          // 读取内容存证交易
                          ContentOnlyNotaryPayloadDO payloadDO =
                                  (ContentOnlyNotaryPayloadDO) tx.getPayload();
    
                          ByteArrayInputStream bis = new ByteArrayInputStream(payloadDO.getContent());
    
                          try{
                              ObjectInputStream ois  = new ObjectInputStream(bis);
                              if (payloadDO.getCategory() == BizCategory.GuestInfo) {
                                  GuestInfo renter = GuestInfo.class.cast(ois.readObject());
                                  System.out.println("--> Username: " + renter.getUserName());
                                  System.out.println("--> Birthday: " + renter.getBirthday());
                                  System.out.println("--> Email: " + renter.getEmail());
                              }
                          }catch (IOException e){
                              e.printStackTrace();
                              return;
                          }catch (ClassNotFoundException e){
                              e.printStackTrace();
                              return;
                          }
                          // read biz time
                          System.out.println("--> Timestamp: " + payloadDO.getTimestamp());
                          return;
                      } else {
                          System.out.println("tx 类型错误");
                          return;
                      }
                  }
              } else {
                  // 查询异常,
                  System.out.println("返回异常");
                  return;
              }
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      }
    }

关于更多SDK的使用方法,请参考 SDK开发指南