区块链笔记:以太坊开发项目示例工程

概述

  • 我们通过几个示例项目来阐述一个完整的Dapp开发过程
  • 我们通过三个项目实例来看下
    • 商品管理项目
    • 通讯录项目
    • 投票系统项目
  • 我们这里详细以商品管理项目来阐述整个开发过程
  • 写在最后的是我们的项目代码示例仓库

以太坊商品管理项目

1) 简单的设计

商品管理(简单示例)

  1. 商品登记
  2. 查询
  3. 上架/下架

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

项目源码地址

  • 点击这里查看 商品管理项目示例
  • 点击这里查看 通讯录项目示例
  • 点击这里查看 投票系统项目示例

你可能感兴趣的:(Block,Chain)