目前Swift服务器开发,主要有四个框架perfect,vapor,kitura,zewo它们之间的优异和区别,各位自己去了解,笔者这里用的是perfect框架,从搭建到实际应用,前前后后弄了小半月,期间遇到各种坑,各种补,翻阅了无数资料,闲来无事整理下。
按照笔者自己的搭建的流程写吧
perfect中文教程 http://perfect.org/docs/index_zh_CN.html
vapor框架的搭建及使用http://www.jianshu.com/p/7ee9f9ac1443
一:MySql篇
为什么使用mysql呢,为了平台的兼容,其实笔者写的时候也用Coredata,sqlite存储过数据,但是用mysql是最理智的。
1,检查是否安装了mysql
commond+shift+go 输入/usr/local回车看看有没有把
如果和笔者的一样,那你已经安装了,如果没有,那请去官网下载
连接是直接到下载页面的
https://dev.mysql.com/downloads/mysql/
下载安装
2,使用navcat或者其它工具连接数据库,笔者用的navcat
点击左上角myconnect->mysql
起个名字作为connectionName ,port默认,userName和password不用管,重要的一点事Encoding
编码格式是UTF-8下面有一个选项是默认勾选的,它有什么作用呢?如果你勾选上了,你会发现你存的汉字都是乱码,所以这里不勾选它。
3,连接时提示你root密码错误
这里笔者也是遇到了,mac下安装时,没有提示设置密码,笔者当时安装时好像是这样的,这是你要重置密码
http://jingyan.baidu.com/article/63f236280a11680208ab3d91.html
连接放上面了,具体我不累赘了
二:Perfect搭建篇
参考文章http://www.cnblogs.com/ludashi/p/6145344.html
在搭建之前,建议大家去了解下Swift的package(包管理器)的作用
1,打开终端,进入到你要存放这个框架的地方,放哪儿,你随意
2,下载框架模板,使用终端完成
git clone https://github.com/PerfectlySoft/PerfectTemplate
cd到模板内,ls你可以看到以下内容
3,更改项目名,并完善模板内容
打开文件夹里的package文件
1),name是对应的项目名,这里你更改成自己想要的项目名,其作用在后面你会明白
2),.Package(url:)这里面是版本配置的依赖包这里还需要添加一些
.Package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", majorVersion: 2),
//Request请求日志过滤器
.Package(url: "https://github.com/dabfleming/Perfect-RequestLogger.git",
majorVersion: 0),
//将日志写入指定文件
.Package(url: "https://github.com/PerfectlySoft/Perfect-Logger.git",
majorVersion: 0, minor: 0),
//MySql数据库依赖包
.Package(url: "https://github.com/PerfectlySoft/Perfect-MySQL.git",
majorVersion: 2, minor: 0)
3,配置依赖包
在终端中输入 Swift build
这一过程是漫长而枯燥的,耐心等待,如果出现问题请重试
1),第一类错误:
这个错误就说明,你的Package文件里配置有问题,请按照我上面说的配置
2),第二类错误
找到链接里对应的文件,删了,重新build
如果你的packages里面够十二个文件夹了,如上图,这时候还报第一类错误,那么这时候你不用理他了,接着下一步操作
4,替换main.swift文件
笔者使用上面参考文章里的demo中main.swift文件替换了系统的main.swift文件,因为我觉得,它那里面的比较好用
https://github.com/lizelu/PerfectDemo
5,生成workspace文件
swift的服务器嘛,怎么也得能用xcode打开运行是吧
终端中输入 swift package generate-xcodeproj
这个时候可以用Xcode打开运行了
运行错误解决方案
解决方案参考文章 http://www.jianshu.com/p/c117294e2442
错误一
Header '/usr/local/include/mysql/mysql.h'
这个错误是因为我们存放mysql.h文件的路径和它引用的路径不同。用 Homebrew安装的MySQL路径确实是正确的。
解决方法:
点击Finder,选择前往文件夹,进入/usr/local目录下,你会发现有mysql文件夹,在文件夹里找到对应mysql.h得到目录,将报错的module.modulemap文件中的路径修改成你自己的路径就可以了。这里我自己最后的路径是/usr/local/mysql-5.7.15-osx10.11-x86_64/include/mysql.h
错误二
ld: library not found for -lmysqlclient for architecture x86_64
解决方法:
在Target中找到MySQL,找到Library Search Paths中加上mysql文件夹下的lib的文件夹路径。我的是/usr/local/Cellar/mysql/5.7.16/lib
在Target中找到PerfectTemplate找到Other Linker Flags 加上-L/usr/local/Cellar/mysql/5.7.16/lib其中在lib目录下能找到对应的mysqlclient文件。
错误三
ld: library not found for -lCOpenSSL for architecture x86_64
找到project,注意不是target,中的search path 中添加 "$(PROJECT_DIR)/**" 引号也要带着
当所有错误都解决的时候,你可以运行了
这时候,你可以再浏览器访问你的本地接口了
三:接口实际应用篇
1,添加get请求已获取图片为例
//返回图片
routes.add(method: .get, uri: "/img", handler: {
request, response in
let docRoot = request.documentRoot
//获取用户上传的get参数
let name = request.param(name: "name");
do {
//let cat = File("\(docRoot)/6.jpg")
let cat = File(String.init(format: "/Users/ybon/Desktop/个人图片/游戏/%@" ,name!));
let imageSize = cat.size
let imageBytes = try cat.readSomeBytes(count: imageSize)
response.setHeader(.contentType, value: MimeType.forExtension("jpg"))
response.setHeader(.contentLength, value: "\(imageBytes.count)")
response.setBody(bytes: imageBytes)
} catch {
response.status = .internalServerError
response.setBody(string: "请求处理出现错误: \(error)")
}
response.completed()
}
)
在浏览器中测试接口
2,添加post请求
//添加联系人
routes.add(method: .post, uri: "/addFriend") { (request, respons) in
var name = "";
if let namer = request.param(name: "name"){
name = namer;
}
var addr = "";
if let addrr = request.param(name: "addr"){
addr = addrr;
}
var desc = "";
if let descr = request.param(name: "desc"){
desc = descr;
}
zySql.sqeryDB(sqlTxt: "INSERT INTO namelist(name,age,addr,desc) VALUES ('\(name)',23,'\(addr)','\(desc)')");
let dic: [String : Any] = ["code": "200"];
respons.setHeader(.contentType, value: "application/json")
do {
try respons.setBody(json: dic)
} catch {
print("json转换失败")
}
respons.completed()
}
这个接口你可以用AFN测试了
更多用法,大家可以自己去摸索了
四:MySQL进阶篇
笔者自己写了一个MySQL类,commond+n创建一个文件
1,导入头文件
import Foundation
import MySQL
import mysqlclient
import PerfectLogger
2,配置mysql的地址,端口,用户名,密码
var host : String{
get{
return "127.0.0.1";
}
}
var port : UInt32{
get{
return 3306;
}
}
var user : String{
get{
return "root";
}
}
var password:String{
get{
return "ybon";
}
}
3,创建mysql对象
private var mysql:MySQL?;
self.connectDataBase();
self.selectDataBase(name: "test_new");
4,连接数据库
private func connectDataBase(){
if mysql == nil {
mysql = MySQL.init();
}
//socket参数随意
let connected = mysql?.connect(host: host, user: user, password: password, db: "test_new", port: port, socket: "zy01", flag: 0);
guard connected! else{
LogFile.error((mysql?.errorMessage())!);
return;
}
LogFile.info("数据库连接成功");
}
5,选择数据库scheme
func selectDataBase(name:String){
guard (mysql?.selectDatabase(named: name))!else{
LogFile.error("数据库编译失败,错误代码:\(mysql?.errorCode())\n错误解释:\(mysql?.errorMessage())");
return;
}
LogFile.info("连接schema:\(name)成功");
}
6,增删改方法
func sqeryDB(sqlTxt:String){
let querySuccess_create = mysql?.query(statement: sqlTxt)
guard querySuccess_create!
else{
LogFile.error("操作失败");
return
}
LogFile.error("操作成功");
}
7,查询所有数据
func getallFriend()->Array>?{
/*
sqeryDB(sqlTxt: "insert into namelist(name) values('张先红')");
保存中文乱码解决方法
1.右键数据库里链接 选择 链接属性
2.切换到高级选项卡下 把使用mysql字符集前面的勾选去掉
*/
let success = mysql?.query(statement: "select *from namelist");
guard success!
else{
LogFile.error("操作失败");
return nil;
}
LogFile.error("操作成功");
let result = mysql?.storeResults();
var arr:Array> = Array.init();
result?.forEachRow(callback: { (row) in
var dic:Dictionary = Dictionary.init();
if row[0] != nil{
dic["name"] = row[0]! as String;
}else{
dic["name"] = "";
}
if row[1] != nil{
dic["age"] = row[1]! as String;
}else{
dic["age"] = "";
}
if row[2] != nil{
dic["addr"] = row[2]! as String;
}else{
dic["addr"] = "";
}
if row[3] != nil{
dic["desc"] = row[3]! as String;
}else{
dic["desc"] = "";
}
if row[4] != nil{
dic["sex"] = row[4]! as String;
}else{
dic["sex"] = "";
}
if row[5] != nil{
dic["id"] = row[5]! as String;
}else{
dic["id"] = "";
}
arr.append(dic);
})
return arr;
}
2017-5-10更新内容
服务器用户上传图片功能的实现。
这里是上传图片的Base64来实现的,其它方式目前正在尝试。具体的内容,笔者的注释写的很详细.
//上传单张图片
routes.add(method: .post, uri: "/zymeb/upImage") { (request, response) in
var dic: [String : Any] = ["code":"201","message":"上传失败"];
if request.param(name: "img") != nil{
//获取到base64的字符串
let imgdata = request.param(name: "img")
//笔者发现,从客户端上传的base64中,所有的+号都被空格所替代了,所以这里要替换回来
let resultStr = imgdata?.stringByReplacing(string: " ", withString: "+");
//把base64转为data
let data = Data.init(base64Encoded: resultStr!);
//以时间戳来命名图片
let date = Date();
let zone = TimeZone.init(identifier: "Asia/Shanghai");
let formatter = DateFormatter();
formatter.timeZone = zone ;
formatter.dateFormat = "yyyyMMddHHmmss";
let dateString = formatter.string(from: date) + ".jpg";
//拼接本地存储图片的地址
let path = URL.init(fileURLWithPath: "/Users/ybon/Desktop/PerfectUpImage/"+dateString);
do {
//保存图片
try data?.write(to:path);
dic["code"]="200";
dic["message"]="上传成功";
dic["imgurl"] = "/zymeb/img?name=" + dateString;
} catch {
print("图片保存失败")
}
}
response.setHeader(.contentType, value: "application/json")
do {
try response.setBody(json: dic)
} catch {
print("json转换失败")
}
response.completed()
}
客户端上传方法
let url = String.init(format: "%@/zymeb/upImage",BaseUrl);
let image = dic["image"];
let data = UIImageJPEGRepresentation(image!, 0.5);
let str = data?.base64EncodedString();
let dic = ["img":str];
//这是笔者自己用URLSession写的post请求,你们用AFN也是一样的哈,不必纠结其内部实现过程,那不是重点.
RequestWork.zyPOSTwithURLSession(url, parmas: dic as NSDictionary) { (anyobject) in
resultFunction(anyobject);
}
转载请注意排版和图片,带上原文链接,谢谢合作
笔者Demo下载地址https://github.com/zhangxianhongx/PerfectService
vapor框架文档 https://vapor.github.io/documentation/getting-started/install-toolbox.html