前端全栈从零单排项目实战 -- 注册登陆

想做一个微笑明信片:)边做边总结点吧
前端要实现注册登陆,创建明信片,上传分享到首页的明信片精选,用户可以互相关注、点赞互动。
后台实现对用户管理及用户作品的增删该查,进行运营统计。
项目地址:
前端:https://github.com/woaigmz/postcard
后台:https://github.com/woaigmz/mp
欢迎大家fork star 提出建议,感谢:)

前端全栈从零单排项目实战 -- 注册登陆_第1张图片
wx.gif

出门装(环境):

①node(自带npm)
mac:通过homebrew 安装 node

安装homebrew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
安装node
brew install node

win:https://nodejs.org/en/download/
②vscode(code - debug)强大的调试功能,node后台的利器
https://code.visualstudio.com/
③chrome
最新版通过科学上网工具下载
④mongodb
mac:

brew install mongodb

配置:https://github.com/woaigmz/woaigmz/blob/master/mongodb-mac
win:http://dl.mongodb.org/dl/win32/x86_64
配置:https://github.com/woaigmz/woaigmz/blob/master/mongodb-win
mongon 可视化工具 https://robomongo.org/download

对线装 :

①cnpm

npm install -g cnpm --registry=https://registry.npm.taobao.org

②webpack

可单独安装,vue-cli安装的不是最新的
cnpm install webpack -g

③vue-cli脚手架,用于帮助搭建所需的模板框架

cnpm install --global vue-cli

④vue全家桶(vue-router,vue-resource,vuex)

建议安装到本地npm install xxx --save  //cd 到 项目目录下
cnpm install vue-router --save
cnpm install vue-resource --save
cnpm install vuex --save

前端

创建项目:

首先我们要通过vue-cli脚手架创建一个项目:


前端全栈从零单排项目实战 -- 注册登陆_第2张图片
create.PNG

目录结构:


前端全栈从零单排项目实战 -- 注册登陆_第3张图片
structural.PNG

入口是main.js 引入项目所需组件:
element-ui :http://element-cn.eleme.io/#/zh-CN/component/installation

import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import VueResource from 'vue-resource'

Vue.config.productionTip = false

Vue.use(ElementUI);
Vue.use(VueResource);

/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: ''
})
vue-router的使用:

App.vue可以直接作为放置路由界面的容器: 没有的话配置router没用






router/index.js 引入页面,配置路由,可以潜逃,具体官网 https://router.vuejs.org/zh/guide/

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import home from '@/components/HomePage'
import personal from '@/components/PersonalPage'
import toolbar from '@/components/Toolbar'

Vue.use(Router)

export default new Router({
 mode:'history',//可设置模式
 routes: [
   {
     path: '/',
     name: 'home',
     component: home
   },
   {
     path: '/home',
     name: 'home',
     component: home
   },
   {
     path: '/personal',
     name: 'personal',
     component: personal
   },
   {
     path: '/toolbar',
     name: 'toolbar',
     component: toolbar
   },
   {
     path: '/hello',
     name: 'HelloWorld',
     component: HelloWorld
   }
 ]
})

配置路由,使用方法 =>
代码方式:

 goPersonalPage: function() {
     console.log(this);
     this.$router.push({ path: "/personal" });
   },
element-ui使用:HomePage.vue

注意,标签是element-ui的不可再使用class,要用id设置,否则会出现一些问题,需要看element-ui源码

vueresource使用:

register函数:es6的Promise暂时没看到,后面再优化代码

register: function() {
     var that = this;
     this.user_form.name = this.input_name;
     this.user_form.password = this.input_pwd;

     if (utils.isEmpty(this.input_name) || utils.isEmpty(this.input_pwd)) {
       that.showSnap("error", "输入格式错误");
       console.log("111");
     } else {
       this.$http
         .post("http://localhost:3001/api/register", this.user_form)
         .then(
           response => {
             if (response.ok) {
               if (
                 !utils.isEmpty(response.body.data.name) &&
                 !utils.isEmpty(response.body.data.password)
               ) {
                 if (response.body.code == "201") {
                   that.showSnap("warning", response.body.message);
                 } else {
                   that.showSnap("success", response.body.message);
                   //TODO:登陆
                   that.login_form.name = response.body.data.name;
                   that.login_form.password = response.body.data.password;
                   that.login_form.token = response.body.data.token;
                   that.login();
                 }
               } else {
                 that.showSnap("success", "响应格式错误");
               }
             }
           },
           () => {
             that.showSnap("error", "注册失败,请检查网络连接");
           }
         );
     }
   },

后台

express + mongoess +mongodb +body-parser(没有这个无法解析body)

入口app.js
const express  = require('express');
const mongooes = require('mongoose');
const bodyParser = require('body-parser');
const user = require('./router/user');
const config = require('./config/params');
const logger = require('morgan');

const db = mongooes.connect(config.mongodb);

