feat(1.0): 新增上传图片
This commit is contained in:
parent
ae0aa4f617
commit
4f582eb802
51
docs/docs.go
51
docs/docs.go
@ -260,6 +260,44 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/admin/upload/image": {
|
||||||
|
"post": {
|
||||||
|
"description": "上传图片",
|
||||||
|
"consumes": [
|
||||||
|
"multipart/form-data"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"通用"
|
||||||
|
],
|
||||||
|
"summary": "上传图片",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"description": "选择文件",
|
||||||
|
"name": "file",
|
||||||
|
"in": "formData",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/upload.uploadImageResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
@ -446,6 +484,19 @@ const docTemplate = `{
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"upload.uploadImageResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"preview_image_url": {
|
||||||
|
"description": "可预览图片地址",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"real_image_url": {
|
||||||
|
"description": "真实图片地址",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securityDefinitions": {
|
"securityDefinitions": {
|
||||||
|
|||||||
@ -252,6 +252,44 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/admin/upload/image": {
|
||||||
|
"post": {
|
||||||
|
"description": "上传图片",
|
||||||
|
"consumes": [
|
||||||
|
"multipart/form-data"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"通用"
|
||||||
|
],
|
||||||
|
"summary": "上传图片",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"description": "选择文件",
|
||||||
|
"name": "file",
|
||||||
|
"in": "formData",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/upload.uploadImageResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/code.Failure"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
@ -438,6 +476,19 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"upload.uploadImageResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"preview_image_url": {
|
||||||
|
"description": "可预览图片地址",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"real_image_url": {
|
||||||
|
"description": "真实图片地址",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securityDefinitions": {
|
"securityDefinitions": {
|
||||||
|
|||||||
@ -129,6 +129,15 @@ definitions:
|
|||||||
description: 描述信息
|
description: 描述信息
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
upload.uploadImageResponse:
|
||||||
|
properties:
|
||||||
|
preview_image_url:
|
||||||
|
description: 可预览图片地址
|
||||||
|
type: string
|
||||||
|
real_image_url:
|
||||||
|
description: 真实图片地址
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
info:
|
info:
|
||||||
contact: {}
|
contact: {}
|
||||||
title: mini-chat 接口文档
|
title: mini-chat 接口文档
|
||||||
@ -291,6 +300,31 @@ paths:
|
|||||||
summary: 管理员登录
|
summary: 管理员登录
|
||||||
tags:
|
tags:
|
||||||
- 管理端.登录
|
- 管理端.登录
|
||||||
|
/admin/upload/image:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- multipart/form-data
|
||||||
|
description: 上传图片
|
||||||
|
parameters:
|
||||||
|
- description: 选择文件
|
||||||
|
in: formData
|
||||||
|
name: file
|
||||||
|
required: true
|
||||||
|
type: file
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/upload.uploadImageResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/code.Failure'
|
||||||
|
summary: 上传图片
|
||||||
|
tags:
|
||||||
|
- 通用
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
LoginVerifyToken:
|
LoginVerifyToken:
|
||||||
in: header
|
in: header
|
||||||
|
|||||||
21
internal/api/upload/upload.go
Normal file
21
internal/api/upload/upload.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package upload
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mini-chat/internal/pkg/logger"
|
||||||
|
"mini-chat/internal/repository/mysql"
|
||||||
|
"mini-chat/internal/repository/mysql/dao"
|
||||||
|
)
|
||||||
|
|
||||||
|
type handler struct {
|
||||||
|
logger logger.CustomLogger
|
||||||
|
writeDB *dao.Query
|
||||||
|
readDB *dao.Query
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(logger logger.CustomLogger, db mysql.Repo) *handler {
|
||||||
|
return &handler{
|
||||||
|
logger: logger,
|
||||||
|
writeDB: dao.Use(db.GetDbW()),
|
||||||
|
readDB: dao.Use(db.GetDbR()),
|
||||||
|
}
|
||||||
|
}
|
||||||
90
internal/api/upload/upload_image.go
Executable file
90
internal/api/upload/upload_image.go
Executable file
@ -0,0 +1,90 @@
|
|||||||
|
package upload
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"mini-chat/configs"
|
||||||
|
"mini-chat/internal/code"
|
||||||
|
"mini-chat/internal/pkg/core"
|
||||||
|
"mini-chat/internal/pkg/idgen"
|
||||||
|
)
|
||||||
|
|
||||||
|
type uploadImageResponse struct {
|
||||||
|
RealImageUrl string `json:"real_image_url"` // 真实图片地址
|
||||||
|
PreviewImageUrl string `json:"preview_image_url"` // 可预览图片地址
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadImage 上传图片
|
||||||
|
// @Summary 上传图片
|
||||||
|
// @Description 上传图片
|
||||||
|
// @Tags 通用
|
||||||
|
// @Accept multipart/form-data
|
||||||
|
// @Produce json
|
||||||
|
// @Param file formData file true "选择文件"
|
||||||
|
// @Success 200 {object} uploadImageResponse
|
||||||
|
// @Failure 400 {object} code.Failure
|
||||||
|
// @Router /admin/upload/image [post]
|
||||||
|
func (h *handler) UploadImage() core.HandlerFunc {
|
||||||
|
return func(ctx core.Context) {
|
||||||
|
file, err := ctx.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
ctx.AbortWithError(core.Error(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.UploadError,
|
||||||
|
fmt.Sprintf("%s: %s", code.Text(code.UploadError), err.Error()),
|
||||||
|
))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if file == nil {
|
||||||
|
ctx.AbortWithError(core.Error(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.UploadError,
|
||||||
|
fmt.Sprintf("%s: %s", code.Text(code.UploadError), "缺少 file 文件"),
|
||||||
|
))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验文件后缀
|
||||||
|
extension := ""
|
||||||
|
if dot := strings.LastIndexByte(file.Filename, '.'); dot != -1 {
|
||||||
|
extension = file.Filename[dot+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
allowedExtensions := map[string]bool{
|
||||||
|
"jpg": true,
|
||||||
|
"jpeg": true,
|
||||||
|
"png": true,
|
||||||
|
"gif": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !allowedExtensions[strings.ToLower(extension)] {
|
||||||
|
ctx.AbortWithError(core.Error(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.UploadError,
|
||||||
|
fmt.Sprintf("%s: %s", code.Text(code.UploadError), "文件后缀应为 .jpg、.jpeg、.png、.gif"),
|
||||||
|
))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存文件
|
||||||
|
imagePath := fmt.Sprintf("image/%s.%s", idgen.GenerateUniqueID(), strings.ToLower(extension))
|
||||||
|
filePath := fmt.Sprintf("%s/%s", configs.GetResourcesFilePath(), imagePath)
|
||||||
|
if err := ctx.SaveUploadedFile(file, filePath); err != nil {
|
||||||
|
ctx.AbortWithError(core.Error(
|
||||||
|
http.StatusBadRequest,
|
||||||
|
code.UploadError,
|
||||||
|
fmt.Sprintf("%s: %s", code.Text(code.UploadError), err.Error()),
|
||||||
|
))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res := new(uploadImageResponse)
|
||||||
|
res.RealImageUrl = filePath
|
||||||
|
res.PreviewImageUrl = fmt.Sprintf("resources/%s", imagePath)
|
||||||
|
|
||||||
|
ctx.Payload(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,6 +19,7 @@ const (
|
|||||||
ServerError = 10101
|
ServerError = 10101
|
||||||
ParamBindError = 10102
|
ParamBindError = 10102
|
||||||
JWTAuthVerifyError = 10103
|
JWTAuthVerifyError = 10103
|
||||||
|
UploadError = 10104
|
||||||
|
|
||||||
AdminLoginError = 20101
|
AdminLoginError = 20101
|
||||||
CreateAppError = 20201
|
CreateAppError = 20201
|
||||||
|
|||||||
@ -4,6 +4,7 @@ var zhCNText = map[int]string{
|
|||||||
ServerError: "内部服务器错误",
|
ServerError: "内部服务器错误",
|
||||||
ParamBindError: "参数错误",
|
ParamBindError: "参数错误",
|
||||||
JWTAuthVerifyError: "JWT 授权验证错误",
|
JWTAuthVerifyError: "JWT 授权验证错误",
|
||||||
|
UploadError: "上传失败",
|
||||||
|
|
||||||
AdminLoginError: "登录失败",
|
AdminLoginError: "登录失败",
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package core
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"mini-chat/internal/pkg/cors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
@ -11,7 +12,6 @@ import (
|
|||||||
"mini-chat/configs"
|
"mini-chat/configs"
|
||||||
_ "mini-chat/docs"
|
_ "mini-chat/docs"
|
||||||
"mini-chat/internal/code"
|
"mini-chat/internal/code"
|
||||||
"mini-chat/internal/pkg/cors"
|
|
||||||
"mini-chat/internal/pkg/env"
|
"mini-chat/internal/pkg/env"
|
||||||
"mini-chat/internal/pkg/errors"
|
"mini-chat/internal/pkg/errors"
|
||||||
"mini-chat/internal/pkg/logger"
|
"mini-chat/internal/pkg/logger"
|
||||||
@ -231,6 +231,7 @@ func New(logger logger.CustomLogger, options ...Option) (Mux, error) {
|
|||||||
// 启动信息
|
// 启动信息
|
||||||
startup.PrintInfo()
|
startup.PrintInfo()
|
||||||
|
|
||||||
|
mux.engine.Use(cors.New())
|
||||||
mux.engine.StaticFS("resources", gin.Dir(configs.GetResourcesFilePath(), true))
|
mux.engine.StaticFS("resources", gin.Dir(configs.GetResourcesFilePath(), true))
|
||||||
|
|
||||||
// withoutTracePaths 这些请求,默认不记录日志
|
// withoutTracePaths 这些请求,默认不记录日志
|
||||||
@ -275,9 +276,9 @@ func New(logger logger.CustomLogger, options ...Option) (Mux, error) {
|
|||||||
mux.engine.GET("/metrics", gin.WrapH(promhttp.Handler())) // register prometheus
|
mux.engine.GET("/metrics", gin.WrapH(promhttp.Handler())) // register prometheus
|
||||||
}
|
}
|
||||||
|
|
||||||
if opt.enableCors {
|
//if opt.enableCors {
|
||||||
mux.engine.Use(cors.New())
|
// mux.engine.Use(cors.New())
|
||||||
}
|
//}
|
||||||
|
|
||||||
// recover 两次,防止 recover 过程中时发生 panic
|
// recover 两次,防止 recover 过程中时发生 panic
|
||||||
mux.engine.Use(func(ctx *gin.Context) {
|
mux.engine.Use(func(ctx *gin.Context) {
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"mini-chat/internal/alert"
|
"mini-chat/internal/alert"
|
||||||
"mini-chat/internal/api/admin"
|
"mini-chat/internal/api/admin"
|
||||||
"mini-chat/internal/api/app"
|
"mini-chat/internal/api/app"
|
||||||
|
"mini-chat/internal/api/upload"
|
||||||
"mini-chat/internal/cron"
|
"mini-chat/internal/cron"
|
||||||
"mini-chat/internal/dblogger"
|
"mini-chat/internal/dblogger"
|
||||||
"mini-chat/internal/pkg/core"
|
"mini-chat/internal/pkg/core"
|
||||||
@ -41,6 +42,7 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo, cron cron.Server) (co
|
|||||||
|
|
||||||
adminHandler := admin.New(logger, db)
|
adminHandler := admin.New(logger, db)
|
||||||
appHandler := app.New(logger, db)
|
appHandler := app.New(logger, db)
|
||||||
|
uploadHandler := upload.New(logger, db)
|
||||||
|
|
||||||
// 管理端非认证接口路由组
|
// 管理端非认证接口路由组
|
||||||
adminNonAuthApiRouter := mux.Group("/admin")
|
adminNonAuthApiRouter := mux.Group("/admin")
|
||||||
@ -49,7 +51,8 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo, cron cron.Server) (co
|
|||||||
ctx.Payload(startup.Info())
|
ctx.Payload(startup.Info())
|
||||||
})
|
})
|
||||||
|
|
||||||
adminNonAuthApiRouter.POST("/login", adminHandler.Login()) // 登录
|
adminNonAuthApiRouter.POST("/login", adminHandler.Login()) // 登录
|
||||||
|
adminNonAuthApiRouter.POST("/upload/image", uploadHandler.UploadImage()) // 上传图片
|
||||||
}
|
}
|
||||||
|
|
||||||
// 管理端认证接口路由组
|
// 管理端认证接口路由组
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user