SpringBoot+Hbase
使用hbase-client,在Spring Boot中实现表创建和查询
一、初始化Spring Boot
登录SpringBoot初始化页面(https://start.spring.io/),勾选所需的配置和Jdk版本,执行代码生成,我选择的是maven project +jdk8
二、导入项目,修改相关配置
打开pom.xml,引用Hbase client,注意版本号跟安装版本对应,我的pom配置文件如下
<!--Hbase-->
<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-client</artifactId>
    <version>2.4.4</version>
</dependency>
<!-- 配置了com.alibaba.fastjson对结果做处理 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.41</version>
</dependency>
application.properties中增加hbase的配置项
# database - hbase
hbase.zookeeper.quorum=hadoop-master,hadoop-slave1,hadoop-slave2,hadoop-slave3
hbase.zookeeper.property.clientPort=2181
zookeeper.znode.parent=/hbase
项目中增加Hbase配置项,HBaseConfig.java
@Configuration
public class HBaseConfig {
    @Value("${hbase.zookeeper.quorum}")
    private String zookeeperQuorum;
    @Value("${hbase.zookeeper.property.clientPort}")
    private String clientPort;
    @Value("${zookeeper.znode.parent}")
    private String znodeParent;
    @Bean
    public Connection hbaseConnection() {
        Connection conn = null;
        try {
            conn = ConnectionFactory.createConnection(configuration());
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
        return conn;
    }
    
    public org.apache.hadoop.conf.Configuration configuration() {
        org.apache.hadoop.conf.Configuration hbaseConf = new org.apache.hadoop.conf.Configuration();
        hbaseConf.set("hbase.zookeeper.quorum", zookeeperQuorum);
        hbaseConf.set("hbase.zookeeper.property.clientPort", clientPort);
        hbaseConf.set("zookeeper.znode.parent", znodeParent);
        return hbaseConf;
    }
}
三、创建BaseService,作为基本功能的父类
BaseService提供了全表查询、创建表和新增记录的基本功能
@Service
public class BaseService {
    @Autowired
    private Connection hbaseConnection;
    /**
     * 创建表
     * @param resultClass
     * @param <T>
     * @return
     */
    public <T> boolean create(Class<T> resultClass){
        try{
            TableInfo annotation = resultClass.getAnnotation(TableInfo.class);
            Table table = hbaseConnection.getTable(TableName.valueOf(annotation.value()));
            Admin admin = hbaseConnection.getAdmin();
            if(admin.tableExists(table.getName())){
                return false;
            }
            // 创建表描述类
            Set<String> clumnnFamily = new HashSet<>();
            Field[] declaredFields = resultClass.getDeclaredFields();
            for(Field field:declaredFields) {
                ColumnGroup group = field.getAnnotation(ColumnGroup.class);
                clumnnFamily.add(group.value());
            }
            TableName tableName = table.getName(); // 表名称
            HTableDescriptor desc = new HTableDescriptor(tableName);
            if(clumnnFamily!=null&&clumnnFamily.size()>0){
                for (String columnGroup:clumnnFamily) {
                    // 创建列族的描述类
                    HColumnDescriptor family = new HColumnDescriptor(columnGroup); // 列族
                    // 将列族添加到表中
                    desc.addFamily(family);
                }
            }
            // 创建表
            admin.createTable(desc); // 创建表
            return true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }
    public <T> void add(T data){
        try {
            // 新增数据
            Class<?> aClass = data.getClass();
            TableInfo annotation = aClass.getAnnotation(TableInfo.class);
            Table table = hbaseConnection.getTable(TableName.valueOf(annotation.value()));
            Put put = new Put("001".getBytes());
            Field[] declaredFields = aClass.getDeclaredFields();
            String methodName;
            for (Field field: declaredFields) {
                ColumnGroup group = field.getAnnotation(ColumnGroup.class);
                methodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                Method method = data.getClass().getMethod(methodName);
                Object invoke = method.invoke(data);
                put.addColumn(group.value().getBytes(), field.getName().getBytes(), invoke.toString().getBytes());
            }
            table.put(put);
            table.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /**
     * 整表查询
     * @param resultClass
     */
    public <T> List<T> scan(Class<T> resultClass){
        List<T> list = new ArrayList<>();
        try {
            Annotation[] annotations = resultClass.getAnnotations();
            TableInfo annotation = resultClass.getAnnotation(TableInfo.class);
            Table table = hbaseConnection.getTable(TableName.valueOf(annotation.value()));
            ResultScanner scanner = table.getScanner(new Scan());
            Map<String, T> resultMap = new HashedMap();
            String rowIndex;
            String columnName;
            String methodName;
            for (Result res : scanner) {
                Cell[] cells = res.rawCells();
                for (Cell cell : cells) {
                    rowIndex = Bytes.toString(CellUtil.cloneRow(cell));
                    T hbaseTest;
                    if (resultMap.containsKey(rowIndex)) {
                        hbaseTest = resultMap.get(rowIndex);
                    } else {
                        hbaseTest = resultClass.newInstance();
                        resultMap.put(rowIndex, hbaseTest);
                    }
                    columnName = Bytes.toString(CellUtil.cloneQualifier(cell));
                    methodName = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
                    Method method = HbaseTest.class.getMethod(methodName, String.class);
                    method.invoke(hbaseTest, Bytes.toString(CellUtil.cloneValue(cell)));
                    System.out.println(
                            Bytes.toString(CellUtil.cloneRow(cell)) + "---" +
                                    Bytes.toString(CellUtil.cloneFamily(cell)) + "---" +
                                    Bytes.toString(CellUtil.cloneQualifier(cell)) + "---" +
                                    Bytes.toString(CellUtil.cloneValue(cell)) + "---" +
                                    cell.getTimestamp()
                    );
                }
            }
            scanner.close();
            table.close();
            Set<Map.Entry<String, T>> entries = resultMap.entrySet();
            for (Map.Entry<String, T> entry : entries) {
                list.add(entry.getValue());
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return list;
    }
}
我自己自定义了两个注解,一个是表注解一个是列族的注解,在使用实体对象时,便于确认对应的表结构
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TableInfo {
    String value() default "";
}
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ColumnGroup {
    String value() default "";
}
四、实际业务使用
业务服务集成BaseService,对应实体配置对应的表
@Data
@TableInfo(value = "hbase_1102")
public class HbaseTest {
    @ColumnGroup(value="cf1")
    private String gender;
    @ColumnGroup(value="cf1")
    private String name;
    @ColumnGroup(value="cf2")
    private String chinese;
    @ColumnGroup(value="cf2")
    private String math;
}
@Service
public class HbaseTestSerice extends BaseService {
    /**
     * 全数据查询
     * @return
     */
    public List<HbaseTest> query(){
        return this.scan(HbaseTest.class);
    }
}
五、Controller层调用
@RestController
@RequestMapping(value = "/hbaseTest")
public class HbaseTestController {
    @Autowired
    HbaseTestSerice hbaseService;
    /**
     * 整表检索
     * @return
     */
    @GetMapping(value = "/query")
    public Result query() {
        return ResultUtil.success(hbaseService.query());
    }
}
六、Postman执行调用
get请求http://localhost:18189/test/query,返回结果如下
{
    "code": 200,
    "msg": null,
    "data": [
        {
            "gender": null,
            "name": "qrl_test",
            "chinese": null,
            "math": null
        },
        {
            "gender": "man",
            "name": "Tom",
            "chinese": "90",
            "math": "91"
        }
    ]
}
七、建表和新增记录
同样的,通过对象上的注解信息,获取表明和列族,创建表描述信息,完成表的创建