赞
踩
日常工作中,经常会碰到一些需要处理的比较琐碎的事项,每次需要投入的绝对时间不多,但每周或者每月需要投入时间进行处理,且基本都是重复性的工作,作为一名混迹程序员圈子多年的码农,实在难以忍受。痛定思痛,决定运用平生所学,自力更生,自己搭建一个web系统,来解决当前遇到的问题。
说干就干,首先,先确定大方向,前端首先想到使用H5实现,接下来对比了常用框架Vue和React,说实在的,有点选择困难,最后,从实用高效的角度,咨询了一下从事H5开发的同事,他们当前使用的主力框架是Vue,那就没什么好纠结了,直接选择Vue,后面有什么问题,咨询请教也相对便捷;考虑到开发效率的问题,咨询H5开发同事,直接选用了vue-manage-system后台管理系统开发框架。至于后台,基于我多年的实践,以及网上研究对比,选择了go语言,也是基于开发效率的考虑,选择了beego作为后台开发框架,选择该框架的主要理由如下,比较知名,国人开发的,中文文档相对比较完善,学习成本相对较低。
下面将分别就vue开发环境的搭建使用、实践过程中遇到的坑以及最终打包发布等事项进行说明。
先从Nodejs下载地址(https://nodejs.org/en/download/)下载最新的LTS版本,我的开发PC系统是win10,下面将以win10系统做说明。先下载64位的msi安装包,如下面例子中的“node-v16.13.1-x64.msi”。然后以管理员身份运行cmd命令(Win + X, A),前面括号中内容是快捷键相关说明,先按wondows图标加上X键,再按A键,即可启动一个以管理员身份运行的cmd窗口。然后切换到前面所下载msi文件存放目录, 执行下面命令,即可完成安装。
msiexec /package node-v16.13.1-x64.msi
这里有一个情况需要特别说明的是,Nodejs安装的时候(我用的 node-v14.17.6-x64.msi 版本),其内部自带了一个python3.9的版本,且安装完成之后,默认就是用的这个版本,如果系统原本安装了其他版本,且有一些组件已经安装,则需要重新安装这些组件。
整体安装步骤可参考下面链接:
https://cn.vuejs.org/v2/guide/installation.html
https://www.cnblogs.com/sunny3158/p/14438325.html
安装@vue/cli包,详情可参见官方链接:https://cli.vuejs.org/zh/guide/installation.html
npm install -g @vue/cli
# OR
yarn global add @vue/cli
安装webpack,它是打包js的工具
npm install -g webpack
如果想纯粹研究Vue的使用,可以考虑使用Vue官方推荐的HBuilder X开发工具(https://www.dcloud.io/hbuilderx.html),该工具有图形化引导页面,可方便创建新项目进行研究。
先安装VSCode,再安装Vetur插件即可满足基本需求。
我们从gitlab上下载vue-manage-system项目,然后进行依赖安装,在VSCode中进行代码编辑,在控制台中根据需要运行命令开启服务,并在浏览器中开启页面查看效果。
git clone https://github.com/lin-xin/vue-manage-system.git // 把模板下载到本地
cd vue-manage-system // 进入模板目录
npm install // 安装项目依赖,等待安装完成之后,安装失败可用 cnpm 或 yarn
// 开启服务器,浏览器访问 http://localhost:8080
npm run serve
// 执行构建命令,生成的dist文件夹放在服务器下即可访问
npm run build
vue-manage-system项目内部使用的组件主要是Element,其具体使用方式请参考官方网站(https://element.eleme.cn/#/zh-CN),了解了使用规则之后,就可以根据个体需求进行相应调整了。
考虑到我们当前采用的架构是前后端分离的,跨域是一个无法回避的问题,对于web端,当前我们采取的是修改vue.config.js文件中的配置,具体样例如下:(更详细的说明可参考博文:Vue 本地跨域处理(包含cookie))
module.exports = { publicPath: './', assetsDir: 'static', productionSourceMap: false, devServer: { host: 'localhost', //target host port: 8080, proxy: { '/v1':{ target:'http://service-dev.what.com', changeOrigin:true, pathRewrite:{ '/v1':'/v1' } } }, disableHostCheck: true } }
前面“开发环境使用”那里已有说明如何用命令行打包,在此就不重复说明了,打包发布重点需要考虑三方面的问题,一是多环境支持,如何使用一个包同时支持开发、测试、生产或其他更多环境;二是如何管理版本号,方便将功能或问题表现和其对应代码相关联;三是如何部署。下面将分别就这三个问题进行说明;
多环境支持的主要思路是,为多个环境分别定义不同的H5访问域名和后台访问域名,且H5域名和后台域名一一对应,这样,获取到了当前域名,即可确定应该访问的后台域名,从而自动实行环境切换。具体代码调整见utils\request.js文件,样例如下,其中域名映射逻辑在remote.js中实现,大家可根据实际情况实现自己的域名映射逻辑。
import remote from './remote';
let remoteUrl = remote.getBaseURL();
const service = axios.create({
baseURL: remoteUrl,
withCredentials: true,
timeout: 5000
});
当前考虑配置一个单独的Version.js文件,打包时,在外部用脚本更新相应字段信息,仅供参考。
使用nginx进行部署,在nginx配置文件中新增一项配置如下,重启nginx使配置生效。如果是有真实的域名,记得先配置好域名解析。
server {
listen 80;
server_name client.what.com;
location / {
root /your/vue/directory/dist;
index index.html;
}
}
如果没有真实的域名,则需要在用户系统host文件中增加一条配置(假设nginx的ip地址是192.168.10.252):
192.168.10.252 client.what.com
下面将分别就beego开发环境的搭建使用、实践过程中遇到的坑以及最终打包发布等事项进行说明。
依据我前面实践,beego在win10下运行会遇到一些问题,所以我最终选择了centos 7.7作为开发用操作系统,接下来的所有说明都是以此为前提条件的。
先去官网https://golang.google.cn/下载最新的安装包(当前是go1.17.5.linux-amd64.tar.gz),然后将该安装包解压到/usr/local目录下,生成go目录/usr/local/go。可以以root或sudo的形式调用以下命令完成:
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.17.5.linux-amd64.tar.gz
将/usr/local/go/bin添加到系统PATH中。可以在$HOME/.profile 或者 /etc/profile (为所有用户)添加下面内容:
export PATH=$PATH:/usr/local/go/bin
最后可运行下面命令验证安装是否正常,可以正常展示go语言版本号即正常。
$ go version
官方文档参考:https://golang.google.cn/doc/install
beego安装,请直接参考官方链接https://beego.vip/quickstart,这里就不重复描述了。
先安装VSCode,再安装官方的Go插件即可满足基本需求。如果要进行远程开发(譬如在win10机器上远程连接到centos7.7进行开发),可参考如下链接配置:
https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack
另外,如果习惯了Eclipse的快捷键类型,可以考虑安装 Eclipse Keymap 插件,将VSCode的快捷键样式切换成Eclipse类型的。
bee 的 api 命令是新建一个 API 项目,我们在命令行下执行 bee api <项目名> 就可以创建一个新的项目。
bee api apiproject
create app folder: /gopath/src/apiproject
create conf: /gopath/src/apiproject/conf
create controllers: /gopath/src/apiproject/controllers
create models: /gopath/src/apiproject/models
create tests: /gopath/src/apiproject/tests
create conf app.conf: /gopath/src/apiproject/conf/app.conf
create controllers default.go: /gopath/src/apiproject/controllers/default.go
create tests default.go: /gopath/src/apiproject/tests/default_test.go
create models object.go: /gopath/src/apiproject/models/object.go
create main.go: /gopath/src/apiproject/main.go
但是注意该命令必须在 $GOPATH/src 下执行。最后会在 $GOPATH/src 相应目录下生成如下目录结构的项目:
apiproject ├── conf │ └── app.conf ├── controllers │ └── object.go │ └── user.go ├── docs │ └── doc.go ├── main.go ├── models │ └── object.go │ └── user.go ├── routers │ └── router.go └── tests └── default_test.go
我们在开发 Go 项目的时候最大的问题是经常需要自己手动去编译再运行,bee run 命令是监控 beego 的项目,通过 fsnotify监控文件系统。但是注意该命令必须在 $GOPATH/src/apiproject 下执行。
这样我们在开发过程中就可以实时的看到项目修改之后的效果:
bee run
13-11-25 09:53:04 [INFO] Uses 'apiproject' as 'apiproject'
13-11-25 09:53:04 [INFO] Initializing watcher...
13-11-25 09:53:04 [TRAC] Directory(/gopath/src/apiproject/controllers)
13-11-25 09:53:04 [TRAC] Directory(/gopath/src/apiproject/models)
13-11-25 09:53:04 [TRAC] Directory(/gopath/src/apiproject)
13-11-25 09:53:04 [INFO] Start building...
13-11-25 09:53:16 [SUCC] Build was successful
13-11-25 09:53:16 [INFO] Restarting apiproject ...
13-11-25 09:53:16 [INFO] ./apiproject is running...
我们打开浏览器就可以看到效果 http://localhost:8080/:
在VSCode上面打开/gopath/src/apiproject所在目录,打开文件进行编辑,保存好之后,进入VSCode上的控制台,执行bee run 命令,即可进行编译运行,从而可验证实际效果。
官网页面参考:https://beego.vip/docs/install/bee.md
数据库直接使用默认的mysql,为了简化mysql服务器的搭建工作,使用docker(对应官网地址https://docs.docker.com/get-started/)启动mysql官方提供的image(对应官方地址https://hub.docker.com/_/mysql),加上合适的配置,即可快速启动一个mysql服务。beego关联mysql,请直接参考官方文档https://beego.vip/docs/mvc/model/overview.md,这里就不再详细说明了。
如果需要直接查看mysql数据库数据,可使用工具HeidiSQL,官网地址:https://www.heidisql.com/。
beego ORM的使用请参考官方文档https://beego.vip/docs/mvc/model/orm.md,在此也不再详细说明了。
模块划分我的理解是以路由为引子,理解了路由的路径,也就理解了模块划分及其逻辑意义,官方文档可参考https://beego.vip/docs/mvc/controller/router.md。
在代码层面,如果要添加新的路由,先查看routers/router.go文件,参照原有样例代码,为新的controller添加相应路由信息,下面的样例,我为controllers/week.go文件中的WeekController
类型增加了"/week"的相对路由信息。
// @APIVersion 1.0.0 // @Title beego Test API // @Description beego has a very cool tools to autogenerate documents for your API // @Contact astaxie@gmail.com // @TermsOfServiceUrl http://beego.me/ // @License Apache 2.0 // @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html package routers import ( "manager/controllers" beego "github.com/beego/beego/v2/server/web" ) func init() { ns := beego.NewNamespace("/v1", beego.NSNamespace("/object", beego.NSInclude( &controllers.ObjectController{}, ), ), beego.NSNamespace("/user", beego.NSInclude( &controllers.UserController{}, ), ), beego.NSNamespace("/week", beego.NSInclude( &controllers.WeekController{}, ), ), ) beego.AddNamespace(ns) }
controllers/week.go文件代码样例如下:
package controllers import ( "fmt" "manager/models" "gitee.com/cfh008/runutils" ) // Operations about Users type WeekController struct { // beego.Controller BaseController } // @Title Current // @Description 获取当前填报周期日期 // @Success 200 // @router /current [post] func (u *WeekController) Current() { defer func() { if r := recover(); r != nil { panicInfo := fmt.Sprintf("%v panic info: %v", runutils.RunFuncName(), r) panic(panicInfo) } }() // reqBody := u.Data[REQUEST_BODY_KEY].(*RequestBody) resBody := u.Data[RESPONSE_BODY_KEY].(*ResponseBody) if u.IsLogin { resBody.Code = 0 resBody.Msg = "获取成功" resBody.Data = models.GetCurrentWeek() u.Data[SYS_JSON_KEY] = resBody } else { resBody.Code = ERROR_USER_NOT_LOGIN resBody.Msg = ERROR_INFO_MAP[resBody.Code] u.Data[SYS_JSON_KEY] = resBody } u.ServeJSON() }
上述代码样例中有“@router”的注解,在执行"bee run"命令时,会自动将注解解析并在routers/commentsRouter_controllers.go
文件中生成相应路由配置。另外,涉及到数据的部分,调用的是"manager/models"模块的方法,即涉及到和数据库打交道的部分,都统一封装在了models模块。
beego配置支持跨域代码样例如下:
package controllers import ( "manager/models" "github.com/beego/beego/v2/adapter" "github.com/beego/beego/v2/adapter/plugins/cors" beego "github.com/beego/beego/v2/server/web" ) type BaseController struct { beego.Controller User models.User // 登录的用户 IsLogin bool // 标识用户是否登陆 } func init() { // 配置CORS 跨域请求 adapter.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{ AllowOrigins: []string{"http://service.what.com", "*"}, AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, AllowHeaders: []string{"Origin", "Authorization", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"}, ExposeHeaders: []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"}, AllowCredentials: true, })) } func (ctl *BaseController) Prepare() { ctl.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", ctl.Ctx.Request.Header.Get("Origin")) ...... }
主体功能代码是参考 beego:跨域问题 博客实现的,但具体细节,有根据实际情况进行调整。
打包发布重点需要考虑三方面的问题,一是打包及多环境支持,如何使用一个包同时支持开发、测试、生产或其他更多环境;二是如何管理版本号,方便将功能或问题表现和其对应代码相关联;三是如何部署。下面将分别就这三个问题进行说明;
项目中有文件conf/app.conf,样例如下:
appname = apiproject runmode = dev # runmode = prod autorender = false copyrequestbody = true EnableDocs = true sqlconn = sessionon = true [prod] httpport = 8880 mysqluser = "root" mysqlpass = "yourpassword" mysqlurls = "192.168.10.250" mysqlport = "3306" mysqldb = "beego" [dev] httpport = 8881 mysqluser = "root" mysqlpass = "yourpassword" mysqlurls = "192.168.10.250" mysqlport = "3307" mysqldb = "beego" [test] httpport = 8882 mysqluser = "root" mysqlpass = "yourpassword" mysqlurls = "192.168.10.250" mysqlport = "3308" mysqldb = "beego"
使用代码读取配置信息样例如下:
package models import ( "fmt" "sync" "gitee.com/cfh008/ioutils" "github.com/beego/beego/v2/client/orm" "github.com/beego/beego/v2/core/logs" beego "github.com/beego/beego/v2/server/web" _ "github.com/go-sql-driver/mysql" ) var modelsOnce sync.Once func Init() { modelsOnce.Do(func() { // 默认为开发模式值,便于内部执行单元测试,需要和app.conf文件中的dev模块值保持一致 user := "root" pwd := "passwordForMysql" url := "192.168.10.250" port := "3307" dbName := "beego" var doErr error = nil // 只有存在配置文件时,才从配置文件中读取参数 if ioutils.Exists("conf/app.conf") { user, doErr = beego.AppConfig.String("mysqluser") if doErr != nil { logs.Error("call beego.AppConfig.String failed with %v", doErr) return } pwd, doErr = beego.AppConfig.String("mysqlpass") if doErr != nil { logs.Error("call beego.AppConfig.String failed with %v", doErr) return } url, doErr = beego.AppConfig.String("mysqlurls") if doErr != nil { logs.Error("call beego.AppConfig.String failed with %v", doErr) return } port, doErr = beego.AppConfig.String("mysqlport") if doErr != nil { logs.Error("call beego.AppConfig.String failed with %v", doErr) return } dbName, doErr = beego.AppConfig.String("mysqldb") if doErr != nil { logs.Error("call beego.AppConfig.String failed with %v", doErr) return } } dataSourceFormat := "%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&loc=Local" // 样例: "root:passwordForMysql@tcp(192.168.10.250:3307)/orm_test?charset=utf8mb4&loc=Local" dataSource := fmt.Sprintf(dataSourceFormat, user, pwd, url, port, dbName) // logs.Info("dataSource(%v)", dataSource) doErr = orm.RegisterDriver("mysql", orm.DRMySQL) if doErr != nil { logs.Error("call orm.RegisterDriver failed with %v", doErr) return } // 参数1 数据库的别名,用来在 ORM 中切换数据库使用 // 参数2 driverName // 参数3 对应的链接字符串 // 参数4(可选) 设置最大空闲连接 // 参数5(可选) 设置最大数据库连接 (go >= 1.2) // 使用 go-sql-driver 驱动时,请注意参数设置 // 从某一版本开始,驱动默认使用 UTC 时间,而非本地时间,所以请指定时区参数或者全部以 UTC 时间存取 // 例如:root:root@/orm_test?charset=utf8&loc=Asia%2FShanghai maxIdle := 30 maxConn := 30 doErr = orm.RegisterDataBase("default", "mysql", dataSource, orm.MaxIdleConnections(maxIdle), orm.MaxOpenConnections(maxConn)) if doErr != nil { logs.Error("call orm.RegisterDataBase failed with %v", doErr) return } doErr = orm.RunSyncdb("default", false, true) if doErr != nil { logs.Error("call orm.RunSyncdb failed with %v", doErr) return } }) }
上面样例中,一共有三个环境的配置,分别是prod、dev 和test,要打哪个环境的包,则先将最上面的runmode配置成相应的值(当前配置的是dev),然后在控制台调用如下命令:
bee pack
如果一切正常,则会在项目下面生成apiproject.tar.gz压缩包,里面包含了上面的配置文件,以及编译生成的可执行文件apiproject,实际运行时,可执行文件会从配置文件中读取相应配置信息,如果找不到该配置文件,runmode值默认是prod,所以,理论上该包是支持多环境的,只是解压完毕后,需要将配置文件中runmode值调整成相应环境的值,再运行可执行文件启动服务。
官方发布部署说明可参见:https://beego.vip/docs/deploy/
当前找到了一个觉得可以采用的方案,有待后续实践,具体链接如下:
golang程序添加版本号
实际验证发现,使用beego命令,不大好操作,当前考虑使用脚本在打包前更新文件版本信息,然后打包,打包完毕之后,再恢复文件或者提交到版本库,仅供参考。
先将前面的apiproject.tar.gz解压到系统某个目录,如/opt/apiproject
,然后切换到该目录下调用下面命令启动服务:
nohup ./apiproject &
假设上述机器的IP是"192.168.10.251",我们部署配置的端口是8880。
然后使用nginx进行重定向,在nginx配置文件中新增一项配置如下,重启nginx使配置生效。如果是有真实的域名,记得先配置好域名解析。
server {
listen 80;
server_name service.what.com;
location / {
proxy_pass http://192.168.10.251:8880;
}
}
如果没有真实的域名,则需要在用户系统host文件中增加一条配置(假设nginx的ip地址是192.168.10.252):
192.168.10.252 service.what.com
特别说明: 实际部署时,web端和后台分别是部署在同一域名下的不同二级域名下的,所以不存在跨域的问题,在内部开发或测试环境,没有采用在同一域名不同二级域名下的部署形式,则需要进行跨域配置,确保功能可正常运行。
当前整体状态是,可以进行开发部署,但部署操作,还存在不少需要人工介入的重复操作,后续需要考虑的方向主要有两个,一是打包部署,统一集成到jenkins这类CI/CD工具上;二是最终部署形式,不论是web端,还是后台,最好采取docker image的形式发布,使得发布标准化。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。