DAPP:投票系統
- 1. 專案背景
- 2. 技術選型
- 3. solidity合約代碼
- 4.功能展示
- 1.投票串列界面
- 2.添加投票頁面
- 3.查看票數及投票頁面
- 4.資料庫表
- 5.專案原始碼地址
1. 專案背景
為鞏固近期學習過的區塊鏈相關知識,我們利用幾天時間開發了一套可以實際應用的基于以太坊智能合約的投票系統,
2. 技術選型
- 智能合約撰寫:solidity
- 私鏈環境:ganache-cli
- 前端:thymeleaf模板引擎
- 后端:springboot+mybatis
- 核心依賴jar包:web3j
專案大體框架如下(由于前端內容較少,且僅用作展示實作基本功能,實際開發程序中沒有采用vue):

3. solidity合約代碼
pragma solidity ^ 0.4.26;
contract Ballot {
string public name; //投票的名稱,name of the Ballot
address public chairman; //合約擁有者的地址
bool public closed; // 記錄投票是否結束
// 獲勝票數比例
uint public proportion; // 獲勝時得票數占總票數的最低比例, 例如50%就賦值為50
uint public totalVotes; // 總票數
// 加投票權集合, 表示哪些人有投票權
address[] voters;
struct Proposal { // 候選人資訊的結構體
bytes32 name;
uint voteCount; // 候選人的得票數
}
Proposal[] public proposals; // 候選人的結構體(可變長)陣列
mapping(address => bool) voteRecords; // 投票者是否投票(默認false)
uint[] winningProposals = [0];
bytes32[] winningProposalsName; // 記錄winning候選人名字的陣列
constructor(string _name, bytes32[] _proposals, uint _proportion, address[] _voters) public { // 合約的建構式
chairman = msg.sender; // 記錄合約的擁有者
closed = false; // 合約默認處于打開
name = _name; // 投票的名稱,如 "選舉學生會主席"
for(uint i = 0; i < _proposals.length; i++) {
proposals.push(Proposal({
name: _proposals[i],
voteCount: 0
}));
}
proportion = _proportion;
voters = _voters;
totalVotes = voters.length;
}
function setChairman(address _chairman) external { // 更換合約擁有者時用
chairman = _chairman;
}
function vote(uint proposal) public { //給候選人投票, 需傳入候選人的序號及投票者的地址
address voterAddress = msg.sender;
require(!closed, "the ballot is already closed."); // 保證合約沒有關閉,即投票沒有結束
// 看投票者的地址是否在合法名單中
bool legal = false;
for(uint i = 0; i < voters.length; i++){
if(voters[i] == voterAddress){
legal = true;
break;
}
}
require(legal, "the voter is illeagal!");
require(proposal < proposals.length, "the prosal is invalid!");
require(!voteRecords[voterAddress], "Already voted."); // 保證投票者沒有投過票
voteRecords[voterAddress] = true;
proposals[proposal].voteCount += 1; // 候選人得票數加一
}
function closeBallot() public { // 關閉投票
require(chairman == msg.sender, "only the chairman can close the ballot."); // 只有擁有者可以關閉投票
closed = true;
}
function getWinningProposals() internal { //統計投票的獲勝者
winningProposals.length = 0;
uint winningVoteCount = 0;
for(uint i = 0; i < proposals.length; i++) {
if(proposals[i].voteCount * 100 / totalVotes >= proportion) {
winningProposals.push(i);
}
}
if(winningProposals.length == 0){
for(i = 0; i < proposals.length; i++){
if(proposals[i].voteCount > winningVoteCount){
winningVoteCount = proposals[i].voteCount;
}
}
for(i = 0; i < proposals.length; i++){
if(proposals[i].voteCount == winningVoteCount){
winningProposals.push(i);
}
}
}
}
function winnerName() public view returns (bytes32[]) { // 回傳得票數最高的候選人的名字
require(closed, "only when the ballot is closed can you examine the winner");
getWinningProposals();
for(uint i = 0; i < winningProposals.length; i++){
winningProposalsName.push(proposals[winningProposals[i]].name);
}
return winningProposalsName;
}
function getProposalNumber() public view returns (uint){
return proposals.length;
}
}
4.功能展示
1.投票串列界面
- 點擊左上角“發起投票”可以新建一次投票;
- 在已有投票串列中,可以對未結束的投票進行投票選舉;
- 僅有合約擁有者可以終止投票,該程序需要輸入私鑰簽名驗證,

2.添加投票頁面
在此頁面可以新建一個投票,并需要提供私鑰,部署并注冊為合約擁有者,

3.查看票數及投票頁面
投票時需要輸入私鑰簽名,且每個賬戶地址僅可投票一次,

4.資料庫表
這里為了簡化設計,沒有另外設計一個投票集合合約,而是使用了mysql資料庫存盤資料,該操作不會泄露區塊資訊,

5.專案原始碼地址
專案原始碼github地址
本專案由于僅為學習鞏固,代碼上有許多冗余和不足,不過基本功能都已經實作,便沒有進行代碼規范,望大家閱讀時諒解,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/267103.html
標籤:區塊鏈
