最近在学习MEAN全栈开发的过程中,写了一个小程序就当练练手熟悉一下怎么去组合强大的功能。

废话不多说,直接上文件预览:

整体文件结构:

其中,public文件夹存放了img,js,css文件,其中的index.js文件用于配置前台路由,routes文件夹存放了后台路由的配置文件,views文件夹存放静态视图文件,app.js文件作为程序的入口,相当于main函数一样。

前台路由设置:

public/javascripts/index.js

/*前端路由处理*/
//创建服务
var blogServices = angular.module('blogServices', ['ngResource']);
//Blog代表上述服务
blogServices.factory('Blog', ['$resource',
function($resource){
return $resource('/api/list/:_id', {_id: '@id'},
{
//默认提供5种方法,在此可以自定义方法;
}
);
}]); //在模板中注入模块
var app = angular.module('app', [
'ngRoute',
'blogServices'
]); app.directive('focus', function () {
return {
restrict: 'A',//限制只可通过属性调用
link: function (scope, element, attr) {
element[0].focus();
}
}
}); app.config(function ($routeProvider) {
$routeProvider.
//自动忽略前面的#
when('/', {
templateUrl: 'posts.html',// 当打开链接为 "/", 载入posts.html
controller: postsCtrl
}).
//add
when('/api/add', {
templateUrl: 'add.html',
controller: postCtrl
}).
//read
when('/api/list/:_id',{
templateUrl: 'read.html',
controller: readCtrl
}).
//modify
when('/api/modify/:_id', {
templateUrl: 'modify.html',
controller: editCtrl
}).
//delete
when('/api/del/:_id',{
templateUrl: 'posts.html',
controller: deleteCtrl
});
//otherwise({
// redirectTo: '/' // 其他情况,跳到链接"/"
//});
}); /* 每个路由对应的控制器 */
// 文章列表控制器
// 注入Blog服务
function postsCtrl($scope,Blog) {
//去后端访问route.get('/list'),返回查找的数据
$scope.posts = Blog.query();
} // 发布文章控制器
function postCtrl($scope, Blog, $location) { // 注入$location服务
$scope.form = {}; // 初始化一个数据模型
// 提交操作函数
$scope.form.submit = function () {
Blog.save({}, $scope.form,function(){
$location.url('/'); // 返回首页;
});
};
} // 读取文章控制器
function readCtrl($scope, Blog, $routeParams){
// 将获取到的数据 通过$scope绑定成NG的数据模型
$scope.post = Blog.get({_id:$routeParams._id});
} //删除文章控制器
function deleteCtrl($scope, Blog, $location, $routeParams){
Blog.delete({_id:$routeParams._id},function(){
$location.url('/'); // 返回首页;
});
} // 修改文章控制器
function editCtrl($scope, Blog, $routeParams, $location) {
//向后台申请数据,写入post模型
$scope.post = Blog.get({_id:$routeParams._id});
// 提交操作函数
$scope.submit = function () {
Blog.save({_id: $routeParams._id},$scope.post,function(){
$location.url('/'); // 返回首页
});
};
} /* $http方法 */
/* 文章列表控制器
function postsCtrl($scope, $http) { // 注入$Http服务,类似于jquery的ajax
//去后端访问route.get('/list'),返回查找的数据
$http.get('/api/list').success(function (data) {
$scope.posts = data; // 将获得的数据保存到NG的数据模型posts里
});
}
发布文章控制器
function postCtrl($scope, $http, $location) { // 注入$location服务
$scope.form = {}; // 初始化一个NG数据模型
// 提交操作函数
$scope.form.submit = function () {
$http.post('/api/add', $scope.form).success(function () {
$location.url('/'); // 返回首页
});
};
}
// 读取文章控制器
function readCtrl($scope,$http, $routeParams){
$http.get('/api/list/' + $routeParams._id).success(function(data){
$scope.post = data; // 将获取到的数据 通过$scope绑定成NG的数据模型
});
}
// 修改文章控制器
function editCtrl($scope, $http, $routeParams, $location) { // 注入$location服务
//向后台申请数据
$http.get('/api/modify/' + $routeParams._id).success(function (data){
//将数据存入post
$scope.post = data;
}); $scope.form = {}; // 初始化一个NG数据模型
// 提交操作函数
$scope.form.submit = function () {
$http.post('/api/modify/' + $routeParams._id, $scope.post).success(function () {
$location.url('/'); // 返回首页
});
};
} //删除文章控制器
function deleteCtrl($scope, $http, $location, $routeParams){
$http.get('/api/del/' + $routeParams._id).success(function () {
$location.url('/'); // 返回首页
});
}*/ // 启动模块
angular.bootstrap(document, ['app']);

用了两种方法去实现,开始用了$http去写路由(见注释部分),最后改为使用$resource去管理API,这里需要注意一点,只用服务端按照RESTful的方式工作的时候,才可以使用Angular资源。

服务端路由

/routes/index.js

