Swift编程iOS DeveloperSwift进阶之路

Swift服务器开发之Vapor

2017-09-18  本文已影响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文件中的端口号

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

上一篇下一篇

猜你喜欢

热点阅读