commit
0f55b05ef0
@ -0,0 +1,9 @@
|
||||
.idea
|
||||
go.sum
|
||||
*.jpeg
|
||||
*.png
|
||||
log.txt
|
||||
logs
|
||||
*.log
|
||||
uploads
|
||||
*.exe
|
||||
@ -0,0 +1,25 @@
|
||||
################################################################################
|
||||
## MAIN STAGE ##
|
||||
################################################################################
|
||||
# Copy the manager into the distroless image.
|
||||
#FROM scratch
|
||||
#FROM mirror.ccs.tencentyun.com/library/alpine:3.13
|
||||
FROM alpine:3.15.0
|
||||
#FROM hub.sre.ink/base/alpine:3.15.0
|
||||
#FROM centos:7.9.2009
|
||||
LABEL Description="niupic uploader"
|
||||
MAINTAINER sre <sre@yangqiao.org>
|
||||
#RUN echo 'https://mirrors.cloud.tencent.com/alpine/v3.13/main' > /etc/apk/repositories \
|
||||
# && echo 'https://mirrors.cloud.tencent.com/alpine/v3.13/community' >>/etc/apk/repositories \
|
||||
# && apk update && apk add tzdata && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
||||
# && echo "Asia/Shanghai" > /etc/timezone
|
||||
RUN apk update && apk add tzdata && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
||||
&& echo "Asia/Shanghai" > /etc/timezone
|
||||
|
||||
WORKDIR /app
|
||||
ADD niupic.bin /app/niupic.bin
|
||||
COPY static /app/static
|
||||
|
||||
#USER nonroot:nonroot
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/app/niupic.bin"]
|
||||
@ -0,0 +1,5 @@
|
||||
all: build-linux-arm64
|
||||
|
||||
build-linux-arm64:
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GO111MODULE=on go mod tidy
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GO111MODULE=on go build -v -a -o niupic.bin main.go
|
||||
@ -0,0 +1,64 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"log"
|
||||
"niupicUpload/service"
|
||||
"niupicUpload/util"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
*
|
||||
@author: sre
|
||||
@date: 2022/8/19 0019
|
||||
@desc: ImageController
|
||||
*
|
||||
*/
|
||||
type ImageController struct{}
|
||||
|
||||
func NewImageController() ImageController {
|
||||
return ImageController{}
|
||||
}
|
||||
|
||||
// UploadNiupic 上传Niupic
|
||||
func (a *ImageController) UploadNiupic(c *gin.Context) {
|
||||
resultRes := util.NewResult(c)
|
||||
f, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
c.JSON(200, gin.H{
|
||||
"code": 400,
|
||||
"msg": "上传失败!",
|
||||
})
|
||||
return
|
||||
} else {
|
||||
//文件类型
|
||||
fileExt := strings.ToLower(path.Ext(f.Filename))
|
||||
fileName := util.Md5Encode(fmt.Sprintf("%s%s", f.Filename, time.Now().String()))
|
||||
fildDir := fmt.Sprintf("%s%d%s_", "upload_tmp_", time.Now().Year(), time.Now().Month().String())
|
||||
subfilepath := fmt.Sprintf("%s%s%s", fildDir, fileName, fileExt)
|
||||
|
||||
err := c.SaveUploadedFile(f, subfilepath)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
resultRes.Error(1, "图片保存失败")
|
||||
} else {
|
||||
url, err := service.UploadNiupic(subfilepath)
|
||||
if err != nil {
|
||||
resultRes.Error(1, "图片上传失败")
|
||||
}
|
||||
os.Remove(subfilepath)
|
||||
c.JSON(200, gin.H{
|
||||
"code": 200,
|
||||
"msg": "ok",
|
||||
"result": url,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
module niupicUpload
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/gin-gonic/gin v1.8.1 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.10.0 // indirect
|
||||
github.com/goccy/go-json v0.9.7 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.7 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"log"
|
||||
"net/http"
|
||||
"niupicUpload/routers"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
*
|
||||
@author: sre
|
||||
@date: 2022/8/19 0019
|
||||
@desc: upload pic to niupic
|
||||
*
|
||||
*/
|
||||
|
||||
var (
|
||||
g errgroup.Group
|
||||
)
|
||||
|
||||
func main() {
|
||||
//设置运行模式 #debug,release,test
|
||||
gin.SetMode("debug")
|
||||
r := routers.Router()
|
||||
server := &http.Server{
|
||||
Addr: ":8080",
|
||||
Handler: r,
|
||||
ReadTimeout: 30 * time.Second,
|
||||
WriteTimeout: 30 * time.Second,
|
||||
MaxHeaderBytes: 1 << 20,
|
||||
}
|
||||
g.Go(func() error {
|
||||
return server.ListenAndServe()
|
||||
})
|
||||
if err := g.Wait(); err != nil {
|
||||
log.Println("启动失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
## build arm64 on oracle k8s
|
||||
```bash
|
||||
cd /root
|
||||
rm -rf niupicUpload
|
||||
git clone https://git.sre.ink/go/niupicUpload.git
|
||||
cd niupicUpload
|
||||
make build-linux-arm64
|
||||
docker build -t sre/niupicupload:arm64 .
|
||||
kubectl -n sre rollout restart deployment niupicupload
|
||||
```
|
||||
|
||||
## usage
|
||||
```bash
|
||||
http://127.0.0.1:8080/upload.html
|
||||
```
|
||||
@ -0,0 +1,30 @@
|
||||
package routers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"niupicUpload/routers/upload"
|
||||
)
|
||||
|
||||
/*
|
||||
*
|
||||
@author: sre
|
||||
@date: 2022/8/19 0019
|
||||
@desc: routers
|
||||
*
|
||||
*/
|
||||
func Router() *gin.Engine {
|
||||
router := gin.Default()
|
||||
//静态资源
|
||||
router = StaticRouter(router)
|
||||
//upload
|
||||
router = upload.Upload(router)
|
||||
return router
|
||||
}
|
||||
func StaticRouter(r *gin.Engine) *gin.Engine {
|
||||
//static 加载静态资源,一般是上传的资源,例如用户上传的图片
|
||||
r.StaticFS("/", http.Dir("static"))
|
||||
//r.StaticFile("/favicon.ico", "static/favicon.ico")
|
||||
return r
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package upload
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"niupicUpload/controller"
|
||||
)
|
||||
|
||||
/*
|
||||
*
|
||||
@author: sre
|
||||
@date: 2022/8/19 0019
|
||||
@desc: todo
|
||||
*
|
||||
*/
|
||||
func Upload(r *gin.Engine) *gin.Engine {
|
||||
//UploadOne
|
||||
imagec := controller.NewImageController()
|
||||
r.POST("/api/upload", imagec.UploadNiupic)
|
||||
return r
|
||||
}
|
||||
@ -0,0 +1,164 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
/*
|
||||
*
|
||||
@author: sre
|
||||
@date: 2022/8/19 0019
|
||||
@desc: todo
|
||||
*
|
||||
*/
|
||||
|
||||
type niupicRes struct {
|
||||
Status string `json:"status"`
|
||||
Code int `json:"code"`
|
||||
Data string `json:"data"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
func UploadNiupic(filepath string) (string, error) {
|
||||
body, err := upload(filepath)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return "", err
|
||||
}
|
||||
var result niupicRes
|
||||
_ = json.Unmarshal(body, &result)
|
||||
return result.Data, nil
|
||||
}
|
||||
func upload(filePath string) ([]byte, error) {
|
||||
|
||||
url := "https://www.niupic.com/api/upload"
|
||||
method := "POST"
|
||||
|
||||
payload := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(payload)
|
||||
file, errFile1 := os.Open(filePath)
|
||||
defer file.Close()
|
||||
part1,
|
||||
errFile1 := writer.CreateFormFile("file", filepath.Base(filePath))
|
||||
_, errFile1 = io.Copy(part1, file)
|
||||
if errFile1 != nil {
|
||||
fmt.Println(errFile1)
|
||||
return nil, errFile1
|
||||
}
|
||||
err := writer.Close()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest(method, url, payload)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Add("authority", "www.niupic.com")
|
||||
req.Header.Add("accept", "application/json")
|
||||
req.Header.Add("accept-language", "zh-CN,zh;q=0.9")
|
||||
req.Header.Add("cache-control", "no-cache")
|
||||
req.Header.Add("content-type", "multipart/form-data; boundary=----WebKitFormBoundaryaMYCTFSFkhzG1SCm")
|
||||
req.Header.Add("cookie", "ua_lang=zh-cn; PHPSESSID=e5a6d75fd9cc2f05ab0bfc22808f34fc; PHPSESSID=e5a6d75fd9cc2f05ab0bfc22808f34fc; ua_lang=zh-cn")
|
||||
req.Header.Add("dnt", "1")
|
||||
req.Header.Add("origin", "https://www.niupic.com")
|
||||
req.Header.Add("referer", "https://www.niupic.com/")
|
||||
req.Header.Add("sec-ch-ua", "\"Chromium\";v=\"104\", \" Not A;Brand\";v=\"99\", \"Google Chrome\";v=\"104\"")
|
||||
req.Header.Add("sec-ch-ua-mobile", "?0")
|
||||
req.Header.Add("sec-ch-ua-platform", "\"Windows\"")
|
||||
req.Header.Add("sec-fetch-dest", "empty")
|
||||
req.Header.Add("sec-fetch-mode", "cors")
|
||||
req.Header.Add("sec-fetch-site", "same-origin")
|
||||
req.Header.Add("'user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36")
|
||||
req.Header.Add("x-requested-with", "XMLHttpRequest")
|
||||
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func uploadFromFile(filePath string) ([]byte, error) {
|
||||
|
||||
url := "https://www.niupic.com/api/upload"
|
||||
method := "POST"
|
||||
|
||||
payload := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(payload)
|
||||
file, errFile1 := os.Open(filePath)
|
||||
defer file.Close()
|
||||
part1,
|
||||
errFile1 := writer.CreateFormFile("file", filepath.Base(filePath))
|
||||
_, errFile1 = io.Copy(part1, file)
|
||||
if errFile1 != nil {
|
||||
fmt.Println(errFile1)
|
||||
return nil, errFile1
|
||||
}
|
||||
err := writer.Close()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest(method, url, payload)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Add("authority", "www.niupic.com")
|
||||
req.Header.Add("accept", "application/json")
|
||||
req.Header.Add("accept-language", "zh-CN,zh;q=0.9")
|
||||
req.Header.Add("cache-control", "no-cache")
|
||||
req.Header.Add("content-type", "multipart/form-data; boundary=----WebKitFormBoundaryaMYCTFSFkhzG1SCm")
|
||||
req.Header.Add("cookie", "ua_lang=zh-cn; PHPSESSID=e5a6d75fd9cc2f05ab0bfc22808f34fc; PHPSESSID=e5a6d75fd9cc2f05ab0bfc22808f34fc; ua_lang=zh-cn")
|
||||
req.Header.Add("dnt", "1")
|
||||
req.Header.Add("origin", "https://www.niupic.com")
|
||||
req.Header.Add("referer", "https://www.niupic.com/")
|
||||
req.Header.Add("sec-ch-ua", "\"Chromium\";v=\"104\", \" Not A;Brand\";v=\"99\", \"Google Chrome\";v=\"104\"")
|
||||
req.Header.Add("sec-ch-ua-mobile", "?0")
|
||||
req.Header.Add("sec-ch-ua-platform", "\"Windows\"")
|
||||
req.Header.Add("sec-fetch-dest", "empty")
|
||||
req.Header.Add("sec-fetch-mode", "cors")
|
||||
req.Header.Add("sec-fetch-site", "same-origin")
|
||||
req.Header.Add("'user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36")
|
||||
req.Header.Add("x-requested-with", "XMLHttpRequest")
|
||||
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<title>上传文件示例</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/api/upload" method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="f1s">
|
||||
<input type="file" name="f1s">
|
||||
<input type="submit" value="上传">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>hello world</title>
|
||||
</head>
|
||||
<body>
|
||||
hello world!
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<title>上传文件示例</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/api/upload" method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="file">
|
||||
<input type="submit" value="上传">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,45 @@
|
||||
package util
|
||||
|
||||
/**
|
||||
@author: sre
|
||||
@date: 2022/8/19 0019
|
||||
@desc: todo
|
||||
**/
|
||||
|
||||
import "strconv"
|
||||
|
||||
type StrTo string
|
||||
|
||||
func (s StrTo) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func (s StrTo) Int() (int, error) {
|
||||
v, err := strconv.Atoi(s.String())
|
||||
return v, err
|
||||
}
|
||||
|
||||
func (s StrTo) MustInt() int {
|
||||
v, _ := s.Int()
|
||||
return v
|
||||
}
|
||||
|
||||
func (s StrTo) UInt32() (uint32, error) {
|
||||
v, err := strconv.Atoi(s.String())
|
||||
return uint32(v), err
|
||||
}
|
||||
|
||||
func (s StrTo) UInt64() (uint64, error) {
|
||||
v, err := strconv.Atoi(s.String())
|
||||
return uint64(v), err
|
||||
}
|
||||
|
||||
func (s StrTo) MustUInt32() uint32 {
|
||||
v, _ := s.UInt32()
|
||||
return v
|
||||
}
|
||||
|
||||
func (s StrTo) MustUInt64() uint64 {
|
||||
v, _ := s.UInt64()
|
||||
return v
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
/*
|
||||
*
|
||||
@author: sre
|
||||
@date: 2022/8/19 0019
|
||||
@desc: todo
|
||||
*
|
||||
*/
|
||||
func Md5Encode(data string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(data))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package util
|
||||
|
||||
/**
|
||||
@author: sre
|
||||
@date: 2022/8/19 0019
|
||||
@desc: todo
|
||||
**/
|
||||
|
||||
type ArticleRequest struct {
|
||||
ID uint64 `form:"id" binding:"required,gte=1"`
|
||||
//State uint8 `form:"state,default=1" binding:"oneof=0 1"`
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
val "github.com/go-playground/validator/v10"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/**
|
||||
@author: sre
|
||||
@date: 2022/8/19 0019
|
||||
@desc: todo
|
||||
**/
|
||||
|
||||
type ValidError struct {
|
||||
Key string
|
||||
Message string
|
||||
}
|
||||
|
||||
type ValidErrors []*ValidError
|
||||
|
||||
func (v *ValidError) Error() string {
|
||||
return v.Message
|
||||
}
|
||||
|
||||
func (v ValidErrors) Error() string {
|
||||
return strings.Join(v.Errors(), ",")
|
||||
}
|
||||
|
||||
func (v ValidErrors) Errors() []string {
|
||||
var errs []string
|
||||
for _, err := range v {
|
||||
errs = append(errs, err.Error())
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// 判断变量是否符合要求
|
||||
func BindAndValid(c *gin.Context, v any) (bool, ValidErrors) {
|
||||
var errs ValidErrors
|
||||
err := c.ShouldBind(v)
|
||||
if err != nil {
|
||||
v := c.Value("trans")
|
||||
trans, _ := v.(ut.Translator)
|
||||
verrs, ok := err.(val.ValidationErrors)
|
||||
if !ok {
|
||||
errs = append(errs, &ValidError{
|
||||
Key: "field",
|
||||
Message: err.Error(),
|
||||
})
|
||||
return false, errs
|
||||
}
|
||||
for key, value := range verrs.Translate(trans) {
|
||||
errs = append(errs, &ValidError{
|
||||
Key: key,
|
||||
Message: value,
|
||||
})
|
||||
}
|
||||
|
||||
return false, errs
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
/**
|
||||
@author: sre
|
||||
@date: 2022/8/19 0019
|
||||
@desc: todo
|
||||
**/
|
||||
|
||||
type Result struct {
|
||||
Ctx *gin.Context
|
||||
}
|
||||
|
||||
func NewResult(ctx *gin.Context) *Result {
|
||||
return &Result{Ctx: ctx}
|
||||
}
|
||||
|
||||
// ResultCont 返回的结果:
|
||||
type ResultCont struct {
|
||||
Code int `json:"code"` //提示代码
|
||||
Msg string `json:"msg"` //提示信息
|
||||
Data any `json:"data"` //出错
|
||||
}
|
||||
|
||||
// 通用错误处理
|
||||
func (r *Result) Error(code int, msg string) {
|
||||
res := ResultCont{}
|
||||
res.Code = code
|
||||
res.Msg = msg
|
||||
res.Data = gin.H{}
|
||||
if gin.Mode() == gin.ReleaseMode {
|
||||
res.Msg = "系统繁忙,请稍后再试"
|
||||
}
|
||||
r.Ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
// Success 成功
|
||||
func (r *Result) Success(data any) {
|
||||
if data == nil {
|
||||
data = gin.H{}
|
||||
}
|
||||
res := ResultCont{}
|
||||
res.Code = 0
|
||||
res.Msg = ""
|
||||
res.Data = data
|
||||
r.Ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
Loading…
Reference in new issue