【Golang 1.18】GoGo垃圾信 - 求職技能三寶大集合
GoGo垃圾信,大家一起進入神乎其技的境界吧。今天這篇呢,主是結合資料端 / 網頁後端 / 手機端,產生出求職三寶系統 - 簡訊 / 推播 / 垃圾信,雖然本篇是以Golang為主體,但在Vue CLI + Typescript的著墨上會比較多,也祝大家51勞動節快樂,也祝我下禮拜能買到快篩試劑,畢竟本土確診人數已經破萬人了啊,每週一戳的大時代來臨了。
做一個長得像這樣的東西
作業環境
項目 | 版本 |
---|---|
CPU | Apple M1 |
macOS | Big Sur 12.3.1 arm64 |
Golang | 1.18.1 arm64 |
Node.js | 16.15.0 arm64 |
Visual Studio Code | 1.66.2 arm64 |
Xcode | 13.2 arm64 |
Android Studio | 2021.1.1 arm64 |
Postman | 9.0.9 arm64 |
Yarn | 1.22.18 |
Vue CLI | 5.0.4 |
Golang - 首先來看看後端API的部分
- 因為Code的部分之前的幾篇都提到過了,這裡就不再細說,只會提比較重要的部分…
功能 | API | 方式 |
---|---|---|
新增單一使用者 | http://localhost:12345/user/ | POST |
搜尋使用者列表 | http://localhost:12345/user/ | GET |
搜尋單一使用者 | http://localhost:12345/user/<username> | GET |
更新單一使用者Token | http://localhost:12345/user/<username> | PATCH |
給單一使用者發垃圾信 | http://localhost:12345/mail/<username> | POST |
給單一使用者發垃圾推播 | http://localhost:12345/push/<username> | POST |
給單一使用者發垃圾簡訊 | http://localhost:12345/sms/<username> | POST |
package main
import (
"net/http"
"william/model"
"william/utility"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
const DatabasePath string = "./file/push.sqlite3"
var User model.User
// [程式一開始要初始化的東西](https://blog.csdn.net/wide288/article/details/92808990)
func init() {
}
func main() {
database, error := utility.Sqlite3.CreateDatabase(DatabasePath)
if error != nil {
utility.Println(error)
}
error = database.AutoMigrate(&model.User{})
if error != nil {
utility.Println(error)
}
routerSetting(database)
}
// [初始化Router相關設定](https://blog.csdn.net/fbbqt/article/details/114386445)
func routerSetting(database *gorm.DB) {
corsConfig := cors.DefaultConfig() // 防止CORS的設定
corsConfig.AllowAllOrigins = true // 防止CORS的設定
router := gin.Default()
router.MaxMultipartMemory = 8 << 20
router.Use(cors.New(corsConfig))
registerWebAPI(router, database)
router.Run(":12345")
}
// 註冊API
func registerWebAPI(router *gin.Engine, database *gorm.DB) {
selectUser(router, database)
selectAllUser(router, database)
insertUser(router, database)
updateUser(router, database)
mailUser(router, database)
pushNotificationUser(router, database)
}
// MARK: - WebAPI
// <GET>搜尋單一使用者 => http://localhost:12345/user/william
func selectUser(router *gin.Engine, database *gorm.DB) {
router.GET("/user/:name", func(context *gin.Context) {
name := context.Param("name")
user, error := User.Select(database, name)
if user.ID != 0 {
utility.ContextJSON(context, http.StatusOK, user, nil)
return
}
utility.ContextJSON(context, http.StatusOK, nil, error)
})
}
// <GET>搜尋使用者列表 => http://localhost:12345/user
func selectAllUser(router *gin.Engine, database *gorm.DB) {
router.GET("/user", func(context *gin.Context) {
users := User.SelectAll(database)
utility.ContextJSON(context, http.StatusOK, users, nil)
})
}
// <POST>新增單一使用者 => http://localhost:12345/user + {"system":0,"name":"William","mail":"linuxice0609@gmail.com","phone":"0912345678"}
func insertUser(router *gin.Engine, database *gorm.DB) {
router.POST("/user", func(context *gin.Context) {
dictionary := utility.RequestBodyToMap(context)
result, error := User.Insert(database, dictionary)
utility.ContextJSON(context, http.StatusOK, result, error)
})
}
// <PATCH>更新單一使用者Token => http://localhost:12345/user/william + {"system":0,"token":"72b3ee73e5314cc4c1991dc9377f1f2c1c123dbc492f5c4197ab11f330b7568f"}
func updateUser(router *gin.Engine, database *gorm.DB) {
router.PATCH("/user/:name", func(context *gin.Context) {
name := context.Param("name")
dictionary := utility.RequestBodyToMap(context)
system := model.MobileSystem(dictionary["system"].(float64))
token := dictionary["token"].(string)
info := map[string]interface{}{
"system": system,
"token": token,
}
result, error := User.Update(database, name, info)
utility.ContextJSON(context, http.StatusOK, result, error)
})
}
// <POST>給單一使用者發垃圾信 => http://localhost:12345/mail/william + {"title":"垃圾信", "message":"什麼事也沒有"}
func mailUser(router *gin.Engine, database *gorm.DB) {
router.POST("/mail/:name", func(context *gin.Context) {
name := context.Param("name")
dictionary := utility.RequestBodyToMap(context)
title := dictionary["title"].(string)
message := dictionary["message"].(string)
result, error := User.EMail(database, name, title, message)
utility.ContextJSON(context, http.StatusOK, result, error)
})
}
// <POST>給單一使用者發垃圾推播 => http://localhost:12345/push/william + {"title":"垃圾信", "message":"什麼事也沒有"}
func pushNotificationUser(router *gin.Engine, database *gorm.DB) {
router.POST("/push/:name", func(context *gin.Context) {
name := context.Param("name")
dictionary := utility.RequestBodyToMap(context)
result, error := User.PushNotification(database, name, dictionary)
utility.ContextJSON(context, http.StatusOK, result, error)
})
}
// <POST>給單一使用者發垃圾簡訊 => http://localhost:12345/sms/william + {"message":"什麼事也沒有"}
func smsUser(router *gin.Engine, database *gorm.DB) {
router.POST("/sms/:name", func(context *gin.Context) {
name := context.Param("name")
dictionary := utility.RequestBodyToMap(context)
message := dictionary["message"].(string)
result, error := User.SMS(database, name, message)
utility.ContextJSON(context, http.StatusOK, result, error)
})
}
➊ 新增單一使用者
- 也就是註冊個人資訊,騙你的個資?
- HTTP Request
{
"system": 0, // 手機系統 (iOS: 0 / Android: 1)
"name": "William", // 個人的姓名代號
"mail": "linuxice0609@gmail.com", // 電子信箱
"phone": "0912345678" // 手機號碼
}
{
"error": null,
"result": {
"isSuccess": true // 新增結果 (成功:true / 失敗:false)
}
}
➋ 搜尋使用者列表
- 這裡就是後台要列出的列表,選擇要對誰發垃圾信?
- HTTP Response
{
"error": null,
"result": [
{
"ID": 1,
"CreatedAt": "2022-05-01T09:07:03.127434+08:00",
"UpdatedAt": "2022-05-01T09:07:03.127434+08:00",
"DeletedAt": null,
"system": 0,
"name": "William",
"mail": "linuxice0609@gmail.com",
"phone": "0912345678",
"token": ""
}
]
}
➌ 搜尋單一使用者
- 取得單一使用者的相關資訊,手機號碼 / eMail / Token
➍ 更新單一使用者Token
- 這個就是給手機端註冊、更新Token用的,有考慮到使用者有可能換手機系統,所以也是可以更新的…
- HTTP Request
{
"system": 0, // 手機系統 (iOS: 0 / Android: 1)
"token": "72b3ee73e5314cc4c1991dc9377f1f2c1c123dbc492f5c4197ab11f330b7568f" // 手機Token
}
- HTTP Response
{
"error": null,
"result": {
"isSuccess": true // 新增結果 (成功:true / 失敗:false)
}
}
➎ 給單一使用者發垃圾信
- 這個就是計對單一使用者的eMail去發送訊息
- HTTP Request
{
"title": "垃圾信", // 信件標題
"message": "什麼事也沒有" // 信件內容
}
- HTTP Response
{
"error": null,
"result": {
"isSuccess": true // 新增結果 (成功:true / 失敗:false)
}
}
➏ 給單一使用者發垃圾推播
{
"title": "垃圾推播",
"message": "就是發垃圾~~~"
}
- HTTP Response
{
"error": null,
"result": {
"isSuccess": true // 新增結果 (成功:true / 失敗:false)
}
}
➐ 給單一使用者發垃圾簡訊
{
"message": "就是發垃圾~~~"
}
- HTTP Response
{
"error": null,
"result": {
"code": "00000",
"msgid": 12345678,
"text": "Success"
}
}
iOS - 再來看看前端iOS的部分
import UIKit
import WWPrint
import WWNetworking
@main
final class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var deviceToken: String?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Utility.shared.userNotificationSetting(delegate: self) {
wwPrint("Granted")
} rejectedHandler: {
wwPrint("Reject")
} result: { (status) in
wwPrint(status.rawValue)
}
return true
}
}
// MARK: - 推播相關
extension AppDelegate {
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
self.deviceToken = deviceToken._hexString()
}
}
// MARK: - UNUserNotificationCenterDelegate
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.badge, .sound, .alert])
}
}
import UIKit
import WWPrint
import WWNetworking
import WWHUD
final class ViewController: UIViewController {
private let ApiUrl = "http://192.168.1.102:12345"
override func viewDidLoad() { super.viewDidLoad() }
@IBOutlet weak var usernameTextField: UITextField!
@IBOutlet weak var eMailTextField: UITextField!
@IBOutlet weak var phoneTextField: UITextField!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
self.view.endEditing(true)
}
/// 使用者註冊
@IBAction func registerUser(_ sender: UIBarButtonItem) {
self.view.endEditing(true)
self.register()
}
/// 使用者更新deviceToken
@IBAction func upddateDeviceToken(_ sender: UIBarButtonItem) {
guard let deviceToken = self.deviceToken() else { return }
self.view.endEditing(true)
self.update(deviceToken: deviceToken)
}
}
// MARK: - 小工具
private extension ViewController {
/// 取得推播的deviceToken
func deviceToken() -> String? {
guard let appDelegate = (UIApplication.shared.delegate) as? AppDelegate,
let deviceToken = appDelegate.deviceToken
else {
return nil
}
return deviceToken
}
/// 使用者註冊
func register() {
let urlString = "\(ApiUrl)/user"
let json: [String: Any?] = [
"system": 0,
"name": usernameTextField.text,
"mail": eMailTextField.text,
"phone": phoneTextField.text
]
WWNetworking.shared.request(with: .POST, urlString: urlString, contentType: .json, paramaters: [:], headers: nil, httpBody: json._jsonSerialization()) { result in
self.responseAction(result: result)
}
}
/// 更新使用者deviceToken
func update(deviceToken: String) {
let urlString = "\(ApiUrl)/user/\(usernameTextField.text ?? "")"
let json: [String: Any?] = [
"system": 0,
"token": deviceToken
]
WWNetworking.shared.request(with: .PATCH, urlString: urlString, contentType: .json, paramaters: nil, headers: nil, httpBody: json._jsonSerialization()) { result in
self.responseAction(result: result)
}
}
/// 顯示提示的HUD
func flashHud(isSuccess: Bool) {
var effect = WWHUD.AnimationEffect.shake(image: #imageLiteral(resourceName: "success"), angle: 10.0, duration: 0.25)
var backgroundColor = UIColor.yellow.withAlphaComponent(0.3)
defer {
DispatchQueue.main.async {
WWHUD.shared.flash(effect: effect, height: 250, backgroundColor: backgroundColor, animation: 0.5, options: .curveEaseIn, completion: nil)
}
}
if (!isSuccess) {
effect = .shake(image: #imageLiteral(resourceName: "fail"), angle: 10.0, duration: 0.25)
backgroundColor = UIColor.gray.withAlphaComponent(0.3)
}
}
/// 取得Response的處理
func responseAction(result: Result<WWNetworking.ResponseInformation, Error>) {
var isSuccess = false
defer { self.flashHud(isSuccess: isSuccess) }
switch result {
case .failure(let error): wwPrint(error)
case .success(let info):
guard let json = info.data?._jsonObject(),
let dictionary = json as? [String: Any],
let result = dictionary["result"] as? [String: Any],
let _isSuccess = result["isSuccess"] as? Bool
else {
return
}
isSuccess = _isSuccess
}
}
}
Android - 再來看看前端Android的部分
package idv.william.example
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.messaging.FirebaseMessaging
import okhttp3.*
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import java.io.IOException
class MainActivity : AppCompatActivity() {
private lateinit var toolbar: Toolbar
private lateinit var usernameEditText: EditText
private lateinit var eMailEditText: EditText
private lateinit var phoneEditText: EditText
private lateinit var token: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initSetting()
FirebaseMessaging.getInstance().subscribeToTopic("news")
FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
if (!task.isSuccessful) return@OnCompleteListener
token = task.result
})
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.option_menu, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_item_register -> { registerUser(); true }
R.id.action_item_setting ->{ settingUser(); true }
else -> { super.onOptionsItemSelected(item) }
}
}
// 初始化設定
private fun initSetting() {
toolbar = this.findViewById(R.id.toolbar)
toolbar.title = "GoGo垃圾信"
usernameEditText = this.findViewById(R.id.username)
eMailEditText = this.findViewById(R.id.eMail)
phoneEditText = this.findViewById(R.id.phone)
setSupportActionBar(toolbar)
}
// 顯示提示Toast
private fun showToast(text: String) {
Log.d("[TOAST]", text)
Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
}
// 產生Request (POST)
private fun requestPostMaker(urlString: String, json: String): Request {
val body = json.toRequestBody()
this.showToast(urlString)
return Request.Builder().url(urlString).post(body).build()
}
// 產生Request (PATCH)
private fun requestPatchMaker(urlString: String, json: String): Request {
val body = json.toRequestBody()
return Request.Builder().url(urlString).patch(body).build()
}
// 註冊User
private fun registerUser() {
val map = mapOf(
"system" to 1,
"name" to usernameEditText.text.toString(),
"mail" to eMailEditText.text.toString(),
"phone" to phoneEditText.text.toString()
)
val urlString = "http://192.168.1.103:12345/user/"
val json = JSONObject(map).toString()
val request = this.requestPostMaker(urlString = urlString, json = json)
OkHttpClient().newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, error: IOException) { runOnUiThread { showToast(text = error.toString()) } }
override fun onResponse(call: Call, response: Response) { runOnUiThread { showToast(text = "成功") } }
})
}
// 更新Token
private fun settingUser() {
val map = mapOf(
"system" to 1,
"token" to token,
)
val urlString = "http://192.168.1.103:12345/user/" + usernameEditText.text.toString()
val json = JSONObject(map).toString()
val request = this.requestPatchMaker(urlString = urlString, json = json)
OkHttpClient().newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, error: IOException) { runOnUiThread { showToast(text = error.toString()) } }
override fun onResponse(call: Call, response: Response) { runOnUiThread { showToast(text = "成功") } }
})
}
}
package idv.william.example
import android.util.Log
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
class FCMMessageReceiverService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
super.onNewToken(token)
Log.d("[TOKEN]", token)
}
override fun onMessageReceived(message: RemoteMessage) {
super.onMessageReceived(message)
message.notification?.body?.let { Log.d("[TOKEN]", it) }
}
}
Vue - 再來看看後端Vue的部分
➊ Node.js + Yarn
nvm install 16.15
npm install yarn --g
node -p process.arch
yarn global add @vue/cli
➋ Vue Command-Line Interface
- 安裝Vue CLI
npm install @vue/cli -g
➌ 建立Vue專案
- 這裡我們使用VueCLI來建立一個叫go-mail-and-push的專案
- 按圖施工,保證成功
vue create go-mail-and-push
cd go-mail-and-push
yarn serve
➍ 安裝網路套件 - axios
yarn add axios // axios套件
yarn add @types/axios // axios套件ts翻譯檔
➎ 安裝元件套件 - element-plus
- 一直為UI長相苦手的我,還是乖乖裝裝element-plus這個套件吧,安裝過的套件,都會記錄在package.json這個檔上面…
yarn add element-plus // 基於 Vue 3,設計師和開發者的套件庫
➏ 簡單來測試一下吧
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus';
import locale from 'element-plus/lib/locale/lang/zh-tw'
import 'element-plus/theme-chalk/index.css'
createApp(App).use(ElementPlus, { locale }).mount('#app')
<!-- App.vue -->
<template>
<div class="app">
<el-header>GoGo垃圾信</el-header>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'App',
components: {
},
setup() {
return {}
}
});
</script>
<style>
#app {
text-align: center;
color: #c3114c;
margin-top: 60px;
}
</style>
➐ 連接Golang API
func routerSetting(database *gorm.DB) {
corsConfig := cors.DefaultConfig() // 防止CORS的設定
corsConfig.AllowAllOrigins = true // 防止CORS的設定
}
- 取得User列表 => http://localhost:12345/user
<template>
<div class="app">
<el-header>GoGo垃圾信</el-header>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import axios from 'axios'
export default defineComponent({
name: 'App',
components: {
},
setup() {
GolangAPI: {
userList: "http://localhost:12345/user",
}
}
const API = {
/// 取得使用者List
userList: async (url: string) => {
const response = await axios.get(url)
const { result, _ } = response.data
const users = result as any[]
return users
}
}
API.userList(Constant.GolangAPI.userList).then((_users) => {
console.table(_users)
})
return {}
}
});
</script>
<style>
#app {
text-align: center;
color: #c3114c;
margin-top: 60px;
}
</style>
➑ 有類型的JavaScript
- TypeScript的橫空出世,就是為了解決JavaScript寫法太過自由的問題,加上是弱類型的語言,有錯誤都會在執行後才會被發現…
- 另外就是IDE的自動提示的問題,因為TypeScript是有類型的,所以在提示function上就會抓得很精準,不能用的就不會出現…
- 產生有類型的Class跟Enum,這也是js的一個痛點…
// SendTypeEnum.ts
type SendTypeEnum = 'eMail' | 'Push' | 'SMS'
export default SendTypeEnum
// User.ts
interface User {
name: string,
mail: string,
system: number,
token: string,
}
export default User
➒ Vue2 Option API => Vue3 Composition API
- Vue 3的Composition API寫起來其實滿直覺的,最主要把一些設定通通放在setup()之內…
- 最主要的,只要是需要綁定的變數,通通要加上一層ref包裝一下…
- 這裡就借助el-table來幫我們跑迴圈…
<template>
<div class="app">
<el-header>GoGo垃圾信</el-header>
<!-- 資料 -->
<el-table :data="users">
<el-table-column prop="name" :label="userLabel.name" width="100"/>
<el-table-column prop="mail" :label="userLabel.mail" width="256"/>
<el-table-column prop="system" :label="userLabel.system" width="100"/>
<el-table-column prop="token" :label="userLabel.token"/>
<el-table-column fixed="right" :label="userLabel.operations" width="200">
<template #default>
<el-button color="#626aef" round @click="">垃圾信</el-button>
<el-button color="#F1F30A" round @click="">垃圾推播</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import axios from 'axios'
import User from "./models/User";
export default defineComponent({
name: 'App',
components: {
},
setup() {
const Constant = {
UserLabel: ref({
name: "姓名",
mail: "電子信箱",
system: "系統",
token: "推播",
operations: "功能",
title: "標題",
message: "內容"
}),
GolangAPI: {
userList: "http://localhost:12345/user",
}
}
const API = {
/// 取得使用者List
userList: async (url: string) => {
const response = await axios.get(url)
const { result, _ } = response.data
const users = result as any[]
return users
}
}
let users = ref<User[]>([])
API.userList(Constant.GolangAPI.userList).then((_users) => {
_users.forEach((user: any) => {
const _user = { name: user.name, mail: user.mail, system: user.system, token: user.token }
users.value.push(_user)
})
})
return { users, userLabel: Constant.UserLabel }
}
});
</script>
<style>
#app {
text-align: center;
color: #c3114c;
margin-top: 60px;
}
</style>
➓ GoGo垃圾信
<template>
<div class="app">
<el-header>GoGo垃圾信</el-header>
<!-- 資料 -->
<el-table :data="users">
<el-table-column prop="name" :label="userLabel.name" width="80"/>
<el-table-column prop="mail" :label="userLabel.mail" width="200"/>
<el-table-column prop="phone" :label="userLabel.phone" width="120"/>
<el-table-column prop="system" :label="userLabel.system" width="60"/>
<el-table-column prop="token" :label="userLabel.token"/>
<el-table-column fixed="right" :label="userLabel.operations" width="300">
<template #default="scope">
<el-button color="#626aef" round @click="handleVisibleDialog(scope.row, true, 'eMail')">垃圾信</el-button>
<el-button color="#F1F30A" round @click="handleVisibleDialog(scope.row, true, 'Push')">垃圾推播</el-button>
<el-button color="#77B068" round @click="handleVisibleDialog(scope.row, true, 'SMS')">垃圾簡訊</el-button>
</template>
</el-table-column>
</el-table>
<!-- 編譯框 -->
<el-dialog v-model="isVisibleDialog" :title="userLabel.dialogTitle" background="red">
<el-form-item :label="userLabel.title" label-width="320"><el-input v-model="temp.title" autocomplete="off" /></el-form-item>
<el-form-item :label="userLabel.message" label-width="320"><el-input v-model="temp.message" autocomplete="off" /></el-form-item>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleVisibleDialog(null, false, '')">Cancel</el-button>
<el-button type="primary" @click="handleAction(username)">Confirm</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import axios from 'axios'
import User from "./models/User";
import SendTypeEnum from "./models/SendTypeEnum";
export default defineComponent({
name: 'App',
components: {
},
setup() {
const Constant = {
UserLabel: ref({
name: "姓名",
mail: "電子信箱",
system: "系統",
phone: "手機號碼",
token: "推播",
operations: "功能",
title: "標題",
message: "內容",
dialogTitle: "發送垃圾信"
}),
GolangAPI: {
userList: "http://localhost:12345/user",
sendMail: "http://localhost:12345/mail",
pushNotification: "http://localhost:12345/push",
sendMessage: "http://localhost:12345/sms",
}
}
const API = {
/// 取得使用者List
userList: async (url: string) => {
const response = await axios.get(url)
const { result, _ } = response.data
const users = result as any[]
return users
},
/// 發發垃圾信
sendMail: async (name: string) => {
const url = `${Constant.GolangAPI.sendMail}/${name}`
const response = await axios.post(url, {
"title": tempFormInformation.value.title,
"message": tempFormInformation.value.message
})
const { result, _ } = response.data
return result
},
/// 發發垃圾推播
pushNotification: async (name: string) => {
const url = `${Constant.GolangAPI.pushNotification}/${name}`
const response = await axios.post(url, {
"title": tempFormInformation.value.title,
"message": tempFormInformation.value.message
})
const { result, _ } = response.data
return result
},
/// 發發垃圾簡訊
sendMessage: async (name: string) => {
const url = `${Constant.GolangAPI.sendMessage}/${name}`
const response = await axios.post(url, {
"title": tempFormInformation.value.title,
"message": tempFormInformation.value.message
})
const { result, _ } = response.data
return result
},
}
let users = ref<User[]>([])
let username = ref("")
let isVisibleDialog = ref(false)
let sendType = ref<SendTypeEnum>("eMail")
let tempFormInformation = ref({ title: "", message: "" })
/// 取得User列表
API.userList(Constant.GolangAPI.userList).then((_users) => {
_users.forEach((user: any) => {
const system = (user.system !== 0) ? 'Android' : 'iOS'
const _user = { name: user.name, mail: user.mail, phone: user.phone, system: system, token: user.token }
users.value.push(_user)
})
})
/// Dialog開關
const handleVisibleDialog = (user: User, isVisible: boolean, type: SendTypeEnum) => {
isVisibleDialog.value = isVisible
sendType.value = type
username.value = user.name
switch (type) {
case "eMail": Constant.UserLabel.value.dialogTitle = `🥳 發送垃圾信`; break
case "Push": Constant.UserLabel.value.dialogTitle = `😍 發送垃圾推播`; break
case "SMS": Constant.UserLabel.value.dialogTitle = `😀 發送垃圾簡訊`; break
default: break
}
tempFormInformation.value = { title: "", message: "" }
}
/// 發送垃圾信 / 發送垃圾推播
const handleAction = (name: string) => {
switch (sendType.value) {
case "eMail": API.sendMail(name); break
case "Push": API.pushNotification(name); break
case "SMS": API.sendMessage(name); break
default: break
}
isVisibleDialog.value = false
tempFormInformation.value = { title: "", message: "" }
}
return { users, username, userLabel: Constant.UserLabel, handleVisibleDialog, handleAction, temp: tempFormInformation, isVisibleDialog }
}
});
</script>
<style>
#app {
text-align: center;
color: #c3114c;
margin-top: 60px;
}
</style>
產生美美的API文件UI - Swagger
編譯SourceCode
- 首先下載swag的SourceCode,因為呢官方編的呢沒有M1的版本,所以…就自己編…
make build
放置編譯好的執行檔
go get -u github.com/swaggo/gin-swagger
go get -u github.com/swaggo/files
./swag
產生文件的JSON檔
- 這裡就是由swagger產生文件的動作,相關的格式請參考官方的文件…
./swag init
go run .
SwaggerUI
- 最後就是重複的產生文件,然後執行…
- http://localhost:12345/swagger/index.html
package main
import (
"william/docs"
swaggerfiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
)
// 註冊API
func registerWebAPI(router *gin.Engine, database *gorm.DB) {
swaggerApiDoc(router)
}
/// MARK: - WebAPI
// 產生DOC文件UI介面
func swaggerApiDoc(router *gin.Engine) {
docs.SwaggerInfo.BasePath = "/"
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
}
// @BasePath /
// @schemes http https
// @Router /user/{name} [get]
// @param name path string true "使用者名稱"
// @Tags 搜尋單一使用者
// @summary <GET>搜尋單一使用者 => http://localhost:12345/user/william
func selectUser(router *gin.Engine, database *gorm.DB) {
router.GET("/user/:name", func(context *gin.Context) {
name := context.Param("name")
user, error := User.Select(database, name)
if user.ID != 0 {
utility.ContextJSON(context, http.StatusOK, user, nil)
return
}
utility.ContextJSON(context, http.StatusOK, nil, error)
})
}
範例程式碼下載 - Golang / Vue / iOS / Android
後記
其實世界上真的沒有什麼東西是可以一步登天的吧?常常有人說我寫的東西都太簡單了,是我用詞太生活化了嗎?不夠專業?難怪我都交不到女朋友;也有人說我比較像PM,學得廣但不深,但容易跨部門溝通;我也相信人外有人,天外有天,每個人都有優於常人之處;在工作場合也是如此,每次大家說的都是同一件事,但因為學習的東西不同,造成『一個事情,各自表述』;不過我真的是很弱,要花雙倍的時間學東西,但至少還是有在進步的;我總是覺得:『唉呀,這Code沒什麼嘛,就這樣…那樣而已』,這種Code才是好的Code,您說呢?