美文网首页iOSer 的自我修养IOS-ProgrammingSwift
服务端写Swift体验 (Perfect框架)

服务端写Swift体验 (Perfect框架)

作者: LuisX | 来源:发表于2017-03-14 21:04 被阅读9259次
Perfect

官方网站
文档详情: 官方中文文档

实践Demo

Perfect实践Demo

简介

Perfect是一组完整、强大的工具箱、软件框架体系和Web应用服务器,可以在Linux、iOS和macOS (OS X)上使用。该软件体系为Swift工程师量身定制了一整套用于开发轻量、易维护、规模可扩展的Web应用及其它REST服务的解决方案,这样Swift工程师就可以实现同时在服务器和客户端上采用同一种语言开发软件项目。

Perfect性能对比

性能表现

Perfect官网

Vapor官网

Kitura官网

Zewo官网

Node.js官网

性能表现

参考连接:不服跑个分

系统要求

Swift 3.0

如果低于3.0版本则Perfect是无法成功编译的。

OS X系统

需要的所有内容均已预装。

Ubuntu Linux系统

Perfect软件框架可以在Ubuntu Linux 14.04 and 15.10环境下运行。

一、Mac搭建Perfect

Mac搭建Perfect

1.创建Swift软件包

打开终端,新建一个PerfectDemoProject文件夹用于保存项目文件。

mkdir PerfectDemoProject
cd PerfectDemoProject
1.1.1

2.初始化git

为了加快项目进度,最简单的方法就是把这个项目目录转化为git repo(代码资源文件夹)。

git init
touch README.html
git add README.html
git commit -m "Initial commit"
1.2.1

3.创建Package.swift文件

在git repo根目录下面创建一个Package.swift文件。这个文件是SPM(Swift软件包管理器)编译项目时必须要用到的文件。

touch Package.swift
1.3.1

使用Xcode打开Package.swift文件并添加如下代码,添加所需要使用的软件包。

//软件包管理
import PackageDescription

let versions = Version(0,0,0)..<Version(10,0,0)
let urls = [
    "https://github.com/PerfectlySoft/Perfect-HTTPServer.git",      //HTTP服务
    "https://github.com/PerfectlySoft/Perfect-MySQL.git",           //MySQL服务
    "https://github.com/PerfectlySoft/Perfect-Mustache.git"         //Mustache
]

let package = Package(
    name: "PerfectDemoProject",
    targets: [],
    dependencies: urls.map { .Package(url: $0, versions: versions) }
)
1.3.2

4.创建Sources文件夹

创建一个名为Sources的文件夹用于保存源程序,然后在这个源程序文件夹下面创建一个main.swift文件。

mkdir Sources
echo 'print("您好!")' >> Sources/main.swift
1.4.1

5.编译运行项目

等待编译成功之后运行项目控制台输出 "您好!"。

swift build
.build/debug/PerfectDemoProject
1.5.1

使用Xcode

1.创建成Xcode可以运行项目

Swift软件包管理器(SPM)能够创建一个Xcode项目,并且能够运行PerfectTemplate模板服务器,还能为您的项目提供完全的源代码编辑和调试。

swift package generate-xcodeproj
创建为Xcode工程 工程目录

2.打开PerfectDemoProject.xcodeproj

在Build Settings中Library Search Paths检索项目软件库中增加(不单单是编译目标)

配置工程

注意: 若在编辑过程中无其他问题且无法运行,请删除PerfectDemoProject.xcodeproj文件,重新使用swift package generate-xcodeproj命令创建

二、搭建HTTP服务器

HTTP服务器

官方:HTTP服务器配置

1.编辑main.swift

import PerfectLib
import PerfectHTTP
import PerfectHTTPServer

//HTTP服务
let networkServer = NetworkServerManager(root: "webroot", port: 8888)
networkServer.startServer()

2.创建并编辑NetworkServerManager.swift

import PerfectLib
import PerfectHTTP
import PerfectHTTPServer

open class NetworkServerManager {
    
    fileprivate var server: HTTPServer
    internal init(root: String, port: UInt16) {
        
        server = HTTPServer.init()                          //创建HTTPServer服务器
        var routes = Routes.init(baseUri: "/api")           //创建路由器
        configure(routes: &routes)                          //注册路由
        server.addRoutes(routes)                            //路由添加进服务
        server.serverPort = port                            //端口
        server.documentRoot = root                          //根目录
        server.setResponseFilters([(Filter404(), .high)])   //404过滤
        
    }
    
