Beego新手项目-短链接编码到部署
--练手实操--
新建git项目
新建beego项目
bee new shorturl_on_beego
预先构想
描述
实现将长链接转换为短链接的功能
- 使用MySQL记录数据
功能划分
- 接口1 长链接转短链接
- 接口2 短链接反查长链接
- 功能3 访问短链接,跳转至长链接
代码实现
引入数据库
- 定义数据库配置文件
; conf/database.conf
dbhost=127.0.0.1
dbuser=root
dbpassword=rootroot
dbport=3306
db=shorturl_on_beego
app.conf中进行引入
appname = shorturl_on_beego
httpport = 8081
runmode = dev
appurl = http://localhost:8081
include "database.conf"
main.go
中注册数据库
package main
import (
"fmt"
"github.com/astaxie/beego/orm"
beego "github.com/beego/beego/v2/server/web"
_ "github.com/go-sql-driver/mysql"
_ "shorturl_on_beego/models"
_ "shorturl_on_beego/routers"
)
func init() {
dbuser, _ := beego.AppConfig.String("dbuser")
dbpassword, _ := beego.AppConfig.String("dbpassword")
dbhost, _ := beego.AppConfig.String("dbhost")
dbport, _ := beego.AppConfig.String("dbport")
db, _ := beego.AppConfig.String("db")
// root:root@tcp(127.0.0.1:3306)/orm_test?charset=utf8
datasource := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&loc=Local", dbuser, dbpassword, dbhost, dbport, db)
// 先注册数据库驱动
orm.RegisterDriver("mysql", orm.DRMySQL)
// 注册数据库
orm.RegisterDataBase("default", "mysql", datasource)
fmt.Println("连接数据库成功")
name := "default"
force := true
err := orm.RunSyncdb(name, force, true)
orm.Debug = true
if err != nil {
panic(err)
}
}
func main() {
beego.Run()
}
定义models
// models/urlRecord.go
package models
import (
"github.com/astaxie/beego/orm"
"time"
)
type UrlRecord struct {
Id uint64 `json:"id"`
Key string `orm:"size(20);unique;description(短链后的key)" json:"key"`
OriginalUrl string `orm:"size(512);unique;description(原长链接)" json:"original_url"`
CreatedAt time.Time `orm:"auto_now_add,type(datetime)" json:"created_at"`
UpdatedAt time.Time `orm:"auto_now,type(datetime)" json:"updated_at"`
}
func (m *UrlRecord) TableName() string {
return "url_records"
}
func init() {
// 注册model
orm.RegisterModel(new(UrlRecord))
}
定义 controller
- 定义 base.go,统一处理json返回
// controllers/base.go
package controllers
import (
beego "github.com/beego/beego/v2/server/web"
"strconv"
)
type BaseController struct {
beego.Controller
}
type ReturnMessage struct {
StatusCode int `json:"status_code"`
Message string `json:"message"`
Data map[string]interface{} `json:"data"`
}
func (c *BaseController) SuccessResponse(retData map[string]interface{}, otherParams ...string) {
state := 200
message := "操作成功"
paramsLen := len(otherParams)
if paramsLen > 0 {
var err error
state, err = strconv.Atoi(otherParams[0])
if err != nil {
state = 200
}
}
if paramsLen > 1 {
message = otherParams[1]
}
c.Data["json"] = c.GetRetMessages(retData, state, message)
c.ServeJSON()
c.StopRun()
}
func (c *BaseController) FailResponse(message string, failCode ...int) {
state := 400
if len(failCode) > 0 {
state = failCode[0]
}
c.Data["json"] = c.GetRetMessages(nil, state, message)
c.ServeJSON()
c.StopRun()
}
func (c *BaseController) GetRetMessages(retData map[string]interface{}, state int, message string) ReturnMessage {
return ReturnMessage{
state, message, retData,
}
}
- 定义 url.go 业务逻辑处理
// controllers/url.go
package controllers
import (
"bytes"
"fmt"
"github.com/astaxie/beego/orm"
_ "github.com/beego/beego/v2/client/cache"
beego "github.com/beego/beego/v2/server/web"
"math/rand"
"shorturl_on_beego/models"
"strings"
"time"
)
type UrlController struct {
BaseController
}
const (
SHORTEN_KEY_LENGTH = 6
)
/*
转成短链接
*/
func (c *UrlController) GetShorten() {
url := c.GetString("url")
// 获取url,判断是否是合法的链接,仅判断startsWith http:// or https://
url = strings.TrimSpace(url)
appUrl, _ := beego.AppConfig.String("appurl")
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
c.FailResponse("非法url")
}
/*
re := md5.Sum([]byte("123456"))
fmt.Printf("%x\n", re) // e10adc3949ba59abbe56e057f20f883e
h := md5.New()
h.Write([]byte("123456"))
re1 := h.Sum(nil)
fmt.Printf("%x\n", re1)
*/
// 查询数据库,最新一条记录
// 数据库操作
var urlRecord models.UrlRecord
o := orm.NewOrm()
qs := o.QueryTable(new(models.UrlRecord))
key := CreateRandomString(SHORTEN_KEY_LENGTH)
err := qs.Filter("original_url", url).One(&urlRecord)
// 找到记录
if err == nil {
c.SuccessResponse(map[string]interface{}{
"url_record": urlRecord,
"shorten_url": appUrl + c.URLFor("UrlController.GetJump", ":key", urlRecord.Key),
"now": time.Now().Format("2006-01-02 15:04:05"),
"from": "db",
})
}
for {
count, _ := qs.Filter("key", key).Count()
if count < 1 {
break
} else {
key = CreateRandomString(SHORTEN_KEY_LENGTH)
}
}
urlRecord = models.UrlRecord{
Key: key,
OriginalUrl: url,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
id, err := o.Insert(&urlRecord)
if err != nil {
c.FailResponse("转链失败,请稍后重试")
}
fmt.Println(id, err, urlRecord)
c.SuccessResponse(map[string]interface{}{
"url_record": urlRecord,
"shorten_url": appUrl + c.URLFor("UrlController.GetJump", ":key", urlRecord.Key),
"now": time.Now().Format("2006-01-02 15:04:05"),
"from": "db_new",
})
}
func (c *UrlController) GetExpand() {
url := c.GetString("url")
url = strings.TrimSpace(url)
// 非本域短链,返回错误
appUrl, _ := beego.AppConfig.String("appurl")
jumpPrefix := appUrl + c.URLFor("UrlController.GetJump") + "/"
if !strings.HasPrefix(url, jumpPrefix) {
c.FailResponse("非法Url")
}
key := url[len(jumpPrefix) : len(jumpPrefix)+SHORTEN_KEY_LENGTH]
o := orm.NewOrm()
qs := o.QueryTable(new(models.UrlRecord))
urlRecord := models.UrlRecord{}
err := qs.Filter("key", key).One(&urlRecord)
if err == orm.ErrNoRows {
// 没有找到记录
c.FailResponse("找不到该短链记录")
}
// 通过 url 提取key
c.SuccessResponse(map[string]interface{}{
"url_record": urlRecord,
"now": time.Now().Format("2006-01-02 15:04:05"),
})
}
func (c *UrlController) GetJump() {
key := c.GetString(":key")
o := orm.NewOrm()
qs := o.QueryTable(new(models.UrlRecord))
urlRecord := models.UrlRecord{}
err := qs.Filter("key", key).One(&urlRecord)
if err != nil {
c.FailResponse("暂无短链数据")
}
c.Redirect(urlRecord.OriginalUrl, 307)
/*
c.SuccessResponse(map[string]interface{}{
"url_record": urlRecord,
"now": time.Now().Format("2006-01-02 15:04:05"),
})
*/
}
func CreateRandomString(len int) string {
var container string
var str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
b := bytes.NewBufferString(str)
length := b.Len()
rand.Seed(time.Now().UnixNano())
for i := 0; i < len; i++ {
random := rand.Intn(length)
container += string(str[random])
}
return container
}
定义路由
// routers/router.go
package routers
import (
beego "github.com/beego/beego/v2/server/web"
"shorturl_on_beego/controllers"
)
func init() {
beego.Router("/", &controllers.MainController{})
beego.Router("/shorten", &controllers.UrlController{}, "get:GetShorten")
beego.Router("/expand", &controllers.UrlController{}, "get:GetExpand")
beego.Router("/j/?:key", &controllers.UrlController{}, "get:GetJump")
}
至此,已可成功完成所需功能
http://localhost:8081/shorten?url=
// 将url转成短链
http://localhost:8081/expand?url=
// 根据短链反查原url链接
http://localhost:8081/j/9Bwq5k
// 访问短链跳转至原始链接
TODO,优化一版加入Redis缓存
定义redis配置
- 定义redis配置内容
; conf/redis.conf
redis.key=collectionName
redis.conn=127.0.0.1:6379
redis.dbnum=1
redis.password=
- app.conf 中引入 redis.conf
include "redis.conf"
新增redis操作struct
// services/redis.go
package services
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/astaxie/beego/orm"
"github.com/beego/beego/v2/client/cache"
"github.com/beego/beego/v2/core/logs"
beego "github.com/beego/beego/v2/server/web"
"time"
)
var (
bm cache.Cache
)
type Redis struct {
}
func init() {
//{"key":"collectionName","conn":":6039","dbNum":"0","password":"thePassWord"}
key, _ := beego.AppConfig.String("redis.key")
conn, _ := beego.AppConfig.String("redis.conn")
dbNum, _ := beego.AppConfig.String("redis.dbnum")
password, _ := beego.AppConfig.String("redis.password")
config := orm.Params{
"key": key,
"conn": conn,
"dbNum": dbNum,
"password": password,
}
configStr, _ := json.Marshal(config)
var err error = nil
bm, err = cache.NewCache("redis", string(configStr))
if err != nil {
logs.Error(err)
}
fmt.Println("连接Redis成功")
}
// 复写一遍,省略 context.Context
func (r *Redis) Get(key string, obj interface{}) error {
v, err := bm.Get(context.Background(), key)
if err != nil {
logs.Error(err)
return err
}
if v == nil {
return errors.New("key not found")
}
err = json.Unmarshal(v.([]byte), obj)
if err != nil {
return err
}
return nil
}
func (r *Redis) Put(key string, val interface{}, timeout time.Duration) error {
v, err := json.Marshal(val)
if err != nil {
return err
}
err = bm.Put(context.Background(), key, v, timeout)
if err != nil {
return err
}
return nil
}
func (r *Redis) Delete(key string) error {
err := bm.Delete(context.Background(), key)
return err
}
// Increment a cached int value by key, as a counter.
func (r *Redis) Incr(key string) error {
return bm.Incr(context.Background(), key)
}
// Decrement a cached int value by key, as a counter.
func (r *Redis) Decr(key string) error {
return bm.Decr(context.Background(), key)
}
func (r *Redis) IsExist(key string) (bool, error) {
return bm.IsExist(context.Background(), key)
}
func (r *Redis) ClearAll(key string) error {
return bm.ClearAll(context.Background())
}
func (r *Redis) StartAndGC(config string) error {
return bm.StartAndGC(config)
}
定义 controller 进行业务处理
// controllers/cachedUrl.go
package controllers
import (
"crypto/md5"
"fmt"
"github.com/astaxie/beego/orm"
_ "github.com/beego/beego/v2/client/cache"
beego "github.com/beego/beego/v2/server/web"
"shorturl_on_beego/models"
"shorturl_on_beego/services"
_ "shorturl_on_beego/services"
"strings"
"time"
)
type CachedUrlController struct {
BaseController
}
const (
CACHED_TTL = 1800 * time.Second
)
/*
转成短链接
*/
func (c *CachedUrlController) GetShorten() {
/*
// Redis 操作
m1 := AA{
Age: 1,
B: 3.1415926,
Str: "Hello, world!",
}
m1Json, _ := json.Marshal(m1)
redisop.BM.Put(context.Background(), "astaxie", m1Json, 1000*time.Second)
v, _ := redisop.BM.Get(context.Background(), "astaxie")
aaa := AA{}
fmt.Println(string(v.([]byte)))
err111 := json.Unmarshal(v.([]byte), &aaa)
fmt.Println("---", err111)
fmt.Println("aaa: ", aaa)
fmt.Println(aaa.Age, aaa.B, aaa.Str)
*/
/*
// 操作redis
redis := new(services.Redis)
m1 := AA{
Age: 1,
B: 3.1415926,
Str: "Hello, world!",
}
err1 := redis.Put("astaxie", m1, 1000*time.Second)
if err1 != nil {
fmt.Println(err1)
}
m2 := AA{}
err1 = redis.Get("astaxie", &m2)
if err1 != nil {
fmt.Println(err1)
}
fmt.Println(m2.Age, m2.Str, m2.B)
*/
url := c.GetString("url")
// 获取url,判断是否是合法的链接,仅判断startsWith http:// or https://
url = strings.TrimSpace(url)
appUrl, _ := beego.AppConfig.String("appurl")
if (!strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://")) || url == "" {
c.FailResponse("非法url")
}
/*
re := md5.Sum([]byte("123456"))
fmt.Printf("%x\n", re) // e10adc3949ba59abbe56e057f20f883e
h := md5.New()
h.Write([]byte("123456"))
re1 := h.Sum(nil)
fmt.Printf("%x\n", re1)
*/
// 查询数据库,最新一条记录
// 数据库操作
var urlRecord models.UrlRecord
redis := new(services.Redis)
urlRedisKey := fmt.Sprintf("%x", md5.Sum([]byte(url)))
isExists, _ := redis.IsExist(urlRedisKey)
if isExists {
// 直接获取,然后返回
cacheErr := redis.Get(urlRedisKey, &urlRecord)
if cacheErr == nil {
c.SuccessResponse(map[string]interface{}{
"url_record": urlRecord,
"shorten_url": appUrl + c.URLFor("CachedUrlController.GetJump", ":key", urlRecord.Key),
"now": time.Now().Format("2006-01-02 15:04:05"),
"from": "redis",
})
}
}
o := orm.NewOrm()
qs := o.QueryTable(new(models.UrlRecord))
key := CreateRandomString(SHORTEN_KEY_LENGTH)
err := qs.Filter("original_url", url).One(&urlRecord)
// 找到记录
if err == nil {
// do cache
_ = redis.Put(urlRedisKey, urlRecord, CACHED_TTL)
_ = redis.Put(key, urlRecord, CACHED_TTL)
c.SuccessResponse(map[string]interface{}{
"url_record": urlRecord,
"shorten_url": appUrl + c.URLFor("CachedUrlController.GetJump", ":key", urlRecord.Key),
"now": time.Now().Format("2006-01-02 15:04:05"),
"from": "db",
})
}
for {
count, _ := qs.Filter("key", key).Count()
if count < 1 {
break
} else {
key = CreateRandomString(SHORTEN_KEY_LENGTH)
}
}
urlRecord = models.UrlRecord{
Key: key,
OriginalUrl: url,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
id, err := o.Insert(&urlRecord)
if err != nil {
c.FailResponse("转链失败,请稍后重试")
}
fmt.Println(id, err, urlRecord)
// do cache
_ = redis.Put(urlRedisKey, urlRecord, CACHED_TTL)
_ = redis.Put(key, urlRecord, CACHED_TTL)
c.SuccessResponse(map[string]interface{}{
"url_record": urlRecord,
"shorten_url": appUrl + c.URLFor("CachedUrlController.GetJump", ":key", urlRecord.Key),
"now": time.Now().Format("2006-01-02 15:04:05"),
"from": "db_new",
})
//c.FailResponse("操作失败")
}
func (c *CachedUrlController) GetExpand() {
url := c.GetString("url")
url = strings.TrimSpace(url)
// 非本域短链,返回错误
appUrl, _ := beego.AppConfig.String("appurl")
jumpPrefix := appUrl + c.URLFor("CachedUrlController.GetJump") + "/"
if !strings.HasPrefix(url, jumpPrefix) {
c.FailResponse("非法Url")
}
key := url[len(jumpPrefix) : len(jumpPrefix)+SHORTEN_KEY_LENGTH]
urlRecord := models.UrlRecord{}
// 通过redis反查
redis := new(services.Redis)
isExists, redisErr := redis.IsExist(key)
if isExists {
redisErr = redis.Get(key, &urlRecord)
if redisErr == nil {
// 直接返回
c.SuccessResponse(map[string]interface{}{
"url_record": urlRecord,
"now": time.Now().Format("2006-01-02 15:04:05"),
"from": "redis",
})
}
}
o := orm.NewOrm()
qs := o.QueryTable(new(models.UrlRecord))
err := qs.Filter("key", key).One(&urlRecord)
if err == orm.ErrNoRows {
// 没有找到记录
c.FailResponse("找不到该短链记录")
}
// 存入缓存
redisErr = redis.Put(urlRecord.Key, urlRecord, CACHED_TTL)
urlRedisKey := fmt.Sprintf("%x", md5.Sum([]byte(urlRecord.OriginalUrl)))
fmt.Println(urlRedisKey)
redisErr = redis.Put(urlRedisKey, urlRecord, CACHED_TTL)
// 通过 url 提取key
c.SuccessResponse(map[string]interface{}{
"url_record": urlRecord,
"now": time.Now().Format("2006-01-02 15:04:05"),
"from": "db",
})
}
func (c *CachedUrlController) GetJump() {
key := c.GetString(":key")
if key == "" {
c.FailResponse("暂无短链信息!")
}
fmt.Println(key)
o := orm.NewOrm()
qs := o.QueryTable(new(models.UrlRecord))
urlRecord := models.UrlRecord{}
// 查询cache
redis := new(services.Redis)
isExist, redisErr := redis.IsExist(key)
fmt.Println(isExist, redisErr)
if isExist {
redisErr = redis.Get(key, &urlRecord)
if redisErr == nil {
fmt.Println("via cache")
c.Redirect(urlRecord.OriginalUrl, 302)
// 不加return,会往下执行
return
}
}
err := qs.Filter("key", key).One(&urlRecord)
if err != nil {
c.FailResponse("暂无短链数据")
}
_ = redis.Put(key, urlRecord, CACHED_TTL)
urlRedisKey := fmt.Sprintf("%x", md5.Sum([]byte(urlRecord.OriginalUrl)))
_ = redis.Put(urlRedisKey, urlRecord, CACHED_TTL)
fmt.Println("via db")
c.Redirect(urlRecord.OriginalUrl, 302)
c.StopRun()
}
定义路由
// routers/router.go
beego.Router("/c/shorten", &controllers.CachedUrlController{}, "get:GetShorten")
beego.Router("/c/expand", &controllers.CachedUrlController{}, "get:GetExpand")
beego.Router("/c/j/?:key", &controllers.CachedUrlController{}, "get:GetJump")
至此,已添加了redis缓存热数据
http://localhost:8081/c/shorten?url=
// 将url转成短链
http://localhost:8081/c/expand?url=
// 根据短链反查原url链接
http://localhost:8081/c/j/9Bwq5k
// 访问短链跳转至原始链接
部署至线上服务器
打包
bee pack -be GOOS=linux
(打包到linux上部署命令)
bee pack -be GOOS=window
(打包到windows上部署命令)
上传文件至服务器
-
将打包好的压缩包上传至服务器
scp /Users/au/go/src/shorturl_on_beego/shorturl_on_beego.tar.gz user@ip:/data/wwwroot/shorturl_on_beego
-
解压压缩包,修改配置
解压压缩包到目录的./dist
文件夹下
cd /data/wwwroot/shorturl_on_beego && mkdir dist && tar -zxvf shorturl_on_beego.tar.gz -C ./dist/
按需修改conf/app.conf
、conf/database.conf
、conf/redis.conf
的配置项;可修改一份放置在/data/wwwroot/shorturl_on_beego
下,后续直接复制至dist/conf
中
ps: 修改 runmode = prod,修改databse.conf
中线上服务器的配置 -
通过 nohup 启动
cd /data/wwwroot/shorturl_on_beego/dist && nohup ./shorturl_on_beego >> /home/ubuntu/shorturl_on_beego.log &
// nohup 启动;ps 需要先cd到目录里面,/data/wwwroot/shorturl_on_beego/dist/shorturl_on_beego 启动,由于没设置viewspath 会导致默认路径有误
ps aux | grep shorturl_on_beego
// 查看pid
kill -9 pid
// 杀死进程
ip+端口形式访问
可通过以下链接访问
http://146.56.250.101:8081/shorten?url=https://www.baidu.com/
http://146.56.250.101:8081/expand?url=
http://146.56.250.101:8081/j/cXSumC
http://146.56.250.101:8081/c/shorten?url=https://www.baidu.com/
http://146.56.250.101:8081/c/expand?url=
http://146.56.250.101:8081/c/j/cXSumC
---
## nginx部署 #### nginx配置 ```` # /usr/local/nginx/conf/vhost/dev.aqiuliuxin614.com.conf server { listen 80; server_name dev.aqiuliuxin614.com; #index index.html index.htm; #root /data/wwwroot/shorturl_on_beego/dist;
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
expires 30d;
access_log off;
root /data/wwwroot/shorturl_on_beego/dist/static;
try_files $uri @backend;
}
location ~ .*\.(js|css)?$ {
expires 7d;
access_log off;
root /data/wwwroot/shorturl_on_beego/dist/static;
try_files $uri @backend;
}
location ~ /(\.user\.ini|\.ht|\.git|\.svn|\.project|LICENSE|README\.md) {
deny all;
}
location / {
try_files /_not_exists_ @backend;
}
location @backend {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8081;
}
}
#### 域名形式访问
`http://dev.aqiuliuxin614.com/shorten?url=https://www.baidu.com/`
`http://dev.aqiuliuxin614.com/expand?url=`
`http://dev.aqiuliuxin614.com/j/cXSumC`
`http://dev.aqiuliuxin614.com/c/shorten?url=https://www.baidu.com/`
`http://dev.aqiuliuxin614.com/c/expand?url=`
`http://dev.aqiuliuxin614.com/c/j/cXSumC`
<br>
## 热更新
#### 修改app.conf
`graceful = true`
#### 重启服务
`ps aux | grep shorturl_on_beego`
`kill -HUP 进程ID`
#### 测试
ps: 访问 `http://146.56.250.101:8081/suspend` 时,延时返回消息,表现为在浏览器一直loading,15秒后,返回首页内容
`GetSuspend` 方法设置了延时返回;
##### 测试预期
1. 运行`kill`命令后,"/suspend" 不可中断;
1. 运行`kill`命令后,"/suspend" 的Data的为原启动时的配置内容;
1. 运行`kill`命令后,"/" 马上返回新启动的配置项
##### 测试过程
1. 访问 "/", "/suspend", 页面中 Website 值为配置内的值
2. 重新访问 "/suspend", 页面loading时,同时监控 `.log` 文件 `tail -f shorten_on_beego.log -n 30`
3. 修改 app.conf 的appname,`ps aux | grep shorten_on_beego` , `kill -HUP 进程id`, 发送信号杀进程;
4. 重新访问 "/", Website的值为新 app.conf 的值,原loading的"/suspend"的页面中Website值为修改前的值
// controllers/base.go
package controllers
import (
"fmt"
beego "github.com/beego/beego/v2/server/web"
"time"
)
type MainController struct {
beego.Controller
}
func (c *MainController) Get() {
c.Data["Website"], _ = beego.AppConfig.String("appname")
c.Data["Email"] = "astaxie@gmail.com"
c.TplName = "index.tpl"
}
func (c *MainController) GetSuspend() {
for i := 0; i < 15; i++ {
time.Sleep(time.Second)
fmt.Println(time.Now().Format("2006-01-02 15:04:05"), i)
}
c.Data["Website"], _ = beego.AppConfig.String("appname")
c.Data["Email"] = "astaxie@gmail.com"
c.TplName = "index.tpl"
}
## 部署脚本
!/bin/bash
/data/wwwroot/shorturl_on_beego/restart.sh
tar -zxf shorturl_on_beego.tar.gz -C /data/wwwroot/shorturl_on_beego/dist/
echo "tar -zxf Success.."
cp app.conf dist/conf/app.conf && cp database.conf dist/conf/database.conf
echo ".conf files Copied.."
appname="shorturl_on_beego"
pid=pidof "${appname}"
if [ ! -n "$pid" ]; then
echo "Begoo Application is not running!"
cd /data/wwwroot/shorturl_on_beego/dist && nohup ./shorturl_on_beego >> /home/ubuntu/shorturl_on_beego.log &
echo "Started!!"
else
echo "Begoo Application is running, pid=${pid}"
echo "Send Kill HUP"
kill -HUP ${pid}
sleep 1
pid=pidof "${appname}"
echo "Restarted!!"
echo "new pid=${pid}"
fi