일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Materials
- ftp
- postgres
- GoCD
- STF
- STF_PortForwarding
- nGrinder
- create table
- openpyxl
- centos
- appium server
- postgresql
- nmap
- rethinkdb
- kitura
- insert
- Jupyter Notebook
- sshpass
- SWIFT
- appium
- port forwarding
- mysql
- PYTHON
- Jupyter
- perfect
- ssh
- 28015
- nohup
- 실행권한
- ubuntu
- Today
- Total
don't stop believing
이미지 업로드와 static file (이미지, html) 보기 본문
Perfect로 이미지를 업로드하고 이미지를 확인해 보겠습니다.
언제나 그렇듯이 swift 버전을 확인하고 가겠습니다.
$ swift -version Apple Swift version 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2) Target: x86_64-apple-macosx10.9
프로젝트 폴더를 만들고 이동합니다. 그리고 swift package init으로 초기화 합니다.
$ mkdir nGleServer014 $ cd nGleServer014 TongChunui-MacBook-Pro:nGleServer014 tongchunkim$ swift package init --type executable Creating executable package: nGleServer014 Creating Package.swift Creating README.md Creating .gitignore Creating Sources/ Creating Sources/nGleServer014/main.swift Creating Tests/
xcodeproj 파일을 생성하고 열어줍니다.
$ swift package generate-xcodeproj $ open nGleServer014.xcodeproj/
xcode가 실행되면 Package.swift 파일에 PerfectHTTPServer를 추가합니다.
// swift-tools-version:4.0 import PackageDescription let package = Package( name: "nGleServer014", dependencies: [ .package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", from: "3.0.0"), ], targets: [ .target( name: "nGleServer014", dependencies: ["PerfectHTTPServer",]), ] )
xcode를 닫고 swift package update와 swift build를 해줍니다.
$ swift package update $ swift build
그리고 webroot 폴더를 만들고 그 안에 업로드한 이미지를 받을 images와 html 파일을 담을 docs 폴더를 만들어 줍니다.
그리고 main.swift가 있는 위치에 controller.swift 파일을 만들어 줍니다. 서버 실행과 route를 분산해 줄겁니다.
$ mkdir webroot $ cd webroot/ $ mkdir images docs $ cd ../Sources/nGleServer014/ $ touch controller.swift
전체 폴더의 tree 구조는 아래와 같이 만들어 집니다.
$ tree . ├── Package.resolved ├── Package.swift ├── README.md ├── Sources │ └── nGleServer014 │ ├── controller.swift │ └── main.swift ├── Tests ├── nGleServer014.xcodeproj │ ├── COpenSSL_Info.plist │ ├── PerfectCHTTPParser_Info.plist │ ├── PerfectCZlib_Info.plist │ ├── PerfectCrypto_Info.plist │ ├── PerfectHTTPServer_Info.plist │ ├── PerfectHTTP_Info.plist │ ├── PerfectLib_Info.plist │ ├── PerfectNet_Info.plist │ ├── PerfectThread_Info.plist │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ └── tongchunkim.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ ├── xcshareddata │ │ └── xcschemes │ │ ├── nGleServer014-Package.xcscheme │ │ └── xcschememanagement.plist │ └── xcuserdata │ └── tongchunkim.xcuserdatad │ └── xcschemes │ ├── nGleServer014.xcscheme │ └── xcschememanagement.plist └── webroot ├── docs └── images └── dejavu_1517991366.jpg
이제 다시 xcodeproj를 만들어 주고 열어 봅니다.
$ swift package generate-xcodeproj $ open nGleServer014.xcodeproj/
먼저 main.swift로 이동합니다.
Controller 클래스는 아직 안만들었지만 우선 아래와 같이 작성합니다.
import PerfectLib import PerfectHTTP import PerfectHTTPServer let server = HTTPServer() server.serverPort = 8080 let control = Controller() server.addRoutes(Routes(control.routes)) do { try server.start() } catch PerfectError.networkError(let err, let msg) { print("Network error thrown: \(err) \(msg)") }
이제 controller.swift로 이동합니다.
import먼저 해줍니다.
import Foundation import PerfectLib import PerfectHTTP import PerfectHTTPServer
이제 request로 들어오는 json 데이터 key 정보들을 정의합니다.
json 데이터가 많아지면 계속 추가하면 됩니다.
struct JSONKey { static let userName = "user_name" static let image = "image" static let imagePath = "image_path" }
이제 Controller 클레스를 만들고 routes를 정의합니다.
이미지를 업로드할 uri와 이미지를 볼 uri를 추가하고 그에 맞는 handler를 추가합니다. handler 함수는 아래에 설명됩니다.
final class Controller { var routes: [Route] { return [ Route(method: .post, uri: "/upload", handler: uploadImage), Route(method: .get, uri: "/image/**", handler: viewImage), ] } }
request로 전달되는 데이터 중 필수로 지정된 key가 모두 있는지 확인하는 함수를 만들어 줍니다.
필수로 지정된 key가 모두 있다면 nil을 반환하고 부족하다면 Array로 반환됩니다. 이후 옵셔널 체인(if let)으로 처리합니다.
func lakedParams(_ paramsNeeded: [String], _ paramsReceived: [(String, String)]) -> [String]? { var laked: [String] = [] for param in paramsNeeded { if paramsReceived.filter({ (key, _) -> Bool in return key == param }).isEmpty { laked.append(param) } } return laked.count > 0 ? laked : nil }
이미지 저장 디렉토리를 불러옵니다.
이미지가 저장될 폴더는 ./webroot/images 입니다.
let imageDir: Dir? = { let imageDir = Dir("./webroot/images") if imageDir.exists == false { do { try imageDir.create() print("Working Directory (\(imageDir.path)) for examples created.") } catch { print("Could not create Working Directory for examples.") return nil } } return imageDir }()
response로 전달할 함수를 만들어 줍니다.
func returnMessage(result: Int, data: [String: Any], response: HTTPResponse) { do { try response.setBody(json: ["result": result, "data": data, "ts": Date().ticks]) .setHeader(.contentType, value: "application/json") .completed() } catch { response.setBody(string: "Error handling request: \(error)") .completed(status: .internalServerError) } }
timestamp를 만들기 위해 extension Date도 해줍니다.
extension Date { var ticks: UInt64 { return UInt64((self.timeIntervalSince1970 + 62_135_596_800) * 10_000_000) } }
드디어 upload 함수를 만들 차례입니다.
func uploadImage(request: HTTPRequest, response: HTTPResponse) { // 부족한 매개변수가 없는지 확인합니다. let needParams = [JSONKey.userName] if let lakedParams = lakedParams(needParams, request.postParams) { let returnData = ["error": "필수 key가 전달되지 않았습니다. \(lakedParams)"] as [String: Any] returnMessage(result: 1001, data: returnData, response: response) return } // 이미지 파일이 업로드 되었는지 확인 guard let imageInformation: MimeReader.BodySpec = request.postFileUploads?.first, let imageFile = imageInformation.file else { let returnData = ["error": "이미지 파일이 전달되지 않았습니다."] as [String: Any] returnMessage(result: 1002, data: returnData, response: response) return } // 사용자 이름 추출 guard let userName = request.param(name: JSONKey.userName) else { let returnData = ["error": "사용자 이름 추출에 실패했습니다."] as [String: Any] returnMessage(result: 1003, data: returnData, response: response) return } // 이미지가 저장될 디렉터리 guard let imageDirectory = imageDir else { let returnData = ["error": "이미지가 저장될 디렉터리를 확인하지 못했습니다."] as [String: Any] returnMessage(result: 1004, data: returnData, response: response) return } // 고유한 이미지 이름을 위해 타임스템프 값을 활용 let timestamp: Int = icuDateToSeconds(getNow()) // 사용자이름_타임스템프.jpg 형식으로 파일이름 지정 let imageFileName: String = userName + "_" + String(timestamp) + ".jpg" // 이미지가 저장될 경로 let imageFilePath: String = imageDirectory.path + imageFileName // 이미지 저장에 실패할 경우 실패 응답 보내기 do { try imageFile.copyTo(path: imageFilePath, overWrite: false) } catch { response.completed(status: .internalServerError) return } let imageUrl = "http://" + server.serverAddress + ":\(server.serverPort)" + "/image/" + imageFileName let returnData = [JSONKey.userName: userName, JSONKey.imageUrl: imageUrl] returnMessage(result: 0, data: returnData, response: response) }
이제 Postman으로 데이터를 전달해 봅시다.
response 데이터가 잘 옵니다.
xcode에서 webroot/images 폴더에 이미지가 업로드 되는지도 확인해 줍니다.
여러번 테스트했는데 모두 잘 들어오고 있습니다.
이제 이미지를 불러 봅시다.
이미지를 보기위해 위에서 route에 get method를 추가했었습니다.
Route(method: .get, uri: "/image/**", handler: viewImage),
viewImage 함수는 아래와 같이 작성합니다.
func viewImage(request: HTTPRequest, response: HTTPResponse) { request.path = request.urlVariables[routeTrailingWildcardKey]! let handler = StaticFileHandler(documentRoot: "webroot/images", allowResponseFilters: true) handler.handleRequest(request: request, response: response) }
이미지를 upload하고 response로 받은 데이터의 image_url 값을 브라우저로 불러 봅니다.
http://0.0.0.0:8080/image/dejavu_1517993432.jpg
viewImage() 함수는 이미지나 html처럼 static한 데이터를 보는데 사용할 수 있습니다.
여기까지 입니다.
'Swift > Perfect' 카테고리의 다른 글
Web 서버 기본 구성 1 (기본 구성과 mustache 확인) (0) | 2018.06.18 |
---|---|
Perfect에서 여러 방법으로 데이터 전달하기 (HTTPRequest) (0) | 2018.06.09 |
json 파일로 config를 관리해 봅시다. (0) | 2018.01.31 |
Perfect로 redis에 연결해 봅시다. 2 (0) | 2018.01.22 |
Perfect로 redis에 연결해 봅시다. 1 (0) | 2018.01.17 |