代理系统开发记录
React + Express + MongoDB
# 工具们
# Yarn
之前一直使用npm,但是有时候实在是太慢(改host也比较麻烦),我就换用了cnpm。听说上个月出来了个新的包管理工具:Yarn,我先拿来试一下......
话说Yarn的官网全是喵。咪桑万岁!
# Version
yarn install v0.27.5
# ex-GF => NPM
npm啥都好,就是没有科学上网前,这就是新世界...
npm会把依赖安装在node_modules中,但是这个过程具有不确定性:当依赖的安装顺序不同的时候,node_modules的目录结构可能会发生变化。
=>结果可能是在不同机子上可能会出现不能运行的情况。
话说我是没有见过这种情况,可能是package.json可能会发生版本匹配错误啥的。为了预防万一,偶尔还是把node_modules一起存一下。(7z压缩这个贼快!)
# 特性
以下,从官网 (opens new window)上看到的...
超快:从缓存中拿到下载过的包,重复利用 安全:自动校验包的完整性 可靠:各系统无差异工作
# 差异
- yarn.lock,解决了只用package.json可能会发生的版本匹配错误。
- 并行安装依赖,缓存中获取依赖
- 好多命令变了
# 使用
因为node自带了npm,所以安装yarn只需npm install yarn就好。
二房居然是大房拉进来的!天呐。
- 初始化新项目(npm init)
yarn init
yarn init
- 添加依赖(npm install)
yarn add
yarn add
- 更新依赖(npm upgrade)
yarn upgrade
//感觉不怎么用,除非有特别需要的功能更新了,更新依赖可能需要修改依赖的使用方式。
2
3
yarn upgrade
//感觉不怎么用,除非有特别需要的功能更新了,更新依赖可能需要修改依赖的使用方式。
2
3
- 删除依赖(npm uninstall)
yarn remove
yarn remove
- 安装依赖
yarn
yarn install
2
yarn
yarn install
2
# Express
在毕业设计里我有使用过Express,简单的使用,可以在毕设相关的文章里了解一下。
这次的项目由于会上线使用,如果需要,我想更深入的学习一下Express。
yarn install v4.15.4
# 对比
毕设中,我用Express来作为整体框架,前后端并没有分开;这一次,我使用前后端分离的理念来做。
So,区别还是有一些的,从route.js来说明。
# route.js
- 毕设
请求方法有get、post、delete,效果为在页面中直接使用地址即可访问对应页面。
使用了依据Schema对应写了对应的controller方法,通过render来调用模板引擎。
模板引擎我选择了Jade。
- 本次
请求方法只是post,因为这些接口我需要在前端使用fetch来请求。
请求调用了Schema的方法,对数据库进行操作
至此,Express的任务就没有了。
两个项目构造不同,所以Express的使用权重并不类似,如果非得说相似处,只能说Schema通过mongoose来操作数据库的方法类似,都是返回json数据,一个是引擎调用,一个是接口获取。
# React
运气不错,找到了很多文档,比较方便去了解。
说白了,就是在写组件,用props来传入数据,用不同的状态来操作数据去刷新组件。
另外,由于对react组件状态的了解不是很深入,没有点得心应手···
# React-Router
这个是真的坑。
百度搜索只有v2.X的文档,然后我以为新的就是2.X版本,没想到我用的已经算是新版本4.X了,其中的差距非常大。
为了赶时间,我并没有看说明上的例子,直接开始写,就采坑无数...
# MongoDB
还是使用mongoose操作,用到了更多的方法,也更熟悉了Robomongo。
有意思的就属于模糊查询、条件筛选啦
# 初想
# 蓝图

