当前位置: 首页 > news >正文

成都市建设局网站/百度高级搜索

成都市建设局网站,百度高级搜索,北京汉邦未来网站建设有限公司,狮山公司网站建设请记住,这个项目主要是为了稍微熟悉下Golang,您可以复制架构,但该项目缺少适当的 ORM,没有适当的身份验证或授权,我完全无视中间件,也没有测试。 我将在其自己的部分中讨论所有这些问题,但重要的…

请记住,这个项目主要是为了稍微熟悉下Golang,您可以复制架构,但该项目缺少适当的 ORM,没有适当的身份验证或授权,我完全无视中间件,也没有测试。
我将在其自己的部分中讨论所有这些问题,但重要的是你要知道这还没有准备好投入生产。

如果我必须从头开始或重新制作项目,我会添加诸如 sqlx 和 Gorm 之类的库。 以及改进 API 和我在下面进行的其他更改。

此外,我想谈谈我正在使用的路由库:Fiber。 请注意,它是版本 2,但是很多教程和博客文章都在展示和谈论 v1,此后发生了一些变化,因此在查找其他信息时确保导入是 github.com/gofiber/fiber/v2。

此外,您绝对应该在项目中有一个配置文件和一个 .env 来隐藏您的数据。

README 中还有一个免责声明:
免责声明
这是一个介绍性的项目,可以稍微了解一下 Golang。 这个项目还没有准备好生产,它有不好的做法,比如分页的工作方式或我们与数据库的交互方式。
通过代码库,您会发现用于调试项目的不同“打印件”,请随意使用它们。 生产就绪缺少什么?
您应该添加适当的记录器、配置、中间件、处理数据的不同方式(可能是 ORM)、处理分页的更好方式以及更好的 API。
请注意,如果您复制并粘贴代码,可能会使自己容易受到 SQL 注入的攻击。 这是出于学习目的而制作的。

Database

您可能应该让 Docker 运行 MySQL(或任何其他 SQL 数据库)。 如果没有,你总是可以在你的系统上安装 MySQL 并使用像 MySQL Workbench 这样的东西来处理它。

Database design

在这里插入图片描述

数据库本身相当简单,你有发布推文的用户和一个关注者表来保存谁关注谁的数据。关注者表主要是为我们的用户实现提要/时间线。

Create Database

在脚本文件夹中,您将找到运行以启动 MySQL 数据库的主要脚本:

use twitterdb;DROP TABLE IF EXISTS tweets;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS followers;CREATE TABLE users (user_id INT NOT NULL AUTO_INCREMENT,user VARCHAR(255) NOT NULL,passhash VARCHAR(40) NOT NULL,email VARCHAR(255) NOT NULL,first_name VARCHAR(255) NOT NULL,last_name VARCHAR(255) NOT NULL,dob DATE,PRIMARY KEY (user_id)
);CREATE TABLE tweets (tweet_id INT NOT NULL AUTO_INCREMENT,user_id INT NOT NULL,tweet VARCHAR(140) NOT NULL,date_tweet DATETIME NOT NULL,PRIMARY KEY (tweet_id),FOREIGN KEY user_id(user_id) REFERENCES users(user_id) ON UPDATE CASCADE ON DELETE CASCADE
);CREATE TABLE followers (id_user INT NOT NULL REFERENCES users (user_id),id_follower INT NOT NULL REFERENCES users (user_id),PRIMARY KEY (id_user, id_follower)
);INSERT INTO users (user, passhash, email, first_name, last_name, dob) VALUES
("foo", "asdsad1", "test@gmail.com", "bob", "bobbinson", "2006-01-01"),
("foo2", "asdsad2", "test2@gmail.com", "bob2", "bobbinson2", "1992-01-01"),
("foo3", "asdsad3", "test3@gmail.com", "bob3", "bobbinson3", "1993-01-01"),
("foo4", "asdsad4", "test4@gmail.com", "bob4", "bobbinson4", "1994-01-01"),
("foo5", "asdsad5", "test5@gmail.com", "bob5", "bobbinson5", "1995-01-01"),
("foo6", "asdsad6", "test6@gmail.com", "bob6", "bobbinson6", "1996-01-01"),
("foo7", "asdsad7", "test7@gmail.com", "bob7", "bobbinson7", "1925-01-01"),
("foo8", "asdsad8", "test8@gmail.com", "bob8", "bobbinson8", "1980-01-01"),
("foo9", "asdsad9", "test9@gmail.com", "bob9", "bobbinson9", "1980-01-01"),
("foo10", "asdsad10", "test10@gmail.com", "bob10", "bobbinson10", "1970-01-01");INSERT INTO tweets(user_id, tweet, date_tweet) VALUES
(1, "test tweet", "2001-01-01 22:00:00"),
(2, "test tweet2", "2002-01-01 22:00:00"),
(3, "test tweet3", "2003-01-01 22:00:00"),
(4, "test tweet4", "2004-01-01 22:00:00"),
(5, "test tweet5", "2005-01-01 22:00:00");INSERT INTO followers(id_user, id_follower) VALUES
(5,1),
(4,1),
(3,1),
(2,1),
(6,1),
(2,5),
(4,5);

