Java与区块链:Web3j/Hyperledger Fabric SDK的应用开发实践
大家好!今天我们来探讨Java在区块链应用开发中的实践,重点关注Web3j和Hyperledger Fabric SDK这两个强大的工具。我们将深入了解如何使用它们与以太坊和Hyperledger Fabric区块链网络进行交互,并构建实际的应用。
1. 区块链技术与Java:为什么选择Java?
区块链作为一种去中心化的分布式账本技术,正在深刻地改变各行各业。Java作为一种成熟、稳定、跨平台的编程语言,在企业级应用开发中占据主导地位。将Java与区块链技术结合,可以充分利用Java的生态系统和开发经验,快速构建可靠、可扩展的区块链应用。
Java的优势:
- 成熟的生态系统: 拥有丰富的库、框架和工具,便于快速开发和集成。
- 跨平台性: “一次编写,到处运行”的特性,方便部署到不同的环境。
- 强大的性能: JVM的优化能力,保证了应用的性能。
- 安全性: Java的安全特性,有助于构建安全的区块链应用。
- 大型企业广泛使用: 容易找到具备相关开发经验的工程师。
2. Web3j:与以太坊交互的利器
Web3j是一个轻量级的Java库,用于与以太坊区块链进行交互。它提供了一系列API,可以方便地进行以下操作:
- 连接到以太坊节点(例如:Geth、Parity)。
- 创建和管理以太坊账户。
- 发送以太币(ETH)交易。
- 部署和调用智能合约。
- 监听区块链事件。
2.1 Web3j入门:配置与连接
首先,我们需要在项目中引入Web3j依赖。如果是使用Maven,可以在pom.xml文件中添加以下依赖:
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>4.9.4</version> <!-- 请使用最新版本 -->
</dependency>
接下来,我们需要连接到以太坊节点。以下代码演示了如何连接到本地的Geth节点:
import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
public class Web3jConnect {
public static void main(String[] args) {
// 连接到本地Geth节点 (需要确保Geth节点已经启动)
Web3j web3 = Web3j.build(new HttpService("http://localhost:8545"));
try {
// 测试连接是否成功
String clientVersion = web3.web3ClientVersion().send().getWeb3ClientVersion();
System.out.println("Connected to Ethereum client: " + clientVersion);
} catch (Exception e) {
System.err.println("Failed to connect to Ethereum client: " + e.getMessage());
e.printStackTrace();
} finally {
web3.shutdown();
}
}
}
代码解释:
Web3j.build(new HttpService("http://localhost:8545")): 创建一个Web3j实例,并通过HTTP连接到本地的Geth节点。你需要确保Geth节点已经启动,并且监听在8545端口。web3.web3ClientVersion().send().getWeb3ClientVersion(): 调用web3ClientVersion方法获取客户端版本号,用于测试连接是否成功。web3.shutdown(): 关闭Web3j连接,释放资源。
2.2 创建和管理账户
Web3j可以用来创建和管理以太坊账户。以下代码演示了如何创建一个新的以太坊账户:
import org.web3j.crypto.Credentials;
import org.web3j.crypto.WalletUtils;
import java.io.File;
public class AccountCreation {
public static void main(String[] args) {
try {
// 生成钱包文件存储目录
File walletDir = new File("wallets");
if (!walletDir.exists()) {
walletDir.mkdirs();
}
// 生成随机密码
String password = "your_secret_password"; // 请替换为安全的密码
// 创建新的钱包文件
String fileName = WalletUtils.generateNewWalletFile(password, walletDir, true);
System.out.println("New wallet file created: " + walletDir.getAbsolutePath() + "/" + fileName);
// 从钱包文件加载账户
Credentials credentials = WalletUtils.loadCredentials(password, walletDir.getAbsolutePath() + "/" + fileName);
System.out.println("Account address: " + credentials.getAddress());
} catch (Exception e) {
System.err.println("Failed to create or load wallet: " + e.getMessage());
e.printStackTrace();
}
}
}
代码解释:
WalletUtils.generateNewWalletFile(password, walletDir, true): 使用给定的密码和目录生成一个新的钱包文件。true表示使用轻量级的KeyStore文件格式。WalletUtils.loadCredentials(password, walletDir.getAbsolutePath() + "/" + fileName): 使用密码和钱包文件加载账户信息。credentials.getAddress(): 获取账户的地址。
警告: 请务必妥善保管你的钱包文件和密码,丢失它们将导致你的以太币丢失。不要将密码硬编码到代码中,使用环境变量或配置文件来管理密码。
2.3 发送以太币交易
以下代码演示了如何发送以太币交易:
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;
import org.web3j.crypto.Credentials;
import org.web3j.tx.Transfer;
import java.math.BigDecimal;
import java.math.BigInteger;
public class SendEther {
public static void main(String[] args) {
Web3j web3 = Web3j.build(new HttpService("http://localhost:8545"));
try {
// 替换为你的账户私钥 或 使用钱包文件加载 Credentials
Credentials credentials = Credentials.create("YOUR_PRIVATE_KEY");
// 收款人地址
String recipientAddress = "RECIPIENT_ADDRESS";
// 要发送的以太币数量 (单位: ether)
BigDecimal amount = BigDecimal.valueOf(0.01);
// 发送以太币
TransactionReceipt transactionReceipt = Transfer.sendFunds(
web3,
credentials,
recipientAddress,
amount,
Transfer.GAS_PRICE, // 默认 gas 价格
Transfer.GAS_LIMIT // 默认 gas 限制
).send();
System.out.println("Transaction hash: " + transactionReceipt.getTransactionHash());
} catch (Exception e) {
System.err.println("Failed to send ether: " + e.getMessage());
e.printStackTrace();
} finally {
web3.shutdown();
}
}
}
代码解释:
Credentials.create("YOUR_PRIVATE_KEY"): 使用私钥创建Credentials对象。请替换为你的账户私钥。 强烈建议从环境变量或配置文件中读取私钥,而不是硬编码到代码中。也可以使用WalletUtils.loadCredentials从钱包文件加载Credentials。Transfer.sendFunds(...): 使用Transfer类发送以太币。transactionReceipt.getTransactionHash(): 获取交易哈希值。
注意事项:
- 发送交易需要消耗Gas,Gas Price和Gas Limit需要根据当前网络状况进行调整。
- 请确保你的账户有足够的以太币来支付Gas费用。
- 在测试环境中,可以使用Faucet获取测试币。
2.4 智能合约交互
Web3j可以方便地与智能合约进行交互。首先,我们需要编译智能合约,并生成Java wrapper类。假设我们有一个简单的智能合约:
pragma solidity ^0.8.0;
contract Greeter {
string greeting;
constructor(string memory _greeting) {
greeting = _greeting;
}
function greet() public view returns (string memory) {
return greeting;
}
function setGreeting(string memory _greeting) public {
greeting = _greeting;
}
}
使用Solidity编译器(solc)编译智能合约,并使用Web3j命令行工具生成Java wrapper类:
solc Greeter.sol --bin --abi --optimize -o .
web3j generate solidity -b Greeter.bin -a Greeter.abi -o src/main/java -p com.example.greeter
这会在src/main/java/com/example/greeter目录下生成Greeter.java文件。
然后,我们可以使用Web3j部署和调用智能合约:
import com.example.greeter.Greeter; // 替换为你的包名
import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
import org.web3j.crypto.Credentials;
import org.web3j.tx.gas.DefaultGasProvider;
public class ContractInteraction {
public static void main(String[] args) {
Web3j web3 = Web3j.build(new HttpService("http://localhost:8545"));
try {
// 替换为你的账户私钥 或 使用钱包文件加载 Credentials
Credentials credentials = Credentials.create("YOUR_PRIVATE_KEY");
// 部署智能合约
Greeter greeter = Greeter.deploy(
web3,
credentials,
new DefaultGasProvider(),
"Hello, World!" // 构造函数参数
).send();
String contractAddress = greeter.getContractAddress();
System.out.println("Contract deployed at address: " + contractAddress);
// 调用智能合约的方法
String greeting = greeter.greet().send();
System.out.println("Greeting: " + greeting);
// 设置新的greeting
greeter.setGreeting("Hello, Java!").send();
// 再次调用greet方法
greeting = greeter.greet().send();
System.out.println("New Greeting: " + greeting);
} catch (Exception e) {
System.err.println("Failed to interact with contract: " + e.getMessage());
e.printStackTrace();
} finally {
web3.shutdown();
}
}
}
代码解释:
Greeter.deploy(...): 部署智能合约。greeter.getContractAddress(): 获取合约地址。greeter.greet().send(): 调用greet方法。greeter.setGreeting("Hello, Java!").send(): 调用setGreeting方法。
2.5 监听区块链事件
Web3j可以监听智能合约发出的事件。以下代码演示了如何监听Greeter合约的GreetingChanged事件(需要修改Greeter.sol,添加事件):
pragma solidity ^0.8.0;
contract Greeter {
string greeting;
event GreetingChanged(string newGreeting); // 定义事件
constructor(string memory _greeting) {
greeting = _greeting;
}
function greet() public view returns (string memory) {
return greeting;
}
function setGreeting(string memory _greeting) public {
greeting = _greeting;
emit GreetingChanged(_greeting); // 触发事件
}
}
import com.example.greeter.Greeter;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
import org.web3j.crypto.Credentials;
import org.web3j.tx.gas.DefaultGasProvider;
public class EventListener {
public static void main(String[] args) {
Web3j web3 = Web3j.build(new HttpService("http://localhost:8545"));
try {
// 替换为你的账户私钥 或 使用钱包文件加载 Credentials
Credentials credentials = Credentials.create("YOUR_PRIVATE_KEY");
// 部署智能合约
Greeter greeter = Greeter.deploy(
web3,
credentials,
new DefaultGasProvider(),
"Hello, World!"
).send();
String contractAddress = greeter.getContractAddress();
System.out.println("Contract deployed at address: " + contractAddress);
// 监听GreetingChanged事件
greeter.greetingChangedEventFlowable(null).subscribe(event -> {
System.out.println("Greeting changed to: " + event.newGreeting);
});
// 设置新的greeting (触发事件)
greeter.setGreeting("Hello, Event!").send();
// 为了保证能够接收到事件,这里需要等待一段时间。实际应用中不需要sleep。
Thread.sleep(5000);
} catch (Exception e) {
System.err.println("Failed to listen to events: " + e.getMessage());
e.printStackTrace();
} finally {
web3.shutdown();
}
}
}
代码解释:
greeter.greetingChangedEventFlowable(null).subscribe(event -> { ... }): 订阅GreetingChanged事件。当事件发生时,会执行subscribe方法中的代码。
3. Hyperledger Fabric SDK:构建企业级区块链应用
Hyperledger Fabric是一个企业级的许可型区块链平台,专注于高性能、可扩展性和安全性。Hyperledger Fabric SDK for Java 提供了 Java API,用于与 Fabric 网络进行交互,包括:
- 连接到 Fabric 网络。
- 注册和登记用户。
- 安装、实例化和升级链码(智能合约)。
- 调用链码。
- 查询账本。
3.1 Fabric SDK入门:配置与连接
首先,我们需要在项目中引入Fabric SDK依赖。如果是使用Maven,可以在pom.xml文件中添加以下依赖(需要根据Fabric版本进行调整):
<dependency>
<groupId>org.hyperledger.fabric</groupId>
<artifactId>fabric-sdk-java</artifactId>
<version>2.2.0</version> <!-- 请使用最新版本并确保与你的Fabric版本兼容 -->
</dependency>
接下来,我们需要配置 Fabric 网络信息,包括通道(Channel)、组织(Organization)、节点(Peer)和排序服务(Orderer)的信息。这些信息通常存储在一个配置文件中。
以下是一个简单的配置文件示例(fabric.properties):
# Channel configuration
channel.name=mychannel
# Organization configuration
org.example.mspid=Org1MSP
org.example.peer.0.name=peer0.org1.example.com
org.example.peer.0.grpc.host=localhost
org.example.peer.0.grpc.port=7051
org.example.peer.0.eventHub.host=localhost
org.example.peer.0.eventHub.port=7053
org.example.orderer.name=orderer.example.com
org.example.orderer.grpc.host=localhost
org.example.orderer.grpc.port=7050
然后,我们可以使用Fabric SDK连接到 Fabric 网络:
import org.hyperledger.fabric.gateway.Gateway;
import org.hyperledger.fabric.gateway.Network;
import org.hyperledger.fabric.gateway.Contract;
import org.hyperledger.fabric.gateway.Wallet;
import org.hyperledger.fabric.gateway.Wallets;
import java.nio.file.Paths;
public class FabricConnect {
public static void main(String[] args) {
try {
// 加载钱包
Wallet wallet = Wallets.newFileSystemWallet(Paths.get("wallet")); // 需要提前创建钱包
// 创建网关构建器
Gateway.Builder builder = Gateway.createBuilder()
.identity(wallet, "user1") // 替换为你的用户身份
.networkConfig(Paths.get("connection.json")) // Fabric提供的连接配置文件,注意不是上面的fabric.properties
.discovery(true); // 启用服务发现
// 创建网关
try (Gateway gateway = builder.connect()) {
// 获取网络
Network network = gateway.getNetwork("mychannel"); // 替换为你的通道名称
// 获取合约
Contract contract = network.getContract("basic"); // 替换为你的链码名称
System.out.println("Successfully connected to Fabric network.");
// 可以调用链码或者查询账本
// ...
}
} catch (Exception e) {
System.err.println("Failed to connect to Fabric network: " + e.getMessage());
e.printStackTrace();
}
}
}
代码解释:
Wallets.newFileSystemWallet(Paths.get("wallet")): 创建一个基于文件系统的钱包。你需要提前创建钱包,并将用户身份添加到钱包中。Gateway.createBuilder(): 创建一个网关构建器。.identity(wallet, "user1"): 设置用户身份。.networkConfig(Paths.get("connection.json")): 设置Fabric网络的连接配置文件。这个connection.json文件是由Fabric网络管理员提供的,包含了网络拓扑信息。.discovery(true): 启用服务发现。gateway.getNetwork("mychannel"): 获取通道。network.getContract("basic"): 获取链码合约。
3.2 注册和登记用户
在 Fabric 网络中,每个用户都需要先注册和登记才能使用。可以使用 Fabric CA(Certificate Authority)进行用户管理。以下代码演示了如何使用 Fabric CA 客户端注册和登记用户:
import org.hyperledger.fabric.sdk.Enrollment;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.security.CryptoSuite;
import org.hyperledger.fabric.sdk.security.CryptoSuiteFactory;
import org.hyperledger.fabric_ca.sdk.HFCAClient;
import org.hyperledger.fabric_ca.sdk.RegistrationRequest;
import java.nio.file.Paths;
import java.util.Properties;
import java.util.Set;
public class UserRegistration {
public static void main(String[] args) {
try {
// Fabric CA 服务器地址
String caUrl = "http://localhost:7054"; // 替换为你的 CA 地址
// CA 客户端属性
Properties caProps = new Properties();
caProps.put("pemFile", Paths.get("../fabric-samples/test-network/organizations/fabric-ca/org1/ca_sk/ca.org1.example.com-cert.pem").toAbsolutePath().toString()); // 替换为你的 CA 证书路径
caProps.put("allowAllHostNames", "true");
// 创建 CA 客户端
HFCAClient caClient = HFCAClient.createNewInstance(caUrl, caProps);
CryptoSuite cryptoSuite = CryptoSuiteFactory.instance();
caClient.setCryptoSuite(cryptoSuite);
// 管理员用户
User admin = // 从钱包或者其他方式加载管理员用户,需要具有 enroll 和 register 权限
null;
// 注册请求
RegistrationRequest registrationRequest = new RegistrationRequest("user1", "org1.department1"); // 替换为你的用户名和组织
registrationRequest.setAffiliation("org1.department1");
registrationRequest.setEnrollmentID("user1");
// 注册用户
String enrollmentSecret = caClient.register(registrationRequest, admin);
System.out.println("Successfully registered user. Enrollment secret: " + enrollmentSecret);
// 登记用户
Enrollment enrollment = caClient.enroll("user1", enrollmentSecret);
// 将用户身份保存到钱包
// ...
} catch (Exception e) {
System.err.println("Failed to register and enroll user: " + e.getMessage());
e.printStackTrace();
}
}
}
代码解释:
HFCAClient.createNewInstance(caUrl, caProps): 创建 Fabric CA 客户端。caClient.register(registrationRequest, admin): 注册用户。需要管理员用户具有注册权限。caClient.enroll("user1", enrollmentSecret): 登记用户。- 需要实现从钱包或其他方式加载管理员用户,并进行登记。
3.3 安装、实例化和升级链码
Fabric SDK 提供了 API 来安装、实例化和升级链码。这些操作通常需要管理员权限。由于代码量较大,这里只提供简要的说明:
- 安装链码: 使用
InstallProposalRequest创建安装提案,并将其发送给指定的 Peer 节点。 - 实例化链码: 使用
InstantiateProposalRequest创建实例化提案,并将其发送给 Orderer 节点。 - 升级链码: 使用
UpgradeProposalRequest创建升级提案,并将其发送给 Orderer 节点。
3.4 调用链码和查询账本
Fabric SDK 提供了 API 来调用链码和查询账本。以下代码演示了如何调用链码:
import org.hyperledger.fabric.gateway.Gateway;
import org.hyperledger.fabric.gateway.Network;
import org.hyperledger.fabric.gateway.Contract;
import org.hyperledger.fabric.gateway.Wallet;
import org.hyperledger.fabric.gateway.Wallets;
import java.nio.file.Paths;
public class InvokeChaincode {
public static void main(String[] args) {
try {
// 加载钱包
Wallet wallet = Wallets.newFileSystemWallet(Paths.get("wallet"));
// 创建网关构建器
Gateway.Builder builder = Gateway.createBuilder()
.identity(wallet, "user1")
.networkConfig(Paths.get("connection.json"))
.discovery(true);
// 创建网关
try (Gateway gateway = builder.connect()) {
// 获取网络
Network network = gateway.getNetwork("mychannel");
// 获取合约
Contract contract = network.getContract("basic");
// 调用链码
byte[] result = contract.submitTransaction("createAsset", "asset1", "blue", "5", "Tom", "100"); // 替换为你的链码方法和参数
System.out.println("Transaction result: " + new String(result));
// 查询账本
byte[] queryResult = contract.evaluateTransaction("readAsset", "asset1"); // 替换为你的链码方法和参数
System.out.println("Query result: " + new String(queryResult));
}
} catch (Exception e) {
System.err.println("Failed to invoke chaincode: " + e.getMessage());
e.printStackTrace();
}
}
}
代码解释:
contract.submitTransaction(...): 调用链码的交易方法。该方法会将交易发送到 Fabric 网络,并等待交易被确认。contract.evaluateTransaction(...): 调用链码的查询方法。该方法会在本地模拟执行交易,并返回结果,不会修改账本。
4. Web3j vs. Hyperledger Fabric SDK:选择合适的工具
| 特性 | Web3j | Hyperledger Fabric SDK |
|---|---|---|
| 区块链类型 | 公有链(以太坊) | 许可链(Hyperledger Fabric) |
| 适用场景 | 去中心化应用(DApps),公开透明的场景 | 企业级应用,需要权限控制和高性能的场景 |
| 许可模式 | 开源,MIT License | 开源,Apache 2.0 License |
| 易用性 | 相对简单易用 | 相对复杂,需要对 Fabric 网络有深入了解 |
| 功能 | 与以太坊节点交互,智能合约部署和调用,事件监听 | 与 Fabric 网络交互,链码安装、实例化和调用,用户管理,权限控制 |
选择哪个工具取决于你的应用场景和需求。如果你需要构建一个去中心化的应用,并且希望利用以太坊的生态系统,那么 Web3j 是一个不错的选择。如果你需要构建一个企业级的应用,并且需要权限控制和高性能,那么 Hyperledger Fabric SDK 更适合你。
5. 案例:使用Web3j构建简单的投票DApp
我们可以使用Web3j构建一个简单的投票DApp。首先,我们需要创建一个智能合约:
pragma solidity ^0.8.0;
contract Voting {
mapping(bytes32 => uint256) public votesReceived;
bytes32[] public candidateList;
constructor(bytes32[] memory candidateNames) {
candidateList = candidateNames;
}
function voteForCandidate(bytes32 candidate) public {
require(validCandidate(candidate));
votesReceived[candidate] += 1;
}
function validCandidate(bytes32 candidate) public view returns (bool) {
for(uint i = 0; i < candidateList.length; i++) {
if (candidateList[i] == candidate) {
return true;
}
}
return false;
}
function totalVotesFor(bytes32 candidate) public view returns (uint256) {
require(validCandidate(candidate));
return votesReceived[candidate];
}
}
然后,我们可以使用Web3j部署和调用智能合约,并创建一个简单的用户界面来让用户投票和查看投票结果。由于篇幅限制,这里只提供核心代码片段:
部署合约:
// 部署合约
Voting voting = Voting.deploy(
web3,
credentials,
new DefaultGasProvider(),
candidates // 候选人列表
).send();
投票:
// 投票
voting.voteForCandidate(candidateName).send();
查看投票结果:
// 查看投票结果
BigInteger votes = voting.totalVotesFor(candidateName).send();
用户界面:
可以使用Java Swing、JavaFX或者Web框架(例如:Spring MVC)创建一个简单的用户界面,让用户选择候选人并进行投票。用户界面可以显示每个候选人的投票结果。
6. 案例:使用Hyperledger Fabric SDK构建供应链管理系统
我们可以使用Hyperledger Fabric SDK构建一个简单的供应链管理系统。该系统可以跟踪商品的流转过程,并记录商品的详细信息。
首先,我们需要创建一个链码来管理商品信息:
package main
import (
"encoding/json"
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
type SmartContract struct {
contractapi.Contract
}
type Asset struct {
ID string `json:"ID"`
Color string `json:"color"`
Size int `json:"size"`
Owner string `json:"owner"`
AppraisedValue int `json:"appraisedValue"`
}
// InitLedger creates the initial set of assets on the ledger.
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
assets := []Asset{
{ID: "asset1", Color: "blue", Size: 5, Owner: "Tomoko", AppraisedValue: 300},
{ID: "asset2", Color: "red", Size: 5, Owner: "Brad", AppraisedValue: 400},
{ID: "asset3", Color: "green", Size: 10, Owner: "Jin Soo", AppraisedValue: 500},
{ID: "asset4", Color: "yellow", Size: 10, Owner: "Max", AppraisedValue: 600},
{ID: "asset5", Color: "black", Size: 15, Owner: "Adriana", AppraisedValue: 700},
{ID: "asset6", Color: "white", Size: 15, Owner: "Michel", AppraisedValue: 800},
}
for _, asset := range assets {
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
err = ctx.GetStub().PutState(asset.ID, assetJSON)
if err != nil {
return fmt.Errorf("failed to put to world state. %v", err)
}
}
return nil
}
// CreateAsset issues a new asset to the world state with given details.
func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
asset := Asset{
ID: id,
Color: color,
Size: size,
Owner: owner,
AppraisedValue: appraisedValue,
}
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
return ctx.GetStub().PutState(id, assetJSON)
}
// ReadAsset returns the asset stored in the world state with given id.
func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return nil, fmt.Errorf("failed to read from world state. %v", err)
}
if assetJSON == nil {
return nil, fmt.Errorf("%s does not exist", id)
}
var asset Asset
err = json.Unmarshal(assetJSON, &asset)
if err != nil {
return nil, err
}
return &asset, nil
}
// UpdateAsset updates an existing asset in the world state with provided parameters.
func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error {
asset, err := s.ReadAsset(ctx, id)
if err != nil {
return err
}
asset.Color = color
asset.Size = size
asset.Owner = owner
asset.AppraisedValue = appraisedValue
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
return ctx.GetStub().PutState(id, assetJSON)
}
// DeleteAsset deletes an given asset from the world state.
func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error {
err := ctx.GetStub().DelState(id)
return err
}
func main() {
chaincode, err := contractapi.NewChaincode(new(SmartContract))
if err != nil {
fmt.Printf("Error creating asset-transfer-basic chaincode: %s", err.Error())
return
}
if err := chaincode.Start(); err != nil {
fmt.Printf("Error starting asset-transfer-basic chaincode: %s", err.Error())
}
}
然后,我们可以使用Hyperledger Fabric SDK调用链码,并创建一个用户界面来管理商品信息。
调用链码:
// 创建商品
contract.submitTransaction("CreateAsset", "asset7", "purple", "20", "Lisa", "900");
// 查询商品
byte[] queryResult = contract.evaluateTransaction("ReadAsset", "asset7");
用户界面:
可以使用Java Swing、JavaFX或者Web框架(例如:Spring MVC)创建一个用户界面,让用户创建、查询、更新和删除商品信息。用户界面可以显示商品的详细信息和流转过程。
7. 总结:Java在区块链应用开发中的角色
Java在区块链应用开发中扮演着重要的角色,Web3j和Hyperledger Fabric SDK 是两个常用的工具,分别适用于不同的区块链平台和应用场景。Web3j 简化了与以太坊的交互,方便构建 DApp。Hyperledger Fabric SDK 适用于企业级应用,提供权限控制和高性能。选择合适的工具,并结合Java的生态系统,可以快速构建可靠、可扩展的区块链应用。