(Fabric Learning 4) Fabric Java SDK connects to the fabcar network

Reference article:

Modify the hosts file of windows to add the address mapping of SDK_Shuicaojie's Blog-CSDN Blog

​​​​​​​​SDK-Java runs through the fabcar that comes with fabric2.2, and it is simple to implement_Shui Caojie's Blog-CSDN Blog
(8) Fabric2.0Java SDK Practice-Contract Transaction_Mark_MMXIX's Blog-CSDN Blog

 

1. Open the fabcar network

Start the network in /your own path/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar

./networkDown.sh

After the startup is successful, check the startup status:

docker ps -a

If the container opens successfully, you're ready for the next step!

2. Create a springboot project

Create a springboot project where options are suggested:

2.0 Project Structure Directory

This is the project structure directory we will eventually generate, and then we will create the files in the creator one by one 

2.1 Import maven dependent packages related to fabric

<dependency>
    <groupId>org.hyperledger.fabric-sdk-java</groupId>
    <artifactId>fabric-sdk-java</artifactId>
    <version>1.4.7</version>
</dependency>

<dependency>
    <groupId>org.hyperledger.fabric</groupId>
    <artifactId>fabric-gateway-java</artifactId>
    <version>2.2.0</version>
</dependency>

2.2 Configuration under the resources package

2.2.1 crypto-config

Create a crypto-config folder, which stores the certificate files of the entire network.

The acquisition of the certificate file is to return to the organization folder in the test-network folder after the fabcar network is opened, and find the orderOrganization and peerOrganization in it

Once found, copy them to the crypto-config folder we created,

2.2.2 connection.json network connection file

 This file is used to connect to the fabric network


{
  "name": "basic-network",
  "version": "1.0.0",
  "dependencies": {
  },
  "client": {
    "organization": "Org1",
    "connection": {
      "timeout": {
        "peer": {
          "endorser": "300"
        },
        "orderer": "300"
      }
    }
  },
  "channels": {
    "mychannel": {
      "orderers": [
        "orderer.example.com"
      ],
      "peers": {
        "peer0.org1.example.com": {
          "endorsingPeer": true,
          "chaincodeQuery": true,
          "ledgerQuery": true,
          "eventSource": true
        },
        "peer0.org2.example.com": {
          "endorsingPeer": true,
          "chaincodeQuery": true,
          "ledgerQuery": true,
          "eventSource": true
        }
      }
    }
  },
  "organizations": {
    "Org1": {
      "mspid": "Org1MSP",
      "peers": [
        "peer0.org1.example.com"
      ],
      "certificateAuthorities": [
        "ca-org1"
      ],
      "adminPrivateKeyPEM": {
        "path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp/keystore/a2fde5eedd98656e6389b5db4a6d311fa89c9f5de3c1dd75c91a08dfa2d1acd4_sk"
      },
      "signedCertPEM": {
        "path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp/signcerts/cert.pem"
      }
    },
    "Org2": {
      "mspid": "Org2MSP",
      "peers": [
        "peer0.org2.example.com"
      ],
      "certificateAuthorities": [
        "ca-org2"
      ],
      "adminPrivateKeyPEM": {
        "path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/keystore/619c1ee996151bb4a6dcf828c1b522bc59c512ee6524b22b70d72046f53e017c_sk"
      },
      "signedCertPEM": {
        "path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/signcerts/cert.pem"
      }
    }
  },
  "orderers": {
    "orderer.example.com": {
      "url": "grpcs://192.168.235.147:7050",
      "mspid": "OrdererMSP",
      "grpcOptions": {
        "ssl-target-name-override": "orderer.example.com",
        "hostnameOverride": "orderer.example.com"
      },
      "tlsCACerts": {
        "path": "src/main/resources/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt"
      },
      "adminPrivateKeyPEM": {
        "path": "src/main/resources/crypto-config/ordererOrganizations/example.com/users/[email protected]/msp/keystore/4f1821d3b3cf81f20aa151eeb98aca45689a3453017092d04900b910ff2d9ca8_sk"
      },
      "signedCertPEM": {
        "path": "src/main/resources/crypto-config/ordererOrganizations/example.com/users/[email protected]/msp/signcerts/cert.pem"
      }
    }
  },
  "peers": {
    "peer0.org1.example.com": {
      "url": "grpcs://192.168.235.147:7051",
      "grpcOptions": {
        "ssl-target-name-override": "peer0.org1.example.com",
        "hostnameOverride": "peer0.org1.example.com",
        "request-timeout": 120001
      },
      "tlsCACerts": {
        "path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
      }
    },
    "peer0.org2.example.com": {
      "url": "grpcs://192.168.235.147:9051",
      "grpcOptions": {
        "ssl-target-name-override": "peer0.org2.example.com",
        "hostnameOverride": "peer0.org2.example.com",
        "request-timeout": 120001
      },
      "tlsCACerts": {
        "path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
      }
    }
  },
  "certificateAuthorities": {
    "ca-org1": {
      "url": "https://192.168.235.147:7054",
      "grpcOptions": {
        "verify": true
      },
      "tlsCACerts": {
        "path": "src/main/resources/crypto-config/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem"
      },
      "registrar": [
        {
          "enrollId": "admin",
          "enrollSecret": "adminpw"
        }
      ]
    },
    "ca-org2": {
      "url": "https://192.168.235.147:8054",
      "grpcOptions": {
        "verify": true
      },
      "tlsCACerts": {
        "path": "src/main/resources/crypto-config/peerOrganizations/org2.example.com/ca/ca.org2.example.com-cert.pem"
      },
      "registrar": [
        {
          "enrollId": "admin",
          "enrollSecret": "adminpw"
        }
      ]
    }
  }
}