刚开始,我没有想的很深入,只是草草的画了一下结构,还有页面的组成。
实在是草图,很随意···
# 页面结构
页面结构如下图所示,其中名称后有#的为非重点页面(不一定实现)。
graph TD
A[登录页] --> B[管理员首页]
A[登录页] --> C[代理首页]
B --> D[项目管理]
B --> H[用户管理]
D --> E[项目查看#]
D --> F[项目查询]
D --> G[项目状态修改]
H --> I[新增用户]
H --> J[删除用户]
H --> K[充值用户]
H --> L[查询用户]
C --> M[项目管理]
C --> N[查看账单]
C --> O[项目申请]
C --> P[账户设置]
M --> Q[项目状态修改]
M --> R[查看项目详情]
N --> R
O --> S[选择模板]
O --> V[保存申请]
P --> T[基本设置]
P --> U[修改密码]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 技术结构
sequenceDiagram
React->>Express: I need data.
Express->>MongoDB: I told you.
MongoDB->>Express: I find this!
Express->>React: Hey man,look at this.
2
3
4
5
大概就是这个意思,中间的通讯方式自然就是接口啦。
# 实现
初上手的感觉就是无从下手,但是在一切都梳理好之后,还都不算很难。
# 代码
代码也在github的这个项目:Agent-customer-management-system (opens new window)上放着呢,但是我还不会用npm上传那种方式,就只好把除了node_module的其他文件上传。
另外,我没有上传数据库备份,拿下来的肯定是没有数据的。
# 坑
大概记录一下做项目中间遇见的坑。
# Q1·React不能引用插件
问题描述:
在本地写的react项目,转化为node上的react后,原来的插件不能用。
解答:
实际很简单,插件中没有export语法,所以在引用插件时会发生很多问题。解决办法就是用插件对应的react版本或者自行改造。
刚遇见的时候以为碰见什么巨难的问题了,所以就写了篇,记录一下。文章链接 (opens new window)
# Q2·修改链接(React-Router v4)
问题描述:
退出功能时需要修改链接(返回登录页),失败
解答:
不是真的失败,是版本修改之后需要使用withRouter才能push新路径。
代码:
import {
Link,
withRouter
} from 'react-router-dom';
class Header extends Component {
A(){
this.props.history.push("/");
}
}
export default withRouter(Header);
2
3
4
5
6
7
8
9
10
11
# Q3·修改路径之后不主动刷新(React-Router v4)
问题描述:
这个问题是出在上一个解决之后,链接成功跳转但是组件没有刷新。
解答:
原理是什么我还没有搞清楚,但是解决的办法就是手动刷新···
window.location.reload();
# Q4·Link跳转时组件不出现或刷新后消失
问题描述:
问题在于我页面间切换时发现链接变了但是组件没有变。
解答:
实际上是由于我没有明确组件的概念,把react组件与router混着写,虽然看起来没有报错,但会出现很多奇怪的问题。
在分开之后,明确什么是container文件夹应该有的代码,什么是component文件夹应该有的东西。
//container文件夹存放页面以及对应的跳转
import React, {
Component
} from 'react';
import {
BrowserRouter as Router,
Route,
Redirect
} from 'react-router-dom';
import Project from '../containers/project';
import Bill from '../containers/bill';
import ApplyPro from '../containers/applyPro';
import Setting from '../containers/setting';
import Header from '../components/Header';
class Main extends Component {
render() {
var username = document.cookie ? JSON.parse('{"' + document.cookie.replace(/;/g, '","').replace(/=/g, '":"').replace(/\s/g, '') + '"}').username : undefined;
if (username === undefined) {
return (
<Redirect to="/" />
)
} else {
return (
<Router>
<div className="body">
<Header user={this.state.user} />
<Route path="/main/pro" component={Project}/>
<Route path="/main/setting" component={Setting}/>
<Route path="/main/billList" component={Bill}/>
<Route path="/main/applyPro" component={ApplyPro}/>
</div>
</Router>
);
}
}
}
export default Main;
//component文件夹存放组件还有Link与强制跳转
import React, {
Component
} from 'react';
import {
Link,
withRouter
} from 'react-router-dom';
import './Header.css';
class Header extends Component {
render() {
return (
<div className="header">
<div className="header-left">
<span>欢迎 {$data.name} 进入XXX营销管理平台</span>
<span>
余额
<span>{money}</span>{
this.props.location.pathname === "/main/pro" ?
<Link to="/main/billList">查看消费明细</Link> :
<Link to="/main/pro">查看项目列表</Link>
}
<Link to="/main/applyPro" className="applyBtn">项目申请</Link>
</span>
</div>
<div className="header-right">
<Link to="/main/setting">账户设置</Link>
<a onClick={this.handleClick.bind(this)}>退出</a>
</div>
</div>
);
}
}
export default withRouter(Header);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

# Q5·react组件化
问题描述:
自以为明白了啥是组件化,就以为自己写的代码是组件化···
解答:
写完了才发现,当前这些我自认为是组件的东西换个地方很难复用。
现在心里面有个想法,就是把其中获取数据的部分提取出来,然后通过props传进去,以后再用,只需要把所有的参数都传进去就可以复用了。
找个闲了的时间,先提取一下看看可行与否。
# Q6·模糊查询
问题描述:
因为我需要做一个搜索的功能,所以就牵扯到了模糊查询。
解答:
官方文档是英文的,不是很好看。
所以我一般是先查询MongoDB有什么方法、功能,然后根据功能点去查询mongoose的方法。
看起来比较麻烦,但是实际执行起开还是蛮快的。
实现原理是通过正则表达式来匹配合适的值,如果有哪里不会查询了,先去想合适的正则表达式。
var _name = new RegExp(sortName, "g");
this.find({
"name": _name
}).sort({
"_id": -1
}).exec((err, userList) => {
if (err) {
//logger.error(err);
console.log(err);
} else {
callback(userList);
}
});
2
3
4
5
6
7
8
9
10
11
12
13
# Q7·mongoose创建新文档失败
问题描述:
我把接收到的json直接存入,报错save is not a function
解答:
出现这个问题是因为加盐(bcrypt)后存入,this混乱。
因为这个json只是属性一样,但并不是当前的Schema对象,所以不存在这个方法。
只需要使用当前Schema的方法就可以。
var self = this;
self.create(_newUser, (err) => {
if (err) {
console.log(err);
callback("faile");
} else {
callback("success");
}
})
2
3
4
5
6
7
8
9
# Q8·校验密码接口不会实现
问题描述:
因为校验密码需要用到User的多个static方法,直接把这样写在static里面不合适,写在外面时,我搞不明白参数的传递,导致一直报错。
解答:
说白了,是由于逻辑不清晰,导致传参混乱,然后报了一堆错误。
router.post('/checkPassword', function(req, res, next) {
User.findUserByName(req.body.username, (user) => {
if (null != user) {
User.comparePassword(req.body.password, user.pwd, (err, isMatch) => {
if (err) {
console.log(err)
} else {
if (isMatch) {
res.send(200, {
status: "ok",
username: user.name,
userGroup: user.group
});
} else {
res.send(200, {
status: "error",
message: "密码错误。"
});
}
}
})
} else {
res.send(200, {
statuskey: "error",
message: "用户名不存在。"
});
}
});
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
有必要专门对于参数这里,重新阅读js高程。
# Q8·自适应的样式不合适
问题描述:
没有明确自适应方案时,没有合适的显示自适应效果。
解答:
先想好,再写。
不要担心因为前期的构思而耽误太久的时间,在构思好后,比较花时间的只有两个:工作量和坑。
需要说明一下,遇见坑的时候,千万记得要找个新思路。我的方法是:和别人聊聊,思路就会丰富的多。
因为没有移动版的需求,自适应时没有用媒体查询,以后需要自己写个东西对移动端更加熟悉。
# 总结
嘿嘿,写个版本号激励一下自己。
暂时是可以打开测一测了(1.2.1),不知道还有哪些需要改的。
过程中因为踩坑没法解决,心情不好很多次,结局证明调整心态是做事中重要的一点,可以保证效率,保证质量。
其余的,就是业务、流程的调整还有上面说的组件化还会有一些工作量,其余的,就可以慢慢优化我的方法了。
希望这个项目可以被稍稍的认可。
_〆(。。)