1. 软件版本 & 部署:
maven:3.3.9,jdk:1.7 ,Struts2:2.3.24.1,Hibernate:4.3.6,Spring:4.2.5,MySQL:5.1.34,Junit:4,Myeclipse:2014;
Hadoop2.6.4,HBase1.1.2
源码下载:https://github.com/fansy1990/ssh_v3/releases
部署参考:http://blog.csdn.net/fansy1990/article/details/51356583
2. 系统功能及核心实现
2.1系统菜单
HBase表管理系统主要是对表以及表数据的相关操作;
2.2 表管理
直接打开Table管理界面,即可看到所有表的简要信息,包括数据库(namspace)、表名、简单表描述等;
这个查询的信息直接基于Admin的listTableNames方法,具体调用如下:
/** * 获取所有表 * * @return * @throws IOException */ public List<HBaseTable> getTables() throws IOException { List<HBaseTable> list = new ArrayList<>(); Admin admin = HadoopUtils.getHBaseConnection().getAdmin(); TableName[] tables = admin.listTableNames(); HBaseTable hTable = null; for (TableName t : tables) { hTable = new HBaseTable(); hTable.setNameSpace(t.getNamespaceAsString()); hTable.setTableName(t.getNameAsString()); // HTableDescriptor htableDes = admin.getTableDescriptor(t); // System.out.println(htableDes.toString()); // System.out.println(htableDes.toStringTableAttributes()); // System.out.println(htableDes.getFamilies().toString()); // System.out.println(htableDes.toStringCustomizedValues()); hTable.setDescription(admin.getTableDescriptor(t) .toStringCustomizedValues()); setRegions(hTable, admin.getTableRegions(t)); list.add(hTable); } return list; }
2.2.1 表详细
表详细功能需要先选定一行记录,否则会提示:
选择一个记录后,点击表详细即可弹出表详细信息:
后台实现通过admin.getTableDescriptor即可获得表的详细信息,但是需要提供表名,表名可以从前天传入即可,如下:
/** * 获取指定表详细信息 * * @param tableName * @return * @throws IOException */ public String getTableDetails(String tableName) throws IOException { Admin admin = HadoopUtils.getHBaseConnection().getAdmin(); HTableDescriptor tableDescriptors = admin .getTableDescriptor(getTableName(tableName)); System.out.println(tableDescriptors.toStringCustomizedValues()); System.out.println(tableDescriptors.toString()); return admin.getTableDescriptor(getTableName(tableName)).toString(); }
2.2.2 表新增
表新增功能只是提供一个简单的新增,即只提供表名、列簇名即可,如下:
同时提交后台后,如果表已经存在则会进行对应的提示,后台通过遍历所有表名实现此功能,效率不高,实现如下:
public boolean checkTableExists(String tableName) throws IOException { Admin admin = HadoopUtils.getHBaseConnection().getAdmin(); TableName[] tables = admin.listTableNames(); for (TableName t : tables) { if (t.getNameAsString().equals(tableName)) { return true; } } return false; }
新增表,通过admin的createTable实现:
public boolean saveTable(String tableName, String cfs) throws IOException { Admin admin = HadoopUtils.getHBaseConnection().getAdmin(); HTableDescriptor hTableDescriptor = new HTableDescriptor( getTableName(tableName)); String[] cfsArr = StringUtils.split(cfs, Utils.COMMA); for (String cf : cfsArr) { hTableDescriptor.addFamily(new HColumnDescriptor(cf)); } admin.createTable(hTableDescriptor); return true; }
2.2.3 表删除
表删除,同样需要选择一条记录,如果没有选择记录,同样会提示选择表,选择表后,点击删除,会进行下面的提示:
如果点击OK,则删除,Cancel则取消;
删除实现,同样使用Admin的disableTable, deleteTable方法
public boolean deleteTable(String tableName) throws IOException { Admin admin = HadoopUtils.getHBaseConnection().getAdmin(); admin.disableTable(getTableName(tableName)); admin.deleteTable(getTableName(tableName)); return true; }
备注: 这里应该先判断此表是否是enable状态,如果不是则直接删除;如果是disable状态,则执行上述代码会有问题;
2.3 表数据管理
在打开表数据管理页面后,会初始化表名的下拉框,下拉框中数据的获取采用AJax的方式访问后台获取,方法同样使用Admin的listTableNames方法;
额
在选择一个表后,会初始化列簇名下拉框数据和start rowkey ,如下:
在查询数据时,可以选择多个列簇名,同时可以修改Start rowkey ,选择记录数以及版本数;
根据表名获取列簇名后台代码实现如下(通过HTableDescriptor的getColumnFamilies方法获取):
public List<TextValue> getTablesColumnFamily(String tableName) throws IOException { List<TextValue> list = new ArrayList<>(); Admin admin = HadoopUtils.getHBaseConnection().getAdmin(); HTableDescriptor tableDescriptor = admin .getTableDescriptor(getTableName(tableName)); HColumnDescriptor[] columnDescriptors = tableDescriptor .getColumnFamilies(); for (HColumnDescriptor t : columnDescriptors) { list.add(new TextValue(t.getNameAsString())); } return list; }
以及start rowKey的后台代码如下(即,只读取第一行数据,然后返回其rowkey):
public String getTableRowKey(String tableName) throws IOException { Table table = HadoopUtils.getHBaseConnection().getTable( getTableName(tableName)); Scan scan = new Scan(); ResultScanner scanner = table.getScanner(scan); Result firstRow = scanner.next(); scanner.close(); table.close(); if (firstRow == null) return "-1"; return new String(firstRow.getRow()); }
根据表名、列簇名、start rowkey、版本数、记录数,获取数据的后台代码如下:
public List<HBaseTableData> getTableData(String tableName, String cfs, String startRowKey, int limit, int versions) throws IOException { List<HBaseTableData> datas = new ArrayList<>(); Table table = HadoopUtils.getHBaseConnection().getTable( getTableName(tableName)); Scan scan = new Scan(); scan.setMaxVersions(versions); if (startRowKey != "-1") { scan.setStartRow(startRowKey.getBytes()); } String[] cfsArr = cfs.split(Utils.COMMA, -1); for (String cf : cfsArr) { scan.addFamily(cf.getBytes()); } ResultScanner scanner = table.getScanner(scan); Result[] rows = scanner.next(limit); for (Result row : rows) { // Cell[] cells = row.rawCells(); datas.addAll(getFromCells(row.rawCells())); } scanner.close(); table.close(); return datas; }
通过设置Scan的maxVersions以及startRow 来限定版本数和开始遍历位置,通过设置scanner.next来限定获取的记录数;
3.1 新增
数据新增,通过指定表名、列簇名即可,如果列簇名指定多个,会提示错误:
数据新增使用window弹出框,为了把表名和列簇名传递到该window,使用了url加参数的方法(比较别扭的方式),具体如下:
var win_table_add_data_ = $(‘#win_table_add_data‘).window({ width:450, height:350, modal:true, left:400, top:150, title:‘数据新增‘, collapsible:false, minimizable:false, maximizable:false, // content: ‘<div style="padding:30px 20px 10px 20px;">‘ + "a" +‘</div>‘ content: ‘<iframe id="tabIframe" src="hbaseCommand/data_add.jsp?tableName=‘+tableName_+‘&cf=‘+cf_+ ‘" frameborder="0" style="border:0;width:100%;height:100%;">‘, // href:"hbaseCommand/data_add.jsp", onOpen:function(){ // 修改对应的值; // $(‘#data_add_ff_tableName‘).val(getFakeData(‘cc_data_retrieve_tableName‘)); // $(‘#data_add_ff_family‘).val(cf_); // $(‘#data_add_ff_family‘).textbox(‘setValue‘,cf_); } });
在弹出框中,用户可以输入rowkey,column,vlaue :
表名、列簇名不可编辑,用户点击添加后,直接put数据到表中;
public boolean saveTableData(String tableName, String cfs, String rowkey, String column, String value) throws IOException { Table table = HadoopUtils.getHBaseConnection().getTable( getTableName(tableName)); Put put = new Put(Bytes.toBytes(rowkey)); put.addColumn(Bytes.toBytes(cfs), Bytes.toBytes(column), Bytes.toBytes(value)); table.put(put); table.close(); return true; }
3.3.2数据删除
直接根据提供的数据使用checkAndDelete进行删除,防止在删除的时候数据被修改:
public boolean deleteTableData(String tableName, String family, String qualifier, String rowkey, String value, long timestamp) throws IOException { Table table = HadoopUtils.getHBaseConnection().getTable( getTableName(tableName)); Delete delete = new Delete(Bytes.toBytes(rowkey)); delete.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier), timestamp); boolean flag = table.checkAndDelete(Bytes.toBytes(rowkey), Bytes.toBytes(family), Bytes.toBytes(qualifier), Bytes.toBytes(value), delete); table.close(); return flag; }
3.3.3 数据更新
数据更新,同样需要选择一条记录,弹出框的方式类似数据新增(比较别扭的方式),不过可修改的内容只有值而已:
除了值之外,其他输入框都是只读的;后台实现,同样使用checkAndPut 方法:
public boolean updateTableData(String tableName, String cfs, String rowkey, String column, String value, long timestamp, String oldValue) throws IOException { Table table = HadoopUtils.getHBaseConnection().getTable( getTableName(tableName)); Put put = new Put(Bytes.toBytes(rowkey)); put.addColumn(Bytes.toBytes(cfs), Bytes.toBytes(column), timestamp, Bytes.toBytes(value)); table.checkAndPut(Bytes.toBytes(rowkey), Bytes.toBytes(cfs), Bytes.toBytes(column), Bytes.toBytes(oldValue), put); table.close(); return true; }
4. 总结
1)HBase的相关API的使用不是很难,主要是如果是插入或者更新操作,需要保持记录前后一致,需要进行row lock,这时就需要用到checkAndXxx 操作了,具体可以参考:http://blog.csdn.net/fansy1990/article/details/51451583 ;
2) 数据新增和数据更新弹出框的方式比较别扭,可以考虑使用新的方式(因为要进行参数的传递);
分享,成长,快乐
脚踏实地,专注
转载请注明blog地址:http://blog.csdn.net/fansy1990