'use strict';
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var model = require('./model');
var Demo = model.Demo;
mongoose.connect('mongodb://localhost/monkey');
/*这里的路由是用来处理访问为'xxx'的请求*/
/* 查找数据库数据.*/
router.get('/api/list',function(req,res,next){
console.log("This is finding data!");
Demo.find({}).sort({createTime: -1}).exec(function (err, docs) {
res.json(docs);
});
}); /*跳转到添加页面,创建新纪录*/
router.post('/api/list',function(req, res){
var demo = new Demo(req.body);
demo.save(function(err,doc){
if (err) {
console.log(err);
res.send(err);
}
else {
console.log('create');
console.log(doc);
res.json({status: 'done'});
}
});
}); //根据id查找相应的记录
router.get('/api/list/:_id',function(req,res){
var id = req.params._id;
console.log(id);
console.log('Now start to read!');
if(id) {
//返回文档
Demo.findOne({_id: id}).exec(function (err, docs) {
console.log(docs);
res.json(docs);
});
}
}); // 根据id删除相应的记录
router.delete('/api/list/:_id',function(req, res){
var id = req.params._id;
console.log('delete');
console.log(id);
if(id) {
console.log('delete id = ' + id);
Demo.findByIdAndRemove(id, function(err, docs) {
console.log(docs);
res.json(docs);
});
}
}); /*查询对应修改记录,并跳转到修改页面
router.get('/api/modify/:_id',function(req, res) {
var id = req.params._id;
console.log('id = ' + id);
console.log('Now start to modify!');
Demo.findOne({_id: id}).exec(function (err, docs) {
console.log(docs);
res.json(docs);
});
});*/ //修改相应的值
router.post('/api/list/:_id',function(req, res) {
var demo = new Demo(req.body);
var id = req.params._id; //因为是post提交,所以不用query获取id
if(id) {
console.log('----update');
console.log(demo);
Demo.findByIdAndUpdate(id, demo,function(err, docs) {
res.json({status: 'done'});
});
}
}); module.exports = router;

  这里的作用是来处理对应URL的前台访问,作为对应的处理函数。

定义数据库

/routes/model.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema; var demoSchema = new Schema({
uid : {
required:true,
type:String,
unique:true,
trim:true
},
title: {
type:String,
required:true
},
content: {
type:String,
required:true
},
createTime : {
type: Date,
default: Date.now
}
}); Demo = mongoose.model('Demo',demoSchema);
exports.Demo = Demo;

视图文件

views//index.html

<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>MAEN BLOG</title>
<link rel="stylesheet" href="stylesheets/common.css" />
<link rel="stylesheet" href="stylesheets/index.css" />
</head>
<body>
<header>
<h1 id="logo"><a href="#">BLOG List</a></h1>
</header> <div id="main">
<!-- 路由区域 -->
<ng-view />
</div> <!-- javascript-->
<script src="javascripts/plugins/angular/angular.min.js" type="text/javascript"></script>
<script src="javascripts/plugins/angular-route/angular-route.min.js" type="text/javascript"></script>
<script src="javascripts/plugins/angular-resource/angular-resource.js" type="text/javascript"></script>
<script src="javascripts/index.js"></script>
</body>
</html>

views/add.html

<form id="post" ng-submit="form.submit()">
<input ng-model="form.uid" focus type="text" placeholder="文章ID" />
<input ng-model="form.title" type="text" placeholder="标题" />
<textarea ng-model="form.content" placeholder="正文"></textarea>
<div>
<button class="btn btn-danger pull-right" type="submit">提交发布</button>
</div>
</form>

views/modify.html

<form id="modify" ng-submit="submit()">
<div>
<div>{{post.createTime|date: 'yyyy-MM-dd HH:mm:ss'}}</div>
<input ng-model="post.title" focus type="text">
<textarea ng-model="post.content"></textarea>
<div>
<button class="btn btn-danger pull-right" type="submit">save</button>
</div>
</div>
</form>

views/posts.html

<table>
<tr>
<th>题目 -
<button class="btn btn-danger"><a href="/#/api/add">发表文章</a></button>
</th>
<th>时间</th>
<th></th>
<th></th>
</tr> <!-- ng-repeat可以根据NG数据模型遍历数据,相当于forEeach -->
<tr ng-repeat="post in posts">
<td><a href="/#/api/list/{{post._id}}">{{ post.title }}</a></td>
<!-- 用filter过滤器,转换了显示的时间格式 -->
<td class="text-muted">{{ post.createTime|date: 'yyyy-MM-dd HH:mm:ss'}}</td>
<td><a href="/#/api/modify/{{post._id}}">修改</a></td>
<td><a href="/#/api/del/{{post._id}}">删除</a></td>
</tr> <!-- ng-hide表示,当文章列表有内容,将不显示这里 -->
<tr ng-hide="posts.length">
<td colspan="2" class="text-muted text-center">没有文章哦</td>
</tr>
</table>

views/read.html

