基于AKKA HTTP构建查询HBase的RESTful API完整过程

如果还不清楚akka http的使用,可参看 使用scala基于AKKA HTTP开发REST接口的简单实例,工程目录结构如下:

整个处理过程:客户端发送get或者post请求->服务端处理->结果返回客户端(以json字符串方式返回),这里的客户端测试工具采用的是IDEA自带的rest测试工具,可通过Tools->Test RESTful Web Service调出。

看服务端的一个get请求处理代码:

val route = get {
  path("row") {
    parameter("rowkey") { rowkey =>
      val result: Future[Option[String]] = selectByRowkey(rowkey)
      onSuccess(result) {
        case Some(item) if (!"".equals(item)) => complete(item)
        case Some(item) if ("".equals(item)) => complete("nothing was found with the rowkey:" + rowkey)
        case None => complete(StatusCodes.NotFound)
      }
    }
  }
} 

代码的逻辑是根据rowkey查hbase对应的记录,比较简单。查询的时候使用Future异步处理查询请求,查询完成时将结果返回客户端,启动服务,在rest客户端测试:

配置好后,点击左上角的绿色三角箭头进行测试,如果是POST请求(服务端接受post参数可参看官网文档),测试配置如下:

还可以通过浏览器测试get请求,如在浏览器输入:http://localhost:8080/row?rowkey=1001进行测试。

业务逻辑编写测试完成后紧接着就是将程序部署到服务器上去,在前一篇介绍akka http的实例时,将依赖的jar包整个打进项目jar包中 ,配置文件也没有分离,本次对这两项做了优化,先看项目在服务器端的部署结构:

其中:bin-存放程序启停shell脚本(java -jar方式运行程序)

           conf-存放的配置文件

           lib-第三方依赖包

           logs-程序日志目录

一.项目打包不包含依赖包

