博客网站源码(基于SpringBoot和Vue的个人博客系统)

今天介绍一个博客项目,是基于SpringBoot和Vue的前后端分离项目,前台界面炫酷无比、科技感十足,后台管理端功能丰富。首页,动态词条首页下方是博客内容炫酷的留言板后台管理界面项目特点前台参考"Hexo"的"Butterfly"设计,美观简洁,响应式体验好。后台参考"element-admin"设计,侧边栏,历史标签,面包屑自动生成。采用Markdown编辑器,写法简单。评论支持表情输入回复等,样式参考Valine。添加音乐播放器,支持在线搜索歌曲。前后端分离部署,适应当前潮流。接入第三方登录,减少注册成本。支持发布说说,随时分享趣事。留言采用弹幕墙,更加炫酷。支持代码高亮和复制,图片预览,深色模式等功能,提升用户体验。搜索文章支持高亮分词,响应速度快。新增文章目录、推荐文章等功能,优化用户体验。新增在线聊天室,支持撤回、语音输入、统计未读数量等功能。新增aop注解实现日志管理。支持动态权限修改,采用RBAC模型,前端菜单和后台权限实时更新。后台管理支持修改背景图片,博客配置等信息,操作简单,支持上传相册。代码支持多种搜索模式(Elasticsearch或MYSQL),支持多种上传模式(OSS或本地),可支持配置。代码遵循阿里巴巴开发规范,利于开发者学习。技术介绍前端: vue + vuex + vue-router + axios + vuetify + element + echarts后端: SpringBoot + nginx + docker + SpringSecurity + Swagger2 + MyBatisPlus + Mysql + Redis + elasticsearch + RabbitMQ + MaxWell + Websocket其他: 接入QQ,微博第三方登录,接入腾讯云人机验证、websocket首页代码展示<template>
<div>
<!– banner –>
<div class="home-banner" :style="cover">
<div class="banner-container">
<!– 联系方式 –>
<h1 class="blog-title animated zoomIn">
{{ blogInfo.websiteConfig.websiteName }}
</h1>
<!– 一言 –>
<div class="blog-intro">
{{ obj.output }} <span class="typed-cursor">|</span>
</div>
<!– 联系方式 –>
<div class="blog-contact">
<a
v-if="isShowSocial('qq')"
class="mr-5 iconfont iconqq"
target="_blank"
:href="
'http://wpa.qq.com/msgrd?v=3&uin=' +
blogInfo.websiteConfig.qq +
'&site=qq&menu=yes'
"
/>
<a
v-if="isShowSocial('github')"
target="_blank"
:href="blogInfo.websiteConfig.github"
class="mr-5 iconfont icongithub"
/>
<a
v-if="isShowSocial('gitee')"
target="_blank"
:href="blogInfo.websiteConfig.gitee"
class="iconfont icongitee-fill-round"
/>
</div>
</div>
<!– 向下滚动 –>
<div class="scroll-down" @click="scrollDown">
<v-icon color="#fff" class="scroll-down-effects">
mdi-chevron-down
</v-icon>
</div>
</div>
<!– 主页文章 –>
<v-row class="home-container">
<v-col md="9" cols="12">
<!– 说说轮播 –>
<v-card class="animated zoomIn" v-if="talkList.length > 0">
<Swiper :list="talkList" />
</v-card>
<v-card
class="animated zoomIn article-card"
style="border-radius: 12px 8px 8px 12px"
v-for="(item, index) of articleList"
:key="item.id"
>
<!– 文章封面图 –>
<div :class="isRight(index)">
<router-link :to="'/articles/' + item.id">
<v-img
class="on-hover"
width="100%"
height="100%"
:src="item.articleCover"
/>
</router-link>
</div>
<!– 文章信息 –>
<div class="article-wrapper">
<div style="line-height:1.4">
<router-link :to="'/articles/' + item.id">
{{ item.articleTitle }}
</router-link>
</div>
<div class="article-info">
<!– 是否置顶 –>
<span v-if="item.isTop == 1">
<span style="color:#ff7242">
<i class="iconfont iconzhiding" /> 置顶
</span>
<span class="separator">|</span>
</span>
<!– 发表时间 –>
<v-icon size="14">mdi-calendar-month-outline</v-icon>
{{ item.createTime | date }}
<span class="separator">|</span>
<!– 文章分类 –>
<router-link :to="'/categories/' + item.categoryId">
<v-icon size="14">mdi-inbox-full</v-icon>
{{ item.categoryName }}
</router-link>
<span class="separator">|</span>
<!– 文章标签 –>
<router-link
style="display:inline-block"
:to="'/tags/' + tag.id"
class="mr-1"
v-for="tag of item.tagDTOList"
:key="tag.id"
>
<v-icon size="14">mdi-tag-multiple</v-icon>{{ tag.tagName }}
</router-link>
</div>
<!– 文章内容 –>
<div class="article-content">
{{ item.articleContent }}
</div>
</div>
</v-card>
<!– 无限加载 –>
<infinite-loading @infinite="infiniteHandler">
<div slot="no-more" />
</infinite-loading>
</v-col>
<!– 博主信息 –>
<v-col md="3" cols="12" class="d-md-block d-none">
<div class="blog-wrapper">
<v-card class="animated zoomIn blog-card mt-5">
<div class="author-wrapper">
<!– 博主头像 –>
<v-avatar size="110">
<img
class="author-avatar"
:src="blogInfo.websiteConfig.websiteAvatar"
/>
</v-avatar>
<div style="font-size: 1.375rem;margin-top:0.625rem">
{{ blogInfo.websiteConfig.websiteAuthor }}
</div>
<div style="font-size: 0.875rem;">
{{ blogInfo.websiteConfig.websiteIntro }}
</div>
</div>
<!– 博客信息 –>
<div class="blog-info-wrapper">
<div class="blog-info-data">
<router-link to="/archives">
<div style="font-size: 0.875rem">文章</div>
<div style="font-size: 1.25rem">
{{ blogInfo.articleCount }}
</div>
</router-link>
</div>
<div class="blog-info-data">
<router-link to="/categories">
<div style="font-size: 0.875rem">分类</div>
<div style="font-size: 1.25rem">
{{ blogInfo.categoryCount }}
</div>
</router-link>
</div>
<div class="blog-info-data">
<router-link to="/tags">
<div style="font-size: 0.875rem">标签</div>
<div style="font-size: 1.25rem">{{ blogInfo.tagCount }}</div>
</router-link>
</div>
</div>
<!– 收藏按钮 –>
<a class="collection-btn" @click="tip = true">
<v-icon color="#fff" size="18" class="mr-1">mdi-bookmark</v-icon>
加入书签
</a>
<!– 社交信息 –>
<div class="card-info-social">
<a
v-if="isShowSocial('qq')"
class="mr-5 iconfont iconqq"
target="_blank"
:href="
'http://wpa.qq.com/msgrd?v=3&uin=' +
blogInfo.websiteConfig.qq +
'&site=qq&menu=yes'
"
/>
<a
v-if="isShowSocial('github')"
target="_blank"
:href="blogInfo.websiteConfig.github"
class="mr-5 iconfont icongithub"
/>
<a
v-if="isShowSocial('gitee')"
target="_blank"
:href="blogInfo.websiteConfig.gitee"
class="iconfont icongitee-fill-round"
/>
</div>
</v-card>
<!– 网站信息 –>
<v-card class="blog-card animated zoomIn mt-5 big">
<div class="web-info-title">
<v-icon size="18">mdi-bell</v-icon>
公告
</div>
<div style="font-size:0.875rem">
{{ blogInfo.websiteConfig.websiteNotice }}
</div>
</v-card>
<!– 网站信息 –>
<v-card class="blog-card animated zoomIn mt-5">
<div class="web-info-title">
<v-icon size="18">mdi-chart-line</v-icon>
网站资讯
</div>
<div class="web-info">
<div style="padding:4px 0 0">
运行时间:<span class="float-right">{{ time }}</span>
</div>
<div style="padding:4px 0 0">
总访问量:<span class="float-right">
{{ blogInfo.viewsCount }}
</span>
</div>
</div>
</v-card>
</div>
</v-col>
</v-row>
<!– 提示消息 –>
<v-snackbar v-model="tip" top color="#49b1f5" :timeout="2000">
按CTRL+D 键将本页加入书签
</v-snackbar>
</div>
</template>

