10个基于java的cms网站内容管理系统(最初实际上数据库数据库数据库)
优采云 发布时间: 2022-02-25 09:2610个基于java的cms网站内容管理系统(最初实际上数据库数据库数据库)
这个项目最初实际上是别人项目的一个分支。一开始是想接触一下mongodb数据库,找了个例子来学习。后来我改了,改得面目全非。后台和数据库进行了重构,前端增加了登录和注册功能,只保留了博客设置页面,但也进行了优化。css
1、功能 基本的博客内容管理器功能,如发布和管理文章等 每个用户都可以通过注册拥有自己的博客 支持markdown语法编辑 支持代码高亮 管理博客页面连接的能力博客页面适配移动端,优化账号管理(修改密码)页面足够大气酷炫。嘿嘿2、用到的技术和实现思路:2.1前端:Vue全家桶2.2后端2.3工具和语言2.4总体思路:
因此,前后端几乎是完全解耦的,只要约定了restful风格的数据接口和数据访问格式即可。html
后端我使用了mongoDB作为数据库,在Express中通过mongoose操作mongoDB,省去了复杂的命令行,通过Javascript操作无疑方便了很多。前端
3、更新
在原项目的基础上做了以下更新:vue
重新设计了数据库,改变了基于用户组的subDocs数据库结构。重新设计所有界面,采用与网易即时理财一致的界面风格,删除原有的旅游模式,增加登录注册功能,支持弹窗登录。增加首页、显示最新发布的文章和注册用户修改密码、登出、登出等功能。优化弹窗组件,更智能,配置项更多,接近网易$.dialog组件。而一组代码只修改了css,实现了PC端的弹窗和wap端的toast在同一个界面下。增加移动端适配,优化原代码,修复部分bug。
如需更多更新,请移至项目 cms-of-Blog_Production 和 cms-of-Blog。jQuery
4、核心代码分析
原作者还写了过度解析的文章。在这里,我主要分析我更新的部分。混帐
4.1. 数据库
原来的数据库经过重新设计,改为按用户分组的subDocs数据库结构。这样与用户为一体的数据库结构更加清晰,操作和阅读也更加方便。代码如下:github
var mongoose = require('mongoose'),
Schema = mongoose.Schema
articleSchema = new Schema({
title: String,
date: Date,
content: String,
}),
linkSchema = new Schema({
name: String,
href: String,
newPage: Boolean
}),
userSchema = new Schema({
name: String,
password: String,
email: String,
emailCode: String,
createdTime: Number,
articles: [articleSchema],
links: [linkSchema]
}),
User = mongoose.model('User', userSchema);
mongoose.connect('mongodb://localhost/platform')
mongoose.set('debug', true)
var db = mongoose.connection
db.on('error', function () {
console.log('db error'.error)
})
db.once('open', function () {
console.log('db opened'.silly)
})
module.exports = {
User: User
}
复制代码
在代码的开头,定义了三个新的 Schema:articleSchema、linkSchema 和 userSchema。在 userSchema 中,articleSchema 和 linkSchema 嵌套在一起,形成了一个按用户分组的 subDocs 数据库结构。Schema是以文件形式存储的数据库模型骨架,不具备操作数据库的能力。然后该模式将作为模型发布。Model 是 Schema 发布的模型,它具有用于数据库操作的抽象属性和行为。Model 可以创建的实体,比如新注册的用户会创建一个实体。网络
数据库建立后,需要进行读取和操作。您可以在注册期间看到发送电子邮件验证码的代码。阿贾克斯
router.post('/genEmailCode', function(req, res, next) {
var email = req.body.email,
resBody = {
retcode: '',
retdesc: '',
data: {}
}
if(!email){
resBody = {
retcode: 400,
retdesc: '参数错误',
}
res.send(resBody)
return
}
function genRandomCode(){
var arrNum = [];
for(var i=0; i 0){
res.render('main', { title: 'CMS-blog' });
}else{
// 自定义错误处理
res.status(403);
res.render('error', {
message: '该用户还没有开通博客。去注册',
});
}
})
})
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
module.exports = app;
复制代码
具体的ajax接口代码可以看server文件夹下的index.js文件。
4.3. 弹出/吐司组件
在原项目的基础上,对弹窗组件进行了优化,更加智能,配置项更多,接近网易$.dialog组件。于是和一组代码只修改了css,实现了同一界面下的pc端弹窗和wap端吐司功能。由于部分格式化参数代码在vuex action中,如果有时间,可以进一步整理成vue组件,方便大家使用。
4.3.1 pop/toast组件配置参数说明4.3.2 pop/toast组件代码
模板
+
{{getPopPara.title}}
{{{getPopPara.content}}}
{{getPopPara.btn1Text}}
{{getPopPara.btn2Text}}
复制代码
脚本
import {pop} from '../vuex/actions'
import {getPopPara} from '../vuex/getters'
import $ from '../js/jquery.min'
export default{
computed:{
showDialog(){
return this.getPopPara.pop
}
},
vuex: {
getters: {
getPopPara
},
actions: {
pop
}
},
methods: {
fn1(){
let fn = this.getPopPara.cb1
let closePop = false
// 若是cb1函数没有明确返回true,则默认按钮点击后关闭弹窗
if(typeof fn == 'function'){
closePop = fn()
}
// 初始值为false, 因此没传也默认关闭
if(!closePop){
this.pop()
}
// !fn && this.pop()
},
fn2(){
let fn = this.getPopPara.cb2
let closePop = false
// 若是cb1函数没有明确返回true,则默认按钮点击后关闭弹窗
if(typeof fn == 'function'){
closePop = fn()
}
// 初始值为false, 因此没传也默认关闭
if(!closePop){
this.pop()
}
// !fn && this.pop()
},
handleClose(){
// this.pop()要放在最后,由于先执行全部参数就都变了
let fn = this.getPopPara.closeFn
typeof fn == 'function' && fn()
this.pop()
}
},
watch:{
'showDialog': function(newVal, oldVal){
// 弹窗打开时
if(newVal){
// 增长弹窗支持键盘操做
$(document).bind('keydown', (event)=>{
// 回车键执行fn1,会出现反复弹窗bug
if(event.keyCode === 27){
this.pop()
}
})
var $dialog = $('.dialog-wrap');
// 移动端改为相似toast,经过更改样式,既不须要增长toast组件,也不须要更改代码,统一pop方法
if(screen.width < 700 && !this.getPopPara.wapGoDialog){
$dialog.addClass('toast-wrap');
setTimeout(()=>{
this.pop();
$dialog.removeClass('toast-wrap');
}, 2000)
}
//调整弹窗居中
let width = $dialog.width();
let height = $dialog.height();
$dialog.css('marginTop', - height/2);
$dialog.css('marginLeft', - width/2);
// 弹窗创建的初始化函数
let fn = this.getPopPara.init;
typeof fn == 'function' && fn();
}else{
// 弹窗关闭时
// 注销弹窗打开时注册的事件
$(document).unbind('keydown')
// 弹窗消失回调
let fn = this.getPopPara.destroy
typeof fn == 'function' && fn()
}
}
}
}
复制代码
4.3.3 pop/toast组件参数格式化代码
为了使用方便,我们在使用时将其缩写。为了让组件被识别,需要在 vuex action 中格式化传入的参数。
<p>function pop({dispatch}, para) {
// 若是没有传入任何参数,默认关闭弹窗
if(para === undefined){
para = {}
}
// 若是只传入字符串,格式化内容为content的para对象
if(typeof para === 'string'){
para = {
content: para
}
}
// 设置默认值
para.pop = !para.content? false: true
para.showClose = para.showClose === undefined? true: para.showClose
para.title = para.title === undefined? '舒适提示': para.title
para.wapGoDialog = !!para.wapGoDialog
// 没有传参数
if(!para.btn1){
para.btn1 = '我知道了|normal'
}
// 没有传class
if(para.btn1.indexOf('|') === -1){
para.btn1 = para.btn1 + '|primary'
}
let array1 = para.btn1.split('|')
para.btn1Text = array1[0]
// 可能会传多个class
for(let i=1,len=array1.length; i