(Fabric Learning 4) Fabric Java SDK se conecta a la red fabcar

Artículo de referencia:

Modifique el archivo de hosts de Windows para agregar el mapeo de direcciones de SDK_Shuicaojie's Blog-CSDN Blog

​​​​​​​​SDK-Java se ejecuta a través del fabcar que viene con fabric2.2, y es fácil de implementar_Blog de Shui Caojie-Blog de CSDN
(8) Fabric2.0Java SDK Practice-Contract Transaction_Mark_Blog de MMXIX-Blog de CSDN

 

1. Abra la red Fabcar

Inicie la red en /su propia ruta/github.com/hyperledger/fabric/scripts/fabric-samples/fabcar

./networkDown.sh

Después de que el inicio sea exitoso, verifique el estado de inicio:

docker ps -a

Si el contenedor se abre con éxito, ¡está listo para el siguiente paso!

2. Crea un proyecto springboot

Cree un proyecto springboot donde se sugieran opciones:

Directorio de la estructura del proyecto 2.0

Este es el directorio de la estructura del proyecto que eventualmente generaremos, y luego crearemos los archivos en el creador uno por uno 

2.1 Importar paquetes dependientes de Maven relacionados con la tela

<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 Configuración bajo el paquete de recursos

2.2.1 cripto-configuración

Cree una carpeta crypto-config, que almacena los archivos de certificado de toda la red.

La adquisición del archivo de certificado consiste en volver a la carpeta de la organización en la carpeta de la red de prueba después de abrir la red fabcar y encontrar la organización de pedidos y la organización de pares en ella.

Una vez encontrados, cópielos en la carpeta crypto-config que creamos,

2.2.2 archivo de conexión de red connection.json

 Este archivo se utiliza para conectarse a la red de tejido


{
  "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"
        }
      ]
    }
  }
}

Todas las claves privadas, certificados e ip deben ser reemplazadas por las tuyas.

Después del reemplazo, debemos configurar el archivo de mapeo de hosts localmente en Windows

La ubicación específica del archivo de asignación: c:\Windows\System32\drivers\etc

El Bloc de notas abre el archivo de hosts y agrega

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

¡La dirección IP aquí usa su propia dirección IP, no la mía! ! !

2.2.3 archivo fabric.config.properties

# 网络配置文件路径
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

 Los archivos del usuario se almacenan aquí y uso el certificado org2 para conectarme

2.3 Archivos en el paquete java

2.3.1 Archivo HyperLedgerFabricGatewayJavaConfig

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 Clase de inicio JavasdkfirstdemoApplication

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 El archivo FabcarController de la capa de control que opera el código de cadena

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;
    }


}

¡Después de que todo esté escrito, inicie el proyecto de arranque!

Después de escribir la clase de control, usemos la herramienta de prueba de interfaz cartero para probarla.

2.4 Interfaz de prueba

2.4.1 Consigue todos los coches

 2.4.2 Consulta de coche por clave

2.4.3 Crear un activo de automóvil

 

2.4.4 Transferir el coche al nuevo propietario

¡Prueba de éxito! ¡Demostración simple de Java SDK completada!

===========================2023.02.24 Agregado =================== ===== ==========

问题1:Error al crear el bean con el nombre 'gateway' definido en el recurso classpath...

Respuesta: Una vez que ocurre este problema, significa que la puerta de enlace no pudo conectarse a la cadena de bloques. En este momento, debe verificar el archivo de configuración especificado del certificado especificado en su directorio local (como el archivo fabric.config.properties en mi artículo), es muy probable que la conexión La ruta incorrecta haga que la puerta de enlace falle.

Pregunta 2: Los archivos de configuración de los miembros de cada organización se pueden dividir.

Por ejemplo, divido org1 y org2.

Cuando comenzamos el proyecto, podemos establecer el archivo de configuración especificado

 

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

 Asegúrese de qué archivo de configuración de la organización está utilizando actualmente.

Supongo que te gusta

Origin blog.csdn.net/Wannabe_hacker/article/details/124284663
Recomendado
Clasificación