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