想要让 Java 项目直接与 以太坊网络 交互,部署并操作 ERC20 通证?
本文用一份零删减、可跑的 最小可复现代码,带你把 Solidity 到 Spring Boot 的全部流程打通。
为什么要用 Java 直调智能合约
- Java 生态庞大:成熟的企业级框架、海量的第三方库,可以无缝与现有微服务融合。
- Web3j 极简封装:不再需要手动拼接 RLP、ABI,开箱即用。
- 链上 > 链下一体化:测试、监控、数据同步,全部可用 Java 调试器一步步跟。
下文围绕五个关键词 “Java”、“Web3j”、“部署”、“ERC20”、“以太坊网络” 展开,全程可复制粘贴执行。
1. 一键编译:把 .sol 文件变成 .java
1.1 加入 web3j-maven-plugin
在项目根目录 pom.xml 的 <build><plugins> 节点内插入:
<plugin>
<groupId>org.web3j</groupId>
<artifactId>web3j-maven-plugin</artifactId>
<version>4.8.7</version>
<configuration>
<packageName>com.demo.contract</packageName>
<sourceDestination>src/main/java</sourceDestination>
<soliditySourceFiles>
<directory>src/main/resources/solc</directory>
<includes>
<include>**/*.sol</include>
</includes>
</soliditySourceFiles>
</configuration>
</plugin>1.2 把 ERC20.sol 放进去
新建目录 src/main/resources/solc/ERC20.sol,代码文末有完整示例,可直接复制。
在 终端定位到 pom.xml 同级目录,执行:
mvn web3j:generate-sources看到 BUILD SUCCESS 后,com.demo.contract.ERC20.java 已自动生成,里面包含 部署函数 deploy 与 所有 view 函数。
2. 初始化:建立与以太坊的连接
2.1 引入依赖
确保已加载 Web3j、Spring Boot Starter:
<dependency>
<groupId>org.web3j</groupId>
<artifactId>web3j-spring-boot-starter</artifactId>
<version>4.0.3</version>
</dependency>2.2 application.yml 配置节点
web3j:
client-address: https://mainnet.infura.io/v3/YOUR_PROJECT_ID # 或本地私链
spring:
logging:
level:
org.web3j.protocol: DEBUG3. 部署合约:一行 sendAsync() 上链
@Autowired
private Web3j web3j;
private static final Credentials CREDENTIALS =
Credentials.create("0x534d8d93a5ef661..."); // 私钥请务必保密
public String deployToken(String coinName, String symbol, long total) throws Exception {
ERC20 erc20 = ERC20.deploy(
web3j,
CREDENTIALS,
new DefaultGasProvider(),
coinName,
BigInteger.valueOf(total),
symbol
).sendAsync().get(); // 异步提交交易
return erc20.getContractAddress();
}想快速体验?直接调用;嫌弃网络慢?👉 十分钟搭建一条本地以太坊私链,gas 费用自己做主!
4. 加载并交互:查询、转账、授权全套代码
| 场景 | 一句话调函数 |
|---|---|
| 查总发行量 | erc20.totalSupply().send() |
| 查账户余额 | erc20.balanceOf(address).send() |
| 普通转账 | erc20.transfer(to, amount).send() |
| 授权额度 | erc20.approve(spender, amount).send() |
| 查询授权额度 | erc20.allowance(owner, spender).send() |
4.1 REST 接口截取片段
@GetMapping("/balance")
public BigInteger getBalance(
@RequestParam String contractAddress,
@RequestParam String accountAddress) throws Exception {
ERC20 erc20 = ERC20.load(contractAddress, web3j, CREDENTIALS, new DefaultGasProvider());
return erc20.balanceOf(accountAddress).sendAsync().get();
}本地 Swagger 启动即可验证,完整源码文末已贴。
5. ERC20.sol 源码(可直接再编译)
pragma solidity ^0.4.24;
library SafeMath { ... } // 略,见原文
contract ERC20 {
using SafeMath for uint256;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowed;
uint256 private _totalSupply;
string public _coinName;
string public _symbol;
uint8 public decimals = 18;
constructor(
string coinName,
uint256 totalSupply,
string symbol
) public {
_coinName = coinName;
_symbol = symbol;
_totalSupply = totalSupply * 10**uint256(decimals);
_balances[msg.sender] = _totalSupply;
}
function totalSupply() public view returns (uint256) { return _totalSupply; }
function balanceOf(address owner) public view returns (uint256) { return _balances[owner]; }
function transfer(address to, uint256 value) public returns (bool) {
require(to != address(0));
require(value <= _balances[msg.sender]);
_balances[msg.sender] = _balances[msg.sender].sub(value);
_balances[to] = _balances[to].add(value);
emit Transfer(msg.sender, to, value);
return true;
}
function approve(address spender, uint256 value) public returns (bool) {
_allowed[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
function allowance(address owner, address spender) public view returns (uint256) {
return _allowed[owner][spender];
}
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}6. 真机实战:三台机器跑同一份合约
- 机器 A(PC)作为写链节点,部署合约、产 Token。
- 机器 B(服务器)定时调用
totalSupply()把数据写入 MySQL。 - 机器 C(移动 App)只做
balanceOf()+transfer(),执行小额支付。
数据贯通后,每分钟交易数、平均 gas 价格、Token 进出账等实时图表一目了然。👉 零门槛获取链上实时大数据,可视化工具在这。
7. 常见问题 FAQ
Q1:测试网络太多,选哪个?
A:Goerli 与 Sepolia 依旧是稳定性最高的公共测试网;私链请用 Ganache CLI,两秒钟就能挖出新区块。
Q2:为什么部署失败,提示 Intrinsic gas too low?
A:Gas Limit 不足所致。Web3j 4.8.7 自带的 DefaultGasProvider 默认 4,300,000 gas,手动提升到 6,000,000 即可。
Q3:Java 是非异步友好语言,如何处理并发?
A:推荐用 CompletableFuture 包裹所有 .sendAsync(),配合 Spring WebFlux,一串 mono.zip() 即可完成链上链下协同调用。
Q4:私钥放在代码里安全吗?
A:根本不安全!部署 Key Vault、配置文件 Encrypt 或硬件钱包签名后再广播交易才是生产实践。
Q5:如何用单元测试穿越整条链路?
A:2 行即可启动 testcontainers-web3j,在 Docker 中跑一条短暂私链,每次跑完自动销毁,CI/CD 友好。
8. 打包命令速查表
# 编译
mvn clean web3j:generate-sources compile -DskipTests
# 测试
mvn test -Dtest=*
# 容器镜像
mvn spring-boot:build-image小结
- 本文用 “Java + Web3j” 把繁琐的 Solidity—ABI—Java—合约调用链 降到了最简。
- 你只需要 三处改动(
pom.xml、application.yml、私钥)就能让一份 Spring Boot 工程具备直接 部署 ERC20 通证 的能力。 - 思路扩展到 NFT、DeFi 协议,同样适用:只要替换
.sol,再按插件一键完成生成即可。
完成以上步骤后,你就拥有了与全球 以太坊网络 实时交互的 Java 服务,想进一步扩展?先看懂这里,再去研究 二层网络、跨链桥 吧!