- 浏览: 2542938 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
nation:
你好,在部署Mesos+Spark的运行环境时,出现一个现象, ...
Spark(4)Deal with Mesos -
sillycat:
AMAZON Relatedhttps://www.godad ...
AMAZON API Gateway(2)Client Side SSL with NGINX -
sillycat:
sudo usermod -aG docker ec2-use ...
Docker and VirtualBox(1)Set up Shared Disk for Virtual Box -
sillycat:
Every Half an Hour30 * * * * /u ...
Build Home NAS(3)Data Redundancy -
sillycat:
3 List the Cron Job I Have>c ...
Build Home NAS(3)Data Redundancy
Spray(10)REST API Project - DAO Layer
8. Prepare the DB first
8.1 H2 database
If we want to use this database in embedded mode, we will do as follow:
Add the h2*.jar to the class path
Use the JDBC driver class: org.h2.Driver
The database URL jdbc:h2:~/test opens the database test in my user home directory.
Based on H2 Console Application, we can access a SQL database using a browser interface. (We do not run under this mode)
9. How to work with DB
I use H2 database as my DAO layer example database.
Here are my application.conf configuration file:
test {
db.driver = org.h2.Driver
db.url = "jdbc:h2:mem:easysprayrestserver_test;DB_CLOSE_DELAY=-1"
db.user = sa
db.password = password
cp = ${cp}
cp.maxPoolSize=25
}
local {
db.driver = org.h2.Driver
db.url = "jdbc:h2:~/easysprayrestserver"
db.user = sa
db.password = password
cp = ${cp}
cp.maxPoolSize=25
}
cp {
minPoolSize=2
acquireIncrement=2
maxPoolSize=250
maxIdleTime=28800
testConnectionOnCheckout=true
preferredTestQuery="select 1"
}
It is very happy to know that the configuration properties can be treated like this>
cp = ${cp}
That is really helpful.
And from my understanding, I am coming from Java Springframework and always playing with J2EE application. So I prefer to have a DAO layer.
BaseDAO.scala class will be as follow:
package com.sillycat.easysprayrestserver.dao
import scala.slick.driver.ExtendedProfile
import scala.slick.driver.H2Driver
import scala.slick.driver.MySQLDriver
import scala.slick.session.Database
import scala.slick.session.Database.threadLocalSession
import scala.slick.session.Session
import com.sillycat.easysprayrestserver.util.DBConn
import com.sillycat.easysprayrestserver.util.TestDBConn
class BaseDAO(overridevalprofile: ExtendedProfile, dbConn: DBConn) extends ProductDAO with UserDAO with CartDAO with RCartProductDAO with Profile {
def db: Database = { dbConn.database }
def create: Unit = db withSession {
Users.create
Products.create
Carts.create
RCartProducts.create
}
def drop: Unit = db withSession {
Users.drop
Products.drop
Carts.drop
RCartProducts.drop
}
def doWithSession(f: Unit => Unit) = db withSession { f }
}
object BaseDAO {
import com.sillycat.easysprayrestserver.model.DBType._
def apply: BaseDAO = {
new BaseDAO(MySQLDriver, DBConn)
}
def apply(s: String): BaseDAO = s match {
case"test" => new BaseDAO(H2Driver, TestDBConn)
case _ => new BaseDAO(MySQLDriver, DBConn)
}
// Clients can import this rather than depending on slick directly
implicitdef threadLocalSession: Session = scala.slick.session.Database.threadLocalSession
}
The Profile file will be as follow, Profile.scala
package com.sillycat.easysprayrestserver.dao
import scala.slick.driver.ExtendedProfile
import com.sillycat.easysprayrestserver.util.JodaDateTimeMapper
import com.sillycat.easysprayrestserver.util.UserTypeMapper
trait Profile {
valprofile: ExtendedProfile
implicitvaljodaMapper = JodaDateTimeMapper
implicitvaluserTypeMapper = UserTypeMapper
}
Here is the most complex part, ModelDAO.scala
package com.sillycat.easysprayrestserver.dao
import scala.slick.util.Logging
import org.joda.time.DateTime
import com.sillycat.easysprayrestserver.model.Product
import com.sillycat.easysprayrestserver.model.Cart
import com.sillycat.easysprayrestserver.model.RCartProduct
import scala.slick.jdbc.meta.MTable
import com.sillycat.easysprayrestserver.model.User
import com.sillycat.easysprayrestserver.model.UserType
import spray.httpx.SprayJsonSupport
import spray.json.DefaultJsonProtocol
import spray.json.DeserializationException
import spray.json.JsNumber
import spray.json.JsObject
import spray.json.JsString
import spray.json.JsValue
import spray.json.RootJsonFormat
import org.joda.time.format.DateTimeFormat
import org.joda.time.DateTime
import spray.json.JsArray
import spray.json._
import DefaultJsonProtocol._
import org.joda.time.DateTime
import scala.slick.util.Logging
import scala.slick.jdbc.meta.MTable
import spray.json.{ RootJsonFormat, DefaultJsonProtocol }
import spray.httpx.SprayJsonSupport
import org.joda.time.format.DateTimeFormat
import scala.slick.ast._
import scala.slick.ast.Util._
trait UserDAO extends Logging { this: Profile =>
import profile.simple._
object Users extends Table[(Long, String, Int, String, DateTime, DateTime, String)]("USER") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc) // 1 This is the primary key column
def userName = column[String]("USER_NAME") // 2
def age = column[Int]("AGE") //3
def userType = column[String]("USER_TYPE") //4
def createDate = column[DateTime]("CREATE_DATE") //5
def expirationDate = column[DateTime]("EXPIRATION_DATE") // 6
def password = column[String]("PASSWORD") // 7
def * = id ~ userName ~ age ~ userType ~ createDate ~ expirationDate ~ password
def persist(implicit session: Session) = id.? ~ userName ~ age ~ userType ~ createDate ~ expirationDate ~ password
def insert(user: User)(implicit session: Session): Long = {
valid = persist.insert(user.id, user.userName, user.age, user.userType.toString(), user.createDate, user.expirationDate, user.password)
id
}
def auth(userName: String, password: String)(implicit session: Session): Option[User] = {
logger.debug("I am authing the userName=" + userName + " password=" + password)
(userName, password) match {
case ("admin", "admin") =>
Option(User(Some(1), "admin", 100, UserType.ADMIN, new DateTime(), new DateTime(), "admin"))
case ("customer", "customer") =>
Option(User(Some(2), "customer", 100, UserType.CUSTOMER, new DateTime(), new DateTime(), "customer"))
case ("manager", "manager") =>
Option(User(Some(3), "manager", 100, UserType.SELLER, new DateTime(), new DateTime(), "manager"))
case _ => None
}
}
def get(userId: Long)(implicit session: Session): Option[User] = {
logger.debug("Try to fetch User Object with userId = " + userId)
valquery = for { item <- Users if (item.id === userId) } yield (item)
logger.debug("Get User by id, SQL should be : " + query.selectStatement)
query.firstOption map {
case (user) => User(Option(user._1), user._2, user._3, UserType.withName(user._4), user._5, user._6, user._7)
}
}
def create(implicit session: Session) = {
if (!MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.create
ddl.createStatements.foreach(println)
}
}
def drop(implicit session: Session) = {
if (MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.drop
ddl.dropStatements.foreach(println)
}
}
}
}
trait ProductDAO extends Logging { this: Profile =>
import profile.simple._
object Products extends Table[Product]("PRODUCT") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc) // 1 This is the primary key column
def productName = column[String]("PRODUCT_NAME") // 2
def productDesn = column[String]("PRODUCT_DESN") //3
def createDate = column[DateTime]("CREATE_DATE") //4
def expirationDate = column[DateTime]("EXPIRATION_DATE") // 5
def productCode = column[String]("PRODUCT_CODE") //6
def * = id.? ~ productName ~ productDesn ~ createDate ~ expirationDate ~ productCode <> (Product.apply _, Product.unapply _)
def forInsert = productName ~ productDesn ~ createDate ~ expirationDate ~ productCode <>
({ t => Product(None, t._1, t._2, t._3, t._4, t._5) },
{ (s: Product) => Some(s.productName, s.productDesn, s.createDate, s.expirationDate, s.productCode) })
def insert(s: Product)(implicit session: Session): Long = {
Products.forInsert returning id insert s
}
def forProductCode(productCode: String)(implicit session: Session): Option[Product] = {
valquery = for {
item <- Products if item.productCode === productCode
} yielditem
query.firstOption
}
def all()(implicit session: Session): Seq[Product] = {
Query(Products).list
}
def create(implicit session: Session) = {
if (!MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.create
ddl.createStatements.foreach(println)
}
}
def drop(implicit session: Session) = {
if (MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.drop
ddl.dropStatements.foreach(println)
}
}
}
}
//Cart(id: Option[Long], cartName: String, cartType: CartType.Value, user: User, products: Seq[Product])
trait CartDAO extends Logging { this: Profile with RCartProductDAO =>
import profile.simple._
object Carts extends Table[(Long, String, String, Long)]("CART") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc) // 1 This is the primary key column
def cartName = column[String]("CART_NAME") // 2
def cartType = column[String]("CART_TYPE") //3
def userId = column[Long]("USER_ID") //5
def * = id ~ cartName ~ cartType ~ userId
def persist(implicit session: Session) = id.? ~ cartName ~ cartType ~ userId.?
def insert(cart: Cart)(implicit session: Session): Long = {
valcartId = persist.insert(cart.id, cart.cartName, cart.cartType.toString(), cart.user.id)
RCartProducts.insertAll(cartId, cart.products)
cartId
}
def create(implicit session: Session) = {
if (!MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.create
ddl.createStatements.foreach(println)
}
}
def drop(implicit session: Session) = {
if (MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.drop
ddl.dropStatements.foreach(println)
}
}
}
}
trait RCartProductDAO extends Logging { this: Profile =>
import profile.simple._
object RCartProducts extends Table[RCartProduct]("R_CART_PRODUCT") {
def cartId = column[Long]("CART_ID", O.NotNull) // 1 This is the primary key column
def productId = column[Long]("PRODUCT_ID", O.NotNull) //2
def * = cartId ~ productId <> (RCartProduct.apply _, RCartProduct.unapply _)
def insertAll(cartId: Long, productIds: Seq[Product])(implicit session: Session): Unit = {
productIds.foreach(x => RCartProducts.insert(RCartProduct(cartId, x.id.get)))
}
def create(implicit session: Session) = {
if (!MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.create
//ddl.createStatements.foreach(println)
}
}
def drop(implicit session: Session) = {
if (MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.drop
//ddl.dropStatements.foreach(println)
}
}
}
}
Mostly, the test class will be as follow:
class ModelDAOSpec extends FunSuite with ShouldMatchers with BeforeAndAfterAll {
implicitvaldao: BaseDAO = BaseDAO.apply("test")
overridedef beforeAll() { dao.create }
overridedef afterAll() { dao.drop }
test("Database tables are created and dropped") {
assert("x" === "x")
}
test("Persist Product") {
dao.db withSession {
valitem = new Product(None, "Iphone5", "Nice device", DateTime.now, DateTime.now, "IPHONE5")
info(item.toString)
valid = dao.Products.insert(item)
assert(id === 1)
dao.Products.insert(new Product(None, "IPhone4S", "Also good", DateTime.now, DateTime.now, "IPHONE4S"))
}
}
…snip…
I will run the test case as follow:
sbt>test-only com.sillycat.easysprayrestserver.dao.*
Next step, I will take a nap, I will try to begin the server part of my SuperPlan project.
10. How to Work with Actor
come soon…
11. How to do Validation
come soon...
Tips
References:
Spray 1 ~ 9
http://sillycat.iteye.com/blog/1766558
http://sillycat.iteye.com/blog/1766568
http://sillycat.iteye.com/blog/1857105
http://sillycat.iteye.com/blog/1858282
http://sillycat.iteye.com/blog/1858298
http://sillycat.iteye.com/blog/1859025
H2
http://www.h2database.com/html/main.html
8. Prepare the DB first
8.1 H2 database
If we want to use this database in embedded mode, we will do as follow:
Add the h2*.jar to the class path
Use the JDBC driver class: org.h2.Driver
The database URL jdbc:h2:~/test opens the database test in my user home directory.
Based on H2 Console Application, we can access a SQL database using a browser interface. (We do not run under this mode)
9. How to work with DB
I use H2 database as my DAO layer example database.
Here are my application.conf configuration file:
test {
db.driver = org.h2.Driver
db.url = "jdbc:h2:mem:easysprayrestserver_test;DB_CLOSE_DELAY=-1"
db.user = sa
db.password = password
cp = ${cp}
cp.maxPoolSize=25
}
local {
db.driver = org.h2.Driver
db.url = "jdbc:h2:~/easysprayrestserver"
db.user = sa
db.password = password
cp = ${cp}
cp.maxPoolSize=25
}
cp {
minPoolSize=2
acquireIncrement=2
maxPoolSize=250
maxIdleTime=28800
testConnectionOnCheckout=true
preferredTestQuery="select 1"
}
It is very happy to know that the configuration properties can be treated like this>
cp = ${cp}
That is really helpful.
And from my understanding, I am coming from Java Springframework and always playing with J2EE application. So I prefer to have a DAO layer.
BaseDAO.scala class will be as follow:
package com.sillycat.easysprayrestserver.dao
import scala.slick.driver.ExtendedProfile
import scala.slick.driver.H2Driver
import scala.slick.driver.MySQLDriver
import scala.slick.session.Database
import scala.slick.session.Database.threadLocalSession
import scala.slick.session.Session
import com.sillycat.easysprayrestserver.util.DBConn
import com.sillycat.easysprayrestserver.util.TestDBConn
class BaseDAO(overridevalprofile: ExtendedProfile, dbConn: DBConn) extends ProductDAO with UserDAO with CartDAO with RCartProductDAO with Profile {
def db: Database = { dbConn.database }
def create: Unit = db withSession {
Users.create
Products.create
Carts.create
RCartProducts.create
}
def drop: Unit = db withSession {
Users.drop
Products.drop
Carts.drop
RCartProducts.drop
}
def doWithSession(f: Unit => Unit) = db withSession { f }
}
object BaseDAO {
import com.sillycat.easysprayrestserver.model.DBType._
def apply: BaseDAO = {
new BaseDAO(MySQLDriver, DBConn)
}
def apply(s: String): BaseDAO = s match {
case"test" => new BaseDAO(H2Driver, TestDBConn)
case _ => new BaseDAO(MySQLDriver, DBConn)
}
// Clients can import this rather than depending on slick directly
implicitdef threadLocalSession: Session = scala.slick.session.Database.threadLocalSession
}
The Profile file will be as follow, Profile.scala
package com.sillycat.easysprayrestserver.dao
import scala.slick.driver.ExtendedProfile
import com.sillycat.easysprayrestserver.util.JodaDateTimeMapper
import com.sillycat.easysprayrestserver.util.UserTypeMapper
trait Profile {
valprofile: ExtendedProfile
implicitvaljodaMapper = JodaDateTimeMapper
implicitvaluserTypeMapper = UserTypeMapper
}
Here is the most complex part, ModelDAO.scala
package com.sillycat.easysprayrestserver.dao
import scala.slick.util.Logging
import org.joda.time.DateTime
import com.sillycat.easysprayrestserver.model.Product
import com.sillycat.easysprayrestserver.model.Cart
import com.sillycat.easysprayrestserver.model.RCartProduct
import scala.slick.jdbc.meta.MTable
import com.sillycat.easysprayrestserver.model.User
import com.sillycat.easysprayrestserver.model.UserType
import spray.httpx.SprayJsonSupport
import spray.json.DefaultJsonProtocol
import spray.json.DeserializationException
import spray.json.JsNumber
import spray.json.JsObject
import spray.json.JsString
import spray.json.JsValue
import spray.json.RootJsonFormat
import org.joda.time.format.DateTimeFormat
import org.joda.time.DateTime
import spray.json.JsArray
import spray.json._
import DefaultJsonProtocol._
import org.joda.time.DateTime
import scala.slick.util.Logging
import scala.slick.jdbc.meta.MTable
import spray.json.{ RootJsonFormat, DefaultJsonProtocol }
import spray.httpx.SprayJsonSupport
import org.joda.time.format.DateTimeFormat
import scala.slick.ast._
import scala.slick.ast.Util._
trait UserDAO extends Logging { this: Profile =>
import profile.simple._
object Users extends Table[(Long, String, Int, String, DateTime, DateTime, String)]("USER") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc) // 1 This is the primary key column
def userName = column[String]("USER_NAME") // 2
def age = column[Int]("AGE") //3
def userType = column[String]("USER_TYPE") //4
def createDate = column[DateTime]("CREATE_DATE") //5
def expirationDate = column[DateTime]("EXPIRATION_DATE") // 6
def password = column[String]("PASSWORD") // 7
def * = id ~ userName ~ age ~ userType ~ createDate ~ expirationDate ~ password
def persist(implicit session: Session) = id.? ~ userName ~ age ~ userType ~ createDate ~ expirationDate ~ password
def insert(user: User)(implicit session: Session): Long = {
valid = persist.insert(user.id, user.userName, user.age, user.userType.toString(), user.createDate, user.expirationDate, user.password)
id
}
def auth(userName: String, password: String)(implicit session: Session): Option[User] = {
logger.debug("I am authing the userName=" + userName + " password=" + password)
(userName, password) match {
case ("admin", "admin") =>
Option(User(Some(1), "admin", 100, UserType.ADMIN, new DateTime(), new DateTime(), "admin"))
case ("customer", "customer") =>
Option(User(Some(2), "customer", 100, UserType.CUSTOMER, new DateTime(), new DateTime(), "customer"))
case ("manager", "manager") =>
Option(User(Some(3), "manager", 100, UserType.SELLER, new DateTime(), new DateTime(), "manager"))
case _ => None
}
}
def get(userId: Long)(implicit session: Session): Option[User] = {
logger.debug("Try to fetch User Object with userId = " + userId)
valquery = for { item <- Users if (item.id === userId) } yield (item)
logger.debug("Get User by id, SQL should be : " + query.selectStatement)
query.firstOption map {
case (user) => User(Option(user._1), user._2, user._3, UserType.withName(user._4), user._5, user._6, user._7)
}
}
def create(implicit session: Session) = {
if (!MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.create
ddl.createStatements.foreach(println)
}
}
def drop(implicit session: Session) = {
if (MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.drop
ddl.dropStatements.foreach(println)
}
}
}
}
trait ProductDAO extends Logging { this: Profile =>
import profile.simple._
object Products extends Table[Product]("PRODUCT") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc) // 1 This is the primary key column
def productName = column[String]("PRODUCT_NAME") // 2
def productDesn = column[String]("PRODUCT_DESN") //3
def createDate = column[DateTime]("CREATE_DATE") //4
def expirationDate = column[DateTime]("EXPIRATION_DATE") // 5
def productCode = column[String]("PRODUCT_CODE") //6
def * = id.? ~ productName ~ productDesn ~ createDate ~ expirationDate ~ productCode <> (Product.apply _, Product.unapply _)
def forInsert = productName ~ productDesn ~ createDate ~ expirationDate ~ productCode <>
({ t => Product(None, t._1, t._2, t._3, t._4, t._5) },
{ (s: Product) => Some(s.productName, s.productDesn, s.createDate, s.expirationDate, s.productCode) })
def insert(s: Product)(implicit session: Session): Long = {
Products.forInsert returning id insert s
}
def forProductCode(productCode: String)(implicit session: Session): Option[Product] = {
valquery = for {
item <- Products if item.productCode === productCode
} yielditem
query.firstOption
}
def all()(implicit session: Session): Seq[Product] = {
Query(Products).list
}
def create(implicit session: Session) = {
if (!MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.create
ddl.createStatements.foreach(println)
}
}
def drop(implicit session: Session) = {
if (MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.drop
ddl.dropStatements.foreach(println)
}
}
}
}
//Cart(id: Option[Long], cartName: String, cartType: CartType.Value, user: User, products: Seq[Product])
trait CartDAO extends Logging { this: Profile with RCartProductDAO =>
import profile.simple._
object Carts extends Table[(Long, String, String, Long)]("CART") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc) // 1 This is the primary key column
def cartName = column[String]("CART_NAME") // 2
def cartType = column[String]("CART_TYPE") //3
def userId = column[Long]("USER_ID") //5
def * = id ~ cartName ~ cartType ~ userId
def persist(implicit session: Session) = id.? ~ cartName ~ cartType ~ userId.?
def insert(cart: Cart)(implicit session: Session): Long = {
valcartId = persist.insert(cart.id, cart.cartName, cart.cartType.toString(), cart.user.id)
RCartProducts.insertAll(cartId, cart.products)
cartId
}
def create(implicit session: Session) = {
if (!MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.create
ddl.createStatements.foreach(println)
}
}
def drop(implicit session: Session) = {
if (MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.drop
ddl.dropStatements.foreach(println)
}
}
}
}
trait RCartProductDAO extends Logging { this: Profile =>
import profile.simple._
object RCartProducts extends Table[RCartProduct]("R_CART_PRODUCT") {
def cartId = column[Long]("CART_ID", O.NotNull) // 1 This is the primary key column
def productId = column[Long]("PRODUCT_ID", O.NotNull) //2
def * = cartId ~ productId <> (RCartProduct.apply _, RCartProduct.unapply _)
def insertAll(cartId: Long, productIds: Seq[Product])(implicit session: Session): Unit = {
productIds.foreach(x => RCartProducts.insert(RCartProduct(cartId, x.id.get)))
}
def create(implicit session: Session) = {
if (!MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.create
//ddl.createStatements.foreach(println)
}
}
def drop(implicit session: Session) = {
if (MTable.getTables(this.tableName).firstOption.isDefined) {
valddl = this.ddl
ddl.drop
//ddl.dropStatements.foreach(println)
}
}
}
}
Mostly, the test class will be as follow:
class ModelDAOSpec extends FunSuite with ShouldMatchers with BeforeAndAfterAll {
implicitvaldao: BaseDAO = BaseDAO.apply("test")
overridedef beforeAll() { dao.create }
overridedef afterAll() { dao.drop }
test("Database tables are created and dropped") {
assert("x" === "x")
}
test("Persist Product") {
dao.db withSession {
valitem = new Product(None, "Iphone5", "Nice device", DateTime.now, DateTime.now, "IPHONE5")
info(item.toString)
valid = dao.Products.insert(item)
assert(id === 1)
dao.Products.insert(new Product(None, "IPhone4S", "Also good", DateTime.now, DateTime.now, "IPHONE4S"))
}
}
…snip…
I will run the test case as follow:
sbt>test-only com.sillycat.easysprayrestserver.dao.*
Next step, I will take a nap, I will try to begin the server part of my SuperPlan project.
10. How to Work with Actor
come soon…
11. How to do Validation
come soon...
Tips
References:
Spray 1 ~ 9
http://sillycat.iteye.com/blog/1766558
http://sillycat.iteye.com/blog/1766568
http://sillycat.iteye.com/blog/1857105
http://sillycat.iteye.com/blog/1858282
http://sillycat.iteye.com/blog/1858298
http://sillycat.iteye.com/blog/1859025
H2
http://www.h2database.com/html/main.html
发表评论
-
Update Site will come soon
2021-06-02 04:10 1672I am still keep notes my tech n ... -
Hadoop Docker 2019 Version 3.2.1
2019-12-10 07:39 289Hadoop Docker 2019 Version 3.2. ... -
Nginx and Proxy 2019(1)Nginx Enable Lua and Parse JSON
2019-12-03 04:17 441Nginx and Proxy 2019(1)Nginx En ... -
Data Solution 2019(13)Docker Zeppelin Notebook and Memory Configuration
2019-11-09 07:15 284Data Solution 2019(13)Docker Ze ... -
Data Solution 2019(10)Spark Cluster Solution with Zeppelin
2019-10-29 08:37 245Data Solution 2019(10)Spark Clu ... -
AMAZON Kinesis Firehose 2019(1)Firehose Buffer to S3
2019-10-01 10:15 315AMAZON Kinesis Firehose 2019(1) ... -
Rancher and k8s 2019(3)Clean Installation on CentOS7
2019-09-19 23:25 308Rancher and k8s 2019(3)Clean In ... -
Pacemaker 2019(1)Introduction and Installation on CentOS7
2019-09-11 05:48 336Pacemaker 2019(1)Introduction a ... -
Crontab-UI installation and Introduction
2019-08-30 05:54 447Crontab-UI installation and Int ... -
Spiderkeeper 2019(1)Installation and Introduction
2019-08-29 06:49 495Spiderkeeper 2019(1)Installatio ... -
Supervisor 2019(2)Ubuntu and Multiple Services
2019-08-19 10:53 366Supervisor 2019(2)Ubuntu and Mu ... -
Supervisor 2019(1)CentOS 7
2019-08-19 09:33 325Supervisor 2019(1)CentOS 7 Ins ... -
Redis Cluster 2019(3)Redis Cluster on CentOS
2019-08-17 04:07 367Redis Cluster 2019(3)Redis Clus ... -
Amazon Lambda and Version Limit
2019-08-02 01:42 433Amazon Lambda and Version Limit ... -
MySQL HA Solution 2019(1)Master Slave on MySQL 5.7
2019-07-27 22:26 514MySQL HA Solution 2019(1)Master ... -
RabbitMQ Cluster 2019(2)Cluster HA and Proxy
2019-07-11 12:41 456RabbitMQ Cluster 2019(2)Cluster ... -
Running Zeppelin with Nginx Authentication
2019-05-25 21:35 318Running Zeppelin with Nginx Aut ... -
Running Zeppelin with Nginx Authentication
2019-05-25 21:34 316Running Zeppelin with Nginx Aut ... -
ElasticSearch(3)Version Upgrade and Cluster
2019-05-20 05:00 322ElasticSearch(3)Version Upgrade ... -
Jetty Server and Cookie Domain Name
2019-04-28 23:59 396Jetty Server and Cookie Domain ...
相关推荐
AndroidAsync.zip,用于Android的异步套接字、HTTP(客户端 服务器)、WebSocket和socket.io库。基于nio,而不是threads.asynchronous socket、http(client server)和android的websocket库。基于nio,而不是线程。
spray-actor-per-request, 使用每个请求模型中的参与者的示例 Spray 应用程序 每个请求的 Spray这个项目提供了一个示例 Spray 应用程序,它使用每个请求模型中的参与者。为什么要为每个HTTP请求启动一个参与者?轻松...
"slick-pg_spray-json_2.10-0.5.2.2.zip"中的Slick-PG版本,结合了Scala的spray-json库,使得JSON数据可以无缝地在数据库和代码之间转换。spray-json是Scala的一个轻量级、快速且易于使用的JSON库,它可以方便地解析...
描述 "spray-cache-spymemcached.zip" 涉及的是一个针对 Spray 框架的缓存扩展,名为 SpyMemcached 后端。Spray 是一个基于 Scala 的高性能、轻量级的 HTTP 和 RESTful 服务构建工具,常用于构建异步、非阻塞的服务...
官方版本,亲测可用
官方版本,亲测可用
官方版本,亲测可用
官方版本,亲测可用
spray-template使得开发RESTful API和服务时,能够快速、灵活地生成动态HTML或其他文本格式的响应。 在spray-can中,spray-template扮演了重要的角色,它允许开发者使用简洁、可读性强的模板语言来构建HTTP响应的...
$ git clone git://github.com/spray/spray-template.git my-project 将目录更改为您的克隆: $ cd 我的项目 启动 SBT: $ sbt 编译一切并运行所有测试: 测试 启动应用程序: 重新开始 浏览到以查看 angular...
官方版本,亲测可用
官方版本,亲测可用
官方版本,亲测可用
官方版本,亲测可用
概要该项目解释了如何使用具有 CORS 支持的 Spray 实现 REST API假设我假设你有经验和你的工作环境准备好使用以下技术/框架: Akka、SBT、CORS、Spray、cURL、Scala、Git要求这篇文章面向那些有 Scala 工作经验并...
GitHub Spray 一个CLI为您的GitHub贡献历史记录图生成喷雾安装npm i -g github-spray要求吉特最近的NodeJS用法创建一个新的GitHub存储库并复制其URLgithub-spray -t < text> --multiplier < factor> --push --origin...