美文网首页理论疯狂iOSswifter
Swift Perfect服务器开发(解决一切疑难杂症)

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

作者: 贝尔特伦 | 来源:发表于2017-05-03 11:12 被阅读946次

目前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

相关文章

网友评论

本文标题:Swift Perfect服务器开发(解决一切疑难杂症)

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