美文网首页理论疯狂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