美文网首页Vapor奇幻之旅
Vapor奇幻之旅(05 Fluent)

Vapor奇幻之旅(05 Fluent)

作者: leacode | 来源:发表于2018-01-23 16:38 被阅读213次

    在上一篇Vapor奇幻之旅(04Routing)中我介绍了Routing的写法,作为一个web应用,数据库是必不可少的,而Fluent则是管理数据的一个抽象层,可以支持数据库的增删改查等操作,默认的FluentProvider支持sqlite数据库,也就是说在没有任何数据库配置的情况下,可以通过Fluent Provider中的内存数据库来快速加载SQLite数据库,这样做的好处是可以轻松的进行接口测试。

    目前Vapor支持的数据库如下:

    数据库类型 Key Package Class 是否来自官方
    Memory memory Fluent Provider Fluent.MemoryDriver Yes
    SQlite sqlite Fluent Provider Fluent.SQLiteDriver Yes
    MySQL mysql MySQLProvider MySQLDriver.Driver Yes
    PostgreSQL postgresql PostgreSQLProvider PostgreSQLDriver.Driver No
    MongoDB N/A MongoProvider N/A No

    对于大型数据库官方只有支持到MySQL,稍显遗憾,开发团队最近都在进行Vapor 3的开发,相信不久后就可以有更多的数据库类型支持了,而且由于Fluent的抽象的特性,只要有相应的驱动,适配任何数据库我想只是时间问题。

    既然是抽象层,我们先不管用啥数据库,可以先把我们的数据模型搭建起来。

    我想给我的网站加一段名人名言,于是我创建一个名为Quotes的模型,代码如下:

    import Vapor
    import FluentProvider
    import HTTP
    
    /// 名人名言
    final class Quotes: Model {
        
        // 这个属性能让Fluent存储额外的信息,如这个model的id
        let storage = Storage()
        
        //***下面是表中的属性***
        
        /// 作者
        let author: String
        /// 内容
        let content: String
        /// 描述
        let description: String
        
        /// 数据库中列的名字
        struct Keys {
            static let id = "id"
            static let author = "author"
            static let content = "content"
            static let description = "description"
        }
        
        // MARK: 初始化Fluent
        
        /// 初始化Quotes
        required init(row: Row) throws {
            author = try row.get(Quotes.Keys.author)
            content = try row.get(Quotes.Keys.content)
            description = try row.get(Quotes.Keys.description)
        }
        
        // 序列化Quotes到数据库
        func makeRow() throws -> Row {
            var row = Row()
            try row.set(Quotes.Keys.author, author)
            try row.set(Quotes.Keys.content, content)
            try row.set(Quotes.Keys.description, description)
            return row
        }
    
    }
    

    我们的model有了,下面就该联系一下数据库了,Fluent 提供了一个Preparation协议,源码如下:

    /// A preparation prepares the database for
    /// any task that it may need to perform during runtime.
    public protocol Preparation {
    
        /// The prepare method should call any methods
        /// it needs on the database to prepare.
        static func prepare(_ database: Database) throws
    
        /// The revert method should undo any actions
        /// caused by the prepare method.
        ///
        /// If this is impossible, the `PreparationError.revertImpossible`
        /// error should be thrown.
        static func revert(_ database: Database) throws
    }
    

    其中prepare方法是让数据库做好准备的方法,比如新建table,而revert方法则是对prepare做的操作进行回滚操作,比如删除table。

    另外,JSON也是网络通讯常用的数据格式,模型通常也需要转换为JSON串,或者需要解析json串到模型。JSON库为我们提供了JSONConvertible协议,demo如下

    extension Quotes: JSONConvertible {
        convenience init(json: JSON) throws {
            self.init(
                author: try json.get(Quotes.Keys.author),
                content: try json.get(Quotes.Keys.content),
                description: try json.get(Quotes.Keys.description)
            )
        }
        
        func makeJSON() throws -> JSON {
            var json = JSON()
            try json.set(Quotes.Keys.id, id)
            try json.set(Quotes.Keys.author, author)
            try json.set(Quotes.Keys.content, content)
            try json.set(Quotes.Keys.description, description)
            return json
        }
    }
    

    在写这个extension之前,还需要在mode里添加一个初始化方法:

    /// 名人名言
    final class Quotes: Model {
        ...
        // MARK: 初始化Fluent
        init(author: String, content: String, description: String) {
            self.author = author
            self.content = content
            self.description = description
        }
       ...
    }
    
    

    模型已经建好了,那么作为一个数据库模型,怎么能少了增删改查呢,药药药,切克闹,增删改查来一套:

    这里我们需要开始写Controller了,在controller文件夹内创建一个QuotesController.swift的文件:

    import Vapor
    import FluentProvider
    
    struct QuotesController {
        
        func addRoutes(to drop: Droplet) {
            let quots = drop.grouped("api","quots")
        }
    }
    

    然后在Config+Setup.swift中准备好新创建的model:

    private func setupPreparations() throws {
            preparations.append(Quotes.self)
    }
    

    接下来在创建一个Routers+Quotes.swift的文件并添加QuotesController的routs.
    Routers+Quotes.swift:

    import Vapor
    
    extension Droplet {
        
        func setupQuotes() {
            let quotsController = QuotesController()
            quotsController.addRoutes(to: self)
        }
        
    }
    

    最后在Droplet+Setup.swift中添加setupQuotes()方法:

    @_exported import Vapor
    
    extension Droplet {
        public func setup() throws {
            setupQuotes()        
        }
    }
    

    现在就可以在我们的controller里面写增删改查了:

    import Vapor
    import FluentProvider
    
    struct QuotesController {
        
        func addRoutes(to drop: Droplet) {
            let quots = drop.grouped("api","quots")
            //添加一个新的quots
            quots.post("create", handler: createQuots)
            //查询所有的quotes
            quots.get(handler: allQuotes)
            // 更新quotes
            quots.post("update", handler: updateQuotes)
            // 删除quotes
            quots.post("delete", handler: deleteQuotes)
    
        }
    
        /// 添加一个新的quots
        func createQuots(_ req: Request) throws -> ResponseRepresentable {
            guard let json = req.json else {
                throw Abort.badRequest
            }
            let quots = try Quotes(json: json)
            try quots.save()
            return quots
        }
        
        /// 查询所有的quots
        func allQuotes(_ req: Request) throws -> ResponseRepresentable {
            let quots = try Quotes.all()
            return try quots.makeJSON()
        }
        /// 更新quotes
        func updateQuotes(_ req: Request) throws -> ResponseRepresentable {
            guard let json = req.json else {
                throw Abort.badRequest
            }
            
            let id: Int = try json.get("id")
            if let quots = try Quotes.find(id) {
                try quots.update(json: json)
            }
            
            return try Quotes.all().makeJSON()
        }
        
        // 删除quotes
        func deleteQuotes(_ req: Request) throws -> ResponseRepresentable {
            guard let json = req.json else {
                throw Abort.badRequest
            }
            let id: Int = try json.get("id")
            if let quots = try Quotes.find(id) {
                try quots.delete()
            }
            
            return try Quotes.all().makeJSON()
        }
        
    }
    

    还需要在Quotes中加入一个update方法,并把参数改成var

    /// 名人名言
    final class Quotes: Model {
        /// 作者
        var author: String
        /// 内容
        var content: String
        /// 描述
        var description: String
        ...
    }
    
    extension Quotes {
        
        func update(json: JSON) throws {
            self.author = try json.get(Quotes.Keys.author)
            self.content = try json.get(Quotes.Keys.content)
            self.description = try json.get(Quotes.Keys.description)
            try self.save()
        }
        
    }
    
    

    现在我们的增删改查就已经完成了,下面cmd+r运行程序,用Rested测试接口:

    增加一个名言 查询插入的结果 更新刚刚插入的数据 删除刚刚插入的数据

    由于默认的数据库是基于内存加载的,重新运行程序则会清空,如果想要保存数据到服务器,你需要使用持续化的数据库,如MySQL、PostgreSQL以及MongoDB,后面我会对这几个数据库操作一一介绍。

    关于Vapor其他知识,可以参考以下文章:

    Vapor奇幻之旅(01开始)
    Vapor奇幻之旅(02部署)
    Vapor奇幻之旅(03上手)
    Vapor奇幻之旅(04Routing)
    Vapor奇幻之旅(05 Fluent)
    Vapor奇幻之旅(06 PostgreSQL)
    Vapor奇幻之旅(07 连接服务端PostgreSQL)
    Vapor奇幻之旅(08 连接服务端MongoDB)
    Vapor奇幻之旅(09 连接MySQL)

    希望你对我的教程能够喜欢,你们的赞是我持续的动力,欢迎加入QQ群参与互动:431296189

    相关文章

      网友评论

        本文标题:Vapor奇幻之旅(05 Fluent)

        本文链接:https://www.haomeiwen.com/subject/aozjaxtx.html