前言
提示:服务外包区块链学习
5被ban了,也不知道怎么改能过,无所谓了,我以后能看的见就行,不知道这篇能不能过审
Web3j的使用基本都是看博客和源码一点一点琢磨的
源码地址
项目源码地址
说明:从这篇博客开始就不用Ubuntu写区块链了,改用Windows,因为需要链接前面写的有关NFT系统的后台,而后台在Windows的主机上,即便用VMware设置了端口映射,主机的MataMask还是链接不上虚拟机上的,所以改用Windows,感觉都差不多,甚至Windows还要简单些。
只记录操作 尚硅谷以太坊区块链直达链接
一、Web3j框架准备
1、导入依赖
<!--- web3j -->
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>org.web3j</groupId>
<artifactId>codegen</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>org.web3j</groupId>
<artifactId>geth</artifactId>
<version>5.0.0</version>
<scope>compile</scope>
</dependency>
2、配置类
Web3j框架主要使用的3个对象: Web3j对象类似Geth中的eth Admin对象类似Geth中的personal Geth跟Admin差不多(我也不知道,只知道一个可以解锁账号,一个可以锁账号)
配置类主要用来对这三个对象进行初始化,以及读写超时的设置
package com.nftmanage.nftmanage.config;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.admin.Admin;
import org.web3j.protocol.geth.Geth;
import org.web3j.protocol.http.HttpService;
import java.util.concurrent.TimeUnit;
@Configuration
public class ETHConfig {
@Value("${web3j.client-address}")
private String rpc;
@Bean
public Web3j web3j() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(60*1000, TimeUnit.MILLISECONDS);
builder.writeTimeout(60*1000, TimeUnit.MILLISECONDS);
builder.readTimeout(60*1000, TimeUnit.MILLISECONDS);
OkHttpClient httpClient = builder.build();
Web3j web3j = Web3j.build(new HttpService(rpc,httpClient,false));
return web3j;
}
@Bean
public Admin admin() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(60 * 1000, TimeUnit.MILLISECONDS);
builder.writeTimeout(60 * 1000, TimeUnit.MILLISECONDS);
builder.readTimeout(60 * 1000, TimeUnit.MILLISECONDS);
OkHttpClient httpClient = builder.build();
Admin admin = Admin.build(new HttpService(rpc, httpClient, false));
return admin;
}
@Bean
public Geth geth() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(60 * 1000, TimeUnit.MILLISECONDS);
builder.writeTimeout(60 * 1000, TimeUnit.MILLISECONDS);
builder.readTimeout(60 * 1000, TimeUnit.MILLISECONDS);
OkHttpClient httpClient = builder.build();
Geth geth = Geth.build(new HttpService(rpc, httpClient, false));
return geth;
}
}
二、Web3j智能合约
1、智能合约类准备
要把智能合约转化为对应的类,才可以调用智能合约 转化需要使用智能合约的ABI和BIN 需要两个工具类 两种方法,后面一种简单的多
package com.nftmanage.nftmanage.utils;
import org.web3j.codegen.SolidityFunctionWrapperGenerator;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.stream.Stream;
public class SolidityUtils {
public static void generateABIAndBIN(String abi,String bin,String abiFileName,String binFileName){
File abiFile = new File("src/main/resources/"+abiFileName);
File binFile = new File("src/main/resources/"+binFileName);
BufferedOutputStream abiBos = null;
BufferedOutputStream binBos = null;
try{
FileOutputStream abiFos = new FileOutputStream(abiFile);
FileOutputStream binFos = new FileOutputStream(binFile);
abiBos = new BufferedOutputStream(abiFos);
binBos = new BufferedOutputStream(binFos);
abiBos.write(abi.getBytes());
abiBos.flush();
binBos.write(bin.getBytes());
binBos.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
if(abiBos != null){
try{
abiBos.close();;
}catch (IOException e){
e.printStackTrace();
}
}
if(binBos != null){
try {
binBos.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
public static void generateClass(String abiFile,String binFile,String generateFile){
String[] args = Arrays.asList(
"-a",abiFile,
"-b",binFile,
"-p","",
"-o",generateFile
).toArray(new String[0]);
Stream.of(args).forEach(System.out::println);
SolidityFunctionWrapperGenerator.main(args);
}
}
package com.nftmanage.nftmanage.utils;
import org.junit.Test;
public class ETHUtils {
@Test
public void genAbi(){
String abi = "[\n" +
"\t{\n" +
"\t\t\"constant\": false,\n" +
"\t\t\"inputs\": [\n" +
"\t\t\t{\n" +
"\t\t\t\t\"name\": \"amount\",\n" +
"\t\t\t\t\"type\": \"uint256\"\n" +
"\t\t\t}\n" +
"\t\t],\n" +
"\t\t\"name\": \"withdraw\",\n" +
"\t\t\"outputs\": [],\n" +
"\t\t\"payable\": false,\n" +
"\t\t\"stateMutability\": \"nonpayable\",\n" +
"\t\t\"type\": \"function\"\n" +
"\t},\n" +
"\t{\n" +
"\t\t\"payable\": true,,\n" +
"\t\t\"stateMutability\": \"payable\",\n" +
"\t\t\"type\": \"fallback\"\n" +
"\t}\n" +
"]";
String bin = "{\n" +
"\t\"linkReferences\": {},\n" +
"\t\"object\": \"608060405234801561001057600080fd5b5060f78061001f6000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d146041575b005b348015604c57600080fd5b50606960048036038101908080359060200190929190505050606b565b005b683635c9adc5dea000008111151515608257600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f1935050505015801560c7573d6000803e3d6000fd5b50505600a165627a7a723058202bb5be9eae163caf1d06733e5ba29e5b2a51e2290708d5d287635637bd249a920029\",\n" +
"\t\"opcodes\": \"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0xF7 DUP1 PUSH2 0x1F PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x3F JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x2E1A7D4D EQ PUSH1 0x41 JUMPI JUMPDEST STOP JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x4C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x69 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0x6B JUMP JUMPDEST STOP JUMPDEST PUSH9 0x3635C9ADC5DEA00000 DUP2 GT ISZERO ISZERO ISZERO PUSH1 0x82 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x8FC DUP3 SWAP1 DUP2 ISZERO MUL SWAP1 PUSH1 0x40 MLOAD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP6 DUP9 DUP9 CALL SWAP4 POP POP POP POP ISZERO DUP1 ISZERO PUSH1 0xC7 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0x2b 0xb5 0xbe SWAP15 0xae AND EXTCODECOPY 0xaf SAR MOD PUSH20 0x3E5BA29E5B2A51E2290708D5D287635637BD249A SWAP3 STOP 0x29 \",\n" +
"\t\"sourceMap\": \"28:197:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;28:197:0;;;;;;;\"\n" +
"}";
String abiFileName = "contract/Faucet.abi";
String binFileName = "contract/Faucet.bin";
SolidityUtils.generateABIAndBIN(abi,bin,abiFileName,binFileName);
}
@Test
public void generateJavaFile(){
String abiFile = "src/main/resources/contract/NFTMarket.abi";
String binFile = "src/main/resources/contract/NFTMarket.bin";
String generateFile = "src/main/java/com/nftmanage/nftmanage/solidity/";
SolidityUtils.generateClass(abiFile,binFile,generateFile);
}
}
第二个类中ABI和BIN需要具体调整成我这样,最后生成的abi和bin文件名可以根据实际使用情况更 准备完毕之后,在第二个类第一个方法那里右键运行方法就可以运行生成abi和bin文件 第二个方法就是通过已有的abi和bin文件来生成Java类的
ABI和BIN的来源: 编译的地方先选择你的智能合约,然后ABI就是复制ABI的地方,Bytecode就是BIN
觉得麻烦的直接在你想要文件在的地方右键新建一个文件命名成abi和bin文件,然后把复制的之间粘贴到文件里面就可以了,前面那些都太麻烦了
2、注意事项
NFT智能合约Java类会报字符串超出String的长度的错,所以需要使用StringBuilder将类里的那一长串字符分开,最后合到一起。
像我这样
三、实践
controller层
package com.nftmanage.nftmanage.controller;
import com.nftmanage.nftmanage.service.BlockChainService;
import com.nftmanage.nftmanage.utils.Result;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.web3j.crypto.Credentials;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@Api(tags="区块链接口类")
@RestController
@CrossOrigin
public class BlockChainController {
@Autowired
BlockChainService blockChainService;
@PostMapping("getHeight")
public Result getHeight() {
return blockChainService.getHeight();
}
@PostMapping("getAccount")
public Result getAccount(){
return blockChainService.getAccounts();
}
@PostMapping("getBalanceOf")
public Result getBalanceOf(@RequestBody Map<String, String> map){
return blockChainService.getBlanceOf(map.get("address"));
}
@PostMapping("sendTransaction")
public Result sendTransaction(@RequestBody Map<String, String> map) throws IOException {
return blockChainService.sendEtherTransaction(map.get("from"),map.get("to"),new BigInteger(map.get("value")+"000000000000000000"),map.get("password"));
}
@PostMapping("withdraw")
public Result withdraw(@RequestBody Map<String, String> map) throws Exception {
return blockChainService.withdraw(Credentials.create(map.get("privateKey")),map.get("amount"));
}
@PostMapping("mintNFT")
public Result mintNFT(@RequestBody Map<String, String> map) throws IOException, ExecutionException, InterruptedException {
blockChainService.mintNFT(Credentials.create(map.get("privateKey")),map.get("tokenURI"));
return Result.ok();
}
@PostMapping("totalSupply")
public Result totalSupply(@RequestBody Map<String, String> map) throws IOException, ExecutionException, InterruptedException {
return Result.ok(blockChainService.totalSupply(Credentials.create(map.get("privateKey"))));
}
@PostMapping("burnNFT")
public Result burnNFT(@RequestBody Map<String, String> map) throws IOException, ExecutionException, InterruptedException {
blockChainService.burnNFT(Credentials.create(map.get("privateKey")),new BigInteger(map.get("tokenId")));
return Result.ok();
}
@PostMapping("tranNFT")
public Result tranNFT(@RequestBody Map<String, String> map) throws IOException, ExecutionException, InterruptedException {
blockChainService.tranNFT(Credentials.create(map.get("privateKey")),map.get("to"),new BigInteger(map.get("tokenId")));
return Result.ok();
}
@PostMapping("tokenURI")
public Result tokenURI(@RequestBody Map<String, String> map) throws IOException, ExecutionException, InterruptedException {
return blockChainService.tokenURI(Credentials.create(map.get("privateKey")),new BigInteger(map.get("tokenId")));
}
}
serviceImpl层:
package com.nftmanage.nftmanage.service.impl;
import com.nftmanage.nftmanage.service.BlockChainService;
import com.nftmanage.nftmanage.solidity.Faucet;
import com.nftmanage.nftmanage.solidity.NFTMarket;
import com.nftmanage.nftmanage.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.admin.Admin;
import org.web3j.protocol.admin.methods.response.BooleanResponse;
import org.web3j.protocol.admin.methods.response.PersonalUnlockAccount;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.RemoteFunctionCall;
import org.web3j.protocol.core.Request;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.*;
import org.web3j.protocol.geth.Geth;
import org.web3j.tx.RawTransactionManager;
import org.web3j.tx.TransactionManager;
import org.web3j.tx.gas.StaticGasProvider;
import org.web3j.utils.Convert;
import java.io.IOException;
import java.math.BigInteger;
import java.util.concurrent.ExecutionException;
@Service
public class BlockChainServiceImpl implements BlockChainService {
@Autowired
private Web3j web3j;
@Autowired
private Admin admin;
@Autowired
private Geth geth;
public Result getHeight(){
try {
EthBlockNumber blockNumber = web3j.ethBlockNumber().send();
return Result.ok(blockNumber.getBlockNumber().longValue());
} catch (Exception e) {
e.printStackTrace();
}
return Result.error();
}
@Override
public Result getAccounts() {
try {
EthAccounts accounts = web3j.ethAccounts().send();
return Result.ok(accounts.getAccounts());
} catch (IOException e) {
e.printStackTrace();
}
return Result.error();
}
@Override
public Result getBlanceOf(String address) {
EthGetBalance balance = null;
try {
balance = web3j.ethGetBalance(address, DefaultBlockParameter.valueOf("latest")).send();
return Result.ok(Convert.fromWei(balance.getBalance().toString(), Convert.Unit.ETHER).toPlainString().concat("ether"));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public boolean unlockAccount(String address, String password) throws IOException {
Request<?, PersonalUnlockAccount> request = admin.personalUnlockAccount(address, password);
return request.send().accountUnlocked();
}
public boolean lockAccount(String address) throws IOException {
Request<?, BooleanResponse> request = geth.personalLockAccount(address);
BooleanResponse response = request.send();
return response.success();
}
public BigInteger getNonce(String address) throws IOException {
Request<?, EthGetTransactionCount> request = web3j.ethGetTransactionCount(address, DefaultBlockParameterName.LATEST);
return request.send().getTransactionCount();
}
@Override
public Result sendEtherTransaction(String from,String to,BigInteger value,String password) throws IOException {
if(unlockAccount(from,password)){
try {
Transaction transaction = new Transaction(from,null,null,null,to,value,null);
String transactionHash = web3j.ethSendTransaction(transaction).send().getTransactionHash();
lockAccount(from);
return Result.ok(transactionHash);
} catch (IOException e) {
e.printStackTrace();
}
}
return Result.error();
}
@Override
public Result withdraw(Credentials credentials,String amount) throws Exception {
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
TransactionManager transactionManager = new RawTransactionManager(web3j, credentials, 123);
Faucet contract = Faucet.load("0xF700ebBC2B452b1D699e8F9DAB0Cf994BCb4E802",web3j,transactionManager,
new StaticGasProvider(gasPrice,BigInteger.valueOf(3000000L)));
RemoteFunctionCall<TransactionReceipt> setWord = contract.withdraw(new BigInteger("100"));
TransactionReceipt transactionReceipt = setWord.sendAsync().get();
String transactionHash = transactionReceipt.getTransactionHash();
System.out.println(transactionHash);
return Result.ok(transactionHash);
}
@Override
public void mintNFT(Credentials credentials,String tokenURI) throws IOException, ExecutionException, InterruptedException {
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
TransactionManager transactionManager = new RawTransactionManager(web3j, credentials, 123);
NFTMarket contract = NFTMarket.load("0x44F0c18BB444Ce4ff856Ae5938d4c0360e90D81b",web3j,transactionManager,
new StaticGasProvider(gasPrice,BigInteger.valueOf(3000000L)));
RemoteFunctionCall<TransactionReceipt> setWord = contract.mintNFT(credentials.getAddress(),tokenURI);
TransactionReceipt transactionReceipt = setWord.sendAsync().get();
transactionReceipt.getTransactionHash();
}
@Override
public BigInteger totalSupply(Credentials credentials) throws ExecutionException, InterruptedException, IOException {
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
TransactionManager transactionManager = new RawTransactionManager(web3j, credentials, 123);
NFTMarket contract = NFTMarket.load("0x44F0c18BB444Ce4ff856Ae5938d4c0360e90D81b",web3j,transactionManager,
new StaticGasProvider(gasPrice,BigInteger.valueOf(3000000L)));
RemoteFunctionCall<BigInteger> setWord = contract.totalSupply();
BigInteger total = setWord.sendAsync().get();
return total;
}
@Override
public BigInteger balanceOfOwner(Credentials credentials) throws Exception {
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
TransactionManager transactionManager = new RawTransactionManager(web3j, credentials, 123);
NFTMarket contract = NFTMarket.load("0x44F0c18BB444Ce4ff856Ae5938d4c0360e90D81b",web3j,transactionManager,
new StaticGasProvider(gasPrice,BigInteger.valueOf(3000000L)));
RemoteFunctionCall<BigInteger> setWord = contract.balanceOf(credentials.getAddress());
BigInteger total = setWord.sendAsync().get();
return total;
}
@Override
public void burnNFT(Credentials credentials,BigInteger tokenId) throws IOException, ExecutionException, InterruptedException {
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
TransactionManager transactionManager = new RawTransactionManager(web3j, credentials, 123);
NFTMarket contract = NFTMarket.load("0x44F0c18BB444Ce4ff856Ae5938d4c0360e90D81b",web3j,transactionManager,
new StaticGasProvider(gasPrice,BigInteger.valueOf(3000000L)));
RemoteFunctionCall<TransactionReceipt> setWord = contract.burnNFT(tokenId);
setWord.sendAsync().get();
}
@Override
public void tranNFT(Credentials credentials,String to,BigInteger tokenId) throws IOException, ExecutionException, InterruptedException {
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
TransactionManager transactionManager = new RawTransactionManager(web3j, credentials, 123);
NFTMarket contract = NFTMarket.load("0x44F0c18BB444Ce4ff856Ae5938d4c0360e90D81b",web3j,transactionManager,
new StaticGasProvider(gasPrice,BigInteger.valueOf(3000000L)));
RemoteFunctionCall<TransactionReceipt> setWord = contract.safeTransferFrom(credentials.getAddress(),to,tokenId);
setWord.sendAsync().get();
}
@Override
public Result tokenURI(Credentials credentials,BigInteger tokenId) throws IOException, ExecutionException, InterruptedException {
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
TransactionManager transactionManager = new RawTransactionManager(web3j, credentials, 123);
NFTMarket contract = NFTMarket.load("0x44F0c18BB444Ce4ff856Ae5938d4c0360e90D81b",web3j,transactionManager,
new StaticGasProvider(gasPrice,BigInteger.valueOf(3000000L)));
RemoteFunctionCall<String> setWord = contract.tokenURI(tokenId);
String tokenURI = setWord.sendAsync().get();
return Result.ok(tokenURI);
}
}
测试框架(Swager) 测试getBalance方法 测试成功!
其余的方法都是可以实现的,有兴趣的小伙伴自行尝试哦
账号私钥的获取方法:
MataMask查看账号详情
导出私钥,输入MataMask的密码即可
Over
|