草庐IT

我的Vue之旅 09 数据数据库表的存储与获取实现 Mysql + Golang

小能的博客 CanAngle's Blog 2023-03-28 原文

第四期 · 将部分数据存储至Mysql,使用axios通过golang搭建的http服务器获取数据。

新建数据库

DROP DATABASE VUE;
create database if not exists vue;
use vue;

JSON TO MYSQL

JSON to MySQL (transform.tools)

DROP DATABASE VUE;
create database if not exists vue;
use vue;

CREATE TABLE gameblog (
  id INT PRIMARY KEY AUTO_INCREMENT,
  title VARCHAR(255),
  text VARCHAR(255),
  img VARCHAR(255)
);

insert into gameblog(title,text,img) values 
("Games of the Month: surrealist solitaire puzzles","What’s that? You need more games? I hear you, anonymous hapi fan.We’ve reached the part of the year when games start coming out fast","https://xiaonenglife.oss-cn-hangzhou.aliyuncs.com/static/pic/2022/11/20221102184434_1.jpg"),
("Games of the Month: Puzzles!","Sometimes you need a good puzzle game, just something to throw all of your attention at and ignore anything else going on. Well if that sometime for you is right now, then you’re in luck because in this Games of the Month","https://xiaonenglife.oss-cn-hangzhou.aliyuncs.com/static/pic/2022/11/20221102184434_2.jpg"),
("The next hapi Creator Day is July 29th!","I don’t think I’m allowed to make the entire body of this post “Thenext itch.io Creator Day is taking place on Friday July 29th.” I mean it’s true, we are hosting the next itch.io Creator Day on Friday July 29th but I should probably write more here.","https://xiaonenglife.oss-cn-hangzhou.aliyuncs.com/static/pic/2022/11/20221102184434_3.jpg");

select * from gameblog;


CREATE TABLE game (
  id INT PRIMARY KEY AUTO_INCREMENT,
  title VARCHAR(255),
  text VARCHAR(255),
  img VARCHAR(255),
  price decimal(6,2) default 0,
  web boolean default 0
  # TODO 发布时间
  # TODO 浏览量
  # TODO 评论量
  # TODO 热度综合指标
);

CREATE TABLE tag (
  id INT PRIMARY KEY AUTO_INCREMENT,
  title VARCHAR(255)
);

CREATE TABLE gametag (
  gameid INT,
  tagid INT
);
# TODO 外键

insert into game(id,title,text,img,price,web) values
(1,"Late Night Mop","A haunted house cleaning simulator.","https://xiaonenglife.oss-cn-hangzhou.aliyuncs.com/static/pic/2022/11/20221102193135_1.png",0,0),
(2,"an average day at the cat cafe","A haunted house cleaning simulator.","https://xiaonenglife.oss-cn-hangzhou.aliyuncs.com/static/pic/2022/11/20221102193135_2.png",0,1),
(3,"Corebreaker","A fast-paced action-platform shooter game with roguelike elements.","https://xiaonenglife.oss-cn-hangzhou.aliyuncs.com/static/pic/2022/11/20221102193135_3.png",19.99,0),
(4,"Atuel","Traverse a surrealist landscape inspired by the Atuel River in Argentina.","https://xiaonenglife.oss-cn-hangzhou.aliyuncs.com/static/pic/2022/11/20221102193135_5.png",0,0);

insert into tag values
(1,"Difficult"),
(2,"Fast-Paced");

insert into gametag values
(3,1),
(3,2),
(4,1);

DELIMITER $$
CREATE PROCEDURE gamelist()
BEGIN
	# TODO
END $$
DELIMITER ;

select a.title,a.text,img,price,web,if(group_concat(c.title separator "#") is null ,"", group_concat(c.title separator "#")) as tag from game a left join gametag b on a.id = b.gameid left join tag c on b.tagid = c.id group by a.id;

本地图片上传OSS图床得到静态资源的持久地址,我使用的是PicGo图床工具。


SQL TO GOLANG STRUCT

在线sql转golang struct - 球儿工具 (qetool.com)

config.go

为了方便mysql服务器的配置,写一个配置文件。

package mysql_vue

import "database/sql"

func GetMySQLDB() (db *sql.DB, err error) {
	dbDriver := "mysql"
	dbUser := "root"
	dbPass := "sql2008"
	dbName := "vue"
	db, err = sql.Open(dbDriver, dbUser+":"+dbPass+"@/"+dbName)
	return
}

gameblog.go

id暂时不需要,后期路由跳转需要用到,可以先注释。

package mysql_vue

import (
	"encoding/json"

	_ "github.com/go-sql-driver/mysql"
)

type Gameblog struct {
	// ID int64 `db:"id" json:"id"`
	Title string `db:"title" json:"title"`
	Text  string `db:"text" json:"text"`
	Img   string `db:"img" json:"img"`
}

func (Gameblog) TableName() string {
	return "gameblog"
}

func (Gameblog) QueryGameblog() (json_ []byte, err error) {
	// db, err := sql.Open("mysql", "root:sql2008@tcp(127.0.0.1:3306)/vue")
	db, err := GetMySQLDB()
	checkError(err)
	defer db.Close()
	// ^ 必须按照顺序选取,下面的Scan需要一一对应,如果多了或少了字段会导致Scan错误.
	results, err := db.Query("SELECT title,text,img FROM gameblog order by id desc")
	checkError(err)
	var gameBlogs []Gameblog
	for results.Next() {
		var gameBlog Gameblog
		err = results.Scan(&gameBlog.Title, &gameBlog.Text, &gameBlog.Img)
		checkError(err)
		gameBlogs = append(gameBlogs, gameBlog)
	}
	json_, err = json.Marshal(gameBlogs)
	checkError(err)
	return json_, nil
}

