Swift服务器开发之Vapor

作者: 贝尔特伦 | 来源:发表于2017-09-18 14:19 被阅读725次

    前言:Swift服务器开发,主要有四个框架perfect,vapor,kitura,zewo它们之间的优异和区别,各位自己去了解。之前笔者曾研究过perfect框架,总结下笔者的感悟。perfect框架目前只能作为后台开发框架,而vapor框架,笔者所了解的,除了能作为后台开发框架,还能作为前端开发框架。总体功能上,vapor比perfect要多,但从单一的服务器功能开发上来说,perfect要比vapor高校,使用简单,这点开发者可以自己去体会。但在集成和配置方面,vapor的优势要比perfect大,vapor无论在mac上还是在linux服务器上,都比perfect要容易集成的多。个有优劣,开发者自行选择,本文简略讲下vapor的集成,重点在于其用法。
    关于vapor的集成,已有很多文章,但是大多都是没有及时更新,随着Swift语法的更新,不同版本在集成上,会遇到不同的问题,所以这里建议大家,在集成的时候,参考

    官方文档:https://docs.vapor.codes/2.0/getting-started/install-on-macos/

    笔者就是查看其它文章时,没有集成成功,而参考官方文档集成成功的。

    perfect框架搭建及使用 http://www.jianshu.com/p/599c5e874fda

    一:Mac OS上集成Vapor

    1,打开终端运行以下命令

    屏幕快照 2017-09-18 下午1.38.08.png

    现在你的mac已经有Swift3.1或者更高版本了,笔者写文章的时候,是Swift3.1

    2,install HomeBrew 初始化HomeBrew

    如果你还没有安装Homebrew,安装它!它对于安装像OpenSSL、MySQL、Postgres、Redis、SQLite等软件依赖非常有用。

    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    

    3,Add Homebrew Tap

    brew tap vapor/homebrew-tap
    brew update
    brew install vapor
    

    4,创建vapor项目

    vapor new 项目名
    

    出现下面这个大仙桃的时候,就表示你创建成功了


    屏幕快照 2017-09-18 下午1.45.52.png

    5,使用终端,进入到你刚才创建的项目的根目录执行build命令

    耐心等待吧,看个小电影什么的。

      vapor build 
    

    一般不会失败的,失败了,就重来一次吧,成功之后,执行run命令,运行起来服务器

    vapor run
    
    屏幕快照 2017-09-18 下午1.56.44.png

    这就代表着你的服务器运行成功了,可以去测试里面的接口了,不过笔者在测试中发现,在mac OS上,通过终端来运行服务器,它里面自带的接口可以访问,但是你自己写的访问不了。笔者自己建了.xcodeproj文件之后,用xcode运行可以访问

    终端内终止启动

    control 、
    

    创建.xcodeproj文件

    vapor xcode -y
    

    然后你可以使用xcode打开了,然后运行

    屏幕快照 2017-09-18 下午2.00.07.png

    二:在linux服务器上集成vapor

    不在累赘,极少有去配置的

    eval "$(curl -sL https://apt.vapor.sh)"
    RUN /bin/bash -c "$(wget -qO- https://apt.vapor.sh)"
    wget -q https://repo.vapor.codes/apt/keyring.gpg -O- | sudo apt-key add -
    echo "deb https://repo.vapor.codes/apt $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/vapor.list
    sudo apt-get update
    sudo apt-get install swift vapor
    eval "$(curl -sL check.vapor.sh)"
    检查swift版本
    swift —version
    检查vapor版本
    vapor —version
    进入主目录 cd / 创建项目
    vapor new 项目名   
    

    剩下的与之前一样,注意不能创建.xcodeproj文件

    三:Vapor使用篇

    接口在这两个文件内,哪个文件里写都可

    屏幕快照 2017-09-18 下午2.07.56.png

    1,添加一个get接口

    drop.get("接口名"){ req in
    
        return "请求结果"
    }
    

    2,添加一个post接口

    drop.post("testAPi"){ req in
        return "请求结果"
    }
    

    3,返回JSON数据,get和post接口方法相同

    drop.post("postBeier") { request in
        return try JSON(node:["message":"bei er te lun"])
    }
    

    4,获取请求参数,get和post获取方式相同

    drop.post("postBeier") { request in
    
        guard let name = request.data["zykey"]?.string else{
            throw Abort.badRequest
        }
    
        return try JSON(node:["message":"bei er te lun","name":name])
    }
    

    5,多路径请求

    //http://localhost/z/x/h

    drop.get("z", "x", "h") { request in
        return "You requested /z/x/h"
    }
    

    6,返回一个网页

     drop.get("zxh") { request in
    return Response(redirect: "http://www.jianshu.com/u/d20fcc519630")
    }
    

    7,返回图片

    drop.get("testImage"){ req in
        return try Response.init(filePath: "/Users/xiaocangkeji/Desktop/001.png");
    }
    

    8,上传单张图片

     drop.post("upImage"){ request in
        let img = request.formData?["img"];
        let imgPart = img?.part;
        let imgBody = imgPart?.body;
    
        if let imgDat = imgBody{
            let data = NSData.init(bytes: imgDat, length: (imgBody?.count)!);
            try?data.write(to: URL.init(fileURLWithPath: "/Users/xiaocangkeji/Desktop/011.jpg"), options: NSData.WritingOptions.atomic);
        } else{
            throw Abort.badRequest
        }
    
        return try JSON(node:["message":"success"]);
    }
    

    9,多图上传,非最优方案,日后更新

    drop.post("upMoreImage"){ request in
      for i in 1...9{
        //根据字段名获取图片信息
        let img = request.formData?["img\(i)"];
        let imgPart = img?.part;
        let imgBody = imgPart?.body;
        if let imgDat = imgBody{
            //将bytes数据转为Data类型数据
            let data = NSData.init(bytes: imgDat, length: (imgBody?.count)!);
            //存到电脑桌面
            try?data.write(to: URL.init(fileURLWithPath: "/Users/xiaocangkeji/Desktop/img\(i).jpg"), options: NSData.WritingOptions.atomic);
        }
      }
       return try JSON(node:["message":"success"]);
    }
    

    10,上传视频 统归于上传文件

    其实和上传图片一样,无论上传图片,视频,word,音频文件等,上传的都是文件,可以统一归属于上传文件类,步骤只是在存储时改下文件格式而已,开发者也可以让接口使用者,在客户端指定存储类型,这样只需要写一个接口就可以了。

    drop.post("upVideo"){ request in
        let video = request.formData?["video"];
        let videoPart = video?.part;
        let videoBody = videoPart?.body;
        //文件名 建议使用时间戳
        let fileName = String.init(format: "%.0f", Date().timeIntervalSince1970);
        //文件格式 这里让客户端传来
        let fileType = request.data["fileType"]?.string
        //如果没有传文件类型则返回错误
        guard (request.data["fileType"]?.string) != nil else{
            throw Abort.badRequest
        }
        if let videoDat = videoBody{
        let data = NSData.init(bytes: videoDat, length: (videoBody?.count)!);
            try?data.write(to: URL.init(fileURLWithPath: "/Users/xiaocangkeji/Desktop/" + fileName + "." + fileType!), options: NSData.WritingOptions.atomic);
        } else{
        throw Abort.badRequest
        }
    
        return try JSON(node:["message":"success"]);
    }
    

    11 返回一个html代码类型的网页

    此方法的作用,各位自己琢磨

    drop.get("BRService","getAnimalHelpInfo"){ request in
    
    
    let res = Response.init(status: .ok, body: "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"><html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><title>宠宝儿寻狗启示</title><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /></head><body><center><lable style=\"font-size:20px\">寻找寻找小花猫 </lable></center><div class=\"headerDiv\"><img class=\"headerImg\" src=\"http://47.98.152.252:8081/testImage?path=UserHeaderImg&name=520180419075931.jpg\" /><div class=\"nameLabel\">贝尔特伦 </div><div class=\"timeLabel\">2018-17-19</div></div><div><label class=\"infoLabel\">地址:</label><label class=\"infoLabel\">南京市 </label><a  href=\"map://chongbaoer\" style=\"font-size:14px\">查看地图 </a></div><div><label class=\"infoLabel\">联系电话 :</label><label class=\"infoLabel\">13260750669 </label></div><div><label class=\"infoLabel\">微信号  :</label><label class=\"infoLabel\">ZXHTD123456 </label></div><label class=\"contentLabel\">wo men我们zhe li我们这里dou shi我们这里都是s l d k j f我们这里都是善良的会计法 s十点f l s十是雷锋精神的理解点发牢骚s l d j f十点发牢骚善良的肌肤带来 s l f j s d l j</label><div><img width=\"100%\" src=\"http://47.98.152.252:8081/testImage?path=UserHeaderImg&name=520180419075931.jpg\" /></div></body></html><style type=\"text/css\">.headerDiv{height: 80px;}.headerImg{width:60px;height:60px;margin-left: 10px;margin-top: 10px;border-radius:60px;}.nameLabel{margin-left: 80px;margin-top: -55px;}.timeLabel{margin-left: 80px;margin-top: 10px;}.infoLabel{font-size: 15px;}.contentLabel{font-size: 14px;}</style>")
    
     return res
    }
    

    四:SQLite 数据操作篇

    数据的操作,其实就是增删改查四类。进行数据库的操作了,开发者都有自己的数据库操作工具了,笔者用的Navicat工具。vapor支持多种数据库操作框架,mysql,sqlite等等,这里我直接用的sqlite,要使用mysql的话,还得配置。

    使用前的准备

    打开项目中的sqlite文件夹,可以看到里面有三个类


    屏幕快照 2017-09-21 下午3.02.43.png

    这个是人家封装好的sqlite的库,一开始肯定都不知道怎么使用,没关系,咱们可以猜,然后点进去看。
    1,第一个sqlite+result看名字,应该是跟结果有关系的,那他应该请求结果的处理类。
    2,第二个sqlite+statement (拿出我的终极武器---有道,翻一下后面单词的意思)连起来就是sqlite的声明之类的意思,联想平时使用sqlit的方法,那这里应该是跟结果集有关系,那就跟数据绑定有关系。
    3,第三个 sqlite 看名字不用想了,一个库的总管家。
    这几个文件开发者可以自己去研究研究,笔者这里,就直接写一些简单的用法(ps:笔者都还没研究透呢,无法给你们讲解,就不装这个逼了 0.0)。

    导入Sqlite库

    import SQLite
    

    连接数据库

    let zySql = try SQLite.init(path: "/Users/beier/Desktop/Vapor.db");
    

    1,path为数据库DB文件路径
    2,sqlite对象设为全局变量
    3,连接时,数据库自动打开
    (小细节:笔者建了一个名为Vapor的DB文件,然后建了一个名为UserList的表,表内字段有 id,name,addr,age,类型分别为INTEGER,TEXT,TEXT,INTEGER)

    1,添加数据

    drop.post("addUser"){ request in
        let name = request.data["name"]?.string
        let age = request.data["age"]?.string
        let addr = request.data["addr"]?.string
        if name == nil || age == nil || addr == nil{
            throw Abort.badRequest
        }
        let sqlStr = "insert into UserList (name,age,addr) values (?,?,?);"
        let result = try zySql.execute(sqlStr, prepareClosure: { (stmt) in
           //绑定数据
          try stmt.bind(name!)
          try stmt.bind(age!)
          try stmt.bind(addr!)
      })
        print(result)
        return try JSON(node:["message":"success"]);
    }
    
    注意,sql语句中的字段顺序,要和下面绑定数据的顺序保持一致,不然数据会错乱。

    1,PostMan调用接口

    屏幕快照 2017-09-21 下午3.26.18.png

    2,刷新UserList表中数据

    屏幕快照 2017-09-21 下午3.25.51.png

    可以看到,数据已经添加到数据库里面了。

    2,更改数据

    drop.post("updateUser"){ request in
        let name = request.data["name"]?.string
        let age = request.data["age"]?.string
        let addr = request.data["addr"]?.string
        let userId = request.data["id"]?.string
        if name == nil || age == nil || addr == nil || userId == nil{
            throw Abort.badRequest
        }
        let sqlStr = String.init(format: "update UserList set name='%@',age=%@,addr='%@' where id=%@", name!,age!,addr!,userId!)
    let result = try zySql.execute(sqlStr, prepareClosure: { (stmt) in
      
        })
        print(result)
        return try JSON(node:["message":"success"]);
    
    }
    

    3,删除数据

    drop.post("deletUser"){ request in
        let userId = request.data["id"]?.string
        if userId == nil{
            throw Abort.badRequest
        }
        let sqlStr = "delete from UserList where id=" + userId! + ";"
        let result = try zySql.execute(sqlStr, prepareClosure: { (stmt) in
       
        })
        print(result)
    
        return try JSON(node:["message":"success"]);
    }
    

    4,查询数据

    drop.post("searchUser"){ request in
        let userId = request.data["id"]?.string
        if userId == nil{
            throw Abort.badRequest
        }
        let sqlStr = "select *from UserList where id=" + userId! + ";"
        let result = try zySql.execute(sqlStr, prepareClosure: { (stmt) in
        
        })
        //result就是一个数组
        var dataArr:Array<Dictionary<String,Any>> = []
        for rowData in result{
            let data = rowData.data
            var dic:Dictionary<String,Any> = [:]
            let name = data["name"]?.wrapped
            let age = data["age"]?.wrapped
            let addr = data["addr"]?.wrapped
            let userID = data["id"]?.wrapped
            dic["name"] = name
            dic["age"] = age
            dic["addr"] = addr
            dic["id"] = userID
            dataArr.append(dic)
        }
    
        return try JSON(node:["message":"success","data":dataArr]);
    }
    

    关于sql语句,需要各位开发者去自学了,对数据库操作,sql语句很重要,各位可以花一些时间记一些常用的sql语句。

    注释:可能遇到的问题

    1,开发者添加的接口,通过终端启动,或者在服务器上启动,访问404,而通过建立的xcode文件启动,就能访问。
    解决方案:终端启动前执行 vapor build一次,以后再启动即可访问。
    2,更改端口号
    启动时命令变为 vapor run serve -—port=8081
    或者修改Config文件夹下server.json文件中的端口号

    备注:转载请标注来源及署名,谢谢

    相关文章

      网友评论

      • 5d789e8efb6a::+1: :+1: :+1: 向贝尔学习
      • 小vv:赞👍 楼主加油 小白跟着你学习
        贝尔特伦:@小vv 谢谢
      • 无星灬:跟着贝哥走
        无星灬:@贝尔特伦 小松哥已经卖饼卖不下去了,还是改卖牛肉面吧
        贝尔特伦:@无星灬 跟着我很快就能转行,卖饼吧,哈哈
      • 44d3387e09f3:NB 啊 ,还有其他的资料吗
        44d3387e09f3:@贝尔特伦 好的谢谢
        贝尔特伦:@Marcello_Gong 目前有的,大多都是配置环境的资料,所以建议去看官方文档。
      • 汾酒iOSer:用swift写服务器,厉害了!有必要继续研究swift,楼主加油,期待更新!
        汾酒iOSer:@贝尔特伦 好的,谢谢分享!:+1:
        贝尔特伦:@SomeVoices 还有一篇perfect的,在本文中有链接,也可以看看

      本文标题:Swift服务器开发之Vapor

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