SpringBoot前后端分离实现个人博客系统

目录
  • 一、项目简介
  • 二、环境介绍
  • 三、系统展示
  • 四、核心代码展示
  • 五、项目总结

一、项目简介

本项目使用springboot+mybatis+前端vue,使用前后端分离架构实现的个人博客系统,共7个模块,首页,写博客,博客详情页,评论管理,文章分类,标签管理和文章归档。该项目没有后端管理功能,比较适合用于大作业!

二、环境介绍

语言环境:Java:  jdk1.8

数据库:Mysql: mysql5.7/redis

应用服务器:Tomcat:  tomcat8.5.31

开发工具:IDEA或eclipse

项目管理工具: maven

三、系统展示

首页

文章分类

标签

登录

发布文章

四、核心代码展示

package com.mszlu.blog.controller;

import com.mszlu.blog.common.aop.LogAnnotation;
import com.mszlu.blog.common.cache.Cache;
import com.mszlu.blog.service.ArticleService;
import com.mszlu.blog.vo.Result;
import com.mszlu.blog.vo.params.ArticleParam;
import com.mszlu.blog.vo.params.PageParams;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

//json数据进行交互
@RestController
@RequestMapping("articles")
public class ArticleController {

    @Autowired
    private ArticleService articleService;
    /**
     * 首页 文章列表
     * @param pageParams
     * @return
     */
    @PostMapping
    //加上此注解 代表要对此接口记录日志
    @LogAnnotation(module="文章",operator="获取文章列表")
    @Cache(expire = 5 * 60 * 1000,name = "listArticle")
    public Result listArticle(@RequestBody PageParams pageParams){
//        int i = 10/0;
        return articleService.listArticle(pageParams);
    }

    /**
     * 首页 最热文章
     * @return
     */
    @PostMapping("hot")
    @Cache(expire = 5 * 60 * 1000,name = "hot_article")
    public Result hotArticle(){
        int limit = 5;
        return articleService.hotArticle(limit);
    }

    /**
     * 首页 最新文章
     * @return
     */
    @PostMapping("new")
    @Cache(expire = 5 * 60 * 1000,name = "news_article")
    public Result newArticles(){
        int limit = 5;
        return articleService.newArticles(limit);
    }

    /**
     * 首页 最新文章
     * @return
     */
    @PostMapping("listArchives")
    public Result listArchives(){
        return articleService.listArchives();
    }

    @PostMapping("view/{id}")
    public Result findArticleById(@PathVariable("id") Long articleId){
        return articleService.findArticleById(articleId);
    }
    //接口url:/articles/publish
    //
    //请求方式:POST
    @PostMapping("publish")
    public Result publish(@RequestBody ArticleParam articleParam){

        return articleService.publish(articleParam);
    }
}
package com.mszlu.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mszlu.blog.dao.dos.Archives;
import com.mszlu.blog.dao.mapper.ArticleBodyMapper;
import com.mszlu.blog.dao.mapper.ArticleMapper;
import com.mszlu.blog.dao.mapper.ArticleTagMapper;
import com.mszlu.blog.dao.pojo.Article;
import com.mszlu.blog.dao.pojo.ArticleBody;
import com.mszlu.blog.dao.pojo.ArticleTag;
import com.mszlu.blog.dao.pojo.SysUser;
import com.mszlu.blog.service.*;
import com.mszlu.blog.utils.UserThreadLocal;
import com.mszlu.blog.vo.ArticleBodyVo;
import com.mszlu.blog.vo.ArticleVo;
import com.mszlu.blog.vo.Result;
import com.mszlu.blog.vo.TagVo;
import com.mszlu.blog.vo.params.ArticleParam;
import com.mszlu.blog.vo.params.PageParams;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private TagService tagService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private ArticleTagMapper articleTagMapper;
    @Override
    public Result listArticle(PageParams pageParams) {
        Page<Article> page = new Page<>(pageParams.getPage(),pageParams.getPageSize());

        IPage<Article> articleIPage = articleMapper.listArticle(
                page,
                pageParams.getCategoryId(),
                pageParams.getTagId(),
                pageParams.getYear(),
                pageParams.getMonth());
        List<Article> records = articleIPage.getRecords();
        return Result.success(copyList(records,true,true));
    }

