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