All the private keys, certificates and ip must be replaced with your own.

After the replacement, we need to set the hosts mapping file locally under windows

The specific location of the mapping file: c:\Windows\System32\drivers\etc

Notepad opens the hosts file and adds

192.168.235.147 peer0.org1.example.com
192.168.235.147 peer0.org2.example.com
192.168.235.147 orderer.example.com

The ip address here uses your own ip address, not mine! ! !

2.2.3 fabric.config.properties file

# 网络配置文件路径
networkConfigPath = src/main/resources/connection.json
# 用户1,机构2证书路径
certificatePath = src/main/resources/crypto-config/peerOrganizations/org2.example.com/msp/signcerts/cert.pem
# 用户1,机构2证书私钥路径
privateKeyPath = src/main/resources/crypto-config/peerOrganizations/org2.example.com/msp/keystore/b30daf192d9ca39fd68817a73f02fde2bb62a637c68b133ede02a74bb43fb191_sk
# 通道名字
channelName = mychannel

# 链码名字
contractName = fabcar

 The user's files are stored here, and I use the org2 certificate to connect

2.3 Files in the java package

2.3.1 HyperLedgerFabricGatewayJavaConfig file

package com.xzd.javasdkfirstdemo;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hyperledger.fabric.gateway.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Properties;

@Configuration
@AllArgsConstructor
@Slf4j
public class HyperLedgerFabricGatewayJavaConfig {


    @Bean
    public Gateway gateway() throws Exception {
        // 主要读取java的配置文件
        Properties properties = new Properties();
        InputStream inputStream = Gateway.class.getResourceAsStream("/fabric.config.properties");
        properties.load(inputStream);

        String networkConfigPath = properties.getProperty("networkConfigPath");
        String certificatePath = properties.getProperty("certificatePath");
        X509Certificate certificate = readX509Certificate(Paths.get(certificatePath));
        String privateKeyPath = properties.getProperty("privateKeyPath");
        PrivateKey privateKey = getPrivateKey(Paths.get(privateKeyPath));
        Wallet wallet = Wallets.newInMemoryWallet();
        wallet.put("user1", Identities.newX509Identity("Org2MSP",certificate,privateKey));

        Gateway.Builder builder = Gateway.createBuilder()
                .identity(wallet , "user1")
                .networkConfig(Paths.get(networkConfigPath));

        Gateway gateway = builder.connect();

        log.info("=========================================== connected fabric gateway {} " , gateway);

        return gateway;
    }



    /*获取合约的办法*/
    @Bean
    public Contract fabcar(Gateway gateway) {
        // 获取mychannel的网络 也就是通道
        Network network = gateway.getNetwork("mychannel");
        // 获取contract的链码 名字为fabcar
        Contract contract = network.getContract("fabcar");
        return contract;
    }
    /*获取证书的办法*/
    private static X509Certificate readX509Certificate(final Path certificatePath) throws IOException, CertificateException {
        // 通过路径获取到文件 如果成功获取 返回身份识别证书的结果
        try (Reader certificateReader = Files.newBufferedReader(certificatePath, StandardCharsets.UTF_8)) {
            return Identities.readX509Certificate(certificateReader);
        }
    }
    /*获取私钥的办法 */
    private static PrivateKey getPrivateKey(final Path privateKeyPath) throws IOException, InvalidKeyException {
        // 通过路径获取到文件 如果成功获取 返回身份识别私钥的结果
        try (Reader privateKeyReader = Files.newBufferedReader(privateKeyPath, StandardCharsets.UTF_8)) {
            return Identities.readPrivateKey(privateKeyReader);
        }
    }
}

