龙空技术网

9.Go语言编写个人博客 图片上传

ITTale 45

前言:

目前看官们对“用c语言编写图案”大概比较讲究,你们都需要分析一些“用c语言编写图案”的相关知识。那么小编也在网摘上搜集了一些对于“用c语言编写图案””的相关文章,希望兄弟们能喜欢,兄弟们一起来学习一下吧!

无论是博客还是其它类型的富文本平台,发布文章或想法怎么能少的了图片吗?这一节咱们就完成图片上传部分的编写。

先把Article模型修改一下:

package modelsimport (	"gorm.io/gorm")type Article struct {	gorm.Model	Title      string  `gorm:"type:varchar(255);not null" json:"title" form:"title"`	Content    string  `gorm:"type:text;not null" json:"content" form:"content"`	UserID     uint    `gorm:"not null" json:"user_id"`	User       User    `gorm:"foreignKey:UserID"`	CoverImage string  `gorm:"type:varchar(255)" json:"cover_image"`	Images     []Image `gorm:"foreignKey:ArticleID"`}type Image struct {	gorm.Model	URL       string `gorm:"type:varchar(255);not null" json:"url"`	ArticleID uint   `gorm:"not null" json:"article_id"`}

我给Title和Content添加了form标签,拿form:"title"来解释。它是一个结构体标签(struct tag),它在 Go 语言中用于为结构体的字段添加元数据。当你在 Go 中处理 HTTP 请求时,经常需要从请求体或查询参数中解析数据。这些数据通常会被解析到一个结构体中。form 标签就是在这个解析过程中起作用的。具体来说,form:"title" 意味着当你从一个表单请求(如 POST 或 PUT 请求的内容类型为 application/x-www-form-urlencoded 或 multipart/form-data)中解析数据到这个结构体时,Go 将会查找表单数据中名为 title 的字段,并将其值解析到结构体的对应字段中。

CoverImage 代表文章的封面图片,它用于存储图片的路径。

Image是新添加的结构体,我们用它保存文章中的图片路径。它与Article结构体是多对一的关系。

接着在db.go文件中把Image数据库迁移加上,请看如下代码:

err = db.AutoMigrate(&User{}, &Article{}, &Image{})

完成上述代码后,我们需要去实现上传图片部分的代码编写。这部分有修改也有新增。完成代码如下:

package apiimport (	"log"	"net/http"	"path/filepath"	"xblog/models"	"github.com/gin-gonic/gin")// CreateArticle 创建新文章func CreateArticle(c *gin.Context) {	// 从上下文中获取当前用户	currentUser, _ := c.Get("currentUser")	user, ok := currentUser.(*models.JwtClaims)	if !ok {		c.JSON(http.StatusUnauthorized, gin.H{"error": "无法获取用户认证信息"})		return	}	// 获取上传的封面图片	coverImage, err := c.FormFile("cover_image")	if err != nil {		c.JSON(http.StatusBadRequest, gin.H{"error": "无法获取封面图片"})		return	}	// 获取文章内容中的图片	contentImages, err := c.MultipartForm()	if err != nil {		c.JSON(http.StatusBadRequest, gin.H{"error": "无法获取图片"})		return	}	// 初始化Article结构体	var article models.Article	// 绑定请求体到article结构体	if err := c.ShouldBind(&article); err != nil {		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})		return	}	// 设置文章的UserID为当前用户的ID	article.UserID = user.UserID	// 保存封面图片到文件系统并将路径保存至数据库	coverImagePath := filepath.Join("/home/nonm/codes/xblog/static/cover/images", coverImage.Filename)	if err := c.SaveUploadedFile(coverImage, coverImagePath); err != nil {		c.JSON(http.StatusInternalServerError, gin.H{"error": "保存封面图片失败"})		return	}	article.CoverImage = coverImagePath	// 保存文章到数据库	if result := models.DB.Create(&article); result.Error != nil {		c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})		return	}	// 保存文章内容中的图片到文件系统并将路径保存至数据库	for _, contentImage := range contentImages.File["content_images"] {		contentImagePath := filepath.Join("/home/nonm/codes/xblog/static/content/images", contentImage.Filename)		log.Printf("Saving content image: %s\n", contentImagePath)		if err := c.SaveUploadedFile(contentImage, contentImagePath); err != nil {			log.Printf("Failed to save content image: %s, error: %v\n", contentImagePath, err)			c.JSON(http.StatusInternalServerError, gin.H{"error": "保存文章内图片失败"})			return		}		image := models.Image{			URL:       contentImagePath,			ArticleID: article.ID,		}		if result := models.DB.Create(&image); result.Error != nil {			c.JSON(http.StatusInternalServerError, gin.H{"error": result.Error.Error()})			return		}	}	// 预加载User和Images数据	if result := models.DB.Preload("User").Preload("Images").First(&article, article.ID); result.Error != nil {		c.JSON(http.StatusInternalServerError, gin.H{"error": "加载文章详情时出现错误"})		return	}	// 返回创建的文章	c.JSON(http.StatusOK, gin.H{"article": article})}