const app = express();
//设置全局参数 'jwt-secret'
app.set('jwt-secret', config.jwtsecret); 
app.use(bodyParser.json());
//body parser 拿到 req 
app.use(bodyParser.urlencoded({extended:false}));
//跨域访问
app.use("*", function (req, res, next) {
   res.header('Access-Control-Allow-Origin', '*');
   res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
   res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
   if (req.method === 'OPTIONS') {
     res.send(200)
   } else {
     next()
   }
 });
//morgan 输出日志到控制台
app.use(logger('dev'));

//路由
app.use('/api',user);

//开启服务
app.listen(config.serverPort,() => {
   console.log('app listening on port'+config.serverPort);
})

morgan 打印日志到终端,很好用的工具,能快速定位错误
/config/params 将一些重要参数抽离出来:

module.exports =  {
   serverPort:3001,
   mongodb : "mongodb://localhost:27017/mp",
   jwtsecret:"5525278",
}
控制器 Controller => router/

eg:user.js 引入Model,定义api,最后处理完逻辑通过router导出

const express = require('express');
const router = express.Router();
const UserModel = require('../model/userSchema');
const StringUtil = require('../utils/StringUtil');
const JsonUtil = require('../utils/JsonUtil');
const TokenCheckUtil = require('../utils/TokenCheckUtil');


//登陆 
router.post("/login", (req, res) => {

 UserModel.where({ name: req.body.name }).findOne((err, success) => {
   if (err) {
     JsonUtil.response(res, '200', err, "返回错误");
   } else {
     if (!StringUtil.isEmpty(success)) {
       console.log(success);
       if (req.body.password == success.password) {
         var token = TokenCheckUtil.getToken({ _id: success._id },req.app);
         UserModel.update({ _id: success._id }, { $set: { token: token }}).exec();
         JsonUtil.response(res, '200', {
           "username": success.name,
           "password": success.password,
           "token":token
         }, "登陆成功");
       } else {
         JsonUtil.response(res, '200', {
           "username": req.body.name,
           "password": req.body.password,
           "token":""
         }, "密码错误");
       }
     }else{
       JsonUtil.response(res, '200', {
         "username": req.body.name,
         "password": req.body.password,
         "token":""
       }, "用户不存在,请先注册");
     }
   }
 });

})




//注册  code == '201' 已注册 
router.post("/register", (req, res) => {
 //name唯一     name 已注册?“已注册”:“creat user”;
 UserModel.where({ name: req.body.name }).findOne((err, success) => {
   if (err) {
     JsonUtil.response(res, '200', err, "返回错误");
   } else {
     if (StringUtil.isEmpty(success)) {
       if (StringUtil.isEmpty(req.body.name) || StringUtil.isEmpty(req.body.password)) {
         JsonUtil.response(res, '200', {
           "name": req.body.name,
           "password": req.body.password
         }, "用户名密码不为能空");
       } else {
         UserModel.create(req.body, (err, success) => {
           if (err) {
             JsonUtil.response(res, '200', err, "返回错误");
           } else {
             JsonUtil.response(res, '200', success, "返回成功");
           }
         });
       }
     } else {
       JsonUtil.response(res, '201', success, "返回成功,账号已存在");
     }
   }
 });
})



module.exports = router;
工具类:

JsonUtil 规范返回值 code data message:

exports.response =function(res,code,data,message){
   var str = {
     "code": code,
     "data": data,
     "message": message
   };
   res.end(JSON.stringify(str));
 };

StringUtil 做一些字符验证:

exports.isEmpty = function(obj){
   if(typeof obj == "undefined" || obj == null || obj == ""){
       return true;
   }else{
       return false;
   }
 }

TokenCheckUtil 做jwt校验:
注意app参数,通过req.app获取,因为通过require加载即使在app导出这里引入,也会延迟导致拿不到app对象

const jwt = require('jsonwebtoken');

exports.getToken = function (obj,app) {
   return jwt.sign(obj, app.get('jwt-secret'), {
       expiresIn: 60 * 60 * 72
   });
}

//api 请求校验 token
exports.verifyToken = function(req, res, next){

   var token = req.body.token || req.query.token || req.headers['x-access-token'];
   if(token){
       jwt.verify(token, req.app.get('jwt-secret') , function(err,decoded) {
           if(err) {
             return res.json({code:"401",message:'token错误'})
           }else {
             //解析成功
             next()
           }
         })
   }else{
       return res.status(403).json({
           code: '403',
           message: '没有提供token!'
       });
   }

}
数据模型Model

model/userSchema.js ORM模型映射数据库表:

const mongoose = require('mongoose')

const userSchema = mongoose.Schema({
 name :String,
 age : String,
 sex : String,
 address : String,
 imgArr:String,
 phone:String,
 password:String,
 token:String,
}, { collection: 'user'})
//这里mongoose.Schema要写上第二个参数,明确指定到数据库中的哪个表取数据 


const User = module.exports = mongoose.model('user',userSchema);

暂时到这里,后面做点其他再更新:)
谢谢 φ(゜▽゜*)♪

你可能感兴趣的:(前端全栈从零单排项目实战 -- 注册登陆)