<form id="read" ng-submit="form.submit()">
<div>
<div>
{{post.createTime|date: 'yyyy-MM-dd HH:mm:ss'}}
</div>
<div>
<input ng-model="post.title" focus type="text">
</div>
<textarea ng-model="post.content"></textarea>
<div>
<a href="#" class="pull-right">back</a>
</div>
</div>
</form>

引导文件

app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser'); var routes = require('./routes');
var user = require('./routes/user');
var http = require('http');
var ejs = require('ejs');
var app = express(); // view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'html');
app.engine('html',ejs.__express); // uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'views')));
app.use('/',routes);
app.use('/users',user.list); // 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
});
});
} // production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;

  

现在的程度只能做到这样子,希望以后的学习中会不断优化。

MEAN 全栈开发 ——实现简单博客的更多相关文章

  1. python 全栈开发,Day81(博客系统个人主页,文章详情页)

    一.个人主页 随笔分类 需求:查询当前站点每一个分类的名称以及对应的文章数 完成这个需求,就可以展示左侧的分类 它需要利用分组查询,那么必须要会基于双下划线的查询. 基于双下划线的查询,简单来讲,就是 ...

  2. python 全栈开发,Day83(博客系统子评论,后台管理,富文本编辑器kindeditor,bs4模块)

    一.子评论 必须点击回复,才是子评论!否则是根评论点击回复之后,定位到输入框,同时加入@评论者的用户名 定位输入框 focus focus:获取对象焦点触发事件 先做样式.点击回复之后,定位到输入框, ...

  3. python 全栈开发,Day80(博客系统分析,博客主页展示)

    一.博客系统分析 数据库的构建 首先,我们分析一个博客系统的功能: 一个博客可以有多个标签(多对多) 一个博客可以有多条评论(一对多) 一个博客只可以有一个类别(多对一) 接下来,我们分析关系的属性: ...

  4. Java 全栈知识体系 - 个人博客

    摘自:https://www.pdai.tech/ 著作权归https://www.pdai.tech所有. 链接:https://www.pdai.tech/ Java 全栈知识体系 包含: Jav ...

  5. python全栈开发day61-django简单的出版社网站展示,添加,删除,编辑(单表的增删改查)

    day61 django内容回顾: 1. 下载: pip install django==1.11.14 pip install -i 源 django==1.11.14 pycharm 2. 创建项 ...

  6. .NET全栈开发工程师学习路径

    PS:最近一直反复地看博客园以前发布的一条.NET全栈开发工程师的招聘启事,觉得这是我看过最有创意也最朴实的一个招聘启事,更为重要的是它更像是一个技术提纲,能够指引我们的学习和提升,现在转载过来与各位 ...

  7. Meteor全栈开发平台 - 不仅仅是前端

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,博客地址为http://www.cnblogs.com/jasonnode/ .网站上有对应每一 ...

  8. Python全栈开发

    Python全栈开发 一文让你彻底明白Python装饰器原理,从此面试工作再也不怕了. 一.装饰器 装饰器可以使函数执行前和执行后分别执行其他的附加功能,这种在代码运行期间动态增加功能的方式,称之为“ ...

  9. Meteor全栈开发平台

    Meteor全栈开发平台 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,博客地址为http://www.cnblogs.com/jasonno ...

随机推荐

  1. Java--谈一谈代理

    一.代理概念    代理在我们日常生活经常听到这个名词,比如我们想看下google我们需要找个代理服务器来帮我们一下,比如我们想买一个外国的什么东西需要在代购网站或者找朋友帮忙在外国买一下,用概念一点 ...

  2. HDU X mod f(x)(题解注释)

    X mod f(x) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  3. struts2运行过程(图解)

    .................................................................................................... ...

  4. C#提取字符串中的数字字符串

    1               }

  5. linux操作系统基础篇(六)

    linux服务篇 1.samba服务的搭建 samba的功能: samba是一个网络服务器,用于Linux和Windows之间共享文件.2. samba服务的启动.停止.重启service smb s ...

  6. (转)Ubuntu 12.04 中安装和配置 Java JDK

    http://www.cnblogs.com/bluestorm/archive/2012/05/10/2493592.html 先去 Oracle下载Linux下的JDK压缩包,我下载的是jdk-7 ...

  7. Python返回Json格式定义的例子

    { "code": 0, // code为0表示成功,否则为1 "message": null, "data": { "syscp ...

  8. Facebook-Haystack合并小文件

    1.原文 https://www.usenix.org/legacy/event/osdi10/tech/full_papers/Beaver.pdf 2.翻译版 http://www.importn ...

  9. iOS推送,看这篇足够了

    一.注册推送: - (void)registerNotification { if ([[[UIDevice currentDevice] systemVersion] floatValue] > ...

  10. 基于 HTML5 WebGL 的 3D “弹力”布局

    分子力(molecular force),又称分子间作用力.范得瓦耳斯力,是指分子间的相互作用.当二分子相距较远时,主要表现为吸引力,这种力主要来源于一个分子被另一个分子随时间迅速变化的电偶极矩所极化 ...