Swift Perfect服务器开发(解决一切疑难杂症)

目前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回车看看有没有把

屏幕快照 2017-05-03 10.59.46.png

如果和笔者的一样,那你已经安装了,如果没有,那请去官网下载
连接是直接到下载页面的
https://dev.mysql.com/downloads/mysql/
下载安装
2,使用navcat或者其它工具连接数据库,笔者用的navcat
点击左上角myconnect->mysql
屏幕快照 2017-05-03 11.05.32.png

起个名字作为connectionName ,port默认,userName和password不用管,重要的一点事Encoding

屏幕快照 2017-05-03 11.06.59.png

编码格式是UTF-8下面有一个选项是默认勾选的,它有什么作用呢?如果你勾选上了,你会发现你存的汉字都是乱码,所以这里不勾选它。
3,连接时提示你root密码错误
这里笔者也是遇到了,mac下安装时,没有提示设置密码,笔者当时安装时好像是这样的,这是你要重置密码
http://jingyan.baidu.com/article/63f236280a11680208ab3d91.html
连接放上面了,具体我不累赘了

二:Perfect搭建篇

参考文章http://www.cnblogs.com/ludashi/p/6145344.html
在搭建之前,建议大家去了解下Swift的package(包管理器)的作用
1,打开终端,进入到你要存放这个框架的地方,放哪儿,你随意

屏幕快照 2017-05-03 11.17.15.png

2,下载框架模板,使用终端完成

  git clone https://github.com/PerfectlySoft/PerfectTemplate

cd到模板内,ls你可以看到以下内容


屏幕快照 2017-05-03 11.20.11.png

3,更改项目名,并完善模板内容
打开文件夹里的package文件

屏幕快照 2017-05-03 11.22.40.png

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)
屏幕快照 2017-05-03 11.25.20.png

3,配置依赖包

在终端中输入 Swift build

这一过程是漫长而枯燥的,耐心等待,如果出现问题请重试
1),第一类错误:


屏幕快照 2017-05-03 11.30.22.png

这个错误就说明,你的Package文件里配置有问题,请按照我上面说的配置
2),第二类错误


屏幕快照 2017-05-03 11.29.51.png

找到链接里对应的文件,删了,重新build

屏幕快照 2017-05-03 11.33.06.png

如果你的packages里面够十二个文件夹了,如上图,这时候还报第一类错误,那么这时候你不用理他了,接着下一步操作
4,替换main.swift文件
笔者使用上面参考文章里的demo中main.swift文件替换了系统的main.swift文件,因为我觉得,它那里面的比较好用
https://github.com/lizelu/PerfectDemo
5,生成workspace文件
swift的服务器嘛,怎么也得能用xcode打开运行是吧

终端中输入  swift package generate-xcodeproj
屏幕快照 2017-05-03 11.44.33.png

这个时候可以用Xcode打开运行了

运行错误解决方案

屏幕快照 2017-05-03 11.45.52.png

解决方案参考文章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)/**" 引号也要带着

当所有错误都解决的时候,你可以运行了

屏幕快照 2017-05-03 11.49.31.png

这时候,你可以再浏览器访问你的本地接口了


屏幕快照 2017-05-03 11.51.34.png

三:接口实际应用篇

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()
}
)

在浏览器中测试接口


屏幕快照 2017-05-03 11.56.29.png

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创建一个文件

屏幕快照 2017-05-03 12.04.03.png
屏幕快照 2017-05-03 12.04.13.png

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<Dictionary<String,Any>>?{
    /*
    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<Dictionary<String,Any>> = Array.init();
    result?.forEachRow(callback: { (row) in
        var dic:Dictionary<String,Any> = 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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容

  • vapor服务器SSL配置 https://www.jianshu.com/p/93c0d6ac5d80 前言:S...
    贝尔特伦阅读 3,230评论 13 32
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,982评论 4 60
  • 他是个人偶师。 在北京胡同里有一家毫不起眼的小店,里面摆着各种各样的人偶,每一件都是他的作品,每一件都是他的孩子。...
    AU秋水诗韵阅读 471评论 4 5
  • 阳光扯开夜的帷幕 窗外开始人车涌动 行人赶路匆匆 表情平淡或凝重 生活一如既往 按部就班走入格子 或激昂奋斗 或如...
    一心小茶馆阅读 514评论 143 39
  • 消逝在周遭耳语 渐隐入观光客的旅游鞋底 时间正撑开手帕,准备好三只白兔 戏法中置换神话典故 初雪已匿形许久 寂寞回...
    凯恩期主义总中奖曲线阅读 354评论 0 2