豆宝社区项目实战教程简介
本项目实战教程配有免费视频教程,配套代码完全开源。手把手从零开始搭建一个目前应用最广泛的Springboot+Vue前后端分离多用户社区项目。本项目难度适中,为便于大家学习,每一集视频教程对应在Github上的每一次提交。
项目首页截图
代码开源地址
视频教程地址
前端技术栈
Vue Vuex Vue Router Axios Bulma Buefy Element Vditor DarkReader
后端技术栈
Spring Boot Mysql Mybatis MyBatis-Plus Spring Security JWT Lombok
tag标签前端
API
src/api/新增tag.js
import request from '@/utils/request'
export function getTopicsByTag(paramMap) {
return request({
url: '/tag/' + paramMap.name,
method: 'get',
params: {
page: paramMap.page,
size: paramMap.size
}
})
}
路由
src\router\index.js
,
{
name: 'tag',
path: '/tag/:name',
component: () => import('@/views/tag/Tag'),
meta: { title: '主题列表' }
}
新增Tag.vue
src/views/新增tag/Tag.vue
<template>
<div id="tag" class="columns">
<div class="column is-three-quarters">
<el-card class="box-card" shadow="never">
<div slot="header" class="">
🔍 检索到 <span class="has-text-info">{{ topics.length }}</span> 篇有关
<span class="has-text-info">{{ this.$route.params.name }}</span>
的话题
</div>
<div class="text item">
<article v-for="(item, index) in topics" :key="index" class="media mt-3">
<div class="media-content">
<div class="content">
<el-tooltip class="item" effect="dark" :content="item.title" placement="top">
<router-link :to="{ name: 'post-detail',params:{id: item.id } }">
{{ item.title }}
</router-link>
</el-tooltip>
</div>
<nav class="level has-text-grey is-size-7">
<div class="level-left">
<span>发布于:{{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
<span class="mx-3">浏览:{{ item.view }}</span>
<span>评论:{{ item.comments }}</span>
</div>
</nav>
</div>
</article>
</div>
</el-card>
</div>
<div class="column">
<el-card class="box-card" shadow="hover">
<div slot="header" class="clearfix">
🤙 关于标签
</div>
<div>
<ul>
<li class="content">标签由平台用户发布使用</li>
<li class="content">系统每周会定时清理无用标签</li>
</ul>
</div>
</el-card>
<el-card shadow="hover">
<div slot="header">
🏷 热门标签
</div>
<div>
<ul>
<li v-for="(tag,index) in tags" :key="index" style="padding: 6px 0">
<router-link :to="{name:'tag',params:{name:tag.name}}">
<span v-if="index<9" class="tag">
0{{ parseInt(index) + 1 }}
</span>
<span v-else class="tag">
{{ parseInt(index) + 1 }}
</span>
{{ tag.name }}
</router-link>
</li>
</ul>
</div>
</el-card>
</div>
</div>
</template>
<script>
import { getTopicsByTag } from '@/api/tag'
export default {
name: 'Tag',
data() {
return {
topics: [],
tags: [],
paramMap: {
name: this.$route.params.name,
page: 1,
size: 10
}
}
},
created() {
this.fetchList()
},
methods: {
fetchList: function() {
getTopicsByTag(this.paramMap).then(response => {
console.log(response)
this.topics = response.data.topics.records
this.tags = response.data.hotTags.records
})
}
}
}
</script>
<style scoped>
#tag {
min-height: 500px;
}
</style>
tag标签后端
BmsTagController
package com.notepad.blog.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.notepad.blog.common.api.ApiResult;
import com.notepad.blog.domain.BmsPost;
import com.notepad.blog.domain.BmsTag;
import com.notepad.blog.service.BmsTagService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/tag")
public class BmsTagController {
@Resource
private BmsTagService tagService;
@GetMapping("/{name}")
public ApiResult<Map<String, Object>> getTopicsByTag(
@PathVariable("name") String tagName,
@RequestParam(value = "page", defaultValue = "1") Integer page,
@RequestParam(value = "size", defaultValue = "10") Integer size) {
Map<String, Object> map = new HashMap<>(16);
LambdaQueryWrapper<BmsTag> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BmsTag::getName, tagName);
BmsTag one = tagService.getOne(wrapper);
Assert.notNull(one, "话题不存在,或已被管理员删除");
Page<BmsPost> topics = tagService.selectTopicsByTagId(new Page<>(page, size), one.getId());
// 其他热门标签
Page<BmsTag> hotTags = tagService.page(new Page<>(1, 10),
new LambdaQueryWrapper<BmsTag>()
.notIn(BmsTag::getName, tagName)
.orderByDesc(BmsTag::getPostCount));
map.put("topics", topics);
map.put("hotTags", hotTags);
return ApiResult.success(map);
}
}
BmsTagService
public Page<BmsPost> selectTopicsByTagId(Page<BmsPost> topicPage, String id) {
// 获取关联的话题ID
Set<String> ids =postTagService.selectPostIdsByTagId(id);
LambdaQueryWrapper<BmsPost> wrapper = new LambdaQueryWrapper<>();
wrapper.in(BmsPost::getId, ids);
return postService.page(topicPage, wrapper);
}
BmsTagMapper.xml
<select id="getTopicIdsByTagId" resultType="java.lang.String">
SELECT t.post_id
from bms_post_tag t
where t.tag_id = #{id}
</select>