<script>
import Swiper from "../../components/Swiper.vue";
import EasyTyper from "easy-typer-js";
export default {
components: {
Swiper
},
created() {
this.init();
this.listHomeTalks();
this.timer = setInterval(this.runTime, 1000);
},
data: function() {
return {
tip: false,
time: "",
obj: {
output: "",
isEnd: false,
speed: 300,
singleBack: false,
sleep: 0,
type: "rollback",
backSpeed: 40,
sentencePause: true
},
articleList: [],
talkList: [],
current: 1
};
},
methods: {
// 初始化
init() {
document.title = this.blogInfo.websiteConfig.websiteName;
// 一言Api进行打字机循环输出效果
fetch("https://v1.hitokoto.cn?c=i")
.then(res => {
return res.json();
})
.then(({ hitokoto }) => {
this.initTyped(hitokoto);
});
},
listHomeTalks() {
this.axios.get("/api/home/talks").then(({ data }) => {
this.talkList = data.data;
});
},
initTyped(input, fn, hooks) {
const obj = this.obj;
// eslint-disable-next-line no-unused-vars
const typed = new EasyTyper(obj, input, fn, hooks);
},
scrollDown() {
window.scrollTo({
behavior: "smooth",
top: document.documentElement.clientHeight
});
},
runTime() {
var timeold =
new Date().getTime() –
new Date(this.blogInfo.websiteConfig.websiteCreateTime).getTime();
var msPerDay = 24 * 60 * 60 * 1000;
var daysold = Math.floor(timeold / msPerDay);
var str = "";
var day = new Date();
str += daysold + "天";
str += day.getHours() + "时";
str += day.getMinutes() + "分";
str += day.getSeconds() + "秒";
this.time = str;
},
infiniteHandler($state) {
let md = require("markdown-it")();
this.axios
.get("/api/articles", {
params: {
current: this.current
}
})
.then(({ data }) => {
if (data.data.length) {
// 去除markdown标签
data.data.forEach(item => {
item.articleContent = md
.render(item.articleContent)
.replace(/<\/?[^>]*>/g, "")
.replace(/[|]*\n/, "")
.replace(/&npsp;/gi, "");
});
this.articleList.push(…data.data);
this.current++;
$state.loaded();
} else {
$state.complete();
}
});
}
},
computed: {
isRight() {
return function(index) {
if (index % 2 == 0) {
return "article-cover left-radius";
}
return "article-cover right-radius";
};
},
blogInfo() {
return this.$store.state.blogInfo;
},
isShowSocial() {
return function(social) {
return this.blogInfo.websiteConfig.socialUrlList.indexOf(social) != -1;
};
},
cover() {
var cover = "";
this.$store.state.blogInfo.pageList.forEach(item => {
if (item.pageLabel == "home") {
cover = item.pageCover;
}
});
return "background: url(" + cover + ") center center / cover no-repeat";
}
}
};
</script>
获取源码请关注后私信“分离博客”

本文出自快速备案,转载时请注明出处及相应链接。

本文永久链接: https://kuaisubeian.cc/43594.html

kuaisubeian