- 我们通过几个示例项目来阐述一个完整的Dapp开发过程
- 我们通过三个项目实例来看下
商品管理项目
通讯录项目
投票系统项目
- 我们这里详细以商品管理项目来阐述整个开发过程
- 写在最后的是我们的项目代码示例仓库
1) 简单的设计
商品管理(简单示例)
- 商品登记
- 查询
- 上架/下架
2)相关智能合约的编写
// 指定编译环境版本的
pragma solidity >=0.4.21 <0.6.0;
/**
* owned 是合约的管理者
*/
contract owned {
address public owner; // 变量账户地址
/**
* 初始化构造函数
* 部署到以太坊节点会被执行一次
* 把部署者的账户地址赋值给一个变量值
* 这个变量值会被存储到区块链的账本中
*/
contructor() public {
owner = msg.sender;
}
/**
* 这里是一个函数修改器,用于限制方法的行为
* 判断当前合约的调用者是否是合约的所有者
* 必须使用当时部署合约的地址才可以调用
*/
modifier onlyOwner {
require(msg.sender == owner, "sender is not authorized");
_;
}
/**
* 合约的所有者指派一个新的管理员
* 也就是更改管理员地址
* @param newOwner address 新的管理账户地址
*/
function transferOwnership(address newOwner) public onlyOwner {
if (newOwner != address(0)) {
owner = newOwner;
}
}
}
/** 接下来是业务逻辑的合约 **/
// 这里继承了前面权限管理的合约
contract Commodity is owned {
// 这个结构体包含了商品的各个属性
struct Comminfo {
string account_name; // 商品名称
string code; // 商品编号
string number; // 商品数量
uint8 status; // 1是上架,2是下架
}
// 商品信息不止登记一条
// 所有商品信息保存在这个mapping这个映射中
// 记录所有数据映射
mapping(uint => Comminfo) commof;
// 整个商品信息有多少条的统计
uint[] lengths;
// 表明有多少条商品信息登记了
// 获取长度
function getLength() public view returns (uint len) {
return lengths.length;
}
// 这里是一个登记的方法,也是保存
// 在这个方法里包含的各个参数属性
// 相当于在mapping状态变量里面继续新增一条商品信息记录
// 实现新增功能
function saveinfo(
string memory account_names,
string memory codes,
string memory numbers,
uint8 status statusw
) public {
uint les = lengths.length;
commOf[les].account_name = account_names;
commOf[les].code = codes;
commOf[les].number = numbers;
commOf[les].status = statusw;
lengths.push(les);
}
// 查询数据
function selectAll(uint key) public view returns (
string memory account_name,
string memory code,
string memory number,
uint8 status,
uint id
) {
account_name = commOf[key].account_name;
code = commOf[key].code;
number = commOf[key].number;
status = commOf[key].status;
id = key;
return (account_name, code, number, status, id);
}
// 判断商品信息是否已经存在,重复性判断
// 两个string比较
function utilCompareInternal(string memory a, string memory b) internal pure returns (bool succ) {
if(bytes(a).length != bytes(b).length) {
return false;
}
for (uint i = 0; i< bytes(a).length; i ++) {
if(bytes(a)[i] != bytes(b)[i]) {
return false;
}
}
return true;
}
// 根据商品代码获取商品信息
function selectOne(uint key, string memory code) public view returns (bool result) {
return utilCompareInternal(commOf[key].code, code);
}
// 设置商品的上架、下架状态
function update(uint key) public {
if(commOf[key].status == 1) {
commOf[key].status = 2;
} else {
commOf[key].status = 1;
}
}
}
3 )nodejs后端
项目文件:/app/src/index.js
import "../css/index.css"; // 前端样式,与前端交互的css文件
import Web3 from "web3"; // 用于与以太坊节点通信
import metaCoinArtifact from "../../build/contracts/Commodity.json"; // 引入合约的ABI文件
// 关键代码片段
save: async function() {
const {web3} = this;
// 商品代码
var codes = document.geElementById('codes').value
// 名称
var name = document.geElementById('name').value
// 数量
var count = document.geElementById('count').value
// 上下架
var status = document.geElementById('switch').value
// 为空校验
if(!code || !name || !count) {
alert("Parameter cannot be null!");
return
}
const {saveinfo} = this.meta.methods;
await saveinfo(name, codes, count, status).send({from: this.account, gas: 3141592}, function() {
location.reload();
});
}
4 )web前端
这里使用最简单的方式来编码
<!-- 关键代码 伪代码 -->
<script src="引入jQuery"></script>
<link rel='stylesheet' type='text/css' href='引入样式文件'>
<script src="index.js"></script>
<button onclick="App.update()">上架/下架</button>
<button onclick="App.selectOne()">查询</button>
<div class='content'>
<button onclick="App.save()">保存</button>
<label>商品代码: <input type='text' id="codes" /></label>
<label>商品名称: <input type='text' id="name" /></label>
<label>商品数量: <input type='text' id="count" /></label>
<label>上下架:
<select id="switch">
<option value="1">上架</option>
<option value="2">下架</option>
</select>
</label>
</div>
- 查询(数据检索)功能
- 保存功能
- 区块链系统具有不可篡改和公正性,实现投票这样的系统是很适合的应用场景
- 查看投票
- 结束投票
- 根据事项发起投票
- 支持或反对
- 同一个地址只能投票一次
- 对于区块链来说,无非就是支持一组属性变量(状态变量),是可以存储在区块账本里面的
- 以及所有与那些属性变量相关的动作(合约中的方法),通过调用这些方法,不断更改状态变量
- 在链上更改状态变量是指不断在新的区块里产生新的值,历史状态值依然保留,是区块链不可串改性的体现
- 不管什么样的合约,它们的逻辑大抵如此
- 与传统的数据库编程不同的是
- 传统数据库编程,我们会在数据库端使用表来处理数据,创建存储过程(相关于区块链中的智能合约)
- 区块链,是把数据存在链上,通过链上合约进行操作,部署合约后,需要后端和前端来实现一个DAPP