@羲凡——只为了更好的活着
Scala 封装Api接口并实现客户端查询(干货)
像把大象装冰箱一样,一共有三步:写好查询语句;写好server并启动;写好client查询结果
1.推荐官网(内容非常值得详看)——https://doc.akka.io/docs/akka-http/current/
2.注意server端中文乱码,URLDecoder.decode(name, “UTF-8”)
3.注意client端中文乱码,URLEncoder.encode(“司马懿”,“UTF8”)
0.添加maven依赖
<!-- Spark Core -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
<!-- Spark SQL -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
<!-- Mysql connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!-- Restful Api -->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-http_2.11</artifactId>
<version>10.1.9</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-stream_2.11</artifactId>
<version>2.5.23</version>
</dependency>
<dependency>
<groupId>ch.megard</groupId>
<artifactId>akka-http-cors_2.11</artifactId>
<version>0.2.2</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-http-spray-json_2.11</artifactId>
<version>10.1.9</version>
</dependency>
<dependency>
<groupId>org.scalaj</groupId>
<artifactId>scalaj-http_2.11</artifactId>
<version>2.4.1</version>
</dependency>
1.Mysql的增改查代码
import java.sql.{Connection, DriverManager, ResultSet}
import java.util.Properties
import scala.collection.mutable
object MysqlUtil {
val url = "jdbc:mysql://deptest23:3306/test_data"
val user = "root"
val password = "1q2w3e4r"
val props = new Properties()
props.put("user", user)
props.put("password", password)
props.setProperty("useSSL", "false")
props.setProperty("useUnicode", "true")
props.setProperty("characterEncoding", "utf8")
var connection: Connection = null
def queryMysql1(name : String, age:Int) ={
var resMap = mutable.Map[String,String]()
try {
classOf[com.mysql.jdbc.Driver]
connection = DriverManager.getConnection(url, props)
val sql =
s"""
|select * from test_data.mysql_stu_info
|where name = "$name" and age=$age
""".stripMargin
val resSet: ResultSet = connection.createStatement().executeQuery(sql)
while(resSet.next()){
val str1: String = resSet.getString("name")
val str2: String = resSet.getString("age")
resMap += str1 -> str2
}
} catch {
case e: Exception => println(e.printStackTrace())
} finally {
connection.close()
}
resMap
}
def queryMysql2(name : String) ={
var resMap = mutable.Map[String,String]()
try {
classOf[com.mysql.jdbc.Driver]
connection = DriverManager.getConnection(url, props)
val sql =
s"""
|select * from test_data.mysql_stu_info
|where name = "$name"
""".stripMargin
val resSet: ResultSet = connection.createStatement().executeQuery(sql)
while(resSet.next()){
val str1: String = resSet.getString("name")
val str2: String = resSet.getString("age")
resMap += str1 -> str2
}
} catch {
case e: Exception => println(e.printStackTrace())
} finally {
connection.close()
}
resMap
}
def insertMysql(name : String, age : Int) ={
try {
classOf[com.mysql.jdbc.Driver]
connection = DriverManager.getConnection(url, props)
val sql = s"insert into test_data.mysql_stu_info(name,age) values('$name',$age)"
val resSet: Int = connection.createStatement().executeUpdate(sql)
println(resSet)
} catch {
case e: Exception => println(e.printStackTrace())
} finally {
connection.close()
}
}
def updateMysql(name : String, age : Int) ={
try {
classOf[com.mysql.jdbc.Driver]
connection = DriverManager.getConnection(url, props)
val sql = s"update test_data.mysql_stu_info set age = $age where name='$name'"
val resSet: Int = connection.createStatement().executeUpdate(sql)
println(resSet)
} catch {
case e: Exception => println(e.printStackTrace())
} finally {
connection.close()
}
}
}
2.封装API接口(server端)
import java.net.URLDecoder
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.stream.ActorMaterializer
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.model.headers.HttpOriginRange
import ch.megard.akka.http.cors.scaladsl.CorsDirectives.cors
import ch.megard.akka.http.cors.scaladsl.settings.CorsSettings
import org.json4s.DefaultFormats
import org.json4s.jackson.Json
import spray.json.DefaultJsonProtocol._
import scala.io.StdIn
import scala.collection.mutable
object WebServer {
val settings = CorsSettings.defaultSettings.copy(
allowedOrigins = HttpOriginRange.*
)
final case class User(name: String, age: Int, addr: String)
implicit val itemFormat = jsonFormat3(User)
final case class Info(name: String, age: Int)
implicit val itemFormat2 = jsonFormat2(Info)
final case class UserGroup(items: List[User])
implicit val orderFormat = jsonFormat1(UserGroup)
private val userGroup = mutable.ListBuffer[User]()
def main(args: Array[String]): Unit = {
implicit val system = ActorSystem("mock_system")
implicit val materializer = ActorMaterializer()
implicit val executionContext = system.dispatcher
val route: Route =
(path("hello") & get & cors(settings)) {
// 基本测试
complete("hello akka")
} ~
(path("list_all") & cors(settings)) {
get {
// 添加两个元素到UserGroup组中,列出所有的内容
userGroup.clear()
userGroup += User("jack", 18, "NewYork")
userGroup += User("mike", 21, "paris")
val user_group = UserGroup(this.userGroup.toList)
complete(user_group)
}
} ~
(path("query1") & cors(settings)) {
get {
parameters('name.as[String], 'age.as[Int]) {
(name, age) => {
val res = Json(DefaultFormats).write(MysqlUtil.queryMysql1(name, age))
complete(res)
}
}
}
} ~
get {
// 传参用pathPrefix,数字用IntNumber、LongNumber,字符串用Remaining
(pathPrefix("query2" / Remaining) & cors(settings)) {
name => {
val nameStr = URLDecoder.decode(name, "UTF-8")
val res = Json(DefaultFormats).write(MysqlUtil.queryMysql2(nameStr))
complete(res)
}
}
} ~
post {
(path("insert") & cors(settings)) {
entity(as[Info]) {
info => {
val res = MysqlUtil.insertMysql(info.name, info.age)
complete("done")
}
}
}
} ~
post {
(path("update") & cors(settings)) {
entity(as[Info]) {
info => {
val res = MysqlUtil.updateMysql(info.name, info.age)
complete("done")
}
}
}
}
// 绑定ip和端口
val bindingFuture = Http().bindAndHandle(route, "localhost", 8227)
println(s"Server online at http://localhost:8227/\nPress RETURN to stop...")
StdIn.readLine()
bindingFuture.flatMap(_.unbind()).onComplete(_ => system.terminate())
}
}
3.查询API接口(client端)
import java.net.URLEncoder
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.http.scaladsl.unmarshalling.Unmarshal
import akka.stream.ActorMaterializer
import scalaj.http.HttpOptions
import scala.util.{Failure, Success}
object WebClient extends App {
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
implicit val executionContext = system.dispatcher
val host_url = "http://localhost:8227"
def getReq(url: String): Unit = {
val responseFuture = Http().singleRequest(HttpRequest(uri = url, method = HttpMethods.GET))
responseFuture.onComplete {
case Success(res) => {
println(res)
Unmarshal(res.entity).to[String].map { json_str =>
Right {
println("get result: ", json_str)
}
}
}
case Failure(error) => println(error.getMessage)
}
}
def postReq(url: String,map:Map[String, Any]): Unit = {
val name = map("name")
val age = map("age")
val body = scalaj.http.Http(url)
.postData(
s"""{
|"name":"$name",
|"age":$age
|}""".stripMargin)
.header("Content-Type", "application/json")
.header("Charset", "UTF-8")
.options(HttpOptions.readTimeout(10000)).asString.body
println(body)
}
val nameUtf8: String = URLEncoder.encode("司马懿","UTF8")
getReq(s"$host_url/query1?name=$nameUtf8&age=27")
Thread.sleep(2000)
getReq(s"$host_url/query2/$nameUtf8")
Thread.sleep(2000)
postReq(host_url+"/insert",Map("name" -> "夏侯惇","age" -> 10))
Thread.sleep(2000)
postReq(host_url+"/update",Map("name" -> "夏侯惇","age" -> 72))
}
参考资料
1.官网——https://doc.akka.io/docs/akka-http/current/
2.这位仁兄的github项目——https://github.com/tashaxing/MockServer
====================================================================
@羲凡——只为了更好的活着
若对博客中有任何问题,欢迎留言交流