├── .gitignore ├── README.md ├── 前端 └── client │ ├── README.md │ ├── babel.config.js │ ├── jsconfig.json │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── css │ │ └── reset.css │ ├── favicon.ico │ └── index.html │ ├── src │ ├── App.vue │ ├── assets │ │ ├── 404.gif │ │ ├── bg.jpg │ │ ├── logo.png │ │ └── showcase.png │ ├── components │ │ ├── DialogFound.vue │ │ ├── HeadNav.vue │ │ ├── HelloWorld.vue │ │ └── LeftMenu.vue │ ├── http.js │ ├── main.js │ ├── router.js │ ├── store.js │ └── views │ │ ├── 404.vue │ │ ├── AboutView.vue │ │ ├── FoundList.vue │ │ ├── Home.vue │ │ ├── HomeView.vue │ │ ├── Index.vue │ │ ├── InfoShow.vue │ │ ├── Login.vue │ │ └── Register.vue │ └── vue.config.js ├── 后端 ├── config │ ├── keys.js │ └── passport.js ├── models │ ├── Profile.js │ └── User.js ├── package-lock.json ├── package.json ├── routes │ └── api │ │ ├── profiles.js │ │ └── users.js ├── server.js └── 一些问题的解决方法.md └── 笔记 ├── md-resources ├── apipost.jpg ├── cmd.jpg ├── createfile.jpg ├── day1.jpg ├── day2.jpg ├── day3.jpg ├── day4.jpg ├── insidethepackage.jpg ├── mongodbworking.jpg ├── nodemon.jpg ├── opencmd.jpg ├── opencmd1.jpg ├── opencmd2.jpg ├── packagejson.jpg ├── postsuccess.jpg ├── posttest.jpg ├── posttest1.jpg ├── routertest.jpg └── thepackage.jpg ├── 笔记1.md ├── 笔记1.xmind ├── 笔记2.md ├── 笔记2.xmind ├── 笔记3.md ├── 笔记3.xmind ├── 笔记4.md └── 笔记4.xmind /.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Capital-management-system-with-authority 2 | 3 | 2022/07/25 4 | 5 | 基于vue2/Element-ui/node.js(express)/mongodb实现的资金管理系统 6 | 7 | 基于本视频 https://www.bilibili.com/video/BV1R341167Fw 练习 8 | 9 | mongodb本地配置,可以按照 https://www.runoob.com/mongodb/mongodb-window-install.html 配置 10 | 11 | 感谢 @技术小余哥 https://space.bilibili.com/419040646 的项目视频,学到了很多ღ( ´・ᴗ・` ) 12 | 13 | 觉得有帮助的话就点个小星星吧~ 14 | 15 | *** 16 | 2022/07/27 17 | 更新了笔记(持续更新中) 18 | 19 | 2022/07/28 20 | 路由的写法已经旧了,之后再改 21 | 22 | 2022/12/30 23 | 修复了项目的错误,各类npm包已更新至当前日期的最新版本,并确保项目运行无误,笔记好久没更新了捏,有时间会更新后端的注释,前端vue2暂时不想看_(:з」∠)_,2018年的教程到现在也依旧有着生命力(o゚v゚)b 24 | 25 | 2023/04/20 26 | 再次更新内部错误,能继续使用了。 27 | 离线版mongodb下载:https://www.mongodb.com/try/download/community 28 | 29 | *** 30 | -------------------------------------------------------------------------------- /前端/client/README.md: -------------------------------------------------------------------------------- 1 | # client 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Customize configuration 19 | See [Configuration Reference](https://cli.vuejs.org/config/). 20 | -------------------------------------------------------------------------------- /前端/client/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /前端/client/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /前端/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint", 9 | "start": "npm run serve" 10 | }, 11 | "dependencies": { 12 | "axios": "^1.3.6", 13 | "core-js": "^3.30.1", 14 | "element-ui": "^2.15.13", 15 | "jwt-decode": "^3.1.2", 16 | "vue": "^2.7.14", 17 | "vue-router": "^3.6.5", 18 | "vuex": "^3.6.2" 19 | }, 20 | "devDependencies": { 21 | "@vue/cli-plugin-babel": "~5.0.0", 22 | "@vue/cli-plugin-router": "~5.0.0", 23 | "@vue/cli-plugin-vuex": "~5.0.0", 24 | "@vue/cli-service": "~5.0.0", 25 | "vue-template-compiler": "^2.6.14" 26 | }, 27 | "browserslist": [ 28 | "> 1%", 29 | "last 2 versions", 30 | "not dead" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /前端/client/public/css/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | body { 32 | line-height: 1; 33 | } 34 | ol, ul { 35 | list-style: none; 36 | } 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | blockquote:before, blockquote:after, 41 | q:before, q:after { 42 | content: ''; 43 | content: none; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } 49 | 50 | .el-loading{ 51 | position: absolute; 52 | z-index: 2000; 53 | background-color: rgba(255,255,255,.7); 54 | margin: 0; 55 | top: 0; 56 | right: 0; 57 | bottom: 0; 58 | left: 0; 59 | -webkit-transition: opacity .3s; 60 | transition: opacity .3s; 61 | } 62 | .el-loading-spinner{ 63 | top: 50%; 64 | margin-top: -21px; 65 | width: 100%; 66 | text-align: center; 67 | position: absolute; 68 | } 69 | -------------------------------------------------------------------------------- /前端/client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/前端/client/public/favicon.ico -------------------------------------------------------------------------------- /前端/client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | client 13 | 14 | 15 | 16 | 19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /前端/client/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 30 | 31 | 32 | 40 | -------------------------------------------------------------------------------- /前端/client/src/assets/404.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/前端/client/src/assets/404.gif -------------------------------------------------------------------------------- /前端/client/src/assets/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/前端/client/src/assets/bg.jpg -------------------------------------------------------------------------------- /前端/client/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/前端/client/src/assets/logo.png -------------------------------------------------------------------------------- /前端/client/src/assets/showcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/前端/client/src/assets/showcase.png -------------------------------------------------------------------------------- /前端/client/src/components/DialogFound.vue: -------------------------------------------------------------------------------- 1 | 57 | 58 | 111 | 112 | -------------------------------------------------------------------------------- /前端/client/src/components/HeadNav.vue: -------------------------------------------------------------------------------- 1 | 35 | 74 | 75 | 141 | -------------------------------------------------------------------------------- /前端/client/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 42 | 43 | 44 | 60 | -------------------------------------------------------------------------------- /前端/client/src/components/LeftMenu.vue: -------------------------------------------------------------------------------- 1 | 36 | 59 | 93 | -------------------------------------------------------------------------------- /前端/client/src/http.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { Message, Loading } from 'element-ui'; 3 | import router from './router' 4 | 5 | let loading //定义loading变量 6 | 7 | function startLoading() { //使用Element loading-start 方法 8 | loading = Loading.service({ 9 | lock: true, 10 | text: '加载中...', 11 | background: 'rgba(0, 0, 0, 0.7)' 12 | }) 13 | } 14 | function endLoading() { //使用Element loading-close 方法 15 | loading.close() 16 | } 17 | 18 | // 请求拦截 设置统一header 19 | axios.interceptors.request.use(config => { 20 | // 加载 21 | startLoading() 22 | if (localStorage.eleToken) 23 | config.headers.Authorization = localStorage.eleToken 24 | return config 25 | }, error => { 26 | return Promise.reject(error) 27 | }) 28 | 29 | // 响应拦截 401 token过期处理 30 | axios.interceptors.response.use(response => { 31 | endLoading() 32 | return response 33 | }, error => { 34 | // 错误提醒 35 | endLoading() 36 | Message.error(error.response.data) 37 | 38 | const { status } = error.response 39 | if (status == 401) { 40 | Message.error('token值无效,请重新登录') 41 | // 清除token 42 | localStorage.removeItem('eleToken') 43 | 44 | // 页面跳转 45 | router.push('/login') 46 | } 47 | 48 | return Promise.reject(error) 49 | }) 50 | 51 | export default axios -------------------------------------------------------------------------------- /前端/client/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | import ElementUI from 'element-ui'; 6 | import 'element-ui/lib/theme-chalk/index.css'; 7 | import axios from './http' 8 | 9 | Vue.use(ElementUI); 10 | 11 | Vue.prototype.$axios = axios 12 | 13 | Vue.config.productionTip = false 14 | 15 | new Vue({ 16 | router, 17 | store, 18 | render: h => h(App) 19 | }).$mount('#app') 20 | -------------------------------------------------------------------------------- /前端/client/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from './views/Index.vue' 4 | import Register from './views/Register' 5 | import Nofind from './views/404' 6 | import Login from './views/Login' 7 | import Home from './views/Home' 8 | import InfoShow from './views/InfoShow' 9 | import FoundList from './views/FoundList' 10 | 11 | Vue.use(Router) 12 | 13 | const router = new Router({ 14 | mode: 'history', 15 | base: process.env.BASE_URL, 16 | routes: [ 17 | { 18 | path: '*', 19 | name: '/404', 20 | component: Nofind 21 | }, 22 | { 23 | path: '/', 24 | redirect: '/index' 25 | }, 26 | { 27 | path: '/register', 28 | name: 'register', 29 | component: Register 30 | }, 31 | { 32 | path: '/login', 33 | name: 'login', 34 | component: Login 35 | }, 36 | { 37 | path: '/index', 38 | component: Index, 39 | children: [ 40 | { path: '', component: Home }, 41 | { path: '/home', name: 'home', component: Home }, 42 | { path: '/infoshow', name: 'infoshow', component: InfoShow }, 43 | { path: '/foundlist', name: 'foundlist', component: FoundList } 44 | ] 45 | }, 46 | 47 | // { 48 | // path: '/about', 49 | // name: 'about', 50 | // // route level code-splitting 51 | // // this generates a separate chunk (about.[hash].js) for this route 52 | // // which is lazy-loaded when the route is visited. 53 | // component: () => import(/* webpackChunkName: "about" */ './views/About.vue') 54 | // } 55 | ] 56 | }) 57 | 58 | // 添加路由守卫 59 | router.beforeEach((to, from, next) => { 60 | const isLogin = localStorage.eleToken ? true : false; 61 | if (to.path == "/login" || to.path == "/register") { 62 | next(); 63 | } else { 64 | isLogin ? next() : next("/login"); 65 | } 66 | }) 67 | 68 | export default router; -------------------------------------------------------------------------------- /前端/client/src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | const types = { 7 | SET_IS_AUTNENTIATED: 'SET_IS_AUTNENTIATED', // 是否认证通过 8 | SET_USER: 'SET_USER' // 用户信息 9 | } 10 | 11 | const state = { // 需要维护的状态 12 | isAutnenticated: false, // 是否认证 13 | user: {} // 存储用户信息 14 | } 15 | 16 | const getters = { 17 | isAutnenticated: state => state.isAutnenticated, 18 | user: state => state.user 19 | } 20 | 21 | const mutations = { 22 | [types.SET_IS_AUTNENTIATED](state, isAutnenticated) { 23 | if (isAutnenticated) 24 | state.isAutnenticated = isAutnenticated 25 | else 26 | state.isAutnenticated = false 27 | }, 28 | [types.SET_USER](state, user) { 29 | if (user) 30 | state.user = user 31 | else 32 | state.user = {} 33 | } 34 | } 35 | 36 | const actions = { 37 | setIsAutnenticated: ({ commit }, isAutnenticated) => { 38 | commit(types.SET_IS_AUTNENTIATED, isAutnenticated) 39 | }, 40 | setUser: ({ commit }, user) => { 41 | commit(types.SET_USER, user) 42 | }, 43 | clearCurrentState: ({ commit }) => { 44 | commit(types.SET_IS_AUTNENTIATED, false) 45 | commit(types.SET_USER, null) 46 | } 47 | } 48 | 49 | export default new Vuex.Store({ 50 | state, 51 | getters, 52 | mutations, 53 | actions 54 | }) 55 | -------------------------------------------------------------------------------- /前端/client/src/views/404.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | 19 | -------------------------------------------------------------------------------- /前端/client/src/views/AboutView.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /前端/client/src/views/FoundList.vue: -------------------------------------------------------------------------------- 1 | 151 | 152 | 300 | 315 | -------------------------------------------------------------------------------- /前端/client/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /前端/client/src/views/HomeView.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /前端/client/src/views/Index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | 38 | 39 | -------------------------------------------------------------------------------- /前端/client/src/views/InfoShow.vue: -------------------------------------------------------------------------------- 1 | 24 | 34 | 73 | -------------------------------------------------------------------------------- /前端/client/src/views/Login.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 88 | 89 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /前端/client/src/views/Register.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 106 | 107 | 108 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /前端/client/vue.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require("@vue/cli-service"); 2 | module.exports = defineConfig({ 3 | transpileDependencies: true, 4 | }); 5 | 6 | const path=require("path") 7 | const debug = process.env.NODE_ENV !== 'production' 8 | 9 | module.exports = { 10 | publicPath: 11 | process.env.NODE_ENV === "production" ? "/production-sub-path/" : "/", 12 | outputDir: "dist", 13 | assetsDir: "assets", 14 | lintOnSave: false, 15 | runtimeCompiler: true, 16 | transpileDependencies: false, 17 | productionSourceMap: true, 18 | // configureWebpack: (config) => { 19 | // // webpack配置,值位对象时会合并配置,为方法时会改写配置 20 | // if (debug) { 21 | // // 开发环境配置 22 | // config.devtool = "eval-cheap-module-source-map"; 23 | // } else { 24 | // // 生产环境配置 25 | // } 26 | // }, 27 | // chainWebpack: (config) => { 28 | // // webpack链接API,用于生成和修改webapck配置,https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md 29 | // if (debug) { 30 | // config.devtool = "eval-cheap-module-source-map"; // 本地开发配置 31 | // } else { 32 | // // 生产开发配置 33 | // } 34 | // }, 35 | parallel: require("os").cpus().length > 1, 36 | pluginOptions: { 37 | // 第三方插件配置 38 | }, 39 | pwa: { 40 | // 单页插件相关配置 https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa 41 | }, 42 | devServer: { 43 | open: true, 44 | host: "localhost", 45 | port: 8080, 46 | https: false, 47 | hot: false, 48 | proxy: { 49 | "/api": { 50 | target: "http://localhost:5000/api/", 51 | ws: true, 52 | changOrigin: true, 53 | pathRewrite: { 54 | "^/api": "", 55 | }, 56 | }, 57 | }, 58 | }, 59 | }; 60 | -------------------------------------------------------------------------------- /后端/config/keys.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mongoURI: "mongodb://127.0.0.1:27017/test", 3 | secretOrKey: "secret", 4 | }; 5 | -------------------------------------------------------------------------------- /后端/config/passport.js: -------------------------------------------------------------------------------- 1 | const JwtStrategy = require('passport-jwt').Strategy, 2 | ExtractJwt = require('passport-jwt').ExtractJwt; 3 | const mongoose = require("mongoose"); 4 | const User = mongoose.model("users"); 5 | const keys = require("../config/keys"); 6 | 7 | const opts = {} 8 | opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); 9 | opts.secretOrKey = keys.secretOrKey; 10 | 11 | module.exports = passport => { 12 | passport.use(new JwtStrategy(opts, (jwt_payload, done) => { 13 | // console.log(jwt_payload); 14 | User.findById(jwt_payload.id) 15 | .then(user => { 16 | if(user){ 17 | return done(null,user); 18 | } 19 | 20 | return done(null,false); 21 | }) 22 | .catch(err => console.log(err)); 23 | })); 24 | } -------------------------------------------------------------------------------- /后端/models/Profile.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const Schema = mongoose.Schema; 3 | 4 | // Create Schema 5 | const ProfileSchema = new Schema({ 6 | type: { 7 | type: String 8 | }, 9 | describe: { 10 | type: String 11 | }, 12 | income: { 13 | type: String, 14 | required: true 15 | }, 16 | expend: { 17 | type: String, 18 | required: true 19 | }, 20 | cash: { 21 | type: String, 22 | required: true 23 | }, 24 | remark: { 25 | type: String 26 | }, 27 | date: { 28 | type: Date, 29 | default: Date.now 30 | } 31 | }); 32 | 33 | module.exports = Profile = mongoose.model('profile', ProfileSchema); 34 | -------------------------------------------------------------------------------- /后端/models/User.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const Schema = mongoose.Schema; 3 | 4 | // Create Schema 5 | const UserSchema = new Schema({ 6 | name: { 7 | type: String, 8 | required: true 9 | }, 10 | email: { 11 | type: String, 12 | required: true 13 | }, 14 | password: { 15 | type: String, 16 | required: true 17 | }, 18 | avatar: { 19 | type: String 20 | }, 21 | identity: { 22 | type: String, 23 | required: true 24 | }, 25 | date: { 26 | type: Date, 27 | default: Date.now 28 | } 29 | }); 30 | 31 | module.exports = User = mongoose.model('users', UserSchema); 32 | -------------------------------------------------------------------------------- /后端/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xiaotingmeow", 3 | "version": "1.0.0", 4 | "description": "restful api", 5 | "main": "server.js", 6 | "scripts": { 7 | "client-install": "npm install --prefix client", 8 | "client": "npm start --prefix client", 9 | "start": "node server.js", 10 | "server": "nodemon server.js", 11 | "dev": "concurrently \"npm run server\" \"npm run client\"", 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "bcrypt": "^5.1.0", 18 | "body-parser": "^1.20.2", 19 | "concurrently": "^7.6.0", 20 | "express": "^4.18.2", 21 | "jsonwebtoken": "^9.0.0", 22 | "mongoose": "^6.10.5", 23 | "passport": "^0.6.0", 24 | "passport-jwt": "^4.0.1" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /后端/routes/api/profiles.js: -------------------------------------------------------------------------------- 1 | // @login & register 2 | const express = require("express"); 3 | const router = express.Router(); 4 | const passport = require("passport"); 5 | 6 | const Profile = require("../../models/Profile"); 7 | 8 | // @route GET api/profiles/test 9 | // @desc 返回的请求的json数据 10 | // @access public 11 | router.get("/test", (req, res) => { 12 | res.json({ msg: "profile works" }); 13 | }); 14 | 15 | // @route POST api/profiles/add 16 | // @desc 创建信息接口 17 | // @access Private 18 | router.post( 19 | "/add", 20 | passport.authenticate("jwt", { session: false }), 21 | (req, res) => { 22 | const profileFields = {}; 23 | 24 | if (req.body.type) profileFields.type = req.body.type; 25 | if (req.body.describe) profileFields.describe = req.body.describe; 26 | if (req.body.income) profileFields.income = req.body.income; 27 | if (req.body.expend) profileFields.expend = req.body.expend; 28 | if (req.body.cash) profileFields.cash = req.body.cash; 29 | if (req.body.remark) profileFields.remark = req.body.remark; 30 | 31 | new Profile(profileFields).save().then((profile) => { 32 | res.json(profile); 33 | }); 34 | } 35 | ); 36 | 37 | // @route GET api/profiles 38 | // @desc 获取所有信息 39 | // @access Private 40 | 41 | router.get( 42 | "/", 43 | passport.authenticate("jwt", { session: false }), 44 | (req, res) => { 45 | Profile.find() 46 | .then((profile) => { 47 | if (!profile) { 48 | return res.status(404).json("没有任何内容"); 49 | } 50 | 51 | res.json(profile); 52 | }) 53 | .catch((err) => res.status(400).json(err)); 54 | } 55 | ); 56 | 57 | // @route GET api/profiles/:id 58 | // @desc 获取单个信息 59 | // @access Private 60 | 61 | router.get( 62 | "/:id", 63 | passport.authenticate("jwt", { session: false }), 64 | (req, res) => { 65 | Profile.findOne({ _id: req.params.id }) 66 | .then((profile) => { 67 | if (!profile) { 68 | return res.status(404).json("没有任何内容"); 69 | } 70 | 71 | res.json(profile); 72 | }) 73 | .catch((err) => res.status(404).json(err)); 74 | } 75 | ); 76 | 77 | // @route POST api/profiles/edit 78 | // @desc 编辑信息接口 79 | // @access Private 80 | router.post( 81 | "/edit/:id", 82 | passport.authenticate("jwt", { session: false }), 83 | (req, res) => { 84 | const profileFields = {}; 85 | 86 | if (req.body.type) profileFields.type = req.body.type; 87 | if (req.body.describe) profileFields.describe = req.body.describe; 88 | if (req.body.income) profileFields.income = req.body.income; 89 | if (req.body.expend) profileFields.expend = req.body.expend; 90 | if (req.body.cash) profileFields.cash = req.body.cash; 91 | if (req.body.remark) profileFields.remark = req.body.remark; 92 | 93 | Profile.findOneAndUpdate( 94 | { _id: req.params.id }, 95 | { $set: profileFields }, 96 | { new: true } 97 | ).then((profile) => res.json(profile)); 98 | } 99 | ); 100 | 101 | // @route POST api/profiles/delete/:id 102 | // @desc 删除信息接口 103 | // @access Private 104 | router.delete( 105 | "/delete/:id", 106 | passport.authenticate("jwt", { session: false }), 107 | (req, res) => { 108 | Profile.findOneAndRemove({ _id: req.params.id }) 109 | .then((profile) => { 110 | res.json(profile); 111 | }) 112 | .catch((err) => res.status(404).json("删除失败!")); 113 | } 114 | // Profile.deleteOne({ _id: req.params.id }) 115 | // .then(profile => { 116 | // profile.save().then(profile => res.json(profile)); 117 | // }) 118 | ); 119 | 120 | module.exports = router; 121 | -------------------------------------------------------------------------------- /后端/routes/api/users.js: -------------------------------------------------------------------------------- 1 | // @login & register 2 | const express = require('express'); 3 | const router = express.Router(); 4 | const bcrypt = require('bcrypt'); 5 | const jwt = require('jsonwebtoken'); 6 | const keys = require('../../config/keys'); 7 | const passport = require('passport'); 8 | 9 | const User = require('../../models/User'); 10 | 11 | // @route GET api/users/test 12 | // @desc 返回的请求的json数据 13 | // @access public 14 | router.get('/test', (req, res) => { 15 | res.json({ msg: 'login works' }); 16 | }); 17 | 18 | // @route POST api/users/register 19 | // @desc 返回的请求的json数据 20 | // @access public 21 | router.post('/register', (req, res) => { 22 | // 查询数据库中是否拥有邮箱 23 | User.findOne({ email: req.body.email }).then(user => { 24 | if (user) { 25 | return res.status(400).json('邮箱已被注册!'); 26 | } else { 27 | const newUser = new User({ 28 | name: req.body.name, 29 | email: req.body.email, 30 | password: req.body.password, 31 | identity: req.body.identity 32 | }); 33 | 34 | bcrypt.genSalt(10, function(err, salt) { 35 | bcrypt.hash(newUser.password, salt, (err, hash) => { 36 | if (err) throw err; 37 | 38 | newUser.password = hash; 39 | 40 | newUser 41 | .save() 42 | .then(user => res.json(user)) 43 | .catch(err => console.log(err)); 44 | }); 45 | }); 46 | } 47 | }); 48 | }); 49 | 50 | // @route POST api/users/login 51 | // @desc 返回token jwt passport 52 | // @access public 53 | 54 | router.post('/login', (req, res) => { 55 | const email = req.body.email; 56 | const password = req.body.password; 57 | // 查询数据库 58 | User.findOne({ email }).then(user => { 59 | if (!user) { 60 | return res.status(404).json('用户不存在!'); 61 | } 62 | 63 | // 密码匹配 64 | bcrypt.compare(password, user.password).then(isMatch => { 65 | if (isMatch) { 66 | const rule = { 67 | id: user.id, 68 | name: user.name, 69 | avatar: user.avatar, 70 | identity: user.identity 71 | }; 72 | jwt.sign(rule, keys.secretOrKey, { expiresIn: 3600 }, (err, token) => { 73 | if (err) throw err; 74 | res.json({ 75 | success: true, 76 | token: 'Bearer ' + token 77 | }); 78 | }); 79 | // res.json({msg:"success"}); 80 | } else { 81 | return res.status(400).json('密码错误!'); 82 | } 83 | }); 84 | }); 85 | }); 86 | 87 | // @route GET api/users/current 88 | // @desc return current user 89 | // @access Private 90 | router.get( 91 | '/current', 92 | passport.authenticate('jwt', { session: false }), 93 | (req, res) => { 94 | res.json({ 95 | id: req.user.id, 96 | name: req.user.name, 97 | email: req.user.email, 98 | identity: req.user.identity 99 | }); 100 | } 101 | ); 102 | 103 | module.exports = router; 104 | -------------------------------------------------------------------------------- /后端/server.js: -------------------------------------------------------------------------------- 1 | //创建一个 Express 应用程序。该函数是模块express()导出的顶级函数。 2 | const express = require("express"); 3 | const app = express(); 4 | 5 | //指定端口为环境变量PORT中的任何内容,如果没有,则为5000 6 | const port = process.env.PORT || 5000; 7 | 8 | //Mongoose为模型提供了一种直接的,基于schema结构去定义你的数据模型。它内置数据验证, 查询构建,业务逻辑钩子等,开箱即用。 9 | const mongoose = require("mongoose"); 10 | 11 | //引入body-parser,bodyparser是一类处理request的body的中间件函数,对传入的请求体进行解析 12 | const bodyParser = require("body-parser"); 13 | 14 | const passport = require("passport"); 15 | 16 | //引入登录和路由模块 17 | const users = require("./routes/api/users"); 18 | 19 | const profiles = require("./routes/api/profiles"); 20 | 21 | const { mongoURI } = require("./config/keys"); 22 | 23 | //引入数据库地址 24 | const db = require("./config/keys").mongoURI; 25 | 26 | require("./config/passport")(passport); 27 | 28 | //返回只解析url被编码过的请求体,而且只查看content-type请求头与type选项匹配的请求,并允许选择使用querystring库解析url编码 29 | app.use(bodyParser.urlencoded({ extended: false })); 30 | //返回只解析JSON且只查看Content-Type请求头与type选项匹配的请求 31 | app.use(bodyParser.json()); 32 | 33 | // passport 初始化 34 | app.use(passport.initialize()); 35 | 36 | //在指定的路径上挂载指定的中间件函数:当请求的路径的基础部分与路径匹配时,中间件函数将执行。 37 | app.use("/api/users", users); 38 | 39 | app.use("/api/profiles", profiles); 40 | 41 | //在升级到mongoose7前处理终端提示用,删除也不影响使用 42 | mongoose.set('strictQuery', true); 43 | 44 | //使用 mongoose.connect() 方法连接 MongoDB,然后输出"连接成功",出现异常时输出错误 45 | mongoose 46 | .connect(db) 47 | .then(() => { 48 | console.log("MongoDB connected!"); 49 | }) 50 | .catch((err) => { 51 | console.log(err); 52 | }); 53 | 54 | //绑定并监听指定主机和端口上的连接。此方法与 Node 的http.Server.listen()相同。 55 | app.listen(port, () => { 56 | console.log(`server running on port ${port}`); 57 | }); 58 | 59 | //使用指定的回调函数将 HTTP GET 请求路由到指定路径。 60 | app.get("/", (req, res) => { 61 | res.send("hello world"); 62 | }); 63 | -------------------------------------------------------------------------------- /后端/一些问题的解决方法.md: -------------------------------------------------------------------------------- 1 | nodemon : 无法加载文件 C:\Users\xiaotingmeow\AppData\Roaming\npm\nodemon.ps1......的解决方案: 2 | 管理员身份打开powerShell 3 | 搜索powerShell,右键选择以管理员身份运行,输入set-ExecutionPolicy RemoteSigned,选择Y或者A,就好了 -------------------------------------------------------------------------------- /笔记/md-resources/apipost.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/apipost.jpg -------------------------------------------------------------------------------- /笔记/md-resources/cmd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/cmd.jpg -------------------------------------------------------------------------------- /笔记/md-resources/createfile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/createfile.jpg -------------------------------------------------------------------------------- /笔记/md-resources/day1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/day1.jpg -------------------------------------------------------------------------------- /笔记/md-resources/day2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/day2.jpg -------------------------------------------------------------------------------- /笔记/md-resources/day3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/day3.jpg -------------------------------------------------------------------------------- /笔记/md-resources/day4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/day4.jpg -------------------------------------------------------------------------------- /笔记/md-resources/insidethepackage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/insidethepackage.jpg -------------------------------------------------------------------------------- /笔记/md-resources/mongodbworking.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/mongodbworking.jpg -------------------------------------------------------------------------------- /笔记/md-resources/nodemon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/nodemon.jpg -------------------------------------------------------------------------------- /笔记/md-resources/opencmd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/opencmd.jpg -------------------------------------------------------------------------------- /笔记/md-resources/opencmd1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/opencmd1.jpg -------------------------------------------------------------------------------- /笔记/md-resources/opencmd2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/opencmd2.jpg -------------------------------------------------------------------------------- /笔记/md-resources/packagejson.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/packagejson.jpg -------------------------------------------------------------------------------- /笔记/md-resources/postsuccess.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/postsuccess.jpg -------------------------------------------------------------------------------- /笔记/md-resources/posttest.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/posttest.jpg -------------------------------------------------------------------------------- /笔记/md-resources/posttest1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/posttest1.jpg -------------------------------------------------------------------------------- /笔记/md-resources/routertest.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/routertest.jpg -------------------------------------------------------------------------------- /笔记/md-resources/thepackage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/md-resources/thepackage.jpg -------------------------------------------------------------------------------- /笔记/笔记1.md: -------------------------------------------------------------------------------- 1 | # 全栈项目-资金管理系统带权限 2 | 3 | 为了防止今后看到就会,写时就废的情况发生,特作此笔记 4 | 5 | 原项目视频链接: 6 | 7 | ## 首先,先新建一个项目 8 | 9 | 新建一个文件夹来存放项目(视频中为node-app) 10 | 11 | 然后在文件夹中 12 | 13 | 14 | 15 | 并输入`cmd`,进入命令行工具 16 | 17 | 长这样 18 | 19 | 20 | 21 | 输入`npm init`,开始配置package.json 22 | 23 | . 24 | 25 | ### 如果`npm init`报错,应该是没有装node.js,如何安装可以看这个 (Node.js安装配置 https://www.runoob.com/nodejs/nodejs-install-setup.html) 26 | 27 | package.json是配置和描述如何与程序交互和运行的中心。 npm CLI(和 yarn)用它来识别你的项目并了解如何处理项目的依赖关系。package.json文件使 npm 可以启动你的项目、运行脚本、安装依赖项、发布到 NPM 注册表以及许多其他有用的任务。(摘自 不求人-package.json详解 ) 28 | 29 | . 30 | 31 | 接下来会有如下选项依次出现`package name,version,description,entry point,test command,git repository,keywords,author,license`(输入完之后,按回车进入下一个) 32 | 33 | 34 | 35 | 详解: 36 | 37 | package name:项目名字(可选) 38 | 39 | version:当前项目版本(可选) 40 | 41 | description:项目描述(可选) 42 | 43 | entry point:项目的入口文件,视频中使用的是server.js,入口文件不会在本过程中创建,需要自己新建文件,在启动node服务如`node xxx,nodemon xxx`时,会先启动这个文件 44 | 45 | test command:项目启动的时候要用什么命令来执行脚本文件(如果留空,默认为node app.js) 46 | 47 | git repository:如果你要将项目上传到git中的话,那么就需要填写git的仓库地址(这里就不写地址了) 48 | 49 | keywords:项目关键字(不需要写) 50 | 51 | author:作者的名字(你叫啥名字) 52 | 53 | license:发行项目需要的证书(不需要写) 54 | 55 | (部分摘自 逍遥的码农-启动node服务请求本地接口 https://blog.csdn.net/weixin_48171107/article/details/121614687) 56 | 57 | 然后就生成了一个package.json文件 58 | 59 | 长这样 60 | 61 | 62 | 63 | 打开之后是这样 64 | 65 | 66 | 67 | (看起来不是新建的,其实这是本项目完成的最终形态) 68 | 69 | 现在先抛开这个文件不管(有了package.json就可以npm装各种包了,会在终端中输入指令) 70 | 71 | ### 视频中是打开终端输入`touch server.js`,至少我没有成功,还可以用这个办法→ 72 | 73 | 74 | 75 | 然后进入server.js 76 | 77 | 现在需要express框架来搭建服务器了(之后再去总结其功能) 78 | 79 | 在位于package.json文件的目录下,打开cmd或者使用vscode打开终端,如图 80 | 81 | 82 | 83 | 出现如图界面 84 | 85 | 86 | 87 | 然后输入npm install express,系统会自动下载,等待完成即可 88 | 89 | ### 如出现下载缓慢请配置npm淘宝镜像(也就是在终端里复制如下语句并回车,之后npm包都会在这网站下载) 90 | 91 | ### ``` npm config set registry https://registry.npm.taobao.org ``` 92 | 93 | (摘自 尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通 P61 5分33秒 https://www.bilibili.com/video/BV1Zy4y1K7SH?p=61) 94 | 95 | . 96 | 97 | express简介: 98 | 99 | Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。 100 | 101 | 使用 Express 可以快速地搭建一个完整功能的网站。 102 | 103 | Express 框架核心特性: 104 | 105 | 可以设置中间件来响应 HTTP 请求。 106 | 107 | 定义了路由表用于执行不同的 HTTP 请求动作。 108 | 109 | 可以通过向模板传递参数来动态渲染 HTML 页面。 110 | 111 | . 112 | 113 | 接下来在server.js中输入如下代码 114 | 115 | ```javascript 116 | //express()用来创建一个Express的程序。express()方法是express模块导出的顶层方法。 117 | const express = require("express"); 118 | const app = express(); 119 | ``` 120 | 121 | ### 现在可以使用express中的各种方法了 122 | 123 | 注释摘自 @XiangZhou-express 4.x api 中文手册 (https://www.zybuluo.com/XiangZhou/note/208532) 124 | 125 | 往下输入如下代码 126 | 127 | ```javascript 128 | //指定端口为环境变量PORT中的内容,如果没有,则为5000 129 | const port = process.env.PORT || 5000; 130 | ``` 131 | 132 | 133 | ```javascript 134 | //绑定程序监听端口到指定的主机和端口号。这个方法和Node中的http.Server.listen()是一样的。 135 | app.listen(port, () => { 136 | console.log(`server running on port ${port}`); 137 | }); 138 | ``` 139 | 140 | ### 现在已经搭建好服务器了(但还不能访问),它会在终端返回给你正在监听的端口 141 | 142 | . 143 | 144 | 关于process.env.PORT的描述: 145 | 146 | 在许多环境(例如Heroku)中,作为一种约定,您可以设置环境变量PORT以告知Web服务器要监听的端口。 147 | 148 | 因此,process.env.PORT || 3000意味着:环境变量PORT中的任何内容,如果没有,则为3000。 149 | 150 | 因此,您可以将app.listen,或传递给app.set('port', ...),从而使您的服务器能够从环境中接受要监听的端口上的参数。 151 | 152 | 如果将3000硬编码传递给app.listen(),则您总是在监听端口3000,这可能只适合您自己,也可能不适合您,具体取决于您的要求和运行服务器的环境的要求. 153 | 154 | 摘自 编程字典-Node.js中的process.env.PORT是什么?(https://codingdict.com/questions/76797) 155 | 156 | . 157 | 158 | 接下来输入 159 | 160 | ```javascript 161 | //路由HTTP GET请求到有特殊回调的特殊路径 162 | app.get("/", (req, res) => { 163 | res.send("hello world"); 164 | }); 165 | 166 | ``` 167 | ### 设置了路由,现在可以访问服务器了 168 | 169 | . 170 | 171 | GET 方法用来请求访问已被 URI 识别的资源。指定的资源经服务器端解析后返回响应内容。也就是说,如果请求的资源是文本,那就保持原样返回;如果是像 CGI(Common Gateway Interface,通用网关接口)那样的程序,则返回经过执行后的输出结果。 172 | 173 | 摘自《图解http》(上野宣 著) 174 | 175 | . 176 | 177 | 现在每次改变服务器代码,都需要重新启动服务器(初始操作为`node server.js`开启服务器,`Ctrl+C`键关闭服务器) 178 | 179 | 在终端输入`npm install nodemon`安装`nodemon` 180 | 181 | 现在在终端输入`nodemon server.js`,每次保存`server.js`文件,nodemon都会自动重启服务器,不需要重复在终端输入并打开服务器. 182 | 183 | 回到package.json新增如下语句后 184 | 185 | 186 | 187 | 就可以使用如下命令`npm run server`来代替`nodemon server.js`.(同理`npm run start`也可代替`node server.js`) 188 | 189 | . 190 | 191 | Nodemon是一个帮助开发基于node .js的应用程序的工具,当检测到目录中的文件发生变化时,它会自动重启节点应用程序。 192 | 193 | Nodemon不需要对代码或开发方法进行任何额外的更改。Nodemon是node的替代包装器。要使用nodemon,在执行脚本时替换命令行上的单词node。 194 | 195 | 摘自 nodemon-npm (https://www.npmjs.com/package/nodemon) 196 | 197 | . 198 | 199 | P1总结: 200 | 201 | -------------------------------------------------------------------------------- /笔记/笔记1.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/笔记1.xmind -------------------------------------------------------------------------------- /笔记/笔记2.md: -------------------------------------------------------------------------------- 1 | 2 | ### 连接Mongodb数据库 3 | 4 | 这里我们不使用老师的方法(mLab已经更新为mongodb Altas,方法依旧但连接不稳定) 5 | 6 | 所以这边使用的是本地mongodb数据库 7 | 8 | 安装和使用方法 Windows 平台安装 MongoDB ( https://www.runoob.com/mongodb/mongodb-window-install.html) 9 | 10 | 数据目录不会主动创建,要先自行新建文件夹后,再使用命令行工具,在mongod.exe目录下,输入`mongod --dbpath=你的数据库路径` 11 | 12 | 比如`mongod --dbpath=..\data\db` 13 | 14 | ### 执行完毕数据库就已经启动了,不要关闭命令行工具,请最小化保持运行 15 | 16 | 然后服务器会默认运行在`127.0.0.1:27017`,在浏览器中如图所示 17 | 18 | 19 | 20 | 为了能对数据库进行操作,我们需要安装mongoose 21 | 22 | 在终端里输入`npm install mongoose` 23 | 24 | 并在server.js中引入 25 | 26 | ```javascript 27 | //Mongoose是在node异步环境下对mongodb进行编写对象操作的工具,为模型提供了一种直接的,基于schema结构去定义你的数据模型。它内置数据验证, 查询构建,业务逻辑钩子等,开箱即用。 28 | const mongoose = require("mongoose"); 29 | ``` 30 | 31 | 可以往下直接写来连接数据库 32 | 33 | ```javascript 34 | //test为mongodb中的数据库,如果test数据库不存在,则会自动创建,可以自行更改 35 | mongoose.connect('mongodb://127.0.0.1:27017/test') 36 | ``` 37 | 38 | 老师的写法是新建一个文件保存地址,然后引用其地址 39 | 40 | 方法为:新建一个config文件夹(与server.js在同一目录),内建一文件keys.js,并输入 41 | 42 | ```javascript 43 | //in keys.js 44 | module.exports = { 45 | mongoURI: "mongodb://127.0.0.1:27017/test", 46 | }; 47 | ``` 48 | 在server.js中引入 49 | 50 | ```javascript 51 | //in server.js 52 | //引入数据库地址 53 | const db = require("./config/keys").mongoURI; 54 | mongoose.connect(db); 55 | ``` 56 | 57 | 为了验证服务器是否连接到了数据库,我们接着写 58 | 59 | ```javascript 60 | //使用 mongoose.connect() 方法连接 MongoDB,成功就输出"连接成功",出现异常时输出错误 61 | mongoose 62 | .connect(db) 63 | .then(() => { 64 | console.log("MongoDB connected!"); 65 | }) 66 | .catch((err) => { 67 | console.log(err); 68 | }); 69 | ``` 70 | 71 | 在终端启动服务器(比如之前的`npm run server`) 72 | 73 | 终端会出现`MongoDB connected!`提示你成功连接 74 | 75 | ### 总结 76 | 77 | ![alt](./md-resources/day2.jpg) -------------------------------------------------------------------------------- /笔记/笔记2.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/笔记2.xmind -------------------------------------------------------------------------------- /笔记/笔记3.md: -------------------------------------------------------------------------------- 1 | ### 搭建路由和数据模型 2 | 3 | . 4 | 5 | 路由 6 | 7 | 路由是指确定应用程序如何响应客户端对特定端点的请求,该端点是 URI(或路径)和特定的 HTTP 请求方法(GET、POST 等)。 8 | 9 | 每个路由可以有一个或多个处理函数,当路由匹配时执行。 10 | 11 | 路由定义采用以下结构: 12 | 13 | ```javascript 14 | app.METHOD(PATH, HANDLER) 15 | ``` 16 | 17 | 摘自 express中文网-基本路由 () 18 | 19 | . 20 | 21 | 数据模型 22 | 23 | Mongoose 的一切始于 Schema。每个 schema 都会映射到一个 MongoDB collection ,并定义这个collection里的文档的构成。 24 | 25 | Models 是从 Schema 编译来的构造函数。 它们的实例就代表着可以从数据库保存和读取的 documents。 从数据库创建和读取 document 的所有操作都是通过 model 进行的。 26 | 27 | . 28 | 29 | 新建一个routes文件夹(与server.js在同一目录) 30 | 31 | 再新建一个api文件夹(在routes文件夹内) 32 | 33 | 在api文件夹内新建users.js文件 34 | 35 | ### users.js储存了有关用户数据操作的路由 36 | 37 | 现在先引入express和实例化router 38 | 39 | ```javascript 40 | //in routes/api/users.js 41 | const express = require('express'); 42 | const router = express.Router(); 43 | ``` 44 | 45 | . 46 | 47 | 一个router对象是一个单独的实例关于中间件和路由。你可以认为其是一个"mini-application"(迷你程序),其具有操作中间件和路由方法的能力。每个Express程序有一个内建的app路由。 48 | 49 | 路由自身表现为一个中间件,所以你可以使用它作为app.use()方法的一个参数或者作为另一个路由的use()的参数。 50 | 51 | 顶层的express对象有一个Router()方法,你可以使用Router()来创建一个新的router对象。 52 | 53 | 一旦创建了路由器对象,就可以像应用程序一样向它添加中间件和HTTP方法路由(例如get、put、post等) 54 | 55 | 摘自 @XiangZhou-express 4.x api 中文手册 () 56 | 57 | . 58 | 59 | 测试一下路由 60 | 61 | ```javascript 62 | //in users.js 63 | // @route GET api/users/test 64 | // @desc 返回的请求的json数据 65 | // @access public 66 | router.get('/test', (req, res) => { 67 | res.json({ msg: 'login works' }); 68 | }); 69 | ``` 70 | 71 | 路由方法写好了:现在当我们访问`指定路径/test`时,就会返回信息`login works` 72 | 73 | 要去使用路由,得先引出users.js,再到server.js引入 74 | 75 | ```javascript 76 | //in users.js 77 | module.exports = router; 78 | ``` 79 | 80 | ```javascript 81 | //in server.js 82 | //引入用户相关路由模块 83 | const users = require("./routes/api/users"); 84 | ``` 85 | 86 | . 87 | 88 | module.exports 89 | Node应用由模块组成,采用CommonJS模块规范。 90 | 91 | 根据这个规范,每个文件就是一个模块,有自己的作用域。在这些文件里面定义的变量、函数、类,都是私有的,对外不可见,因此规避掉了作用域污染。 92 | 93 | 根据CommonJS规定,每个模块内部,module变量代表当前模块,这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实就是加载该模块的exports属性。 94 | 95 | 摘自 锕琅 module.export和exports两者区别及使用方法 (https://blog.csdn.net/weixin_44339850/article/details/99887127) 96 | 97 | . 98 | 99 | 引入后再使用 100 | 101 | ```javascript 102 | //在指定的路径上挂载指定的中间件函数:当请求的路径的基础部分与路径匹配时,中间件函数将执行。 103 | app.use("/api/users", users); 104 | ``` 105 | 106 | 接下来在浏览器输入`localhost:5000/api/users/test` 107 | 108 | 就会出现返回的信息 ![alt](./md-resources/routertest.jpg) 109 | 110 | ### 然后我们需要创建数据模型,用在数据库中存储并进行增删改查. 111 | 112 | 新建一个models文件夹(与server.js在同一目录) 113 | 114 | 在models文件夹内新建User.js文件(数据模型文件名字还是尽量与路由方法文件区分开,这里用的是老师的写法) 115 | 116 | 引入mongoose,并实例化Schema(模式;图式;架构) 117 | 118 | ```javascript 119 | const mongoose = require('mongoose'); 120 | const Schema = mongoose.Schema; 121 | ``` 122 | 123 | 创建一个Schema,填入属性和类型,类型需要首字母大写 124 | 125 | ```javascript 126 | const UserSchema = new Schema({ 127 | name: { 128 | type: String, 129 | required: true 130 | }, 131 | email: { 132 | type: String, 133 | required: true 134 | }, 135 | password: { 136 | type: String, 137 | required: true 138 | }, 139 | avatar: { 140 | type: String 141 | }, 142 | identity: { 143 | type: String, 144 | required: true 145 | }, 146 | date: { 147 | type: Date, 148 | default: Date.now 149 | } 150 | }); 151 | ``` 152 | require:必要的数据,没有则不会创建数据集合 153 | 154 | 使用这个Schema(模式)编译的Models(模型)也需要引出,所以 155 | 156 | ```javascript 157 | module.exports = User = mongoose.model('users', UserSchema); 158 | ``` 159 | . 160 | 161 | Models 是从 Schema 编译来的构造函数。 它们的实例就代表着可以从数据库保存和读取的 documents。 从数据库创建和读取 document 的所有操作都是通过 model 进行的。 162 | 163 | 第一个参数是跟 model 对应的集合( collection )名字的 单数 形式。 Mongoose 会自动找到名称是 model 名字 复数 形式的 collection 。 对于上例,User 这个 model 就对应数据库中 users 这个 collection。.model() 这个函数是对 schema 做了拷贝(生成了 model)。 你要确保在调用 .model() 之前把所有需要的东西都加进 schema 里了! 164 | 165 | 摘自 Mongoose 5.0 中文文档-Models (http://www.mongoosejs.net/docs/models.html) 166 | 167 | . 168 | 169 | 总结 170 | 171 | ![alt](./md-resources/day3.jpg) -------------------------------------------------------------------------------- /笔记/笔记3.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/笔记3.xmind -------------------------------------------------------------------------------- /笔记/笔记4.md: -------------------------------------------------------------------------------- 1 | ### 搭建注册接口并存储数据 2 | 3 | 接下来要搭建注册接口,但首先讲的是接口测试工具 4 | 5 | 老师用的是postman,我根据弹幕建议用的是apipost(postman为英文界面,apipost是中文界面) 6 | 7 | 下载ApiPost软件,打开如图所示,使用前请运行服务器和数据库 8 | 9 | ![alt](./md-resources/apipost.jpg) 10 | 11 | 准备好软件,就可以写注册接口了 12 | 13 | 在写之前需要npm安装body-parser 14 | 15 | 在终端输入`npm install body-parser`即可安装 16 | 17 | . 18 | 19 | body-parser介绍 20 | 21 | 处理用户post请求提交的数据,把数据保存在req.body中。以一个对象的形式提供给服务器,方便进行后续的处理。由于无论用户提交什么服务器都会接受,所以需要在使用数据前进行验证来提高安全性。 22 | 23 | 注意:此中间件已经被express集成,无需调用安装body-parser,可以直接采用express.json()和express.urlencoded()实现相同功能。东西都是一样的,所以这里还是使用body-parser来介绍。 24 | 25 | 摘自 神的孩子都在跳舞-深入浅出 Express 中间件 body-parser () 26 | 27 | 原来已经集成了呀...... 28 | 29 | . 30 | 31 | 安装完body-parser之后还需要在server.js中引入 32 | 33 | ```javascript 34 | //in server.js 35 | //引入body-parser,bodyparser是一类处理request的body的中间件函数,对传入的请求体进行解析 36 | const bodyParser = require("body-parser"); 37 | ``` 38 | 39 | 引入后,同样需要在server.js中使用此中间件 40 | 41 | ```javascript 42 | //这是常用的方法,常见的前端请求解决方案如表单post提交、axios、fetch等库的post请求都需要这个中间件进行解析,返回json的格式数据。当请求的数据类型是application/x-www-form-urlencoded时才会进入这个中间件进行处理。 43 | app.use(bodyParser.urlencoded({ extended: false })); 44 | //解析并返回 json格式的数据,这是常用的方法。内部会查看content-type,只有是正确的content-type默认是application/json才进入这个中间件解析处理。 45 | app.use(bodyParser.json()); 46 | ``` 47 | 48 | 注释摘自 神的孩子都在跳舞-深入浅出 Express 中间件 body-parser () 49 | 50 | 接下来就是写接口了,首先写一个注册接口 51 | 52 | 我们会将注册的邮箱和密码发送到服务器,首先是"发送" 53 | 54 | 在users.js中写下如下代码 55 | 56 | ```javascript 57 | //in users.js 58 | router.post('/register', (req, res) => { 59 | console.log(req.body) 60 | }); 61 | ``` 62 | 63 | 接下来可以测试一下这个接口 64 | 65 | ![alt](./md-resources/posttest1.jpg) 66 | 67 | 图中: 68 | 69 | 接口方法要使用POST, 70 | 71 | 路径与接口路径相同, 72 | 73 | 数据类型是application/x-www-form-urlencoded, 74 | 75 | 至少要发送内容否则代码只会返回空对象, 76 | 77 | `[Object:null prototype]`为在新版本node.js中,我们使用了旧的URL接口,新接口为`new URL(input[, base])`,目前不影响使用,如何更改这里就不演示了(因为我没改成功),具体可自行搜索. 78 | 79 | . 80 | 81 | POST 介绍 82 | 83 | POST 方法用来传输实体的主体。 虽然用 GET 方法也可以传输实体的主体,但一般不用 GET 方法进行 传输,而是用 POST 方法。虽说 POST 的功能与 GET 很相似,但 POST 的主要目的并不是获取响应的主体内容。 84 | 85 | 摘自《图解http》(上野宣 著) 86 | 87 | . 88 | 89 | 当我们的数据"发送"之后,服务器需要"判断"提交的邮箱是否和数据库中已经保存的邮箱有重复,我们需要引入数据库中的`User`来进行操作. 90 | 91 | ```javascript 92 | //in users.js 93 | const User = require('../../models/User'); 94 | ``` 95 | 96 | 接下来我们修改之前的代码为 97 | 98 | ```javascript 99 | //in users.js 100 | router.post('/register', (req, res) => { 101 | // 查询数据库中是否拥有邮箱 102 | User.findOne({ email: req.body.email }).then(user => { 103 | if (user) { 104 | return res.status(400).json('邮箱已被注册!'); 105 | } 106 | }) 107 | }) 108 | ``` 109 | 110 | . 111 | 112 | 上面代码中 `findOne()` 查询被执行时,查询结果被传给回调函数。形式为 `findOne({'xxx':'xxx'},callback(error,result))` 113 | 114 | 但如果不传callback参数,则Query 的一个实例(一个 query 对象)被返回,这个 query 提供了构建查询器的特殊接口。 115 | 116 | Query 实例有一个 `.then()`函数,then() 方法返回一个 Promise . 117 | 118 | Promise 对象用于表示一个异步操作的最终完成(或失败)及其结果值. 119 | 120 | 它最多需要有两个参数:Promise 的成功和失败情况的回调函数,语法为 121 | 122 | ```javascript 123 | p.then(onFulfilled[, onRejected]); 124 | 125 | p.then(value => { 126 | // fulfillment 127 | }, reason => { 128 | // rejection 129 | }); 130 | ``` 131 | 132 | 上面代码中 `.then(user => {...})` 对应 `.then(value => {...}` ,则为 `.then(onFulfilled)` 133 | 134 | 所以,当 `findOne()` 成功时,将找到的数据集合(包含模型里的所有信息,以对象的形式)传递给 `user` 后, `then()` 携带参数 `user` 执行接下来的函数. 135 | 136 | . 137 | 138 | 如果用户(user)存在,则返回状态码400,并返回json数据"邮箱已被注册!" 139 | 140 | 如果用户不存在(即可以注册),则为下面的代码 141 | 142 | ```javascript 143 | router.post('/register', (req, res) => { 144 | // 查询数据库中是否拥有邮箱 145 | User.findOne({ email: req.body.email }).then(user => { 146 | if (user) { 147 | console.log(user) 148 | return res.status(400).json('邮箱已被注册!'); 149 | } else { 150 | const newUser = new User({ 151 | name: req.body.name, 152 | email: req.body.email, 153 | password: req.body.password, 154 | identity: req.body.identity 155 | }); 156 | } 157 | }) 158 | }) 159 | ``` 160 | 创建一个新的User实例,并将POST的名字,email,密码填入,新实例的信息会添加进数据库中. 161 | 162 | 为了用户信息安全,我们需要对密码进行加密,需要安装npm包bcrypt 163 | 164 | 在终端输入`npm install bcrypt` 165 | 166 | 并且引入它 167 | 168 | ```javascript 169 | const bcrypt = require('bcrypt'); 170 | ``` 171 | bcrypt是一个可以帮助你加密密码的库 172 | 173 | 不必多说,直接就用吧,将代码添加在`const newUser`函数之后 174 | 175 | ```javascript 176 | bcrypt.genSalt(10, function(err, salt) { 177 | bcrypt.hash(newUser.password, salt, (err, hash) => { 178 | if (err) throw err; 179 | newUser.password = hash; 180 | newUser 181 | .save() 182 | .then(user => res.json(user)) 183 | .catch(err => console.log(err)); 184 | }); 185 | }); 186 | ``` 187 | bcrypt官方文档的代码为 188 | 189 | ```javascript 190 | const bcrypt = require('bcrypt'); 191 | const saltRounds = 10; 192 | const myPlaintextPassword = 's0/\/\P4$$w0rD'; 193 | const someOtherPlaintextPassword = 'not_bacon'; 194 | 195 | bcrypt.genSalt(saltRounds, function(err, salt) { 196 | bcrypt.hash(myPlaintextPassword, salt, function(err, hash) { 197 | // Store hash in your password DB. 198 | }); 199 | }); 200 | ``` 201 | saltRounds可以适当更改 202 | 203 | myPlaintextPassword是你需要加密的密码 204 | 205 | hash即为已经加密的密码,在我们的代码中是将加密后生成的字符串覆盖了之前的密码 206 | 207 | 更多用法在(https://www.npmjs.com/package/bcrypt) 208 | 209 | 然后执行存储方法`save()`,当您使用 new 创建 Mongoose 模型的实例时,调用 save() 会使 Mongoose 插入一个新文档。 210 | 211 | 存储成功了,就会返回json数据(在代码中为user对象) 212 | 213 | 出错则会返回错误 214 | 215 | 接下来在ApiPost测试一下 216 | 217 | ![alt](./md-resources/postsuccess.jpg) 218 | 219 | 数据返回成功! 220 | 221 | ### 总结 222 | 223 | ![alt](./md-resources/day4.jpg) -------------------------------------------------------------------------------- /笔记/笔记4.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/笔记4.xmind --------------------------------------------------------------------------------