    //MARK: 开启服务
    open func startServer() {
        
        do {
            print("启动HTTP服务器")
            try server.start()
        } catch PerfectError.networkError(let err, let msg) {
            print("网络出现错误:\(err) \(msg)")
        } catch {
            print("网络未知错误")
        }
        
    }
    
    //MARK: 注册路由
    fileprivate func configure(routes: inout Routes) {
        
        // 添加接口,请求方式,路径
         routes.add(method: .get, uri: "/") { (request, response) in
         response.setHeader( .contentType, value: "text/html")          //响应头
         let jsonDic = ["hello": "world"]
         let jsonString = self.baseResponseBodyJSONData(status: 200, message: "成功", data: jsonDic)
         response.setBody(string: jsonString)                           //响应体
         response.completed()                                           //响应
         }
        
    }

    //MARK: 通用响应格式
     func baseResponseBodyJSONData(status: Int, message: String, data: Any!) -> String {
        
        var result = Dictionary<String, Any>()
        result.updateValue(status, forKey: "status")
        result.updateValue(message, forKey: "message")
        if (data != nil) {
            result.updateValue(data, forKey: "data")
        }else{
            result.updateValue("", forKey: "data")
        }
        guard let jsonString = try? result.jsonEncodedString() else {
            return ""
        }
        return jsonString
        
    }
    
    //MARK: 404过滤
    struct Filter404: HTTPResponseFilter {
        
        func filterBody(response: HTTPResponse, callback: (HTTPResponseFilterResult) -> ()) {
            callback(.continue)
        }
        
        func filterHeaders(response: HTTPResponse, callback: (HTTPResponseFilterResult) -> ()) {
            if case .notFound = response.status {
                response.setBody(string: "404 文件\(response.request.path)不存在。")
                response.setHeader(.contentLength, value: "\(response.bodyBytes.count)")
                callback(.done)
                
            } else {
                callback(.continue)
            }
        }
        
    }

}

3.运行结果

2.3.1

4.访问接口效果

2.4.1

三、搭建MySQL数据库

MySQL数据库

官方:MySQL配置

工具

数据库管理工具: Navicat Premium

(1)安装MySQL

手动安装MySQLhttps://dev.mysql.com/downloads/mysql/

1.安装Homebrew

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
3.1.1

PASS:若要卸载Homebrew

cd `brew --prefix`
rm -rf Cellar$ brew prune
rm -rf Library .git .gitignore bin/brew README.md share/man/man1/brew
rm -rf ~/Library/Caches/Homebrew

2.使用Homebrew安装MySQL

brew install mysql
3.1.2

PASS:若要卸载MySQL(仅供参考)

brew remove mysql  
brew cleanup  
launchctl unload -w ~/Library/LaunchAgents/com.mysql.mysqld.plist  
rm ~/Library/LaunchAgents/com.mysql.mysqld.plist  
sudo rm /usr/local/mysql
sudo rm -rf /usr/local/mysql*
sudo rm -rf /Library/StartupItems/MySQLCOM
sudo rm -rf /Library/PreferencePanes/My*
(编辑 /etc/hostconfig) sudo vi /etc/hostconfig (删除行 MYSQLCOM=-YES)
sudo rm -rf /Library/Receipts/mysql*
sudo rm -rf /Library/Receipts/MySQL*
sudo rm -rf /var/db/receipts/com.mysql.* 

卸载MySQL参考链接

(2)配置MySQL

示例配置
账号:root
密码:Fengxu::1226

#开启MySQL服务
mysql.server start
#初始化MySQL配置向导
mysql_secure_installation
3.2.1

3.编辑mysqlclient.pc文件

将mysqlclient.pc文件设置为可读写后删除-fno-omit-frame-pointer内容。

//文件路径:
/usr/local/lib/pkgconfig/mysqlclient.pc
3.2.2

(3)创建数据库和表

1.使用Navicat Premium工具,连接本地数据库

打开Navicat Premium点击链接,选择MySQL后,输入连接名、密码,确定保存。

示例链接名:TianTianDB

3.3.1

2.创建TianProject数据库

右键点击TIanTIanDB数据库连接,选择新建数据库,输入数据库名,确认保存。

示例数据库名:TianProject

3.3.2

3.创建account_level表

展开TIanTIanDB数据库,右键点击表,选择新建表,如下图,保存名为account_level表。

示例表名:account_level

3.3.3

4.向account_level表中添加数据

示例表数据:如下图

3.3.4

(4)编辑Perfect服务端

1.创建并编辑DataBaseManager.swift

import MySQL