这个给出完整的pom文件,供参考

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.vip.bigdata</groupId>
  <artifactId>api</artifactId>
  <version>1.0-SNAPSHOT</version>
  <inceptionYear>2008</inceptionYear>
  <properties>
    <scala.version>2.12.6</scala.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.scala-lang</groupId>
      <artifactId>scala-library</artifactId>
      <version>${scala.version}</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.4</version>
    </dependency>
    <dependency>
      <groupId>com.typesafe.akka</groupId>
      <artifactId>akka-http_2.12</artifactId>
      <version>10.1.3</version>
    </dependency>
    <dependency>
      <groupId>com.typesafe.akka</groupId>
      <artifactId>akka-stream_2.12</artifactId>
      <version>2.5.12</version>
    </dependency>
    <dependency>
      <groupId>com.typesafe.akka</groupId>
      <artifactId>akka-http-spray-json_2.12</artifactId>
      <version>10.1.3</version>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.16</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-it</artifactId>
      <version>1.1.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-common</artifactId>
      <version>1.1.1</version>
    </dependency>
    <dependency>
      <groupId>com.aliyun.phoenix</groupId>
      <artifactId>ali-phoenix-core</artifactId>
      <version>4.11.0-AliHBase-1.1-0.3</version>
    </dependency>
    <!--<dependency>-->
      <!--<groupId>jdk.tools</groupId>-->
      <!--<artifactId>jdk.tools</artifactId>-->
      <!--<version>1.8</version>-->
      <!--<scope>system</scope>-->
      <!--<systemPath>C:/Program Files/Java/jdk1.8.0_171/lib/tools.jar</systemPath>-->
    <!--</dependency>-->
  </dependencies>

  <build>
    <resources>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
      <excludes>
        <exclude>conf/*</exclude>
      </excludes>
    </resource>
    </resources>
    <sourceDirectory>src/main/scala</sourceDirectory>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.6</version>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <classpathPrefix>lib/</classpathPrefix>
              <mainClass>com.vip.bigdata.server.HbaseServer</mainClass>
            </manifest>
            <addMavenDescriptor>false</addMavenDescriptor>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.10</version>
        <executions>
          <execution>
            <id>copy-dependencies</id>
            <phase>package</phase>
            <goals>
              <goal>copy-dependencies</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}/lib</outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.scala-tools</groupId>
        <artifactId>maven-scala-plugin</artifactId>
        <version>2.15.2</version>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>testCompile</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <scalaVersion>${scala.version}</scalaVersion>
          <args>
            <arg>-target:jvm-1.8</arg>
          </args>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

最主要是配置这两块的内容:

maven-jar-plugin插件里的:
<manifest>
  <addClasspath>true</addClasspath>
  <classpathPrefix>lib/</classpathPrefix>
  <mainClass>com.vip.bigdata.server.HbaseServer</mainClass>
</manifest>
maven-dependency-plugin插件里的:
<execution>
  <id>copy-dependencies</id>
  <phase>package</phase>
  <goals>
    <goal>copy-dependencies</goal>
  </goals>
  <configuration>
    <outputDirectory>${project.build.directory}/lib</outputDirectory>
  </configuration>
</execution>

上面的配置是把依赖的jar包拷贝打包后的lib文件夹下,如下所示:

把lib文件夹的包传到服务器上的lib文件夹下。 

二.打包不包含配置文件

在有一篇博文中有提到:maven打包不包含配置文件

在上面给出的配置中:

<resource>
  <directory>src/main/resources</directory>
  <filtering>true</filtering>
  <excludes>
    <exclude>conf/*</exclude>
  </excludes>
</resource>

这个地方就是配置打包时不包含conf下所有的配置文件,将conf里的配置文件上传到服务器中的conf目录下,需要注意的是读取配置文件的类也要响应的调整路径,下面给出完成的代码:

package com.vip.bigdata.util

import java.io.{BufferedInputStream, File, FileInputStream}
import java.util.Properties

import scala.util.Try

object PropertyConfig extends  Logging {
  val directory = new File("..")
  val filePath = directory.getAbsolutePath
  val appConfName = "application.properties"
  val appConfPath = filePath + "/conf/"+appConfName
  val prop = new Properties() {
    new Properties() {
      if (sys.env.get("os").mkString.toLowerCase.contains("windows")) {
        logInfo("load resource from peoperties file inside on windows")
        if (Try(new BufferedInputStream(new FileInputStream(appConfPath))).isFailure)
          logWarn("Cannot load resource from properties file inside on windows, maybe properties file doesn't exists")
      } else {
        if (new File(appConfPath).exists()) {
          logInfo("Load resource from properties file outside")
          load(new FileInputStream(appConfPath))
        } else {
          logInfo("Load resource from properties file inside")
          if (Try(load(this.getClass.getClassLoader.getResourceAsStream(appConfPath))).isFailure)
            logWarn("Cannot load resource from properties file inside, maybe properties file doesn't exists")
        }
      }
    }.getProperty(appConfName, appConfName)
      .split(",")
      .foreach(line => {
        val f = filePath+"/conf/"+line
        if (sys.env.get("os").mkString.toLowerCase.contains("windows")) {
          logInfo("load resource from peoperties file inside on windows")
          if (Try(load(new BufferedInputStream(new FileInputStream(f)))).isFailure)
            logWarn("Cannot load resource from properties file inside on windows, maybe properties file doesn't exists")
        } else {
          if (new File(f).exists()) {
            logInfo(s"Load resource $f from properties file outside")
            load(new FileInputStream(f))
          } else {
            logInfo(s"Load resource $f from properties file inside")
            if (Try(new BufferedInputStream(new FileInputStream(f))).isFailure)
              logWarn(s"Cannot load resource $f from properties file inside, maybe properties file $f doesn't exists")
          }
        }
      })
  }

  def getProperty(key: String): String = {
    logInfo(s"the $key of property value is:"+this.prop.getProperty(key))
    return this.prop.getProperty(key);
  }

}

上面的代码是先加载application.properties配置文件,这个配置文件里放的是要加载的所有的配置文件,格式如下:

配置文件间以逗号隔开,这样所有的配置文件都会一次性加载进去,上面的类继承了自定义的Logging日志类,可以忽略。

还需要注意一点,因为把log4j的配置文件放到了conf目录下,代码要稍作改动,不然无法读到log4j的配置文件,日志功能也就不起作用了,具体如下,因为我有一个Logging日志接口,所以在里面添加下面的代码即可,

PropertyConfigurator.configure(filePath+"/conf/log4j.properties")//log4j的完整日志路径

至此整个工程部署完成就可以进行测试了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值