2.3.2 JavasdkfirstdemoApplication startup class

package com.xzd.javasdkfirstdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication
@EnableConfigurationProperties
public class JavasdkfirstdemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(JavasdkfirstdemoApplication.class, args);
    }

}

2.3.3 The control layer FabcarController file that operates the chain code

package com.xzd.javasdkfirstdemo;

import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.StringUtils;
import org.hyperledger.fabric.gateway.*;
import org.hyperledger.fabric.sdk.Peer;
import org.springframework.web.bind.annotation.*;

import java.util.EnumSet;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeoutException;

@RestController
@RequestMapping("/car")
@Slf4j
@AllArgsConstructor
public class FabcarController {
    final Gateway gateway;

    final Contract contract;
    /*根据key查询对应的car*/
    @GetMapping("/{key}")
    public Map<String, Object> queryCarByKey(@PathVariable String key) throws GatewayException {

        Map<String, Object> result = Maps.newConcurrentMap();
        byte[] queryAssets = contract.evaluateTransaction("QueryCar",key);

        result.put("payload", StringUtils.newStringUtf8(queryAssets));
        result.put("status", "ok");

        return result;


    }

    /*查询所有的car*/
    @GetMapping("/all")
    public Map<String, Object> queryAllCar() throws GatewayException{

        Map<String, Object> result = Maps.newConcurrentMap();
        byte[] queryAllAssets = contract.evaluateTransaction("QueryAllCars");

        result.put("payload", StringUtils.newStringUtf8(queryAllAssets));
        result.put("status", "ok");

        return result;
    }
    
    /*新增一个car的资产*/
    @PostMapping("/add")
    @ResponseBody
    public Map<String,Object> createCar(@RequestParam("carnumber")String carnumber,@RequestParam("make")String make,
                                        @RequestParam("model")String model,@RequestParam("colour")String colour,
                                        @RequestParam("owner")String owner) throws GatewayException, TimeoutException, InterruptedException {
        Network network = gateway.getNetwork("mychannel");
        Map<String, Object> result = Maps.newConcurrentMap();
        byte[] transaction = contract.createTransaction("CreateCar")
                .setEndorsingPeers(network.getChannel().getPeers(EnumSet.of(Peer.PeerRole.ENDORSING_PEER)))
                .submit(carnumber,make,model,colour,owner);
        result.put("payload", StringUtils.newStringUtf8(contract.evaluateTransaction("QueryCar",carnumber)));
        result.put("status", "ok");
        return result;
    }

    /*将一个car资产转移到另一个owner上*/
    @PutMapping("/update")
    @ResponseBody
    public Map<String,Object> updateCarOwner(@RequestParam("carnumber")String carnumber,@RequestParam("newowner")String newowner) throws GatewayException,InterruptedException, TimeoutException, ContractException {
        Map<String, Object> result = Maps.newConcurrentMap();
        byte[] transaction = contract.submitTransaction("ChangeCarOwner", carnumber, newowner);
        result.put("payload", StringUtils.newStringUtf8(contract.evaluateTransaction("QueryCar",carnumber)));
        result.put("status", "ok");
        return result;
    }


}

After everything is written, start the boot project!

After writing the control class, let's use the interface testing tool postman to test it!

2.4 Test interface

2.4.1 Get all cars

 2.4.2 Query car based on key

2.4.3 Create a car asset

 

2.4.4 Transfer the car to the new owner

Test success! Simple java sdk demo completed!

===========================2023.02.24 Added ======================== ==========

问题1:Error creating bean with name 'gateway' defined in class path resource...

Answer: Once this problem occurs, it means that the gateway failed to connect to the blockchain. At this time, you must check the specified configuration file of the specified certificate in your local directory (such as the fabric.config.properties file in my article), it is very likely to connect The wrong path causes the gateway to fail.

Question 2: The configuration files of members of each organization can be split.

For example, I split org1 and org2.

When we start the project, we can set the specified configuration file

 

-Dspring.config.location=classpath:/application-test-network-org1.properties

 Make sure which organization's configuration file you are currently using.

Guess you like

Origin blog.csdn.net/Wannabe_hacker/article/details/124284663