//MARK: 数据库信息
let mysql_host = "127.0.0.1"
let mysql_user = "root"
let mysql_password = "Fengxu::1226"
let mysql_database = "TianProject"

//MARK: 表信息
let table_account = "account_level"                    //等级

open class DataBaseManager {
    
    fileprivate var mysql: MySQL
    internal init() {
        mysql = MySQL.init()                           //创建MySQL对象
        guard connectedDataBase() else {               //开启MySQL连接
            return
        }
    }
    
    //MARK: 开启连接
    private func connectedDataBase() -> Bool {
        
        let connected = mysql.connect(host: mysql_host, user: mysql_user, password: mysql_password, db: mysql_database)
        guard connected else {
            print("MySQL连接失败" + mysql.errorMessage())
            return false
        }
        print("MySQL连接成功")
        return true
        
    }
    
    //MARK: 执行SQL语句
    /// 执行SQL语句
    ///
    /// - Parameter sql: sql语句
    /// - Returns: 返回元组(success:是否成功 result:结果)
    @discardableResult
    func mysqlStatement(_ sql: String) -> (success: Bool, mysqlResult: MySQL.Results?, errorMsg: String) {
        
        guard mysql.selectDatabase(named: mysql_database) else {            //指定database
            let msg = "未找到\(mysql_database)数据库"
            print(msg)
            return (false, nil, msg)
        }
        
        let successQuery = mysql.query(statement: sql)                      //sql语句
        guard successQuery else {
            let msg = "SQL失败: \(sql)"
            print(msg)
            return (false, nil, msg)
        }
        let msg = "SQL成功: \(sql)"
        print(msg)
        return (true, mysql.storeResults(), msg)                            //sql执行成功
        
    }
    
    /// 增
    ///
    /// - Parameters:
    ///   - tableName: 表
    ///   - key: 键  (键,键,键)
    ///   - value: 值  ('值', '值', '值')
    func insertDatabaseSQL(tableName: String, key: String, value: String) -> (success: Bool, mysqlResult: MySQL.Results?, errorMsg: String){
        
        let SQL = "INSERT INTO \(tableName) (\(key)) VALUES (\(value))"
        return mysqlStatement(SQL)
        
    }
    
    /// 删
    ///
    /// - Parameters:
    ///   - tableName: 表
    ///   - key: 键
    ///   - value: 值
    func deleteDatabaseSQL(tableName: String, key: String, value: String) -> (success: Bool, mysqlResult: MySQL.Results?, errorMsg: String) {
        
        let SQL = "DELETE FROM \(tableName) WHERE \(key) = '\(value)'"
        return mysqlStatement(SQL)
        
    }
    
    /// 改
    ///
    /// - Parameters:
    ///   - tableName: 表
    ///   - keyValue: 键值对( 键='值', 键='值', 键='值' )
    ///   - whereKey: 查找key
    ///   - whereValue: 查找value
    func updateDatabaseSQL(tableName: String, keyValue: String, whereKey: String, whereValue: String) -> (success: Bool, mysqlResult: MySQL.Results?, errorMsg: String) {
        
        let SQL = "UPDATE \(tableName) SET \(keyValue) WHERE \(whereKey) = '\(whereValue)'"
        return mysqlStatement(SQL)
        
    }
    
    /// 查所有
    ///
    /// - Parameters:
    ///   - tableName: 表
    ///   - key: 键
    func selectAllDatabaseSQL(tableName: String) -> (success: Bool, mysqlResult: MySQL.Results?, errorMsg: String) {
        
        let SQL = "SELECT * FROM \(tableName)"
        return mysqlStatement(SQL)
        
    }
    
    /// 查
    ///
    /// - Parameters:
    ///   - tableName: 表
    ///   - keyValue: 键值对
    func selectAllDataBaseSQLwhere(tableName: String, keyValue: String) -> (success: Bool, mysqlResult: MySQL.Results?, errorMsg: String) {
        
        let SQL = "SELECT * FROM \(tableName) WHERE \(keyValue)"
        return mysqlStatement(SQL)
        
    }
    
    //获取account_level表中所有数据
    func mysqlGetHomeDataResult() -> [Dictionary<String, String>]? {
        
        let result = selectAllDatabaseSQL(tableName: table_level)
        var resultArray = [Dictionary<String, String>]()
        var dic = [String:String]()
        result.mysqlResult?.forEachRow(callback: { (row) in
            dic["accountLevelId"] = row[0]
            dic["name"] = row[1]
            resultArray.append(dic)
        })
        return resultArray
        
    }
}

2.NetworkServerManager.swift中添加访问接口