可以看到我先是添加了获取上传封面图片(CoverImage)与获取文章内容中的图片(ContentImages)这两个语句块。

这里重点解释一下保存封面图片到文件系统并将路径保存至数据库。

coverImagePath := filepath.Join("/home/nonm/codes/xblog/static/cover/images", coverImage.Filename) 这行代码使用 filepath.Join 函数来构造封面图片的保存路径。filepath.Join 是一个用于连接文件路径的函数,它会根据操作系统使用正确的路径分隔符。它连接了两个字符串:"/home/nonm/codes/xblog/static/cover/images"(这是服务器上用于存储封面图片的目录路径)和 coverImage.Filename(上传文件的原始文件名)以创建出一个完整的文件路径。当然您也可以使用相对路径。

if err := c.SaveUploadedFile(coverImage, coverImagePath); err != nil { 接下来,使用 Gin 的 c.SaveUploadedFile 函数尝试将上传的封面图片文件保存到上一步构造的文件路径。c.SaveUploadedFile 接受两个参数:上传的文件 (coverImage) 和目标保存路径 (coverImagePath)。如果保存文件过程中出现任何错误,SaveUploadedFile 函数会返回一个错误 (err)。如果 err 不为 nil,这意味着保存文件时发生了错误。在这种情况下,代码会使用 c.JSON 方法向客户端返回一个状态码为 500 Internal Server Error 的 HTTP 响应,并附上一个包含错误信息 "保存封面图片失败" 的 JSON 对象。

如果没有错误发生,文件成功保存到服务器,那么 coverImagePath(包含了新保存的封面图片的完整路径)将被赋值给 article.CoverImage。这样,文章的 CoverImage 字段就包含了指向封面图片文件的路径,可以在后续过程中用于引用或显示封面图片。

for _, contentImage := range contentImages.File["content_images"] { 这行代码遍历 contentImages.File["content_images"] 切片,这个切片包含了所有上传的文章内容图片。这是一个 for 循环,contentImage 是循环变量,代表当前遍历到的图片。

contentImagePath := filepath.Join("/home/nonm/codes/xblog/static/content/images", contentImage.Filename) 这行代码和前面的 coverImagePath 作用一样。

log.Printf("Saving content image: %s\n", contentImagePath) 这行代码使用 log.Printf 打印日志,记录正在保存的图片路径。对于跟踪和调试非常有用。

if err := c.SaveUploadedFile(contentImage, contentImagePath); err != nil { 使用 Gin 的 c.SaveUploadedFile 函数尝试将当前遍历到的文章内容图片文件保存到指定路径。如果保存文件过程出错,函数会返回一个错误 (err)。如果保存文件出错,打印失败的日志,并使用 c.JSON 向客户端返回一个状态码为 500 Internal Server Error 的 HTTP 响应,附上错误信息 "保存文章内图片失败"。

如果文件成功保存,将创建一个新的 models.Image 实例(image),设置 URL 字段为图片的保存路径(contentImagePath),设置 ArticleID 字段为当前文章的 ID。

if result := models.DB.Create(&image); result.Error != nil { 使用 GORM 的 Create 方法尝试将 Image 实例保存到数据库。如果保存过程出错,函数会返回一个包含错误信息的 result.Error,并向客户端返回一个状态码为 500 Internal Server Error 的 HTTP 响应,并附上错误信息。

关于预加载请看上一篇文件。这里就不再次解释了。

好,到这里我们图片上传代码就编写完成了。使用Curl去测试一下。

如图可知,文件系统与数据库都成功保存了相应的数据。

标签: #用c语言编写图案