目录
实现用户注册和登录
首先,我们要在 MySQL 中创建一个新的用户表:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
在后端的 Go 代码中,我们将创建两个新的路由,一个用于处理用户注册,一个用于处理用户登录:
func main() {
// other code
r.POST("/register", register)
r.POST("/login", login)
// other code
}
下面,我们将分别实现 register
和 login
函数。在用户注册时,我们将用户的密码哈希后存储在数据库中,以提高安全性。在用户登录时,我们将用户输入的密码和数据库中存储的哈希密码进行比较,如果匹配则登录成功:
import (
"github.com/gin-gonic/gin"
"golang.org/x/crypto/bcrypt"
)
type User struct {
ID int `json:"id"`
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
func register(c *gin.Context) {
// Parse and validate the request body
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Hash the password
hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Insert the user into the database
res, err := db.Exec("INSERT INTO users (username, password) VALUES (?, ?)", user.Username, hash)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Return the user ID
id, err := res.LastInsertId()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"id": id})
}
func login(c *gin.Context) {
// Parse and validate the request body
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Get the user from the database
var dbUser User
err := db.QueryRow("SELECT * FROM users WHERE username = ?", user.Username).Scan(&dbUser.ID, &dbUser.Username, &dbUser.Password)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// Compare the passwords
if err := bcrypt.CompareHashAndPassword([]byte(dbUser.Password), []byte(user.Password)); err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Incorrect password"})
return
}
// Return the user ID
c.JSON(http.StatusOK, gin.H{"id": dbUser.ID})
}
在前端的 Vue 3 代码中,我们可以为用户注册和登录创建两个新的组件。在用户注册和登录的表单提交时,我们向后端发送 POST 请求。如果请求成功,我们将用户的 ID 存储在 localStorage
中,以此实现用户认证和权限控制。
实现评论功能
首先,我们在 MySQL 中创建一个新的评论表:
CREATE TABLE comments (
id INT AUTO_INCREMENT PRIMARY KEY,
article_id INT NOT NULL,
user_id INT NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (article_id) REFERENCES articles(id),
FOREIGN KEY (user_id) REFERENCES users(id)
);
然后,我们在后端的 Go 代码中创建一个新的路由来处理获取和创建评论的请求:
func main() {
// other code
r.GET("/articles/:id/comments", getComments)
r.POST("/articles/:id/comments", createComment)
// other code
}
在前端的 Vue 3 代码中,我们可以在文章详情页面下方添加一个评论列表和一个评论表单。在页面加载时,我们向后端发送 GET 请求获取评论列表。在表单提交时,我们向后端发送 POST 请求创建新的评论。
实现分类和标签功能
首先,我们在 MySQL 中创建两个新的表来存储分类和标签:
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE
);
CREATE TABLE tags (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE
);
CREATE TABLE article_categories (
article_id INT NOT NULL,
category_id INT NOT NULL,
PRIMARY KEY (article_id, category_id),
FOREIGN KEY (article_id) REFERENCES articles(id),
FOREIGN KEY (category_id) REFERENCES categories(id)
);
CREATE TABLE article_tags (
article_id INT NOT NULL,
tag_id INT NOT NULL,
PRIMARY KEY (article_id, tag_id),
FOREIGN KEY (article_id) REFERENCES articles(id),
FOREIGN KEY (tag_id) REFERENCES tags(id)
);
然后,我们在后端的 Go 代码中创建新的路由来处理获取和创建分类和标签的请求,以及按分类和标签过滤文章的请求。
用户注册和登录的前端处理
在前端部分,我们首先需要为注册和登录功能创建两个新的 Vue 组件:Register.vue
和 Login.vue
。
Register.vue
组件的代码如下:
<template>
<form @submit.prevent="register">
<label>
用户名:
<input v-model="username" type="text" required>
</label>
<label>
密码:
<input v-model="password" type="password" required>
</label>
<button type="submit">注册</button>
</form>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
username: '',
password: ''
};
},
methods: {
async register() {
try {
const res = await axios.post('/register', {
username: this.username,
password: this.password
});
localStorage.setItem('userId', res.data.id);
this.$router.push('/');
} catch (error) {
console.error(error);
}
}
}
};
</script>
同样,Login.vue
组件的代码如下:
<template>
<form @submit.prevent="login">
<label>
用户名:
<input v-model="username" type="text" required>
</label>
<label>
密码:
<input v-model="password" type="password" required>
</label>
<button type="submit">登录</button>
</form>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
username: '',
password: ''
};
},
methods: {
async login() {
try {
const res = await axios.post('/login', {
username: this.username,
password: this.password
});
localStorage.setItem('userId', res.data.id);
this.$router.push('/');
} catch (error) {
console.error(error);
}
}
}
};
</script>
这两个组件的模板部分都包含一个表单,用于接收用户输入的用户名和密码。@submit.prevent="register"
和 @submit.prevent="login"
用于阻止表单的默认提交行为,并调用 register
或 login
方法。
评论功能的前端处理
对于评论功能,我们需要在文章详情页下面添加一个评论表单和一个评论列表。
首先,我们需要在文章详情组件 Article.vue
中添加以下代码:
<template>
<!-- other code -->
<section>
<form @submit.prevent="submitComment">
<label>
评论:
<textarea v-model="commentContent" required></textarea>
</label>
<button type="submit">提交评论</button>
</form>
<div v-for="comment in comments" :key="comment.id">
<h3>{
{ comment.user.username }}</h3>
<p>{
{ comment.content }}</p>
</div>
</section>
</template>
<script>
import axios from 'axios';
export default {
// other code
data() {
return {
comments: [],
commentContent: ''
};
},
async created() {
try {
const res = await axios.get(`/articles/${this.id}/comments`);
this.comments = res.data;
} catch (error) {
console.error(error);
}
},
methods: {
async submitComment() {
try {
const res = await axios.post(`/articles/${this.id}/comments`, {
content: this.commentContent,
user_id: localStorage.getItem('userId')
});
this.comments.push(res.data);
this.commentContent = '';
} catch (error) {
console.error(error);
}
}
}
};
</script>
分类和标签功能的前端处理
对于分类和标签功能,我们可以在文章列表页面添加一个侧边栏来显示所有的分类和标签。用户可以点击分类或标签来查看相关的文章。
首先,我们需要在文章列表组件 Articles.vue
中添加以下代码:
<template>
<!-- other code -->
<aside>
<section>
<h2>分类</h2>
<ul>
<li v-for="category in categories" :key="category.id">
<a @click="filterByCategory(category.id)">{
{ category.name }}</a>
</li>
</ul>
</section>
<section>
<h2>标签</h2>
<ul>
<li v-for="tag in tags" :key="tag.id">
<a @click="filterByTag(tag.id)">{
{ tag.name }}</a>
</li>
</ul>
</section>
</aside>
</template>
<script>
import axios from 'axios';
export default {
// other code
data() {
return {
categories: [],
tags: [],
articles: []
};
},
async created() {
try {
const [categoriesRes, tagsRes, articlesRes] = await Promise.all([
axios.get('/categories'),
axios.get('/tags'),
axios.get('/articles')
]);
this.categories = categoriesRes.data;
this.tags = tagsRes.data;
this.articles = articlesRes.data;
} catch (error) {
console.error(error);
}
},
methods: {
async filterByCategory(id) {
try {
const res = await axios.get(`/articles?category=${id}`);
this.articles = res.data;
} catch (error) {
console.error(error);
}
},
async filterByTag(id) {
try {
const res = await axios.get(`/articles?tag=${id}`);
this.articles = res.data;
} catch (error) {
console.error(error);
}
}
}
};
</script>
以上就是使用 Vue 3、Go 和 MySQL 实现用户注册和登录、评论、分类和标签功能的全部内容。这些功能对于一个博客系统来说都非常重要,可以极大地提高用户体验。我希望这篇博客对你有所帮助,如果你有任何问题或建议,欢迎在评论区留言。