添加http://127.0.0.1:8888/api/home 接口,返回account_level表中所有数据

//MARK: 注册路由
fileprivate func configure(routes: inout Routes) {
        
     routes.add(method: .get, uri: "/home") { (request, response) in
            
         let result = DataBaseManager().mysqlGetHomeDataResult()
         let jsonString = self.baseResponseBodyJSONData(status: 200, message: "成功", data: result)
         response.setBody(string: jsonString)
         response.completed()
            
      }
        
}

(5)验证效果

1.运行结果

3.5.1

2.访问接口效果

浏览器访问http://127.0.0.1:8888/api/home 接口

3.5.2

相关文章

网友评论

  • fbccb107dd76:作者你好,最近是按照你的Demo试验了一下Perfect服务器端,遇到点问题,Build时,PerfectMySQL报错,/Users/yangjing/Documents/Xcode Program/PerfectTemplate/.build/checkouts/Perfect-MySQL.git-4976130768219902098/Sources/PerfectMySQL/MySQL.swift:103:12: Binary operator '==' cannot be applied to operands of type 'Int' and 'Bool'等19个错误。都在PerfectMySQL的文件里,不知道什么缘故。
    无法解决,求作者帮忙解答
    笙绳省盛:同样的问题,作者有办法吗?
  • YourReference:1、执行 mysql.server start 报错
    ERROR! The server quit without updating PID file (/usr/local/var/mysql/appledeMacBook-Air-2.local.pid).

    2、执行mysql_secure_installation报错
    Error: Access denied for user 'root'@'localhost' (using password: YES)

    3、Could not build Objective-C module 'mysqlclient' 报错
    4、'mysql/udf_registration_types.h' file not found with <angled> include; use "quotes" instead

    目前遇到这几个报错,无法解决,求作者帮忙解答
  • 偶识君乎:获取hello world 数据那里的404错误,其实是因为你代码那个位置的configure 里面配置的是 / 好像过不了,我在那里配置了 /home ,就没有404了。
  • ZFJ_张福杰:楼主 我通过浏览器或者postman请求都正常,可以获取Jason数据,但是通过手机AFNetworking 3.0请求是失败的,这是为什么呢???
  • 骑毛驴的小强:error: header '/usr/local/include/mysql/mysql.h' not found header "/usr/local/include/mysql/mysql.h"
    error: could not build Objective-C module 'mysqlclient' import mysqlclient
    报这个错误的先找到 TARGETS中的 PerfectMySQL里面的other linker flags这个里面是否有值 ,需要添加-L/usr/local/Cellar/mysql/5.7.20/lib 和 -lmysqlclient 这2行(是2行),这个前前你要homebrew安装了mysql,可以去/usr/local/Cellar/mysql看这个文件夹是否存在,没有就homebrew install mysql,然后在other linker flags里面加上那2行即可(注意点:直接MYSQL官网下包安装的不行,需要homebrew再次安装)
  • Zclee:启动啦sever,但是访问接口报404
    字节码:你的路由没配置好
    此问题是由于在创建路由Routes时错误导致的,你可尝试:
    var routes = Routes()
    routes.add(method: .get, uri: "/") { (request, response) in
    response.appendBody(string: "<html><title>Hello, world!</title><body>Hello, world!</body></html>")
    response.completed()
    }
  • 隔壁班小明:谢谢楼主分享,给你666个赞
  • Unique_c:LZ好, 没有用Xcode编辑,直接搭建好,swift build 出现 No such module 'MySQL', 请问怎么解决?(swift版本 3.1)
    b2c5a1b6c897:swift build 以后出现could not build Objective-C module 'mysqlclient',这个问题怎么解决啊
    Unique_c:@shenhualxt 谢谢
    5993729c0924:改为 import PerfectMySQL
  • 1876c153eb8b:楼主你好,请问swift build时报/Users/MacBook/PerfectDemoProject/.build/checkouts/Perfect-mysqlclient.git-5333716826204139417/module.modulemap:2:12: error: header '/usr/local/include/mysql/mysql.h' not found
    header "/usr/local/include/mysql/mysql.h"
    ^
    /Users/MacBook/PerfectDemoProject/.build/checkouts/Perfect-MySQL.git-4976130768219902098/Sources/PerfectMySQL.swift:25:8: error: could not build Objective-C module 'mysqlclient'
    import mysqlclient
    ^
    <unknown>:0: error: build had 1 command failures
    error: exit(1): /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-build-tool -f /Users/MacBook/PerfectDemoProject/.build/debug.yaml
    这个错误是什么原因呀,求帮助,谢谢
    柳絮风微:同问第三个error,我也是遇到这个问题
    骑毛驴的小强:请看我此文的评论,解决办法
    Ash_Gao:我也有遇到这样的问题,有解决吗
  • select刘冠:大神,问个题外话:
    mysql.query(statement: "")
    MySQL查询语句只有这种写法,如何防止SQL注入漏洞
  • 心至靜行至遠:请问楼主,为什么浏览器显示的是乱码?
    字节码:Safari-系统偏好设置-高级-默认编码 选择UTF-8
  • 方振:很棒,正是需要的
  • 上个月:你好,我现在本地服务已经搭好,Log内容:
    启动HTTP服务器,
    [INFO] Starting HTTP server on 0.0.0.0:8888,
    但是在浏览器输入 我的IP地址:8888/api 或者 0.0.0.0:8888/api ,
    响应404 鏂囦欢/api涓嶅瓨鍦ㄣ€ 这种乱码,
    打断点是运行404过滤这里 response.setBody(string: "404 文件\(response.request.path)不存在。") 请问这个问题是可能是出在什地方
    上个月:@王小宾 你手机上能返回api的json数据么 还是手机也是404没乱码
    王小宾:我也遇到了这个问题,官方说默认使用utf8编码,在浏览器上似乎没有作用,而在手机端访问正常。
    后知后觉空想家:我也是遇到了同样的问题
  • 东方_未明:总结的很好很简洁👍
  • 跳跳虾:打开项目编辑的时候,PerfectThread 2.0.12 这个库里的文件报错,是怎么回事啊,
  • 我家有个大金毛:怎么指定ios编译错误,只能运行在mac 上?
  • 2c5f6efcdd8f:超级小白问个问题。在第一部分swift build过程中,终端报出nonWhitelistedFlags("Non whitelisted flags found: [\"-fno-omit-frame-pointer\"] in pc file mysqlclient")。不知道是什么问题,有空的话希望分享一下,谢谢
    砖头很烫手:我也是这个问题 我是直接把-fno-omit-frame-pointer删除后重新build就成功了
    d80c89a0af81:将mysqlclient.pc文件设置为可读写后删除-fno-omit-frame-pointer内容。
  • FLYc:请问必须使用brew 安装MySQL么?我自己在MySQL 官网下载安装包安装的,build的时报 一下问题 /Users/rayland/Documents/swiftweb/PerfectDemoProject/Packages/mysqlclient-2.0.0/module.modulemap:2:12: error: header '/usr/local/include/mysql/mysql.h' not found
    header "/usr/local/include/mysql/mysql.h",修改module.modulemap中的数据库路径。还是报错
    LuisX:@FLYc 你可以看一下MySQL官网和Perfect官方的说明
    FLYc:@LuisX此文件 mysqlclient.pc 必须存在该路径 /usr/local/lib/pkgconfig/ 下么?我从MySQL中拷贝一份到此路径下。便没有报找不到MySQL错误了
    LuisX:@FLYc 注意: 若在编辑过程中无其他问题且无法运行,请删除PerfectDemoProject.xcodeproj文件,重新使用swift package generate-xcodeproj命令创建
  • 鬓白红颜殁:LZ好,感谢分享,有个问题,在 二、搭建HTTP服务器 这一步,按照你的代码考进来,在NetworkServerManager.swift里面有一个警告,两个报错。
    警告是:/Users/xxx/Perfect/PerfectDemo/Sources/NetworkServerManager.swift:9:8: File 'NetworkServerManager.swift' is part of module 'PerfectLib'; ignoring import
    报错是:/Users/xxx/Perfect/PerfectDemo/Sources/NetworkServerManager.swift:10:8: No such module 'PerfectHTTP'
    /Users/xxx/Perfect/PerfectDemo/Sources/main.swift:3:8: No such module 'PerfectLib'。步骤是按照你的弄的,不知道问题出在哪里了。
    LuisX:@鬓白红颜殁 成功就好:grin::grin::grin:,这个问题还有待官方解决。
    鬓白红颜殁:@LuisX 重新创建后,运行成功了,十分感谢!
    这个问题还真有点诡异,直接用官方的PerfectTemplate 如果向里面添加文件后也会出现这些个问题。
    LuisX:您好,是这样的,有时候可能是因为编译成xcodeproj文件的原因.导致无法运行,报错的.
    注意:若在编辑过程中无其他问题且无法运行,请删除PerfectDemoProject.xcodeproj文件,重新使用swift package generate-xcodeproj命令创建

本文标题:服务端写Swift体验 (Perfect框架)

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