其他文件是我们稍后将使用的查询示例。

Project Architecture

在这里插入图片描述

如果您熟悉构建软件,如果不熟悉这应该很熟悉,首先让我告诉您缺少什么,然后我们将遍历每个文件夹。

该项目缺少配置、中间件、记录器和测试等文件夹。 如果你能更好地组织控制器,你就会有一个路由文件夹,你可以更好地组织 API。

关于导入包的说明

在这个项目中,您可能会对以下导入感到困惑:

import ("goexample/database""goexample/models""goexample/services/utils"
)

这里的 goexample 是项目的名称,我只是在之后重命名了我的 repo 这样它才有意义,所以我们使用“goexample/database”而不是“mini-twitter-clone/database”来导入数据库包。
对于任何其他新项目,只需使用文件夹的名称。

API

路由存储在 controller.go 中:

package apiimport ("goexample/services""github.com/gofiber/fiber/v2"
)func SetupRoutes(app *fiber.App) {api := app.Group("/api")//get all unordened usersapi.Get("/users", services.GetUsers)//get all users ordered by age ASCapi.Get("/users/age", services.GetUsersByAgeAsc)//get all unordened tweets from dbapi.Get("/tweets", services.GetTweets)//http://localhost:3000/api/feed/1//get MOST RECENT feed/timeline for the userapi.Get("/feed/:id", services.GetFeedTweets)//paginationapi.Get("/feed/:id/:limit/:offset", services.GetFeedTweetsPaginated)//can try https://github.com/gofiber/fiber/issues/193#issuecomment-591976894//a whole presentation on why you shouldn't do what I did://https://use-the-index-luke.com/no-offset}

我正在使用类似于 Express 的 Fiber 库,这里我们有几个端点,我们通过 Get 请求调用这些端点,一旦服务器收到请求,它的响应就是调用我从服务包中公开的函数——那就是 我们的业务逻辑在哪里。

注意:分页未正确实现。

这只是一个简单的示例,此端点与其他端点一样存在安全问题,但您应该通过示例了解库和 Golang 的工作方式。

请注意,在 /feed/:id 中,id 参数与我们要为其获取提要的用户有关。

启动项目

您可以通过执行 go run 来启动项目。 文件夹内。
您的终端应如下所示:

在这里插入图片描述
让我们访问不同的端点以查看响应,我将使用普通浏览,但如果您不熟悉调试后端,则应检查 Postman。

让我们从控制器运行端点:

http://127.0.0.1:3000/api/users

在这里插入图片描述
我留下了很多打印输出,所以如果你在每次通话时检查你的终端,你应该会看到如下内容:在这里插入图片描述

接下来是我们按年龄对用户排序的调用:

http://127.0.0.1:3000/api/users/age

当我们请求推文时,我们会得到所有的推文:

http://127.0.0.1:3000/api/tweets

在这里插入图片描述

在这里插入图片描述
现在我们获取 ID 为 1 的用户的提要或时间线:

http://127.0.0.1:3000/api/feed/1

在这里插入图片描述

在这里插入图片描述
请记住,分页尚未准备好生产,但核心概念是相同的:

http://127.0.0.1:3000/api/feed/1/2/1

在这里插入图片描述
由于我们在服务包中的业务逻辑和我们公开的功能,所有调用都能正常工作。

Services

在服务包中,我们有当某人或某物点击其中一个端点时调用的函数。 请记住,我们通过在包中使用大写字母来公开功能。

让我们看一下 timeline_tweets.go,它包含 controller.go 文件中两个不同端点的两个函数:


package servicesimport ("fmt""goexample/database""goexample/models""goexample/services/utils""log""github.com/gofiber/fiber/v2"
)func GetFeedTweets(c *fiber.Ctx) error {//you shouldn't do this by the way, but it's just a demo// dbQuery := fmt.Sprintf("SELECT users.user_id, users.user, users.first_name, users.last_name, tweets.tweet, tweets.date_tweet FROM users INNER JOIN tweets ON users.user_id = tweets.user_id INNER JOIN followers ON users.user_id = followers.id_user WHERE followers.id_follower = %s ORDER BY tweets.date_tweet DESC;", c.Params("id"))// rows, err := database.DB.Query(dbQuery)//avoid the SQL injection by rewriting it likedbQuery := "SELECT users.user_id, users.user, users.first_name, users.last_name, tweets.tweet, tweets.date_tweet FROM users INNER JOIN tweets ON users.user_id = tweets.user_id INNER JOIN followers ON users.user_id = followers.id_user WHERE followers.id_follower = ? ORDER BY tweets.date_tweet DESC;"rows, err := database.DB.Query(dbQuery, c.Params("id"))//check for errorsif err != nil {return utils.DefaultErrorHandler(c, err)}//close db connectiondefer rows.Close()//create a slice of tweetsvar timelineTweets []models.TimelineTweet//loop through the result setfor rows.Next() {timelineTweet := models.TimelineTweet{}err := rows.Scan(&timelineTweet.User_id, &timelineTweet.User, &timelineTweet.First_name, &timelineTweet.Last_name, &timelineTweet.Tweet, &timelineTweet.Date_tweet)if err != nil {log.Fatal(err)}timelineTweets = append(timelineTweets, timelineTweet)}fmt.Print(timelineTweets)utils.ResponseHelperJSON(c, timelineTweets, "timeline", "No timeline found")return err
}func GetFeedTweetsPaginated(c *fiber.Ctx) error {// dbQuery := fmt.Sprintf("SELECT users.user_id, users.user, users.first_name, users.last_name, tweets.tweet, tweets.date_tweet FROM users INNER JOIN tweets ON users.user_id = tweets.user_id INNER JOIN followers ON users.user_id = followers.id_user WHERE followers.id_follower = %s ORDER BY tweets.date_tweet DESC LIMIT %s OFFSET %s;", c.Params("id"), c.Params("limit"), c.Params("offset"))// avoid a SQL injection by rewriting it likedbQuery := "SELECT users.user_id, users.user, users.first_name, users.last_name, tweets.tweet, tweets.date_tweet FROM users INNER JOIN tweets ON users.user_id = tweets.user_id INNER JOIN followers ON users.user_id = followers.id_user WHERE followers.id_follower = ? ORDER BY tweets.date_tweet DESC LIMIT ? OFFSET ?;"rows, err := database.DB.Query(dbQuery, c.Params("id"), c.Params("limit"), c.Params("offset"))if err != nil {return utils.DefaultErrorHandler(c, err)}defer rows.Close()var timelineTweets []models.TimelineTweetfor rows.Next() {timelineTweet := models.TimelineTweet{}err := rows.Scan(&timelineTweet.User_id, &timelineTweet.User, &timelineTweet.First_name, &timelineTweet.Last_name, &timelineTweet.Tweet, &timelineTweet.Date_tweet)if err != nil {log.Fatal(err)}timelineTweets = append(timelineTweets, timelineTweet)}//TODO: implement a response with pages and all that pagination jazzutils.ResponseHelperJSON(c, timelineTweets, "timeline", "No timeline found")return err
}

您首先注意到的是我们如何将上下文传递给 GetFeedTweets,然后我们使用变量“c”来使用 Fiber 库所说的上下文。

之后,我们使用包数据库中公开的变量 DB 打开 DB,读取数据,然后关闭它。

为了正确存储和扫描数据,我们使用模型包中的结构。

之后您将看到 utils 包中的几个函数。 这些函数主要是辅助函数,因此您可以查看 Golang 如何执行循环和某些其他操作。

我们的服务包中的其他两个文件非常相似,我们在这里的工作是从数据库中获取数据,通过我们的结构数组扫描它,然后以 JSON 格式将其发送回用户。 以及我们运行 utils 包中的一些功能。

Utils

这个包包含辅助函数,也许最有趣的是在 user_helper 里面,因为它有与切片数据交互的函数,但是要小心,它们的实现并不像你想象的那么好。

让我们看看最有帮助的,response_helper.go

package utilsimport ("github.com/gofiber/fiber/v2"
)//response JSON for services after you loop and scan
func ResponseHelperJSON(c *fiber.Ctx, data any, dataType string, dataError string) {if data != nil {c.Status(200).JSON(&fiber.Map{"success": true,dataType:  data,})} else {c.Status(404).JSON(&fiber.Map{"success": false,"error":   dataError,})}
}

请注意,此函数包含通用类型的数据,因为我使用关键字 any 并且我正在与 Fiber 通过变量“c”提供的上下文进行交互。

Models

models 文件夹包含我们用作与数据库交互的实体的不同结构,如 services 文件夹中所示。

这是一个示例,请注意,即使您想公开整个结构,所有内容都必须以大写字母开头:

package modelstype UserWithAge struct{Id         int   `json:"id"`User       string `json:"user"`Passhash   string `json:"passhash"`Email      string `json:"email"`First_name string `json:"first_name"`Last_name  string `json:"last_name"`Age        int    `json:"age"`
}

Database

数据库包非常简单,请记住使用配置文件和 .env 来存储您的敏感数据。

package databaseimport ("database/sql""fmt""log"
)var DB *sql.DBfunc Connect() error{var err error//use a config file for thisDB, err = sql.Open("mysql", "root:password@tcp(127.0.0.1:3306)/twitterdb")if err != nil {log.Fatal(err)return err}if err = DB.Ping(); err != nil {log.Fatal(err)return err}fmt.Println("Connected to database")return nil}

Main.go

最后,这是我们启动服务器的地方:

package mainimport ("github.com/gofiber/fiber/v2""goexample/database""log""goexample/api"_ "github.com/go-sql-driver/mysql"
)func main() {if err := database.Connect(); err != nil {log.Fatal(err)}app := fiber.New()api.SetupRoutes(app)log.Fatal(app.Listen(":3000"))}
http://www.jmfq.cn/news/5329117.html

相关文章:

  • 住房和建设部网站/自媒体引流推广
  • 陕西省建设工程质量监督站网站/杭州百度快速排名提升
  • 德州力点科技 网站建设/百度的seo排名怎么刷
  • 阳澄湖大闸蟹网站建设/成都网站排名优化公司
  • 广东深圳建设工程信息网站/2022年关键词排名
  • 东莞易宣网站建设公司怎么样/黑马培训
  • 郯城建设银行网站/南宁网站推广大全
  • 人大网站建设方案 文库/长沙seo优化排名
  • 高端网站建设需要的人员配备/天津百度关键词排名
  • 白云区手机版网站建设/网络营销和传统营销的区别
  • 深圳公司网站建设案例/sns营销
  • 简述使用asp建设动态网站/网站建设开发
  • 网站建设的软硬件环境/什么是全网营销推广
  • 南京建设银行网站首页/淄博网站推广
  • 网站建设实训设备/自己做一个网站需要什么
  • 企业网站建设参考文献/百度网盘app官方下载
  • 常州模板网站建设咨询/网络推广的方式有哪些?
  • 南通精诚建设集团有限公司网站/yoast seo
  • 如何建设自己的摄影网站/软文营销文章300字
  • 北京专业建设网站公司/免费二级域名生成网站
  • 房山网站建设服务/seo入门基础教程
  • 福建宏盛建设集团有限公司网站/如何做线上营销
  • 高职考技能考网站建设试题/网站优化 福州
  • 广州黄埔网站建设公司/爱站工具包下载
  • 上海网站建设流/服务营销
  • 建设银行网站开通查询密码/长春关键词优化公司
  • 网站建设考察报告/推广费用一般多少钱
  • 贾汪建设局网站/谷歌搜索引擎入口google
  • 公司电子商务网站建设规划方案/竞价托管外包代运营
  • 合肥高端网站建设/媒体软文推广平台