//    @Override
//    public Result listArticle(PageParams pageParams) {
//        /**
//         * 1. 分页查询 article数据库表
//         */
//        Page<Article> page = new Page<>(pageParams.getPage(),pageParams.getPageSize());
//        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
//        if (pageParams.getCategoryId() != null){
//            // and category_id=#{categoryId}
//            queryWrapper.eq(Article::getCategoryId,pageParams.getCategoryId());
//        }
//        List<Long> articleIdList = new ArrayList<>();
//        if (pageParams.getTagId() != null){
//            //加入标签 条件查询
//            //article表中 并没有tag字段 一篇文章 有多个标签
//            //article_tag  article_id 1 : n tag_id
//            LambdaQueryWrapper<ArticleTag> articleTagLambdaQueryWrapper = new LambdaQueryWrapper<>();
//            articleTagLambdaQueryWrapper.eq(ArticleTag::getTagId,pageParams.getTagId());
//            List<ArticleTag> articleTags = articleTagMapper.selectList(articleTagLambdaQueryWrapper);
//            for (ArticleTag articleTag : articleTags) {
//                articleIdList.add(articleTag.getArticleId());
//            }
//            if (articleIdList.size() > 0){
//                // and id in(1,2,3)
//                queryWrapper.in(Article::getId,articleIdList);
//            }
//        }
//        //是否置顶进行排序
//        //order by create_date desc
//        queryWrapper.orderByDesc(Article::getWeight,Article::getCreateDate);
//        Page<Article> articlePage = articleMapper.selectPage(page, queryWrapper);
//        List<Article> records = articlePage.getRecords();
//        //能直接返回吗? 很明显不能
//        List<ArticleVo> articleVoList = copyList(records,true,true);
//        return Result.success(articleVoList);
//    }

    @Override
    public Result hotArticle(int limit) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Article::getViewCounts);
        queryWrapper.select(Article::getId,Article::getTitle);
        queryWrapper.last("limit "+limit);
        //select id,title from article order by view_counts desc limit 5
        List<Article> articles = articleMapper.selectList(queryWrapper);

        return Result.success(copyList(articles,false,false));
    }

    @Override
    public Result newArticles(int limit) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Article::getCreateDate);
        queryWrapper.select(Article::getId,Article::getTitle);
        queryWrapper.last("limit "+limit);
        //select id,title from article order by create_date desc desc limit 5
        List<Article> articles = articleMapper.selectList(queryWrapper);

        return Result.success(copyList(articles,false,false));
    }

    @Override
    public Result listArchives() {
        List<Archives> archivesList = articleMapper.listArchives();
        return Result.success(archivesList);
    }

    @Autowired
    private ThreadService threadService;

    @Override
    public Result findArticleById(Long articleId) {
        /**
         * 1. 根据id查询 文章信息
         * 2. 根据bodyId和categoryid 去做关联查询
         */
        Article article = this.articleMapper.selectById(articleId);
        ArticleVo articleVo = copy(article, true, true,true,true);
        //查看完文章了,新增阅读数,有没有问题呢?
        //查看完文章之后,本应该直接返回数据了,这时候做了一个更新操作,更新时加写锁,阻塞其他的读操作,性能就会比较低
        // 更新 增加了此次接口的 耗时 如果一旦更新出问题,不能影响 查看文章的操作
        //线程池  可以把更新操作 扔到线程池中去执行,和主线程就不相关了
        threadService.updateArticleViewCount(articleMapper,article);
        return Result.success(articleVo);
    }

    @Override
    public Result publish(ArticleParam articleParam) {
        //此接口 要加入到登录拦截当中
        SysUser sysUser = UserThreadLocal.get();
        /**
         * 1. 发布文章 目的 构建Article对象
         * 2. 作者id  当前的登录用户
         * 3. 标签  要将标签加入到 关联列表当中
         * 4. body 内容存储 article bodyId
         */
        Article article = new Article();
        article.setAuthorId(sysUser.getId());
        article.setWeight(Article.Article_Common);
        article.setViewCounts(0);
        article.setTitle(articleParam.getTitle());
        article.setSummary(articleParam.getSummary());
        article.setCommentCounts(0);
        article.setCreateDate(System.currentTimeMillis());
        article.setCategoryId(Long.parseLong(articleParam.getCategory().getId()));
        //插入之后 会生成一个文章id
        this.articleMapper.insert(article);
        //tag
        List<TagVo> tags = articleParam.getTags();
        if (tags != null){
            for (TagVo tag : tags) {
                Long articleId = article.getId();
                ArticleTag articleTag = new ArticleTag();
                articleTag.setTagId(Long.parseLong(tag.getId()));
                articleTag.setArticleId(articleId);
                articleTagMapper.insert(articleTag);
            }
        }
        //body
        ArticleBody articleBody  = new ArticleBody();
        articleBody.setArticleId(article.getId());
        articleBody.setContent(articleParam.getBody().getContent());
        articleBody.setContentHtml(articleParam.getBody().getContentHtml());
        articleBodyMapper.insert(articleBody);

        article.setBodyId(articleBody.getId());
        articleMapper.updateById(article);
        Map<String,String> map = new HashMap<>();
        map.put("id",article.getId().toString());
        return Result.success(map);
    }

    private List<ArticleVo> copyList(List<Article> records, boolean isTag, boolean isAuthor) {
        List<ArticleVo> articleVoList = new ArrayList<>();
        for (Article record : records) {
            articleVoList.add(copy(record,isTag,isAuthor,false,false));
        }
        return articleVoList;
    }
    private List<ArticleVo> copyList(List<Article> records, boolean isTag, boolean isAuthor, boolean isBody,boolean isCategory) {
        List<ArticleVo> articleVoList = new ArrayList<>();
        for (Article record : records) {
            articleVoList.add(copy(record,isTag,isAuthor,isBody,isCategory));
        }
        return articleVoList;
    }

    @Autowired
    private CategoryService categoryService;

    private ArticleVo copy(Article article, boolean isTag, boolean isAuthor, boolean isBody,boolean isCategory){
        ArticleVo articleVo = new ArticleVo();
        articleVo.setId(String.valueOf(article.getId()));
        BeanUtils.copyProperties(article,articleVo);

        articleVo.setCreateDate(new DateTime(article.getCreateDate()).toString("yyyy-MM-dd HH:mm"));
        //并不是所有的接口 都需要标签 ,作者信息
        if (isTag){
            Long articleId = article.getId();
            articleVo.setTags(tagService.findTagsByArticleId(articleId));
        }
        if (isAuthor){
            Long authorId = article.getAuthorId();
            articleVo.setAuthor(sysUserService.findUserById(authorId).getNickname());
        }
        if (isBody){
            Long bodyId = article.getBodyId();
            articleVo.setBody(findArticleBodyById(bodyId));
        }
        if (isCategory){
            Long categoryId = article.getCategoryId();
            articleVo.setCategory(categoryService.findCategoryById(categoryId));
        }
        return articleVo;
    }

    @Autowired
    private ArticleBodyMapper articleBodyMapper;

    private ArticleBodyVo findArticleBodyById(Long bodyId) {
        ArticleBody articleBody = articleBodyMapper.selectById(bodyId);
        ArticleBodyVo articleBodyVo = new ArticleBodyVo();
        articleBodyVo.setContent(articleBody.getContent());
        return articleBodyVo;
    }

}

