goravel 学习笔记
大约 5 分钟
dockerfile
FROM golang:alpine AS builder
ENV GO111MODULE=on \
CGO_ENABLED=0 \
GOARCH="amd64" \
GOOS=linux
WORKDIR /build
COPY . .
ENV GOPROXY=https://goproxy.cn,direct
RUN go mod tidy
RUN go build --ldflags "-extldflags -static" -o main .
FROM alpine:latest
WORKDIR /www
# 安装 tzdata 包,该包包含时区数据
RUN apk add --no-cache tzdata
# 设置时区为 Asia/Shanghai
ENV TZ=Asia/Shanghai
# 创建时区文件软链接
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY /build/main /www/
COPY /build/database/ /www/database/
COPY /build/public/ /www/public/
COPY /build/storage/ /www/storage/
COPY /build/resources/ /www/resources/
#COPY --from=builder /build/.env /www/.env
COPY /build/web/dist /www/web/dist
ENTRYPOINT ["/www/main"]
前端资源
facades.Route().Static("storage", "./storage") // 图片访问
facades.Route().Static("assets", "./web/dist/assets")
facades.Route().Static("images", "./web/dist/images")
facades.Route().Static("vite.svg", "./web/dist/vite.svg")
扩展包
go list -m -versions github.com/orangbus/spider
go list -m -versions github.com/orangbus/elastic
go list -m -versions github.com/orangbus/axios
go list -m -versions github.com/orangbus/rabbitmq
别名
alias gg='go run . artisan'
alias ggm='gg migrate'
alias ggm='gg make:model'
alias ggc='gg make:controller'
alias gg-sd="gg db:seed"
alias gg-m="gg db:migrate"
初始化表
go run . artisan make:migration create_admins_table
创建模型
go run . artisan make:model admins
生成表结构
go run . artisan make:migrate
go run . artisan db:seed
控制器
go run . artisan make:controller admin/admin_index/admin_index
go run . artisan make:controller api/api_index/api_index
中间件
go run . artisan make:middleware admin/auth
package admin
import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
)
func Auth() http.Middleware {
return func(ctx http.Context) {
token := ctx.Request().Header("Authorization")
path := ctx.Request().Path()
if path == "/admin/websocket/msg" {
token = ctx.Request().Input("token")
}
_, err := facades.Auth(ctx).Guard("admin").Parse(token)
if err != nil {
ctx.Request().AbortWithStatusJson(419, map[string]interface{}{
"code": 419,
"msg": "请重新登陆",
})
}
ctx.Request().Next()
}
}
go run . artisan make:middleware admin/auth
package user
import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
)
func Auth() http.Middleware {
return func(ctx http.Context) {
token := ctx.Request().Header("Authorization")
_, err := facades.Auth(ctx).Parse(token)
if err != nil {
ctx.Request().AbortWithStatusJson(419, map[string]interface{}{
"code": 419,
"msg": "请重新登陆",
})
}
ctx.Request().Next()
}
}
json字段处理
package models
import (
"database/sql/driver"
"encoding/json"
"github.com/goravel/framework/database/orm"
)
type Articles struct {
orm.Model
Uid uint `json:"uid"`
Status int `json:"status" form:"status"`
Type int `json:"type" form:"type"`
CateId int `json:"cate_id" form:"cate_id"`
Title string `json:"title" form:"title"`
Poster string `json:"poster" form:"poster"`
Author string `json:"author" form:"author"`
Slogan string `json:"slogan" form:"slogan"`
Content string `json:"content" form:"content"`
Draft string `json:"draft" form:"draft"`
CapContent JSON `json:"cap_content" form:"cap_content"`
Images JSON `json:"images" form:"images"`
Videos JSON `json:"videos" form:"videos"`
Audios JSON `json:"audios" form:"audios"`
}
// JSON 自定义JSON类型
type JSON []byte
// MarshalJSON 实现json.Marshaler接口
func (j JSON) MarshalJSON() ([]byte, error) {
if len(j) == 0 {
return []byte("[]"), nil
}
return j, nil
}
// UnmarshalJSON 实现json.Unmarshaler接口
func (j *JSON) UnmarshalJSON(data []byte) error {
*j = append([]byte(nil), data...)
return nil
}
// Scan 实现sql.Scanner接口,用于从数据库读取数据
func (j *JSON) Scan(value interface{}) error {
if value == nil {
*j = nil
return nil
}
var bytes []byte
switch v := value.(type) {
case []byte:
bytes = v
case string:
bytes = []byte(v)
default:
return json.Unmarshal([]byte{}, j)
}
*j = append([]byte(nil), bytes...)
return nil
}
// Value 实现driver.Valuer接口,用于将数据写入数据库
func (j JSON) Value() (driver.Value, error) {
if j == nil {
return nil, nil
}
return string(j), nil
}
开发一个扩展包
gg make:package elastic
将包赋值出来完成功能的开发,创建一个github仓库
go mod init github.com/orangbus/elastic
提交代码
git init
git add .
git push master
发布版本号(注意:版本格式需要是 x.x.x 否则获取扩展包的时候获取不到指定的版本)
git tag -a <tagname> -m '描述信息' // git tag -a v1.0.0
git push origin v1.0.0
查看扩展包的版本列表
go list -m -versions github.com/orangbus/elastic
快捷操作
@user
var $user$ models.$model$
if err := facades.Auth(ctx).User(&$user$); err != nil {
return resp.Error(ctx, err)
}
enum("user","admin")
@login
var $user$ models.$model$
token, err := facades.Auth(ctx).Guard("$user$").User(&user)
if err != nil {
return resp.Error(ctx,err)
}
enum("user","admin")
@logout
if err := facades.Auth(ctx).Logout();err != nil {
return resp.Error(ctx,err)
}
@list-search
func (r *$controller$) List(ctx http.Context) http.Response {
$name$ := ctx.Request().Input("$name$")
db := facades.Orm().Query()
if $name$ != "" {
db = db.Where("$name$", $name$)
}
var list []models.$models$
var total int64
page, limit := utils.GetLimit(ctx)
if err := db.OrderBy("id","desc").Paginate(page, limit, &list, &total); err != nil {
return resp.Error(ctx, err)
}
return resp.List(ctx, list, total)
}
enum("name","status","type","created_at","date_bt")
@list
func (r *$controller$) List(ctx http.Context) http.Response {
var list []models.$models$
var total int64
page, limit := utils.GetLimit(ctx)
if err := facades.Orm().Query().OrderBy("id").Paginate(page, limit, &list, &total); err != nil {
return resp.Error(ctx, err)
}
return resp.List(ctx, list, total)
}
@store
// "github.com/mitchellh/mapstructure"
func (r *$controller$) Store(ctx http.Context) http.Response {
param := models.$model${}
if err := ctx.Request().Bind(¶m); err != nil {
return resp.Error(ctx, err)
}
id := ctx.Request().InputInt("id")
if id > 0 {
var article models.Articles
if err := facades.Orm().Query().Where("id", id).First(&$model$); err != nil {
return resp.Error(ctx, err)
}
if err := mapstructure.Decode(param, &$model$); err != nil {
return resp.Error(ctx, err)
}
if err := facades.Orm().Query().Save(&$model$); err != nil {
return resp.Error(ctx, err)
}
} else {
if err := facades.Orm().Query().Create(¶m); err != nil {
return resp.Error(ctx, err)
}
}
return resp.Success(ctx, "保存成功!")
}
@updateOrcreate
func (r *$controller$) Store(ctx http.Context) http.Response {
param := models.$model${}
if err := ctx.Request().Bind(¶m); err != nil {
return resp.Error(ctx, err)
}
id := ctx.Request().InputInt("id")
param.ID = cast.ToUint(id)
if err := facades.Orm().Query().UpdateOrCreate(&models.$model${}, map[string]any{"id": id}, param); err != nil {
return resp.Error(ctx, err)
}
return resp.Success(ctx, "保存成功!")
}
enum("user","admin","movie","website","movie","article")
@geLimit
var total int64
page, limit := utils.GetLimit(ctx)
@getLImit-methods
func GetLimit(ctx http.Context, limit ...int) (int, int) {
defaultLimit := 10
if len(limit) > 0 {
defaultLimit = limit[0]
}
page := ctx.Request().QueryInt("page", 1)
req_limit := ctx.Request().QueryInt("limit", 10)
if req_limit > 100 {
defaultLimit = 100
}
return page, defaultLimit
}
@delete
func (r *$controller$) Delete(ctx http.Context) http.Response {
id := ctx.Request().Input("id")
var ids []any
if strings.Contains(id, ",") {
for _, v := range strings.Split(id, ",") {
ids = append(ids, cast.ToInt(v))
}
} else {
ids = append(ids, cast.ToInt(id))
}
if _, err := facades.Orm().Query().WhereIn("id", ids).Delete(&models.$model$); err != nil {
return resp.Error(ctx, err)
}
return resp.Success(ctx, "删除成功!")
}
enum("user","admin","cate","article","download","movie")
@clear
func (r *MovieHistory) Clear(ctx http.Context) http.Response {
var histories models.Histories
sql := fmt.Sprintf("TRUNCATE TABLE %s", histories.TableName())
if _, err := facades.Orm().Query().Exec(sql); err != nil {
return resp.Error(ctx, err)
}
return resp.Success(ctx, "删除成功!")
}
@route
$name$Controller := $controller_package$
router.Prefix("$group_name$").Group(func(router route.Router) {
router.Get("list", $name$Controller.List)
router.Post("store", $name$Controller.Store)
router.Post("delete", $name$Controller.Delete)
})
enum("amdin","api","user","cate","minio","website","article","movie","login")
@validate 手动验证
validate, err := facades.Validation().Make(ctx.Request().All(),
map[string]string{
"name": "required",
"url": "required",
},
validation.Messages(map[string]string{
"name.required": "名称不能为空",
"url.required": "地址不能为空",
}))
if err != nil {
return resp.Error(ctx, err)
}
if validate.Fails() {
return resp.Fail(ctx, validate.Errors().One())
}
param := models.$model_name${}
if err := validate.Bind(¶m); err != nil {
return resp.Error(ctx, err)
}
validator, err := facades.Validation().Make(ctx.Request().All(), map[string]string{
"name": "required",
"email": "required|email",
"password": "required|min_len:6",
}, validation.Messages(map[string]string{
"name.required": "用户名不能为空",
"email.required": "邮箱不能为空",
"password.required": "密码不能为空",
"password.min_len": "密码长度不不少于6位",
}))
if err != nil {
return resp.Error(ctx, err)
}
if validator.Fails() {
return resp.Fail(ctx, validator.Errors().One())
}
@validate-rule 验证规则
enum("required","int","string","max","min","max_len","min_len","email","array","file","image","date","alpha","alpha_num","json")
@first
if err := facades.Orm().Query().where("id",id).First(&$model$);err != nil{
return resp.Error(ctx,err)
}
@update
if _,err := facades.Orm().Query().Model(&$model$).where("id",id).update("$value$",$value$);err != nil{
return resp.Error(ctx,err)
}
@res
return resp.$method$(ctx, "$msg$")
enum("Success","Error","Fail","List","Data")
enum("保存成功",list, total)
@res-success
return resp.Success(ctx, "$msg$")
enum("保存成功","删除成功","登录成功")
@respfail
return resp.Fail(ctx, "$msg$")
enum("保存成功","删除成功","登录成功")
@res-error
return resp.Error(ctx, err)
@res-list
return resp.List(ctx, list, total)
@err
if err != nil{
return $return$
}
enum("err","resp.Error(ctx, err)","resp.Fail(ctx, $msg$)")
$$ 275914.1×(1+30.5%) n)
450000 $$