MEAN 全栈开发 ——实现简单博客

最近在学习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;

  

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

时间: 2024-10-10 15:11:41

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

基于MEAN全栈架构的多用户博客系统(Angular2+Node+MongoDB)

基于MEAN全栈架构的多用户博客系统(Angular2+Node+MongoDB)课程学习地址:http://www.xuetuwuyou.com/course/223课程出自学途无忧网:http://www.xuetuwuyou.com 课程介绍一.课程简介MEAN是一个Javascript平台的现代Web开发框架总称,它是MongoDB + Express +AngularJS + NodeJS 四个框架的第一个字母组合.它与传统LAMP一样是一种全套开发工具的简称.本课程结合项目全面系统的

Python全栈开发

Python全栈开发 一文让你彻底明白Python装饰器原理,从此面试工作再也不怕了. 一.装饰器 装饰器可以使函数执行前和执行后分别执行其他的附加功能,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator),装饰器的功能非常强大,但是理解起来有些困难,因此我尽量用最简单的例子一步步的说明这个原理. 1.不带参数的装饰器 假设我定义了一个函数f,想要在不改变原来函数定义的情况下,在函数运行前打印出start,函数运行后打印出end,要实现这样一个功能该怎么实现?看下面如何用

PYTHON高级全栈开发工程师-老男孩教育

PYTHON高级全栈开发工程师 最近开班日期:2016年4月17号                               课程周期:4至4.5个月 学习方式:全脱产面授学习(周一至周五,早9:30-晚9:00) 课程收费:RMB15800 适用人群:应届专科.本科毕业生及其它对从事编程开发感兴趣的人群 学员年龄:18-30岁之间 平均就业工资:8-12K 课程咨询QQ:41117397  70271111  80042789  41117483      技术讨论群:         Py

spring boot + vue + element-ui全栈开发入门——开篇

最近经常看到很多java程序员朋友还在使用Spring 3.x,Spring MVC(struts),JSP.jQuery等这样传统技术.其实,我并不认为这些传统技术不好,而我想表达的是,技术的新旧程度体现了做项目时的生产力.生产力低了,项目的开发成本就高.反之,生产力高,则成本低.笔者写本系列的目的是让使用“前后端不分离”的老技术的开发者做一个入门级的过度.因为目前流行的“前后端分离”技术足够简单,足够方便,足够易学,也足够完善. 项目所使用的前端技术是:element-ui,文档地址是:ht

实习模块vue+java小型全栈开发(三)

实习模块vue+java小型全栈开发(三) --dx 背景 首先,先给自己一个答案:这篇博客我定义为(三),因为之前的两个模块页面,内容都是一样的,但是被改了几次需求,就一直拖着没有上传. 今天是真正意义上的全栈开发,用的都是当前市面上的最新的框架前端是vuejs,后端springBoot全家桶,知识点很全,而我正好勉强的把前端知识赶完,然后进行的这次模块开发,并且这次模块开发给了我很大的惊喜. 全栈果然很神奇. 模块简介:点击考勤之后,调到一个页面,完成这个页面的所用功能. 完成之后的页面:我

未来物联网全栈开发 —— JavaScript OR Python?

物联网开发涉及面庞杂,开发周期长,所以我们必须寻找一种覆盖面广的编程语言和方法. JavaScript 支持 HTTP 和 JSON .支持函数式编程.可提供交互式环境等特点堪称适用于物联网全栈开发: Python 作为一种胶水语言,可在物联网及嵌入式系统中承担大量任务,并部分替代以上语言. ??物联网是新一代信息技术的重要组成部分,也是"信息化"时代的重要发展阶段,不太清楚的可以看上篇文章<IoT领域的故事.经历.技术实战>,正所谓语言无国度,无论是 Js 还是 Pyth

JavaScript —— 下一代物联网全栈开发

作者简介:李知周,中国科学院微系统与信息技术研究所博士,物联网早期创业者,发起了开源物联网项目 Openfpgaduino,目前在国际知名投资银行从事基于大数据与机器学习的网络安全开发. 本文为<程序员>杂志原创文章,未经授权,请勿转载 关注公众号"CSDN 物联网开发"微信公众号,了解更多物联网资讯与干货 Jeff Atwood 曾提出"任何能够用 JavaScript 实现的应用,最终都必将用 JavaScript 实现"他对 JavaScript

全栈开发必备的10款Sublime Text 插件

全栈开发必备的10款Sublime Text 插件 来源:梦想天空博客园   时间:2014-11-28 10:16:28   阅读数:673734 分享到:14 [导读] Sublime Text 具有漂亮的用户界面和强大的功能,例如代码缩略图,多重选择,快捷命令等.Sublime Text 更妙的是它的可扩展性.所以,这里挑选了全栈开发必备的10款 Sublime Text 插件,让本已精彩的编辑器更加好用,全端开发的码农们不用去网上一个个找了,赶紧收藏起来吧. Sublime Text 具

Redux+React Router+Node.js全栈开发

详情请交流  QQ  709639943 01.Java深入微服务原理改造房产销售平台 02.跨平台混编框架 MUI 仿豆瓣电影 APP 03.Node.js入门到企业Web开发中的应用 04.Redux+React Router+Node.js全栈开发 05.Java秒杀系统方案优化 高性能高并发实战 06.企业级刚需Nginx入门,全面掌握Nginx配置+快速搭建高可用架构 07.快速上手Linux 玩转典型应用 08.全面系统讲解CSS 工作应用+面试一步搞定 09.Java Spring