forked from niemingzhao/niemingzhao.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
278 lines (151 loc) · 177 KB
/
atom.xml
1
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>聂明照的博客</title>
<subtitle>桃李不言,下自成蹊</subtitle>
<link href="http://www.niemingzhao.top/atom.xml" rel="self"/>
<link href="http://www.niemingzhao.top/"/>
<updated>2020-12-20T13:20:45.353Z</updated>
<id>http://www.niemingzhao.top/</id>
<author>
<name>聂明照</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>Ubuntu Server Settings</title>
<link href="http://www.niemingzhao.top/2020/12/20/Ubuntu-Server-Settings/"/>
<id>http://www.niemingzhao.top/2020/12/20/Ubuntu-Server-Settings/</id>
<published>2020-12-20T12:27:16.000Z</published>
<updated>2020-12-20T13:20:45.353Z</updated>
<content type="html"><![CDATA[<a id="more"></a><h3 id="Initial Settings">Initial Settings<a class="header-anchor" href="#Initial Settings" aria-hidden="true"></a></h3><h4 id="Change Source List (Optional)">Change Source List (Optional)<a class="header-anchor" href="#Change Source List (Optional)" aria-hidden="true"></a></h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">lsb_release -a</span><br><span class="line"></span><br><span class="line">sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak</span><br><span class="line">sudo vi /etc/apt/sources.list</span><br><span class="line"></span><br><span class="line">:%d</span><br><span class="line"></span><br><span class="line">...(for 18.04)</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse</span><br><span class="line">...</span><br><span class="line">...(for 16.04)</span><br><span class="line"># deb cdrom:[Ubuntu 16.04 LTS _Xenial Xerus_ - Release amd64 (20160420.1)]/ xenial main restricted</span><br><span class="line">deb-src http://archive.ubuntu.com/ubuntu xenial main restricted #Added by software-properties</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ xenial main restricted multiverse universe #Added by software-properties</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted multiverse universe #Added by software-properties</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ xenial universe</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ xenial multiverse</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ xenial-updates multiverse</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse #Added by software-properties</span><br><span class="line">deb http://archive.canonical.com/ubuntu xenial partner</span><br><span class="line">deb-src http://archive.canonical.com/ubuntu xenial partner</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted multiverse universe #Added by software-properties</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ xenial-security universe</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ xenial-security multiverse</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">:wq!</span><br><span class="line"></span><br><span class="line">sudo apt-get update</span><br></pre></td></tr></table></figure><h4 id="Update System">Update System<a class="header-anchor" href="#Update System" aria-hidden="true"></a></h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get upgrade</span><br><span class="line">sudo apt-get dist-upgrade</span><br><span class="line">sudo apt-get install -f</span><br><span class="line">sudo apt-get autoremove</span><br><span class="line">sudo apt-get autoclean</span><br><span class="line">sudo apt-get clean</span><br></pre></td></tr></table></figure><h4 id="Add New User">Add New User<a class="header-anchor" href="#Add New User" aria-hidden="true"></a></h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">sudo adduser nie</span><br><span class="line"></span><br><span class="line">sudo vi /etc/sudoers</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"># User privilege specification</span><br><span class="line">...</span><br><span class="line">nie ALL=(ALL:ALL) ALL</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">:wq!</span><br><span class="line"></span><br><span class="line">history -c && history -w</span><br><span class="line">su nie</span><br></pre></td></tr></table></figure><h4 id="Enable SSH Remote Login">Enable SSH Remote Login<a class="header-anchor" href="#Enable SSH Remote Login" aria-hidden="true"></a></h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install openssh-client</span><br><span class="line">sudo apt-get install openssh-server</span><br><span class="line"></span><br><span class="line">sudo vi /etc/ssh/sshd_config</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line">PermitRootLogin no</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">:wq!</span><br><span class="line"></span><br><span class="line">sudo service ssh restart</span><br></pre></td></tr></table></figure><h4 id="Install Basic Environment">Install Basic Environment<a class="header-anchor" href="#Install Basic Environment" aria-hidden="true"></a></h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install git</span><br><span class="line">sudo apt-get install wget</span><br><span class="line">sudo apt-get install curl</span><br><span class="line">sudo apt-get install openssl</span><br><span class="line">sudo apt-get install libssl-dev</span><br><span class="line">sudo apt-get install ca-certificates</span><br><span class="line">sudo apt-get install build-essential</span><br><span class="line"></span><br><span class="line">sudo apt-get install python</span><br><span class="line">sudo apt-get install python-pip</span><br><span class="line">sudo apt-get install python-dev</span><br><span class="line">sudo apt-get install python3</span><br><span class="line">sudo apt-get install python3-pip</span><br><span class="line">sudo apt-get install python3-dev</span><br><span class="line">sudo apt-get install python3-venv</span><br><span class="line"></span><br><span class="line">mkdir ~/.pip</span><br><span class="line">vi ~/.pip/pip.conf</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line">[global]</span><br><span class="line">index-url = https://pypi.tuna.tsinghua.edu.cn/simple</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">:wq!</span><br><span class="line"></span><br><span class="line">cd ~</span><br><span class="line">python3 -m venv venv</span><br><span class="line">source venv/bin/activate</span><br><span class="line">python -m pip install --upgrade pip setuptools</span><br><span class="line">pip install wheel twine autopep8 pylint PyInstaller Sphinx PyQt5 numpy sympy scipy pandas matplotlib scikit-learn scikit-image requests beautifulsoup4 jupyter jupyter_contrib_nbextensions</span><br><span class="line">jupyter contrib nbextension install --sys-prefix</span><br><span class="line">mkdir ~/workspace</span><br><span class="line">mkdir ~/workspace/notebook</span><br><span class="line">jupyter notebook --generate-config</span><br><span class="line">jupyter notebook password</span><br><span class="line">vi ~/.jupyter/jupyter_notebook_config.py</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line">c.NotebookApp.notebook_dir = u'/home/nie/workspace/notebook'</span><br><span class="line">c.NotebookApp.allow_remote_access = True</span><br><span class="line">c.NotebookApp.open_browser = False</span><br><span class="line">c.NotebookApp.ip = '*'</span><br><span class="line">c.NotebookApp.port = 8888</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">:wq!</span><br><span class="line"></span><br><span class="line">sudo vi /lib/systemd/system/jupyter.service</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line">[Unit]</span><br><span class="line">Description=jupyter</span><br><span class="line">After=network.target</span><br><span class="line">[Service]</span><br><span class="line">User=nie</span><br><span class="line">Group=nie</span><br><span class="line">Type=simple</span><br><span class="line">PIDFile=/run/jupyter.pid</span><br><span class="line">WorkingDirectory=/home/nie/workspace/notebook</span><br><span class="line">EnvironmentFile=/home/nie/venv/bin/jupyter</span><br><span class="line">ExecStart=/home/nie/venv/bin/jupyter notebook</span><br><span class="line">Restart=always</span><br><span class="line">RestartSec=30s</span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">:wq!</span><br><span class="line"></span><br><span class="line">sudo systemctl daemon-reload</span><br><span class="line">sudo systemctl enable jupyter.service</span><br><span class="line">sudo systemctl start jupyter.service</span><br><span class="line">sudo systemctl status jupyter.service</span><br><span class="line"></span><br><span class="line">deactivate</span><br><span class="line"></span><br><span class="line">sudo apt-get install software-properties-common</span><br><span class="line">sudo add-apt-repository ppa:webupd8team/java</span><br><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get install oracle-java8-installer</span><br><span class="line">sudo apt-get install oracle-java8-set-default</span><br><span class="line">sudo vi /etc/environment</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line">JAVA_HOME="/usr/lib/jvm/java-8-oracle"</span><br><span class="line">JRE_HOME="/usr/lib/jvm/java-8-oracle/jre"</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">:wq!</span><br><span class="line"></span><br><span class="line">source /etc/environment</span><br><span class="line">echo $JAVA_HOME</span><br><span class="line"></span><br><span class="line">sudo apt-get install maven</span><br><span class="line"></span><br><span class="line">sudo apt-get install nginx</span><br><span class="line">ls /etc/nginx/sites-available</span><br><span class="line">ls /etc/nginx/sites-enabled</span><br><span class="line">sudo service nginx reload</span><br><span class="line"></span><br><span class="line">sudo apt-get install tomcat8</span><br><span class="line">sudo apt-get install tomcat8-admin tomcat8-docs tomcat8-examples tomcat8-user</span><br><span class="line">ls /var/lib/tomcat8/webapps</span><br><span class="line">sudo vi /etc/tomcat8/tomcat-users.xml</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line"> <role rolename="manager-gui"/></span><br><span class="line"> <role rolename="admin-gui"/></span><br><span class="line"> <user username="nie" password="123456" roles="manager-gui,admin-gui"/></span><br><span class="line"></tomcat-users></span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">:wq!</span><br><span class="line"></span><br><span class="line">sudo service tomcat8 restart</span><br><span class="line"></span><br><span class="line">sudo apt-get install nodejs</span><br><span class="line">sudo apt-get install nodejs-dev</span><br><span class="line">sudo apt-get install npm</span><br><span class="line">npm config set registry https://registry.npm.taobao.org</span><br><span class="line">sudo npm install -g npm</span><br><span class="line">sudo npm install -g n</span><br><span class="line">sudo n lts</span><br><span class="line">sudo npm cache clean --force</span><br><span class="line"></span><br><span class="line">sudo apt-get install mariadb-server mariadb-client</span><br><span class="line">sudo mysql -u root</span><br><span class="line"></span><br><span class="line">use mysql;</span><br><span class="line">update user set plugin='' where User='root';</span><br><span class="line">flush privileges;</span><br><span class="line">exit</span><br><span class="line"></span><br><span class="line">sudo service mysql restart</span><br><span class="line">sudo mysql_secure_installation</span><br><span class="line">sudo mysql -u root -p</span><br><span class="line"></span><br><span class="line">exit</span><br><span class="line"></span><br><span class="line">sudo apt-get install mongodb</span><br><span class="line">sudo service mongodb restart</span><br><span class="line">mongo</span><br><span class="line"></span><br><span class="line">exit</span><br><span class="line"></span><br><span class="line">sudo apt-get install redis-server</span><br><span class="line">sudo service redis-server restart</span><br><span class="line">redis-cli</span><br><span class="line"></span><br><span class="line">exit</span><br></pre></td></tr></table></figure><h4 id="Safeguard System">Safeguard System<a class="header-anchor" href="#Safeguard System" aria-hidden="true"></a></h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install rkhunter</span><br><span class="line">sudo vi /etc/rkhunter.conf</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line">UPDATE_MIRRORS=1</span><br><span class="line">...</span><br><span class="line">MIRRORS_MODE=0</span><br><span class="line">...</span><br><span class="line">WEB_CMD=""</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">:wq!</span><br><span class="line"></span><br><span class="line">sudo rkhunter --update</span><br><span class="line">sudo rkhunter --checkall</span><br><span class="line"></span><br><span class="line">sudo apt-get install clamav</span><br><span class="line">sudo apt-get install clamav-daemon</span><br><span class="line">sudo clamscan -r ~/ --remove</span><br><span class="line"></span><br><span class="line">sudo apt-get install denyhosts</span><br><span class="line">sudo vi /etc/denyhosts.conf</span><br><span class="line"></span><br><span class="line">...</span><br><span class="line">PURGE_DENY = 1h</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">:wq!</span><br><span class="line"></span><br><span class="line">sudo service denyhosts stop</span><br><span class="line">sudo denyhosts --purge</span><br><span class="line">sudo service denyhosts restart</span><br><span class="line">sudo iptables --flush</span><br></pre></td></tr></table></figure><h4 id="Cleanup System">Cleanup System<a class="header-anchor" href="#Cleanup System" aria-hidden="true"></a></h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get autoremove --purge</span><br><span class="line">sudo apt-get autoclean</span><br><span class="line">sudo apt-get clean</span><br><span class="line">kill -9 $(ps -A -ostat,ppid | grep -e '[zZ]'| awk '{ print $2 }')</span><br><span class="line">dpkg -l |grep ^rc|awk '{print $2}' |sudo xargs dpkg -P</span><br><span class="line">history -c && history -w</span><br></pre></td></tr></table></figure><h4 id="Backup System">Backup System<a class="header-anchor" href="#Backup System" aria-hidden="true"></a></h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">sudo su</span><br><span class="line">cd /</span><br><span class="line">tar -cvpzf backup.tar.gz --exclude=/backup.tar.gz --exclude=/proc --exclude=/sys --exclude=/mnt --exclude=/media --exclude=/run --exclude=/dev /</span><br><span class="line"></span><br><span class="line">sudo su</span><br><span class="line">cd /</span><br><span class="line">tar -xvpzf backup.tar.gz -C / --numeric-owner</span><br><span class="line">mkdir /proc /sys /mnt /media</span><br><span class="line">reboot</span><br><span class="line"></span><br><span class="line">(from Live CD)</span><br><span class="line">sudo su</span><br><span class="line">cd /</span><br><span class="line">ls /media</span><br><span class="line">rm -fr /media/whatever/*</span><br><span class="line">tar -xvpzf /path/to/backup.tar.gz -C /media/whatever --numeric-owner</span><br><span class="line">mkdir /media/whatever/proc /media/whatever/sys /media/whatever/mnt /media/whatever/media</span><br><span class="line">for f in dev dev/pts proc ; do mount --bind /$f /media/whatever/$f ; done</span><br><span class="line">chroot /media/whatever</span><br><span class="line">dpkg-reconfigure grub-pc</span><br><span class="line">reboot</span><br></pre></td></tr></table></figure><h3 id="Command Skills">Command Skills<a class="header-anchor" href="#Command Skills" aria-hidden="true"></a></h3><h4 id="Software">Software<a class="header-anchor" href="#Software" aria-hidden="true"></a></h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">apt-cache search package # 查找软件库中的包</span><br><span class="line">apt-cache show package # 显示包信息</span><br><span class="line">apt-cache depends package # 查询包依赖哪些包</span><br><span class="line">apt-cache rdepends package # 查询包被哪些包依赖</span><br><span class="line">sudo apt-get update # 更新包列表</span><br><span class="line">sudo apt-get upgrade # 升级所有包</span><br><span class="line">sudo apt-get dist-upgrade # 升级所有包,更新依赖关系</span><br><span class="line">sudo apt-get install -f # 修复所有包依赖关系</span><br><span class="line">sudo apt-get install package # 安装包</span><br><span class="line">sudo apt-get install package --reinstall # 重新安装包</span><br><span class="line">sudo apt-get remove package # 卸载包</span><br><span class="line">sudo apt-get purge package # 卸载包,删除配置文件</span><br><span class="line">sudo apt-get autoremove # 卸载孤立包</span><br><span class="line">sudo apt-get autoclean # 清理旧版本包缓存</span><br><span class="line">sudo apt-get clean # 清理所有包缓存</span><br><span class="line">sudo apt-get check # 检查所有包依赖关系</span><br><span class="line"></span><br><span class="line">dpkg -L package # 查看包安装内容</span><br><span class="line">dpkg -S filename # 查找文件属于哪个包</span><br><span class="line">dpkg -l # 查看已安装包列表</span><br><span class="line">dpkg -l | grep package # 查看已安装相关包列表</span><br></pre></td></tr></table></figure><h4 id="System">System<a class="header-anchor" href="#System" aria-hidden="true"></a></h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br></pre></td><td class="code"><pre><span class="line">uname -a # 查看内核</span><br><span class="line">lsb_release -a # 查看系统版本</span><br><span class="line">lscpu # 查看CPU信息</span><br><span class="line">lsmod # 查看内核模块信息</span><br><span class="line">lspci # 查看PCI设备</span><br><span class="line">lsusb # 查看USB设备</span><br><span class="line">lsblk # 查看块设备</span><br><span class="line">sudo lshw # 显示硬件信息</span><br><span class="line">sudo dmidecode # 显示硬件信息</span><br><span class="line">cat /proc/cpuinfo # 查看CPU信息</span><br><span class="line">cat /proc/interrupts # 查看中断信息</span><br><span class="line">cat /proc/meminfo # 查看内存使用信息</span><br><span class="line">cat /proc/net/dev # 查看网络统计信息</span><br><span class="line">cat /proc/mounts # 查看文件系统信息</span><br><span class="line">cat /proc/swaps # 查看swap使用信息</span><br><span class="line">cat /proc/mdstat # 查看软raid阵列信息</span><br><span class="line">cat /proc/scsi/scsi # 查看硬raid阵列信息</span><br><span class="line">uptime # 显示系统运行时间</span><br><span class="line">date # 显示系统日期</span><br><span class="line">last # 查看系统登录情况</span><br><span class="line">lastlog # 查看用户登录情况</span><br><span class="line">ulimit -a # 查看系统限制</span><br><span class="line">ipcs -l # 查看内核限制</span><br><span class="line"></span><br><span class="line">blkid # 查看硬盘分区ID</span><br><span class="line">sudo fdisk -l # 查看硬盘分区</span><br><span class="line">sudo fdisk /dev/sda1 # 硬盘分区</span><br><span class="line">sudo mkfs -t ext3 /dev/sda1 # 硬盘格式化,ext3分区</span><br><span class="line">sudo mkfs -t vfat /dev/sda1 # 硬盘格式化,fat32分区</span><br><span class="line">sudo mkfs -t ntfs /dev/sda1 # 硬盘格式化,ntfs分区</span><br><span class="line">sudo mount -t ntfs -o nls=utf8,umask=0 /dev/sdb1 /mnt/c # 只读挂载ntfs分区</span><br><span class="line">sudo mount -t ntfs-3g -o locale=zh_CN.utf8,umask=0 /dev/sdb1 /mnt/c # 可写挂载ntfs分区</span><br><span class="line">sudo mount -t vfat -o iocharset=utf8,umask=0 /dev/sda1 /mnt/c # 挂载fat32分区</span><br><span class="line">sudo mount -t smbfs -o username=xxx,password=xxx,iocharset=utf8 //192.168.1.1/share /mnt/share # 挂载网络共享文件</span><br><span class="line">sudo mount -t iso9660 -o loop,utf8 xxx.iso /mnt/iso # 挂载ISO文件</span><br><span class="line">sudo umount /dev/sda1 # 卸载分区</span><br><span class="line">df -h # 查看硬盘剩余空间</span><br><span class="line">sudo du -hs dirname # 查看目录占用空间</span><br><span class="line"></span><br><span class="line">free -h # 查看内存使用情况</span><br><span class="line">top # 动态显示进程执行情况</span><br><span class="line">ps -A # 查看当前进程</span><br><span class="line">ps -ef | grep srvname # 查看进程执行情况</span><br><span class="line">pstree # 查看当前进程树</span><br><span class="line">sudo kill PID # 中止进程</span><br><span class="line">sudo kill -9 PID # 强制中止进程</span><br><span class="line">sudo lsof -p PID # 查看进程打开的文件</span><br><span class="line">sudo lsof filename # 查看打开文件的进程</span><br><span class="line">sudo lsof -i :portname # 查看使用端口的进程</span><br><span class="line">nohup program & # 后台运行程序</span><br><span class="line"></span><br><span class="line">ifconfig # 查看IP地址</span><br><span class="line">ping IP # 查看IP地址连接情况</span><br><span class="line">host hostname # 查看主机名称对应的IP地址</span><br><span class="line">sudo route -n # 查看路由信息</span><br><span class="line">sudo netstat -atnp # 查看网络连接状况</span><br><span class="line">sudo dhclient # 使用DHCP协定从服务器获取IP地址</span><br><span class="line">sudo iptables -t nat -L # 查看nat规则</span><br><span class="line">sudo iptables -L -n # 查看filter规则</span><br><span class="line"></span><br><span class="line">service --status-all # 查看全部服务状态</span><br><span class="line">sudo service srvname start # 启动服务</span><br><span class="line">sudo service srvname stop # 停止服务</span><br><span class="line">sudo service srvname restart # 重启服务</span><br><span class="line">sudo service srvname status # 查看服务状态</span><br><span class="line"></span><br><span class="line">sudo adduser username # 增加用户,创建用户目录</span><br><span class="line">sudo useradd username # 增加用户</span><br><span class="line">sudo deluser username # 删除用户,删除用户目录</span><br><span class="line">sudo userdel username # 删除用户</span><br><span class="line">sudo addgroup groupname # 增加用户组</span><br><span class="line">sudo groupadd groupname # 增加用户组</span><br><span class="line">sudo delgroup groupname # 删除用户组</span><br><span class="line">sudo groupdel groupname # 删除用户组</span><br><span class="line">sudo passwd username # 修改用户密码</span><br><span class="line">sudo chfn username # 修改用户资料</span><br><span class="line">sudo gpasswd –a username groupname # 添加用户至用户组</span><br><span class="line">sudo gpasswd –d username groupname # 从用户组删除用户</span><br><span class="line">sudo usermod -L username # 锁定用户</span><br><span class="line">sudo usermod -U username # 解锁用户</span><br><span class="line">sudo groupmod -n groupname groupname # 重命名用户组</span><br><span class="line">groups username # 查看用户所属的用户组</span><br><span class="line">newgrp groupname # 切换到用户组</span><br><span class="line">su username # 切换用户</span><br><span class="line">sudo su # 切换root用户</span><br><span class="line">whoami # 查看当前用户</span><br><span class="line">who # 查看当前用户登录信息</span><br><span class="line"></span><br><span class="line">sudo shutdown -h now # 关机</span><br><span class="line">sudo halt # 关机</span><br><span class="line">sudo shutdown -r now # 重启</span><br><span class="line">sudo reboot # 重启</span><br></pre></td></tr></table></figure><h4 id="File">File<a class="header-anchor" href="#File" aria-hidden="true"></a></h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">touch filename # 创建空文件</span><br><span class="line">cat filename # 一屏查看文件</span><br><span class="line">more filename # 分页查看文件</span><br><span class="line">less filename # 可控分页查看文件</span><br><span class="line">cat -n filename # 带行号查看文件</span><br><span class="line">grep string filename # 根据字符串匹配来查看文件</span><br><span class="line">grep -l -r string dirname # 显示内容包含字符串的文件名</span><br><span class="line">grep -L -r string dirname # 显示内容不包含字符串的文件名</span><br><span class="line">find dirname -name filename # 查找文件</span><br><span class="line">head -n 2 filename # 显示文件开始两行的内容</span><br><span class="line">tail -n 2 filename # 显示文件末尾两行的内容</span><br><span class="line"></span><br><span class="line">pwd # 查看当前目录</span><br><span class="line">cd dirname # 切换目录,~为home,/为root,.为current,..为parent,-为previous</span><br><span class="line">ls dirname # 查看目录内容</span><br><span class="line">ls -a dirname # 查看目录内容,包含隐藏文件</span><br><span class="line">ls -l dirname # 详细查看目录内容</span><br><span class="line">mkdir -pv dirname # 递归创建目录</span><br><span class="line">rm -fr dirname # 递归删除文件/目录</span><br><span class="line">mv srcname distname # 移动文件/目录,可用来重命名</span><br><span class="line">cp srcname distname # 复制文件</span><br><span class="line">cp -r srcname distname # 复制目录</span><br><span class="line">file filename # 查看文件类型</span><br><span class="line">stat filename # 查看文件时间</span><br><span class="line">diff filename filename # 对比文件差异</span><br><span class="line">ln -s srcname distname # 建立软连接</span><br><span class="line"></span><br><span class="line">tar -zcvf xxx.tar.gz dirname # 压缩目录为xxx.tar.gz</span><br><span class="line">tar -xf xxx.tar.gz -C dirname # 解压缩xxx.tar.gz到目录</span><br><span class="line"></span><br><span class="line">sudo chown username:groupname filename # 改变文件/目录的所属用户和组</span><br><span class="line">sudo chown -R username:groupname dirname # 改变目录及其内容的所属用户和组</span><br><span class="line">sudo chmod u+rwx filename # 修改文件/目录权限,用户添加读写运行权限</span><br><span class="line">sudo chmod g+r filename # 修改文件/目录权限,组成员添加读权限</span><br><span class="line">sudo chmod o+r filename # 修改文件/目录权限,其他用户添加读权限</span><br><span class="line">sudo chmod a+w filename # 修改文件/目录权限,所有用户添加写权限</span><br><span class="line">sudo chmod 777 filename # 修改文件/目录权限,所有用户添加读写运行权限</span><br><span class="line">sudo chmod go-rwx filename # 修改文件/目录权限,删除组成员与其他用户对目录的读写执行权限</span><br></pre></td></tr></table></figure><link rel="stylesheet" href="https://cdn.bootcss.com/KaTeX/0.6.0/katex.min.css">]]></content>
<summary type="html"><a id="more"></a>
<h3 id="Initial Settings">Initial Settings<a class="header-anchor" href="#Initial Settings" aria-hidden="true"></a></h3>
<</summary>
<category term="技术" scheme="http://www.niemingzhao.top/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="Linux" scheme="http://www.niemingzhao.top/tags/Linux/"/>
</entry>
<entry>
<title>权限系统设计</title>
<link href="http://www.niemingzhao.top/2020/10/25/%E6%9D%83%E9%99%90%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/"/>
<id>http://www.niemingzhao.top/2020/10/25/%E6%9D%83%E9%99%90%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/</id>
<published>2020-10-25T09:47:30.000Z</published>
<updated>2020-12-20T13:20:45.353Z</updated>
<content type="html"><![CDATA[<h3 id="前言">前言<a class="header-anchor" href="#前言" aria-hidden="true"></a></h3><p>权限管理是所有后台系统的都会涉及的一个重要组成部分,主要目的是对不同的人访问资源进行权限的控制,避免因权限控制缺失或操作不当引发的风险问题,如操作错误、隐私数据泄露等问题。</p><a id="more"></a><p>目前在公司负责权限这块,所以对权限这块的设计比较熟悉,公司采用微服务架构,权限系统自然就独立出来了,其他业务系统包括商品中心、订单中心、用户中心、仓库系统、小程序、多个APP等十几个系统和终端。</p><h3 id="1.权限模型">1.权限模型<a class="header-anchor" href="#1.权限模型" aria-hidden="true"></a></h3><p>迄今为止最为普及的权限设计模型是RBAC模型,基于角色的访问控制(Role-Based Access Control)。</p><h4 id="1.1 RBAC0模型">1.1 RBAC0模型<a class="header-anchor" href="#1.1 RBAC0模型" aria-hidden="true"></a></h4><p>RBAC0模型如下:</p><p><img src="http://images.niemingzhao.top/image/2020/10/25/wu_1elfioupi9h174lipquagfp6.png-default" alt="" class="center-block"></p><p>这是权限最基础也是最核心的模型,它包括用户/角色/权限,其中用户和角色是多对多的关系,角色和权限也是多对多的关系。</p><p><strong>用户</strong>是发起操作的主体,按类型分可分为2B和2C用户,可以是后台管理系统的用户,可以是OA系统的内部员工,也可以是面向C端的用户,比如阿里云的用户。</p><p><strong>角色</strong>起到了桥梁的作用,连接了用户和权限的关系,每个角色可以关联多个权限,同时一个用户关联多个角色,那么这个用户就有了多个角色的多个权限。有人会问了为什么用户不直接关联权限呢?在用户基数小的系统,比如20个人的小系统,管理员可以直接把用户和权限关联,工作量并不大,选择一个用户勾选下需要的权限就完事了。但是在实际企业系统中,用户基数比较大,其中很多人的权限都是一样的,就是个普通访问权限,如果管理员给100人甚至更多授权,工作量巨大。这就引入了“角色(Role)”概念,一个角色可以与多个用户关联,管理员只需要把该角色赋予用户,那么用户就有了该角色下的所有权限,这样设计既提升了效率,也有很大的拓展性。</p><p><strong>权限</strong>是用户可以访问的资源,包括页面权限、操作权限、数据权限:</p><ul><li>页面权限:即用户登录系统可以看到的页面,由菜单来控制,菜单包括一级菜单和二级菜单,只要用户有一级和二级菜单的权限,那么用户就可以访问页面。</li><li>操作权限:即页面的功能按钮,包括查看、新增、修改、删除、审核等,用户点击删除按钮时,后台会校验用户角色下的所有权限是否包含该删除权限,如果是,就可以进行下一步操作,反之提示无权限。有的系统要求“可见即可操作”,意思是如果页面上能够看到操作按钮,那么用户就可以操作。要实现此需求,这里就需要前端来配合,前端开发把用户的权限信息缓存,在页面判断用户是否包含此权限,如果有,就显示该按钮,如果没有,就隐藏该按钮。某种程度上提升了用户体验,但是在实际场景可自行选择是否需要这样做。</li><li>数据权限:数据权限就是用户在同一页面看到的数据是不同的,比如财务部只能看到其部门下的用户数据,采购部只看采购部的数据。在一些大型的公司,全国有很多城市和分公司,比如杭州用户登录系统只能看到杭州的数据,上海用户只能看到上海的数据。解决方案一般是把数据和具体的组织架构关联起来。举个例子,再给用户授权的时候,用户选择某个角色同时绑定组织如财务部或者合肥分公司,那么该用户就有了该角色下财务部或合肥分公司下的的数据权限。</li></ul><p><img src="http://images.niemingzhao.top/image/2020/10/25/wu_1elfj5juv1t8p1d4h1c241efhk9g9.png-default" alt="" class="center-block"></p><p>以上是RBAC的核心设计及模型分析,此模型也叫做RBAC0,而基于核心概念之上,RBAC还提供了扩展模式,包括RBAC1、RBAC2、RBAC3模型。下面介绍这三种类型。</p><h4 id="1.2 RBAC1模型">1.2 RBAC1模型<a class="header-anchor" href="#1.2 RBAC1模型" aria-hidden="true"></a></h4><p><img src="http://images.niemingzhao.top/image/2020/10/25/wu_1elfj82so1buj1o4s1jpj1aja3ic.png-default" alt="" class="center-block"></p><p>此模型引入了角色继承(Hierarchical Role)概念,即角色具有上下级的关系,角色间的继承关系可分为一般继承关系和受限继承关系。一般继承关系仅要求角色继承关系是一个绝对偏序关系,允许角色间的多继承。而受限继承关系则进一步要求角色继承关系是一个树结构,实现角色间的单继承。这种设计可以给角色分组和分层,一定程度简化了权限管理工作。</p><h4 id="1.3 RBAC2模型">1.3 RBAC2模型<a class="header-anchor" href="#1.3 RBAC2模型" aria-hidden="true"></a></h4><p>基于核心模型的基础上,进行了角色的约束控制,RBAC2模型中添加了责任分离关系,其规定了权限被赋予角色时,或角色被赋予用户时,以及当用户在某一时刻激活一个角色时所应遵循的强制性规则。责任分离包括静态责任分离和动态责任分离。主要包括以下约束:</p><ul><li>互斥角色:同一用户只能分配到一组互斥角色集合中至多一个角色,支持责任分离的原则。互斥角色是指各自权限互相制约的两个角色,比如财务部有会计和审核员两个角色,他们是互斥角色,那么用户不能同时拥有这两个角色,体现了职责分离原则。</li><li>基数约束:一个角色被分配的用户数量受限;一个用户可拥有的角色数目受限;同样一个角色对应的访问权限数目也应受限,以控制高级权限在系统中的分配。</li><li>先决条件角色:即用户想获得某上级角色,必须先获得其下一级的角色。</li></ul><h4 id="1.4 RBAC3模型">1.4 RBAC3模型<a class="header-anchor" href="#1.4 RBAC3模型" aria-hidden="true"></a></h4><p>即最全面的权限管理,它是基于RBAC0,将RBAC1和RBAC2进行了整合。</p><h4 id="1.5 用户组">1.5 用户组<a class="header-anchor" href="#1.5 用户组" aria-hidden="true"></a></h4><p>当平台用户基数增大,角色类型增多时,而且有一部分人具有相同的属性,比如财务部的所有员工,如果直接给用户分配角色,管理员的工作量就会很大,如果把相同属性的用户归类到某用户组,那么管理员直接给用户组分配角色,用户组里的每个用户即可拥有该角色,以后其他用户加入用户组后,即可自动获取用户组的所有角色,退出用户组,同时也撤销了用户组下的角色,无须管理员手动管理角色。</p><p>根据用户组是否有上下级关系,可以分为有上下级的用户组和普通用户组:</p><ul><li>具有上下级关系的用户组:最典型的例子就是部门和职位,可能多数人没有把部门职位和用户组关联起来吧。当然用户组是可以拓展的,部门和职位常用于内部的管理系统,如果是面向C端的系统,比如淘宝网的商家,商家自身也有一套组织架构,比如采购部、销售部、客服部、后勤部等,有些人拥有客服权限,有些人拥有上架权限等等,所以用户组是可以拓展的。</li><li>普通用户组:即没有上下级关系,和组织架构、职位都没有关系,也就是说可以跨部门、跨职位,举个例子,某电商后台管理系统,有拼团活动管理角色,我们可以设置一个拼团用户组,该组可以包括研发部的后台开发人员、运营部的运营人员、采购部的人员等等。</li></ul><p>每个公司都会涉及到到组织和职位,下面就重点介绍这两个。</p><h5 id="1.5.1 组织">1.5.1 组织<a class="header-anchor" href="#1.5.1 组织" aria-hidden="true"></a></h5><p>常见的组织架构如下图:</p><p><img src="http://images.niemingzhao.top/image/2020/10/25/wu_1elfjkt8te0o1i6j1m3rngk1o75f.png-default" alt="" class="center-block"></p><p>我们可以把组织与角色进行关联,用户加入组织后,就会自动获得该组织的全部角色,无须管理员手动授予,大大减少工作量,同时用户在调岗时,只需调整组织,角色即可批量调整。组织的另外一个作用是控制数据权限,把角色关联到组织,那么该角色只能看到该组织下的数据权限。</p><h5 id="1.5.2 职位">1.5.2 职位<a class="header-anchor" href="#1.5.2 职位" aria-hidden="true"></a></h5><p>假设财务部的职位如下图:</p><p><img src="http://images.niemingzhao.top/image/2020/10/25/wu_1elfjmeolr9i1d231a7e131p4s3i.png-default" alt="" class="center-block"></p><p>每个组织部门下都会有多个职位,比如财务部有总监、会计、出纳等职位,虽然都在同一部门,但是每个职位的权限是不同的,职位高的拥有更多的权限。总监拥有所有权限,会计和出纳拥有部分权限。特殊情况下,一个人可能身兼多职。</p><h4 id="1.6 含有组织/职位/用户组的模型">1.6 含有组织/职位/用户组的模型<a class="header-anchor" href="#1.6 含有组织/职位/用户组的模型" aria-hidden="true"></a></h4><p>根据以上场景,新的权限模型就可以设计出来了,如下图:</p><p><img src="http://images.niemingzhao.top/image/2020/10/25/wu_1elfjoc3j1h3v1hjgf6452sinl.png-default" alt="" class="center-block"></p><p>根据系统的复杂度不同,其中的多对多关系和一对一关系可能会有变化:</p><ul><li>在单系统且用户类型单一的情况下,用户和组织是一对一关系,组织和职位是一对多关系,用户和职位是一对一关系,组织和角色是一对一关系,职位和角色是一对一关系,用户和用户组是多对对关系,用户组和角色是一对一关系,当然这些关系也可以根据具体业务进行调整。模型设计并不是死的,如果小系统不需要用户组,这块是可以去掉的。</li><li>分布式系统且用户类型单一的情况下,到这里权限系统就会变得很复杂,这里就要引入了一个“系统”概念,此时系统架构是个分布式系统,权限系统独立出来,负责所有的系统的权限控制,其他业务系统比如商品中心、订单中心、用户中心,每个系统都有自己的角色和权限,那么权限系统就可以配置其他系统的角色和权限。</li><li>分布式系统且用户类型多个的情况下,比如淘宝网,它的用户类型包括内部用户、商家、普通用户,内部用户登录多个后台管理系统,商家登录商家中心。这些做权限控制,如果你作为架构师,该如何来设计呢?</li></ul><h3 id="2.授权流程">2.授权流程<a class="header-anchor" href="#2.授权流程" aria-hidden="true"></a></h3><p>授权即给用户授予角色,按流程可分为手动授权和审批授权。权限中心可同时配置这两种,可提高授权的灵活性。</p><ul><li>手动授权:管理员登录权限中心为用户授权,根据在哪个页面授权分为两种方式:给用户添加角色、给角色添加用户。给用户添加角色就是在用户管理页面,点击某个用户去授予角色,可以一次为用户添加多个角色;给角色添加用户就是在角色管理页面,点击某个角色,选择多个用户,实现了给批量用户授予角色的目的。</li><li>审批授权:即用户申请某个职位角色,那么用户通过OA流程申请该角色,然后由上级审批,该用户即可拥有该角色,不需要系统管理员手动授予。</li></ul><h3 id="3.表结构">3.表结构<a class="header-anchor" href="#3.表结构" aria-hidden="true"></a></h3><p>有了上述的权限模型,设计表结构就不难了。下面是多系统下的表结构,简单设计下,主要提供思路:</p><p><img src="http://images.niemingzhao.top/image/2020/10/25/wu_1elfk56ue1gqep3v2j211n21noro.png-default" alt="" class="center-block"></p><h3 id="4.权限框架">4.权限框架<a class="header-anchor" href="#4.权限框架" aria-hidden="true"></a></h3><ul><li>Apache Shrio</li><li>Spring Security</li></ul><p>在项目中可以采用其中一种框架。</p><h3 id="5.结语">5.结语<a class="header-anchor" href="#5.结语" aria-hidden="true"></a></h3><p>权限系统可以说是整个系统中最基础,同时也可以很复杂的,在实际项目中,会遇到多个系统,多个用户类型,多个使用场景,这就需要具体问题具体分析,但最核心的RBAC模型是不变的,我们可以在其基础上进行扩展来满足需求。</p><blockquote><p>本文引用自<a href="https://www.cnblogs.com/iceblow/">iceblow的博客</a>——<a href="https://www.cnblogs.com/iceblow/p/11121362.html">可能是史上最全的权限系统设计</a>。</p></blockquote><link rel="stylesheet" href="https://cdn.bootcss.com/KaTeX/0.6.0/katex.min.css">]]></content>
<summary type="html"><h3 id="前言">前言<a class="header-anchor" href="#前言" aria-hidden="true"></a></h3>
<p>权限管理是所有后台系统的都会涉及的一个重要组成部分,主要目的是对不同的人访问资源进行权限的控制,避免因权限控制缺失或操作不当引发的风险问题,如操作错误、隐私数据泄露等问题。</p></summary>
<category term="技术" scheme="http://www.niemingzhao.top/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="Java" scheme="http://www.niemingzhao.top/tags/Java/"/>
</entry>
<entry>
<title>前端开发30年变迁史</title>
<link href="http://www.niemingzhao.top/2020/10/16/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%9130%E5%B9%B4%E5%8F%98%E8%BF%81%E5%8F%B2/"/>
<id>http://www.niemingzhao.top/2020/10/16/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%9130%E5%B9%B4%E5%8F%98%E8%BF%81%E5%8F%B2/</id>
<published>2020-10-16T13:53:49.000Z</published>
<updated>2020-12-20T13:20:45.353Z</updated>
<content type="html"><![CDATA[<blockquote><p>缅怀司徒正美大神,愿天堂没有996!</p></blockquote><a id="more"></a><blockquote><p>本文引用自《CSDN程序人生》,作者司徒正美。</p></blockquote><h3 id="前言">前言<a class="header-anchor" href="#前言" aria-hidden="true"></a></h3><p>1990年,第一个Web浏览器的诞生;1991年,WWW诞生,这标志着前端技术的开始。</p><p>在这将近30年的前端发展史中,我们经历了从最早的纯静态页面,到JavaScript跨时代的诞生;从PC端到移动端;从依赖后端到前端可自由打包开发;从早期的网景Navigator浏览器到现在各家浏览器百花齐放……</p><p>我们经历了前端的洪荒时代、prototype时代、jQuery时代 、后jQuery时期、三大框架割据时代,这其中均是由国外开发者主导,直到如今的小程序时代,才是中国开发者独创的。</p><p>这是漫长的技术储备下的成果,最终促成了良好的技术成长收获。期间的前端发展之路,崎岖艰难。</p><h3 id="洪荒时代(1990~1994年)">洪荒时代(1990~1994年)<a class="header-anchor" href="#洪荒时代(1990~1994年)" aria-hidden="true"></a></h3><p>在1990~1994年期间,前端界发生的大事有:WWW(World Wide Web)的诞生、浏览器的诞生、JavaScript的诞生,没有专业的前端,页面全是由后端开发的。</p><p>1990年,万维网之父蒂姆·伯纳斯-李(Tim Berners-Lee)在NeXT电脑上发明了第一个Web浏览器。</p><p>1991年8月6日,Tim在alt.hypertext新闻组贴出了一份关于World Wide Web的简单摘要,这标志了Web页面在Internet上的首次登场。</p><p>最早的Web主要被一帮科学家们用来共享和传递信息,全世界的Web服务器也就几十台。由于仅是用来传递信息,从可视化方式或从传递数量上看,仅比电报强一点点。</p><p>当时还没有JavaScript,用的是纯静态的页面。</p><p>1993年,CGI(Common Gateway Interface)出现了,人们可以在后端动态生成页面。</p><p>Perl由于跨操作系统和易于修改的特性成为CGI的主要编写语言。当然,CGI也支持其他支持标准输入输出和环境变量的语言编写,比如Shell脚本、C/C++语言,只要符合接口标准即可。</p><p>但显然,页面的内容更新完全由后端生成,这带来一个严重的缺憾:每次更新都要整页刷新,加上早期的网速情况,这个操作是非常慢的。因此针对这情况,人们从多方面着手改进:编写语言的升级、浏览器的升级、HTML的升级。</p><p>1994年,网景公司成立,发布了第一款商业浏览器Navigator。自从这款浏览器面世后,微软推出IE浏览器。虽说有竞争才有发展,但这也埋下了JavaScript分裂的种子。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekorg7974j411tn1ntj1p4e19vu6.png-default" alt="" class="center-block"></p><p>同年,PHP诞生。PHP能将动态的内容嵌入到HTML中,提升了编写页面的效率与可读性,其性能也比一般的CGI高。PHP的界定符、循环语句等的发明,深刻影响了后来的ASP、JSP,乃致后来的JavaScript前端模板引擎。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekorjglc1uv6rblhli18tm1po59.png-default" alt="" class="center-block"></p><p>1994年10月,W3C小组也成立了,他们负责HTML的发展路径,其宗旨是通过促进通用协议的发展。</p><p>待这一切就绪后, JavaScript于1995年诞生了。</p><p>传闻,网景工程师布兰登·艾克(Brendan Eich)只花了10天时间设计出JavaScript语言,近乎上帝七日创造世界那么高效。但也因为工期太短的缘故,导致许多瑕疵,因此一直被正统传序员所嫌弃,直到Ajax的出世,才让人们找到理由忍受它的畸形。早期的浏览器都配有一个选项,用来禁止JavaScript语言运行。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekorkc4m51r1mrl43f1o9sqbgc.png-default" alt="" class="center-block"></p><p>JavaScript主要语言特征<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>:</p><ol><li>借鉴C语言的基本语法;</li><li>借鉴Java语言的数据类型和内存管理;</li><li>借鉴Scheme语言,将函数提升到"第一等公民"(first-class citizen)的地位;</li><li>借鉴Self语言,使用基于原型(prototype)的继承机制。</li></ol><p>时下,静态语言大行其道,类与接口被证明是构建大工程的最佳实践,人们想不出没有类的语言如何编写业务。因此当时的微软也打造了另一门运行于浏览器的语言——VBScript。</p><p>如果继续细探JavaScript的能力,你会发现它早期真的非常空洞,一门没有灵魂的语言,没有包管理机制,也没有像Java与C++那样的打辅助用的SDK,内置的方法也屈指可数。比如说数组方法,早期只有push、pop、shift、unshift、splice、slice、sort、reverse、concat、join等操作。动态调用方面,Function的apply、call操作还没有出现!</p><p>早年的偷懒,导致后来不得不补课:到了2019年,数组上的原型方法,是原来3倍。</p><p>除了方法缺乏,还有性能问题,大家讨论用eval还是Function,用哪种循环方式,用parseInit还是~~,就是为了那一点点的性能提升。<a href="http://xn--jsperf-9v9ii49d.com">例如jsperf.com</a>,就是一个专门研究JavaScript性能的网站。</p><p>因此JavaScript诞生后,其两大任务就是完善语言特性与提高性能。这两座大山分别由著名的prototype.js与jQuery来搬掉。</p><p>在搬掉之前,前端界还有一个曲折实践——第一次浏览器战争,并由其发展而来UA嗅深技术。</p><h3 id="浏览器战争(1994~2005年)">浏览器战争(1994~2005年)<a class="header-anchor" href="#浏览器战争(1994~2005年)" aria-hidden="true"></a></h3><p>浏览器战争一共打了三场,IE浏览器vs网景浏览器、IE浏览vs火狐浏览器、IE浏览器vs谷歌浏览器。</p><p>第一场浏览器之战打得尤其激烈。</p><p>微软的IE浏览器发布于1994年,但此时的网景已经占领绝对优势。微软在落后的情况,反编译Netscape的源码,推出IE与JScript。但是由于Bug非常多,大家不愿意为IE开发网站,因此发掘出UA,专门过滤掉IE浏览器。</p><p>UA即Navigator.userAgent,是用一个字符串来记录用户当前运行在什么操作系统与浏览器中。当前IE3的UA是这样的:</p><pre><code>Mozilla/2.0 (compatible; MSIE 3.02; Windows 95)</code></pre><p>程序判断UA信息,假如发现当前运行的环境是IE浏览器的话,就提示用户用网景浏览器打开。因此微软不得不让自己的UA尽量伪装成网景的UA,欺骗用于检测UA的脚本,达到IE浏览器可以跑这些网站的目的。</p><p>最终,第一次浏览器之战以微软胜利,Netscape被美国在线收购,而落下帷幕。</p><p>第一次浏览器战争年代非常久远了,但其结局告诉我们,其实技术强弱并不重要。那时技术保护并没有这么重视,否则微软的行为可能会被告(谷歌的openSDK仅抄袭几十行代码,被Oracle公司诉讼赔88亿)。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekorppst11a29qf1lh11ei2186ef.png-default" alt="" class="center-block"></p><p>第一次浏览器战争带来了一个问题:尽管当时有ECMA-262(JavaScript规范文档)与W3C(HTML与CSS的规范文档),微软却没有照规范来实现JavaScript、HTML与CSS,导致前端兼容问题的诞生。所以CSS Hack、浏览器判定、特性侦测,这些技术就应运而生。</p><p>这个时代最著名的人物是Dean Edwrad,他是最早的近乎完美解决事件绑定的兼容性大神,其addEvent内置于jQuery最早的版本中。jQuery的作者John Resig看到其超强的技艺,最后放弃推出大而全的框架,专攻选择器引擎。</p><p>Dean Edwrad的IE7.js、IE8.js是早期处理浏览器兼容的良药,可以说是一切Polyfill<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>的起源。他写了大量的Hack,比如在IE如何测量元素的宽高,许多操作DOM的兼容。</p><p>这时期太早,中国基本没有参与这次浏览器战争。</p><h3 id="prototype时期(2005~2009年)">prototype时期(2005~2009年)<a class="header-anchor" href="#prototype时期(2005~2009年)" aria-hidden="true"></a></h3><p>prototype是Sam Stephenson写的一个非常优雅的JavaScript基础类库。他是Ruby的大牛,因此prototype的许多方法名都是来自Ruby界。</p><p>Sam Stephenson最大的贡献是发掘了prototype与创造了Function.prototype.bind,在数组上也写了一大堆方法,其中许多被标准化了。</p><p>同期的MooTools也是基于prototype来扩展方法,当时,大家还在前端论坛为这个争吵(如在Object.prototype加了方法,那么基于for in来检测空对象就会失败)。还有前端工程师喜欢在当时很出名的前端聚集地——蓝色理想(现沦为设计师网站)上,讨论如何扒脚本、分享弹层、日历等小组件的技术,这在当时已经是非常了不起的事。</p><p>prototype当时还解决两大问题:动画特效与Ajax请求。动画特效是由Scriptaculous提供,我们现在所熟知的各种缓动函数,各种特效的命名与大致的运行形态,都是由Scriptaculous确定下来的。</p><p>在早期,谷歌就开始使用iframe实现页面刷新。</p><p>2005年2月,杰西·詹姆士·贾瑞特(Jesse James Garrett)发表了一篇名为《Ajax:一种Web应用程序开发的新方法》的文章后,Ajax被挖掘出,大家才开始重视起这技术的应用。</p><p>例如IE下的ActiveXObject(“Microsoft.XMLHTTP”),这是IE创建Ajax引擎的。假如当时有工程师开发出一个核心库,如果不包含Ajax的封装,便不好意思发布出来。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekors2a31og21goc10441h811524i.png-default" alt="" class="center-block"></p><p>当时前端开发模式是选择一个核心库,找一些组件,或者扒别人的脚本进行开发。</p><p>Prototype.js的源码挺好理解的,代码量也少,只有5000多行,里面的每个方法也很易扒出来,因此一些大公司总有高手能创造自己的Prototype.js。</p><p>但前端开发还是离不开后端,因为前端没有模块机制,当时我们需要用PHP进行打包。打包是雅虎34条军规之一,可以减少请求数。打包的同时也可以进行混淆,防止代码小偷来窥探。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekortcud191ga9jano8h0qqvl.png-default" alt="" class="center-block"></p><p>N年前,前端面试必问的题目:</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekoru1n31ch711bvb60th2pu0o.png-default" alt="" class="center-block"></p><p>这个时期,还没有前后端分离,可国内一些带着深厚后端背景的高手已经入场。</p><h3 id="jQuery时期(2009~2012年)">jQuery时期(2009~2012年)<a class="header-anchor" href="#jQuery时期(2009~2012年)" aria-hidden="true"></a></h3><p>2006年,jQuery发布,它当时的竞争对手很多:Dojo、Prototype、ExtJS、MooTools。</p><p>所以那时jQuery的宣传口号仅能说是它的性能上升了100%、200%、300%。直到2009年,Sizzle选择器引擎研发成功,jQuery才取得压倒性的优势。</p><p>当时前端界首要面对的是浏览器兼容性问题,jQuery在处理DOM兼容上真是知微见著, 发掘出大量的DOM/BOM兼容方案(例如Dean Edwrad的addEvent(),IE的px转换方案,domReady的doScroll方案,globalEval的兼容方案等)。</p><p>jQuery也打破了前端开发者的编程思维,之前是按照后端的开发思路来的:做一个业务就先封装一个类,有了这个类后,再想办法传入一个DOM,然后再通过类方法操作DOM。而jQuery是DOM为中心,开发者可以选一个或多个DOM,变成jQuery对象,然后进行链式操作。当时为了改变用户的思维,国内的高手写了不少文章来引导大家。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekorvdve420p611k8j12qv1ga6r.png-default" alt="" class="center-block"></p><p>其次,开发者们已开始注重前后端分离,并要求不能污染Object原型对象,不能污染window全局变量。这样,jQuery只占用两个全局变量。</p><p>再次,jQuery非常轻量级,采用Dean Edwards编写的Packer压缩后,大小不到30KB。并且里面实现得非常精妙,以令人瞠目的手段解决各种兼容痼疾。</p><p>为了学习这些技巧,高手们翻了一遍遍jQuery的源码,所以网上有大量关于其源码详解的书藉。甚至前端工程师在面试时也会被考到jQuery的源码实现,这样,jQuery在国内更加流行。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekos06e81q8772odj5ur4bdeu.png-default" alt="" class="center-block"></p><p>jQuery的流行间接带来以下的发展:</p><ul><li>促使人们对CSS1~CSS3选择器的学习</li><li>促进了浏览器原生选择器引擎document.querySelectorAll、Element.matches的诞生</li><li>提高人们对domReady(DOMContentLoaded事件)的认识</li><li>促进了Promise与requestAnimateFrame 的诞生</li><li>最重要的是降低前端门槛,让更多人进入这行业,前端工程师的队伍越来越壮大</li></ul><p>这样的话,不断涌现出优秀的工程师,他们创造了大量jQuery插件与UI库。为后jQuery时代,人们研发前端模块加载、统一异步机制、打造大型MVC框架,甚至伸向后端,接管打包脚本而发明Node.js,来腾出大量时间。</p><p>这个时期涌现了大量jQuery-like的库,其中最著名的是Zepto.js。Zepto的出现也标志着我们进入移动互联网时代。那时配套出的著名库还有iScroll、fastclick、Lazy Load、Modernizr、fullPage。</p><p>jQuery的链式操作风麾一时,也带来许多问题,当Ajax出现依赖时,就不可避免就出现回调地狱。因此针对这方面的讨论,诞生Deffered与Promise。有关回调地狱的讨论,在后来讲Node.js异步处理时,将会再一次热烈地讨论。因此太阳下没有新事,我们总是遇到相似的问题。</p><p>jQuery如此多的选择器也法维护,随着越来越多人涌现这行业,页面的交互也越来越复杂,从Web Page向Web App进化,新的趋势带来新的开发方式。</p><h3 id="后jQuery时期(2012~2016年)">后jQuery时期(2012~2016年)<a class="header-anchor" href="#后jQuery时期(2012~2016年)" aria-hidden="true"></a></h3><p>这时期以RequireJS的诞生为起点,以RN的出现结束。同时解决了前端的模块定义问题,模块打包问题(通过Node.js),JavaScript不依靠其他语言创造了一套自己的工具链。</p><p>jQuery的出现让前端工程师开发更加轻松,假如工程师想实现一个功能,现搜索出一个jQuery插件来实现。那时候大家在前端网站就整天介绍jQuery插件,很少讨论一些底层的实现。</p><p>前端工程师通常编写一个页面,会引入十多个乃至几十个jQuery插件,页面上塞满了Script标签。众所周知,浏览器是单线程,Script的加载,会影响到页面的解析与呈现,导致著名的白屏问题(当时前端用力过猛,body中的所有东西都是动态生成的)。</p><p>jQuery另一个问题是<strong>全局污染</strong>,由于插件的质量问题,或者开发的素质问题,这已经是IIEF模块或命名空间等传统手段无法解决了。</p><p>于是一些优秀的前端工程师们决定从取经后端,引入模块机制。早期,这种模块机制在Dojo、EXT这些框架中都是内置的,但是显然说服不了另一个框架的用户用对方的模块机制,于是有人立志要统一这种模块定义方式,成立了CommonJS。</p><p>但不料,CommonJS内部也有派系,谁也说不服对方。终于有一个人忍不住自己独立开发出RequireJS,其模块规范即为AMD。AMD最大的优势是它支持各种插件,且简单明了,并且提供shim机制加载以非AMD规范编写的JavaScript代码。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekos2t331k4pap9dal18hh6oa11.png-default" alt="" class="center-block"></p><p>但在CommonJS诞生很久一段时间后,在后端的Node.js出现时才有用武之地。而国内,则流行另一种规范风格,背靠阿里的大旗,有人推出了SeaJS,号称其规范为CMD。其实无论国内还是国外,都产生许多模块加载器,但最后还是被淘汰了,规范一个就够了,不宜过多。</p><p>但是前端工程师的创造力就是这么惊人,从无到有,再到泛滥成灾,一年足矣。这可能与前端代码是开源的原因。最后有人统一了前两种规范(AMD、Node.js模块),同时还支持老式的“全局”变量规范。</p><p>自此,JavaScript开发模式焕然一身了,大家只要在代码外面包一层就可以全世界通用,不用提心全局污染的问题。</p><p>其次,jQuery开发者需要解决大段HTML的生成问题,之前jQuery有$.html, $.append, $before等方法,可以将一大段符合HTML结构的字符串转换成DOM再插入到页面上。</p><p>但现在我们想分离出来,让HTML独立到不同的文件中,然后插数据,这就是前端模板。前端模板的情况与模板规范一样,从没有到多如芝麻的境地。这时筛选一个好用且性能高的模板是一件让前端工程师头疼的问题,那时网上有许多评测文章来介绍它们。</p><p>前端模板技术可以用一个公式来描述:</p><pre><code>HTML = template(vars)</code></pre><p>有了前端模板后,又诞生了前端路由,基于它们,人们发明一个新词汇SPA。作为这个时代的尾声,来自Ruby界的高手Ryan Dahl发明了Node.js。前端工程师们欢呼:可以不用传统的后端就能自己写一个网站了!</p><p>Node.js的发展就不详述上,很快它就冒出海量模块、路由、状态管理、数据库、MVC框架都有了。这时,前端就缺自己的MVC框架了。Node.js转眼就十岁生日了。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekos4gqa15ug1raa70lgb79hf14.png-default" alt="" class="center-block"></p><p>著名的MEAN架构,是JavaScript全栈开发的先锋。当时涌现了大量的MVC与MVVM框架。最先火起来的是Backbone.js,使用纯正的MVC模型,Backbone.js是jQuery最后的支持者,它强依赖于jQuery。</p><p>Backbone.js的作者还搞了另一套编译语言CoffeeScript, 里面的箭头函数、类机制、解构赋值等语法糖都深深影响了后来的ES6。</p><p>接着下来是谷歌的Angular,微软的Knockout.js,苹果的Ember.js这三个MVVM框架,MVVM就是比MVC多一个数据绑定功能,但这数据绑定功能是非常难实现。Knockout是使用函数代替属性的技巧实现,它的设计影响到后来的Mobx;Ember.js是基于Object.defineProperty;Angular是将函数体转译成setter、getter函数。</p><p>大公司的介入,对个人开发者影响是很大,毕竟大家都爱迷信大公司,因此局面一下子就稳定下来。大公司还带来了全新的开发模式,早期都是找一个核心库,再搜刮一大堆插件,然后自己写业务代码,最后后端打包。</p><p>大公司将后端开发经验挪用过来,用Node.js开发了一套CLI,里面包含了脚手架生成,打包脚本、语法风格检测、环境变量插入,代码复杂度检测,代码提交时自动跑单元测试,图片与JS压缩等功能。ESLint、JSLint、JSHint、CSS Lint、htmllint等就是那时期出现的。</p><p>但CLI的出现导致了前端的分裂,以前大家都使用jQuery,但自CLI帮你建好项目的那一刻起,就将你划归某一子阵营,你是Angular?Ember.js?还是jQuery?对了,jQuery没有大公司支撑的阵营被快速边缘化。</p><p>对于个人开发者,他们是没有能力开发这么功能完备的CLI,于是出现了Code Climate、Travis CI、CircleCI这样的平台。它们的出现标志着jQuery小作坊时代的终结了。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekos5gbodu1a1i15dovi12vq17.png-default" alt="" class="center-block"></p><p>前端开发者也出现分化:有些人转向后端,出现了CNode的门户网站。另外一些人开始搞工程化。一时间出现上百种构建工具,出名的有Grunt、Gulp、FIS3、webpack、Rollup、npm-script。</p><p>你方唱罢我登场,这些构建工具均会经历时代的考验,如大浪淘沙般,最后存活得仅为寥寥。</p><p>因此在这场工程化得盛宴中,注定把许多低层次的jQueryer淘汰掉。jQueryer在空闲之余培育出的前端模板、前端路由、MVC框架、模块加载器、Node.js构建工具,却不料最终成为它自己的挖墓人。</p><p>jQuery的时代一去不返了,再没有人关心拖堂拖了N年的Bootstrap 4终于发布了,没有人知道jQuery3.5的瘦身计划,也没有人问jQuery的源码,渐渐地,大家不关注jQuery的工具链了。</p><h3 id="三大框架割据时代(2016~至今)">三大框架割据时代(2016~至今)<a class="header-anchor" href="#三大框架割据时代(2016~至今)" aria-hidden="true"></a></h3><p>React是突然爆发的,虽然它是与Angular是同时期发布,但因为JSX怪异的语法让人们远离它。此时已经进入移动互联网的中期,大公司都有自己的App,或者基于原生,或者基于Hybird。</p><p>Hybird是用WebView加载一个网站或一个SPA。</p><p>由于原生成本太贵,需要招两套班子,一套安卓的,一套iOS的;而Hybird则一直存在性能问题。于是在2017年,Facebook推出了React Native(RN)。</p><p>RN的性能不比原生差多少,比Hybird能好些,其次使用JSX开发界面比原生的快;RN只需要低成本的前端开发人员就能上手了。中国国内经过瀑布流(图片导购)、团购、P2P、共享经济(如共享单车、共享充电宝、共享按摩椅)、区块链等全新商业模式的开发浪潮后,前端人员数量大增。现在,他们只要稍微培训就可以转型为App开发。</p><p>在开发RN的过程中,人们开始了解React一系列的优胜之处。比如JSX背后的虚拟DOM技术,虽然事实证明虚拟DOM不会带来性能的巨大优势,但保证了你怎么写其性能不会太差。</p><p>React为了引入JSX,必须需要引入编译,这又间接促成Babel与webpack的壮大。尤其是Babel,让我们在很旧的浏览器中使用非常新的语法,甚至一些还没有定案的语法。React从14升级到React 15,强制使用class语法,让这个推了好久的语法糖终于大规模落地。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekos73ct174hfo31ic01o2g1h9k1a.png-default" alt="" class="center-block"></p><p>之前如果JavaScript想使用类,只能自己模拟类,由于没有官方的实现,只能任由各优秀工程师发挥。而普通人想用好类,需要了解很复杂的prototype机制。</p><p>现在只用几个新关键字就可以得到这一切。</p><p>如果对比Python 2与Python 3间的升级,JavaScript实在太幸运了!针对CSS逻辑功能过弱的问题,我们也有了新的解决方案:Less、Sass、PostCSS与CSS Modules!</p><p>谷歌在发布Angular的同时,也发布了一个叫Polymer的框架,那时它想推广一种叫Web Components的浏览器自定义组件技术。这其实是微软在IE5就玩剩的HTC技术的升级版。虽然它没有火起来,但它将Script、Style、Template三种内容混在一个文件的设计,启发一个留美华人,再结合当时的Backbone.js、Angular等设计,Vue.js横空出世。目前,这是国人最成功的前端框架了。</p><p>除此之外,国人也弄了好几套迷你React框架与迷你Vue框架。这有点像jQuery时代,大家疯狂做迷你jQuery框架一样。</p><p>总的来说,最有创造力的是React团队,做出状态管理器、CSS-in-JS、Flow静态类型检查、devTool、Fetch、前后端同构、Fiber、suspend、并发渲染等名词层出不穷。其中,状态管理器拥有上百套,CSS-in-JS也拥有上百套,Flow则让前端尝鲜到接口编程的好处,间接推动TypeScript发展。这三大框架无法比拼个一二出来:Vue.js有国人的拥趸,React与Angular有大公司光环。</p><p>三大框架的缠斗从PC领域扩展到移动端:React有RN,Vue.js有Weex,Angular有ionic。想当年我们为了兼容浏览器,攒了一大堆浏览器侦探的Hack,全部贬值为垃圾了。</p><p>在这时期,一种全新的后端渲染崛起,称之为前后同构,既拥有早期SEO的功效,又能复用大量的业务逻辑。随着国内移动互联网的发展,获客成本提高,各种有效的商业模式都进入红海,但只有头部用户能赚到钱,马太效应越来越严重,纯粹的技术解决方案已经无法满足商业诉求了。</p><h3 id="小程序时代(2017~至今)">小程序时代(2017~至今)<a class="header-anchor" href="#小程序时代(2017~至今)" aria-hidden="true"></a></h3><p>小程序时代与三大框架的时代几乎重合,但是出自不同一批人,决战的平台也不一样。</p><p>一直以来前端技术都是由国外开发者主导的,即便是Vue.js也是由美国的华人创造的。但是国内外的技术更新是存在代差,国内通常延期两三年,这个时间差可以让一些模仿者得以生存(如SeaJS、FIS、avalon)。但随着封闭的时间越来越长,国内肯会也会诞生自己的专有物种。小程序就是其中之一。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekos8j3lsnid5u7at1e715qo1d.png-default" alt="" class="center-block"></p><p>小程序的出现有着明显的商业诉求,因为马太效应,一些超大流量的App诞生了。这些大流量App集成了许多功能,但显然公司再多员工,也无法所有功能全是自己弄,于是产生小程序这种“外包”的手段。</p><p>小程序是国内前端技术的一次厚积薄发:底层运行的迷你React的虚拟DOM,内置组件是使用Web Component,API来源于Hybird的桥方法,打包使用webpack,调试台是Chrome console的简化版,WXML、WXSS的语法高亮也应该是webpack或VS Code的插件,模块机制是Node.js的CommonJS……其中最值得一提的是微信开发者工具,以后开发者工具成了各种小程序/快应用的标配。</p><p>但微信小程序一开始的复用能力非常弱,没有类继承,不能使用npm, 不支持Less、Sass,因此基于它的转译框架就应运而生。第一代译转框架是wept、WePY、mpvue,它们无一例外是Vue风格的。因为WXML的模板指令与Vue非常相似,只是改一下就能兼容。当时也出现了一个MINA的框架,听说是微信团队开发的,可以单独架起Node.js后端,让小程序运于浏览器中,方便做单元测试。</p><p>第一代转译框架主要是基于Template标签实现组件机制,自定义组件机制是很后的事了。这就造成了利用第一代转译框架编写的小程序项目很难升级。那时候是个人开发者的天堂,这些框架都是某一大牛独力开发的。</p><p><img src="http://images.niemingzhao.top/image/2020/10/16/wu_1ekos9ca9nfnp8s1jfn7sh1hj51g.png-default" alt="" class="center-block"></p><p>第二代转译框架是大公司主导的,因为需要兼容的小程序越来越多,百度、支付宝、字节跳动、小米、华为等公司都推出自己的小程序和快应用。个人开发者很难凭个人力量去开发转译框架,这时候各大团队纷纷推出自己的轮子:如京东的Taro、滴滴的Chameleon网易的Megalo、去哪儿网的nanachi、百度的Okam等。</p><p>在这个时期,Angular显然落伍了,一是Angular升级太快,国内的高手还没有消化好,新一版的Angular又发布了。二是国内缺乏迷你Angular的轮子,导致庞大的Angular无法塞进小程序中。</p><p>国外谷歌发布了Flutter跨平台转译框架,但是它的编写语言是Dart,它也无法跨界到小程序中。</p><p>未来不仅国内一线巨头争夺小程序,二三线的巨头也可能会加入小程序的混战中,例如有人称360也在打造自己的小程序平台。小程序这种新的流量变现模式深刻地影响了国内的互联网布局。</p><h3 id="结语">结语<a class="header-anchor" href="#结语" aria-hidden="true"></a></h3><p>当初JavaScript被误解为最糟糕的语言,时至今日它是最流行的语言:GitHub 60%的开源项目都是与JavaScript有关。</p><p>以前,从事这行业的人被称为页面仔,现在他们的起薪有的比PHP、JAVA、C++等后端还高。甚至有人说,“任何可以使用JavaScript来编写的应用,最终会由JavaScript编写。”</p><p>我们前端开发者触及的领域不仅仅是浏览器,还可以做后端,做桌面端,做手机端,做小程序端,前端开发者的性价比越来越高,越来越重要。可谓是时代造英雄。</p><p>笔者有幸成为前端开发者大队伍中的一员,也坚信我们前端开发者以后的路会越来越宽,越来越好走。</p><link rel="stylesheet" href="https://cdn.bootcss.com/KaTeX/0.6.0/katex.min.css"><hr class="footnotes-sep"><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p>计算机和编程语言的发展历史 <a href="#fnref1" class="footnote-backref">↩︎</a></p></li><li id="fn2" class="footnote-item"><p>Polyfill是一块代码(通常是Web上的JavaScript),用来为旧浏览器提供它没有原生支持的较新的功能 <a href="#fnref2" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
<summary type="html"><blockquote>
<p>缅怀司徒正美大神,愿天堂没有996!</p>
</blockquote></summary>
<category term="技术" scheme="http://www.niemingzhao.top/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="前端" scheme="http://www.niemingzhao.top/tags/%E5%89%8D%E7%AB%AF/"/>
</entry>
<entry>
<title>文章排版示例</title>
<link href="http://www.niemingzhao.top/2019/12/30/%E6%96%87%E7%AB%A0%E6%8E%92%E7%89%88%E7%A4%BA%E4%BE%8B/"/>
<id>http://www.niemingzhao.top/2019/12/30/%E6%96%87%E7%AB%A0%E6%8E%92%E7%89%88%E7%A4%BA%E4%BE%8B/</id>
<published>2019-12-30T19:53:27.000Z</published>
<updated>2020-12-20T13:20:45.353Z</updated>
<content type="html"><![CDATA[<h3 id="中文文章排版实例:论语学而篇第一">中文文章排版实例:论语学而篇第一<a class="header-anchor" href="#中文文章排版实例:论语学而篇第一" aria-hidden="true"></a></h3><a id="more"></a><p><strong><small>作者:</small></strong><small><abbr title="名丘,字仲尼">孔子</abbr>(前551年9月28日-前479年4月11日)</small></p><h4 id="本篇引语">本篇引语<a class="header-anchor" href="#本篇引语" aria-hidden="true"></a></h4><p>《学而》是《论语》第一篇的篇名。《论语》中各篇一般都是以第一章的前二三个字作为该篇的篇名。《学而》一篇包括16章,内容涉及诸多方面。其中重点是「吾日三省吾身」;「节用而爱人,使民以时」;「礼之用,和为贵」以及仁、孝、信等道德范畴。</p><h4 id="原文">原文<a class="header-anchor" href="#原文" aria-hidden="true"></a></h4><p>子曰:「学而时习之,不亦说乎?有朋自远方来,不亦乐乎?人不知,而不愠,不亦君子乎?」</p><h4 id="译文">译文<a class="header-anchor" href="#译文" aria-hidden="true"></a></h4><p>孔子说:「学了又时常温习和练习,不是很愉快吗?有志同道合的人从远方来,不是很令人高兴的吗?人家不了解我,我也不怨恨、恼怒,不也是一个有德的君子吗?」</p><h4 id="评析">评析<a class="header-anchor" href="#评析" aria-hidden="true"></a></h4><p>宋代著名学者<ins>朱熹</ins>对此章评价极高,说它是「入道之门,积德之基」。本章这三句话是人们非常熟悉的。历来的解释都是:学了以后,又时常温习和练习,不也高兴吗等等。三句话,一句一个意思,前后句子也没有什么连贯性。但也有人认为这样解释不符合原义,指出这里的「学」不是指学习,而是指学说或主张;「时」不能解为时常,而是时代或社会的意思,「习」不是温习,而是使用,引申为采用。而且,这三句话不是孤立的,而是前后相互连贯的。这三句的意思是:自己的学说,要是被社会采用了,那就太高兴了;退一步说,要是没有被社会所采用,可是很多朋友赞同我的学说,纷纷到我这里来讨论问题,我也感到快乐;再退一步说,即使社会不采用,人们也不理解我,我也不怨恨,这样做,不也就是君子吗?(见《齐鲁学刊》1986年第6期文)这种解释可以自圆其说,而且也有一定的道理,供读者在理解本章内容时参考。</p><p>此外,在对「人不知,而不愠」一句的解释中,也有人认为,「人不知」的后面没有宾语,人家不知道什么呢?当时因为孔子有说话的特定环境,他不需要说出知道什么,别人就可以理解了,却给后人留下一个谜。有人说,这一句是接上一句说的,从远方来的朋友向我求教,我告诉他,他还不懂,我却不怨恨。这样,「人不知」就是「人家不知道我所讲述的」了。这样的解释似乎有些牵强。</p><p>总之,本章提出以学习为乐事,做到人不知而不愠,反映出孔子学而不厌、诲人不倦、注重修养、严格要求自己的主张。这些思想主张在《论语》书中多处可见,有助于对第一章内容的深入了解。</p><h3 id="英文文章排版实例">英文文章排版实例<a class="header-anchor" href="#英文文章排版实例" aria-hidden="true"></a></h3><p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p><blockquote><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p></blockquote><h4 id="The standard Lorem Ipsum passage, used since the 1500s">The standard Lorem Ipsum passage, used since the 1500s<a class="header-anchor" href="#The standard Lorem Ipsum passage, used since the 1500s" aria-hidden="true"></a></h4><p>“Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.”</p><h4 id="Section 1.10.32 of “de Finibus Bonorum et Malorum”, written by Cicero in 45 BC">Section 1.10.32 of “de Finibus Bonorum et Malorum”, written by Cicero in 45 BC<a class="header-anchor" href="#Section 1.10.32 of “de Finibus Bonorum et Malorum”, written by Cicero in 45 BC" aria-hidden="true"></a></h4><p>“Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?”</p><h4 id="List style in action">List style in action<a class="header-anchor" href="#List style in action" aria-hidden="true"></a></h4><ul><li><p>If you wish to succeed, you should use persistence as your good friend, experience as your reference, prudence as your brother and hope as your sentry.</p><p>如果你希望成功,当以恒心为良友,以经验为参谋,以谨慎为兄弟,以希望为哨兵。</p></li><li><p>Sometimes one pays most for the things one gets for nothing.</p><p>有时候一个人为不花钱得到的东西付出的代价最高。</p></li><li><p>Only those who have the patience to do simple things perfectly ever acquire the skill to do difficult things easily.</p><p>只有有耐心圆满完成简单工作的人,才能够轻而易举的完成困难的事。</p></li></ul><hr><p><abbr title="法国作家罗切福考尔德">La Racheforcauld</abbr> said: <mark>“Few things are impossible in themselves; and it is often for want of will, rather than of means, that man fails to succeed”.</mark> You just need to follow the browser’s behavior, and set a right <code>margin</code> to it。it will works nice as the demo you’re watching now. The following code is the best way to render typo in Chinese:</p><blockquote><p>无论走到哪里,都应该记住,过去都是假的,回忆是一条没有尽头的路,一切以往的春天都不复存在,就连那最坚韧而又狂乱的爱情归根结底也不过是一种转瞬即逝的现实。</p><footer><strong>马尔克斯</strong><cite>《百年孤独》</cite></footer></blockquote><link rel="stylesheet" href="https://cdn.bootcss.com/KaTeX/0.6.0/katex.min.css">]]></content>
<summary type="html"><h3 id="中文文章排版实例:论语学而篇第一">中文文章排版实例:论语学而篇第一<a class="header-anchor" href="#中文文章排版实例:论语学而篇第一" aria-hidden="true"></a></h3></summary>
<category term="Markdown" scheme="http://www.niemingzhao.top/tags/Markdown/"/>
</entry>
<entry>
<title>Java Web架构发展</title>
<link href="http://www.niemingzhao.top/2019/06/22/Java-Web%E6%9E%B6%E6%9E%84%E5%8F%91%E5%B1%95/"/>
<id>http://www.niemingzhao.top/2019/06/22/Java-Web%E6%9E%B6%E6%9E%84%E5%8F%91%E5%B1%95/</id>
<published>2019-06-22T08:06:08.000Z</published>
<updated>2020-12-20T13:20:45.353Z</updated>
<content type="html"><![CDATA[<p>前后端分离已成为互联网项目开发的业界标准使用方式,通过Nginx + Tomcat的方式(也可以中间加一个Node.js)有效的进行解耦,并且前后端分离会为以后的大型分布式架构、弹性计算架构、微服务架构、多端化服务(多种客户端,例如:浏览器,车载终端,安卓,iOS等等)打下坚实的基础。</p><a id="more"></a><p>这个步骤是系统架构从猿进化成人的必经之路。</p><p>核心思想是<strong>前端HTML页面通过Ajax调用后端的RESTful API接口并使用JSON数据进行交互</strong>。</p><blockquote><p>Web服务器:一般指像Nginx、Apache这类的服务器,他们一般只能解析静态资源。<br>应用服务器:一般指像Tomcat,Jetty,Resin这类的服务器可以解析动态资源也可以解析静态资源,但解析静态资源的能力没有Web服务器好。<br>一般都是只有Web服务器才能被外网访问,应用服务器只能内网访问。</p></blockquote><h3 id="术业有专攻(开发人员分离)">术业有专攻(开发人员分离)<a class="header-anchor" href="#术业有专攻(开发人员分离)" aria-hidden="true"></a></h3><p>以前的Java Web项目大多数都是Java程序员又当爹又当妈,又搞前端(Ajax/jQuery/JS/HTML/CSS等等),又搞后端(Java/MySQL/Oracle等等)。</p><p>随着时代的发展,渐渐的许多大中小公司开始把前后端的界限分的越来越明确,前端工程师只管前端的事情,后端工程师只管后端的事情。</p><p>正所谓术业有专攻,一个人如果什么都会,那么他毕竟什么都不精。</p><p>大中型公司需要专业人才,小公司需要全才,但是对于个人职业发展来说,我建议是分开。</p><ul><li>对于后端Java工程师:</li></ul><p>把精力放在Java基础、设计模式、JVM原理、Spring + SpringMVC原理及源码、Linux、MySQL事务隔离与锁机制、MongoDB、HTTP/TCP、多线程、分布式架构(Dubbo、DubboX、Spring Cloud)、弹性计算架构、微服务架构(SpringBoot + ZooKeeper + Docker + Jenkins)、Java性能优化以及相关的项目管理等等。</p><p>后端追求的是:<em>三高(高并发、高可用、高性能),安全,存储,业务等等</em>。</p><ul><li>对于前端工程师:</li></ul><p>把精力放在HTML5、CSS3、jQuery、AngularJS、Bootstrap、ReactJS、VueJS、Webpack、Less/Sass、Gulp、Node.js、Google V8引擎、JavaScript多线程、模块化、面向切面编程、设计模式、浏览器兼容性、性能优化等等。</p><p>前端追求的是:<em>页面表现,速度流畅,兼容性,用户体验等等</em>。</p><p>术业有专攻,这样你的核心竞争力才会越来越高,正所谓你往生活中投入什么,生活就会反馈给你什么。并且两端的发展都越来越高深,你想什么都会,那你毕竟什么都不精。</p><p>通过将Team分成前后端Team,让两边的工程师更加专注各自的领域,独立治理,然后构建出一个全栈式的精益求精的Team。</p><h3 id="原始人时代(各种耦合)">原始人时代(各种耦合)<a class="header-anchor" href="#原始人时代(各种耦合)" aria-hidden="true"></a></h3><p>曾几何时,我们的Java Web项目都是使用了若干后台框架,SpringMVC/Struts + Spring + SpringJDBC/Hibernate/MyBatis等等。</p><p>大多数项目在Java后端都是分了三层——控制层(Controller/Action)、业务层(Service/Model)、持久层(Dao)。</p><p>控制层负责接收参数,调用相关业务层,封装数据,以及路由&渲染到JSP页面。然后,JSP页面上使用各种标签(JSTL/EL/Struts标签等)或者手写Java表达式(<%= %>)将后台的数据展现出来,玩的是MVC那套思路。</p><p>我们先看这种情况:需求定完了,代码写完了,测试测完了,然后呢?要发布了吧?你需要用Maven或者Eclipse等工具把你的代码打成一个War包,然后把这个War包发布到你的生产环境下的Web容器(Tomcat/JBoss/WebLogic/WebSphere/Jetty/Resin)里,对吧?</p><p>发布完了之后,你要启动你的Web容器,开始提供服务,这时候你通过配置域名、DNS等等相关,你的网站就可以访问了(假设你是个网站)。</p><p>那我们来看,你的前后端代码是不是全都在那个War包里?包括你的JS、CSS、图片、各种第三方的库,对吧?</p><p>好,下面在浏览器中输入你的网站域名(<a href="http://www.xxx.com">www.xxx.com</a>),之后发生了什么?(这个问题也是很多公司的面试题)</p><p>我捡干的说了啊,基础不好的童鞋请自己去搜。</p><p>浏览器在通过域名通过DNS服务器找到你的服务器外网IP,将HTTP请求发送到你的服务器,在TCP 3次握手之后(HTTP下面是TCP/IP),通过TCP协议开始传输数据,你的服务器得到请求后,开始提供服务,接收参数,之后返回你的应答给浏览器,浏览器再通过Content-Type来解析你返回的内容,呈现给用户。</p><p>那么我们来看,先假设你的首页中有100张图片,此时,用户看似一次的HTTP请求,其实并不是一次。用户在第一次访问的时候,浏览器中不会有缓存,你的100张图片,浏览器要连着发起100次HTTP请求(有人会跟我说HTTP长连短连的问题,不在这里讨论),你的服务器接收这些请求,都需要耗费内存去创建Socket来玩TCP传输(消耗你服务器上的计算资源)。</p><p>重点来了,这样的话,你的服务器的压力会非常大,因为页面中的所有请求都是只请求到你这台服务器上,如果1个人还好,如果10000个人并发访问呢(先不聊服务器集群,这里就说单实例服务器),那你的服务器能扛住多少个TCP连接?你的带宽有多大?你的服务器的内存有多大?你的硬盘是高性能的吗?你能抗住多少IO?你给Web服务器分的内存有多大?会不会宕机?</p><p>这就是为什么,<strong>越是大中型的Web应用,他们越是要解耦</strong>。</p><p>理论上你可以把你的数据库 + 应用服务 + 消息队列 + 缓存 + 用户上传的文件 + 日志 + 等等都扔在一台服务器上,你也不用玩什么服务治理,也不用做什么性能监控,什么报警机制等等,就乱成一锅粥好了。</p><p>但是这样就好像是你把鸡蛋都放在一个篮子里,隐患非常大。如果因为一个子应用的内存不稳定导致整个服务器内存溢出而<br>Hung住,那你的整个网站就挂掉了。</p><p>如果出意外挂掉,而恰好这时你们的业务又处于井喷式发展高峰期,那么恭喜你,业务成功被技术卡住,很可能会流失大量用户,后果不堪设想。</p><p><em>注意:技术一定是要走在业务前面的,否则你将错过最佳的发展期哟,亲~</em></p><p>此外,你的应用全部都耦合在一起,相当于一个巨石,当服务端负载能力不足时,一般会使用<strong>负载均衡</strong>的方式,将服务器做成集群,这样其实你是在水平扩展一块块巨石,性能加速度会越来越低。要知道,本身负载就低的功能或者模块是没有必要水平扩展的。在本文中的例子就是你的性能瓶颈不在前端,那干嘛要水平扩展前端呢???还有发版部署上线的时候,我明明只改了后端的代码,为什么要前端也跟着发布呢???(引用自:《架构探险-轻量级微服务架构》,黄勇)</p><p>正常的互联网架构,是都要拆开的,你的Web服务器集群,你的应用服务器集群 + 文件服务器集群 + 数据库服务器集群 + 消息队列集群 + 缓存集群等等。</p><h3 id="JSP的痛点">JSP的痛点<a class="header-anchor" href="#JSP的痛点" aria-hidden="true"></a></h3><p>以前的Java Web项目大多数使用JSP作为页面层展示数据给用户,因为流量不高,因此也没有那么苛刻的性能要求,但现在是大数据时代,对于互联网项目的性能要求是越来越高,因此原始的前后端耦合在一起的架构模式已经逐渐不能满足我们,我们需要寻找一种解耦的方式,来大幅度提升我们的负载能力。</p><ol><li>动态资源和静态资源全部耦合在一起,服务器压力大,因为服务器会收到各种HTTP请求,例如CSS的HTTP请求,JS的,图片的等等。一旦服务器出现状况,前后台一起玩完,用户体验极差。</li><li>UI出好设计图后,前端工程师只负责将设计图切成HTML,需要由Java工程师来将HTML套成JSP页面,出错率较高(因为页面中经常会出现大量的JS代码),修改问题时需要双方协同开发,效率低下。</li><li>JSP必须要在支持Java的Web服务器里运行(例如Tomcat,Jetty,Resin等),无法使用Nginx等(Nginx据说单实例HTTP并发高达5W,这个优势要用上),性能提不上来。</li><li>第一次请求JSP,必须要在Web服务器中编译成Servlet,第一次运行会较慢。</li><li>每次请求JSP都是访问Servlet再用输出流输出的HTML页面,效率没有直接使用HTML高(是每次哟,亲~)。</li><li>JSP内有较多标签和表达式,前端工程师在修改页面时会捉襟见肘,遇到很多痛点。</li><li>如果JSP中的内容很多,页面响应会很慢,因为是同步加载。</li><li>需要前端工程师使用Java的IDE(例如Eclipse),以及需要配置各种后端的开发环境,你们有考虑过前端工程师的感受吗?</li></ol><p>基于上述的一些痛点,我们应该<strong>把整个项目的开发权重往前移,实现前后端真正的解耦!</strong></p><h3 id="开发模式">开发模式<a class="header-anchor" href="#开发模式" aria-hidden="true"></a></h3><p>以前老的方式是:</p><ol><li>产品经理/领导/客户提出需求</li><li>UI做出设计图</li><li>前端工程师做HTML页面</li><li>后端工程师将HTML页面套成JSP页面(前后端强依赖,后端必须要等前端的HTML做好才能套JSP。如果HTML发生变更,就更痛了,开发效率低)</li><li>集成出现问题</li><li>前端返工</li><li>后端返工</li><li>二次集成</li><li>集成成功</li><li>交付</li></ol><p>新的方式是:</p><ol><li>产品经理/领导/客户提出需求</li><li>UI做出设计图</li><li>前后端约定接口&数据&参数</li><li>前后端并行开发(无强依赖,可前后端并行开发,如果需求变更,只要接口&参数不变,就不用两边都修改代码,开发效率高)</li><li>前后端集成</li><li>前端页面调整</li><li>集成成功</li><li>交付</li></ol><h3 id="请求方式">请求方式<a class="header-anchor" href="#请求方式" aria-hidden="true"></a></h3><p>以前老的方式是:</p><ol><li>客户端请求</li><li>服务端的Servlet或Controller接收请求(后端控制路由&渲染页面,整个项目开发的权重大部分在后端)</li><li>调用Service,Dao代码完成业务逻辑</li><li>返回JSP</li><li>JSP展现一些动态的代码</li></ol><p>新的方式是:</p><ol><li>浏览器发送请求</li><li>直接到达HTML页面(前端控制路由&渲染页面,整个项目开发的权重前移)</li><li>HTML页面负责调用服务端接口产生数据(通过Ajax等等,后台返回JSON格式数据,JSON数据格式因为简洁高效而取代XML)</li><li>填充HTML,展现动态效果,在页面上进行解析并操作DOM。</li></ol><p>(有兴趣的童鞋可以访问一下阿里巴巴等大型网站,然后按一下F12,监控一下你刷新一次页面,他的HTTP是怎么玩的,大多数都是单独请求后台数据,使用JSON传输数据,而不是一个大而全的HTTP请求把整个页面包括动 + 静全部返回过来)</p><p>总结一下新的方式的请求步骤:</p><p>大量并发浏览器请求 —> Web服务器集群(Nginx) —> 应用服务器集群(Tomcat) —> 文件/数据库/缓存/消息队列服务器集群</p><p>同时又可以分模块,还可以按业务拆成一个个的小集群,为后面的架构升级做准备。</p><h3 id="前后端分离的优势">前后端分离的优势<a class="header-anchor" href="#前后端分离的优势" aria-hidden="true"></a></h3><ol><li>可以实现真正的前后端解耦,前端服务器使用Nginx。</li></ol><p>前端/Web服务器放的是CSS、JS、图片等等一系列静态资源(甚至你还可以把CSS、JS、图片等资源放到特定的文件服务器,例如阿里云的OSS,并使用CDN加速),前端服务器负责控制页面引用&跳转&路由,前端页面异步调用后端的接口,后端/应用服务器使用Tomcat(把Tomcat想象成一个数据提供者),加快整体响应速度。</p><p>(这里需要使用一些前端工程化的框架比如Node.js、ReactJS、Router、Redux、Gulp、Webpack)</p><ol start="2"><li>发现bug,可以快速定位是谁的问题,不会出现互相踢皮球的现象。</li></ol><p>页面逻辑、跳转错误、浏览器兼容性问题、脚本错误、页面样式等问题,全部由前端工程师来负责。接口数据出错、数据没有提交成功、应答超时等问题,全部由后端工程师来解决。双方互不干扰,前端与后端是相亲相爱的一家人。</p><ol start="3"><li>在大并发情况下,可以同时水平扩展前后端服务器。</li></ol><p>比如淘宝的一个首页就需要2000+台前端服务器做集群来抗住日均多少亿+的日均PV。去参加阿里的技术峰会,听他们说他们的Web容器都是自己写的,就算他单实例抗10万HTTP并发,2000台是2亿HTTP并发,并且他们还可以根据预知洪峰来无限拓展,很恐怖,就一个首页。</p><ol start="4"><li>减少后端服务器的并发/负载压力</li></ol><p>除了接口以外的其他所有HTTP请求全部转移到前端Nginx上,接口的请求调用Tomcat,参考Nginx反向代理Tomcat。且除了第一次页面请求外,浏览器会大量调用本地缓存。</p><ol start="5"><li><p>即使后端服务器暂时超时或者宕机了,前端页面也会正常访问,只不过数据刷不出来而已。</p></li><li><p>也许你也需要有微信相关的轻应用,那样你的接口完全可以共用,如果也有App相关的服务,那么只要通过一些代码重构,也可以大量复用接口,提升效率。(多端应用)</p></li><li><p>页面显示的东西再多也不怕,因为是异步加载。</p></li><li><p>Nginx支持页面热部署,不用重启服务器,前端升级更无缝。</p></li><li><p>增加代码的维护性&易读性(前后端耦合在一起的代码读起来相当费劲)。</p></li><li><p>提升开发效率,因为可以前后端并行开发,而不是像以前的强依赖。</p></li><li><p>在Nginx中部署证书,外网使用HTTPS访问,并且只开放443和80端口,其他端口一律关闭(防止黑客端口扫描),内网使用HTTP,性能和安全都有保障。</p></li><li><p>前端大量的组件代码得以复用,组件化,提升开发效率,抽出来!</p></li></ol><h3 id="注意事项">注意事项<a class="header-anchor" href="#注意事项" aria-hidden="true"></a></h3><ol><li>在开需求会议的时候,前后端工程师必须全部参加,并且需要制定好接口文档,后端工程师要写好测试用例(2个维度),不要让前端工程师充当你的专职测试,推荐使用Chrome的插件Postman或SoapUI或Jmeter,Service层的测试用例拿JUnit写。PS:前端也可以玩单元测试吗?</li><li>上述的接口并不是Java里的interface,说白了调用接口就是调用你Controller里的方法。</li><li>加重了前端团队的工作量,减轻了后端团队的工作量,提高了性能和可扩展性。</li><li>我们需要一些前端的框架来解决类似于页面嵌套,分页,页面跳转控制等功能。(上面提到的那些前端框架)</li><li>如果你的项目很小,或者是一个单纯的内网项目,那你大可放心,不需要任何架构,但是如果你的项目是外网项目,呵呵哒。</li><li>以前还有人在使用类似于Velocity/FreeMarker等模板框架来生成静态页面,仁者见仁智者见智。</li><li>这篇文章主要的目的是说JSP在大型外网Java Web项目中被淘汰掉,可没说JSP可以完全不学,对于一些学生朋友来说,JSP/Servlet等相关的Java Web基础还是要掌握牢的,不然你以为SpringMVC这种框架是基于什么来写的?</li><li>如果页面上有一些权限等等相关的校验,那么这些相关的数据也可以通过Ajax从接口里拿。<strong>类似于数据校验这种,前后端都需要做!</strong></li><li>对于既可以前端做也可以后端做的逻辑,我建议是放到前端,为什么?因为你的逻辑需要计算资源进行计算,如果放到后端去run逻辑,则会消耗带宽&内存&CPU等等计算资源,你要记住一点就是:<strong>服务端的计算资源是有限的</strong>,而如果放到前端,使用的是客户端的计算资源,这样你的服务端负载就会下降(高并发场景)。</li><li>前端需要有机制应对后端请求超时以及后端服务器宕机的情况,友好的展示给用户。</li></ol><h3 id="扩展阅读">扩展阅读<a class="header-anchor" href="#扩展阅读" aria-hidden="true"></a></h3><ol><li>其实对于JS、CSS、图片这类的静态资源可以考虑放到类似于阿里云的OSS这类文件服务器上(如果是普通的服务器&操作系统,存储在到达PB级的文件后,或者单个文件夹内的文件数量达到3-5万,IO会有很严重的性能问题),再在OSS上配CDN(全国子节点加速),这样无论你在全国的哪个地方,你页面打开的速度像飞一样,并且你的Nginx的负载会进一步降低。</li><li>如果你要玩轻量级微服务架构,要使用Node.js做网关,用Node.js的好处还有利于SEO优化,因为Nginx只是向浏览器返回页面静态资源,而国内的搜索引擎爬虫只会抓取静态数据,不会解析页面中的JS,这使得Web应用得不到良好的搜索引擎支持。同时因为Nginx不会进行页面的组装渲染,需要把静态页面返回到浏览器,然后完成渲染工作,这加重了浏览器的渲染负担。浏览器发起的请求经过Nginx进行分发,URL请求统一分发到Node.js,在Node.js中进行页面组装渲染;API请求则直接发送到后端服务器,完成响应。</li><li>如果遇到跨域问题,Spring4的CORS可以完美解决,但一般使用Nginx反向代理都不会有跨域问题,除非你把前端服务和后端服务分成两个域名。<em>JSONP的方式也被淘汰掉了。</em></li><li>如果想玩多端应用,注意要去掉Tomcat原生的Session机制,要使用Token机制,使用缓存(因为是分布式系统),做单点,对于Token机制的安全性问题,可以搜一下JWT。</li><li>前端项目中可以加入Mock测试(构造虚拟测试对象来模拟后端,可以独立开发和测试),后端需要有详细的测试用例,保证服务的可用性与稳定性。</li></ol><h3 id="总结">总结<a class="header-anchor" href="#总结" aria-hidden="true"></a></h3><p>前后端分离并非仅仅只是一种开发模式,而是一种架构模式(前后端分离架构)。</p><p>千万不要以为只有在撸代码的时候把前端和后端分开就是前后端分离了。需要区分前后端项目。前端项目与后端项目是两个项目,放在两个不同的服务器,需要独立部署,两个不同的工程,两个不同的代码库,不同的开发人员。</p><p>前后端工程师需要约定交互接口,实现并行开发,开发结束后需要进行独立部署,前端通过Ajax来调用HTTP请求调用后端的RESTful API。</p><p>前端只需要关注页面的样式与动态数据的解析&渲染,而后端专注于具体业务逻辑。</p><blockquote><p>本文引用自<a href="https://www.cnblogs.com/z00377750/">风动静泉的博客</a>——<a href="https://www.cnblogs.com/z00377750/p/9136385.html">JavaWeb架构发展</a>。如有侵权,请留言告知,及时撤除。</p></blockquote><link rel="stylesheet" href="https://cdn.bootcss.com/KaTeX/0.6.0/katex.min.css">]]></content>
<summary type="html"><p>前后端分离已成为互联网项目开发的业界标准使用方式,通过Nginx + Tomcat的方式(也可以中间加一个Node.js)有效的进行解耦,并且前后端分离会为以后的大型分布式架构、弹性计算架构、微服务架构、多端化服务(多种客户端,例如:浏览器,车载终端,安卓,iOS等等)打下坚实的基础。</p></summary>
<category term="技术" scheme="http://www.niemingzhao.top/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="Java" scheme="http://www.niemingzhao.top/tags/Java/"/>
</entry>
<entry>
<title>Markdown Demo</title>
<link href="http://www.niemingzhao.top/2019/01/01/markdown-demo/"/>
<id>http://www.niemingzhao.top/2019/01/01/markdown-demo/</id>
<published>2019-01-01T00:00:00.000Z</published>
<updated>2020-12-20T13:20:45.353Z</updated>
<content type="html"><![CDATA[<p>这是一个段落。<br>这是一个段落。</p><a id="more"></a><h1 id="一级标题">一级标题<a class="header-anchor" href="#一级标题" aria-hidden="true"></a></h1><h2 id="二级标题">二级标题<a class="header-anchor" href="#二级标题" aria-hidden="true"></a></h2><h1 id="一级标题-2">一级标题<a class="header-anchor" href="#一级标题-2" aria-hidden="true"></a></h1><h2 id="二级标题-2">二级标题<a class="header-anchor" href="#二级标题-2" aria-hidden="true"></a></h2><h3 id="三级标题">三级标题<a class="header-anchor" href="#三级标题" aria-hidden="true"></a></h3><h4 id="四级标题">四级标题<a class="header-anchor" href="#四级标题" aria-hidden="true"></a></h4><h5 id="五级标题">五级标题<a class="header-anchor" href="#五级标题" aria-hidden="true"></a></h5><h6 id="六级标题">六级标题<a class="header-anchor" href="#六级标题" aria-hidden="true"></a></h6><blockquote><p>区块引用</p><blockquote><p>嵌套引用</p></blockquote></blockquote><ul><li>第一项<ul><li>第一项</li><li>第二项</li><li>第三项</li></ul></li><li>第二项<ul><li>第一项</li><li>第二项</li><li>第三项</li></ul></li><li>第三项<ol><li>第一项</li><li>第二项</li><li>第三项</li></ol></li></ul><hr><hr><hr><pre><code>void main(){ printf("Hello, Markdown.");}</code></pre><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Hello, Markdown."</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><table><thead><tr><th style="text-align:left">1</th><th style="text-align:center">2</th><th style="text-align:right">3</th></tr></thead><tbody><tr><td style="text-align:left">aaaaa</td><td style="text-align:center">bbbbb</td><td style="text-align:right">ccccc</td></tr><tr><td style="text-align:left"><em>ABC</em></td><td style="text-align:center"><em>123</em></td><td style="text-align:right"><em>abc</em></td></tr></tbody></table><ul><li><input type="checkbox" id="checkbox0"><label for="checkbox0">任务A</label></li><li><input type="checkbox" id="checkbox1" checked="true"><label for="checkbox1">任务B</label><ul><li><input type="checkbox" id="checkbox2" checked="true"><label for="checkbox2">任务1</label></li><li><input type="checkbox" id="checkbox3" checked="true"><label for="checkbox3">任务2</label></li><li><input type="checkbox" id="checkbox4" checked="true"><label for="checkbox4">任务3</label></li></ul></li><li><input type="checkbox" id="checkbox5"><label for="checkbox5">任务C</label></li></ul><dl><dt>Definition</dt><dd>这是一个定义。</dd></dl><p><a href="https://www.baidu.com/">https://www.baidu.com/</a><br><a href="https://www.baidu.com/" title="Baidu">链接</a><br><a href="https://www.baidu.com/" title="Baidu">链接</a><br><img src="https://www.baidu.com/img/bd_logo1.png" alt="图片" title="Baidu"><br><img src="https://www.baidu.com/img/bd_logo1.png" alt="图片" title="Baidu" class="fancybox center-block"><br><a href="#anchor" title="Anchor">锚点</a><br><a href="#anchor" title="Anchor">锚点</a></p><p id="anchor" name="anchor">锚点</p><p>这是一个脚注<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>。</p><p>这是一个缩写(<abbr title="Hyper Text Markup Language">HTML</abbr>)。</p><p>H<sup>2</sup>,H<sub>2</sub><br><em>斜体</em>,<em>斜体</em><br><strong>粗体</strong>,<strong>粗体</strong><br><em><strong>粗斜体</strong></em>,<em><strong>粗斜体</strong></em><br><s>删除</s>,<ins>插入</ins>,<mark>标记</mark><br><code>printf("Hello, Markdown.");</code></p><p>\,`,*,_,{},[],(),#,+,-,.,!</p><p>&,<,©,😄,<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi>E</mi><mo>=</mo><mi>m</mi><msup><mi>c</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">E=mc^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.8141079999999999em;"></span><span class="strut bottom" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="base textstyle uncramped"><span class="mord mathit" style="margin-right:0.05764em;">E</span><span class="mrel">=</span><span class="mord mathit">m</span><span class="mord"><span class="mord mathit">c</span><span class="vlist"><span style="top:-0.363em;margin-right:0.05em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle uncramped"><span class="mord mathrm">2</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span></span></span></span></p><p><span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mrow><mo fence="true">{</mo><mtable><mtr><mtd><mrow><msub><mi>a</mi><mn>1</mn></msub><mi>x</mi><mo>+</mo><msub><mi>b</mi><mn>1</mn></msub><mi>y</mi><mo>+</mo><msub><mi>c</mi><mn>1</mn></msub><mi>z</mi><mo>=</mo><msub><mi>d</mi><mn>1</mn></msub></mrow></mtd></mtr><mtr><mtd><mrow><msub><mi>a</mi><mn>2</mn></msub><mi>x</mi><mo>+</mo><msub><mi>b</mi><mn>2</mn></msub><mi>y</mi><mo>+</mo><msub><mi>c</mi><mn>2</mn></msub><mi>z</mi><mo>=</mo><msub><mi>d</mi><mn>2</mn></msub></mrow></mtd></mtr><mtr><mtd><mrow><msub><mi>a</mi><mn>3</mn></msub><mi>x</mi><mo>+</mo><msub><mi>b</mi><mn>3</mn></msub><mi>y</mi><mo>+</mo><msub><mi>c</mi><mn>3</mn></msub><mi>z</mi><mo>=</mo><msub><mi>d</mi><mn>3</mn></msub></mrow></mtd></mtr></mtable></mrow></mrow><annotation encoding="application/x-tex">\begin{cases}a_1x+b_1y+c_1z=d_1\\a_2x+b_2y+c_2z=d_2\\a_3x+b_3y+c_3z=d_3\end{cases}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:2.41em;"></span><span class="strut bottom" style="height:4.32em;vertical-align:-1.9099999999999997em;"></span><span class="base displaystyle textstyle uncramped"><span class="minner displaystyle textstyle uncramped"><span class="style-wrap reset-textstyle textstyle uncramped"><span class="delimsizing mult"><span class="vlist"><span style="top:0.9500099999999998em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="delimsizinginner delim-size4"><span>⎩</span></span></span><span style="top:0.9500099999999998em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="delimsizinginner delim-size4"><span>⎪</span></span></span><span style="top:-0.000010000000000287557em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="delimsizinginner delim-size4"><span>⎨</span></span></span><span style="top:-1.1500100000000002em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="delimsizinginner delim-size4"><span>⎪</span></span></span><span style="top:-1.4500200000000003em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="delimsizinginner delim-size4"><span>⎧</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span></span><span class="mord"><span class="mtable"><span class="col-align-l"><span class="vlist"><span style="top:-1.4020000000000001em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="mord displaystyle textstyle uncramped"><span class="mord"><span class="mord mathit">a</span><span class="vlist"><span style="top:0.15em;margin-right:0.05em;margin-left:0em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">1</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span><span class="mord mathit">x</span><span class="mbin">+</span><span class="mord"><span class="mord mathit">b</span><span class="vlist"><span style="top:0.15em;margin-right:0.05em;margin-left:0em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">1</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span><span class="mord mathit" style="margin-right:0.03588em;">y</span><span class="mbin">+</span><span class="mord"><span class="mord mathit">c</span><span class="vlist"><span style="top:0.15em;margin-right:0.05em;margin-left:0em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">1</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span><span class="mord mathit" style="margin-right:0.04398em;">z</span><span class="mrel">=</span><span class="mord"><span class="mord mathit">d</span><span class="vlist"><span style="top:0.15em;margin-right:0.05em;margin-left:0em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">1</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span></span></span><span style="top:0.0379999999999997em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="mord displaystyle textstyle uncramped"><span class="mord"><span class="mord mathit">a</span><span class="vlist"><span style="top:0.15em;margin-right:0.05em;margin-left:0em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">2</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span><span class="mord mathit">x</span><span class="mbin">+</span><span class="mord"><span class="mord mathit">b</span><span class="vlist"><span style="top:0.15em;margin-right:0.05em;margin-left:0em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">2</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span><span class="mord mathit" style="margin-right:0.03588em;">y</span><span class="mbin">+</span><span class="mord"><span class="mord mathit">c</span><span class="vlist"><span style="top:0.15em;margin-right:0.05em;margin-left:0em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">2</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span><span class="mord mathit" style="margin-right:0.04398em;">z</span><span class="mrel">=</span><span class="mord"><span class="mord mathit">d</span><span class="vlist"><span style="top:0.15em;margin-right:0.05em;margin-left:0em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">2</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span></span></span><span style="top:1.4779999999999998em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="mord displaystyle textstyle uncramped"><span class="mord"><span class="mord mathit">a</span><span class="vlist"><span style="top:0.15em;margin-right:0.05em;margin-left:0em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">3</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span><span class="mord mathit">x</span><span class="mbin">+</span><span class="mord"><span class="mord mathit">b</span><span class="vlist"><span style="top:0.15em;margin-right:0.05em;margin-left:0em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">3</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span><span class="mord mathit" style="margin-right:0.03588em;">y</span><span class="mbin">+</span><span class="mord"><span class="mord mathit">c</span><span class="vlist"><span style="top:0.15em;margin-right:0.05em;margin-left:0em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">3</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span><span class="mord mathit" style="margin-right:0.04398em;">z</span><span class="mrel">=</span><span class="mord"><span class="mord mathit">d</span><span class="vlist"><span style="top:0.15em;margin-right:0.05em;margin-left:0em;"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span><span class="reset-textstyle scriptstyle cramped"><span class="mord mathrm">3</span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span></span></span><span class="baseline-fix"><span class="fontsize-ensurer reset-size5 size5"><span style="font-size:0em;"></span></span></span></span></span></span></span><span class="sizing reset-size5 size5 reset-textstyle textstyle uncramped nulldelimiter"></span></span></span></span></span></span></p><img src='data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBjb250ZW50U2NyaXB0VHlwZT0iYXBwbGljYXRpb24vZWNtYXNjcmlwdCIgY29udGVudFN0eWxlVHlwZT0idGV4dC9jc3MiIGhlaWdodD0iMTMycHgiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiIHN0eWxlPSJ3aWR0aDo5OHB4O2hlaWdodDoxMzJweDsiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDk4IDEzMiIgd2lkdGg9Ijk4cHgiIHpvb21BbmRQYW49Im1hZ25pZnkiPjxkZWZzPjxmaWx0ZXIgaGVpZ2h0PSIzMDAlIiBpZD0iZjFyNjQ0emxiemN2c24iIHdpZHRoPSIzMDAlIiB4PSItMSIgeT0iLTEiPjxmZUdhdXNzaWFuQmx1ciByZXN1bHQ9ImJsdXJPdXQiIHN0ZERldmlhdGlvbj0iMi4wIi8+PGZlQ29sb3JNYXRyaXggaW49ImJsdXJPdXQiIHJlc3VsdD0iYmx1ck91dDIiIHR5cGU9Im1hdHJpeCIgdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAuNCAwIi8+PGZlT2Zmc2V0IGR4PSI0LjAiIGR5PSI0LjAiIGluPSJibHVyT3V0MiIgcmVzdWx0PSJibHVyT3V0MyIvPjxmZUJsZW5kIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9ImJsdXJPdXQzIiBtb2RlPSJub3JtYWwiLz48L2ZpbHRlcj48L2RlZnM+PGc+PGxpbmUgc3R5bGU9InN0cm9rZTojQTgwMDM2O3N0cm9rZS13aWR0aDoxLjA7c3Ryb2tlLWRhc2hhcnJheTo1LjAsNS4wOyIgeDE9IjE5IiB4Mj0iMTkiIHkxPSI0MC4yOTY5IiB5Mj0iODkuNDI5NyIvPjxsaW5lIHN0eWxlPSJzdHJva2U6I0E4MDAzNjtzdHJva2Utd2lkdGg6MS4wO3N0cm9rZS1kYXNoYXJyYXk6NS4wLDUuMDsiIHgxPSI3NCIgeDI9Ijc0IiB5MT0iNDAuMjk2OSIgeTI9Ijg5LjQyOTciLz48cmVjdCBmaWxsPSIjRkVGRUNFIiBmaWx0ZXI9InVybCgjZjFyNjQ0emxiemN2c24pIiBoZWlnaHQ9IjMwLjI5NjkiIHN0eWxlPSJzdHJva2U6I0E4MDAzNjtzdHJva2Utd2lkdGg6MS41OyIgd2lkdGg9IjI0IiB4PSI1IiB5PSI1Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTQiIGxlbmd0aEFkanVzdD0ic3BhY2luZ0FuZEdseXBocyIgdGV4dExlbmd0aD0iMTAiIHg9IjEyIiB5PSIyNC45OTUxIj5BPC90ZXh0PjxyZWN0IGZpbGw9IiNGRUZFQ0UiIGZpbHRlcj0idXJsKCNmMXI2NDR6bGJ6Y3ZzbikiIGhlaWdodD0iMzAuMjk2OSIgc3R5bGU9InN0cm9rZTojQTgwMDM2O3N0cm9rZS13aWR0aDoxLjU7IiB3aWR0aD0iMjQiIHg9IjUiIHk9Ijg4LjQyOTciLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nQW5kR2x5cGhzIiB0ZXh0TGVuZ3RoPSIxMCIgeD0iMTIiIHk9IjEwOC40MjQ4Ij5BPC90ZXh0PjxyZWN0IGZpbGw9IiNGRUZFQ0UiIGZpbHRlcj0idXJsKCNmMXI2NDR6bGJ6Y3ZzbikiIGhlaWdodD0iMzAuMjk2OSIgc3R5bGU9InN0cm9rZTojQTgwMDM2O3N0cm9rZS13aWR0aDoxLjU7IiB3aWR0aD0iMjQiIHg9IjYwIiB5PSI1Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTQiIGxlbmd0aEFkanVzdD0ic3BhY2luZ0FuZEdseXBocyIgdGV4dExlbmd0aD0iMTAiIHg9IjY3IiB5PSIyNC45OTUxIj5CPC90ZXh0PjxyZWN0IGZpbGw9IiNGRUZFQ0UiIGZpbHRlcj0idXJsKCNmMXI2NDR6bGJ6Y3ZzbikiIGhlaWdodD0iMzAuMjk2OSIgc3R5bGU9InN0cm9rZTojQTgwMDM2O3N0cm9rZS13aWR0aDoxLjU7IiB3aWR0aD0iMjQiIHg9IjYwIiB5PSI4OC40Mjk3Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTQiIGxlbmd0aEFkanVzdD0ic3BhY2luZ0FuZEdseXBocyIgdGV4dExlbmd0aD0iMTAiIHg9IjY3IiB5PSIxMDguNDI0OCI+QjwvdGV4dD48cG9seWdvbiBmaWxsPSIjQTgwMDM2IiBwb2ludHM9IjYyLDY3LjQyOTcsNzIsNzEuNDI5Nyw2Miw3NS40Mjk3LDY2LDcxLjQyOTciIHN0eWxlPSJzdHJva2U6I0E4MDAzNjtzdHJva2Utd2lkdGg6MS4wOyIvPjxsaW5lIHN0eWxlPSJzdHJva2U6I0E4MDAzNjtzdHJva2Utd2lkdGg6MS4wOyIgeDE9IjE5IiB4Mj0iNjgiIHkxPSI3MS40Mjk3IiB5Mj0iNzEuNDI5NyIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmdBbmRHbHlwaHMiIHRleHRMZW5ndGg9IjMxIiB4PSIyNiIgeT0iNjYuMzYzOCI+SGVsbG88L3RleHQ+PCEtLU1ENT1bYzk3MGUxYjZhMTc2ZmM0NTk4NjI2ODkxYmVhMWQwMmVdCkBzdGFydHVtbA0KQSAtPiBCOiBIZWxsbw0KQGVuZHVtbA0KClBsYW50VU1MIHZlcnNpb24gMS4yMDIwLjI0KEZyaSBEZWMgMTggMTc6MDA6MzYgVVRDIDIwMjApCihHUEwgc291cmNlIGRpc3RyaWJ1dGlvbikKSmF2YSBSdW50aW1lOiBKYXZhKFRNKSBTRSBSdW50aW1lIEVudmlyb25tZW50CkpWTTogSmF2YSBIb3RTcG90KFRNKSA2NC1CaXQgU2VydmVyIFZNCkRlZmF1bHQgRW5jb2Rpbmc6IFVURi04Ckxhbmd1YWdlOiBlbgpDb3VudHJ5OiBVUwotLT48L2c+PC9zdmc+'><blockquote><p>Do not just seek happiness for yourself. Seek happiness for all. Through kindness. Through mercy.</p><footer><strong>David Levithan</strong><cite>Wide Awake</cite></footer></blockquote><blockquote><p>Every interaction is both precious and an opportunity to delight.</p><footer><strong>Seth Godin</strong><cite><a href="http://sethgodin.typepad.com/seths_blog/2009/07/welcome-to-island-marketing.html">Welcome to Island Marketing</a></cite></footer></blockquote><figure class="highlight javascript"><figcaption><span>_.compact</span><a href="http://underscorejs.org/#compact">Underscore.js</a></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">_.compact([<span class="number">0</span>, <span class="number">1</span>, <span class="literal">false</span>, <span class="number">2</span>, <span class="string">''</span>, <span class="number">3</span>]);</span><br><span class="line">=> [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br></pre></td></tr></table></figure><iframe src="https://www.baidu.com/" width="100%" height="300" frameborder="0" loading="lazy" allowfullscreen></iframe><img src="https://www.baidu.com/img/bd_logo1.png" class="image" width="300" height="150" title="Baidu"><a href="https://www.baidu.com/" title="Baidu" target="">Baidu</a><link rel="stylesheet" href="https://cdn.bootcss.com/KaTeX/0.6.0/katex.min.css"><hr class="footnotes-sep"><section class="footnotes"><ol class="footnotes-list"><li id="fn1" class="footnote-item"><p><a href="https://www.baidu.com/">https://www.baidu.com/</a> <a href="#fnref1" class="footnote-backref">↩︎</a></p></li></ol></section>]]></content>
<summary type="html"><p>这是一个段落。<br>
这是一个段落。</p></summary>
<category term="Markdown" scheme="http://www.niemingzhao.top/tags/Markdown/"/>
</entry>
<entry>
<title>前端工程化工具自选</title>
<link href="http://www.niemingzhao.top/2017/01/14/%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%8C%96%E5%B7%A5%E5%85%B7%E8%87%AA%E9%80%89/"/>
<id>http://www.niemingzhao.top/2017/01/14/%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%8C%96%E5%B7%A5%E5%85%B7%E8%87%AA%E9%80%89/</id>
<published>2017-01-14T12:51:00.000Z</published>
<updated>2020-12-20T13:20:45.353Z</updated>
<content type="html"><![CDATA[<p>工欲善其事,必先利其器。在Web2.0+的时代,前端的工作早已经不再是切切图、写写动效了。现在,前端的发展已经走向工程化、自动化、大型化,而这些进步需要一大批前端工具来实现。下面是我目前选择的一些前端工程化工具,以备使用时参考。</p><a id="more"></a><h2 id="构建">构建<a class="header-anchor" href="#构建" aria-hidden="true"></a></h2><ul><li>gulp,更先进灵活,以后的趋势,<strong>我的选择</strong>。</li><li>grunt,目前仍有大量使用者,插件丰富,更成熟。</li></ul><h2 id="模块打包">模块打包<a class="header-anchor" href="#模块打包" aria-hidden="true"></a></h2><ul><li>browserify,更简单方便,但功能较少,<strong>我的选择</strong>。</li><li>webpack,功能强大,有大量使用者,但配置复杂。</li></ul><h2 id="脚手架">脚手架<a class="header-anchor" href="#脚手架" aria-hidden="true"></a></h2><ul><li>yeoman,功能强大全面,插件丰富,<strong>我的选择</strong>。</li></ul><h2 id="包管理">包管理<a class="header-anchor" href="#包管理" aria-hidden="true"></a></h2><ul><li>npm,Node.js官方包管理工具,功能强大,但好像不太适合前端包管理,<strong>我的选择</strong>。</li><li>bower,更适合前端包管理,但并不好使。</li></ul><h2 id="CSS预处理">CSS预处理<a class="header-anchor" href="#CSS预处理" aria-hidden="true"></a></h2><ul><li>stylus,新一代预处理器,功能强大灵活,但支持者较少。</li><li>less,功能较弱,但使用简单,支持者较多,<strong>我的选择</strong>。</li><li>scss/sass,功能强大,老牌预处理器,支持者众,但配置复杂。</li></ul><h2 id="模板引擎">模板引擎<a class="header-anchor" href="#模板引擎" aria-hidden="true"></a></h2><ul><li>ejs,语法简单灵活,但功能较少,代码不直观,<strong>我的选择</strong>。</li><li>jade,功能强大,代码简洁灵活,但上手不容易。</li><li>handlebars,功能强大,上手不容易。</li></ul><h2 id="测试">测试<a class="header-anchor" href="#测试" aria-hidden="true"></a></h2><ul><li>mocha,<strong>我的选择</strong>。</li><li>jasmine。</li><li>chai。</li></ul><h2 id="ES6编译">ES6编译<a class="header-anchor" href="#ES6编译" aria-hidden="true"></a></h2><ul><li>babel,功能强大全面,<strong>我的选择</strong>。</li></ul><h2 id="版本管理">版本管理<a class="header-anchor" href="#版本管理" aria-hidden="true"></a></h2><ul><li>git,<strong>我的选择</strong>。</li></ul><blockquote><p>未完待续…</p></blockquote><link rel="stylesheet" href="https://cdn.bootcss.com/KaTeX/0.6.0/katex.min.css">]]></content>
<summary type="html"><p>工欲善其事,必先利其器。在Web2.0+的时代,前端的工作早已经不再是切切图、写写动效了。现在,前端的发展已经走向工程化、自动化、大型化,而这些进步需要一大批前端工具来实现。下面是我目前选择的一些前端工程化工具,以备使用时参考。</p></summary>
<category term="技术" scheme="http://www.niemingzhao.top/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="前端" scheme="http://www.niemingzhao.top/tags/%E5%89%8D%E7%AB%AF/"/>
</entry>
<entry>
<title>为本机Git配置SSH链接</title>
<link href="http://www.niemingzhao.top/2017/01/07/%E4%B8%BA%E6%9C%AC%E6%9C%BAGit%E9%85%8D%E7%BD%AESSH%E9%93%BE%E6%8E%A5/"/>
<id>http://www.niemingzhao.top/2017/01/07/%E4%B8%BA%E6%9C%AC%E6%9C%BAGit%E9%85%8D%E7%BD%AESSH%E9%93%BE%E6%8E%A5/</id>
<published>2017-01-07T12:24:00.000Z</published>
<updated>2020-12-20T13:20:45.353Z</updated>
<content type="html"><![CDATA[<p>访问代码仓库时,需要建立安全链接,对于Git,常用的安全链接协议有HTTPS和SSH两种。HTTPS使用更简单,只需在向仓库提交代码时提供一下用户名和密码即可。但是经常出现需要频繁提供用户名和密码的情况,这个不能忍。相比之下,SSH的方式虽然配置有点难,但一次配置,次次可用,是个更好的方式。</p><a id="more"></a><h2 id="配置方式">配置方式<a class="header-anchor" href="#配置方式" aria-hidden="true"></a></h2><h3 id="配置Git账户信息">配置Git账户信息<a class="header-anchor" href="#配置Git账户信息" aria-hidden="true"></a></h3><p>要使用Git建立远程链接,肯定要先配置本机的Git账户信息啦。<br>首先打开本机上的bash终端,下面的命令行都是在bash终端中执行的,使用windows系统的小伙伴们不要使用cmd,需要打开git-bash才行。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config --global user.name "username"</span><br><span class="line">git config --global user.email "email"</span><br></pre></td></tr></table></figure><p>上面引号里就是你的远程代码仓库(如github)的账号信息了,username是用户名(昵称),email是注册邮箱。</p><h3 id="检查本机是否存在SSH Key">检查本机是否存在SSH Key<a class="header-anchor" href="#检查本机是否存在SSH Key" aria-hidden="true"></a></h3><p>检查一下本机是不是已经建立过SSH Key,如果有的话可以备份到其它地方保存,然后删除掉本机的SSH Key。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cd ~/.ssh</span><br></pre></td></tr></table></figure><p>如果执行命令后,会进入文件夹,就说明已经建立过SSH Key,需要清空。</p><h3 id="生成新的SSH Key">生成新的SSH Key<a class="header-anchor" href="#生成新的SSH Key" aria-hidden="true"></a></h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-keygen -t rsa -C "email"</span><br></pre></td></tr></table></figure><p>执行命令后,会问你一些问题,是否要建立密码一类的,不用管,一路回车略过就行。然后你会在你的本机用户主目录下看到一个<code>.ssh</code>的文件夹。里面有<code>id_rsa</code>和<code>id_rsa.pub</code>两个文件,这两个就是SSH Key的秘钥对,<code>id_rsa</code>是私钥,不能泄露出去,<code>id_rsa.pub</code>是公钥,可以放心地告诉任何人。</p><h3 id="为远程仓库配置SSH Key">为远程仓库配置SSH Key<a class="header-anchor" href="#为远程仓库配置SSH Key" aria-hidden="true"></a></h3><p>进入你的远程仓库(如github)的设置(总账户的设置而不是单个代码库的设置),点开<code>SSH and GPG keys</code>,然后点击<code>New SSH key</code>,Title随便填,再打开<code>id_rsa.pub</code>文件,复制所有内容填到Key文本框内,点击<code>Add SSH key</code>保存即可。</p><h3 id="测试SSH链接">测试SSH链接<a class="header-anchor" href="#测试SSH链接" aria-hidden="true"></a></h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh -T [email protected]</span><br></pre></td></tr></table></figure><p>执行命令后,可能会问你是否继续链接,输入<code>yes</code>回车即可。如果看到<code>Hi</code>后面是你的用户名,就说明配置成功,以后就可以直接提交代码了。</p><link rel="stylesheet" href="https://cdn.bootcss.com/KaTeX/0.6.0/katex.min.css">]]></content>
<summary type="html"><p>访问代码仓库时,需要建立安全链接,对于Git,常用的安全链接协议有HTTPS和SSH两种。HTTPS使用更简单,只需在向仓库提交代码时提供一下用户名和密码即可。但是经常出现需要频繁提供用户名和密码的情况,这个不能忍。相比之下,SSH的方式虽然配置有点难,但一次配置,次次可用,是个更好的方式。</p></summary>
<category term="技术" scheme="http://www.niemingzhao.top/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="Git" scheme="http://www.niemingzhao.top/tags/Git/"/>
</entry>
<entry>
<title>岳阳楼记</title>
<link href="http://www.niemingzhao.top/2016/10/29/%E5%B2%B3%E9%98%B3%E6%A5%BC%E8%AE%B0/"/>
<id>http://www.niemingzhao.top/2016/10/29/%E5%B2%B3%E9%98%B3%E6%A5%BC%E8%AE%B0/</id>
<published>2016-10-29T13:03:00.000Z</published>
<updated>2020-12-20T13:20:45.353Z</updated>
<content type="html"><![CDATA[<p>范仲淹[宋]</p><p>庆历四年春,滕子京谪守巴陵郡。越明年,政通人和,百废具兴。乃重修岳阳楼,增其旧制,刻唐贤今人诗赋于其上。属予作文以记之。<a id="more"></a></p><p>予观夫巴陵胜状,在洞庭一湖。衔远山,吞长江,浩浩汤汤,横无际涯;朝晖夕阴,气象万千。此则岳阳楼之大观也,前人之述备矣。然则北通巫峡,南极潇湘,迁客骚人,多会于此,览物之情,得无异乎?</p><p>若夫淫雨霏霏,连月不开,阴风怒号,浊浪排空;日星隐曜,山岳潜形;商旅不行,樯倾楫摧;薄暮冥冥,虎啸猿啼。登斯楼也,则有去国怀乡,忧谗畏讥,满目萧然,感极而悲者矣。</p><p>至若春和景明,波澜不惊,上下天光,一碧万顷;沙鸥翔集,锦鳞游泳;岸芷汀兰,郁郁青青。而或长烟一空,皓月千里,浮光跃金,静影沉璧,渔歌互答,此乐何极!登斯楼也,则有心旷神怡,宠辱偕忘,把酒临风,其喜洋洋者矣。</p><p>嗟夫!予尝求古仁人之心,或异二者之为,何哉?不以物喜,不以己悲;居庙堂之高则忧其民;处江湖之远则忧其君。是进亦忧,退亦忧。然则何时而乐耶?其必曰“先天下之忧而忧,后天下之乐而乐”乎?噫!微斯人,吾谁与归?</p><p>时六年九月十五日。</p><link rel="stylesheet" href="https://cdn.bootcss.com/KaTeX/0.6.0/katex.min.css">]]></content>
<summary type="html"><p>范仲淹[宋]</p>
<p>庆历四年春,滕子京谪守巴陵郡。越明年,政通人和,百废具兴。乃重修岳阳楼,增其旧制,刻唐贤今人诗赋于其上。属予作文以记之。</summary>
<category term="文粹" scheme="http://www.niemingzhao.top/categories/%E6%96%87%E7%B2%B9/"/>
<category term="古文" scheme="http://www.niemingzhao.top/tags/%E5%8F%A4%E6%96%87/"/>
</entry>
<entry>
<title>Git常用命令小记</title>
<link href="http://www.niemingzhao.top/2016/10/04/Git%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E5%B0%8F%E8%AE%B0/"/>
<id>http://www.niemingzhao.top/2016/10/04/Git%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E5%B0%8F%E8%AE%B0/</id>
<published>2016-10-04T16:22:00.000Z</published>
<updated>2020-12-20T13:20:45.353Z</updated>
<content type="html"><![CDATA[<p>Git的使用确实要比SVN复杂,下面记录了一下Git的常用命令,以备以后查用。</p><a id="more"></a><h2 id="排除监视文件">排除监视文件<a class="header-anchor" href="#排除监视文件" aria-hidden="true"></a></h2><ul><li>在代码库根目录添加一个<code>.gitignore</code>文件,在文件中写上文件名(含路径)或路径名即可</li></ul><h2 id="新建">新建<a class="header-anchor" href="#新建" aria-hidden="true"></a></h2><ul><li>新建一个代码库</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git init <repo></span><br></pre></td></tr></table></figure><ul><li>克隆一个项目</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git clone [url]</span><br></pre></td></tr></table></figure><h2 id="配置">配置<a class="header-anchor" href="#配置" aria-hidden="true"></a></h2><ul><li>显示当前配置</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git config --list</span><br></pre></td></tr></table></figure><ul><li>编辑配置文件</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git config -e <--global></span><br></pre></td></tr></table></figure><ul><li>设置用户信息</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ git config <--global> user.name "[name]"</span><br><span class="line">$ git config <--global> user.email "[email]"</span><br></pre></td></tr></table></figure><h2 id="添加/删除">添加/删除<a class="header-anchor" href="#添加/删除" aria-hidden="true"></a></h2><ul><li>添加指定文件到暂存区</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git add [file]</span><br></pre></td></tr></table></figure><ul><li>添加指定目录到暂存区,包含子目录</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git add [dir]</span><br></pre></td></tr></table></figure><ul><li>添加当前目录的所有文件到暂存区</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git add .</span><br></pre></td></tr></table></figure><blockquote><p>未完待续…</p></blockquote><link rel="stylesheet" href="https://cdn.bootcss.com/KaTeX/0.6.0/katex.min.css">]]></content>
<summary type="html"><p>Git的使用确实要比SVN复杂,下面记录了一下Git的常用命令,以备以后查用。</p></summary>
<category term="技术" scheme="http://www.niemingzhao.top/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="Git" scheme="http://www.niemingzhao.top/tags/Git/"/>
</entry>
<entry>
<title>滕王阁序</title>
<link href="http://www.niemingzhao.top/2016/08/30/%E6%BB%95%E7%8E%8B%E9%98%81%E5%BA%8F/"/>
<id>http://www.niemingzhao.top/2016/08/30/%E6%BB%95%E7%8E%8B%E9%98%81%E5%BA%8F/</id>
<published>2016-08-30T07:46:00.000Z</published>
<updated>2020-12-20T13:20:45.353Z</updated>
<content type="html"><![CDATA[<p>王勃[唐]</p><p>豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,控蛮荆而引瓯越。物华天宝,龙光射牛斗之墟;人杰地灵,徐孺下陈蕃之榻。雄州雾列,俊采星驰。台隍枕夷夏之交,宾主尽东南之美。<a id="more"></a>都督阎公之雅望,棨戟遥临;宇文新州之懿范,襜帷暂驻。十旬休假,胜友如云;千里逢迎,高朋满座。腾蛟起凤,孟学士之词宗;紫电青霜,王将军之武库。家君作宰,路出名区;童子何知,躬逢胜饯。</p><p>时维九月,序属三秋。潦水尽而寒潭清,烟光凝而暮山紫。俨骖騑于上路,访风景于崇阿;临帝子之长洲,得天人之旧馆。层峦耸翠,上出重霄;飞阁流丹,下临无地。鹤汀凫渚,穷岛屿之萦回;桂殿兰宫,即冈峦之体势。</p><p>披绣闼,俯雕甍,山原旷其盈视,川泽纡其骇瞩。闾阎扑地,钟鸣鼎食之家;舸舰迷津,青雀黄龙之舳。云销雨霁,彩彻区明。落霞与孤鹜齐飞,秋水共长天一色。渔舟唱晚,响穷彭蠡之滨;雁阵惊寒,声断衡阳之浦。<br>遥襟甫畅,逸兴遄飞。爽籁发而清风生,纤歌凝而白云遏。睢园绿竹,气凌彭泽之樽;邺水朱华,光照临川之笔。四美具,二难并。穷睇眄于中天,极娱游于暇日。天高地迥,觉宇宙之无穷;兴尽悲来,识盈虚之有数。望长安于日下,目吴会于云间。地势极而南溟深,天柱高而北辰远。关山难越,谁悲失路之人?萍水相逢,尽是他乡之客。怀帝阍而不见,奉宣室以何年?</p><p>嗟乎!时运不齐,命途多舛。冯唐易老,李广难封。屈贾谊于长沙,非无圣主;窜梁鸿于海曲,岂乏明时?所赖君子见机,达人知命。老当益壮,宁移白首之心?穷且益坚,不坠青云之志。酌贪泉而觉爽,处涸辙以犹欢。北海虽赊,扶摇可接;东隅已逝,桑榆非晚。孟尝高洁,空余报国之情;阮籍猖狂,岂效穷途之哭!</p><p>勃,三尺微命,一介书生。无路请缨,等终军之弱冠;有怀投笔,慕宗悫之长风。舍簪笏于百龄,奉晨昏于万里。非谢家之宝树,接孟氏之芳邻。他日趋庭,叨陪鲤对;今兹捧袂,喜托龙门。杨意不逢,抚凌云而自惜;钟期既遇,奏流水以何惭?</p><p>呜乎!胜地不常,盛筵难再;兰亭已矣,梓泽丘墟。临别赠言,幸承恩于伟饯;登高作赋,是所望于群公。敢竭鄙怀,恭疏短引;一言均赋,四韵俱成。请洒潘江,各倾陆海云尔:</p><p>滕王高阁临江渚,佩玉鸣鸾罢歌舞。<br>画栋朝飞南浦云,珠帘暮卷西山雨。<br>闲云潭影日悠悠,物换星移几度秋。<br>阁中帝子今何在?槛外长江空自流。</p><link rel="stylesheet" href="https://cdn.bootcss.com/KaTeX/0.6.0/katex.min.css">]]></content>
<summary type="html"><p>王勃[唐]</p>
<p>豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,控蛮荆而引瓯越。物华天宝,龙光射牛斗之墟;人杰地灵,徐孺下陈蕃之榻。雄州雾列,俊采星驰。台隍枕夷夏之交,宾主尽东南之美。</summary>
<category term="文粹" scheme="http://www.niemingzhao.top/categories/%E6%96%87%E7%B2%B9/"/>
<category term="古文" scheme="http://www.niemingzhao.top/tags/%E5%8F%A4%E6%96%87/"/>
</entry>
<entry>
<title>Markdown语法小记</title>
<link href="http://www.niemingzhao.top/2016/08/23/Markdown%E8%AF%AD%E6%B3%95%E5%B0%8F%E8%AE%B0/"/>
<id>http://www.niemingzhao.top/2016/08/23/Markdown%E8%AF%AD%E6%B3%95%E5%B0%8F%E8%AE%B0/</id>
<published>2016-08-23T08:25:00.000Z</published>
<updated>2020-12-20T13:20:45.353Z</updated>
<content type="html"><![CDATA[<p>Markdown(百度百科:<a href="http://baike.baidu.com/link?url=u9yLyguvr1TEzeJViCDtlIHOJgpuJc7iCgYKRecaIUBiUoFmMOIbZhvKbReXCLm4LPtv8QIzokVHe9H78XjS9uNN1_tQ4wrSIAjTxferXOO">Markdown</a>)是一种轻量级的标记语言,语法简洁明了,易学易写,非常适合于编写结构化文档。Markdown的语法和HTML很类似,都是“文本+标记”的形式,文本表示内容,标记表示结构和排版。和HTML不同的是,Markdown的语法要简单的多,只涵盖纯文本可以涵盖的范围,所用的标记也只对应HTML标记中有关文本内容的部分。但Markdown的语法是兼容HTML的,也就是说,可以直接在Markdown文档中插入任何HTML内容,插入的HTML内容将得到与在HTML文档中相同的呈现效果。Markdown文档的扩展名为<code>.md</code>,可以使用任意文本编辑器(如记事本)打开和编辑。但要看到Markdown文档的呈现效果,则需要使用MarkdownPad等Markdown解析器。当然,也有许多在线Markdown解析器可供使用。</p><a id="more"></a><h2 id="基本语法">基本语法<a class="header-anchor" href="#基本语法" aria-hidden="true"></a></h2><h3 id="区块元素">区块元素<a class="header-anchor" href="#区块元素" aria-hidden="true"></a></h3><h4 id="段落">段落<a class="header-anchor" href="#段落" aria-hidden="true"></a></h4><ul><li>两个空行之间的连续文本行构成一个段落。空行指行内没有文本,但可以包含空格和制表符。连续文本行指行间没有空行。</li><li>段落内的文本不会产生换行,换行符将被转换为空格。如果要使段落内产生换行,需要在换行符前加至少两个空格。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Markdown是一种轻量级的 </span><br><span class="line">标记语言。</span><br></pre></td></tr></table></figure><h4 id="标题">标题<a class="header-anchor" href="#标题" aria-hidden="true"></a></h4><ul><li>类SETEXT形式使用<code>=</code>(一级标题)和<code>-</code> (二级标题)标记,底线形式,至少一个。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">一级标题</span><br><span class="line">===</span><br><span class="line">二级标题</span><br><span class="line">---</span><br></pre></td></tr></table></figure><ul><li>类ATX形式使用<code>#</code>标记,行首形式,可以有一到六个,几个就是几级标题,和文本间要有空格。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"># 一级标题</span><br><span class="line">## 二级标题</span><br><span class="line">### 三级标题</span><br><span class="line">#### 四级标题</span><br><span class="line">##### 五级标题</span><br><span class="line">###### 六级标题</span><br></pre></td></tr></table></figure><h4 id="引用">引用<a class="header-anchor" href="#引用" aria-hidden="true"></a></h4><ul><li>使用<code>></code>标记,行首形式,只需一个,可以每行都加,也可以只在每个段落第一行加,和文本间要有空格。</li><li>可以嵌套其它Markdown标记,包括另一层引用。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">> 这是第一层引用</span><br><span class="line">> > 这是第二层引用</span><br><span class="line">> # 这是引用中的标题</span><br><span class="line">> * 这是引用中的列表</span><br><span class="line">> 下面是引用中的代码块</span><br><span class="line">> </span><br><span class="line">> code is here!</span><br><span class="line">> </span><br></pre></td></tr></table></figure><h4 id="列表">列表<a class="header-anchor" href="#列表" aria-hidden="true"></a></h4><ul><li>无序列表使用<code>*</code>、<code>+</code>或<code>-</code>标记,行首形式,只需一个,和文本间要有空格。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">* 第一条</span><br><span class="line">* 第二条</span><br></pre></td></tr></table></figure><ul><li>有序列表使用数字加<code>.</code>来标记,行首形式,只需一个,和文本间要有空格,数字的序列并不会影响生成的列表序列。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">1. 第一条</span><br><span class="line">2. 第二条</span><br></pre></td></tr></table></figure><ul><li>可以嵌套其它Markdown标记,包括另一层列表。</li><li>要取消显示为有序列表,可以将<code>.</code>改为<code>\.</code>。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1. 第一条</span><br><span class="line"> * 第一条</span><br><span class="line"> * 第二条</span><br><span class="line">2. 第二条</span><br><span class="line">3\. 第三条</span><br></pre></td></tr></table></figure><h4 id="代码块">代码块<a class="header-anchor" href="#代码块" aria-hidden="true"></a></h4><ul><li>使用缩进四个空格或一个制表符来标记,行首形式,每一行都要缩进,区块前后都要有至少一个空行。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">code is here!</span><br><span class="line"> code is here!</span><br></pre></td></tr></table></figure><h4 id="分隔线">分隔线<a class="header-anchor" href="#分隔线" aria-hidden="true"></a></h4><ul><li>使用<code>*</code>、<code>-</code>或<code>_</code>标记,底线形式,至少三个。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">*****</span><br><span class="line">-----</span><br><span class="line">_____</span><br></pre></td></tr></table></figure><h3 id="区段元素">区段元素<a class="header-anchor" href="#区段元素" aria-hidden="true"></a></h3><h4 id="超链接">超链接<a class="header-anchor" href="#超链接" aria-hidden="true"></a></h4><ul><li>行内式使用<code>[Text](URL "Title")</code>的形式来标记,其中,Text为链接文本,URL为链接网址,Title为链接标题,Title不是必须的。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">这是一个[超链接](https://www.baidu.com/ "示例链接")。</span><br></pre></td></tr></table></figure><ul><li>参考式使用<code>[Text][ID]</code>的形式来标记,其中,Text为链接文本,ID为识别符,识别符不区分大小写。然后需要在文档另外任意位置定义链接内容,使用<code>[ID]: URL "Title"</code>的形式来标记,其中,ID为识别符,URL为链接网址,Title为链接标题,Title不是必须的。也可以省略识别符,直接使用链接文本当作识别符。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">这是一个[超链接][A]。</span><br><span class="line">[A]: https://www.baidu.com/ "示例链接"</span><br></pre></td></tr></table></figure><ul><li>自动链接使用<code><></code>标记,中间直接包含链接网址即可。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">这是一个<https://www.baidu.com/>。</span><br></pre></td></tr></table></figure><h4 id="强调">强调<a class="header-anchor" href="#强调" aria-hidden="true"></a></h4><ul><li>使用<code>* *</code>或<code>_ _</code>标记,中间包含的文本会显示为斜体,和文本间不能有空格。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">这里需要*强调*。</span><br></pre></td></tr></table></figure><ul><li>使用<code>** **</code>或<code>__ __</code>标记,中间包含的文本会显示为加粗,和文本间不能有空格。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">这里需要**强调**。</span><br></pre></td></tr></table></figure><h4 id="代码">代码<a class="header-anchor" href="#代码" aria-hidden="true"></a></h4><ul><li>使用<code>` `</code>标记,中间可以包含行内代码,和文本间不能有空格。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">这里是代码`code`。</span><br></pre></td></tr></table></figure><h4 id="图片">图片<a class="header-anchor" href="#图片" aria-hidden="true"></a></h4><ul><li>语法和超链接的相同,也分为行内式和参考式两种,唯一不同为需要在<code>[Text]</code>前加一个<code>!</code>。</li><li>不支持指定图片的大小,如有需求要使用HTML中的<code><img></code>标记。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">这里是一幅![图片](https://www.baidu.com/img/bd_logo1.png "示例图片")</span><br></pre></td></tr></table></figure><h4 id="字符转义">字符转义<a class="header-anchor" href="#字符转义" aria-hidden="true"></a></h4><ul><li>使用<code>\</code>来插入在Markdown语法中有特殊作用的字符。这些字符有<code>\</code>、<code>`</code>、<code>*</code>、<code>_</code>、<code>{}</code>、<code>[]</code>、<code>()</code>、<code>#</code>、<code>+</code>、<code>-</code>、<code>.</code>、<code>!</code>。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">转义一些字符:\\、\`、\*等。</span><br></pre></td></tr></table></figure><h2 id="扩展语法">扩展语法<a class="header-anchor" href="#扩展语法" aria-hidden="true"></a></h2><h3 id="删除线">删除线<a class="header-anchor" href="#删除线" aria-hidden="true"></a></h3><ul><li>使用<code>~~ ~~</code>标记,为区段元素,中间包含的文本会显示有删除线,和文本间不能有空格。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">这是一些~~删除文本~~。</span><br></pre></td></tr></table></figure><h3 id="高亮代码块">高亮代码块<a class="header-anchor" href="#高亮代码块" aria-hidden="true"></a></h3><ul><li>使用三个<code>`</code>加代码名称标记,为区块元素,底线形式。与基本语法的代码块颇不同,无需缩进,代码块文本前后各以三个<code>`</code>为一行,代码名称可以省略。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">略</span><br></pre></td></tr></table></figure><h3 id="表格">表格<a class="header-anchor" href="#表格" aria-hidden="true"></a></h3><ul><li>使用<code>|</code>标记分割不同的单元格,使用<code>-</code>标记分割表头和其它行,标记数量不限,为区块元素,底线形式。为了美观,可以添加多个空格进行对齐。</li><li>使用<code>:</code>标记配合<code>-</code>标记来设置单元格内容对齐方式。<code>:----</code>为左对齐,<code>:---:</code>为居中对齐,<code>----:</code>为右对齐,默认为左对齐。</li><li>可以嵌套其它Markdown区段元素标记。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">| left | center | right |</span><br><span class="line">| :--- | :----: | ----: |</span><br><span class="line">| aaaa | bbbbbb | ccccc |</span><br><span class="line">| *a* | *b* | *c* |</span><br></pre></td></tr></table></figure><h3 id="任务列表">任务列表<a class="header-anchor" href="#任务列表" aria-hidden="true"></a></h3><ul><li>大多数Markdown解析器都未实现此元素。</li><li>主要用来显示总体中的选择情况。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">- [ ] A</span><br><span class="line">- [x] B</span><br><span class="line"> - [x] B1</span><br><span class="line"> - [x] B2</span><br><span class="line"> - [x] B3</span><br><span class="line">- [ ] C</span><br></pre></td></tr></table></figure><h2 id="后记">后记<a class="header-anchor" href="#后记" aria-hidden="true"></a></h2><p>Markdown发展到现在,在不同的解析器中产生了一些不同的标准,显示的效果也会有差异,但大都涵盖了上述语法。在使用不同的Markdown解析器前,最好先看一下该解析器的说明文档,了解它使用哪些标准,会支持哪些Markdown语法。</p><link rel="stylesheet" href="https://cdn.bootcss.com/KaTeX/0.6.0/katex.min.css">]]></content>
<summary type="html"><p>Markdown(百度百科:<a href="http://baike.baidu.com/link?url=u9yLyguvr1TEzeJViCDtlIHOJgpuJc7iCgYKRecaIUBiUoFmMOIbZhvKbReXCLm4LPtv8QIzokVHe9H78XjS9uNN1_tQ4wrSIAjTxferXOO">Markdown</a>)是一种轻量级的标记语言,语法简洁明了,易学易写,非常适合于编写结构化文档。Markdown的语法和HTML很类似,都是“文本+标记”的形式,文本表示内容,标记表示结构和排版。和HTML不同的是,Markdown的语法要简单的多,只涵盖纯文本可以涵盖的范围,所用的标记也只对应HTML标记中有关文本内容的部分。但Markdown的语法是兼容HTML的,也就是说,可以直接在Markdown文档中插入任何HTML内容,插入的HTML内容将得到与在HTML文档中相同的呈现效果。Markdown文档的扩展名为<code>.md</code>,可以使用任意文本编辑器(如记事本)打开和编辑。但要看到Markdown文档的呈现效果,则需要使用MarkdownPad等Markdown解析器。当然,也有许多在线Markdown解析器可供使用。</p></summary>
<category term="技术" scheme="http://www.niemingzhao.top/categories/%E6%8A%80%E6%9C%AF/"/>
<category term="Markdown" scheme="http://www.niemingzhao.top/tags/Markdown/"/>
</entry>
</feed>