http

Simplify server.go

前面我们把评论相关的请求处理代码写在了 server.go,移出到 comment.go,并在init初始化中绑定各个请求路径处理函数。

comment.go

package server

import (
	"fmt"
	"net/http"
	"strconv"
)

type Comment interface {
	QueryComment(pid int64) (json_ []byte, err error)
	InsertComment(uid, pid int64, text string) (json_ []byte, err error)
	DeleteComment(id int64) error
}

func init() {
	http.HandleFunc("/insertComment", insertComment)
	http.HandleFunc("/deleteComment", deleteComment)
	http.HandleFunc("/queryComment", queryComment)
}

func insertComment(w http.ResponseWriter, r *http.Request) {
	....
}

func deleteComment(w http.ResponseWriter, r *http.Request) {
	....
}

func queryComment(w http.ResponseWriter, r *http.Request) {
	....
}

gameblog.go

接口用于确保某个数据库对象实现了处理函数,否则编译不通过。

package server

import (
	"fmt"
	"net/http"
)

type Gameblog interface {
	QueryGameblog() (json_ []byte, err error)
}

func init() {
	http.HandleFunc("/queryGameblog", QueryGameblog)
}

func QueryGameblog(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		fmt.Fprintf(w, "Only GET Method")
		return
	}
	json, err := gameblog.QueryGameblog()
	if err != nil {
		fmt.Fprintf(w, "Error Delete")
		return
	}
	fmt.Fprint(w, string(json))
}

server.go

package server

import (
	"log"
	"net/http"

	mysql_vue "wolflong.com/vue_http/lib/mysql"
	sq3_vue "wolflong.com/vue_http/lib/sqlite"
)

var comment Comment = sq3_vue.Comment{}
var gameblog Gameblog = mysql_vue.Gameblog{}

func StartServer() {
	err := http.ListenAndServe(":1314", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

postman test api

使用 postman 测试当前接口。


Axios

修改 HomeView.vue 的选项卡api,在 created 钩子函数添加axios请求访问。

  created() {
    this.axios
      .get("queryGameblog")
      .then((response) => {
        if (!response.data) {
          this.gameBlog = [];
          return;
        }
        this.gameBlog = response.data;
      })
      .catch((err) => {
        console.log(err);
      });
  },


gamelist.go

查询语句使用两次左连接,并用 group_concat 聚合函数,聚合 tag,分解tag的过程可以从服务端迁移到客户端进行降低性能消耗。

package mysql_vue

import (
	"encoding/json"
	"strings"
)

type Gamelist struct {
	// ID    int64    `db:"id" json:"id"`
	Title string   `db:"title" json:"title"`
	Text  string   `db:"text" json:"text"`
	Img   string   `db:"img" json:"img"`
	Price float64  `db:"price" json:"price"`
	Tag   []string `db:"tag" json:"tag"` // 新添加
	Web   bool     `db:"Web" json:"web"`
}

// type Tag struct {
// 	ID    int64  `db:"id" json:"id"`
// 	Title string `db:"title" json:"title"`
// }

func (Gamelist) QueryGamelist() (json_ []byte, err error) {
	db, err := GetMySQLDB()
	checkError(err)
	defer db.Close()
	results, err := db.Query(`select a.title,a.text,img,price,web,if(group_concat(c.title separator "#") is null ,"", group_concat(c.title separator "#")) as tag from game a left join gametag b on a.id = b.gameid left join tag c on b.tagid = c.id group by a.id;`)
	checkError(err)
	var GameList []Gamelist
	for results.Next() {
		var g Gamelist
		var tag string
		err = results.Scan(&g.Title, &g.Text, &g.Img, &g.Price, &g.Web, &tag)
		g.Tag = strings.Split(tag, "#") // 这里暂且由服务端完成分解
		checkError(err)
		GameList = append(GameList, g)
	}
	json_, err = json.Marshal(GameList)
	checkError(err)
	return json_, nil
}

HTTP

gamelist.go

package server

import (
	"fmt"
	"net/http"
)

type Gamelist interface {
	QueryGamelist() (json_ []byte, err error)
}

func init() {
	http.HandleFunc("/queryGamelist", QueryGamelist)
}

func QueryGamelist(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		fmt.Fprintf(w, "Only GET Method")
		return
	}
	json, err := gamelist.QueryGamelist()
	if err != nil {
		fmt.Fprintf(w, "Error Delete")
		return
	}
	fmt.Fprint(w, string(json))
}

server.go

添加语句 var gamelist Gamelist = mysql_vue.Gamelist{}


Axios

this.axios
  .get("queryGamelist")
  .then((response) => {
    if (!response.data) {
      this.latestGames.games = [];
      this.mostFeatureGames.games = [];
      return;
    }
    this.latestGames.games = response.data;
    this.mostFeatureGames.games = response.data;
  })
  .catch((err) => {
    console.log(err);
  });


有关我的Vue之旅 09 数据数据库表的存储与获取实现 Mysql + Golang的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  3. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  4. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  5. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

    我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

  6. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

  7. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  8. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  9. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  10. ruby - Rack:如何将 URL 存储为变量? - 2

    我正在编写一个简单的静态Rack应用程序。查看下面的config.ru代码:useRack::Static,:urls=>["/elements","/img","/pages","/users","/css","/js"],:root=>"archive"map'/'dorunProc.new{|env|[200,{'Content-Type'=>'text/html','Cache-Control'=>'public,max-age=6400'},File.open('archive/splash.html',File::RDONLY)]}endmap'/pages/search.

随机推荐