Bean Treasure community project actual combat tutorial introduction
This project is equipped with a free video tutorial, the supporting code is completely open source. Build from scratch the most widely used Springboot+Vue front-end and back-end separation multi-user community project. This project is of moderate difficulty. For your convenience, each video tutorial will correspond to each submission on Github.
Screenshot of project Home Page
Open source code address
The front end
Video Tutorial Address
Video tutorial
Front-end technology stack
Vue Vuex Vue Router Axios Bulma Buefy Element Vditor DarkReader
Back-end technology stack
Spring Boot Mysql Mybatis MyBatis-Plus Spring Security JWT Lombok
# # the front-end
1. The SRC \ API \ modify post. Js
// Get article details
export function getTopic(id) {
return request({
url: `/post`.method: 'get'.params: {
id: id
}
})
}
Copy the code
2. The routing
// Article details
{
name: "post-detail".path: "/post/:id".component: () = > import("@/views/post/Detail"),
meta: { title: "Details"}},Copy the code
3. The SRC \ views \ post \ create Detail vue
<template> <div class="columns"> <! --> <div class="column is-three-quarters"> <! <div slot="header" class="has-text-centered" > <p class="is-size-5 has-text-weight-bold">{{ topic.title }}</p> <div class="has-text-grey is-size-7 mt-3"> <span>{{ Dayjs (top.createTime). Format ('YYYY/MM/DD HH: MM :ss')}}</span> < el-Divider direction="vertical" /> <span> {{topicuser. alias}}</span> < el-Divider direction="vertical" /> <span> View: {{topic.view}}</span> </div> </div> <! --Markdown--> <div id="preview" /> <! -- tag --> <nav class="level has-text-grey is-sie-7 mt-6"> <div class="level-left"> <p class="level-item"> <b-taglist> <router-link v-for="(tag, index) in tags" :key="index" :to="{ name: 'tag', params: { name: tag.name } }" > <b-tag type="is-info is-light mr-1"> {{ "#" + tag.name }} </b-tag> </router-link> </b-taglist> </p> </div> <div v-if="token && user.id === topicUser.id" class="level-right" > <router-link class="level-item" :to="{name:'topic-edit',params: {id:topic.id}}" > <span class="tag"> Edit </span> </router-link> <a class="level-item"> <span class="tag" @ click = "handleDelete (topic. Id)" > delete < / span > < / a > < / div > < / nav > < / el - card > < / div > < div class = "column" > the author information < / div > < / div > </template> <script> import { deleteTopic, getTopic } from '@/api/post' import { mapGetters } from 'vuex' import Vditor from 'vditor' import 'vditor/dist/index.css' export default { name: 'TopicDetail', computed: { ... mapGetters([ 'token','user' ]) }, data() { return { flag: false, topic: { content: '', id: this.$route.params.id }, tags: [], topicUser: {} } }, mounted() { this.fetchTopic() }, methods: { renderMarkdown(md) { Vditor.preview(document.getElementById('preview'), md, { hljs: { style: 'github' } }) }, // Initialize async fetchTopic() {getTopic(this.$route.params.id). Then (response => {const {data} = response document.title = data.topic.title this.topic = data.topic this.tags = data.tags this.topicUser = data.user // this.comments = data.comments this.renderMarkdown(this.topic.content) this.flag = true }) }, handleDelete(id) { deleteTopic(id).then(value => { const { code, message } = value alert(message) if (code === 200) { setTimeout(() => { this.$router.push({ path: '/' }) }, 500) } }) } } } </script> <style> #preview { min-height: 300px; } </style>Copy the code
Article details back end
vo
import lombok.Data;
@Data
public class ProfileVO {
/** * user ID */
private String id;
/** * User name */
private String username;
/** ** ** /
private String alias;
/** ** avatar */
private String avatar;
/** ** /
private Integer followCount;
/** * Number of followers */
private Integer followerCount;
/** * number of articles */
private Integer topicCount;
/** * number of columns */
private Integer columns;
/** * number of comments */
private Integer commentCount;
}
Copy the code
BmsFollow
@Data
@TableName("bms_follow")
public class BmsFollow implements Serializable {
private static final long serialVersionUID = 1L;
/** * primary key */
@TableId(type = IdType.AUTO)
private Integer id;
/** * id */
@TableField("parent_id")
private String parentId;
/** * id */
@TableField("follower_id")
private String followerId;
public BmsFollow(a) {}}Copy the code
BmsFollowMapper
public interface BmsFollowMapper extends BaseMapper<BmsFollow> {}Copy the code
BmsPostController
/** * Get article details by id **@return* /
@GetMapping
public ApiResult getPostById(@RequestParam("id") String id) {
Map<String, Object> map = postService.getPostById(id);
return ApiResult.success(map);
}
Copy the code
BmsPostservice
public Map<String, Object> getPostById(String id) {
HashMap<String, Object> map = new HashMap<>(16);
// query the article
BmsPost post = this.getById(id);
Assert.notNull(post,"Current article does not exist or has been deleted");
/ / look at + 1
post.setView(post.getView()+1);
this.updateById(post);
// the expression is transcoded
post.setContent(EmojiParser.parseToUnicode(post.getContent()));
map.put("topic",post);
// The tag of the article
/ / label
QueryWrapper<BmsPostTag> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(BmsPostTag::getPostId, post.getId());
Set<String> set = new HashSet<>();
for (BmsPostTag articleTag : postTagService.list(wrapper)) {
set.add(articleTag.getTagId());
}
List<BmsTag> tags = tagService.listByIds(set);
map.put("tags", tags);
/ / the author
ProfileVO user = userService.getUserProfile(post.getUserId());
map.put("user", user);
return map;
}
Copy the code
UmsUserService
@Autowired
private BmsPostMapper postMapper;
@Autowired
private BmsFollowMapper followMapper;
public ProfileVO getUserProfile(String userId) {
ProfileVO profile = new ProfileVO();
UmsUser user = baseMapper.selectById(userId);
BeanUtils.copyProperties(user, profile);
// Number of user articles
int count = postMapper.selectCount(new LambdaQueryWrapper<BmsPost>().eq(BmsPost::getUserId, userId));
profile.setTopicCount(count);
/ / number of fans
int followers = followMapper.selectCount((new LambdaQueryWrapper<BmsFollow>().eq(BmsFollow::getParentId, userId)));
profile.setFollowerCount(followers);
return profile;
}
Copy the code