Swift + Perfect開發(fā)你的服務(wù)器(高級版)

序言:

1.以下代碼中的意義舶沛,會在代碼里解釋,用比較容易理解的詞語注釋窗价,若有晦澀之處如庭,可私信于我。
2.現(xiàn)已假設(shè)讀者閱讀過我的另外兩篇文章??
Swift Perfect開發(fā)你的服務(wù)器(初級版)
Swift Perfect開發(fā)你的服務(wù)器(中級版)
3.準備Peffect助手工具:Perfect Assistant 3.0創(chuàng)建服務(wù)器項目

基于“以上”編譯成功后撼港,在默認的main.swift文件里坪它,全部清空,然后替換成我的代碼:

// 導(dǎo)入所需要的庫
import PerfectLib
import PerfectHTTP
import PerfectHTTPServer
import PerfectMustache

import Foundation

let root = "./webroot"

// 配置服務(wù)器端口帝牡、根目錄等
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() // 開啟服務(wù)器
} 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.這里定義接口,為客戶端服務(wù)墨技,我們請求的方法惩阶,和url,在這里設(shè)置扣汪。
     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是客戶端的請求,有些參數(shù)我們可在這里獲取
2.response是我們給客戶端的響應(yīng)茅主,想要返回的數(shù)據(jù)舞痰,在這設(shè)置
*/
func TestUpload(request: HTTPRequest, response: HTTPResponse) {
    
    do{
        
        guard let uploads = request.postFileUploads, uploads.count >= 1 else {
            let successArray: [String:Any] = ["result":"false", "msg":"請選擇正確的圖片數(shù)量"]
            let jsonStr = try successArray.jsonEncodedString()
            try response.setBody(json: jsonStr)
            response.completed()
            return
        }
/* 
這里的iOSTime參數(shù)是我在客戶端那邊傳過來的當(dāng)前本地時間。
其實是可以在這設(shè)置的诀姚,但由于客戶端和服務(wù)器的精確時間并不一致响牛,
所以采用了客戶端的時間為標(biāo)準,同時也鍛煉了我們傳參的能力
*/
        guard let currentTime = request.param(name: "iOSTime") else {
            return
        }
        #if os(Linux)
// Dir.workingDir.parentDir拿到父目錄赫段,也可在本地運行打印看看是什么東東
        guard let parentPath = Dir.workingDir.parentDir?.path else {
            return
        }
        
// 設(shè)置我們存放圖片的路徑呀打,同時nginx的配置也要與這個路徑有關(guān)聯(lián),看過我之前的文章會不陌生糯笙!
        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

        // 官網(wǎng)上摘取的代碼
        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環(huán)境運行)
                        let resultPath = fileDir.path + upload.fileName
                        // Ubuntu存放到數(shù)據(jù)庫的路徑
                        let realPath = "http://www.crios.cn/pictures/" + "\(currentTime)" + upload.fileName
                        let _ = try thisFile.moveTo(path: resultPath, overWrite: true)
                        
                        // 這里會報錯贬丛,DataBaseManager.swift還沒有創(chuàng)建,先不管给涕,會在下一步執(zhí)行
                        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 {
// 通用的返回數(shù)據(jù)豺憔,可參照我的代碼或官網(wǎng)的额获、設(shè)定
                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數(shù)據(jù)庫管理類

import Foundation
import PerfectMySQL

// MARK: 數(shù)據(jù)庫信息
#if os(Linux) // 在Ubuntu下
let user = "root"
let password = "你的密碼"
let dataBase = "test1" // test1數(shù)據(jù)庫是自己在Navicat Premium圖形工具里創(chuàng)建的
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()                           //創(chuàng)建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: 執(zhí)行SQL語句
    /// 執(zhí)行SQL語句
    ///
    /// - Parameter sql: sql語句
    /// - Returns: 返回元組(success:是否成功 result:結(jié)果)
    @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執(zhí)行成功
        
    }
    
    /// 創(chuàng)建表 (查詢是否有此表,若否焕阿,則創(chuàng)建)
    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)
        
    }
    
    // 獲取數(shù)據(jù)庫某個表中的所有數(shù)據(jù)
    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項目

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撤摸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子褒纲,更是在濱河造成了極大的恐慌准夷,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件莺掠,死亡現(xiàn)場離奇詭異衫嵌,居然都是意外死亡,警方通過查閱死者的電腦和手機彻秆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門楔绞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人唇兑,你說我怎么就攤上這事酒朵。” “怎么了扎附?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵蔫耽,是天一觀的道長。 經(jīng)常有香客問我留夜,道長匙铡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任碍粥,我火速辦了婚禮鳖眼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嚼摩。我一直安慰自己钦讳,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布低斋。 她就那樣靜靜地躺著,像睡著了一般匪凡。 火紅的嫁衣襯著肌膚如雪膊畴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天病游,我揣著相機與錄音唇跨,去河邊找鬼稠通。 笑死,一個胖子當(dāng)著我的面吹牛买猖,可吹牛的內(nèi)容都是我干的改橘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼玉控,長吁一口氣:“原來是場噩夢啊……” “哼飞主!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起高诺,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤碌识,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后虱而,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體筏餐,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年牡拇,在試婚紗的時候發(fā)現(xiàn)自己被綠了魁瞪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡惠呼,死狀恐怖导俘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情罢杉,我是刑警寧澤趟畏,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站滩租,受9級特大地震影響赋秀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜律想,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一猎莲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧技即,春花似錦著洼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至葵陵,卻和暖如春液荸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背脱篙。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工娇钱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伤柄,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓文搂,卻偏偏與公主長得像适刀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子煤蹭,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容