-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
423 lines (254 loc) · 213 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
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>编程之路</title>
<link href="/atom.xml" rel="self"/>
<link href="/"/>
<updated>2021-05-18T04:05:30.699Z</updated>
<id>/</id>
<author>
<name>DLZ</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>负面情绪</title>
<link href="/2021/05/2021/05/%E8%B4%9F%E9%9D%A2%E6%83%85%E7%BB%AA/"/>
<id>/2021/05/2021/05/负面情绪/</id>
<published>2021-05-17T16:00:00.000Z</published>
<updated>2021-05-18T04:05:30.699Z</updated>
<content type="html"><![CDATA[<p>…<br><a id="more"></a></p><p>还是想写点日记,可能是晚上听了一些话,让自己心里有点不舒服。尽管自己给了自己一些心理暗示,但是夜深人静的时候,还是感觉到了自己内心的负面情绪。自卑、嫉妒、焦虑、愧疚、急于表现自己、急躁、不甘,无助。 一时间找不到支持自己努力工作的点。</p><p>是为了让自己变成能力更强的人吗?可是自己还是很差劲、比不上别人。是为了把一项任务出色的完成吗?可是任务似乎是无穷无尽的,而自己遇到问题时还是一样的不知所措,可笑。 每天过得那么累,却感觉没有收获。 </p><hr><p>作为一个人,一个独立的生命,当不知所措、感觉到不对劲、意识到负面情绪产生的时候,应该从自己的内心寻求答案。一切负面情绪都来源于我们的内心,可能事情无法避免,但是事情是客观的,客观的事情没有完全决定了主观的情绪,我生来会有情绪,但不意味着我不能控制自己的情绪。傻逼需求跟我的愤怒没有必然的联系,生产环境问题的出现跟我的紧张没有必然的联系,别人的质疑、嘲讽理论上我也可以不紧张、不怀疑自己、不生气。 </p><p>负面情绪实在是累赘,对我来说,工作的难度是 1,工作时的负面情堵带来的难度就是 2,无形中承受了许多不必要的痛苦。一直以来,负面情绪比思路还得更快。甩掉累赘,生活似乎又变得轻松了许多。</p>]]></content>
<summary type="html">
<p>…<br>
</summary>
<category term="日记" scheme="/categories/%E6%97%A5%E8%AE%B0/"/>
</entry>
<entry>
<title>做事的方法论</title>
<link href="/2021/03/2021/03/%E5%81%9A%E4%BA%8B%E7%9A%84%E6%96%B9%E6%B3%95%E8%AE%BA/"/>
<id>/2021/03/2021/03/做事的方法论/</id>
<published>2021-03-09T16:00:00.000Z</published>
<updated>2021-03-10T09:36:28.082Z</updated>
<content type="html"><![CDATA[<p>为什么比怎么做重要得多,没有想明白做一件事的目的,就很难把事情做好,即便做成了也可能浪费了很多时间,甚至只是运气好。<br><a id="more"></a><br>开始做一件事情之前,列出有哪些步骤,这是一般的做法。但这只是表面,因为这种情况下,能想到的步骤,大概率是模仿,或者是说抄袭别人的。不能否定模仿和抄袭的意义,因为别人这么做肯定有他的原因,别人肯定也是权衡过利弊的,但是未必我们和别人的目的不一样、现有的资源也不一样,直接照搬属实是愚蠢。</p><p>即便不是照搬,直接列出各个步骤也不是最好的方案。因为我们最终要解决的问题都没弄明白,思考得越多可能越偏离我们的目标。</p><p>啊,这个道理实在是简单。那为什么我之前没有这么做呢?</p><p>可能我们的大脑就不喜欢思考,而更喜欢看到成果,即使所谓的成果最后会变成废品。</p><p>回想去年做的那么多外包,包括今年,都可以作为反面教材:把项目看成是一个个功能,所谓做项目就是开发这些功能。结果给客户看的时候,发现人家要的不是这个样子的,又或者有些对客户很重要的功能没有开发,一来一回浪费了很多时间和精力,做了很多无用功。以前觉得是原型的问题,没有一开始让客户看到软件的样子,没有一开始跟客户确定好。但是我现在觉得不是这个问题,首先原型图不能画到非常完整,很多细节只有到开发的时候才能想到,其次,可能客户一开始也不知道自己原来需要 XX 功能。身为技术服务团队,也可以叫做外包,但不管叫什么,都应该替客户着想,先听取客户的需求,然后分析客户的需求,不合理的争取去掉,有必要但没有提的建议加上去。最终目的不是实现客户的需求然后拿钱,而是挖掘客户的需求、优化客户的工作流,为客户提供最好的解决方案。</p><p>不过说得简单,做起来不容易,而且即便真这么做了,也要做好心里准备,毕竟这是必要条件,而不是充分条件,事情还是可能搞砸。</p><p>思考之后的结果,也是分成很多个步骤,不过跟一开始列出的步骤肯定不一样。这个时候就一步步实施这些步骤,如果实施过程中有新的思考,也可以对计划进行优化。</p><p>另外,光思考远远不够,我们还需要往脑子里装入新的东西、新的概念,来帮助我们思考出更好的结果。</p>]]></content>
<summary type="html">
<p>为什么比怎么做重要得多,没有想明白做一件事的目的,就很难把事情做好,即便做成了也可能浪费了很多时间,甚至只是运气好。<br>
</summary>
<category term="工作" scheme="/categories/%E5%B7%A5%E4%BD%9C/"/>
</entry>
<entry>
<title>不要为自己的作品感到丢脸</title>
<link href="/2021/01/2021/isb/"/>
<id>/2021/01/2021/isb/</id>
<published>2021-01-11T16:00:00.000Z</published>
<updated>2021-01-11T18:24:15.443Z</updated>
<content type="html"><![CDATA[<p>凡是自己做出来的东西,都关系着自己的脸面。<br><a id="more"></a><br>对于一些事情,我可以不在乎脸面,比如说我游戏打得菜,说我又穷又丑,这些都无所谓。可是对于一些事情,我不得不在意,因为我就是靠这些事情吃饭的,如果这些事情都做不好,那么可以从楼上跳下去了。</p><p>喷一下自己:</p><p>你写的什么 jb 定时任务,能把服务器 CPU 跑满?如果这是一台很重要的服务器,并且有很多人正在用,那怎么办呢,重启服务器?你怎么不把你自己重启一下?上线服务之前不会用脑子想想会不会有什么影响吗?不知道定时任务运行的时候先判断一下上一个进程是否还在运行吗?定时任务处理失败的时候,不知道告警通知吗?一天天的一点小事都处理不好,以后那什么去应付稍微大一些的项目?</p><p>测试服务器和正式服务器理解不了吗?正式环境部署到测试服务器上面,脑子里面装的都是狗屎吗?这是一个有工作经验的人应该做出来的事情吗?</p><p>是得有多傻逼,才有把数据库删了那么多次,虽然是本地的数据库,可是这种事情为什么会发生那么多次呢,难道做事情的时候不知道自己在干嘛吗?想过那么多次定时备份数据库,找到解决方案了吗?真的脑残,还做个屁的开发。</p><p>总是看到别人做得不好的地方,为什么不审视一下自己呢?做项目难道真的就是功能跑通就可以了吗,难道你就这点追求吗。用户体验不用管了是吗,产品的逻辑存在问题看不到吗?问题留着留着自己就消失了吗,那么多问题为什么不能理清楚,然后花时间去解决呢。总说做得差不多了,确实可以跑完现有的流程,可是距离真实使用还有很长的一段距离,为什么不想方设法把问题解决呢?产品不仅仅是一个软件,它属于客户,面向用户,关系着公司的形象,同时也是每一个开发人员能力的体现。身为开发这个产品的一员,有责任去思考如何把产品做得更好。如果对公司不认可,完全可以离开,但是身在其中,就应该花心思做好每一个经手的产品,直到自己满意,直到自己觉得无可挑剔。</p><p>为什么你说话总是那么没底气,产品明明是你在做,为什么当别人问起的时候,你是如此的不自信,甚至背后的逻辑都说不明白。你说你忘了,但是这不应该出现。简单的逻辑你不会忘,即使忘了你想一下就知道,甚至别人都不用问你。复杂的逻辑你记不住,很可能是因为这只是你当时想出来的一个解决方案,为了满足需求,没有思考总结和归纳,导致你也不知道为什么这么做,也不知道有没有更好的方式去实现,更没有思考这样的实现是否存在潜在的问题,更不用说总结经验为下一次做准备了。</p><p>时间并没有想象中那么稀缺,可能你确实有点辛苦,但是很多辛苦是可以避免的,很多辛苦其实是在弥补之前自己没有选择正确的方式(甚至没有思考什么是正确的方式)。</p><p>多思考厉害的人会怎么做,多思考在不同情况下该如何应对。</p><p>不需要别人的认可,如果认为别人说得不对完全可以不听,但是凡事要先过自己这一关。</p>]]></content>
<summary type="html">
<p>凡是自己做出来的东西,都关系着自己的脸面。<br>
</summary>
<category term="工作" scheme="/categories/%E5%B7%A5%E4%BD%9C/"/>
</entry>
<entry>
<title>一个工作习惯</title>
<link href="/2020/12/2020/%E4%B8%80%E4%B8%AA%E5%B7%A5%E4%BD%9C%E4%B9%A0%E6%83%AF/"/>
<id>/2020/12/2020/一个工作习惯/</id>
<published>2020-12-10T16:00:00.000Z</published>
<updated>2020-12-10T17:42:48.884Z</updated>
<content type="html"><![CDATA[<p>突然觉得自己工作处于一种浑浑噩噩的状态。</p><a id="more"></a><p>虽然一直在做项目,也多多少少有一些进度,但是没有给自己制定计划,没有明确自己在某个时间点应该完成到什么程度。</p><p>也不是说这种状态就完全是错的。如果我只考虑当前涉及到的业务,把这一部分实现之后再去考虑其他部分,那这样最终也可以完成任务。</p><p>我现在觉得这种状态是错的,是因为我深刻体会到了这么做背后的痛苦。我们是根据业务的需求去开发,可以说业务需求决定了我们如何设计这个项目。比如 A 需求,通过方案一可以很好地实现,但是后面发现 A 需求跟 B 模块有关联,现有的方案无法优雅地实现。所以现在算是什么情况呢?现在是需求没变,只是发现了之前遗漏掉的一些关联,导致项目部分代码需要重构。项目都没有做完,就要把一部分代码重构,而且这部分代码没有问题,只是无法满足需求。这实在是一件可笑且可悲的事情。</p><p>项目需要重构很正常,但是还没有做完就要重构,那么一定是哪里出了问题。</p><p>我们应该在开发之前梳理业务的流程,在梳理的时候应该能够用自己的话说出来,这里的说主要是为了检查自己能否将这个功能进行抽象。进行抽象的好处是让自己能够以更高的视角看待项目,让业务流程看起来更加清晰,本质上就是化繁为简。同样的功能,可能有很复杂的实现,也可能有很简单的实现(注意我这里说的是“可能”而非“可以”)。</p><p>对于一项不熟悉的任务,很难一开始就给出合适的解决方案,甚至开始时都无法判断一个方案是否可行。如果说犯错在所难免,那么我们应该尽早的将错误暴露出来:模拟使用某个方案,深入体会该方案是否足够简单,是否完全满足需求。这件事并不简单,因为凭空想象很难,深入到每一个细节也是需要花很多时间的。但是在脑海中模拟完整的业务流程是很有价值的,因为这样做可以最小化试错成本(除非自己对于业务非常熟悉,有过这部分的经验)。</p><p>胡说八道了那么多,标题所指的工作习惯究竟是什么呢?其实就是在做一些没有完全把握的功能时,要学会去抽象这个功能,要完整地梳理完业务中的每一个流程,思考它们之间的关系,提出业务中的不合理性,最终给出合理的解决方案。(让一个开发去做这些事情,实在是过分。此外,更过分的是客户的需求可能会发生改变,意味着很多付出都白费掉了,不过解决方法很简单:加钱)</p><p>明确自己的任务,将思考和执行分开:前期光是思考,一行代码都不要写。后期光是执行,按照计划实现就好。当任务明确之后,就可以评估任务完成的时间,让自己有目标,也看得到自己完成了哪些任务,而不至于浑浑噩噩不知道要做什么,也不知道做了什么。</p>]]></content>
<summary type="html">
<p>突然觉得自己工作处于一种浑浑噩噩的状态。</p>
</summary>
<category term="工作" scheme="/categories/%E5%B7%A5%E4%BD%9C/"/>
</entry>
<entry>
<title>十一月的第一天</title>
<link href="/2020/11/2020/%E5%8D%81%E4%B8%80%E6%9C%88%E7%9A%84%E7%AC%AC%E4%B8%80%E5%A4%A9/"/>
<id>/2020/11/2020/十一月的第一天/</id>
<published>2020-10-31T16:00:00.000Z</published>
<updated>2020-11-01T16:08:42.428Z</updated>
<content type="html"><![CDATA[<p>不知不觉已经一年多没有写过博客了,换一个说法:自从出来工作以后,就没有再写过博客了。</p><a id="more"></a><p>时间过得真快,不知不觉 2020 年都快过去了。公司今年从大学城搬到科韵路,我也从穗石村搬到了岗元新村,一眨眼已经 7 个月了。</p><p>今天是周日,我完全有时间也有兴趣写代码,我可以学如何写一个 composer 包、npm 包,也可以继续学习 Go 的协程,也可以研究 Laravel + Vue 的管理后台的权限控制。</p><p>不过,我并没有写代码,而是选择了打游戏。</p><p>因为我觉得自己需要脱离一下工作的状态,我有一种感觉:我在做自己喜欢的事情,但是是以一种我不喜欢的方式在做。之所以会有这种感觉,可能是这一周的工作太赶了。另一方面,觉得这么赶其实意义没什么意义。</p><p>我需要完成的工作还有很多,这些工作实际上都已经延期了,而且我还不确定什么时候可以完成。而这一周,精力都放在另一个我看来没那么重要的项目上面了。赶进度的结果就是留了很多坑要填。</p><p>回头看看自己这几个月的工作,我不知道如何形容。如果只用一个词来描述的话,我只想说两个字:垃圾。表面上看起来我是三个项目一起在做,可是实际上是一个都没有做好。</p><p>究其原因,一个很大的因素是:在前端花掉了太多的时间。我跟同事说过:我有三分之一的时间在写服务端,有三分之一的时间在写管理后台,还有三分之一的时间在想业务的流程该是什么样子的。一开始以为三个项目都挺简单的,习惯性一边写接口一边写管理端,直至业务的流程变了两三次,也没有想到要兼顾三个项目的进度,没有想到要把一部分的工作交给同事去做。导致了同事有时间,但是没有接口去调。项目延期跟我有直接关系,但我仍然觉得根本原因在于整个项目的把控。如果业务流程一开始足够清晰,不需要在开发阶段就调整两三次,不需要我写到的时候再去想、再去问,能节约一部分时间。如果业务流程足够清晰,原型图足够完成,那么设计师和前端也可以一开始就完成前端界面的设计,而不是等到后面才意识到:这里还少一个界面。</p><p>另一个重要因素是我没有规划,这一点在上面也提到了。正确的做法应该是,在正式写代码之前,把要做的事情全部列出来。至少要把某一个部分的细节全部列出来,从数据结构,到数据的新建、数据的修改,数据的查询和筛选,以及数据之间的关联。因为它们之间可能会相互的影响,后者可能会影响前者的设计,如果一开始没有考虑周到,就可能刚开始可能就会做无用功。</p><p>以前我都是只关注某一个点,没有全局的规划。导致后面才发现原来的逻辑跑不通,这个时候才去问,如果可以早点思考,就能减少一些这样的情况。另一方面,可以给自己定目标,当时间不足时,可以忽略一些不重要的东西,把精力放在主流程上面,而不是在某一个小点上浪费过多的时间。</p><p>不早了,到睡觉的时间了,睡眠是最重要的。</p>]]></content>
<summary type="html">
<p>不知不觉已经一年多没有写过博客了,换一个说法:自从出来工作以后,就没有再写过博客了。</p>
</summary>
<category term="生活" scheme="/categories/%E7%94%9F%E6%B4%BB/"/>
</entry>
<entry>
<title>奇葩问题:IDEA 中正确运行,命令行运行就出错</title>
<link href="/2019/07/articles/bug%20-%20IDEA%20%E4%B8%AD%E6%AD%A3%E7%A1%AE%E8%BF%90%E8%A1%8C%EF%BC%8C%E5%91%BD%E4%BB%A4%E8%A1%8C%E8%BF%90%E8%A1%8C%E5%87%BA%E9%94%99/"/>
<id>/2019/07/articles/bug - IDEA 中正确运行,命令行运行出错/</id>
<published>2019-07-28T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.932Z</updated>
<content type="html"><![CDATA[<p>同一个世界,同一份代码,不同的结果。<br><a id="more"></a></p><h1 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h1><p>简单来说,就是一个项目在 IDEA 中可以正常运行,打成 jar 包之后,通过 <code>java -jar</code> 在命令行运行就出错。</p><p>具体来说:</p><p>这是一个 Spring Boot 项目,在 service 层发出一个 HTTP 请求。</p><p>在 IDEA 运行的时候,能得到正确的 json 数据,在命令行中就只得到“未知错误”的提示。</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2019-07-29_17-28-18.png" alt></p><h1 id="解决过程"><a href="#解决过程" class="headerlink" title="解决过程"></a>解决过程</h1><h2 id="HTTP-request"><a href="#HTTP-request" class="headerlink" title="HTTP request"></a>HTTP request</h2><p>既然是 HTTP 的 response 不同,首先想到的是比较一下两处的 request 有何不同。</p><p><em>查看 okhttp 中请求主体的方法:</em></p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> String <span class="title">bodyToString</span><span class="params">(<span class="keyword">final</span> Request request)</span></span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">final</span> Request copy = request.newBuilder().build();</span><br><span class="line"> <span class="keyword">final</span> Buffer buffer = <span class="keyword">new</span> Buffer();</span><br><span class="line"> copy.body().writeTo(buffer);</span><br><span class="line"> <span class="keyword">return</span> buffer.readUtf8();</span><br><span class="line"> } <span class="keyword">catch</span> (<span class="keyword">final</span> IOException e) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"did not work"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>然而,两种方式发出的 HTTP request 好像都很正常,除去一些会变化的字符串外,请求主体一模一样。(这里<strong>会变化的字符串</strong>指的是时间戳、MD5 加密得到的字符串等,它们每次运行都是不一样的值)</p><p>此时应该将字符串写死,再对比两者的不同。</p><p>但是因为改起来太麻烦,加上以前的经验,我选择对请求主体中的字符进行 URL 编码,事实证明这是一个愚蠢的行为,它导致了在 IDEA 中也得不到想要的结果。</p><p>第一次尝试宣告失败。</p><h2 id="为-okhttp-设置代理"><a href="#为-okhttp-设置代理" class="headerlink" title="为 okhttp 设置代理"></a>为 okhttp 设置代理</h2><p>使用下面的方式创建 OkHttpClient 就能在 Fidder 中捕获到 okhttp 发送和接收的数据了。</p><figure class="highlight java"><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">String hostname = <span class="string">"localhost"</span><span class="comment">/*127.0.0.1*/</span>;</span><br><span class="line"><span class="keyword">int</span> port = <span class="number">8888</span>;</span><br><span class="line">System.out.println(<span class="string">"设置代理"</span>);</span><br><span class="line">Proxy proxy = <span class="keyword">new</span> Proxy(Proxy.Type.HTTP,</span><br><span class="line"><span class="keyword">new</span> InetSocketAddress(hostname, port));</span><br><span class="line"></span><br><span class="line"><span class="keyword">this</span>.client = <span class="keyword">new</span> OkHttpClient().newBuilder().proxy(proxy).build();</span><br></pre></td></tr></table></figure><p>这里的思路是:不单单对比请求主体,而是通过 Fidder 更细致地比较两次 HTTP 请求的区别。</p><p>确实可以捕获到程序发出的 HTTP 请求,但是跟刚才一样,除去一些会变化的值,两者几乎是一样的。</p><p>第二次尝试也没有发现有用的信息。</p><h2 id="MD5"><a href="#MD5" class="headerlink" title="MD5"></a>MD5</h2><p>还是回到最初的疑惑:明明是一样的代码,而且是同一台电脑上,为什么得到不一样的结果?</p><p>同样的代码,难道会计算出不一样的 Hash Value ?</p><p><strong>是的。</strong></p><p>可能是直觉,也可能是实在没有思路了,所以猜测是 sign 字段(通过 MD5 算法生成)的问题。</p><p>很快验证出的确是 sign 字段有问题,但是怎么解决呢?</p><p>因为不知道在命令行运行时怎么 debug,所以一切都变得很麻烦。</p><p>经过慢慢的试验,一步步打印出来,最后发现进行摘要的字符串其实是一样的,但是得到的结果却不一样。</p><p>很明显是摘要算法有问题。</p><p>这个方法是我在网上复制的,难道它在命令行中执行会得到不一样的结果?</p><p>我又在网上搜了其他的 MD5 代码,但是还是一样出错。(如果此时运行对了,可能我永远都不会知道问题真正的原因了)。</p><p>最终用我的工地英语在谷歌搜索:<code>java cmd md5 digest difference</code>,然后看到<a href="https://stackoverflow.com/questions/6928641/will-java-messagedigest-generated-different-md5-hash-on-different-jdk-version" target="_blank" rel="noopener">这篇回答</a>,才知道因为 MD5 算法中,要将字符串转换成 byte[],而 IDEA 和命令行的编码不同,导致得到的 byte[] 不同,进而导致 sign 不同。</p><p><em>在计算 Hash Value 的时候指定编码。</em></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">byte</span>[] array = md.digest(str.getBytes(<span class="string">"UTF-8"</span>));</span><br></pre></td></tr></table></figure><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>虽然解决这个问题只需要改一行代码,但是整个过程却花了我很多时间,做了太多太多无谓的尝试。</p><p>不过还好,还是解决了。</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/psb.webp" alt></p>]]></content>
<summary type="html">
<p>同一个世界,同一份代码,不同的结果。<br>
</summary>
<category term="Java" scheme="/categories/Java/"/>
<category term="java" scheme="/tags/java/"/>
<category term="bug" scheme="/tags/bug/"/>
</entry>
<entry>
<title>对 Java 中流的理解</title>
<link href="/2019/07/articles/%E5%AF%B9%20Java%20%E4%B8%AD%E6%B5%81%E7%9A%84%E7%90%86%E8%A7%A3/"/>
<id>/2019/07/articles/对 Java 中流的理解/</id>
<published>2019-07-16T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.935Z</updated>
<content type="html"><![CDATA[<p>通过表达整理自己的思路,但不一定正确。<br><a id="more"></a></p><p>以前学习 Java 中文件和流的时候,理解不深,当时又觉得很少用 Java 操作文件,所以就没有好好看,导致对于“文件”和“流”这两个概念都分不清。</p><p>印象中只记得有好多个类,记不得有多少个,更分不清各自有什么用,结果现在看不懂别人的代码了,所以再学习一下,争取能看懂。</p><h1 id="文件和流"><a href="#文件和流" class="headerlink" title="文件和流"></a>文件和流</h1><p>Java 提供了文件相关的类,和流相关的类,以前感觉都差不多。实际上前者主要是操作文件(比如删除、复制等),而不是进入文件中读取文件的数据。而后者是读写文件中的内容。</p><p>假设有一个 a.txt 文件,与文件相关的类,可以将它删除、改名。而与流相关的类,可以读取 a.txt 里面的内容,或者修改 a.txt 里面的内容。</p><p>上面是 Java 中类的区别,那么“文件”和“流”这两个名词各自是什么意思呢?</p><p>文件就是电脑里存在的文件:文本文件、图片文件、视频文件等等。</p><p>至于流,真的不好理解,网上有些说对数据的读、写是流,有的说文件就是流,以前认为流是内存和数据之间的通道。整半天没搞懂,迫于找不到通俗易懂的解释,所以根据网上的理解,自己瞎猜。</p><p>从实际应用的角度看,程序可能需要从外部读取数据,比如从硬盘中读取数据、从网络中获取数据。这些操作类似,不如将它们抽象化,用一个类表示,这也刚好符合面向对象的思想。</p><p>看到这里,我想说的是,不要单独去理解什么是流。(忘掉流吧,我偷电瓶养你)</p><p>直接从 InputStream 开始理解,它是一个抽象类,既然是类就应该可以用来表示某一类事物(就像 Person 类可以表示人一样)。所以 InputStream 就可以看成是<strong>所有可以读取到数据的东西</strong>。不过是硬盘,还是键盘,只要我可以从你那里读取到数据,你就是 InputStream(输入流)。</p><p>OutputStream 也是同样的道理,我往硬盘写数据的时候,硬盘就是 OutputStream(输出流)。</p><p>理解的前提是忘掉“流”,“流”只不过是类名里的最后一个字,如果设计者喜欢,叫做 OutputBlock 又有何不可呢?其次是牢记在 Java 中类是为了表示一类事物,InputStream 和 OutputStream 也不例外。</p><h1 id="常见的类及其描述"><a href="#常见的类及其描述" class="headerlink" title="常见的类及其描述"></a>常见的类及其描述</h1><h2 id="Some-important-Byte-stream-classes"><a href="#Some-important-Byte-stream-classes" class="headerlink" title="Some important Byte stream classes."></a>Some important Byte stream classes.</h2><table><thead><tr><th>Stream class</th><th>Description</th></tr></thead><tbody><tr><td><strong>BufferedInputStream</strong></td><td>Used for Buffered Input Stream.</td></tr><tr><td><strong>BufferedOutputStream</strong></td><td>Used for Buffered Output Stream.</td></tr><tr><td><strong>DataInputStream</strong></td><td>Contains method for reading java standard datatype</td></tr><tr><td><strong>DataOutputStream</strong></td><td>An output stream that contain method for writing java standard data type</td></tr><tr><td><strong>FileInputStream</strong></td><td>Input stream that reads from a file</td></tr><tr><td><strong>FileOutputStream</strong></td><td>Output stream that write to a file.</td></tr><tr><td><strong>InputStream</strong></td><td>Abstract class that describe stream input.</td></tr><tr><td><strong>OutputStream</strong></td><td>Abstract class that describe stream output.</td></tr><tr><td><strong>PrintStream</strong></td><td>Output Stream that contain <code>print()</code> and <code>println()</code> method</td></tr></tbody></table><h2 id="Some-important-Charcter-stream-classes"><a href="#Some-important-Charcter-stream-classes" class="headerlink" title="Some important Charcter stream classes."></a>Some important Charcter stream classes.</h2><table><thead><tr><th>Stream class</th><th>Description</th></tr></thead><tbody><tr><td><strong>BufferedReader</strong></td><td>Handles buffered input stream.</td></tr><tr><td><strong>BufferedWriter</strong></td><td>Handles buffered output stream.</td></tr><tr><td><strong>FileReader</strong></td><td>Input stream that reads from file.</td></tr><tr><td><strong>FileWriter</strong></td><td>Output stream that writes to file.</td></tr><tr><td><strong>InputStreamReader</strong></td><td>Input stream that translate byte to character</td></tr><tr><td><strong>OutputStreamReader</strong></td><td>Output stream that translate character to byte.</td></tr><tr><td><strong>PrintWriter</strong></td><td>Output Stream that contain <code>print()</code> and <code>println()</code> method.</td></tr><tr><td><strong>Reader</strong></td><td>Abstract class that define character stream input</td></tr><tr><td><strong>Writer</strong></td><td>Abstract class that define character stream output</td></tr></tbody></table><p>具体的类就不研究怎么用了,估计使用得最多的就是 Bufferedxxx 了。</p><h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><p>下面这段代码的意思是:</p><ol><li>获取到字节输入流</li><li>将字节输入流转换成字符输入流</li><li>再转换成缓冲字符输入流</li><li>然后在逐行读取内容</li></ol><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line">InputStream inputStream = request.getInputStream();</span><br><span class="line"></span><br><span class="line"><span class="comment">//BufferedReader是包装设计模式,性能更高</span></span><br><span class="line">BufferedReader in = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> InputStreamReader(inputStream,<span class="string">"UTF-8"</span>));</span><br><span class="line">StringBuffer sb = <span class="keyword">new</span> StringBuffer();</span><br><span class="line">String line ;</span><br><span class="line"><span class="keyword">while</span> ((line = in.readLine()) != <span class="keyword">null</span>){</span><br><span class="line"> sb.append(line);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>创建一个 BufferedReader 之前还要先创建一个 InputStreamReader,这看起来很麻烦,为什么不直接创建缓冲字符输入流呢?</p><p>首先,因为要从不同的设备中读取数据,所以需要设计多个类,而每个类都可能需要用到缓冲这个功能,如果再为每个类设计一个具有缓冲功能的类,那么类的数目将会翻一倍。</p><p>所以 BufferedReader 被设计为:接收一个字符输入流,并具有缓冲的功能,虽然使用上麻烦了一点,但是还是可以接受的,不然更多的类需要去记。</p>]]></content>
<summary type="html">
<p>通过表达整理自己的思路,但不一定正确。<br>
</summary>
<category term="Java" scheme="/categories/Java/"/>
</entry>
<entry>
<title>Linux 安装 nginx</title>
<link href="/2019/05/articles/Linux%20%E5%AE%89%E8%A3%85%20nginx/"/>
<id>/2019/05/articles/Linux 安装 nginx/</id>
<published>2019-05-13T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.927Z</updated>
<content type="html"><![CDATA[<p>记录在 Linux 安装 nginx 的过程。</p><a id="more"></a><h1 id="下载"><a href="#下载" class="headerlink" title="下载"></a>下载</h1><p><a href="http://nginx.org/en/download.html" target="_blank" rel="noopener">下载地址</a></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget http://nginx.org/download/nginx-1.16.0.tar.gz</span><br></pre></td></tr></table></figure><h1 id="解压"><a href="#解压" class="headerlink" title="解压"></a>解压</h1><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar -zvxf nginx-xxx.tar.gz</span><br></pre></td></tr></table></figure><h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./configure</span><br></pre></td></tr></table></figure><h1 id="可能需要安装的库"><a href="#可能需要安装的库" class="headerlink" title="可能需要安装的库"></a>可能需要安装的库</h1><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install -y httpd-devel pcre perl pcre-devel zlib zlib-devel GeoIP GeoIP-devel</span><br></pre></td></tr></table></figure><h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make install</span><br></pre></td></tr></table></figure><h1 id="启动"><a href="#启动" class="headerlink" title="启动"></a>启动</h1><figure class="highlight shell"><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">cd /usr/local/nginx/sbin</span><br><span class="line">./nginx</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>记录在 Linux 安装 nginx 的过程。</p>
</summary>
<category term="nginx" scheme="/categories/nginx/"/>
</entry>
<entry>
<title>Bootstrap4 Dropdown 组件扩展 hover 事件</title>
<link href="/2019/05/articles/Bootstrap%20Dropdown%20%E4%BF%AE%E6%94%B9%E8%A7%A6%E5%8F%91%E4%BA%8B%E4%BB%B6/"/>
<id>/2019/05/articles/Bootstrap Dropdown 修改触发事件/</id>
<published>2019-05-10T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.921Z</updated>
<content type="html"><![CDATA[<p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/19051201.gif" alt></p><a id="more"></a><p>效果如图所示,很简单的一个功能,但是因为我在这上面花了很多时间,所以我决定把它记录下来。</p><h1 id="官方文档"><a href="#官方文档" class="headerlink" title="官方文档"></a>官方文档</h1><p><a href="https://getbootstrap.com/docs/4.0/components/dropdowns/" target="_blank" rel="noopener">Dropdowns · Bootstrap </a></p><h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><p>Bootstrap 提供的下拉菜单默认是通过鼠标点击触发,下面是一个简单的完整示例。</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/2019051201.gif" alt></p><figure class="highlight html"><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"><span class="meta"><!DOCTYPE html></span></span><br><span class="line"><span class="tag"><<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1.0"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">"X-UA-Compatible"</span> <span class="attr">content</span>=<span class="string">"ie=edge"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>Document<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"</span> <span class="attr">integrity</span>=<span class="string">"sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">crossorigin</span>=<span class="string">"anonymous"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"container"</span>></span></span><br><span class="line"> <span class="comment"><!-- Default dropright button --></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"btn-group dropright"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">button</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">class</span>=<span class="string">"btn btn-secondary dropdown-toggle"</span> <span class="attr">data-toggle</span>=<span class="string">"dropdown"</span> <span class="attr">aria-haspopup</span>=<span class="string">"true"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">aria-expanded</span>=<span class="string">"false"</span>></span></span><br><span class="line"> Dropright</span><br><span class="line"> <span class="tag"></<span class="name">button</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"dropdown-menu"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Action<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Another action<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Something else here<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"dropdown-divider"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Separated link<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://code.jquery.com/jquery-3.2.1.slim.min.js"</span> <span class="attr">integrity</span>=<span class="string">"sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">crossorigin</span>=<span class="string">"anonymous"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"</span> <span class="attr">integrity</span>=<span class="string">"sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">crossorigin</span>=<span class="string">"anonymous"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"</span> <span class="attr">integrity</span>=<span class="string">"sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">crossorigin</span>=<span class="string">"anonymous"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure><h1 id="扩展-hover-事件"><a href="#扩展-hover-事件" class="headerlink" title="扩展 hover 事件"></a>扩展 hover 事件</h1><p>有时候希望鼠标放上去就展开菜单,而不需要鼠标点击,只需要一点简单的代码就可以实现:</p><figure class="highlight html"><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 class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="undefined"> .dropdown-menu {</span></span><br><span class="line"><span class="undefined"> margin:0 !important;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> .dropright:hover > .dropdown-menu {</span></span><br><span class="line"><span class="undefined"> display:block;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"></span><span class="tag"></<span class="name">style</span>></span></span><br></pre></td></tr></table></figure><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/19051202.gif" alt></p><p>为什么加上这几句就行了呢?因为 <code>dropdown-menu</code> 类的原来的样式是 <code>display:none;</code>,所以设置 <code>display:block;</code> 之后 <code>dropdown-menu</code> 就会显示出来了。</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2019-05-12_12-07-15.png" alt></p><h1 id="问题一"><a href="#问题一" class="headerlink" title="问题一"></a>问题一</h1><p>当鼠标放上去时没有问题,但是如果鼠标点击之后就会<strong>出现问题</strong>。首先是位置,下拉菜单的位置改变了,其次是鼠标移走之后下拉菜单也不会自动关闭。</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/19051203.gif" alt></p><h1 id="问题一的解决方法"><a href="#问题一的解决方法" class="headerlink" title="问题一的解决方法"></a>问题一的解决方法</h1><p>删掉 <code>button</code> 标签的 <code>data-toggle="dropdown"</code>,这个方法看起来一点也不优雅,但是目前只能想到这个。</p><h1 id="问题二"><a href="#问题二" class="headerlink" title="问题二"></a>问题二</h1><p>本来下拉菜单是在右侧显示的,但是现在却是在下面显示。</p><h1 id="问题二的解决方法"><a href="#问题二的解决方法" class="headerlink" title="问题二的解决方法"></a>问题二的解决方法</h1><p>在 <code><style></code> 标签中添加:</p><figure class="highlight css"><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 class="selector-class">.dropright</span> {</span><br><span class="line"> <span class="attribute">position</span>: relative;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.dropdown-menu</span> {</span><br><span class="line"> <span class="attribute">position</span>: absolute;</span><br><span class="line"> <span class="attribute">left</span>: <span class="number">100%</span>;</span><br><span class="line"> <span class="attribute">top</span>: <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>一开始我就搜到了解决办法,但是由于我太蠢了,看都不看直接复制,导致一直得不到想要的效果(根本原因是:别人的 HTML 代码跟官方示例不一样,所以直接复制过来自然没效果)。</p><p>后来找到了另一种方法,然后那个方法也有很大的缺陷:鼠标移走时下拉菜单不会关闭。尽管最后也解决了这个问题,但是效果并不好,而且有时还有 bug。</p><p>直到昨晚一点多终于搞明白了,一方面觉得自己真是蠢,抄代码都能抄歪来,另一方面没人分享自己的喜悦,所以有了这篇文章。</p><p>欢迎批评指点,如果对你有帮助那就更好了。</p><h1 id="完整代码"><a href="#完整代码" class="headerlink" title="完整代码"></a>完整代码</h1><figure class="highlight html"><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></pre></td><td class="code"><pre><span class="line"><span class="meta"><!DOCTYPE html></span></span><br><span class="line"><span class="tag"><<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1.0"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">"X-UA-Compatible"</span> <span class="attr">content</span>=<span class="string">"ie=edge"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>Document<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">link</span> <span class="attr">rel</span>=<span class="string">"stylesheet"</span> <span class="attr">href</span>=<span class="string">"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"</span> <span class="attr">integrity</span>=<span class="string">"sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">crossorigin</span>=<span class="string">"anonymous"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="css"> <span class="selector-class">.dropdown-menu</span> {</span></span><br><span class="line"><span class="css"> <span class="selector-tag">margin</span><span class="selector-pseudo">:0</span> !<span class="selector-tag">important</span>;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="css"> <span class="selector-class">.dropright</span><span class="selector-pseudo">:hover</span> > <span class="selector-class">.dropdown-menu</span> {</span></span><br><span class="line"><span class="css"> <span class="selector-tag">display</span><span class="selector-pseudo">:block</span>;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="css"> <span class="selector-class">.dropright</span> {</span></span><br><span class="line"><span class="undefined"> position: relative;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="css"> <span class="selector-class">.dropdown-menu</span> {</span></span><br><span class="line"><span class="undefined"> position: absolute;</span></span><br><span class="line"><span class="undefined"> left: 100%;</span></span><br><span class="line"><span class="undefined"> top: 0;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> </span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"container"</span>></span></span><br><span class="line"> <span class="comment"><!-- Default dropright button --></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"btn-group dropright"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">button</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">class</span>=<span class="string">"btn btn-secondary dropdown-toggle"</span> <span class="attr">aria-haspopup</span>=<span class="string">"true"</span> <span class="attr">aria-expanded</span>=<span class="string">"false"</span>></span></span><br><span class="line"> Dropright</span><br><span class="line"> <span class="tag"></<span class="name">button</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"dropdown-menu"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Action<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Another action<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Something else here<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"dropdown-divider"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Separated link<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">br</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"btn-group dropright"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">button</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">class</span>=<span class="string">"btn btn-secondary dropdown-toggle"</span> <span class="attr">aria-haspopup</span>=<span class="string">"true"</span> <span class="attr">aria-expanded</span>=<span class="string">"false"</span>></span></span><br><span class="line"> Dropright</span><br><span class="line"> <span class="tag"></<span class="name">button</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"dropdown-menu"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Action<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Another action<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Something else here<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"dropdown-divider"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Separated link<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">br</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"btn-group dropright"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">button</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">class</span>=<span class="string">"btn btn-secondary dropdown-toggle"</span> <span class="attr">aria-haspopup</span>=<span class="string">"true"</span> <span class="attr">aria-expanded</span>=<span class="string">"false"</span>></span></span><br><span class="line"> Dropright</span><br><span class="line"> <span class="tag"></<span class="name">button</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"dropdown-menu"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Action<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Another action<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Something else here<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"dropdown-divider"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"dropdown-item"</span> <span class="attr">href</span>=<span class="string">"#"</span>></span>Separated link<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://code.jquery.com/jquery-3.2.1.slim.min.js"</span> <span class="attr">integrity</span>=<span class="string">"sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">crossorigin</span>=<span class="string">"anonymous"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"</span> <span class="attr">integrity</span>=<span class="string">"sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">crossorigin</span>=<span class="string">"anonymous"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"</span> <span class="attr">integrity</span>=<span class="string">"sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">crossorigin</span>=<span class="string">"anonymous"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/19051201.gif" alt></p>
</summary>
<category term="前端" scheme="/categories/%E5%89%8D%E7%AB%AF/"/>
</entry>
<entry>
<title>Maven 聚合与继承</title>
<link href="/2019/02/articles/Maven%20%E8%81%9A%E5%90%88%E4%B8%8E%E7%BB%A7%E6%89%BF/"/>
<id>/2019/02/articles/Maven 聚合与继承/</id>
<published>2019-02-10T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.929Z</updated>
<content type="html"><![CDATA[<p>聚合是为了方便的构建多个项目,继承是为了简化 POM 的重复配置。</p><a id="more"></a><h1 id="聚合"><a href="#聚合" class="headerlink" title="聚合"></a>聚合</h1><p>一个实际的项目可能由多个“模块”组成,每个模块都是一个 Maven 项目。</p><p>这样就可能产生一个需求:同时构建多个 Maven 项目。此时如果进入到每个 Maven 项目的目录中,执行 mvn 命令进行构建就有点麻烦了。所以就有了“聚合”这个概念,聚合实际的作用就是同时构建多个 Maven 项目。</p><h1 id="聚合的步骤"><a href="#聚合的步骤" class="headerlink" title="聚合的步骤"></a>聚合的步骤</h1><p>要聚合模块其实很简单,就是创建一个 Maven 项目,然后在这个项目的 pom.xml 文件中声明要聚合的模块。</p><h2 id="目录结构"><a href="#目录结构" class="headerlink" title="目录结构"></a>目录结构</h2><p>举例,moduleB和 moduleC 是普通的模块,moduleA 是聚合模块,目录结构如下:</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2019-02-12_11-59-31.png" alt></p><p>需要注意的是:</p><ul><li>聚合模块下没有 src 目录,只有一个 pom.xml 文件。毕竟它只是起聚合模块的作用,不需要实际代码。</li><li>目录结构不一定是这样的,下面的 pom.xml 还可以配置聚合模块所在的目录。</li></ul><h2 id="moduleA-的-pom-xml"><a href="#moduleA-的-pom-xml" class="headerlink" title="moduleA 的 pom.xml"></a>moduleA 的 pom.xml</h2><p>注意点 :</p><ul><li>packaging 元素必须为 pom</li><li>建议填写 name 标签的内容,因为执行 mvn 命令时将会输出该标签下的内容。(如果没有写,将输出 artifactId)</li><li>modules 下的每个 module 标签对应一个模块。<strong>注意 module 标签中的是模块的相对路径,也就是对这个 pom.xml 的相对路径。</strong></li></ul><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><?xml version="1.0" encoding="UTF-8"?></span><br><span class="line"><span class="tag"><<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">modelVersion</span>></span>4.0.0<span class="tag"></<span class="name">modelVersion</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.test.modules<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>moduleC<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.0-SNAPSHOT<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">packaging</span>></span>pom<span class="tag"></<span class="name">packaging</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">name</span>></span>module A<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">modules</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">module</span>></span>../moduleA<span class="tag"></<span class="name">module</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">module</span>></span>../moduleB<span class="tag"></<span class="name">module</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">modules</span>></span></span><br><span class="line"> </span><br><span class="line"><span class="tag"></<span class="name">project</span>></span></span><br></pre></td></tr></table></figure><h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><p>在 moduleA 目录下执行 Maven 命令即可。</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2019-02-12_12-26-23.png" alt></p><h1 id="继承"><a href="#继承" class="headerlink" title="继承"></a>继承</h1><p>这里的继承指的是 pom.xml 的继承,因为多个 Maven 项目可能存在多个相同的配置,使用继承就可以减少一些配置。</p><p>怎么做呢?</p><p>简单来说就是创建一个 Maven 项目,它的 pom.xml 作为父POM,然后在其他项目中通过坐标引入这个父项目,这样子POM将会继承父POM的一些配置。</p><h2 id="举例"><a href="#举例" class="headerlink" title="举例"></a>举例</h2><p>聚合与继承不一样,但是不冲突,刚才的 moduleA 是聚合模块,同时 moduleA 的 pom.xml 也可以作为父POM。</p><p>使用了继承之后的 moduleB 的 pom.xml:</p><p>注意点:</p><ul><li>使用 parent 标签继承 moduleA</li><li>使用坐标定位 moduleA</li><li>relativePath 对应 moduleA 的相对目录<ul><li>默认值是 <code>../pom.xml</code></li><li>如果在这里的目录找不到,将会在本地仓库查找</li><li>最好写上 relativePath</li></ul></li><li>在 moduleB 的 pom.xml 中不用写 <code>groupId</code> 和 <code>artifactId</code>,因为会从 moduleA 的 pom.xml 中继承。<ul><li>如果和父POM不一样,也可以写上去。</li></ul></li></ul><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><?xml version="1.0" encoding="UTF-8"?></span><br><span class="line"><span class="tag"><<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">modelVersion</span>></span>4.0.0<span class="tag"></<span class="name">modelVersion</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>moduleB<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">parent</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.test.modules<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>moduleA<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.0-SNAPSHOT<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">relativePath</span>></span>../moduleA<span class="tag"></<span class="name">relativePath</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">parent</span>></span></span><br><span class="line"> </span><br><span class="line"><span class="tag"></<span class="name">project</span>></span></span><br></pre></td></tr></table></figure><h1 id="可以继承的-POM-元素"><a href="#可以继承的-POM-元素" class="headerlink" title="可以继承的 POM 元素"></a>可以继承的 POM 元素</h1><ul><li>groupId 项目组 ID</li><li>version 项目版本</li><li>description 项目的描述信息</li><li>organization 项目的组织信息</li><li>inceptionYear 项目的创始年份</li><li>url 项目的 URL 地址</li><li>developers 项目的开发者信息</li><li>contributors 项目的贡献者信息</li><li>distributionManagement 项目的部署配置</li><li>issueManagement 项目的缺陷跟踪系统信息</li><li>ciManagement 项目的持续集成系统信息</li><li>scm 项目的版本控制系统信息</li><li>mailingLists 项目的邮件列表信息</li><li>properties 自定义的 Maven 属性</li><li>dependencies 项目的依赖配置</li><li>dependencyManagement 项目的依赖管理配置</li><li>repositories 项目的仓库配置</li><li>build 项目源码目录配置、输出目录配置、插件配置、插件管理配置等</li><li>reporting 项目的报告输出目录配置、报告插件配置</li></ul><h1 id="依赖管理"><a href="#依赖管理" class="headerlink" title="依赖管理"></a>依赖管理</h1><p>上面说到 dependencies 是可以继承的,也就是说父POM中添加的依赖,子项目中也会引入。</p><p>这样一来有一些好处,不过也有一些不好的地方:如果某个子项目继承了这个父POM,但是这个子项目并不需要那么多的依赖,这样岂不是产生了不必要的引用?</p><p>dependencyManagement 的作用就体现出来了,在父POM中使用 dependencyManagement :</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependencyManagement</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="comment"><!-- 随意添加的一个依赖 --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.sonatype.aether<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>aether-parent<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.7<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependencies</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependencyManagement</span>></span></span><br></pre></td></tr></table></figure><p>现在的效果是:</p><ul><li>如果子项目中没有添加这个依赖,那么即使继承了父POM,子项目也不会引入这个依赖。</li></ul><p>看起来没什么卵用,因为在子项目中还是要手动的添加依赖,但实际上还是有用的。因为在子项目中添加依赖时,可以省略 <code>version</code>,在父POM中做统一的版本管理,需要修改版本时只需要修改父POM中的 <code>version</code>。</p><h1 id="使用-import"><a href="#使用-import" class="headerlink" title="使用 import"></a>使用 import</h1><p>import 也是依赖范围的一种,只不过在 dependencyManagement 中才有用。</p><p>实际作用是:把上面的 moduleA 中的 dependencyManagement 合并到当前的 POM 的 dependencyManagement 元素中。(当然也可以使用复制、继承的方式实现)</p><p>注意点:</p><ul><li>type 是 pom</li><li>scope 是 import</li></ul><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependencyManagement</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.test.modules<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>moduleA<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.0-SNAPSHOT<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">type</span>></span>pom<span class="tag"></<span class="name">type</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>import<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependencies</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependencyManagement</span>></span></span><br></pre></td></tr></table></figure><h1 id="插件管理"><a href="#插件管理" class="headerlink" title="插件管理"></a>插件管理</h1><p>插件管理与依赖管理类似,使用 pluginManagement 之后同样是按需引入。</p><p>插件的隐含信息:</p><ul><li>版本。核心插件已经配置了版本</li><li>内置绑定。插件已经绑定了生命周期的阶段</li></ul><figure class="highlight xml"><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"><span class="tag"><<span class="name">build</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">pluginManagement</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.maven.plugins<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>maven-compiler-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">source</span>></span>1.5<span class="tag"></<span class="name">source</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">target</span>></span>1.5<span class="tag"></<span class="name">target</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">pluginManagement</span>></span></span><br><span class="line"><span class="tag"></<span class="name">build</span>></span></span><br></pre></td></tr></table></figure><p>同样建议在父POM中统一管理插件的版本。</p><h1 id="超级POM"><a href="#超级POM" class="headerlink" title="超级POM"></a>超级POM</h1><p>超级POM类似于 Java 的 Object 类,是所有类的基类。</p><p>Maven 项目中的 pom.xml 还可以自定义源码目录,但是不建议这么做,最好是按照约定来开发。</p><p>现在只需要知道有超级POM的存在,并且所有 pom.xml 都继承自它,所以有很多配置不用我们自己书写,就可以直接使用。</p><h1 id="反应堆"><a href="#反应堆" class="headerlink" title="反应堆"></a>反应堆</h1><p>反应堆这个翻译有点难以理解,大概可以理解成:多个存在聚合关系的项目在构建时,Maven 需要解读构建的顺序,解读得到的结构顺序称为反应堆。</p><p>比如 moduleA 是聚合模块,moduleB、moduleC 是普通模块,同时这两个模块继承自 moduleD。</p><p>假设 moduleA 中模块的声明顺序是:</p><p>moduleB -> moduleC -> moduleD</p><p>在构建过程的,Maven 得到的反应堆是 moduleD -> moduleB -> moduleC。</p><p>这是因为从上往下构建,发现某个模块依赖于另一个模块,那么 Maven 将会先构建被依赖的模块,也就是这里的 moduleD。</p><p>另外,moduleC 也依赖于 moduleD,但是由于 moduleD 已经被构建,所以直接构建 moduleC。</p><h1 id="裁剪反应堆"><a href="#裁剪反应堆" class="headerlink" title="裁剪反应堆"></a>裁剪反应堆</h1><p>对于一个聚合项目,有时可能只需要构建一部分的模块,而不是完整的反应堆。</p><p>Maven 的命令行选项:</p><ul><li>-am,–also-make 同时构建所列模块的依赖模块</li><li>-amd,-also-make-dependents 同时构建依赖于所列模块的模块(谁依赖我,就构建谁)</li><li>-pl, –projects \<arg> 只构建指定的模块,模块间用逗号隔开</li><li>-rf,-resume-from 从指定模块开始往下构建反应堆</li></ul><p>这些选项还可以组合使用,由于理解不深,不举例了。</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>多模块开发必须使用聚合。</p><p>使用继承可以简化项目的依赖和插件配置。</p>]]></content>
<summary type="html">
<p>聚合是为了方便的构建多个项目,继承是为了简化 POM 的重复配置。</p>
</summary>
<category term="Maven" scheme="/categories/Maven/"/>
</entry>
<entry>
<title>Maven 生命周期与插件</title>
<link href="/2019/02/articles/Maven%20%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E4%B8%8E%E6%8F%92%E4%BB%B6/"/>
<id>/2019/02/articles/Maven 生命周期与插件/</id>
<published>2019-02-09T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.929Z</updated>
<content type="html"><![CDATA[<p>生命周期是对项目进行的一系列操作,插件用来完成这些操作。</p><a id="more"></a><h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p>构建一个项目包括:清理文件 -> 编译 -> 测试 -> 部署。</p><p>因为每一个项目都要进行类似的操作,所以 Maven 抽象出了<strong>生命周期</strong>。</p><p>光是存在生命周期并没有什么意义,而且生命周期<strong>只是定义了</strong>一系列操作,所以在实际的使用中,需要对项目进行某个具体的操作时,将由某个插件来完成这项任务。</p><p>抽象<strong>生命周期</strong>的好处是:制定了规范,只要遵守规范 Maven 就可以自动帮我们完成很多事情。</p><p><strong>抽象</strong>生命周期的好处是:便于拓展。</p><h1 id="三套生命周期"><a href="#三套生命周期" class="headerlink" title="三套生命周期"></a>三套生命周期</h1><p>三套生命周期包括:clean、default、site,每个生命周期又包括多个阶段。</p><p>后一个阶段需要前一个阶段先完成。比如执行第 3 个阶段,Maven 会先执行前面第 1、2 个阶段。</p><h2 id="clean-生命周期"><a href="#clean-生命周期" class="headerlink" title="clean 生命周期"></a>clean 生命周期</h2><p>clean 生命周期的目的是清理项目,它包括三个阶段:</p><ul><li>pre-clean 执行一些清理前需要完成的工作</li><li>clean 清理上一次构建生成的文件</li><li>post-clean 执行一些清理后需要完成的工作</li></ul><h2 id="default-生命周期"><a href="#default-生命周期" class="headerlink" title="default 生命周期"></a>default 生命周期</h2><p>default 生命周期是真正构建时需要执行的,比如编译就是在这个生命周期里面的。</p><p>话说回来,为什么要有三个生命周期呢?我自己的理解是:构建项目时需要执行的任务在 default 生命周期里,但是清理文件这一工作并不是每一次都要执行的,或者是说,清理文件这件事是和编译、打包项目相独立的。所以,他们分为了两个生命周期。site 生命周期同理。逻辑上独立生命周期可以方便理解,实际中使用中,独立生命周期也有好处,比如不是当这一次不需要清理文件时,就不需要加 <code>clean</code> 命令。</p><p>default 生命周期所包括的阶段:</p><ul><li>validate</li><li>initialize</li><li>generate-sources</li><li>process-sources 处理项目主资源文件。一般来说,是对 src/main/resources 目录的内容进行变量替换等工作后,复制到项目输出的主 classpath 目录中。</li><li>generate-resources</li><li>process-resources</li><li>compile 编译项目的主源码。一般来说,是编译 src/main/java 目录下的 Java 文件至项目输出的主 classpath 目录中。</li><li>process-classes</li><li>generate-test-sources</li><li>process-test-sources</li><li>generate-test-resources</li><li>process-test-resources</li><li>test-compile 编译项目的测试代码。一般来说,是编译 src/test/java 目录下的 Java 文件至项目输出的测试 classpath 目录中</li><li>process-test-classes</li><li>test 使用单元测试框架运行测试,测试代码不会被打包或部署。</li><li>prepare-package</li><li>package 接受编译好的代码,打包成可发布的格式,如 JAR</li><li>pre-integration-test</li><li>integration-test</li><li>post-integration-test</li><li>verify</li><li>install 将包安装到 Maven 本地仓库,供本地其他 Maven 项目使用。</li><li>deploy 将最终的包复制到远程仓库,供其他开发人员和 Maven 使用。</li></ul><p><a href="http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html" target="_blank" rel="noopener">官方解释</a></p><h2 id="site-生命周期"><a href="#site-生命周期" class="headerlink" title="site 生命周期"></a>site 生命周期</h2><p>site 生命周期的目的是建立和发布项目站点,Maven 能够基于 POM 所包含的信息,自动生成一个友好的站点,方便团队交流和发布项目信息。</p><p>site 生命周期所包含的阶段:</p><ul><li>pre-site 执行一些在生成项目站点之前需要完成的工作</li><li>site 生成项目站点文档</li><li>post-site 执行一些在生成项目站点之后需要完成的工作</li><li>site-deploy 将生成的项目站点发布到服务器生</li></ul><h1 id="命令行与生命周期"><a href="#命令行与生命周期" class="headerlink" title="命令行与生命周期"></a>命令行与生命周期</h1><ul><li>命令 <code>mvn clean</code> 调用 clean 生命周期的 clean 阶段。实际执行的是 clean 生命周期的 pre-clean 和 clean 阶段。也就是说,调用某个阶段,之前的阶段都会被调用。</li><li>命令 <code>mvn clean install</code> 实际执行的是 clean 生命周期的 pre-clean、clean 阶段,以及 default 生命周期的从 validate 至 install 的所有阶段。</li></ul><h1 id="插件目标"><a href="#插件目标" class="headerlink" title="插件目标"></a>插件目标</h1><p>前面说了,生命周期只是定义了规范,具体执行某一项操作是通过插件来完成的。</p><p>有些操作会比较相似,这样也就有一些代码可以复用。</p><p>现在的问题是:如果每一项任务都对应一个插件,代码就不好复用,所以这样不可取。</p><p>所以,一个插件有多个目标,一个目标用来执行生命周期中的一个任务。</p><h1 id="插件绑定"><a href="#插件绑定" class="headerlink" title="插件绑定"></a>插件绑定</h1><p>Maven 抽象出了生命周期,假设现在也有了插件,但是它们两者似乎并没有任何关系。</p><p>所以就需要插件绑定,将二者联系起来。</p><h2 id="内置绑定"><a href="#内置绑定" class="headerlink" title="内置绑定"></a>内置绑定</h2><p>Maven 为一些<strong>生命周期阶段</strong>绑定了插件的目标。</p><p>比如 default 生命周期的 compile 阶段跟 maven-compiler-plugin 插件的 compile 目标绑定了。</p><h2 id="自定义绑定"><a href="#自定义绑定" class="headerlink" title="自定义绑定"></a>自定义绑定</h2><p>有时候我们需要执行某项任务,但是并没有内置绑定插件目标来实现它。</p><p>此时就需要自定义绑定插件来完成。</p><p>这里需要注意的是 <code>executions</code> 元素,它下面的每一个 <code>execution</code> 子元素用来配置一个任务。</p><p>其中 <code>phrase</code> 指的是生命周期的某一个阶段,<code>goal</code> 指的是插件的某一个目标。</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">build</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.maven<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>maven-source-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.1.1<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">executions</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">execution</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>id<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">phase</span>></span>verify<span class="tag"></<span class="name">phase</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goals</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goal</span>></span>java<span class="tag"></<span class="name">goal</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">goals</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">execution</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">executions</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"><span class="tag"></<span class="name">build</span>></span></span><br></pre></td></tr></table></figure><p>如果没有 <code>phase</code> 标签,也不过出错。这是因为很多插件的目标在编写时已经定义了默认的绑定阶段,所以这里可以不写。</p><h2 id="查看插件信息"><a href="#查看插件信息" class="headerlink" title="查看插件信息"></a>查看插件信息</h2><p>使用下面这条命令:</p><p>(如果省略了版本信息,Maven 将自动获取最新版本来进行表述)</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">mvn help:describe -Dplugin=org.apache.maven.plugins:maven-source-plugin:2.1.1 -Ddetail</span><br></pre></td></tr></table></figure><p>查看默认绑定阶段:<code>Bound to phase:</code></p><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"> Implementation: org.apache.maven.plugin.source.TestSourceJarNoForkMojo</span><br><span class="line"> Language: java</span><br><span class="line"> Bound to phase: package</span><br><span class="line"></span><br><span class="line">...</span><br></pre></td></tr></table></figure><h3 id="使用前缀"><a href="#使用前缀" class="headerlink" title="使用前缀"></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">mvn help:describe -Dplugin=compiler</span><br></pre></td></tr></table></figure><h3 id="指定插件目标"><a href="#指定插件目标" class="headerlink" title="指定插件目标"></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">mvn help:describe -Dplugin=compiler -Dgoal=compile</span><br></pre></td></tr></table></figure><h3 id="输出更详细的信息"><a href="#输出更详细的信息" class="headerlink" title="输出更详细的信息"></a>输出更详细的信息</h3><p>加了 <code>-Ddetail</code>,将插件目标读取的属性列出。</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">mvn help:describe -Dplugin=compiler -Dgoal=compile -Ddetail</span><br></pre></td></tr></table></figure><h1 id="插件配置"><a href="#插件配置" class="headerlink" title="插件配置"></a>插件配置</h1><h2 id="命令行插件配置"><a href="#命令行插件配置" class="headerlink" title="命令行插件配置"></a>命令行插件配置</h2><p>用户可以在 Maven 命令中使用 -D 参数,并伴随一个参数建=参数值的形式,来配置插件目标的参数。</p><p>例如:maven-surefire-plugin 提供了一个 maven.test.skip 参数,当其值为 true 时,将会跳过测试。</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">mvn install -Dmaven.test.skip=true</span><br></pre></td></tr></table></figure><p>参数 -D 是 Java 自带的,其功能是通过命令行设置一个 Java 系统属性,Maven 会在需要时读取该属性的值,实现插件参数的配置。</p><h2 id="pom-中插件全局配置"><a href="#pom-中插件全局配置" class="headerlink" title="pom 中插件全局配置"></a>pom 中插件全局配置</h2><p>例如,为 maven-compiler-plugin 插件配置:</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.maven.plugins<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>maven-compiler-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>3.8.0<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">source</span>></span>1.8<span class="tag"></<span class="name">source</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">target</span>></span>1.8<span class="tag"></<span class="name">target</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"><span class="tag"></<span class="name">plugins</span>></span></span><br></pre></td></tr></table></figure><h2 id="pom-中插件任务配置"><a href="#pom-中插件任务配置" class="headerlink" title="pom 中插件任务配置"></a>pom 中插件任务配置</h2><p>例子:</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">project</span>></span></span><br><span class="line"> [...]</span><br><span class="line"> <span class="tag"><<span class="name">build</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>maven-antrun-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.8<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">executions</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">execution</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">phase</span>></span> <span class="comment"><!-- a lifecycle phase --></span> <span class="tag"></<span class="name">phase</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">tasks</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">echo</span>></span>xxxxxx<span class="tag"></<span class="name">echo</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">tasks</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goals</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">goal</span>></span>run<span class="tag"></<span class="name">goal</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">goals</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">execution</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">executions</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">build</span>></span></span><br><span class="line"> [...]</span><br><span class="line"><span class="tag"></<span class="name">project</span>></span></span><br></pre></td></tr></table></figure><h1 id="从命令行调用插件"><a href="#从命令行调用插件" class="headerlink" title="从命令行调用插件"></a>从命令行调用插件</h1><p>之前执行的命令,比如:<code>mvn install</code> 是执行生命周期中的某一个阶段。</p><p>但是 Maven 也支持直接执行执行插件的某个目标,比如:</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">mvn dependency:tree</span><br></pre></td></tr></table></figure><h1 id="插件解析机制"><a href="#插件解析机制" class="headerlink" title="插件解析机制"></a>插件解析机制</h1><p>刚说了从命令行调用插件的某个目标,但是话说回来,Maven 定义一个插件,应该也是使用坐标的,为什么 Maven 可以识别上面的 <code>dependency</code> 呢?</p><p>下面慢慢说。</p><h2 id="插件仓库"><a href="#插件仓库" class="headerlink" title="插件仓库"></a>插件仓库</h2><p>如果在本地找不到插件的话,将会到远程仓库查找。</p><p>这跟查找依赖的方式很像,但是查找依赖的远程仓库跟查找插件的远程仓库是不一样的,它们的配置方式也是不一样的。</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">project</span>></span></span><br><span class="line"> ...</span><br><span class="line"> <span class="tag"><<span class="name">pluginRepositories</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">pluginRepository</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>apache.snapshots<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url</span>></span>http://repository.apache.org/snapshots/<span class="tag"></<span class="name">url</span>></span></span><br><span class="line"> <span class="comment"><!-- The releases element here is due to an issue in Maven 2.0 that will be</span></span><br><span class="line"><span class="comment"> fixed in future releases. This should be able to be disabled altogether. --></span></span><br><span class="line"> <span class="tag"><<span class="name">releases</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">updatePolicy</span>></span>daily<span class="tag"></<span class="name">updatePolicy</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">releases</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">snapshots</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">updatePolicy</span>></span>daily<span class="tag"></<span class="name">updatePolicy</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">snapshots</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">pluginRepository</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">pluginRepositories</span>></span></span><br><span class="line"> ...</span><br><span class="line"><span class="tag"></<span class="name">project</span>></span></span><br></pre></td></tr></table></figure><p>或</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">settings</span>></span></span><br><span class="line"> ...</span><br><span class="line"> <span class="tag"><<span class="name">profiles</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">profile</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>apache<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">pluginRepositories</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">pluginRepository</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>apache.snapshots<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">name</span>></span>Maven Plugin Snapshots<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url</span>></span>http://repository.apache.org/snapshots/<span class="tag"></<span class="name">url</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">releases</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">enabled</span>></span>false<span class="tag"></<span class="name">enabled</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">releases</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">snapshots</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">enabled</span>></span>true<span class="tag"></<span class="name">enabled</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">snapshots</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">pluginRepository</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">pluginRepositories</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">profile</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">profiles</span>></span></span><br><span class="line"> ...</span><br><span class="line"><span class="tag"></<span class="name">settings</span>></span></span><br></pre></td></tr></table></figure><h2 id="插件的默认-groupId"><a href="#插件的默认-groupId" class="headerlink" title="插件的默认 groupId"></a>插件的默认 groupId</h2><p>如果是官方插件(即如果其 groupId 是 org.apache.maven.plugins)就可以省略 groupId 配置,但是不推荐省略,免得别人不理解看不出来。</p><h2 id="解析插件版本"><a href="#解析插件版本" class="headerlink" title="解析插件版本"></a>解析插件版本</h2><ul><li>对于核心插件,Maven 的超级 POM 中设置了版本。因此,即使用户不加任何配置,它们的版本就确定了。</li><li>对于非核心插件,又没有指定版本,Maven 将会检查所有仓库中的可用版本,然后做出选择。</li></ul><p>建议指定一个明确的版本。</p><h2 id="解析插件前缀"><a href="#解析插件前缀" class="headerlink" title="解析插件前缀"></a>解析插件前缀</h2><p><code>~\.m2\repository\org\apache\maven\plugins\maven-metadata.xml</code> 和 <code>~\.m2\repository\org\codehaus\mojo\maven-metadata.xml</code> 存储了插件和前缀的对应关系。</p><p>随便举个例子:</p><figure class="highlight xml"><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"><span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">name</span>></span>Appfuse Maven Plugin<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">prefix</span>></span>appfuse<span class="tag"></<span class="name">prefix</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>appfuse-maven-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"></<span class="name">plugin</span>></span></span><br></pre></td></tr></table></figure><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>原来生命周期不仅仅是 <code>clean</code>、<code>install</code> …,而且生命周期分为三套。</p><p>原来插件是生命周期的具体实现,原来插件目标是与生命周期的某个阶段相绑定的。</p>]]></content>
<summary type="html">
<p>生命周期是对项目进行的一系列操作,插件用来完成这些操作。</p>
</summary>
<category term="Maven" scheme="/categories/Maven/"/>
</entry>
<entry>
<title>Maven 仓库</title>
<link href="/2019/02/articles/Maven%20%E4%BB%93%E5%BA%93/"/>
<id>/2019/02/articles/Maven 仓库/</id>
<published>2019-02-07T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.928Z</updated>
<content type="html"><![CDATA[<p>了解 Maven 中的仓库。</p><a id="more"></a><h1 id="使用-Maven-添加依赖"><a href="#使用-Maven-添加依赖" class="headerlink" title="使用 Maven 添加依赖"></a>使用 Maven 添加依赖</h1><p>一般来说,要在 Java 中使用别人的写好的代码,通常是下载别人提供的 jar 包,然后引入当前的项目来使用。</p><p>这么做的问题是:</p><ul><li>需要手动下载 jar 包</li><li>可能这个 jar 包又依赖于其他的 jar 包</li><li>…</li></ul><p>而在 Maven 中一切都变得很简单,创建一个 Maven 项目之后,假设我们需要使用 okhttp,只需要在谷歌搜索 okhttp,复制下面这段代码到我们的 pom.xml 中即可。</p><figure class="highlight xml"><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"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.squareup.okhttp3<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>okhttp<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>3.13.1<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><p>当然了,实际上还是需要下载 jar 包的,毕竟“存在”才可以“使用”,不过这些工作不需要我们来完成。</p><p>在 pom.xml 添加 okhttp 的依赖之后,Maven 会替我们解决依赖的问题,并下载需要的 jar 包。</p><h1 id="Maven-背后的工作"><a href="#Maven-背后的工作" class="headerlink" title="Maven 背后的工作"></a>Maven 背后的工作</h1><p>我们只是告诉 Maven 需要 okhttp 这个依赖,然后呢?Maven 会去哪里下载这个依赖呢?</p><p>实际上 Maven 中有一个默认的地址,它默认就会去那里寻找 jar 包。</p><p>不过,暂时不关心如何查找,先关心在我们电脑中发生的事情。</p><p>Maven 下载 jar 包之后,统一保存到 <code>~/.m2/repository</code> 目录下,这个目录称为本地仓库。</p><h1 id="仓库的概念"><a href="#仓库的概念" class="headerlink" title="仓库的概念"></a>仓库的概念</h1><p>我认为仓库其实就是一个文件夹而已。仓库中存在文件,实际上就是文件夹中存放了一大堆 jar 包(也存在其他文件,<strong>我总是说 jar 包是因为我对其他类型文件用得比较少,认识不深</strong>)。</p><h1 id="仓库的规范(布局)"><a href="#仓库的规范(布局)" class="headerlink" title="仓库的规范(布局)"></a>仓库的规范(布局)</h1><p>为了更好的管理这些 jar 包,仓库有一套规范。否则,假设所有 jar 包都存在一个文件夹中,当 jar 包文件特别多时,查找就需要花很多的时间。(规范的作用还有很多,我还体会不到)</p><p>那么这套规范(或者是说布局)是什么?</p><p>简单说来,就是对于每一个 Maven 项目所构建的文件,就好比一个 jar 包,都在仓库中有一个明确且独立的位置。换句话说,根据一个 Maven 项目的坐标,就可以确定这个项目所生成的 jar 包的位置。</p><p>比如:</p><p>项目坐标:</p><figure class="highlight xml"><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 class="tag"><<span class="name">groupId</span>></span>com.diaolizhi<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"><span class="tag"><<span class="name">artifactId</span>></span>tieba-tool<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"><<span class="name">version</span>></span>1.3-SNAPSHOT<span class="tag"></<span class="name">version</span>></span></span><br></pre></td></tr></table></figure><p>实际的文件路径:</p><p><code>C:\Users\xxx\.m2\repository\com\diaolizhi\tieba-tool\1.3-SNAPSHOT</code></p><p>由此可知,<strong>大致</strong>的对应关系是:</p><p><code>groupId/artifactId/version/artifactId-version.packaging</code></p><p><strong>实际上,仓库的规范(布局)不仅仅是根据上面的 groupId、artifactId 和 version,这里只是举个例子。</strong></p><h1 id="仓库的分类"><a href="#仓库的分类" class="headerlink" title="仓库的分类"></a>仓库的分类</h1><ul><li>仓库<ul><li>本地仓库</li><li>远程仓库<ul><li>中央仓库</li><li>私服</li><li>其他公共库</li></ul></li></ul></li></ul><h1 id="本地仓库"><a href="#本地仓库" class="headerlink" title="本地仓库"></a>本地仓库</h1><p>就是默认的 <code>~/.m2/repository</code> 那么目录而已。</p><h2 id="修改本地仓库的位置"><a href="#修改本地仓库的位置" class="headerlink" title="修改本地仓库的位置"></a>修改本地仓库的位置</h2><p>编辑 <code>~/.m2/setting.xml</code> 文件。(先从 Maven 的安装目录将该文件复制过来)</p><figure class="highlight xml"><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 class="tag"><<span class="name">settings</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">localRepository</span>></span>D:\java\repository<span class="tag"></<span class="name">localRepository</span>></span></span><br><span class="line"><span class="tag"></<span class="name">settings</span>></span></span><br></pre></td></tr></table></figure><h1 id="中央仓库"><a href="#中央仓库" class="headerlink" title="中央仓库"></a>中央仓库</h1><p>可以看成一台服务器,上面存放了非常多的 Maven 项目。</p><p>当本地仓库找不到某个依赖时,就会到中央仓库去寻找。</p><h1 id="私服"><a href="#私服" class="headerlink" title="私服"></a>私服</h1><p>架设在局域网的仓库服务。</p><p>特点:</p><ul><li>当 Maven 需要下载时,会向私服发送请求</li><li>如果私服不存在该文件,就向外部的远程仓库请求,并且缓存到私服上,以供下一次使用</li><li>从本地上传文件到私服上供局域网内用户使用</li></ul><h1 id="配置远程仓库"><a href="#配置远程仓库" class="headerlink" title="配置远程仓库"></a>配置远程仓库</h1><p><a href="https://maven.apache.org/guides/mini/guide-multiple-repositories.html" target="_blank" rel="noopener">官方文档 - Setting up Multiple Repositories</a></p><p>修改 pom.xml:</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">project</span>></span></span><br><span class="line">...</span><br><span class="line"> <span class="tag"><<span class="name">repositories</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">repository</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>my-repo1<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">name</span>></span>your custom repo<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url</span>></span>http://jarsm2.dyndns.dk<span class="tag"></<span class="name">url</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">releases</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">enabled</span>></span>true<span class="tag"></<span class="name">enabled</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">updatePolicy</span>></span>daily<span class="tag"></<span class="name">updatePolicy</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">checksumPolicy</span>></span>ignore<span class="tag"></<span class="name">checksumPolicy</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">releases</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">snapshots</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">enabled</span>></span>false<span class="tag"></<span class="name">enabled</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">snapshots</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">layout</span>></span>default<span class="tag"></<span class="name">layout</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">repository</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">repository</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>my-repo2<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">name</span>></span>your custom repo<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url</span>></span>http://jarsm2.dyndns.dk<span class="tag"></<span class="name">url</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">repository</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">repositories</span>></span></span><br><span class="line">...</span><br><span class="line"><span class="tag"></<span class="name">project</span>></span></span><br></pre></td></tr></table></figure><ul><li>id 用来声明一个远程仓库<ul><li>如果 id 设置为 central 将会覆盖中央仓库的配置</li></ul></li><li>name 是远程仓库的名字,用来给人看的</li><li>url 表示远程仓库的地址</li><li>releases 对应发行版本,snapshots 对应快照版本<ul><li>enabled 表示是否对发行版本/快照版本进行下载<ul><li>根据上面的配置:从远程仓库下载发行版本,但是不会下载快照版本</li></ul></li><li>updatePolicy 配置从远程仓库检查更新的频率<ul><li>daily 每天检查一次</li><li>never 从不</li><li>always 每次构建时更新</li><li>interval: X 每个 X 分钟检查更新一次(X 为任意整数)</li></ul></li><li>checksumPolicy 配置 Maven 检查校验和文件的策略<ul><li>默认值 warn 校验失败输出警告信息</li><li>fail 校验失败就让构建失败</li><li>ignore 完全忽略校验和错误</li></ul></li></ul></li></ul><h1 id="远程仓库的认证"><a href="#远程仓库的认证" class="headerlink" title="远程仓库的认证"></a>远程仓库的认证</h1><p><a href="https://maven.apache.org/guides/mini/guide-encryption.html" target="_blank" rel="noopener">参考文档</a></p><p>修改 settings.xml:</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">settings</span>></span></span><br><span class="line">...</span><br><span class="line"> <span class="tag"><<span class="name">servers</span>></span></span><br><span class="line">...</span><br><span class="line"> <span class="tag"><<span class="name">server</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>my-proj<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">username</span>></span>repo-user<span class="tag"></<span class="name">username</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">password</span>></span>repo-pwd<span class="tag"></<span class="name">password</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">server</span>></span></span><br><span class="line">...</span><br><span class="line"> <span class="tag"></<span class="name">servers</span>></span></span><br><span class="line">...</span><br><span class="line"><span class="tag"></<span class="name">settings</span>></span></span><br></pre></td></tr></table></figure><p>远程仓库是在 pom.xml 中配置的,而认证是在 settings.xml 中配置的。</p><p>这么做也是很好理解的,如果账号密码写在 Maven 项目中,那么这个项目发给别人的时候就可能造成账号的泄漏,所以写在本地的 settings.xml 是相对安全的。</p><p>另外需要注意,这里的 <code>id</code> 和 pom.xml 中配置的远程仓库的 <code>id</code> 需要对应起来。</p><h1 id="部署至远程仓库"><a href="#部署至远程仓库" class="headerlink" title="部署至远程仓库"></a>部署至远程仓库</h1><p><a href="https://maven.apache.org/pom.html#Distribution_Management" target="_blank" rel="noopener">参考文档</a></p><p>在 settings.xml 中添加:</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0</span></span></span><br><span class="line"><span class="tag"><span class="string"> https://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span></span><br><span class="line"> ...</span><br><span class="line"> <span class="tag"><<span class="name">distributionManagement</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">repository</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>corp1<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">name</span>></span>Corporate Repository<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url</span>></span>scp://repo/maven2<span class="tag"></<span class="name">url</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">repository</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">snapshotRepository</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>propSnap<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">name</span>></span>Propellors Snapshots<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url</span>></span>sftp://propellers.net/maven<span class="tag"></<span class="name">url</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">snapshotRepository</span>></span></span><br><span class="line"> ...</span><br><span class="line"> <span class="tag"></<span class="name">distributionManagement</span>></span></span><br><span class="line"> ...</span><br><span class="line"><span class="tag"></<span class="name">project</span>></span></span><br></pre></td></tr></table></figure><p><code>distributionManagement</code> 包括两个子元素: <code>repository</code>、<code>snapshotRepository</code>,分别对应发布版本的仓库和快照版本的仓库。</p><p><strong>上面的配置是在 settings.xml 中的,当执行 <code>mvn clean deploy</code> 时,会判断当前项目是发布版本还是快照版本,部署到对应的远程仓库中。</strong></p><h1 id="快照版本"><a href="#快照版本" class="headerlink" title="快照版本"></a>快照版本</h1><p>一个人写项目的时候体现不出快照版本的好处,当两个人合作的时候就体现出来了。</p><p>小明开发项目 A,小红开发项目 B。项目 B 依赖于项目 A,并且项目 A 正在开发。</p><p>怎么保证小红时刻可以获取到最新的项目 A 呢?</p><ul><li>每次下载源码进行编译。这显然不合理,不仅浪费时间,而且编译出错也不好解决。</li><li>项目 A 部署时修改版本号。这可以,但是有些麻烦,每次上传需要修改版本号,下载也需要修改版本号。</li><li>使用快照。上传和下载时都使用: x.y-SNAPSHOT。这样做的神奇之处在于,上传到远程仓库时,名字不是 x.y-SNAPSHOT 而是 x.y-时间戳。另一方面,需要下载最新版本的项目 A 时,Maven 会检查远程仓库是否有更新,如果有就下载。<ul><li>什么时候会下载最新版本的项目 A 呢?<ul><li>根据上面提到的 updatePolicy,默认每天更新一次</li><li>或者使用 <code>mvn clean install-U</code></li></ul></li></ul></li></ul><h1 id="解析依赖的机制"><a href="#解析依赖的机制" class="headerlink" title="解析依赖的机制"></a>解析依赖的机制</h1><p>当我们在 pom.xml 中添加依赖的时候,Maven 是如何判断从哪里得到这个依赖的呢?</p><ul><li>如果依赖的范围是 system,直接从本地文件系统解析该文件,找到就结束</li><li>根据依赖计算仓库路径,尝试在本地仓库查找该文件,找到就结束</li><li>上面两种方式都找不到时,如果依赖的版本号是确定的,比如 1.2、2.1-beta-1,将遍历所有远程仓库,发现后就下载,然后结束</li><li>如果版本号指定的是 RELEASE 或者 LATEST 或者 SNAPSHOT,Maven 会根据更新策略,访问远程仓库的元数据:<code>groupId/artifactId/maven-metadata.xml</code>,将其与本地仓库的元数据合并后,计算出真实的版本号,然后在从本地仓库或者远程仓库中查找。</li></ul><p>注意点:</p><ul><li>快照版本在远程仓库中带时间戳,但是从远程仓库下载之后时间戳又变成了 SNAPSHOT。</li><li>RELEASE 表示最新的发布版本,LATEST 表示最新版本(包括快照版本)</li><li>不要使用 RELEASE 和 LATEST </li></ul><h1 id="镜像"><a href="#镜像" class="headerlink" title="镜像"></a>镜像</h1><p>修改 settings.xml:</p><figure class="highlight xml"><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"><span class="tag"><<span class="name">settings</span>></span></span><br><span class="line"> ...</span><br><span class="line"> <span class="tag"><<span class="name">mirrors</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">mirror</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>UK<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">name</span>></span>UK Central<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url</span>></span>http://uk.maven.org/maven2<span class="tag"></<span class="name">url</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">mirrorOf</span>></span>central<span class="tag"></<span class="name">mirrorOf</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">mirror</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">mirrors</span>></span></span><br><span class="line"> ...</span><br><span class="line"><span class="tag"></<span class="name">settings</span>></span></span><br></pre></td></tr></table></figure><p><code>mirrorOf</code> 表示这个是哪个仓库的镜像,这里的 <code>central</code> 指的就是中央仓库。</p><p>因为私服可以访问外部仓库,所以直接指定私服作为镜像也是可以的,反正找不到的时候它会向外部寻找。</p><p><code>mirrorOf</code> 中间可以是:</p><ul><li><code>*</code> 匹配所有远程仓库</li><li><code>external: *</code> 匹配所有不在本机上的远程仓库</li><li><code>repo1, repo2</code> 匹配仓库 repo1 和 repo2</li><li><code>*, !repo1</code> 匹配所有远程仓库,repo1 除外</li></ul><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><ul><li>仓库用来存放 Maven 生成的文件,且仓库的目录有自己的规范。</li><li>仓库可以大致分为本地仓库和远程仓库。</li><li>快照是在开发时使用的。</li><li>使用镜像可以加快 Maven 的下载速度。</li></ul>]]></content>
<summary type="html">
<p>了解 Maven 中的仓库。</p>
</summary>
<category term="Maven" scheme="/categories/Maven/"/>
</entry>
<entry>
<title>创建 Maven 项目</title>
<link href="/2019/02/articles/Maven%E7%AC%94%E8%AE%B0%20-%20%E5%88%9B%E5%BB%BA%20Maven%20%E9%A1%B9%E7%9B%AE/"/>
<id>/2019/02/articles/Maven笔记 - 创建 Maven 项目/</id>
<published>2019-02-07T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.929Z</updated>
<content type="html"><![CDATA[<p>温故知新。</p><a id="more"></a><h1 id="pom-文件"><a href="#pom-文件" class="headerlink" title="pom 文件"></a>pom 文件</h1><p>该文件的作用:</p><ul><li>在茫茫 Java 类库中声明自己的身份</li><li>并且声明需要依赖的类库</li><li>说明项目将怎么样进行构建(比如说明入口文件)</li><li>…</li></ul><h1 id="简单的-pom-xml-示例"><a href="#简单的-pom-xml-示例" class="headerlink" title="简单的 pom.xml 示例"></a>简单的 pom.xml 示例</h1><ul><li>xml 版本、编码方式声明</li><li>project 是根元素</li><li>对于 Maven2 和 Maven3 来说 <code>modelVersion</code> 只能是 4.0.0</li><li>groupId 域名倒序加项目名</li><li>artifactId 模块名</li><li>version 版本</li><li>name 项目的描述</li></ul><figure class="highlight xml"><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"><?xml version="1.0" encoding="UTF-8"?></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">modelVersion</span>></span>4.0.0<span class="tag"></<span class="name">modelVersion</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.diaolizhi.second<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>myHelloWorld<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.0-SNAPSHOT<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">name</span>></span>myHelloWorld<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"><span class="tag"></<span class="name">project</span>></span></span><br></pre></td></tr></table></figure><h1 id="Maven-项目规定"><a href="#Maven-项目规定" class="headerlink" title="Maven 项目规定"></a>Maven 项目规定</h1><ul><li>项目代码放在 <code>/src/main/java/com.xxx.groupId.artifactId</code> 目录下 </li><li>测试代码放在 <code>/src/test/java/com.xxx.groupId.artifactId</code> 目录下</li></ul><h1 id="Maven-输出"><a href="#Maven-输出" class="headerlink" title="Maven 输出"></a>Maven 输出</h1><ul><li>输出内容在 <code>/target/</code> 目录下,包括生成的 jar 包</li><li><code>classes</code> 目录下是编译生成的 class 文件</li></ul><h1 id="指定入口类"><a href="#指定入口类" class="headerlink" title="指定入口类"></a>指定入口类</h1><ul><li>借助 maven-shade-plugin</li></ul><h1 id="mvn-clean"><a href="#mvn-clean" class="headerlink" title="mvn clean"></a>mvn clean</h1><ul><li>删除 target 目录</li></ul><h1 id="mvn-compile"><a href="#mvn-compile" class="headerlink" title="mvn compile"></a>mvn compile</h1><ul><li>编译项目主代码</li></ul><h1 id="mvn-test"><a href="#mvn-test" class="headerlink" title="mvn test"></a>mvn test</h1><ul><li>执行测试用例</li></ul><h1 id="mvn-package"><a href="#mvn-package" class="headerlink" title="mvn package"></a>mvn package</h1><ul><li>打包</li></ul><h1 id="mvn-install"><a href="#mvn-install" class="headerlink" title="mvn install"></a>mvn install</h1><ul><li>打包并添加到本地仓库</li></ul>]]></content>
<summary type="html">
<p>温故知新。</p>
</summary>
<category term="Maven" scheme="/categories/Maven/"/>
</entry>
<entry>
<title>Maven 相关目录</title>
<link href="/2019/02/articles/Maven%E7%AC%94%E8%AE%B0%20-%20Maven%20%E7%9B%B8%E5%85%B3%E7%9B%AE%E5%BD%95/"/>
<id>/2019/02/articles/Maven笔记 - Maven 相关目录/</id>
<published>2019-02-07T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.929Z</updated>
<content type="html"><![CDATA[<p>对 Maven 的理解及其相关目录。</p><a id="more"></a><h1 id="Maven-是什么"><a href="#Maven-是什么" class="headerlink" title="Maven 是什么"></a>Maven 是什么</h1><p>Maven 是一个构建工具、依赖管理工具。</p><h1 id="什么是构建"><a href="#什么是构建" class="headerlink" title="什么是构建"></a>什么是构建</h1><p>从源代码开始,编译 -> 测试 -> 打包 -> 部署 -> 运行。</p><h1 id="什么是依赖管理"><a href="#什么是依赖管理" class="headerlink" title="什么是依赖管理"></a>什么是依赖管理</h1><p>Maven 使用坐标定位一个依赖包,而且每一个依赖都指定了自己的依赖,不需要我们手动的下载、导入 jar 包,也不需要我们人工的解决包的依赖、以及兼容问题。</p><h1 id="M2-HOME"><a href="#M2-HOME" class="headerlink" title="M2_HOME"></a>M2_HOME</h1><p>在电脑上 M2_HOME 环境变量指向的是 Maven 的安装目录。</p><p>下面介绍该目录下的几个目录:</p><h2 id="bin"><a href="#bin" class="headerlink" title="bin"></a>bin</h2><p>该目录包含了 mvn 运行的脚本。</p><p>当我们在命令行执行 mvn 时,运行的就是这里的 mvn 文件。</p><h2 id="boot"><a href="#boot" class="headerlink" title="boot"></a>boot</h2><p>该目录包含一个类加载器框架。</p><p>对于一般的 Maven 用户不必关心它。</p><h2 id="conf"><a href="#conf" class="headerlink" title="conf"></a>conf</h2><p>该目录包含一个非常重要的 settings.xml 文件。</p><p>直接修改该文件将会在全局范围内改变 Maven 的设置,所以推荐将该文件复制到 <code>~/.m2/</code> 目录中再修改,这样做只对一个用户生效。</p><h2 id="lib"><a href="#lib" class="headerlink" title="lib"></a>lib</h2><p>该目录包含 Maven 运行时需要的 Jar 包,可以说这个目录才是真正的 Maven。</p><h1 id="m2"><a href="#m2" class="headerlink" title="~./m2"></a>~./m2</h1><p>默认情况下,<code>~/.m2</code> 目录下只有一个 repository 目录,这个 repository 包含通过 Maven 下载的 Jar 包。</p><p>另外,推荐将 <code>M2_HOME/conf/settings.xml</code> 复制到这个目录下。</p>]]></content>
<summary type="html">
<p>对 Maven 的理解及其相关目录。</p>
</summary>
<category term="Maven" scheme="/categories/Maven/"/>
</entry>
<entry>
<title>Shell 脚本自动部署 Spring Boot 项目</title>
<link href="/2019/01/articles/Shell%20%E8%84%9A%E6%9C%AC%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%20Spring%20Boot%20%E9%A1%B9%E7%9B%AE/"/>
<id>/2019/01/articles/Shell 脚本自动部署 Spring Boot 项目/</id>
<published>2019-01-12T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.929Z</updated>
<content type="html"><![CDATA[<p>同步代码 -> 打包 -> 终止进程 -> 运行项目<br><a id="more"></a></p><h1 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h1><h2 id="Git"><a href="#Git" class="headerlink" title="Git"></a>Git</h2><p>腾讯云 Linux 主机自带 Git,无需再安装。</p><p>但是需要执行:</p><figure class="highlight shell"><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</span><br></pre></td></tr></table></figure><p>并将 ~/.ssh/id_rsa.pub 里的内容复制到 GitHub,这样才可以 git clone 私有项目。</p><h2 id="maven"><a href="#maven" class="headerlink" title="maven"></a>maven</h2><p>maven 用来打包 Spring Boot 项目,下载方式:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget http://mirror.bit.edu.cn/apache/maven/maven-3/3.6.0/binaries/apache-maven-3.6.0-bin.tar.gz</span><br></pre></td></tr></table></figure><p>解压:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar -zvxf apache-xxxx</span><br></pre></td></tr></table></figure><p>添加到 $PATH 变量:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim /etc/profile</span><br></pre></td></tr></table></figure><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">PATH="$PATH":/usr/xxxxx</span><br></pre></td></tr></table></figure><h2 id="JDK"><a href="#JDK" class="headerlink" title="JDK"></a>JDK</h2><p>maven 需要 jdk 而不是 jre,否则执行 maven install 时会报错,如果装了 jdk 可以跳过这一步。</p><p>安装命令:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install java-1.8.0-openjdk-devel</span><br></pre></td></tr></table></figure><p>安装之后使用 find 命令找到安装目录,并将其 bin 目录添加到 $PATH 变量中。</p><h1 id="编写脚本"><a href="#编写脚本" class="headerlink" title="编写脚本"></a>编写脚本</h1><h2 id="关键点"><a href="#关键点" class="headerlink" title="关键点"></a>关键点</h2><ul><li>如何终止正在运行的进程</li><li>如何获取到最新生成的 jar 包的文件名</li></ul><h2 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h2><ul><li>定义 PRONAME (代表的是项目名)变量,然后通过 pkill 命令根据项目名终止进程。</li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pkill -f "java -jar $PRONAME"</span><br></pre></td></tr></table></figure><ul><li>通过 ls 和 tail 命令找到最新生成的 jar 包</li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ls -tr $PRONAME*.jar | tail -n 1</span><br></pre></td></tr></table></figure><h2 id="注意点"><a href="#注意点" class="headerlink" title="注意点"></a>注意点</h2><p>需要指定项目的<strong>绝对路径</strong>,因为不确定在哪个目录下执行此脚本,所以就可能导致无法切换到正确的目录,那就会出错。</p><p>另外,如果:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PROPATH='~/xxxxx/xxxxx/xxxx.sh'</span><br></pre></td></tr></table></figure><p>也是无法正确的切换目录的,要把 ~ 替换成 /root</p><h2 id="完整脚本"><a href="#完整脚本" class="headerlink" title="完整脚本"></a>完整脚本</h2><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 项目名</span></span><br><span class="line">PRONAME="demo"</span><br><span class="line"><span class="meta">#</span><span class="bash"> 项目所在路径</span></span><br><span class="line">PROPATH='/root/xxxxx/xxxxx/xxxx.sh'</span><br><span class="line"></span><br><span class="line">nohup git pull origin master >/dev/null 2>&1</span><br><span class="line"></span><br><span class="line">cd $PROPATH</span><br><span class="line"></span><br><span class="line">nohup mvn install -DskipTests >/dev/null 2>&1</span><br><span class="line"></span><br><span class="line">cd target</span><br><span class="line"></span><br><span class="line">FILENAME=`ls -tr $PRONAME*.jar | tail -n 1`</span><br><span class="line"></span><br><span class="line">pkill -f "java -jar $PRONAME"</span><br><span class="line"></span><br><span class="line">nohup java -jar $FILENAME >/dev/null 2>log.txt &</span><br></pre></td></tr></table></figure><h1 id="Java-执行-Shell-脚本"><a href="#Java-执行-Shell-脚本" class="headerlink" title="Java 执行 Shell 脚本"></a>Java 执行 Shell 脚本</h1><p>既然可以通过 Java 执行 Shell 脚本,那么就可以创建一个 Get 接口,当它被调用时就执行上面这个脚本。</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ReloadSystem</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">reloadSystem</span><span class="params">()</span> </span>{</span><br><span class="line"> ProcessBuilder processBuilder = <span class="keyword">new</span> ProcessBuilder();</span><br><span class="line"></span><br><span class="line"> processBuilder.command(<span class="string">"bash"</span>, <span class="string">"-c"</span>, <span class="string">"bash ~/xxxxx/xxxxx/xxxx.sh"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"></span><br><span class="line"> Process process = processBuilder.start();</span><br><span class="line"></span><br><span class="line"> StringBuilder output = <span class="keyword">new</span> StringBuilder();</span><br><span class="line"></span><br><span class="line"> BufferedReader reader = <span class="keyword">new</span> BufferedReader(</span><br><span class="line"> <span class="keyword">new</span> InputStreamReader(process.getInputStream()));</span><br><span class="line"></span><br><span class="line"> String line;</span><br><span class="line"> <span class="keyword">while</span> ((line = reader.readLine()) != <span class="keyword">null</span>) {</span><br><span class="line"> output.append(line + <span class="string">"\n"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">int</span> exitVal = process.waitFor();</span><br><span class="line"> <span class="keyword">if</span> (exitVal == <span class="number">0</span>) {</span><br><span class="line"> System.out.println(output);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><ol><li>本地开发,提交到 GitHub</li><li>访问指定接口,执行 Shell 脚本自动完成下面的工作:<ol><li>使用 git pull 同步代码</li><li>使用 mvn install 打包</li><li>终止进程</li><li>使用 java -jar 运行项目</li></ol></li></ol><p>有更好的部署工具,但是现在已经可以满足我的需求了,所以没有动力去学习了。</p>]]></content>
<summary type="html">
<p>同步代码 -&gt; 打包 -&gt; 终止进程 -&gt; 运行项目<br>
</summary>
<category term="Linux" scheme="/categories/Linux/"/>
</entry>
<entry>
<title>GitHub 开放私有仓库</title>
<link href="/2019/01/articles/GitHub%20%E5%BC%80%E6%94%BE%E7%A7%81%E6%9C%89%E4%BB%93%E5%BA%93/"/>
<id>/2019/01/articles/GitHub 开放私有仓库/</id>
<published>2019-01-07T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.923Z</updated>
<content type="html"><![CDATA[<p>喜大普奔,纪念一下。</p><a id="more"></a><p>是时候把自己的垃圾代码设为私有了。</p><p>水一张图片。</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/diaolizhi.jpeg" alt></p>]]></content>
<summary type="html">
<p>喜大普奔,纪念一下。</p>
</summary>
<category term="GitHub" scheme="/categories/GitHub/"/>
</entry>
<entry>
<title>Spring Boot 2.x 免费升级 HTTPS</title>
<link href="/2019/01/articles/Spring%20Boot%20%E5%85%8D%E8%B4%B9%E5%8D%87%E7%BA%A7%20HTTPS/"/>
<id>/2019/01/articles/Spring Boot 免费升级 HTTPS/</id>
<published>2019-01-01T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.930Z</updated>
<content type="html"><![CDATA[<p>有个🔒的感觉就是 8 一样嗷。</p><a id="more"></a><p>本文只说操作步骤,别的不讲,因为不会。</p><h1 id="必要的前提"><a href="#必要的前提" class="headerlink" title="必要的前提"></a>必要的前提</h1><ul><li>拥有一个域名</li><li>拥有一个 Linux 服务器</li></ul><h1 id="申请证书"><a href="#申请证书" class="headerlink" title="申请证书"></a>申请证书</h1><p>我是通过 <a href="https://www.youtube.com/watch?v=fL6A9I1-U6M" target="_blank" rel="noopener">Youtube 视频</a> 了解到如何快速免费的申请一个 HTTPS 证书的,推荐大家可以看一哈。</p><p>申请证书的网站是:<a href="https://freessl.cn/" target="_blank" rel="noopener">FreeSSL</a></p><h2 id="进入首页"><a href="#进入首页" class="headerlink" title="进入首页"></a>进入首页</h2><p>需要注意的是:<strong>证书的类型</strong>以及<strong>证书的有效期</strong>,根据个人需要选择。</p><p>我选择的是第二个,因为我需要用到多个二级域名。</p><p>如果只有一个网站,建议选择第一个,因为有效期比较长。</p><p><strong>如果证书到期了,就需要到这个网站再申请一次。</strong></p><p>接下来输入自己的域名,我输入的是:*.ddllzz.xyz</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2019-01-02_15-59-34.png" alt></p><h2 id="创建证书"><a href="#创建证书" class="headerlink" title="创建证书"></a>创建证书</h2><p>直接输入邮箱然后点击创建即可。</p><p><strong>但是为了安全起见,推荐自己生成 CSR,工具自己去网上搜。</strong></p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2019-01-02_16-18-43.png" alt> </p><h2 id="验证"><a href="#验证" class="headerlink" title="验证"></a>验证</h2><p>完成上面一步之后可以看到:</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2019-01-02_16-27-12.png" alt></p><p>此时需要根据上面的提示为自己的域名添加 DNS 解析:</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2019-01-02_16-29-44.png" alt></p><p>等待一会点击上面图中的“配置完成,检测一下”。</p><p>看到下图说明 OK 了。</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2019-01-02_16-31-19.png" alt></p><p>再然后点击上图的“点击验证”,得到证书信息:</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2019-01-02_17-44-33.png" alt></p><p>点击下载证书,记得保管好。</p><h1 id="转换"><a href="#转换" class="headerlink" title="转换"></a>转换</h1><p>刚才下载了证书(下载的是一个压缩包),压缩包里的文件是:full_chain.pem 和 private.key,而我们在 Spring Boot 中需要的是 pkcs12 类型的文件,所以需要用 openssl 进行转换。</p><p><strong>推荐在 Linux 下完成转换,因为我在 Windows 下生成的 private.key 一直是 0kb,同样的操作在 Linux 下就没问题。</strong></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl pkcs12 -export -in full_chain.pem -inkey private.key -out keystore.p12(这个是生成的文件名) -name tomacat -CAfile full_chain.pem -caname root</span><br></pre></td></tr></table></figure><p>现在得到了 keystore.p12,就可以在 Spring Boot 项目中使用它了。</p><h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><p>将刚刚得到的 kyestore.p12 文件复制到 Spring Boot 项目中的 resources 目录下,然后在 application.properties 文件中添加:</p><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">server.port=8443</span><br><span class="line">server.ssl.trust-store-type=PKCS12</span><br><span class="line">server.ssl.key-store=classpath:kyestore.p12</span><br><span class="line">server.ssl.key-store-password=这里是进行转换时输入的密码</span><br><span class="line">server.ssl.key-alias=tomcat</span><br></pre></td></tr></table></figure><h1 id="本地测试"><a href="#本地测试" class="headerlink" title="本地测试"></a>本地测试</h1><p>在本地测试时,如果通过 <a href="https://127.0.0.1:8443" target="_blank" rel="noopener">https://127.0.0.1:8443</a> 访问,会提示不安全:</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2019-01-02_17-52-02.png" alt> </p><p>因为刚才的证书是属于 ddllzz.xyz 这个域名的,但是现在并非通过这个域名访问,所以会提示不安全。</p><p>现在修改本机 hosts 文件,添加一行:</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">127.0.0.1 ddllzz.xyz</span><br></pre></td></tr></table></figure><p>再次通过 <a href="https://ddllzz.xyz:8443" target="_blank" rel="noopener">https://ddllzz.xyz:8443</a> 访问就行了:</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2019-01-02_17-55-45.png" alt></p><h1 id="80-端口重定向到-HTTPS"><a href="#80-端口重定向到-HTTPS" class="headerlink" title="80 端口重定向到 HTTPS"></a>80 端口重定向到 HTTPS</h1><p>在 Spring Boot 中使用下面这段代码,就可以实现:</p><blockquote><p>当访问 ddllzz.xyz 时跳转到 <a href="https://ddllzz.xyz:8443。" target="_blank" rel="noopener">https://ddllzz.xyz:8443。</a></p></blockquote><p>它存在的意义是:别人可能并不知道你 HTTPS 设置的端口,如果没有这个重定向就无法通过 HTTPS 的方式访问了。</p><p>当然了,设置其他端口重定向到 HTTPS 也是可以的。</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> ServletWebServerFactory <span class="title">servletContainer</span><span class="params">()</span> </span>{</span><br><span class="line"> TomcatServletWebServerFactory tomcat = <span class="keyword">new</span> TomcatServletWebServerFactory() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">postProcessContext</span><span class="params">(Context context)</span> </span>{</span><br><span class="line"> SecurityConstraint securityConstraint = <span class="keyword">new</span> SecurityConstraint();</span><br><span class="line"> securityConstraint.setUserConstraint(<span class="string">"CONFIDENTIAL"</span>);</span><br><span class="line"> SecurityCollection collection = <span class="keyword">new</span> SecurityCollection();</span><br><span class="line"> collection.addPattern(<span class="string">"/*"</span>);</span><br><span class="line"> securityConstraint.addCollection(collection);</span><br><span class="line"> context.addConstraint(securityConstraint);</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> tomcat.addAdditionalTomcatConnectors(redirectConnector());</span><br><span class="line"> <span class="keyword">return</span> tomcat;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">private</span> Connector <span class="title">redirectConnector</span><span class="params">()</span> </span>{</span><br><span class="line"> Connector connector = <span class="keyword">new</span> Connector(</span><br><span class="line"> TomcatServletWebServerFactory.DEFAULT_PROTOCOL);</span><br><span class="line"> connector.setScheme(<span class="string">"http"</span>);</span><br><span class="line"> connector.setPort(<span class="number">80</span>);</span><br><span class="line"> connector.setSecure(<span class="keyword">false</span>);</span><br><span class="line"> connector.setRedirectPort(<span class="number">8443</span>);</span><br><span class="line"> <span class="keyword">return</span> connector;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><p><a href="https://juejin.im/post/5b44b4fef265da0f767530f7" target="_blank" rel="noopener">一文教你将 SpringBoot 网站升级为 HTTPS</a></p><p><a href="https://www.heydari.be/spring-boot-application-secured-by-a-lets-encrypt-certificate/" target="_blank" rel="noopener">Spring Boot Application Secured by Let’s Encrypt Certificate</a></p><p><a href="openssl pkcs12 -export -in crt1 -inkey private.key -out keystore.p12 -name tomcat -CAfile CAcrt -caname root">Spring Boot Secured By Let’s Encrypt</a></p><p><a href="https://github.com/spring-projects/spring-boot/issues/9836" target="_blank" rel="noopener">redirect http to https in Spring boot 2.0.0 M2</a></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>终于写完了,写了好几个小时。</p><p>比上午第一次弄还要久,不过总算是搞定了,下次再弄应该就不会那么费劲了。</p>]]></content>
<summary type="html">
<p>有个🔒的感觉就是 8 一样嗷。</p>
</summary>
<category term="Spring Boot" scheme="/categories/Spring-Boot/"/>
</entry>
<entry>
<title>通过表单上传 Blob 对象</title>
<link href="/2018/12/articles/%E9%80%9A%E8%BF%87%E8%A1%A8%E5%8D%95%E4%B8%8A%E4%BC%A0%20Blob%20%E5%AF%B9%E8%B1%A1/"/>
<id>/2018/12/articles/通过表单上传 Blob 对象/</id>
<published>2018-12-16T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.939Z</updated>
<content type="html"><![CDATA[<p>获取到 Blob 对象之后,如何通过表单提交?</p><a id="more"></a><h1 id="目的"><a href="#目的" class="headerlink" title="目的"></a>目的</h1><p>在 Javascript 中获取到了 Blob 对象,希望将 Blob 对象传递给后端。</p><h1 id="条件"><a href="#条件" class="headerlink" title="条件"></a>条件</h1><p>在 HTML 中有一个 form 表单,form 中有一个可以上传文件的 input 输入框。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">input</span> <span class="attr">id</span>=<span class="string">"recordInput"</span> <span class="attr">type</span>=<span class="string">"file"</span> <span class="attr">name</span>=<span class="string">"file"</span>></span></span><br></pre></td></tr></table></figure><p>但是这个输入框只能点击 -> 选择文件,那么如何将 Blob 与输入框联系起来呢?</p><h1 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h1><p>可以直接看这个回答:</p><p><a href="https://stackoverflow.com/questions/50157450/send-blob-object-with-post-form" target="_blank" rel="noopener">Send Blob object with POST Form</a></p><p>首先需要这个方法,它将 File 对象转换成一个 FileList 对象:</p><figure class="highlight javascript"><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"><span class="function"><span class="keyword">function</span> <span class="title">createFileList</span>(<span class="params">a</span>) </span>{</span><br><span class="line"> a = [].slice.call(<span class="built_in">Array</span>.isArray(a) ? a : <span class="built_in">arguments</span>);</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> c, b = c = a.length, d = !<span class="number">0</span>; b-- && d;) d = a[b] <span class="keyword">instanceof</span> File;</span><br><span class="line"> <span class="keyword">if</span> (!d) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">TypeError</span>(<span class="string">'expected argument to FileList is File or array of File objects'</span>);</span><br><span class="line"> <span class="keyword">for</span> (b = (<span class="keyword">new</span> ClipboardEvent(<span class="string">''</span>)).clipboardData || <span class="keyword">new</span> DataTransfer; c--;) b.items.add(a[c]);</span><br><span class="line"> <span class="keyword">return</span> b.files;</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>之所以要转换,是因为 input 元素中有一个属性:files,它的类型就是 FileList,必须要转换才可以进行赋值。<em>(注意:并没有 file 这个属性。)</em></p><p>第二步,设置 input 的 files 属性(使用 jQuery 查找元素):</p><figure class="highlight javascript"><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 class="keyword">var</span> recInput = $(<span class="string">"#recordInput"</span>)[<span class="number">0</span>];</span><br><span class="line">recInput.files = createFileList(<span class="keyword">new</span> File([blob], <span class="string">"my-record.mp3"</span>, {<span class="attr">type</span>: <span class="string">"audio/mp3"</span>}));</span><br></pre></td></tr></table></figure><p>这样一来,不用点击选择文件,input 框就已经选中文件了。</p><p><img src="https://md-img-1252869657.cos.ap-shanghai.myqcloud.com/hexo/Snipaste_2018-12-17_22-25-20.png" alt></p><p>后端简略代码:</p><figure class="highlight java"><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"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">IndexController</span> </span>{</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> String path = <span class="string">"D:\\del\\"</span>;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@PostMapping</span>(<span class="string">"/upload"</span>)</span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">upload</span><span class="params">(@RequestParam(name = <span class="string">"file"</span>)</span> MultipartFile file) </span>{</span><br><span class="line"> System.out.println(file);</span><br><span class="line"></span><br><span class="line"> File file1 = <span class="keyword">new</span> File(path + <span class="string">"aa.mp3"</span>);</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> file.transferTo(file1);</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> file.getOriginalFilename();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><ul><li>Blob、File、FileList 各自是一种类型,而且 File 是 Blob 的子类。</li><li>查找元素时即使通过 ID 查找,也要使用下标 [0] 选择元素</li></ul>]]></content>
<summary type="html">
<p>获取到 Blob 对象之后,如何通过表单提交?</p>
</summary>
<category term="Javascript" scheme="/categories/Javascript/"/>
</entry>
<entry>
<title>Centos nginx 配置 https</title>
<link href="/2018/12/articles/Centos%20nginx%20%E9%85%8D%E7%BD%AE%20https/"/>
<id>/2018/12/articles/Centos nginx 配置 https/</id>
<published>2018-12-12T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.923Z</updated>
<content type="html"><![CDATA[<p>在腾讯云主机上给 nginx 配置 https。</p><a id="more"></a><h1 id="前提"><a href="#前提" class="headerlink" title="前提"></a>前提</h1><ul><li>安装了 nginx(在<a href="http://nginx.org/download/" target="_blank" rel="noopener">这里</a>下载 nginx-1.9.9.tar.gz),解压,通过 make 命令安装。</li><li>准备好证书,这里是腾讯云备案送一年的证书。</li><li>为了上传文件方便,下载<a href="https://winscp.net/eng/download.php" target="_blank" rel="noopener">winscp</a>。</li></ul><h1 id="修改-nginx-配置"><a href="#修改-nginx-配置" class="headerlink" title="修改 nginx 配置"></a>修改 nginx 配置</h1><p>进入到 /usr/local/nginx/conf 目录下,修改 nginx.conf,添加一个:</p><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></pre></td><td class="code"><pre><span class="line">server {</span><br><span class="line"> listen 443;</span><br><span class="line"> server_name diaolizhi.com; #填写绑定证书的域名</span><br><span class="line"> ssl on;</span><br><span class="line"> ssl_certificate 1_diaolizhi.com_bundle.crt;</span><br><span class="line"> ssl_certificate_key 2_diaolizhi.com.key;</span><br><span class="line"> ssl_session_timeout 5m;</span><br><span class="line"> ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #按照这个协议配置</span><br><span class="line"> ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;#按照这个套件配置</span><br><span class="line"> ssl_prefer_server_ciphers on;</span><br><span class="line"> location / {</span><br><span class="line"> root html/record; #站点目录</span><br><span class="line"> index index.html index.htm;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>注意:站点目录的 html 前面没有斜杠。</strong></p><h2 id="报错"><a href="#报错" class="headerlink" title="报错"></a>报错</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nginx: [emerg] the "ssl" parameter requires ngx_http_ssl_module...</span><br></pre></td></tr></table></figure><p>提示没有 ssl 这个模块,参考博客:<a href="https://www.cnblogs.com/ghjbk/p/6744131.html" target="_blank" rel="noopener">博客园</a></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>在 Linux 安装 nginx 之后,可以配置不同的端口,每个端口可以对应 html 目录下的不同的文件夹。</p><p>只要添加一个 server,比如:</p><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></pre></td><td class="code"><pre><span class="line">server {</span><br><span class="line"> listen 8000;</span><br><span class="line"> server_name localhost;</span><br><span class="line"></span><br><span class="line"> location /{</span><br><span class="line"> root html/record;</span><br><span class="line"> index index.html index.htm;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>具体用到再百度吧。</p>]]></content>
<summary type="html">
<p>在腾讯云主机上给 nginx 配置 https。</p>
</summary>
<category term="nginx" scheme="/categories/nginx/"/>
</entry>
<entry>
<title>Spring Boot 集成 Shiro 实现权限控制</title>
<link href="/2018/12/articles/Spring%20Boot%20%E9%9B%86%E6%88%90%20Shiro%20%E5%AE%9E%E7%8E%B0%E6%9D%83%E9%99%90%E6%8E%A7%E5%88%B6/"/>
<id>/2018/12/articles/Spring Boot 集成 Shiro 实现权限控制/</id>
<published>2018-12-10T16:00:00.000Z</published>
<updated>2020-11-01T13:59:30.931Z</updated>
<content type="html"><![CDATA[<p>拥有指定的权限才可以进行相应的操作。</p><a id="more"></a><p>有一些操作是所有人都可以执行的,比如:访问首页、访问登录界面。而有一些就需要管理员权限,比如:删除用户。</p><p>为了实现这种功能,Shiro 提供了<strong>角色</strong>和<strong>权限</strong>两个概念。</p><p>推荐一篇博客:<a href="https://mrbird.cc/Spring-Boot-Shiro%20Authorization.html" target="_blank" rel="noopener">Spring Boot Shiro权限控制</a></p><p>我的理解是:一个用户对应一个或多个角色,一个角色又对应一个或多个权限。这样一来,用户就对应了多个明确的角色或者权限。然后设置接口所需要的角色或权限,实现权限控制。</p><p>在 Web 应用中,角色、权限都存放在数据库中,当然了还有用户表,以及<em>用户-角色表</em>、<em>角色-权限表</em>,总共有五个数据表。</p><p>当 Shiro 需要验证权限的时候,就需要从数据库中查找数据。</p><p>那么需要查找的是什么呢?</p><p>先看看 Shiro 需要的是什么。Realm 除了认证功能之外,还有授权的功能,对应的就是 doGetAuthorizationInfo 方法。在这个方法中返回的是一个 AuthorizationInfo 对象,而这个对象有两个方法:setRoles 和 setStringPermissions。</p><p>也就是说,Shiro 需要用户所对应的多个角色,以及多个权限。那么在数据访问层要做的就是查找一个用户所对应的角色和权限。</p><p>大概了解授权的流程之后,下面就具体说该怎么做。</p><h1 id="创建数据表"><a href="#创建数据表" class="headerlink" title="创建数据表"></a>创建数据表</h1><p>建议阅读上面推荐的文章,讲得比较详细。</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line">CREATE DATABASE <span class="comment">/*!32312 IF NOT EXISTS*/</span>`shiro-login` <span class="comment">/*!40100 DEFAULT CHARACTER SET utf8 */</span>;</span><br><span class="line"></span><br><span class="line">USE `shiro-login`;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*Table structure for table `t_permission` */</span></span><br><span class="line"></span><br><span class="line">DROP TABLE IF EXISTS `t_permission`;</span><br><span class="line"></span><br><span class="line">CREATE TABLE `t_permission` (</span><br><span class="line"> `id` <span class="keyword">int</span>(<span class="number">11</span>) NOT NULL AUTO_INCREMENT,</span><br><span class="line"> `url` varchar(<span class="number">50</span>) NOT NULL,</span><br><span class="line"> `name` varchar(<span class="number">100</span>) NOT NULL,</span><br><span class="line"> <span class="function">PRIMARY <span class="title">KEY</span> <span class="params">(`id`)</span></span></span><br><span class="line"><span class="function">) ENGINE</span>=InnoDB AUTO_INCREMENT=<span class="number">4</span> DEFAULT CHARSET=utf8;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*Table structure for table `t_role` */</span></span><br><span class="line"></span><br><span class="line">DROP TABLE IF EXISTS `t_role`;</span><br><span class="line"></span><br><span class="line">CREATE TABLE `t_role` (</span><br><span class="line"> `id` <span class="keyword">int</span>(<span class="number">11</span>) NOT NULL AUTO_INCREMENT,</span><br><span class="line"> `name` varchar(<span class="number">20</span>) NOT NULL,</span><br><span class="line"> `memo` varchar(<span class="number">50</span>) NOT NULL,</span><br><span class="line"> <span class="function">PRIMARY <span class="title">KEY</span> <span class="params">(`id`)</span></span></span><br><span class="line"><span class="function">) ENGINE</span>=InnoDB AUTO_INCREMENT=<span class="number">3</span> DEFAULT CHARSET=utf8;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*Table structure for table `t_role_permission` */</span></span><br><span class="line"></span><br><span class="line">DROP TABLE IF EXISTS `t_role_permission`;</span><br><span class="line"></span><br><span class="line">CREATE TABLE `t_role_permission` (</span><br><span class="line"> `rid` <span class="keyword">int</span>(<span class="number">11</span>) NOT NULL,</span><br><span class="line"> `pid` <span class="keyword">int</span>(<span class="number">11</span>) NOT NULL,</span><br><span class="line"> <span class="function">PRIMARY <span class="title">KEY</span> <span class="params">(`rid`,`pid`)</span></span></span><br><span class="line"><span class="function">) ENGINE</span>=InnoDB DEFAULT CHARSET=utf8;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*Table structure for table `t_user` */</span></span><br><span class="line"></span><br><span class="line">DROP TABLE IF EXISTS `t_user`;</span><br><span class="line"></span><br><span class="line">CREATE TABLE `t_user` (</span><br><span class="line"> `id` <span class="keyword">int</span>(<span class="number">11</span>) NOT NULL AUTO_INCREMENT,</span><br><span class="line"> `username` varchar(<span class="number">20</span>) NOT NULL,</span><br><span class="line"> `password` varchar(<span class="number">100</span>) NOT NULL,</span><br><span class="line"> `salt` varchar(<span class="number">20</span>) NOT NULL,</span><br><span class="line"> <span class="function">PRIMARY <span class="title">KEY</span> <span class="params">(`id`)</span>,</span></span><br><span class="line"><span class="function"> UNIQUE KEY `username` <span class="params">(`username`)</span></span></span><br><span class="line"><span class="function">) ENGINE</span>=InnoDB AUTO_INCREMENT=<span class="number">10</span> DEFAULT CHARSET=utf8;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*Table structure for table `t_user_role` */</span></span><br><span class="line"></span><br><span class="line">DROP TABLE IF EXISTS `t_user_role`;</span><br><span class="line"></span><br><span class="line">CREATE TABLE `t_user_role` (</span><br><span class="line"> `uid` <span class="keyword">int</span>(<span class="number">11</span>) NOT NULL,</span><br><span class="line"> `rid` <span class="keyword">int</span>(<span class="number">11</span>) NOT NULL,</span><br><span class="line"> <span class="function">PRIMARY <span class="title">KEY</span> <span class="params">(`uid`,`rid`)</span></span></span><br><span class="line"><span class="function">) ENGINE</span>=InnoDB DEFAULT CHARSET=utf8;</span><br></pre></td></tr></table></figure><h1 id="插入数据"><a href="#插入数据" class="headerlink" title="插入数据"></a>插入数据</h1><p>数据仅供参考,根据自己的设计插入数据。</p><figure class="highlight sql"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">DATABASE</span> <span class="comment">/*!32312 IF NOT EXISTS*/</span><span class="string">`shiro-login`</span> <span class="comment">/*!40100 DEFAULT CHARACTER SET utf8 */</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">USE</span> <span class="string">`shiro-login`</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*Data for the table `t_permission` */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">insert</span> <span class="keyword">into</span> <span class="string">`t_permission`</span>(<span class="string">`id`</span>,<span class="string">`url`</span>,<span class="string">`name`</span>) <span class="keyword">values</span> </span><br><span class="line">(<span class="number">1</span>,<span class="string">'/user'</span>,<span class="string">'user:add'</span>),</span><br><span class="line">(<span class="number">2</span>,<span class="string">'/user'</span>,<span class="string">'user:delete'</span>),</span><br><span class="line">(<span class="number">3</span>,<span class="string">'/user'</span>,<span class="string">'user:see'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*Data for the table `t_role` */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">insert</span> <span class="keyword">into</span> <span class="string">`t_role`</span>(<span class="string">`id`</span>,<span class="string">`name`</span>,<span class="string">`memo`</span>) <span class="keyword">values</span> </span><br><span class="line">(<span class="number">1</span>,<span class="string">'admin'</span>,<span class="string">'超级管理员'</span>),</span><br><span class="line">(<span class="number">2</span>,<span class="string">'test'</span>,<span class="string">'测试用户'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*Data for the table `t_role_permission` */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">insert</span> <span class="keyword">into</span> <span class="string">`t_role_permission`</span>(<span class="string">`rid`</span>,<span class="string">`pid`</span>) <span class="keyword">values</span> </span><br><span class="line">(<span class="number">1</span>,<span class="number">1</span>),</span><br><span class="line">(<span class="number">1</span>,<span class="number">2</span>),</span><br><span class="line">(<span class="number">1</span>,<span class="number">3</span>),</span><br><span class="line">(<span class="number">2</span>,<span class="number">3</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*Data for the table `t_user` */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">insert</span> <span class="keyword">into</span> <span class="string">`t_user`</span>(<span class="string">`id`</span>,<span class="string">`username`</span>,<span class="string">`password`</span>,<span class="string">`salt`</span>) <span class="keyword">values</span> </span><br><span class="line">(<span class="number">1</span>,<span class="string">'zs'</span>,<span class="string">'6f294b522deba0531722c92b4199c6b95d76b00e231ca2c765aae8c32fd36222'</span>,<span class="string">'zsreg'</span>),</span><br><span class="line">(<span class="number">2</span>,<span class="string">'root'</span>,<span class="string">'6a9629cd8b8c68a86c800cdeae59f2b3185bb6ce1c0896a675e91a860c7702ee'</span>,<span class="string">'rootreg'</span>),</span><br><span class="line">(<span class="number">3</span>,<span class="string">'admin'</span>,<span class="string">'dddf9fe0979a7db4fbf06a2366c5862e775fd702c56249decb372e876636b9ab'</span>,<span class="string">'adminreg'</span>),</span><br><span class="line">(<span class="number">8</span>,<span class="string">'aaa'</span>,<span class="string">'02d66435c563cc9130876fc5d7c1496e6b451345741b46d1472de3d6c82a8afa'</span>,<span class="string">'aaareg'</span>),</span><br><span class="line">(<span class="number">9</span>,<span class="string">'aaaa'</span>,<span class="string">'b344150010d7630f0422fdd9f491a450a8299831e28c78b2f5173ed5b1fd164e'</span>,<span class="string">'aaaareg'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*Data for the table `t_user_role` */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">insert</span> <span class="keyword">into</span> <span class="string">`t_user_role`</span>(<span class="string">`uid`</span>,<span class="string">`rid`</span>) <span class="keyword">values</span> </span><br><span class="line">(<span class="number">2</span>,<span class="number">1</span>),</span><br><span class="line">(<span class="number">9</span>,<span class="number">2</span>);</span><br></pre></td></tr></table></figure><h1 id="创建实体类"><a href="#创建实体类" class="headerlink" title="创建实体类"></a>创建实体类</h1><p>使用 IDEA 自动生成即可。</p><h1 id="UserRoleMapper"><a href="#UserRoleMapper" class="headerlink" title="UserRoleMapper"></a>UserRoleMapper</h1><p>根据用户名查找角色集:</p><figure class="highlight java"><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"><span class="meta">@Mapper</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">UserRoleMapper</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Select</span>(<span class="string">"SELECT t_role.name FROM t_role, t_user, t_user_role WHERE t_user.`id` = t_user_role.`uid` AND t_user.`username` = #{username} AND t_user_role.`rid` = t_role.`id`"</span>)</span><br><span class="line"> <span class="function">List<TRole> <span class="title">findRolesByUsername</span><span class="params">(String username)</span></span>;</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="UserPermissionMapper"><a href="#UserPermissionMapper" class="headerlink" title="UserPermissionMapper"></a>UserPermissionMapper</h1><p>根据用户名查找权限集:</p><figure class="highlight java"><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"><span class="meta">@Mapper</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">UserPermissionMapper</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Select</span>(<span class="string">"SELECT p.* FROM t_user u LEFT JOIN t_user_role ur ON u.`id` = ur.`uid` LEFT JOIN t_role r ON ur.`rid` = r.`id` LEFT JOIN t_role_permission rp ON r.`id` = rp.`rid` LEFT JOIN t_permission p ON rp.`pid` = p.`id` WHERE u.`username` = #{username} "</span>)</span><br><span class="line"> <span class="function">List<TPermission> <span class="title">findPermissonsByUsername</span><span class="params">(String username)</span></span>;</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="Realm-添加方法"><a href="#Realm-添加方法" class="headerlink" title="Realm 添加方法"></a>Realm 添加方法</h1><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="keyword">private</span> UserRoleMapper userRoleMapper;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="keyword">private</span> UserPermissionMapper userPermissionMapper;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> AuthorizationInfo <span class="title">doGetAuthorizationInfo</span><span class="params">(PrincipalCollection principals)</span> </span>{</span><br><span class="line"></span><br><span class="line"> String username = (String) SecurityUtils.getSubject().getPrincipal();</span><br><span class="line"></span><br><span class="line"> List<TRole> roles = userRoleMapper.findRolesByUsername(username);</span><br><span class="line"></span><br><span class="line"> SimpleAuthorizationInfo info = <span class="keyword">new</span> SimpleAuthorizationInfo();</span><br><span class="line"> Set<String> roleSet = <span class="keyword">new</span> HashSet<>();</span><br><span class="line"> <span class="keyword">for</span> (TRole t : roles) {</span><br><span class="line"> roleSet.add(t.getName());</span><br><span class="line"> System.out.println(t.getName());</span><br><span class="line"> }</span><br><span class="line"> info.setRoles(roleSet);</span><br><span class="line"></span><br><span class="line"> List<TPermission> ps = userPermissionMapper.findPermissonsByUsername(username);</span><br><span class="line"></span><br><span class="line"> Set<String> pSet = <span class="keyword">new</span> HashSet<>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (TPermission p : ps) {</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果在 mapper 没有查到任何数据,ps 也不为 null,但是 ps.get(0) 的值是 null</span></span><br><span class="line"> <span class="keyword">if</span> (p != <span class="keyword">null</span>) {</span><br><span class="line"> pSet.add(p.getName());</span><br><span class="line"> System.out.println(p.getName());</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"> info.setStringPermissions(pSet);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> info;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="添加权限控制"><a href="#添加权限控制" class="headerlink" title="添加权限控制"></a>添加权限控制</h1><h2 id="方法一:配置文件中"><a href="#方法一:配置文件中" class="headerlink" title="方法一:配置文件中"></a>方法一:配置文件中</h2><p>在 ShiroConfig 类的 shiroFilterChainDefinition 方法中:</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> ShiroFilterChainDefinition <span class="title">shiroFilterChainDefinition</span><span class="params">()</span> </span>{</span><br><span class="line"> DefaultShiroFilterChainDefinition chainDefinition = <span class="keyword">new</span> DefaultShiroFilterChainDefinition();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// authc 是必须通过认证,而不是“记住我”</span></span><br><span class="line"> chainDefinition.addPathDefinition(<span class="string">"/admin/**"</span>, <span class="string">"roles[admin]"</span>);</span><br><span class="line"></span><br><span class="line"> chainDefinition.addPathDefinition(<span class="string">"/me/**"</span>, <span class="string">"roles[admin]"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> chainDefinition;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="方法二:使用注解"><a href="#方法二:使用注解" class="headerlink" title="方法二:使用注解"></a>方法二:使用注解</h2><p>在 Controller 的接口上配置:</p><figure class="highlight java"><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"><span class="comment">// 表示当前Subject已经通过login进行了身份验证;即Subject.isAuthenticated()返回true。</span></span><br><span class="line"><span class="meta">@RequiresAuthentication</span> </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 表示当前Subject已经身份验证或者通过记住我登录的。</span></span><br><span class="line"><span class="meta">@RequiresUser</span> </span><br><span class="line"></span><br><span class="line"><span class="comment">// 表示当前Subject没有身份验证或通过记住我登录过,即是游客身份。</span></span><br><span class="line"><span class="meta">@RequiresGuest</span> </span><br><span class="line"></span><br><span class="line"><span class="comment">// 表示当前Subject需要角色admin和user。 </span></span><br><span class="line"><span class="meta">@RequiresRoles</span>(value={<span class="string">"admin"</span>, <span class="string">"user"</span>}, logical= Logical.AND) </span><br><span class="line"></span><br><span class="line"><span class="comment">// 表示当前Subject需要权限user:a或user:b。</span></span><br><span class="line"><span class="meta">@RequiresPermissions</span> (value={<span class="string">"user:a"</span>, <span class="string">"user:b"</span>}, logical= Logical.OR)</span><br></pre></td></tr></table></figure><h1 id="定义授权失败跳转页面"><a href="#定义授权失败跳转页面" class="headerlink" title="定义授权失败跳转页面"></a>定义授权失败跳转页面</h1><p>在 properties 文件中:</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">shiro.unauthorizedUrl=/error123</span><br><span class="line">shiro.loginUrl=/toLogin</span><br></pre></td></tr></table></figure><h1 id="捕获全局异常"><a href="#捕获全局异常" class="headerlink" title="捕获全局异常"></a>捕获全局异常</h1><h2 id="两种情况"><a href="#两种情况" class="headerlink" title="两种情况"></a>两种情况</h2><ul><li>一个接口使用注解指定了所需要的权限,当<strong>没有登录</strong>或者<strong>没有权限</strong>访问这个接口时,它不会跳转到失败页面,也不会跳转到登录页面,而是抛出一个异常。</li><li>在配置文件中指定一个接口所需的权限,那么它就会跳转到错误页面或者登录界面。</li></ul><p>为了解决第一种情况,就需要捕获异常:</p><figure class="highlight java"><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"><span class="meta">@RestControllerAdvice</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ShiroExceptionHandler</span> </span>{ </span><br><span class="line"> <span class="meta">@ExceptionHandler</span>(value = AuthorizationException.class)</span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">handleAuthorizationException</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"没有权限访问"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><ul><li>创建角色和权限</li><li>查询角色和权限</li><li>重写 doGetAuthorizationInfo</li><li>给接口配置权限</li></ul>]]></content>
<summary type="html">
<p>拥有指定的权限才可以进行相应的操作。</p>
</summary>
<category term="Spring Boot" scheme="/categories/Spring-Boot/"/>
</entry>
</feed>