在上一篇博客使用Perfect写服务端–初级(一)中已经示范了在本地启动一个服务的过程,这一篇博客将展示具体的一些基本开发,写接口、连接数据库、数据库增删查改等。
启动HTTP服务
我们之前已经克隆了官方的例子,并且已经编译好生成了Xcode可以直接打开的工程文件,现在打开工程,在PerfectTemplate目录下新建一个swift文件,取名为MyServer

导入需要用到的库
import PerfectLib
import PerfectHTTP
import PerfectHTTPServer
然后使用命令
$ swift build
$ swift package generate-xcodeproj
重新编译。
具体代码:
open class MyServer{
fileprivate var server : HTTPServer
internal init(root : String , port : UInt16){
// 构造httpServer对象
server = HTTPServer.init()
// 构造路由对象
var routes = Routes.init()
// 配置路由 (URL,回调函数)
configure(routes: &routes)
// 将路由添加进服务
server.addRoutes(routes)
// 设置根目录和端口
server.documentRoot = root
server.serverPort = port
}
// 配置路由的方法
fileprivate func configure(routes : inout Routes){
// 添加接口, 路径为/,请求方法为GET,回调函数为闭包
routes.add(method: .get, uri: "/") { (request, response) in
// 取得URL中的参数
// let param = request.params()
//返回数据头
response.setHeader(.contentType, value: "text/html")
//返回数据体
response.appendBody(string: "Hello world")
//返回
response.completed()
}
}
// 启动服务
open func start(){
do {
try self.server.start()
} catch PerfectError.networkError(let err, let msg) {
print("Network error thrown: \(err) \(msg)")
} catch{
print("Network unknow error")
}
}
}
这样就写完了一个HTTP Server,包含了一个接口,接口返回的内容是一个字符串形式的Hello world。使用Perfect搭建一个HTTP服务还是比较简单,Perfect已经处理了大部分事物,在路由的创建过程中,开发者只需要提供一个处理该路由的回调函数。
在main.swift中调用start启动服务
let myServer = MyServer.init(root: "/Users/admin/Desktop/PerfectTemplate/Sources/file", port: 8181)
myServer.start()

在Xcode中直接编译运行,在浏览器的地址栏输入localhost:8181就能看到返回的Hello world字符串
其中参数root设置的根目录路径下的文件在没有其它设置的情况下是可以通过URL直接访问或者下载的,比如在我当前设置的路径下放入一个json文件

然后我们就可以通过URL http://localhost:8181/loading.json访问到这个json文件中的内容

类似json,html文件,或者图片都可以直接访问,其它文件是可以直接下载的。
添加接口
接口可以在配置路由的方法里添加
// get请求 在闭包里对这个请求做处理 返回一个json
routes.add(method: .get, uri: "/getDatas") { (request, response) in
response.setHeader(.contentType, value: "application/json; charset=utf-8")
// 获取参数
guard let content = request.param(name: "content") else{
let jsonString = self.baseResponseBodyJSONData(status: -1, message: "失败", data: "缺少参数")
response.setBody(string: jsonString)
response.completed()
return
}
let dic = ["content" : content]
let jsonString = self.baseResponseBodyJSONData(status: 200, message: "请求成功", data: dic)
response.setBody(string: jsonString)
response.completed()
}
通用json格式
private 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
}
设置完成后重启服务,然后在浏览器中请求

这样一个接口就完成了,很简单,可以根据自己的需求添加一个接口试一试。
如果需要保存数据,或者获取数据那就需要用到数据库了,下面进行接入数据库的实践。
MySQL接入
对于MySQL的接入可以直接使用Perfect提供的Perfect-MySQL库。
在Package.swift添加引用:
.package(url: "https://github.com/PerfectlySoft/Perfect-MySQL.git", from: "3.0.0")

重新编译,下载Perfect-MySQL库,重新生成工程并且打开
$ swift build
$ swift package generate-xcodeproj
如果执行swift build有报错,可以先执行swift package generate-xcodeproj然后请看文章最后的解决办法
安装MySQL
可以参考文章:Mac下使用homebrew安装配置mysql
Mac下安装MySQL这里就不多说了,安装和配置可自行谷歌和百度,或者参考上面的博客链接,但是记得请用homebrew安装,之前我下载的官网的包,然后手动安装后面出了点小问题,后面还是用的homebrew安装的,所以为了避免后面出现一些小问题记得请用homebrew安装。
安装数据库管理工具
我现在用的管理工具是Navicat Premium,有更好的可以推荐。
Navicat Premium下载地址
创建数据库和表
在本地安装配置好MySQL和工具Navicat Premium后,使用Navicat Premium连接本地数据库。
1.打开Navicat Premium,新建一个MySQL连接

2.创建数据库
选择刚才创建的MySQL连接,右键新建数据库,数据库名字自己取

3.创建表
选择创建的数据库,双击展开,然后展开表,右键表选择新建表,添加字段

4.插入数据

创建数据库管理类
打开工程,新建数据库管理类
import Foundation
import PerfectMySQL
//MARK: 数据库信息
// XieteProject
let mysql_host = "localhost"
let mysql_user = "root"
let mysql_password = "**********" //这里请填写自己数据库的密码
let mysql_database = "XieteProject"
//MARK: 表信息
let table_column = "tbl_column"
let dbManager = DataBaseManager.init()
open class DataBaseManager {
fileprivate var mysql : MySQL
internal init(){
mysql = MySQL.init() // 创建MySQL对象
//设置客户端字符集,这是非常必要的操作,否则所有中文可能都会变成问号
guard mysql.setOption(.MYSQL_SET_CHARSET_NAME, "utf8mb4") else {
return
}
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: 元组
@discardableResult
func mysqlStatement(_ sql : String) -> (success : Bool, mysqlResult : MySQL.Results?, errorMsg: String){
guard mysql.selectDatabase(named: mysql_database) else {
let msg = "未找到\(mysql_database)数据库:\(mysql.errorMessage())"
print(msg)
return (false, nil, msg)
}
let successQuery = mysql.query(statement: 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)
}
/// 增
///
/// - Parameters:
/// - tableName: 表
/// - key: 键 (键,键,键)
/// - value: 值 ('值', '值', '值')
/// - Returns: 元组
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)
}
}
编写接口获取数据库数据
在路由配置里添加接口
routes.add(method: .get, uri: "/getColumn") { (request, response) in
response.setHeader(.contentType, value: "application/json; charset=utf-8")
let dbManager = DataBaseManager.init()
let result = dbManager.selectAllDatabaseSQL(tableName: table_column)
var resultArray = [Dictionary<String, String>]()
var dic = [String : String]()
result.mysqlResult?.forEachRow(callback: { (row) in
dic["id"] = row[0]
dic["content"] = row[1]
resultArray.append(dic)
})
let jsonString = self.baseResponseBodyJSONData(status: 200, message: "success", data: resultArray)
response.setBody(string: jsonString)
response.completed()
}
最后在Xcode中直接编译运行,运行成功后在浏览器里输入URL:http://localhost:8181/getColumn就能获取到json数据了。


查询数据库表里的数据已经完成,插入数据可以自己编写实践。后面会更新进行部署服务的一些实践操作。
下面附上本文的demo链接
错误解决办法
引用
Perfect-MySQL库然后执行swift build报错,如果是这种错误
其实是库里面的
swift文件报错了,我们可以打开工程,找到PerfectMySQL库,然后按照下面的方式改好,在Xcode里编译下就好了。







