Swift + Perfect开发你的服务器(高级版)

序言:

1.以下代码中的意义,会在代码里解释,用比较容易理解的词语注释,若有晦涩之处,可私信于我。
2.现已假设读者阅读过我的另外两篇文章👇
Swift Perfect开发你的服务器(初级版)
Swift Perfect开发你的服务器(中级版)
3.准备Peffect助手工具:Perfect Assistant 3.0创建服务器项目

基于“以上”编译成功后,在默认的main.swift文件里,全部清空,然后替换成我的代码:

// 导入所需要的库
import PerfectLib
import PerfectHTTP
import PerfectHTTPServer
import PerfectMustache

import Foundation

let root = "./webroot"

// 配置服务器端口、根目录等
let server = HTTPServer()
server.serverPort = 8181
server.documentRoot = root

// 配置路由,BasicRoutes在RoutesManager.swift的代码里,往下看,go go go
let basic = BasicRoutes()
server.addRoutes(Routes(basic.routes))

/* 另一种方法
 * var routes = Routes()
 * routes.add(method: .post, uri: "/testUpload", handler: TestUpload)
 * server.addRoutes(routes)
 */
do {
    try server.start() // 开启服务器
} catch PerfectError.networkError(let err, let msg) {
    print("Netword error thrown: \(err) \(msg)")
}

打开项目,新建RoutesManager.swift,添加以下代码

import Foundation
import PerfectLib
import PerfectHTTP
import PerfectHTTPServer

// 路由
class BasicRoutes {
    
    var routes: [Route] {
        return [
    /*
     1.这里定义接口,为客户端服务,我们请求的方法,和url,在这里设置。
     2.由于我们还没有新建TestUpload方法,所以这里暂时会报错,先不管,往下看,go go go
     */
            Route(method: .post, uri: "/api/testUploadImage", handler: TestUpload) 
        ]
    }

}

新建路由助手类RoutesHelper.swift,然后添加下面代码

import Foundation
import PerfectLib
import PerfectHTTP

let testStr = "CRTest"
/* 
 图片上传方法:
1. request是客户端的请求,有些参数我们可在这里获取
2.response是我们给客户端的响应,想要返回的数据,在这设置
*/
func TestUpload(request: HTTPRequest, response: HTTPResponse) {
    
    do{
        
        guard let uploads = request.postFileUploads, uploads.count >= 1 else {
            let successArray: [String:Any] = ["result":"false", "msg":"请选择正确的图片数量"]
            let jsonStr = try successArray.jsonEncodedString()
            try response.setBody(json: jsonStr)
            response.completed()
            return
        }
/* 
这里的iOSTime参数是我在客户端那边传过来的当前本地时间。
其实是可以在这设置的,但由于客户端和服务器的精确时间并不一致,
所以采用了客户端的时间为标准,同时也锻炼了我们传参的能力
*/
        guard let currentTime = request.param(name: "iOSTime") else {
            return
        }
        #if os(Linux)
// Dir.workingDir.parentDir拿到父目录,也可在本地运行打印看看是什么东东
        guard let parentPath = Dir.workingDir.parentDir?.path else {
            return
        }
        
// 设置我们存放图片的路径,同时nginx的配置也要与这个路径有关联,看过我之前的文章会不陌生!
        let fileDir = Dir(parentPath + "usr/local/sources/pictures/" + currentTime)
        do {
            try fileDir.create()
        } catch {
            Log.error(message: "\(error)")
        }
        #else
        let fileDir = Dir(Dir.workingDir.path + "webroot/pictures")
        do {
            try fileDir.create()
        } catch {
            Log.error(message: "\(error)")
        }
        #endif

        // 官网上摘取的代码
        if let uploads = request.postFileUploads, uploads.count > 0 {
            var ary = [[String:Any]]()
            var pathArr = [String]()
            for upload in uploads {
                ary.append([
                    "fieldName": upload.fieldName,
                    "contentType": upload.contentType,
                    "fileName": upload.fileName,
                    "fileSize": upload.fileSize,
                    "tmpFileName": upload.tmpFileName
                    ])
                // move file to webroot
                let thisFile = File(upload.tmpFileName)
                if (thisFile.path != "") {
                    do {
                        // 本地存放路径(本地即为Mac环境运行)
                        let resultPath = fileDir.path + upload.fileName
                        // Ubuntu存放到数据库的路径
                        let realPath = "http://www.crios.cn/pictures/" + "\(currentTime)" + upload.fileName
                        let _ = try thisFile.moveTo(path: resultPath, overWrite: true)
                        
                        // 这里会报错,DataBaseManager.swift还没有创建,先不管,会在下一步执行
                        let sql = DataBaseManager().createTable(tableName: testStr + currentTime)
                        if sql.success {
                            #if os(Linux)
                            let _ = DataBaseManager().insertDatabaseSQL(tableName: testStr + currentTime, key: "path,currentTime", value: "'\(realPath)','\(currentTime)'")
                            #else
                            let _ = DataBaseManager().insertDatabaseSQL(tableName: testStr + currentTime, key: "path,currentTime", value: "'\(resultPath)','\(currentTime)'")
                            #endif
                        }
                        #if os(Linux)
                        pathArr.append(realPath)
                        #else
                        pathArr.append(resultPath)
                        #endif
                        
                    } catch {

                        let successArray: [String:Any] = ["success": 1, "result": "\(error)", "msg": "失败"]
                        Log.error(message: "\(error)")
                        let jsonStr = try successArray.jsonEncodedString()
                        try response.setBody(json: jsonStr)
                        response.completed()
                    }
                }
            }
            do {
// 通用的返回数据,可参照我的代码或官网的、设定
                let successArray: [String:Any] = ["success": 1, "result": pathArr, "msg": "成功"]
                let jsonStr = try successArray.jsonEncodedString()
                try response.setBody(json: jsonStr)
                response.completed()
            } catch {
                
                let successArray: [String:Any] = ["success": 1, "result": "后台格式错误", "msg": "成功"]
                let jsonStr = try successArray.jsonEncodedString()
                try response.setBody(json: jsonStr)
                response.completed()
            }
            
        }
        
    }catch{
        Log.error(message: "\(error)")
    }
}

