FISCO BCOS 区块链应用(五)结合WeBase开发区块链目录管理系统

目录

前提条件及说明

1.1 搭建Fisco Bcos区块链底层平台

1.2 搭建java项目并引入 web3sdk

1.3 搭建WeBase区块链管理平台

应用开发

 1合约设计

2代码实现

3合约编译

4 java SDK集成

应用端对接

业务代码接入

应用界面效果


前提条件及说明

1.1 搭建Fisco Bcos区块链底层平台

官方地址:

FISCO BCOS 区块链 — FISCO BCOS v2.8.0 文档

打不开可以看看其他的2.2版本地址:

 版本及兼容 - 《FISCO BCOS 2.2 技术文档》 - 书栈网 · BookStack

本案例环境以fisco bcos2.4 , 双机, 单群组, 4机构 8节点为例.

1.2 搭建java项目并引入 web3sdk

        
            org.fisco-bcos
            web3sdk
            2.4.0
            ${dependency.scope}
        

1.3 搭建WeBase区块链管理平台

官方地址:

WeBASE 技术文档 — WeBASE v1.5.4 文档

搭建到节点管理平台即可.即部署 节点前置服务+节点管理服务.

Fisco Bcos内置的案例居为0.4.x版本. 建议也使用该版本进行合约开发.

WeBase提供solidity开发IDE, 可以直接编写,编译合约代码,我们使用172.16.0.119是内网IP, 同学们使用需替换成自己部署的地址

http://172.16.0.119:5002/WeBASE-Front/#/contract

也推荐使用常用的在线IDE, remix

Remix - Ethereum IDE

基于Fisco Bcos能较为便捷的把指定的业务数据上链.

内置封装了Table.sol接口合约. 我们开发业务应用时可基于该合约接口, 以类似操作数据库DAO层的形式, 实现CRUD操作. 

常规使用了Table.sol中的table合约

 

contract TableFactory {function openTable(string memory) public view returns (Table); //open tablefunction createTable(string, string, string) public returns (int256); //create table
}

其中createtable中的3个参数分别为 表名, 主键字段, 值字段,多个用逗号分割.

//Table main contract
contract Table {function select(string, Condition) public view returns (Entries);function insert(string, Entry) public returns (int256);function update(string, Entry, Condition) public returns (int256);function remove(string, Condition) public returns (int256);function newEntry() public view returns (Entry);function newCondition() public view returns (Condition);
}

  • Table合约的insert、remove、update和select函数中key的类型为string,其长度最大支持255字符。
  • Entry的get/set接口的key的类型为string,其长度最大支持255字符,value支持的类型有int256(int)、address和string,其中string的不能超过16MB

应用开发

 1合约设计

        系统功能开发都需要基于业务和一定的应用场景. 我们以已有的目录管理系统作为应用案例.  目录是数据采集、共享、交换的向导,通过收集维护各部门的数据目录, 最终形成某个全量的信用主体应用目录, 并可对外公开发布。  通过数据项、信息类的标准化、制订、编目,最终把目录信息上链。

 已基于业务表设计的table合约有数据项合约、信息类合约以及目录节点合约。

合约一旦部署发布,则不可删除, 则合约修改已新增的形式.

如信息类合约 UBcosInfoclassContract_V3.  需自行把 V1,V2版本的数据重新通过v3版本合约上链.  信息类合约是把传统数据库表中的数据用table合约用相同的结构把数据上链.

2代码实现

确定业务表上链的字段包括:

string rid, string clsname, string clscode,string clsenname,string reftype,string sourcedept,string remark

其中rid作为table key.  table表名暂定为: u_bcos_infoclass_v3

在构造函数里进行表的创建, 合约包含了 select,insert,update,remove 4个接口。 

UBcosInfoclassContract_V3 合约代码:

pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "./Table.sol";contract UBcosInfoclassContract_V3 {event CreateResult(int256 count);event InsertResult(int256 count);event UpdateResult(int256 count);event RemoveResult(int256 count);TableFactory tableFactory;string constant TABLE_NAME = "u_bcos_infoclass_v3";constructor() public {tableFactory = TableFactory(0x1001); //The fixed address is 0x1001 for TableFactory//创建信息类合约表, 参数分别为: //TABLE_NAME:表名, //表关键字段:rid, //表值字段:"clsname,clscode,clsenname,reftype,sourcedept,remark"tableFactory.createTable(TABLE_NAME, "rid", "clsname,clscode,clsenname,reftype,sourcedept,remark");}//select recordsfunction select(string rid)publicviewreturns (string, string, string,string){Table table = tableFactory.openTable(TABLE_NAME);Condition condition = table.newCondition();Entries entries = table.select(rid, condition);string memory rid_bytes;string memory clsname_bytes;string memory clscode_bytes;string memory sourcedept_bytes;if(entries.size()>0){Entry entry = entries.get(0);rid_bytes = entry.getString("rid");clsname_bytes = entry.getString("clsname");clscode_bytes = entry.getString("clscode");sourcedept_bytes = entry.getString("sourcedept");}return (rid_bytes, clsname_bytes, clscode_bytes,sourcedept_bytes);}//insert recordsfunction insert(string rid, string clsname, string clscode,string clsenname,string reftype,string sourcedept,string remark)publicreturns (int256){Table table = tableFactory.openTable(TABLE_NAME);Entry entry = table.newEntry();entry.set("rid", rid);entry.set("clsname", clsname);entry.set("clscode", clscode);entry.set("clsenname", clsenname);entry.set("reftype", reftype);entry.set("sourcedept", sourcedept);entry.set("remark", remark);int256 count = table.insert(rid, entry);emit InsertResult(count);return count;}//update recordsfunction update(string rid, string clsname, string clscode,string clsenname,string reftype,string sourcedept,string remark)publicreturns (int256){Table table = tableFactory.openTable(TABLE_NAME);Entry entry = table.newEntry();entry.set("clsname", clsname);entry.set("clscode", clscode);entry.set("clsenname", clsenname);entry.set("reftype", reftype);entry.set("sourcedept", sourcedept);entry.set("remark", remark);Condition condition = table.newCondition();condition.EQ("rid", rid);int256 count = table.update(rid, entry, condition);emit UpdateResult(count);return count;}//remove recordsfunction remove(string rid ) public returns (int256) {Table table = tableFactory.openTable(TABLE_NAME);Condition condition = table.newCondition();condition.EQ("rid", rid);//condition.EQ("item_id", item_id);int256 count = table.remove(rid, condition);emit RemoveResult(count);return count;}
}

3合约编译

在WeBase结点管理服务中 新建合约, 并粘贴代码. 点击编译即可.

可以在IDE面板直接进行合约方法的调用

编译后可导出得到合约的java文件.  地层还是console控制台代码转换, Webase命令行操作的方式进行了可视化界面集成.

4 java SDK集成

 通过得到的UBcosInfoclassContract_V3.java文件

   对合约类进行接口封装

package com.dxx.blockchain.contract.transaction;/*** 信息类合约交易接口* @author wuhaixin* 2020年6月14日*/public interface UBcosInfoclassContractV3Transaction {/*** 插入信息类,返回[blockNumber,trans_hash]* 2020年6月14日下午10:25:56* @param rid* @param clsname* @param clscode* @param clsenname* @param reftype* @param sourcedept* @param remark* @return* @throws Exception* @author wuhaixin*/public String[] insertInfoClass(String rid,String clsname,String clscode,String clsenname,String reftype,String sourcedept,String remark) throws Exception;/*** 更新信息类.返回[blockNumber,trans_hash]* 2020年6月14日下午10:25:45* @param rid* @param clsname* @param clscode* @param clsenname* @param reftype* @param sourcedept* @param remark* @return* @throws Exception* @author wuhaixin*/public String[] updateInfoClass(String rid,String clsname,String clscode,String clsenname,String reftype,String sourcedept,String remark) throws Exception;/*** 根据rid删除链上的记录返回[blockNumber,trans_hash]* 2020年6月14日下午10:25:27* @param rid* @return* @throws Exception* @author wuhaixin*/public String[] removeInfoClass(String rid) throws Exception;/*** 返回 rid,clsname,clscode,sourcedept* 2020年6月14日下午10:25:13* @param rid* @return* @throws Exception* @author wuhaixin*/public String[] selectInfoClass(String rid) throws Exception;}

部分实现类代码

/*** 信息类合约交易实现* @author wuhaixin* 2020年6月14日*/
@Component
public class UBcosInfoclassContractV3TransactionImpl implements UBcosInfoclassContractV3Transaction{/*** 插入信息类,返回[blockNumber,trans_hash]* 2020年6月14日下午10:25:56* @param rid* @param clsname* @param clscode* @param clsenname* @param reftype* @param sourcedept* @param remark* @return* @throws Exception* @author wuhaixin*/public String[] insertInfoClass(String rid,String clsname,String clscode,String clsenname,String reftype,String sourcedept,String remark) throws Exception{clsname = clsname==null?"":clsname;clscode = clscode==null?"":clscode;clsenname = clsenname==null?"":clsenname;reftype = reftype==null?"":reftype;sourcedept = sourcedept==null?"":sourcedept;remark = remark==null?"":remark;Web3j web3j = Web3jFactory.getWeb3j();Credentials credentials = CredentialsFactory.getCredentials();BigInteger gasPrice = new BigInteger("0");BigInteger gasLimit = new BigInteger("300000000");//可以使用deploy或者load函数初始化合约对象,两者使用场景不同,前者适用于初次部署合约,后者在合约已经部署并且已知合约地址时使用。//deploy每次会产生一个新的合约地址.//UBcosInfoclassContract_V3 contract = UBcosInfoclassContract_V3.deploy(web3j, credentials, new StaticGasProvider(gasPrice, gasLimit)).send();//load使用固定的合约地址.UBcosInfoclassContract_V3 contract = UBcosInfoclassContract_V3.load(contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit));TransactionReceipt transactionReceipt = contract.insert(rid, clsname, clscode, clsenname, reftype, sourcedept, remark).send();String blockNumber = transactionReceipt.getBlockNumber().intValue()+"";String trans_hash = transactionReceipt.getTransactionHash();return new String[]{blockNumber,trans_hash};}

至此, 信息类合约接口已开发完毕, 可提供给应用系统使用.

应用端对接

业务代码接入

信息类业务应用代码如下:

主要是上链与保存区块信息

 String[] transResult = uBcosInfoclassContractV3Transaction.insertInfoClass(result.getId(), result.getClsname(), result.getClscode(), result.getClsenname(), result.getReftype(), result.getSourcedept(), result.getRemark());
/**
* 控制层顶部添加@RequestMapping("/infoclass")
* 编码人员根据实际选择资源授权的类型.admin
* 方法名采用动宾结构,uri请求则去除宾语,比如方法:addUser,则requestmapping("/add")
* 若是页面跳转,则与方法名一致,如addUser对应得jsp页面为addUser.jsp
* controller的入口界面文件除外.如userIndex.jsp
* 最终访问路径为: {应用名称}/infoclass/admin/*,{应用名称}/infoclass/usr/*,{应用名称}/infoclass/web/*,
* InfoClassController 控制器
* 2018年07月05日
* @author whx
*/
@Controller
@RequestMapping("/infoclass")
public class InfoClassController {/**注入信息类合约交易接口*/@AutowiredUBcosInfoclassContractV3Transaction uBcosInfoclassContractV3Transaction;/**
* 新增对象
* 2018年07月05日
* @param entity
* @author whx
*/
@Operator(operator="添加信息类")
@ResponseBody
@RequestMapping("/admin/addInfoClass")
public AjaxResponse addInfoClass(InfoClassDO entity){AjaxResponse resp = AjaxResponse.instance();resp.setSuccess(false);InfoClassDO result = infoClassService.saveAndCreateTable(entity);try {result.setSourcedept(AuthedUserUtil.getUserAccount());String[] transResult = uBcosInfoclassContractV3Transaction.insertInfoClass(result.getId(), result.getClsname(), result.getClscode(), result.getClsenname(), result.getReftype(), result.getSourcedept(), result.getRemark());result.setBlockNumber(Integer.parseInt(transResult[0]));result.setTrans_hash(transResult[1]);infoClassService.update(result);} catch (Exception e) {e.printStackTrace();}if(result!=null){resp.setSuccess(true);resp.setMessage("保存成功!");}else{resp.setMessage("信息类英文名称对应的数据库表已存在,无法新建信息类,请修改编码或使用生成功能!");}return resp;
}
}
}

应用界面效果

信息类管理模块增改时会插入区块链的块高和交易Hash

该区块交易信息也可以从区块链管理平台上查看.


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部