五、项目总结

本项目使用技术新,采用最流行的springboot和vue前后端分离。适合大作业中使用。

以上就是SpringBoot前后端分离实现个人博客系统的详细内容,更多关于SpringBoot个人博客系统的资料请关注我们其它相关文章!

(0)

相关推荐

  • Springboot与vue实例讲解实现前后端分离的人事管理系统

    目录 一,项目简介 二,环境介绍 三,系统展示 四,核心代码展示 五,项目总结 一,项目简介 系统是前后端分离的项目,直接启动Springboot应用程序类后,再启动前端工程访问即可.主要实现了企业的人事管理功能,主要包含员工管理.薪资管理.职位管理.权限管理.网盘文件分享管理等模块. 系统亮点:使用REDIS进行数据缓存,优化查询性能:使用分布式文件系统进行文件存储服务:基于Springboot+vue实现前后端分离开发 二,环境介绍 语言环境:Java: jdk1.8 数据库:Mysql:

  • 使用java springboot制作博客管理系统

    目录 前言 需求分析 用户管理. 文章管理. 链接管理. 日志管理. 数据管理. 系统管理. 功能分析 部分表设计 部分代码实现 前言 博客,又译为网络日志. 部落格或部落阁等,是一种通常由个人管理.不定期张贴新的文章的网站. 博客上的文章通常根据张贴时间, 以倒序方式由新到旧排列. 许多博客专注在特定的课题上提供评论或新闻, 其他则被作为比较个人的日记. 一个典型的博客结合了文字.图像. 其他博客或网站的链接. 及其它与主题相关的媒体. 能够让读者以互动的方式留下意见,是许多博客的重要要素.大

  • springboot+VUE前后端分离实现疫情防疫平台JAVA

    目录 主要模块: 系统主要实现如下: 登录之后进入系统首页:目前系统主要功能如下 用户管理模块:用户添加.修改.删除.查询等基本操作 角色管理模块.通过用户绑定角色.角色控制菜单显示.灵活控制菜单. 前端VUE代码添加菜单 菜单添加修改列表层操作 历史行程数据管理:添加修改删除等操作 用户每日健康打卡列表数据展示以及添加打卡信息 员工出行外出报备管理申请 员工复工申请 管理员审核 通知公告模块: 一些设计报告和文档描述参考 数据库连接: 主要模块: 管理员用户登录:用户登录. 用户信息: 用户信

  • Vue+SpringBoot开发V部落博客管理平台

    V部落是一个多用户博客管理平台,采用Vue+SpringBoot开发. 演示地址: http://45.77.146.32:8081/index.html 项目地址: https://github.com/lenve/VBlog 登陆页面 文章列表 发表文章 用户管理 栏目管理 数据统计 技术栈 后端技术栈 后端主要采用了: 1.SpringBoot 2.SpringSecurity 3.MyBatis 4.部分接口遵循Restful风格 5.MySQL 前端技术栈 前端主要采用了: 1.Vue

  • SpringBoot前后端分离实现个人博客系统

    目录 一.项目简介 二.环境介绍 三.系统展示 四.核心代码展示 五.项目总结 一.项目简介 本项目使用springboot+mybatis+前端vue,使用前后端分离架构实现的个人博客系统,共7个模块,首页,写博客,博客详情页,评论管理,文章分类,标签管理和文章归档.该项目没有后端管理功能,比较适合用于大作业! 二.环境介绍 语言环境:Java:  jdk1.8 数据库:Mysql: mysql5.7/redis 应用服务器:Tomcat:  tomcat8.5.31 开发工具:IDEA或ec

  • vue+springboot前后端分离实现单点登录跨域问题解决方法

    最近在做一个后台管理系统,前端是用时下火热的vue.js,后台是基于springboot的.因为后台系统没有登录功能,但是公司要求统一登录,登录认证统一使用.net项目组的认证系统.那就意味着做单点登录咯,至于不知道什么是单点登录的同学,建议去找一下万能的度娘. 刚接到这个需求的时候,老夫心里便不屑的认为:区区登录何足挂齿,但是,开发的过程狠狠的打了我一巴掌(火辣辣的一巴掌)...,所以这次必须得好好记录一下这次教训,以免以后再踩这样的坑. 我面临的第一个问题是跨域,浏览器控制台直接报CORS,

  • shiro整合springboot前后端分离

    本文实例为大家分享了shiro整合springboot前后端分离的具体代码,供大家参考,具体内容如下 1.shiro整合springboot的配置 package com.hisi.config; import java.util.LinkedHashMap; import java.util.Map; import javax.servlet.Filter; import org.apache.shiro.session.mgt.eis.MemorySessionDAO; import org

  • 部署vue+Springboot前后端分离项目的步骤实现

    单页应用 vue经常被用来开发单页应用(SinglePage Web Application,SPA),什么叫做单页应用呢,也就是只有一张web页面的应用,单页应用的跳转只需要刷新局部资源,大大加快的了我们页面的响应速度 前端页面打包 打开vue工程,在项目根目录下创建一个配置文件:vue.config.js,然后在里面写入以下内容: module.exports = { assetsDir: 'static', // 静态资源保存路径 outputDir: 'dist', // 打包后生成的文

  • Vue+SpringBoot前后端分离中的跨域问题

    在前后端分离开发中,需要前端调用后端api并进行内容显示,如果前后端开发都在一台主机上,则会由于浏览器的同源策略限制,出现跨域问题(协议.域名.端口号不同等),导致不能正常调用api接口,给开发带来不便. 封装api请求 import axios from 'axios' //axios.create创建一个axios实例,并对该实例编写配置,后续所有通过实例发送的请求都受当前配置约束 const $http = axios.create({ baseURL: '', timeout: 1000

  • IDEA教程创建SpringBoot前后端分离项目示例图解

    目录 创建springboot项目 测试项目 按照MVC格式创建数据库项目 总结 springboot就是简化Spring应用中的初始化配置,快速创建项目而生的. 创建springboot项目 代开idea,点击File->New->Project,弹出如下对话框 输入组织.工程名,选择maven工程,注意:java版本号选择8 可以根据自己项目的需求选择依赖包,系统会自动将这些依赖包写入maven的pom文件,如下选择Spring Web.myBtias.mySQL驱动等.无需担心漏掉依赖包

  • springBoot前后端分离项目中shiro的302跳转问题

    springBoot前后端分离项目shiro的302跳转 项目是使用的springboot ,使用的shiro做的用户鉴权.在前端请求时当用户信息失效,session失效的时候,shiro会重定向到配置的login.jsp 页面,或者是自己配置的logUrl. 因是前后端分离项目,与静态资源文件分离,固重定向后,接着会404. 经过查找网上配置资料,发现302原因是 FormAuthenticationFilter中onAccessDenied 方法做了相应处理.那知道问题所在,就可以有解决方了

  • SpringBoot前后端分离实现验证码操作

    目录 1.SpringBoot版本 2.引入依赖 3.实现思路 新建验证码枚举类 定义验证码配置信息 定义验证逻辑生成类 在控制层上定义验证码生成接口 效果体验 在前端调用接口 1.SpringBoot版本 本文基于的Spring Boot的版本是2.6.7 . 2.引入依赖 captcha一款超简单的验证码生成,还挺好玩的.还有中文验证码,动态验证码. .在项目中pom.xml配置文件中添加依赖,如下: <!--验证码--> <dependency> <groupId>

  • SpringBoot前后端分离解决跨域问题的3种解决方案总结

    目录 什么是跨域 跨域问题的解决策略 三种解决方法 总结 什么是跨域 想要知道什么是跨域的话,我们可以通过一个小案例简单了解一下跨域的概念:在项目代码编写的时候,我们将前端项目代码和后端的项目代码相分离开,一个运行在本地的8080端口一个运行在本地的8888端口,这也就是我们常说的前后端分离项目.现在使用前端的请求去调用后端的接口,就会产生以下的错误 Access to XMLHttpRequest at 'http://localhost:8888/请求名' from origin ‘http

  • Java前后端分离的在线点餐系统实现详解

    项目功能: 此项目分为两个角色:普通用户和管理员.普通用户有登录注册.浏览商品信息.添加购物车.结算订单.查看个人信息.查看个人订单详情等等功能.管理员有管理所有商品信息.管理所有订单信息.管理所有用户信息.查看收益数据图表等等功能. 应用技术:SpringBoot + VueCli + MySQL + MyBatis + Redis + ElementUI 运行环境:IntelliJ IDEA2019.3.5 + MySQL5.7+ Redis5.0.5 + JDK1.8 + Maven3.6

随机推荐