新建MySQL数据库管理类

import Foundation
import PerfectMySQL

// MARK: 数据库信息
#if os(Linux) // 在Ubuntu下
let user = "root"
let password = "你的密码"
let dataBase = "test1" // test1数据库是自己在Navicat Premium图形工具里创建的
let host = "0.0.0.0"
    
#else
let user = "root"
let password = "你的密码"
let dataBase = "CRTest"
let host = "0.0.0.0"
#endif



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: host, user: user, password: password, db: dataBase)
        guard connected else {
            print(mysql.errorMessage())
            return false
        }
        print("MySQL Connect Success")
        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: dataBase) else {            //指定database
            let msg = "NO\(dataBase)Database"
            print(msg)
            return (false, nil, msg)
        }
        
        let successQuery = mysql.query(statement: sql)                      //sql语句
        guard successQuery else {
            let msg = "SQL_Error: \(sql)"
            print(msg)
            return (false, nil, msg)
        }
        let msg = "SQL_Success: \(sql)"
        print(msg)
        return (true, mysql.storeResults(), msg)                            //sql执行成功
        
    }
    
    /// 创建表 (查询是否有此表,若否,则创建)
    func createTable(tableName: String) -> (success: Bool, mysqlResult: MySQL.Results?, errorMsg: String){
        let insert = "SELECT * FROM \(tableName)"
        let statement = mysqlStatement(insert)
        if !statement.success {
            let SQL = "CREATE TABLE \(tableName) (id INT(10) PRIMARY KEY AUTO_INCREMENT, path VARCHAR(255), companyName VARCHAR(255),phoneNumber VARCHAR(255))"
            return mysqlStatement(SQL)
        }
        return mysqlStatement(insert)
    }
//    CREATE TABLE samples (id INT PRIMARY KEY AUTO_INCREMENT, created_at DATETIME, location POINT, reading JSON)
    /// 增
    ///
    /// - 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)
        
    }
    
    // 获取数据库某个表中的所有数据
    func mysqlGetUserDataResult(tableName: String) -> [Dictionary<String, String>]? {
        
        let result = selectAllDatabaseSQL(tableName: tableName)
        var resultArray = [Dictionary<String, String>]()
        var dic = [String:String]()
        result.mysqlResult?.forEachRow(callback: { (row) in
            dic["uuid"] = row[1]
            resultArray.append(dic)
        })
        
        return resultArray
        
    }
}

代码可从我的Github上下载,并新建了客户端的代码 Perfect项目

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

推荐阅读更多精彩内容