最近在学习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;
现在的程度只能做到这样子,希望以后的学习中会不断优化。