├── .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 |
2 |
3 |
4 |
5 |
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 |
2 |
3 |
9 |
10 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | 取 消
49 | 提 交
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
111 |
112 |
--------------------------------------------------------------------------------
/前端/client/src/components/HeadNav.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 米修在线后台管理系统
7 |
8 |
9 |
10 |
![]()
11 |
12 |
欢迎
13 |
{{user.name}}
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 | 个人信息
24 | 退出
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
74 |
75 |
141 |
--------------------------------------------------------------------------------
/前端/client/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 | For a guide and recipes on how to configure / customize this project,
6 | check out the
7 | vue-cli documentation.
8 |
9 |
Installed CLI Plugins
10 |
15 |
Essential Links
16 |
23 |
Ecosystem
24 |
31 |
32 |
33 |
34 |
42 |
43 |
44 |
60 |
--------------------------------------------------------------------------------
/前端/client/src/components/LeftMenu.vue:
--------------------------------------------------------------------------------
1 |
2 |
35 |
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 |
2 |
3 |

4 |
5 |
6 |
7 |
18 |
19 |
--------------------------------------------------------------------------------
/前端/client/src/views/AboutView.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is an about page
4 |
5 |
6 |
--------------------------------------------------------------------------------
/前端/client/src/views/FoundList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
12 | --
13 |
18 |
19 |
20 |
21 | 筛选
28 |
29 |
30 | 添加
37 |
38 |
39 |
40 |
41 |
49 |
50 |
51 |
58 |
59 |
60 | {{ scope.row.date }}
61 |
62 |
63 |
69 |
70 |
76 |
77 |
78 |
79 | + {{ scope.row.income }}
80 |
81 |
82 |
83 |
84 | - {{ scope.row.expend }}
85 |
86 |
87 |
93 |
94 | {{ scope.row.cash }}
95 |
96 |
97 |
98 |
99 |
106 |
107 | 编辑
114 | 删除
121 |
122 |
123 |
124 |
125 |
126 |
127 |
140 |
141 |
142 |
143 |
144 |
149 |
150 |
151 |
152 |
300 |
315 |
--------------------------------------------------------------------------------
/前端/client/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
米修在线
5 |
专注于线上教育, 用心做课程, 用心做服务!
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/前端/client/src/views/HomeView.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/前端/client/src/views/Index.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
23 |
38 |
39 |
--------------------------------------------------------------------------------
/前端/client/src/views/InfoShow.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
![]()
7 |
8 |
9 |
10 |
11 |
12 |
13 | {{user.name}}
14 |
15 |
16 |
17 | {{user.identity == 'manager' ? '管理员' : '普通员工'}}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
34 |
73 |
--------------------------------------------------------------------------------
/前端/client/src/views/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
25 |
88 |
89 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/前端/client/src/views/Register.vue:
--------------------------------------------------------------------------------
1 |
2 |
32 |
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 | 
--------------------------------------------------------------------------------
/笔记/笔记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 | 就会出现返回的信息 
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 | 
--------------------------------------------------------------------------------
/笔记/笔记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 | 
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 | 
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 | 
218 |
219 | 数据返回成功!
220 |
221 | ### 总结
222 |
223 | 
--------------------------------------------------------------------------------
/笔记/笔记4.xmind:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotingmeow/Capital-management-system-with-authority/e3097a6edf76429bca2df494da45245392a4e0a5/笔记/笔记4.xmind
--------------------------------------------------------------------------------