Repository navigation
Expand file tree
/
Copy pathatom.xml
More file actions
582 lines (349 loc) · 386 KB
/
Copy pathatom.xml
File metadata and controls
582 lines (349 loc) · 386 KB
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
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>ZZY补完计划</title>
<link href="/atom.xml" rel="self"/>
<link href="https://github.com/zzycreate/"/>
<updated>2020-05-12T01:17:23.859Z</updated>
<id>https://github.com/zzycreate/</id>
<author>
<name>zzycreate</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Java常用对象转换之 Stream 流</title>
<link href="https://github.com/zzycreate/2019/07/14/java-convert-example-stream/"/>
<id>https://github.com/zzycreate/2019/07/14/java-convert-example-stream/</id>
<published>2019-07-14T19:23:47.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>平时的开发中会经常遇到一些对象需要转换,本项目记录一些常见对象转换的方法,例如:文件转换、日期时间转换、stream流转换、集合对象转换等, 具体的示例代码见 github 项目:<a href="https://github.com/zzycreate/java-convert-example">zzycreate/java-convert-example</a><br>本文记录一些常用的 Stream 操作,以备需要时直接使用</p></blockquote><a id="more"></a><h2 id="流的基本构成"><a href="#流的基本构成" class="headerlink" title="流的基本构成"></a>流的基本构成</h2><p>Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。<br>原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;<br>高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。</p><p>Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。</p><p>而和迭代器又不同的是,Stream 可以并行化操作,迭代器只能命令式地、串行化操作。<br>顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。</p><p>Stream 流的使用基本分为三种操作:生成 Stream 流数据源、Stream 流中值操作、Stream 流结束操作。另外还有 short-circuiting 操作作为补充。</p><h3 id="Stream-流的生成"><a href="#Stream-流的生成" class="headerlink" title="Stream 流的生成"></a>Stream 流的生成</h3><p>想要获取 Stream 流数据源有很多种方式:</p><ol><li>从集合中获取:集合对象(List、Set、Queue等)的 stream()、parallelStream() 方法可以直接获取 Stream 对象</li><li>从数组中获取:数据对象可以利用 Arrays.stream(T[] array) 或者 Stream.of() 的工具方法获取 Stream 对象</li><li>从IO流中获取:BufferedReader 提供了 lines() 方法可以逐行获取IO流里面的数据</li><li>静态工厂方法:Stream.of(Object[])、IntStream.range(int, int)、Stream.iterate(Object, UnaryOperator) 等静态工厂方法可以提供 Stream 对象</li><li>Files类的操作路径的方法:如list、find、walk等。</li><li>随机数流:Random.ints()</li><li>其他诸如 Random.ints()、BitSet.stream()、Pattern.splitAsStream(java.lang.CharSequence)、JarFile.stream() 等方法</li><li>更底层的使用StreamSupport,它提供了将Spliterator转换成流的方法。</li></ol><h3 id="Stream-流的中间操作-Intermediate"><a href="#Stream-流的中间操作-Intermediate" class="headerlink" title="Stream 流的中间操作(Intermediate)"></a>Stream 流的中间操作(Intermediate)</h3><p>一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。<br>这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。只有在 Terminal 操作执行时才会真正的执行这些 Intermediate 操作。</p><p>常用的 Intermediate 操作有:map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered</p><h3 id="Stream-流的执行操作-Terminal"><a href="#Stream-流的执行操作-Terminal" class="headerlink" title="Stream 流的执行操作(Terminal)"></a>Stream 流的执行操作(Terminal)</h3><p>一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。<br>Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。</p><p>常用的 Terminal 操作有:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator</p><h3 id="Short-circuiting"><a href="#Short-circuiting" class="headerlink" title="Short-circuiting"></a>Short-circuiting</h3><p>当操作一个无限大的 Stream,而又希望在有限时间内完成操作,则在管道内拥有一个 short-circuiting 操作是必要非充分条件。</p><p>常用的 Short-circuiting 操作有:anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit</p><h2 id="生成-Stream-流数据源"><a href="#生成-Stream-流数据源" class="headerlink" title="生成 Stream 流数据源"></a>生成 Stream 流数据源</h2><h3 id="集合对象-gt-Stream"><a href="#集合对象-gt-Stream" class="headerlink" title="集合对象 -> Stream"></a>集合对象 -> Stream</h3><p>集合对象本身提供了 stream() 和 parallelStream() ,两个方法可以直接获取 Stream 流</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Stream<String> listStream = list.stream();</span><br><span class="line">Stream<String> listParallelStream = list.parallelStream();</span><br><span class="line">Stream<String> setStream = set.stream();</span><br><span class="line">Stream<String> setParallelStream = set.parallelStream();</span><br></pre></td></tr></table></figure><h3 id="数组对象-gt-Stream"><a href="#数组对象-gt-Stream" class="headerlink" title="数组对象 -> Stream"></a>数组对象 -> Stream</h3><p>数组对象转换需要利用工具类 Arrays、 Stream 的静态方法</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Stream<String> arrayStream = Arrays.stream(array);</span><br><span class="line">Stream<String> arrayStream1 = Stream.of(array);</span><br></pre></td></tr></table></figure><h3 id="IO-流-gt-Stream"><a href="#IO-流-gt-Stream" class="headerlink" title="IO 流 -> Stream"></a>IO 流 -> Stream</h3><p>IO 流可以包装成 BufferedReader 转换为 Stream</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("input.txt"), StandardCharsets.UTF_8));</span><br><span class="line">Stream<String> stream = reader.lines();</span><br></pre></td></tr></table></figure><h3 id="流对象提供的构造方法"><a href="#流对象提供的构造方法" class="headerlink" title="流对象提供的构造方法"></a>流对象提供的构造方法</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">IntStream intStream = IntStream.range(1, 4);</span><br><span class="line">DoubleStream doubleStream = DoubleStream.builder().add(1.1).add(2.1).add(3.1).add(4.1).build();</span><br><span class="line">LongStream longStream = LongStream.of(1L, 2L, 3L, 4L);</span><br></pre></td></tr></table></figure><h2 id="Stream-流的-Intermediate-操作"><a href="#Stream-流的-Intermediate-操作" class="headerlink" title="Stream 流的 Intermediate 操作"></a>Stream 流的 Intermediate 操作</h2><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/stream/StreamIntermediateExample.java">StreamIntermediateExample.java</a></p><h3 id="map"><a href="#map" class="headerlink" title="map"></a>map</h3><p>map 的作用就是把 input Stream 的每一个元素,映射成 output Stream 的另外一个元素。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">// 转大写</span><br><span class="line">List<String> stringList = list.stream()</span><br><span class="line"> .map(String::toUpperCase)</span><br><span class="line"> .collect(Collectors.toList()); // [ABC, EFG, HIJ]</span><br><span class="line"></span><br><span class="line">// 数据计算</span><br><span class="line">List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9).stream()</span><br><span class="line"> .map(n -> n * n)</span><br><span class="line"> .collect(Collectors.toList()); // [1, 4, 9, 16, 25, 36, 49, 64, 81]</span><br><span class="line"></span><br><span class="line">// 获取对象属性</span><br><span class="line">List<String> list = list.stream()</span><br><span class="line"> .map(Item::getDetail).map(ItemDetail::getValue)</span><br><span class="line"> .collect(Collectors.toList()); // [v1, v5, v3, v2, v4]</span><br></pre></td></tr></table></figure><h3 id="flatMap"><a href="#flatMap" class="headerlink" title="flatMap"></a>flatMap</h3><p>flatMap 把 input Stream 中的层级结构扁平化</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Stream<List<Integer>> inputStream = Stream.of(</span><br><span class="line"> Arrays.asList(1),</span><br><span class="line"> Arrays.asList(2, 3),</span><br><span class="line"> Arrays.asList(4, 5, 6)</span><br><span class="line">);</span><br><span class="line">// 将集合对象里面的数据拿出来转换为扁平结构</span><br><span class="line">Stream<Integer> outputStream = inputStream.</span><br><span class="line"> flatMap((childList) -> childList.stream()); // [1, 2, 3, 4, 5, 6]</span><br></pre></td></tr></table></figure><h3 id="filter"><a href="#filter" class="headerlink" title="filter"></a>filter</h3><p>filter 对原始 Stream 进行某项测试,<strong>通过</strong>测试的元素被留下来生成一个新 Stream。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Integer[] sixNums = {1, 2, 3, 4, 5, 6};</span><br><span class="line">// 对2取模等于0的是偶数,filter留下数字中的偶数</span><br><span class="line">Integer[] evens = Stream.of(sixNums)</span><br><span class="line"> .filter(n -> n % 2 == 0)</span><br><span class="line"> .toArray(Integer[]::new); // [2, 4, 6]</span><br></pre></td></tr></table></figure><h3 id="distinct"><a href="#distinct" class="headerlink" title="distinct"></a>distinct</h3><p>distinct 是对元素进行去重,去重是利用了对象的 hashCode() 和 equals() 方法</p><p>如果distinct()正在处理有序流,那么对于重复元素,将保留以遭遇顺序首先出现的元素,并且以这种方式选择不同元素是稳定的。<br>在无序流的情况下,不同元素的选择不一定是稳定的,是可以改变的。distinct()执行有状态的中间操作。<br>在有序流的并行流的情况下,保持distinct()的稳定性是需要很高的代价的,因为它需要大量的缓冲开销。<br>如果我们不需要保持遭遇顺序的一致性,那么我们应该可以使用通过BaseStream.unordered()方法实现的无序流。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Integer[] nums = {1, 1, 2, 3, 4, 5, 4, 5, 6};</span><br><span class="line">Integer[] evens = Stream.of(nums)</span><br><span class="line"> .distinct()</span><br><span class="line"> .toArray(Integer[]::new);// [1, 2, 3, 4, 5, 6]</span><br></pre></td></tr></table></figure><h3 id="sorted"><a href="#sorted" class="headerlink" title="sorted"></a>sorted</h3><p>sorted 方法用于排序,利用 Comparator 类的静态方法可以快速构造一个比较器实现排序。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">List<Integer> list = Arrays.asList(5, 2, 4, 8, 6, 1, 9, 3, 7);</span><br><span class="line"></span><br><span class="line">// sorted() 无参方法为自然排序</span><br><span class="line">List<Integer> sorted = list.stream().sorted().collect(Collectors.toList());// [1, 2, 3, 4, 5, 6, 7, 8, 9]</span><br><span class="line"></span><br><span class="line">// 使用 Comparator.reverseOrder() 获得一个自然逆序比较器,用于逆序排序</span><br><span class="line">List<Integer> reverse = list.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());// [1, 2, 3, 4, 5, 6, 7, 8, 9]</span><br><span class="line"></span><br><span class="line">// 使用 Comparator.comparing() 获取一个自定义比较器,显现自定义对象的排序</span><br><span class="line">List<Item> codeSorted = StreamIntermediateExample.newItems().stream()</span><br><span class="line"> .sorted(Comparator.comparing(Item::getCode))</span><br><span class="line"> .collect(Collectors.toList());</span><br><span class="line">// [Item(name=Name1, code=1, number=1.1, detail=ItemDetail(id=101, value=v1)), Item(name=Name2, code=2, number=2.2, detail=ItemDetail(id=202, value=v2)), Item(name=Name3, code=3, number=3.3, detail=ItemDetail(id=303, value=v3)), Item(name=Name4, code=4, number=4.4, detail=ItemDetail(id=404, value=v4)), Item(name=Name5, code=5, number=5.5, detail=ItemDetail(id=505, value=v5))]</span><br><span class="line"></span><br><span class="line">List<Item> codeReverse = StreamIntermediateExample.newItems().stream()</span><br><span class="line"> .sorted(Comparator.comparing(Item::getCode).reversed())</span><br><span class="line"> .collect(Collectors.toList());</span><br><span class="line">// [Item(name=Name5, code=5, number=5.5, detail=ItemDetail(id=505, value=v5)), Item(name=Name4, code=4, number=4.4, detail=ItemDetail(id=404, value=v4)), Item(name=Name3, code=3, number=3.3, detail=ItemDetail(id=303, value=v3)), Item(name=Name2, code=2, number=2.2, detail=ItemDetail(id=202, value=v2)), Item(name=Name1, code=1, number=1.1, detail=ItemDetail(id=101, value=v1))]</span><br></pre></td></tr></table></figure><h3 id="unordered"><a href="#unordered" class="headerlink" title="unordered"></a>unordered</h3><p>某些流的返回的元素是有确定顺序的,我们称之为 encounter order。这个顺序是流提供它的元素的顺序,比如数组的encounter order是它的元素的排序顺序,List是它的迭代顺序(iteration order),对于HashSet,它本身就没有encounter order。</p><p>一个流是否是encounter order主要依赖数据源和它的中间操作,比如数据源List和Array上创建的流是有序的(ordered),但是在HashSet创建的流不是有序的。</p><p>sorted()方法可以将流转换成encounter order的,unordered可以将流转换成encounter order的。</p><p>注意,这个方法并不是对元素进行排序或者打散,而是返回一个是否encounter order的流。</p><p>可以参见 stackoverflow 上的问题: <a href="https://stackoverflow.com/questions/21350195/stream-ordered-unordered-problems" target="_blank" rel="noopener">stream-ordered-unordered-problems</a></p><p>除此之外,一个操作可能会影响流的有序,比如map方法,它会用不同的值甚至类型替换流中的元素,所以输入元素的有序性已经变得没有意义了,但是对于filter方法来说,它只是丢弃掉一些值而已,输入元素的有序性还是保障的。</p><p>对于串行流,流有序与否不会影响其性能,只是会影响确定性(determinism),无序流在多次执行的时候结果可能是不一样的。</p><p>对于并行流,去掉有序这个约束可能会提高性能,比如distinct、groupingBy这些聚合操作。</p><h3 id="peek"><a href="#peek" class="headerlink" title="peek"></a>peek</h3><p>peek() 接受一个 Consumer 消费者方法,而 map() 接受一个 Function 方法; Consumer 方法返回值是 void,而 Function 方法有返回值,peek 和 map 方法的区别主要在于流处理过程中返回值的不同。<br>peek() 方法是 Intermediate 方法,而 forEach() 方法是 Terminal 方法; 如果 peek 方法后没有 Terminal 方法,则 peek 并不会真正的执行,forEach 方法则会立即执行。<br>forEach 和 peek 都是接受 Consumer 对象的,因此如果在 Stream 流处理的过程中做一些数据操作或者打印操作,选择 peek 方法,该方法还会返回 Stream 流,用于下一步处理; 如果已经是处理的最后一步,则选择 forEach 用于最终执行整个流。 </p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">// [Abc, efG, HiJ] -> [Abc, efG, HiJ]</span><br><span class="line">List<String> peek = StreamIntermediateExample.newStringList().stream()</span><br><span class="line"> .peek(str -> {</span><br><span class="line"> if ("Abc".equals(str)) {</span><br><span class="line"> str = str.toUpperCase();</span><br><span class="line"> }</span><br><span class="line"> }).collect(Collectors.toList());</span><br></pre></td></tr></table></figure><p>peek 方法对对象的修改,会影响到集合里面的元素,但如果集合中是 String 这种,则不会改变,<br>因为修改后的 String 在常量池中是另一个对象,由于 Consumer 无法返回该对象,Stream 内的元素仍然指向原来的 String。<br>对对象的修改则是改变堆中对象的数据,对象的引用并没有发生变化,Stream 中的元素任然指向原对象,只是对象内部已经发生了改变。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">// [Name1, Name5, Name3, Name2, Name4] -> [xxx, Name5, Name3, Name2, Name4]</span><br><span class="line">List<String> peek1 = StreamIntermediateExample.newItems().stream()</span><br><span class="line"> .peek(item -> {</span><br><span class="line"> if (item.getCode() == 1) {</span><br><span class="line"> item.setName("xxx");</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> .map(Item::getName)</span><br><span class="line"> .collect(Collectors.toList());</span><br></pre></td></tr></table></figure><h3 id="limit"><a href="#limit" class="headerlink" title="limit"></a>limit</h3><p>limit 方法会对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素;</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/5HBDY6enzbM1SrA.jpg" alt="stream-limit" title> </div> <div class="image-caption">stream-limit</div> </figure><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);</span><br><span class="line"></span><br><span class="line">// 截取指定元素位置以内的元素</span><br><span class="line">List<Integer> limit2 = numbers.stream().limit(2).collect(Collectors.toList());// [1, 2]</span><br><span class="line"></span><br><span class="line">List<Integer> limit6 = numbers.stream().limit(6).collect(Collectors.toList());// [1, 2, 3, 4, 5, 6]</span><br><span class="line"></span><br><span class="line">List<Integer> limit8 = numbers.stream().limit(8).collect(Collectors.toList());// [1, 2, 3, 4, 5, 6]</span><br></pre></td></tr></table></figure><h3 id="skip"><a href="#skip" class="headerlink" title="skip"></a>skip</h3><p>skip 方法会返回一个丢弃原Stream的前N个元素后剩下元素组成的新Stream,如果原Stream中包含的元素个数小于N,那么返回空Stream;</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/hTcN1CvDeRrQW2t.jpg" alt="stream-limit" title> </div> <div class="image-caption">stream-limit</div> </figure><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);</span><br><span class="line"></span><br><span class="line">// 忽略指定元素位置以内的元素</span><br><span class="line">List<Integer> skip2 = numbers.stream().skip(2).collect(Collectors.toList());// [3, 4, 5, 6]</span><br><span class="line"></span><br><span class="line">List<Integer> skip6 = numbers.stream().skip(6).collect(Collectors.toList());// []</span><br><span class="line"></span><br><span class="line">List<Integer> skip8 = numbers.stream().skip(8).collect(Collectors.toList());// []</span><br></pre></td></tr></table></figure><h3 id="parallel"><a href="#parallel" class="headerlink" title="parallel"></a>parallel</h3><p>parallel stream是基于fork/join框架的,简单点说就是使用多线程来完成的,使用parallel stream时要考虑初始化fork/join框架的时间,<br>如果要执行的任务很简单,那么初始化fork/join框架的时间会远多于执行任务所需时间,也就导致了效率的降低.<br>根据附录doug Lee的说明,任务数量*执行方法的行数>=10000或者执行的是消耗大量时间操作(如io/数据库)才有必要使用</p><p>Java 8为ForkJoinPool添加了一个通用线程池,这个线程池用来处理那些没有被显式提交到任何线程池的任务。<br>它是ForkJoinPool类型上的一个静态元素,它拥有的默认线程数量等于运行计算机上的处理器数量。<br>当调用Arrays类上添加的新方法时,自动并行化就会发生。<br>比如用来排序一个数组的并行快速排序,用来对一个数组中的元素进行并行遍历。自动并行化也被运用在Java 8新添加的Stream API中。</p><p>并行流是 JDK8 对多线程的应用,但是难以控制,要想用好并行流,需要深入理解 ForkJoinPool 。<br>以下的例子详阅:<a href="https://blog.csdn.net/u011001723/article/details/52794455" target="_blank" rel="noopener">深入浅出parallelStream</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">System.out.println("Hello World!");</span><br><span class="line">// 构造一个10000个元素的集合</span><br><span class="line">List<Integer> list = new ArrayList<>();</span><br><span class="line">for (int i = 0; i < 10000; i++) {</span><br><span class="line"> list.add(i);</span><br><span class="line">}</span><br><span class="line">// 统计并行执行list的线程</span><br><span class="line">Set<Thread> threadSet = new CopyOnWriteArraySet<>();</span><br><span class="line">// 并行执行</span><br><span class="line">list.stream().parallel().forEach(integer -> {</span><br><span class="line"> Thread thread = Thread.currentThread();</span><br><span class="line"> // System.out.println(thread);</span><br><span class="line"> // 统计并行执行list的线程</span><br><span class="line"> threadSet.add(thread);</span><br><span class="line">});</span><br><span class="line">System.out.println("threadSet一共有" + threadSet.size() + "个线程"); // 6</span><br><span class="line">System.out.println("系统一个有" + Runtime.getRuntime().availableProcessors() + "个cpu"); // 8</span><br><span class="line">List<Integer> list1 = new ArrayList<>();</span><br><span class="line">List<Integer> list2 = new ArrayList<>();</span><br><span class="line">for (int i = 0; i < 100000; i++) {</span><br><span class="line"> list1.add(i);</span><br><span class="line"> list2.add(i);</span><br><span class="line">}</span><br><span class="line">Set<Thread> threadSetTwo = new CopyOnWriteArraySet<>();</span><br><span class="line">CountDownLatch countDownLatch = new CountDownLatch(2);</span><br><span class="line">Thread threadA = new Thread(() -> {</span><br><span class="line"> list1.stream().parallel().forEach(integer -> {</span><br><span class="line"> Thread thread = Thread.currentThread();</span><br><span class="line"> // System.out.println("list1" + thread);</span><br><span class="line"> threadSetTwo.add(thread);</span><br><span class="line"> });</span><br><span class="line"> countDownLatch.countDown();</span><br><span class="line">});</span><br><span class="line">Thread threadB = new Thread(() -> {</span><br><span class="line"> list2.stream().parallel().forEach(integer -> {</span><br><span class="line"> Thread thread = Thread.currentThread();</span><br><span class="line"> // System.out.println("list2" + thread);</span><br><span class="line"> threadSetTwo.add(thread);</span><br><span class="line"> });</span><br><span class="line"> countDownLatch.countDown();</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">threadA.start();</span><br><span class="line">threadB.start();</span><br><span class="line">countDownLatch.await();</span><br><span class="line">System.out.println("threadSetTwo一共有" + threadSetTwo.size() + "个线程"); // 9</span><br><span class="line"></span><br><span class="line">System.out.println("---------------------------");</span><br><span class="line">// [Thread[main,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-3,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-1,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-4,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-5,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-2,5,main]]</span><br><span class="line">System.out.println(threadSet);</span><br><span class="line">// [Thread[ForkJoinPool.commonPool-worker-6,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-7,5,main],</span><br><span class="line">// Thread[Thread-0,5,],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-5,5,main],</span><br><span class="line">// Thread[Thread-1,5,],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-4,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-3,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-2,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-1,5,main]]</span><br><span class="line">System.out.println(threadSetTwo);</span><br><span class="line">System.out.println("---------------------------");</span><br><span class="line">threadSetTwo.addAll(threadSet);</span><br><span class="line">// [Thread[ForkJoinPool.commonPool-worker-6,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-7,5,main],</span><br><span class="line">// Thread[Thread-0,5,],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-5,5,main],</span><br><span class="line">// Thread[Thread-1,5,],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-4,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-3,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-2,5,main],</span><br><span class="line">// Thread[ForkJoinPool.commonPool-worker-1,5,main],</span><br><span class="line">// Thread[main,5,main]]</span><br><span class="line">// 执行forEach本身的线程也作为线程池中的一个工作线程</span><br><span class="line">System.out.println(threadSetTwo);</span><br><span class="line">System.out.println("threadSetTwo一共有" + threadSetTwo.size() + "个线程");</span><br><span class="line">System.out.println("系统一个有" + Runtime.getRuntime().availableProcessors() + "个cpu");</span><br></pre></td></tr></table></figure><h3 id="sequential"><a href="#sequential" class="headerlink" title="sequential"></a>sequential</h3><p>通过parallel()方法可以将串行流转换成并行流,sequential()方法将流转换成串行流。</p><p>顺序流和并行流相对,这种使用的方法很少,暂时没有研究。</p><h2 id="Stream-流的-Terminal-操作"><a href="#Stream-流的-Terminal-操作" class="headerlink" title="Stream 流的 Terminal 操作"></a>Stream 流的 Terminal 操作</h2><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/stream/StreamTerminalExample.java">StreamTerminalExample.java</a></p><h3 id="collect"><a href="#collect" class="headerlink" title="collect"></a>collect</h3><p>collect 方法是 Terminal 操作,可以将 Stream 流转换为集合,Collectors 中提供了一些便捷的生成 Collector 的方法,<br>例如 <code>toList()</code> 用于生成 List 列表,<code>toSet()</code> 可以用于生成 Set 堆,<code>toMap()</code> 可以用于生成 Map。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">List<String> list = Arrays.asList("apple", "orange", "banana", "pear");</span><br><span class="line">List<String> collectList = list.stream().filter(s -> s.length() > 5).collect(Collectors.toList());//[orange, banana]</span><br><span class="line">Set<String> collectSet = list.stream().filter(s -> s.length() > 5).collect(Collectors.toSet());// [orange, banana]</span><br></pre></td></tr></table></figure><p><code>Collectors.toMap()</code> 有三个重构方法,推荐至少使用三个参数的 toMap() 方法,<code>BinaryOperator<U> mergeFunction</code><br>这个参数有利于解决,生成Map时的主键重复问题,避免因为源数据问题产生问题。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Map<Integer, Item> collectMap1 = items.stream()</span><br><span class="line"> .collect(Collectors.toMap(Item::getCode, Function.identity()));</span><br><span class="line">Map<Integer, Item> collectMap2 = StreamConstant.newItems().stream()</span><br><span class="line"> .collect(Collectors.toMap(Item::getCode, Function.identity(), (a, b) -> a));</span><br></pre></td></tr></table></figure><p><code>toCollection()</code> 可以用于生成各种各样自定义的集合结构。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Stack<String> collect = items.stream()</span><br><span class="line"> .map(Item::getName)</span><br><span class="line"> .collect(Collectors.toCollection(Stack::new));</span><br></pre></td></tr></table></figure><p>Collector包含四种不同的操作:supplier(初始构造器), accumulator(累加器), combiner(组合器), finisher(终结者)。</p><p>简单分组:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Map<Integer, List<Item>> groupingByCollect = StreamConstant.newItems().stream()</span><br><span class="line"> .collect(Collectors.groupingBy(Item::getCode));</span><br></pre></td></tr></table></figure><p>平均值:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Double average = StreamConstant.newItems().stream()</span><br><span class="line"> .collect(Collectors.averagingInt(Item::getCode));</span><br></pre></td></tr></table></figure><p>统计:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">IntSummaryStatistics summaryStatistics = StreamConstant.newItems().stream()</span><br><span class="line"> .collect(Collectors.summarizingInt(Item::getCode));// IntSummaryStatistics{count=5, sum=15, min=1, average=3.000000, max=5}</span><br></pre></td></tr></table></figure><p>拼接(三个参数分别是:连接符、字符串前缀、字符串后缀):</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">String join = list.stream()</span><br><span class="line"> .collect(Collectors.joining(" and ", "The ", " are fruits"));// The apple and orange and banana and pear are fruits</span><br></pre></td></tr></table></figure><p><code>Collector.of()</code> 方法可以创建了一个新的collector,我们必须给这个collector提供四种功能:supplier, accumulator, combiner,finisher.</p><p>supplier 初始化构造分割符;accumulator 处理数据,并叠加数据;combiner 进行数据连接,finisher 生成最终数据。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Collector<Item, StringJoiner, String> personNameCollector =</span><br><span class="line"> Collector.of(</span><br><span class="line"> () -> new StringJoiner(" | "), // supplier</span><br><span class="line"> (j, p) -> j.add(p.getName().toUpperCase()), // accumulator</span><br><span class="line"> (j1, j2) -> j1.merge(j2), // combiner</span><br><span class="line"> StringJoiner::toString); // finisher</span><br><span class="line">String names = StreamConstant.newItems().stream()</span><br><span class="line"> .collect(personNameCollector);</span><br><span class="line">System.out.println(names); // NAME1 | NAME5 | NAME3 | NAME2 | NAME4</span><br></pre></td></tr></table></figure><h3 id="toArray"><a href="#toArray" class="headerlink" title="toArray"></a>toArray</h3><p><code>toArray()</code> 方法可以将流中的数据放入一个数组中。无参方法只能生成 <code>Object[]</code> 对象数组,单参方法可以指定生成的数组类型。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">List<String> list = Arrays.asList("apple", "orange", "banana", "pear");</span><br><span class="line">Object[] objects = list.stream().filter(s -> s.length() > 5).toArray();</span><br><span class="line">String[] strings = list.stream().filter(s -> s.length() > 5).toArray(String[]::new);</span><br></pre></td></tr></table></figure><h3 id="forEach-forEachOrdered"><a href="#forEach-forEachOrdered" class="headerlink" title="forEach/forEachOrdered"></a>forEach/forEachOrdered</h3><p>forEach 方法接收一个 Lambda 表达式,然后在 Stream 的每一个元素上执行该表达式。</p><p>一般认为,forEach 和常规 for 循环的差异不涉及到性能,它们仅仅是函数式风格与传统 Java 风格的差别。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">// Java 8</span><br><span class="line">list.stream()</span><br><span class="line"> .filter(s -> s.length() > 5)</span><br><span class="line"> .forEach(System.out::println);</span><br><span class="line">// Pre-Java 8</span><br><span class="line">for (String s : list) {</span><br><span class="line"> if (s.length() > 5) {</span><br><span class="line"> System.out.println(s);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>forEach 是 terminal 操作,因此它执行后,Stream 的元素就被“消费”掉了,你无法对一个 Stream 进行两次 terminal 运算。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Stream<String> stream = list.stream().filter(s -> s.length() > 5);</span><br><span class="line">stream.forEach(element -> System.out.println("1: "+element));// ok</span><br><span class="line">stream.forEach(element -> System.out.println("2: "+element));// java.lang.IllegalStateException: stream has already been operated upon or closed</span><br></pre></td></tr></table></figure><p>要想实现上述类似功能,可以使用 peek 方法,peek是中间方法,流还没有被消费掉。或者利用Supplier提供者,Supplier的get方法可以构造新的Stream。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Supplier<Stream<String>> streamSupplier= () -> (list.stream().filter(s -> s.length() > 5));</span><br><span class="line">streamSupplier.get().forEach(element -> System.out.println("1: "+element));</span><br><span class="line">streamSupplier.get().forEach(element -> System.out.println("2: "+element));</span><br></pre></td></tr></table></figure><p>forEachOrdered 是为了保证执行后数据的有序性。</p><h3 id="reduce"><a href="#reduce" class="headerlink" title="reduce"></a>reduce</h3><p>Stream 的 reduce 方法,返回单个的结果值,并且reduce操作每处理一个元素总是创建一个新值。常用的方法有average、sum、min、max、count,都可以使用reduce方法实现。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"><U> U reduce(U identity,BiFunction<U,? super T,U> accumulator,BinaryOperator<U> combiner)</span><br><span class="line">#第一个参数identity返回实例u,传递你要返回的U类型对象的初始化实例u, 用于提供一个循环计算的初始值</span><br><span class="line"></span><br><span class="line">#第二个参数累加器accumulator,可以使用二元ℷ表达式(即二元lambda表达式),声明你在u上累加你的数据来源t的逻辑</span><br><span class="line">#例如(u,t)->u.sum(t),此时lambda表达式的行参列表是返回实例u和遍历的集合元素t,函数体是在u上累加t</span><br><span class="line">#BinaryOperator 的函数方法为 apply(U u, T t), 第一个参数为上次函数计算的返回值,第二个参数为 Stream 中的元素,函数方法会将两个值计算apply,得到的值赋值给下次执行该方法的第一个参数</span><br><span class="line"></span><br><span class="line">#第三个参数组合器combiner,同样是二元ℷ表达式,(u,t)->u</span><br><span class="line">#lambda表达式行参列表同样是(u,t),函数体返回的类型则要和第一个参数的类型保持一致</span><br></pre></td></tr></table></figure><p>具体的一个示例:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Supplier<Stream<Integer>> supplier = () -> (Stream.of(1, 2, 3, 4).filter(p -> p > 2));</span><br><span class="line">List<Integer> result = supplier.get()</span><br><span class="line"> .collect(() -> new ArrayList<>(), (list, item) -> list.add(item), (one, two) -> one.addAll(two));</span><br><span class="line">System.out.println(result);// [3, 4]</span><br><span class="line">/* 或者使用方法引用 */</span><br><span class="line">result = supplier.get().collect(ArrayList::new, List::add, List::addAll);</span><br><span class="line">System.out.println(result);// [3, 4]</span><br></pre></td></tr></table></figure><h3 id="min-max-count"><a href="#min-max-count" class="headerlink" title="min/max/count"></a>min/max/count</h3><p>一般比较大小需要比较器 Comparator, min 和 max 返回值类型是 Optional。</p><p>count 是对满足条件的数据进行统计,计算次数。等价于 <code>return mapToLong(e -> 1L).sum();</code></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Supplier<Stream<Integer>> supplier = () -> (Stream.of(1, 2, 3, 4).filter(p -> p > 2));</span><br><span class="line">Optional<Integer> min = supplier.get().min(Integer::compareTo);// Optional[3]</span><br><span class="line">Optional<Integer> max = supplier.get().max(Integer::compareTo);// Optional[4]</span><br><span class="line">long count = supplier.get().count();// 2</span><br></pre></td></tr></table></figure><h3 id="anyMatch-allMatch-noneMatch"><a href="#anyMatch-allMatch-noneMatch" class="headerlink" title="anyMatch/allMatch/noneMatch"></a>anyMatch/allMatch/noneMatch</h3><ul><li>allMatch:Stream 中全部元素符合传入的 predicate,返回 true</li><li>anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true</li><li>noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true</li></ul><p>它们都不是要遍历全部元素才能返回结果。例如 allMatch 只要一个元素不满足条件,就 skip 剩下的所有元素,返回 false。对清单 13 中的 Person 类稍做修改,加入一个 age 属性和 getAge 方法。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">boolean b1 = StreamConstant.newItems().stream().map(Item::getCode).anyMatch(i -> i > 3);// true</span><br><span class="line">boolean b2 = StreamConstant.newItems().stream().map(Item::getCode).anyMatch(i -> i > 5);// false</span><br><span class="line">boolean b3 = StreamConstant.newItems().stream().map(Item::getCode).allMatch(i -> i > 3);// false</span><br><span class="line">boolean b4 = StreamConstant.newItems().stream().map(Item::getCode).allMatch(i -> i > 5);// false</span><br><span class="line">boolean b5 = StreamConstant.newItems().stream().map(Item::getCode).noneMatch(i -> i > 3);// false</span><br><span class="line">boolean b6 = StreamConstant.newItems().stream().map(Item::getCode).noneMatch(i -> i > 5);// true</span><br></pre></td></tr></table></figure><h3 id="findFirst-findAny"><a href="#findFirst-findAny" class="headerlink" title="findFirst/findAny"></a>findFirst/findAny</h3><p>findFirst 是一个 termimal 兼 short-circuiting 操作,它总是返回 Stream 的第一个元素,或者空。<br>findAny 是搜索到任何一个符合条件的结果返回,因为流可能是并行的,因此顺序可能不是确定的。如果顺序是确定的,使用 findFirst 可以方便的获取第一个元素。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Optional<String> first = StreamConstant.newStringList().stream().findFirst();// Optional[Abc]</span><br><span class="line">String any = StreamConstant.newStringList().stream()</span><br><span class="line"> .filter(s -> s.length() > 5).findAny().orElse("ERROR");// ERROR</span><br></pre></td></tr></table></figure><h2 id="有效的特殊用法"><a href="#有效的特殊用法" class="headerlink" title="有效的特殊用法"></a>有效的特殊用法</h2><h3 id="自定义去重"><a href="#自定义去重" class="headerlink" title="自定义去重"></a>自定义去重</h3><p>利用 Map 的 key 不能重复的特性进行去重,实现下方静态方法,在需要的使用结合 filter 和 distinctByKey 方法进行去重。</p><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/stream/tools/DistinctByKey.java">DistinctByKey.java</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {</span><br><span class="line"> Map<Object, Boolean> seen = new ConcurrentHashMap<>();</span><br><span class="line"> // putIfAbsent 如果map中有值,则返回原值,新值也不会放入map中,如果原来没有值,则返回null,本次put的值也会放入map中</span><br><span class="line"> return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>使用的时候只需要使用 filter 过滤掉重复项:</p><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/stream/StreamSpecialExample.java">StreamSpecialExample.java</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">items.stream().filter(distinctByKey(Item::getName)).collect(Collectors.toList());</span><br></pre></td></tr></table></figure><h3 id="求和"><a href="#求和" class="headerlink" title="求和"></a>求和</h3><p>BigDecimal 对象求和:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">//计算 总金额</span><br><span class="line">BigDecimal totalMoney = stream().map(Item::getDetail).map(ItemDetail::getMoney)</span><br><span class="line"> .reduce(BigDecimal.ZERO, BigDecimal::add);</span><br><span class="line">System.err.println("totalMoney:" + totalMoney.setScale(2, RoundingMode.HALF_UP)); //totalMoney:166.50</span><br></pre></td></tr></table></figure><p>基本类型求和:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">//计算 数量</span><br><span class="line">double sum = stream().mapToDouble(Item::getNumber).sum();</span><br><span class="line">System.err.println("sum:" + sum); //sum:16.5</span><br></pre></td></tr></table></figure><p>参考文章:<br><a href="https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/index.html" target="_blank" rel="noopener">Java 8 中的 Streams API 详解</a><br><a href="https://colobu.com/2016/03/02/Java-Stream/#%E6%8E%92%E5%BA%8F_Ordering" target="_blank" rel="noopener">Java Stream 详解 ——鸟窝</a><br><a href="https://www.jianshu.com/p/0c07597d8311" target="_blank" rel="noopener">Java 8 Stream 教程</a></p>]]></content>
<summary type="html">
<blockquote>
<p>平时的开发中会经常遇到一些对象需要转换,本项目记录一些常见对象转换的方法,例如:文件转换、日期时间转换、stream流转换、集合对象转换等, 具体的示例代码见 github 项目:<a href="https://github.com/zzycreate/java-convert-example">zzycreate/java-convert-example</a><br>本文记录一些常用的 Stream 操作,以备需要时直接使用</p>
</blockquote>
</summary>
<category term="编码" scheme="https://github.com/zzycreate/categories/%E7%BC%96%E7%A0%81/"/>
<category term="Java" scheme="https://github.com/zzycreate/tags/Java/"/>
<category term="java-convert-example" scheme="https://github.com/zzycreate/tags/java-convert-example/"/>
<category term="Stream" scheme="https://github.com/zzycreate/tags/Stream/"/>
<category term="JDK8" scheme="https://github.com/zzycreate/tags/JDK8/"/>
</entry>
<entry>
<title>Java常用对象转换之时间操作</title>
<link href="https://github.com/zzycreate/2019/06/29/java-convert-example-datetime/"/>
<id>https://github.com/zzycreate/2019/06/29/java-convert-example-datetime/</id>
<published>2019-06-29T17:07:47.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>平时的开发中会经常遇到一些对象需要转换,本项目记录一些常见对象转换的方法,例如:文件转换、日期时间转换、stream流转换、集合对象转换等, 具体的示例代码见 github 项目:<a href="https://github.com/zzycreate/java-convert-example">zzycreate/java-convert-example</a><br>本文记录一些常用的时间操作,以备需要时直接使用</p></blockquote><a id="more"></a><h2 id="java-的时间操作-API"><a href="#java-的时间操作-API" class="headerlink" title="java 的时间操作 API"></a>java 的时间操作 API</h2><h3 id="java-util-包的时间操作"><a href="#java-util-包的时间操作" class="headerlink" title="java.util 包的时间操作"></a>java.util 包的时间操作</h3><p><code>jdk 1.1</code> 就开始提供了基础的日期时间相关的功能,<code>java.util.Date</code>、<code>java.util.Calendar</code>、<code>java.text.DateFormat</code>、<code>java.sql.Date</code>、<code>java.sql.Time</code>、<br><code>java.sql.Timestamp</code> 等是 <code>jdk 1.1</code> 中常用的日期时间类,<code>java.util.Date</code> 代表了时间,<code>java.util.Calendar</code> 代表了日期,<code>java.text.DateFormat</code><br>用于格式化时间,<code>java.sql.Date</code> 是 <code>java.util.Date</code> 的包装类,代表了数据库中的 DATE,<code>java.sql.Time</code> 代表数据库的时间(不含日期), <code>java.sql.Timestamp</code> 代表了数据库的 TIMESTAMP。</p><p>SimpleDateFormat 时间格式化常用字符及含义:</p><table><thead><tr><th>字母</th><th>含义</th><th>示例</th></tr></thead><tbody><tr><td>G</td><td>纪元</td><td>在 Locale.CHINA语言环境下,如 ‘公元’;<br>在Locale.US语言环境下,如 ‘AD’</td></tr><tr><td>y</td><td>年份。一般用 yy 表示两位年份,yyyy 表示 4 位年份</td><td>使用 yy 表示的年扮,如 11;<br>使用 yyyy 表示的年份,如 2011</td></tr><tr><td>M</td><td>月份。一般用 MM 表示月份,如果使用 MMM,则会根据语言环境显示不同语言的月份</td><td>使用 MM 表示的月份,如 05;<br>使用 MMM 表示月份,在 Locale.CHINA语言环境下,如“十月”;<br>在Locale.US语言环境下,如 Oct</td></tr><tr><td>d</td><td>月份中的天数。一般用 dd 表示天数</td><td>使用 dd 表示的天数,如 10</td></tr><tr><td>D</td><td>年份中的天数。表示当天是当年的第几天, 用 D 表示</td><td>使用 D 表示的年份中的天数,如 295</td></tr><tr><td>E</td><td>星期几。用 E 表示,会根据语言环境的不同, 显示不同语言的星期几</td><td>使用 E 表示星期几,<br>在 Locale.CHINA 语言环境下,如“星期四”;<br>在 Locale.US 语言环境下,如 Thu</td></tr><tr><td>H</td><td>一天中的小时数(0~23)。一般用 HH 表示小时数</td><td>使用 HH 表示的小时数,如 18</td></tr><tr><td>h</td><td>一天中的小时数(1~12)。一般使用hh表 示小时数</td><td>使用 hh 表示的小时数,如 10 (注意 10 有可能是 10 点,也可能是 22 点)</td></tr><tr><td>m</td><td>分钟数。一般使用 mm 表示分钟数</td><td>使用 mm 表示的分钟数,如 29</td></tr><tr><td>s</td><td>秒数。一般使用 ss 表示秒数</td><td>使用 ss 表示的秒数,如 38</td></tr><tr><td>S</td><td>毫秒数。一般使用 SSS 表示毫秒数</td><td>使用 SSS 表示的毫秒数,如 156</td></tr></tbody></table><p><code>Date</code> 代表了一个特定的时间,可以精确到毫秒,也能表示年月日等日期概念。</p><p>但 util 中的日期时间操作存在一些问题:</p><ol><li>Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。</li><li>java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。</li><li>对于时间、时间戳、格式化以及解析,并没有一些明确定义的类。对于格式化和解析的需求,我们有java.text.DateFormat抽象类,但通常情况下,SimpleDateFormat类被用于此类需求。</li><li>所有的日期类都是可变的,因此他们都不是线程安全的,这是Java日期类最大的问题之一。</li><li>日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。</li></ol><h3 id="java-time-包的时间操作"><a href="#java-time-包的时间操作" class="headerlink" title="java.time 包的时间操作"></a>java.time 包的时间操作</h3><p>Java 8 新增的日期时间 API 遵循 JSR 310 设计规范,解决上述 API 中的缺陷。</p><p>主要的操作对象有:</p><ol><li>java.time.LocalTime: 时间</li><li>java.time.LocalDate: 日期</li><li>java.time.LocalDateTime: 日期/时间</li><li>java.time.ZoneId: 时区</li><li>java.time.ZoneOffset: 时区偏移量</li><li>java.time.ZonedDateTime: 带时区信息的日期/时间</li><li>java.time.Instant: 时刻(时间戳)</li><li>java.time.Duration java.time.Period: 时间段</li></ol><p>这些对象都是线程安全,且不可变,API 方法设计简单,转换容易,配合 <code>java.time.format.DateTimeFormatter</code> 可以很容易的进行格式化。</p><p>以上这些对象的关联关系:</p><ol><li>LocalDateTime = LocalDate + LocalTime</li><li>ZonedDateTime = LocalDateTime + ZoneId/ZoneOffset</li><li>Instant = seconds + nano</li></ol><p>Java 8日期/时间API是JSR-310的实现,它的实现目标是克服旧的日期时间实现中所有的缺陷,新的日期/时间API的一些设计原则是:</p><ol><li>不变性:新的日期/时间API中,所有的类都是不可变的,这对多线程环境有好处。</li><li>关注点分离:新的API将人可读的日期时间和机器时间(unix timestamp)明确分离,它为日期(Date)、时间(Time)、日期时间(DateTime)、时间戳(unix timestamp)以及时区定义了不同的类。</li><li>清晰:在所有的类中,方法都被明确定义用以完成相同的行为。举个例子,要拿到当前实例我们可以使用now()方法,在所有的类中都定义了format()和parse()<br>方法,而不是像以前那样专门有一个独立的类。为了更好的处理问题,所有的类都使用了工厂模式和策略模式,一旦你使用了其中某个类的方法,与其他类协同工作并不困难。</li><li>实用操作:所有新的日期/时间API类都实现了一系列方法用以完成通用的任务,如:加、减、格式化、解析、从日期/时间中提取单独部分,等等。</li><li>可扩展性:新的日期/时间API是工作在ISO-8601日历系统上的,但我们也可以将其应用在非IOS的日历上。</li></ol><h2 id="java-1-1-日期-时间操作"><a href="#java-1-1-日期-时间操作" class="headerlink" title="java 1.1 日期/时间操作"></a>java 1.1 日期/时间操作</h2><h3 id="对象构造"><a href="#对象构造" class="headerlink" title="对象构造"></a>对象构造</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">// 毫秒值</span><br><span class="line">long timestamp = System.currentTimeMillis();</span><br><span class="line"></span><br><span class="line">// java.util.Date 除了一下两种构造方法,其他构造方法均已过期</span><br><span class="line">Date date = new Date();</span><br><span class="line">Date date1 = new Date(timestamp);</span><br><span class="line"></span><br><span class="line">// sql date/time/timestamp 是针对SQL语言使用的,Date只有日期而没有时间,Time只有时间而没有日期</span><br><span class="line">java.sql.Date sqlDate = new java.sql.Date(timestamp);</span><br><span class="line">java.sql.Date sqlDate1 = new java.sql.Date(date1.getTime());</span><br><span class="line">java.sql.Time sqlTime = new java.sql.Time(timestamp);</span><br><span class="line">java.sql.Time sqlTime1 = new java.sql.Time(date1.getTime());</span><br><span class="line">java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(timestamp);</span><br><span class="line">java.sql.Timestamp sqlTimestamp1 = new java.sql.Timestamp(date1.getTime());</span><br><span class="line"></span><br><span class="line">// Calendar 代表日历, GregorianCalendar 代表公历</span><br><span class="line">Calendar calendar = Calendar.getInstance();</span><br><span class="line">GregorianCalendar gregorianCalendar = new GregorianCalendar();</span><br></pre></td></tr></table></figure><h3 id="对象取值"><a href="#对象取值" class="headerlink" title="对象取值"></a>对象取值</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">long timestamp = System.currentTimeMillis();</span><br><span class="line">Date date = new Date(timestamp);</span><br><span class="line">java.sql.Date sqlDate = new java.sql.Date(timestamp);</span><br><span class="line">java.sql.Time sqlTime = new java.sql.Time(timestamp);</span><br><span class="line">java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(timestamp);</span><br><span class="line">Calendar calendar = Calendar.getInstance();</span><br><span class="line">GregorianCalendar gregorianCalendar = new GregorianCalendar();</span><br><span class="line"></span><br><span class="line">// Date 除了 getTime() 方法可以获取时间戳毫秒值外,其他 get 方法在 jdk8 中均已过期,不推荐时间</span><br><span class="line">// sql date/time/timestamp 均为 util date 的子类,过期方法类似</span><br><span class="line">long s = date.getTime();</span><br><span class="line">long sqlTimes = sqlDate.getTime();</span><br><span class="line">long sqlTime1 = sqlTime.getTime();</span><br><span class="line">long sqlTime2 = sqlTimestamp.getTime();</span><br><span class="line">long sqlNano1 = sqlTimestamp.getNanos();</span><br><span class="line">long sqlNano2 = sqlTimestamp.getNanos();</span><br><span class="line"></span><br><span class="line">Date calendarTime = calendar.getTime();</span><br><span class="line">int year = calendar.get(Calendar.YEAR);</span><br><span class="line">// 由于月份是从0开始,一般 +1 之后才和人的主观感受一致</span><br><span class="line">int month = calendar.get(Calendar.MONTH) + 1;</span><br><span class="line">int dateNum = calendar.get(Calendar.DATE);</span><br><span class="line">int hour = calendar.get(Calendar.HOUR_OF_DAY);</span><br><span class="line">int minute = calendar.get(Calendar.MINUTE);</span><br><span class="line">int second = calendar.get(Calendar.SECOND);</span><br><span class="line">// 星期</span><br><span class="line">int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);</span><br><span class="line">// 日期</span><br><span class="line">int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);</span><br><span class="line"></span><br><span class="line">boolean isLeapYear = gregorianCalendar.isLeapYear(year);</span><br></pre></td></tr></table></figure><h2 id="java-8-日期-时间操作"><a href="#java-8-日期-时间操作" class="headerlink" title="java 8 日期/时间操作"></a>java 8 日期/时间操作</h2><p>JSR 303 的日期时间对象虽然多,但是操作的 API 基本类似,很容易理解,以下距离没有列举所有情况,但其他操作基本类似。</p><h3 id="对象构造-1"><a href="#对象构造-1" class="headerlink" title="对象构造"></a>对象构造</h3><p>对象的创建基本都是 now (当前时间)、of (静态构造方法)、parse (文本解析)、at (维度组合)、to (对象转换)、between (区间) 等简单明了的 API。</p><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/datetime/Jdk8TimeExample.java">Jdk8TimeExample.java</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">LocalTime time = LocalTime.now();</span><br><span class="line">LocalTime time1 = LocalTime.of(13, 14, 15);</span><br><span class="line">LocalTime time2 = LocalTime.ofSecondOfDay(47655);</span><br><span class="line">LocalTime time3 = LocalTime.parse("13:14:15");</span><br><span class="line"></span><br><span class="line">LocalDate date = LocalDate.now();</span><br><span class="line">LocalDate date1 = LocalDate.of(2019, 5, 10);</span><br><span class="line">LocalDate date2 = LocalDate.ofYearDay(2019, 130);</span><br><span class="line">LocalDate date3 = LocalDate.parse("2019-05-10");</span><br><span class="line"></span><br><span class="line">LocalDateTime dateTime = LocalDateTime.now();</span><br><span class="line">LocalDateTime dateTime1 = LocalDateTime.of(2019, 5, 10, 13, 14, 15);</span><br><span class="line">LocalDateTime dateTime2 = LocalDateTime.of(date, time);</span><br><span class="line">LocalDateTime dateTime3 = date.atStartOfDay();</span><br><span class="line">LocalDateTime dateTime4 = date.atTime(time);</span><br><span class="line">LocalDateTime dateTime5 = date.atTime(13, 14, 15);</span><br><span class="line">LocalDateTime dateTime6 = time.atDate(date);</span><br><span class="line"></span><br><span class="line">ZonedDateTime zonedDateTime = ZonedDateTime.now();</span><br><span class="line">ZonedDateTime zonedDateTime1 = dateTime.atZone(ZoneId.systemDefault());</span><br><span class="line">ZonedDateTime zonedDateTime2 = dateTime.atZone(ZoneId.of("Asia/Shanghai"));</span><br><span class="line"></span><br><span class="line">LocalDateTime dateTime7 = zonedDateTime.toLocalDateTime();</span><br><span class="line">LocalDate date4 = zonedDateTime.toLocalDate();</span><br><span class="line">LocalTime time4 = zonedDateTime.toLocalTime();</span><br><span class="line"></span><br><span class="line">Instant instant = dateTime.toInstant(ZoneOffset.of("+08:00"));</span><br><span class="line">Instant instant1 = zonedDateTime.toInstant();</span><br><span class="line">Instant instant2 = new Date().toInstant();</span><br><span class="line"></span><br><span class="line">Duration duration = Duration.between(time, time1);</span><br><span class="line">Period period = Period.between(date, date1);</span><br></pre></td></tr></table></figure><h3 id="对象取值和比较"><a href="#对象取值和比较" class="headerlink" title="对象取值和比较"></a>对象取值和比较</h3><p>对象的 get 方法可以获取对象结构的组成部分,is方法可以用做时间的简单判断。</p><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/datetime/Jdk8TimeExample.java">Jdk8TimeExample.java</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">ZonedDateTime zonedDateTime = ZonedDateTime.now();</span><br><span class="line">LocalDateTime dateTime = zonedDateTime.toLocalDateTime();</span><br><span class="line">LocalDate date = dateTime.toLocalDate();</span><br><span class="line">LocalTime time = dateTime.toLocalTime();</span><br><span class="line"></span><br><span class="line">int year = date.getYear();</span><br><span class="line">Month month = date.getMonth();</span><br><span class="line">int monthValue = date.getMonthValue();</span><br><span class="line">int dayOfYear = date.getDayOfYear();</span><br><span class="line">int dayOfMonth = date.getDayOfMonth();</span><br><span class="line">DayOfWeek dayOfWeek = date.getDayOfWeek();</span><br><span class="line"></span><br><span class="line">int hour = time.getHour();</span><br><span class="line">int minute = time.getMinute();</span><br><span class="line">int second = time.getSecond();</span><br><span class="line">int nano = time.getNano();</span><br><span class="line"></span><br><span class="line">ZoneId zone = zonedDateTime.getZone();</span><br><span class="line">ZoneOffset offset = zonedDateTime.getOffset();</span><br><span class="line"></span><br><span class="line">LocalDateTime now = LocalDateTime.now();</span><br><span class="line"></span><br><span class="line">boolean isBefore = dateTime.isBefore(now);</span><br><span class="line">boolean isAfter = dateTime.isAfter(now);</span><br><span class="line">boolean isLeapYear = dateTime.toLocalDate().isLeapYear();</span><br></pre></td></tr></table></figure><h3 id="时间加减"><a href="#时间加减" class="headerlink" title="时间加减"></a>时间加减</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">LocalDate date = LocalDate.now();</span><br><span class="line">LocalDate minus1 = date.minus(1, ChronoUnit.DAYS);</span><br><span class="line">LocalDate date1 = date.minusDays(1);</span><br><span class="line">LocalDate date2 = date.minusMonths(2);</span><br><span class="line">LocalDate plus1 = date.plus(1, ChronoUnit.WEEKS);</span><br><span class="line">LocalDate date3 = date.plusYears(1);</span><br><span class="line"></span><br><span class="line">LocalTime time = LocalTime.now();</span><br><span class="line">LocalTime minus2 = time.minus(1, ChronoUnit.SECONDS);</span><br><span class="line">LocalTime time1 = time.minusSeconds(2);</span><br><span class="line">LocalTime time2 = time.minusMinutes(30);</span><br><span class="line">LocalTime plus2 = time.plus(3, ChronoUnit.HALF_DAYS);</span><br><span class="line">LocalTime time3 = time.plusHours(2);</span><br><span class="line"></span><br><span class="line">LocalDateTime dateTime = LocalDateTime.now();</span><br><span class="line"></span><br><span class="line">LocalDateTime minus = dateTime.minus(10, ChronoUnit.SECONDS);</span><br><span class="line">LocalDateTime dateTime1 = dateTime.minusSeconds(10L);</span><br><span class="line">LocalDateTime dateTime2 = dateTime.minusDays(10L);</span><br><span class="line"></span><br><span class="line">LocalDateTime plus = dateTime.plus(10, ChronoUnit.SECONDS);</span><br><span class="line">LocalDateTime dateTime3 = dateTime.plusMinutes(10L);</span><br><span class="line">LocalDateTime dateTime4 = dateTime.plusMonths(5);</span><br></pre></td></tr></table></figure><h2 id="类型转换"><a href="#类型转换" class="headerlink" title="类型转换"></a>类型转换</h2><blockquote><p>以下为 jdk 1.1 时间日期与 jdk1.8 时间日期的转换</p></blockquote><h3 id="Date-gt-Instant"><a href="#Date-gt-Instant" class="headerlink" title="Date -> Instant"></a>Date -> Instant</h3><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/datetime/DateLocalDateTimeConvertExample.java">DateLocalDateTimeConvertExample.java</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Instant instant = new Date().toInstant();</span><br><span class="line">Instant instant1 = Instant.ofEpochMilli(new Date().getTime())</span><br></pre></td></tr></table></figure><h3 id="Date-gt-LocalDateTime-LocalDate-LocalTime"><a href="#Date-gt-LocalDateTime-LocalDate-LocalTime" class="headerlink" title="Date -> LocalDateTime/LocalDate/LocalTime"></a>Date -> LocalDateTime/LocalDate/LocalTime</h3><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/datetime/DateLocalDateTimeConvertExample.java">DateLocalDateTimeConvertExample.java</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());</span><br><span class="line">LocalDate localDate = LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault()).toLocalDate();</span><br><span class="line">LocalTime localTime = LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault()).toLocalTime();</span><br></pre></td></tr></table></figure><h3 id="Instant-gt-Date"><a href="#Instant-gt-Date" class="headerlink" title="Instant -> Date"></a>Instant -> Date</h3><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/datetime/DateLocalDateTimeConvertExample.java">DateLocalDateTimeConvertExample.java</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Date date = new Date(Instant.now().toEpochMilli());</span><br></pre></td></tr></table></figure><h3 id="LocalDateTime-gt-Date"><a href="#LocalDateTime-gt-Date" class="headerlink" title="LocalDateTime -> Date"></a>LocalDateTime -> Date</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Date date = new Date(LocalDateTime.now().toInstant(ZoneOffset.of("+08:00")).toEpochMilli());</span><br></pre></td></tr></table></figure><blockquote><p>以下为字符串与时间日期的转换</p></blockquote><h3 id="String-gt-Date"><a href="#String-gt-Date" class="headerlink" title="String -> Date"></a>String -> Date</h3><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/datetime/DateTimeStringExample.java">DateTimeStringExample.java</a></p><p>使用 <code>SimpleDateFormat</code> 按照格式解析字符串,可能会出现异常,格式见前文表格。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try {</span><br><span class="line"> SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");</span><br><span class="line"> Date date = sdf.parse("2019-01-02 15:23:46");</span><br><span class="line">} catch (ParseException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>或者间接利用 LocalDateTime 进行字符串解析</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");</span><br><span class="line">LocalDateTime localDateTime = LocalDateTime.parse("2019-05-10 13:14:15", dateTimeFormatter);</span><br><span class="line">Date date = Date.from(localDateTime.toInstant(ZoneOffset.of("+08:00")));</span><br></pre></td></tr></table></figure><h3 id="String-gt-LocalDateTime"><a href="#String-gt-LocalDateTime" class="headerlink" title="String -> LocalDateTime"></a>String -> LocalDateTime</h3><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/datetime/DateTimeStringExample.java">DateTimeStringExample.java</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");</span><br><span class="line">LocalDateTime dateTime = DateTimeStringExample.toLocalDateTime("2019-05-10 13:14:15", dateTimeFormatter);</span><br></pre></td></tr></table></figure><h3 id="Date-gt-String"><a href="#Date-gt-String" class="headerlink" title="Date -> String"></a>Date -> String</h3><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/datetime/DateExample.java">DateExample.java</a></p><p>利用 <code>SimpleDateFormat</code> 进行时间的格式化:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");</span><br><span class="line">String str = sdf.format(new Date);</span><br></pre></td></tr></table></figure><p>利用 <code>DateTimeFormatter</code> 进行时间的格式化:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());</span><br><span class="line">DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");</span><br><span class="line">String str = zonedDateTime.format(dateTimeFormatter);</span><br></pre></td></tr></table></figure><h3 id="Instant-gt-String"><a href="#Instant-gt-String" class="headerlink" title="Instant -> String"></a>Instant -> String</h3><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/datetime/DateExample.java">DateExample.java</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">ZonedDateTime zonedDateTime = Instant.now().atZone(ZoneId.systemDefault());</span><br><span class="line">DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");</span><br><span class="line">String str = zonedDateTime.format(dateTimeFormatter);</span><br></pre></td></tr></table></figure><h3 id="Date-Instant-gt-epochMilli"><a href="#Date-Instant-gt-epochMilli" class="headerlink" title="Date/Instant -> epochMilli"></a>Date/Instant -> epochMilli</h3><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/datetime/DateExample.java">DateExample.java</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">long epochMilli = new Date().getTime();</span><br><span class="line">long epochMilli1 = Instant.now().toEpochMilli();</span><br><span class="line">long epochMilli2 = new Date().toInstant().toEpochMilli();</span><br></pre></td></tr></table></figure><h3 id="epochMilli-gt-Date-Instant"><a href="#epochMilli-gt-Date-Instant" class="headerlink" title="epochMilli -> Date/Instant"></a>epochMilli -> Date/Instant</h3><p>示例代码: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/datetime/DateExample.java">DateExample.java</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">long epochMilli = System.currentTimeMillis();</span><br><span class="line">Date date = new Date(epochMilli);</span><br><span class="line">Instant instant = Instant.ofEpochMilli(epochMilli);</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<blockquote>
<p>平时的开发中会经常遇到一些对象需要转换,本项目记录一些常见对象转换的方法,例如:文件转换、日期时间转换、stream流转换、集合对象转换等, 具体的示例代码见 github 项目:<a href="https://github.com/zzycreate/java-convert-example">zzycreate/java-convert-example</a><br>本文记录一些常用的时间操作,以备需要时直接使用</p>
</blockquote>
</summary>
<category term="编码" scheme="https://github.com/zzycreate/categories/%E7%BC%96%E7%A0%81/"/>
<category term="Java" scheme="https://github.com/zzycreate/tags/Java/"/>
<category term="java-convert-example" scheme="https://github.com/zzycreate/tags/java-convert-example/"/>
<category term="datetime" scheme="https://github.com/zzycreate/tags/datetime/"/>
<category term="JSR 310" scheme="https://github.com/zzycreate/tags/JSR-310/"/>
</entry>
<entry>
<title>Java常用对象转换之文件操作</title>
<link href="https://github.com/zzycreate/2019/05/04/java-convert-example-file/"/>
<id>https://github.com/zzycreate/2019/05/04/java-convert-example-file/</id>
<published>2019-05-04T21:07:47.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>平时的开发中会经常遇到一些对象需要转换,本项目记录一些常见对象转换的方法,例如:文件转换、日期时间转换、stream流转换、集合对象转换等, 具体的示例代码见 github 项目:<a href="https://github.com/zzycreate/java-convert-example">zzycreate/java-convert-example</a><br>本文记录一些常用的文件操作,以备需要时直接使用</p></blockquote><a id="more"></a><h2 id="文件"><a href="#文件" class="headerlink" title="文件"></a>文件</h2><p>Java 为文件操作设计了很多的类,有数据相关的 IO Stream 流,与文件相关的File、Path等对文件系统的抽象。<br>Java 的 io 包和几乎包含了所有操作输入、输出需要的类,另外 java1.4 开始推出的 nio 接口能更高效的完成一些工作。<br>Java io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。所有这些流类代表了输入源和输出目标。<br>一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。 </p><h3 id="IO"><a href="#IO" class="headerlink" title="IO"></a>IO</h3><h4 id="IO-流分类:"><a href="#IO-流分类:" class="headerlink" title="IO 流分类:"></a>IO 流分类:</h4><ul><li>按照流的流向分,可以分为输入流和输出流;</li><li>按照操作单元划分,可以划分为字节流和字符流;</li><li>按照流的角色划分为节点流和处理流。</li></ul><p>按照操作方式分类:</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/B51QcvfjrkKzygM.jpg" alt="java IO Stream 操作方式分类" title> </div> <div class="image-caption">java IO Stream 操作方式分类</div> </figure><p>按照操作对象分类:</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/T5cL6VxDgeqHvb2.jpg" alt="java IO Stream 操作对象分类" title> </div> <div class="image-caption">java IO Stream 操作对象分类</div> </figure><h4 id="IO-流基础对象:"><a href="#IO-流基础对象:" class="headerlink" title="IO 流基础对象:"></a>IO 流基础对象:</h4><ul><li>InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。</li><li>OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。</li></ul><h3 id="NIO"><a href="#NIO" class="headerlink" title="NIO"></a>NIO</h3><p>java 1.4 版本后,重新设计出了一套新的 IO 接口:Non-blocking IO(NIO)</p><h4 id="NIO-与-IO-的区别:"><a href="#NIO-与-IO-的区别:" class="headerlink" title="NIO 与 IO 的区别:"></a>NIO 与 IO 的区别:</h4><ol><li>IO是面向流的,NIO是面向缓冲区的;</li><li>IO流是阻塞的,NIO流是不阻塞的;</li><li>NIO有选择器,而IO没有。</li></ol><h4 id="读写数据方式:"><a href="#读写数据方式:" class="headerlink" title="读写数据方式:"></a>读写数据方式:</h4><ul><li>从通道进行数据读取 :创建一个缓冲区,然后请求通道读取数据。</li><li>从通道进行数据写入 :创建一个缓冲区,填充数据,并要求通道写入数据。</li></ul><h3 id="文件-1"><a href="#文件-1" class="headerlink" title="文件"></a>文件</h3><p>java 文件操作的基础是 File/Path, 一个代表文件,一个代表路径,两者组合完整地描述各种操作系统中的文件,尤其适合 Linux 的<br>‘Everything is a File’ 的哲学。</p><h3 id="String-gt-File-(Write-File)"><a href="#String-gt-File-(Write-File)" class="headerlink" title="String -> File (Write File)"></a>String -> File (Write File)</h3><h4 id="使用-NIO-的-Files-推荐"><a href="#使用-NIO-的-Files-推荐" class="headerlink" title="使用 NIO 的 Files (推荐)"></a>使用 NIO 的 Files <strong>(推荐)</strong></h4><p>由于 Files 是 nio 在 java7 新增的内容,使用本方法需要首先将程序的 jdk 升级到 jdk7+; Files 工具类提供了各种读写创建删除文件等操作,可以很方便的操作文件和流。</p><ol><li>如果写入的是字符数据,则需要设置字符编码 Charset</li><li>如果写入的是字节数据(byte[]),不需要设置字符编码</li><li>如果想在已存在的文件后追加内容,可以增加 java.nio.file.StandardOpenOption#APPEND 参数</li></ol><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/string2file/String2FileWithJavaNioExample.java">String2FileWithJavaNioExample</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">List<String> lines = Arrays.asList("The second line", "The second line");</span><br><span class="line">Path path = Paths.get("filename.txt");</span><br><span class="line">try {</span><br><span class="line"> Files.write(path, lines, StandardCharsets.UTF_8);</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="使用-NIO-的-Channel"><a href="#使用-NIO-的-Channel" class="headerlink" title="使用 NIO 的 Channel"></a>使用 NIO 的 Channel</h4><p>标准的IO编程接口是面向字节流和字符流的。而NIO是面向通道和缓冲区的,数据总是从通道中读到buffer缓冲区内,或者从buffer写入到通道中。</p><p>Java NIO 的 Channel 和 IO 流的对比:</p><ol><li>通道可以读也可以写,流一般来说是单向的(只能读或者写)。</li><li>通道可以异步读写。</li><li>通道总是基于缓冲区Buffer来读写。</li></ol><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/string2file/String2FileWithJavaNioExample.java">String2FileWithJavaNioExample</a></p><p>使用 FileOutputStream 的 FileChannel:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">String data = "The second line" + System.getProperty("line.separator") + </span><br><span class="line"> "The second line" + System.getProperty("line.separator");</span><br><span class="line">// use ByteBuffer wrap data</span><br><span class="line">final ByteBuffer buffer = ByteBuffer.wrap(data.getBytes());</span><br><span class="line">// try-with-resources auto close the channel</span><br><span class="line">try (// open channel</span><br><span class="line"> final FileOutputStream fos = new FileOutputStream(new File("filename.txt"));</span><br><span class="line"> FileChannel channel = fos.getChannel()) {</span><br><span class="line"> // write buffer to channel</span><br><span class="line"> while (buffer.hasRemaining()) {</span><br><span class="line"> channel.write(buffer);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>使用 RandomAccessFile 的 FileChannel:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">String data = "The second line" + System.getProperty("line.separator") + </span><br><span class="line"> "The second line" + System.getProperty("line.separator");</span><br><span class="line">final ByteBuffer buffer = ByteBuffer.wrap(data.getBytes());</span><br><span class="line">try(final RandomAccessFile file = new RandomAccessFile("filename.txt", "rw");</span><br><span class="line"> FileChannel channel = file.getChannel()){</span><br><span class="line"> </span><br><span class="line"> while (buffer.hasRemaining()){</span><br><span class="line"> channel.write(buffer);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="使用-BufferedWriter-推荐"><a href="#使用-BufferedWriter-推荐" class="headerlink" title="使用 BufferedWriter (推荐)"></a>使用 BufferedWriter <strong>(推荐)</strong></h4><ol><li>BufferedWriter 可以设置缓存区大小</li><li>OutputStreamWriter 可以指定字符集编码 </li><li>FileOutputStream 可以指定文件编辑模式(追加/覆盖)</li></ol><p>使用 PrintWriter/FileWriter 一般写入的内容比较少,如果需要写入大量数据,应该要使用缓冲流,提高效率。</p><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/string2file/String2FileWithWriterExample.java">String2FileWithWriterExample</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try (Writer writer = new BufferedWriter(new OutputStreamWriter(</span><br><span class="line"> new FileOutputStream("filename.txt", true), StandardCharsets.UTF_8))) {</span><br><span class="line"> writer.write("The second line" + System.getProperty("line.separator") + </span><br><span class="line"> "The second line" + System.getProperty("line.separator"));</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="使用-PrintWrite"><a href="#使用-PrintWrite" class="headerlink" title="使用 PrintWrite"></a>使用 PrintWrite</h4><p>使用PrintWrite可以很简单的使用println进行单行输入,但是存在的文件会被截断</p><ol><li>如果文件已经存在,PrintWriter 会将文件大小截断为零,如果不想截断文件,可以使用FileWriter作为替代,FileWriter设置字符大小和缓冲大小。</li><li>使用 PrintWriter 不需要输入文件 path,所以创建文件的路径需要看执行程序时的工作目录。</li><li>PriteWriter 会导致吞异常,见 <a href="https://stackoverflow.com/questions/1747040/difference-between-java-io-printwriter-and-java-io-bufferedwriter/1747092#1747092" target="_blank" rel="noopener">stackoverflow.com/a/1747092/4678667</a> 。</li></ol><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/string2file/String2FileWithWriterExample.java">String2FileWithWriterExample</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try (PrintWriter writer = new PrintWriter("filename.txt", "UTF-8")) {</span><br><span class="line"> writer.println("The first line");</span><br><span class="line"> writer.println("The second line");</span><br><span class="line">} catch (FileNotFoundException | UnsupportedEncodingException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="使用-FileWriter"><a href="#使用-FileWriter" class="headerlink" title="使用 FileWriter"></a>使用 FileWriter</h4><p>FileWriter 在创建的时候可以指定追加/覆盖模式,避免 PrintWriter 截断已存在的文件。</p><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/string2file/String2FileWithWriterExample.java">String2FileWithWriterExample</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try (FileWriter writer = new FileWriter(new File("filename.txt"), true)) {</span><br><span class="line"> writer.append("The first line").append(System.getProperty("line.separator"))</span><br><span class="line"> .append(LINE2).append(System.getProperty("line.separator"));</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="使用-commons-io-的-FileUtils"><a href="#使用-commons-io-的-FileUtils" class="headerlink" title="使用 commons-io 的 FileUtils"></a>使用 commons-io 的 FileUtils</h4><p>Commons-io 项目地址: <a href="https://commons.apache.org/proper/commons-io/" target="_blank" rel="noopener">apache/commons-io</a><br>使用 commons-io 包中的 FileUtils 进行文件写入, 重构的方法可以设置文件编码和写入模式</p><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/string2file/String2FileWithCommonsExample.java">String2FileWithCommonsExample</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try {</span><br><span class="line"> String data = "The second line" + System.getProperty("line.separator") + </span><br><span class="line"> "The second line" + System.getProperty("line.separator");</span><br><span class="line"> FileUtils.writeStringToFile(new File("filename.txt"), data, StandardCharsets.UTF_8, true);</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="使用-guava-的-Files"><a href="#使用-guava-的-Files" class="headerlink" title="使用 guava 的 Files"></a>使用 guava 的 Files</h4><p>Guava 的官方开源项目地址: <a href="https://github.com/google/guava">google/guava</a><br>guava 的 Files 可以直接向文件中写入 byte[] 数据<br>Files 已被标注为 @Beta 不稳定的版本,并提示使用 jdk7 nio 的 Files、MoreFiles 等工具类利用 nio 的 Path 进行文件处理 </p><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/string2file/String2FileWithGuavaExample.java">String2FileWithGuavaExample</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try {</span><br><span class="line"> String data = "The second line" + System.getProperty("line.separator") + </span><br><span class="line"> "The second line" + System.getProperty("line.separator");</span><br><span class="line"> Files.write(data.getBytes(), new File("filename.txt"));</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="使用-guava-的-CharSink-ByteSink"><a href="#使用-guava-的-CharSink-ByteSink" class="headerlink" title="使用 guava 的 CharSink/ByteSink"></a>使用 guava 的 CharSink/ByteSink</h4><p>guava 的 CharSink 可以直接向文件中写入字符数据,ByteSink 则可以写入字节数据<br>Files 中的 write、append、copy 等方法本质上都是调用的这些 Sink 类。 </p><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/string2file/String2FileWithGuavaExample.java">String2FileWithGuavaExample</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try {</span><br><span class="line"> String data = "The second line" + System.getProperty("line.separator") + </span><br><span class="line"> "The second line" + System.getProperty("line.separator");</span><br><span class="line"> Files.asCharSink(new File("filename.txt"), StandardCharsets.UTF_8, FileWriteMode.APPEND).write(data);</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="File-gt-String-Read-File"><a href="#File-gt-String-Read-File" class="headerlink" title="File -> String (Read File)"></a>File -> String (Read File)</h3><h4 id="使用-NIO-的-Files-推荐-1"><a href="#使用-NIO-的-Files-推荐-1" class="headerlink" title="使用 NIO 的 Files (推荐)"></a>使用 NIO 的 Files <strong>(推荐)</strong></h4><p>NIO 的 Files 工具类提供多种 read 方法可以快速进行文件读取</p><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/file2string/File2StringWithNioExample.java">File2StringWithNioExample</a></p><p>使用 readAllBytes 读取字节:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try {</span><br><span class="line"> return new String(Files.readAllBytes(Paths.get("filename.txt")));</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>使用 readAllLines 逐行读取字符串:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try {</span><br><span class="line"> List<String> lines = Files.readAllLines(Paths.get("filename.txt"), StandardCharsets.UTF_8);</span><br><span class="line"> StringBuilder sb = new StringBuilder();</span><br><span class="line"> lines.forEach(s -> sb.append(s).append(SEPARATOR));</span><br><span class="line"> return sb.toString();</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br><span class="line">return null;</span><br></pre></td></tr></table></figure><p>由于 Stream 内部无法在 lambda 中使用带有 checked Exception 的方法,因此要对异常的抓取,防止发生异常 </p><p>使用 lines 逐行读取字符串:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try (Stream<String> lines = Files.lines(Paths.get("filename.txt"), StandardCharsets.UTF_8)) {</span><br><span class="line"> StringBuilder content = new StringBuilder();</span><br><span class="line"> lines.forEach(s -> content.append(s).append(SEPARATOR));</span><br><span class="line"> return content.toString();</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="使用-Scanner"><a href="#使用-Scanner" class="headerlink" title="使用 Scanner"></a>使用 Scanner</h4><p>Scanner 默认的缓冲大小为 1024, 可以读取文件,但是读取空文件的时候会出现异常,见 <a href="https://stackoverflow.com/questions/326390/how-do-i-create-a-java-string-from-the-contents-of-a-file" target="_blank" rel="noopener">Scanner的讨论</a></p><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/file2string/File2StringWithScannerExample.java">File2StringWithScannerExample</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try (Scanner scanner = new Scanner(new File(FILE_NAME_INPUT), "UTF-8")) {</span><br><span class="line"> return scanner.useDelimiter("\\A").next();</span><br><span class="line">} catch (FileNotFoundException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="使用-BufferedReader-推荐"><a href="#使用-BufferedReader-推荐" class="headerlink" title="使用 BufferedReader (推荐)"></a>使用 BufferedReader <strong>(推荐)</strong></h4><p>BufferedReader 缓冲流,可以高效的读取文件,使用 Reader 和 InputStream 组合可以设置各种配置。 </p><ol><li>使用 InputStreamReader 可以设置字符集</li><li>使用 FileInputStream 可以读取文件</li><li>或者使用 FileReader 直接读取文件,并用 BufferedReader 包装成缓存使用</li></ol><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/file2string/File2StringWithReaderExample.java">File2StringWithReaderExample</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">// new BufferedReader(new FileReader("filename.txt"));</span><br><span class="line">try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("filename.txt"), StandardCharsets.UTF_8))) {</span><br><span class="line"> String line;</span><br><span class="line"> StringBuilder stringBuilder = new StringBuilder();</span><br><span class="line"> while ((line = reader.readLine()) != null) {</span><br><span class="line"> stringBuilder.append(line).append(SEPARATOR);</span><br><span class="line"> }</span><br><span class="line"> return stringBuilder.toString();</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="使用-FileInputStream"><a href="#使用-FileInputStream" class="headerlink" title="使用 FileInputStream"></a>使用 FileInputStream</h4><p>仅仅使用 FileInputStream 进行文件读取,从 FileInputStream 写入 byte[] 缓存,转换为文本数据,这段代码只需要 jdk1.0+</p><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/file2string/File2StringWithReaderExample.java">File2StringWithReaderExample</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">FileInputStream fis = null;</span><br><span class="line">try {</span><br><span class="line"> fis = new FileInputStream("filename.txt");</span><br><span class="line"> byte[] buffer = new byte[fis.available()];</span><br><span class="line"> int length = fis.read(buffer);</span><br><span class="line"> return new String(buffer, 0, length, StandardCharsets.UTF_8);</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">} finally {</span><br><span class="line"> if (fis != null) {</span><br><span class="line"> try {</span><br><span class="line"> fis.close();</span><br><span class="line"> } catch (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><br><span class="line">return null;</span><br></pre></td></tr></table></figure><h4 id="使用-commons-io-的-IOUtils"><a href="#使用-commons-io-的-IOUtils" class="headerlink" title="使用 commons-io 的 IOUtils"></a>使用 commons-io 的 IOUtils</h4><p>commons-io 的 IOUtils 工具类提供了大量 IO 相关的工具方法,使用 IOUtils.copy 直接将 Reader/InputStream 转换为 Writer/OutputStream </p><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/file2string/File2StringWithCommonsExample.java">File2StringWithCommonsExample</a></p><p>使用 FileReader 读取文件,使用 StringWriter 将流中的内容输出出来:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try (FileReader fileReader = new FileReader("filename.txt");</span><br><span class="line"> StringWriter stringWriter = new StringWriter()) {</span><br><span class="line"> IOUtils.copy(fileReader, stringWriter);</span><br><span class="line"> return stringWriter.toString();</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="使用-commons-io-的-FileUtils-1"><a href="#使用-commons-io-的-FileUtils-1" class="headerlink" title="使用 commons-io 的 FileUtils"></a>使用 commons-io 的 FileUtils</h4><p>commons-io 的 FileUtils 提供了文件相关的工具方法, 使用 FileUtils.readByFileUtilsReadFileToString 读取文件内容</p><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/file2string/File2StringWithCommonsExample.java">File2StringWithCommonsExample</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try {</span><br><span class="line"> return FileUtils.readFileToString(new File("filename.txt"), StandardCharsets.UTF_8);</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="使用-guava-的-Files-1"><a href="#使用-guava-的-Files-1" class="headerlink" title="使用 guava 的 Files"></a>使用 guava 的 Files</h4><p>直接使用 guava 的 Files 转换为 ByteSource/CharSource 然后直接 read 成字符串:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try {</span><br><span class="line"> // Resources.asCharSource(new URL(""), StandardCharsets.UTF_8).read();</span><br><span class="line"> return Files.asCharSource(new File("filename.txt"), StandardCharsets.UTF_8).read();</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>或者使用 readLines 逐行读取:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try {</span><br><span class="line"> return String.join(System.getProperty("line.separator"), Files.readLines(new File("filename.txt"), StandardCharsets.UTF_8));</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="File-gt-File-copy-File"><a href="#File-gt-File-copy-File" class="headerlink" title="File -> File (copy File)"></a>File -> File (copy File)</h3><h4 id="使用-NIO-的-Channel-1"><a href="#使用-NIO-的-Channel-1" class="headerlink" title="使用 NIO 的 Channel"></a>使用 NIO 的 Channel</h4><p>标准的IO编程接口是面向字节流和字符流的。而NIO是面向通道和缓冲区的,数据总是从通道中读到buffer缓冲区内,或者从buffer写入到通道中。</p><p>Java NIO 的 Channel 和 IO 流的对比:</p><ol><li>通道可以读也可以写,流一般来说是单向的(只能读或者写)。</li><li>通道可以异步读写。</li><li>通道总是基于缓冲区Buffer来读写。</li></ol><p>Buffer 及其子类不是线程安全的</p><p>Buffer 的属性:</p><ol><li>capacity - 缓存容量</li><li>limit - 缓存下表限制值</li><li>position - 当前操作的下标值</li><li>mark - 临时下标值</li></ol><p>几个属性的关系: 0 <= mark <= position <= limit <= capacity</p><p>Buffer 的方法:</p><ol><li>mark(): mark 设置成 position</li><li>clear(): mark 设置为 -1 清除标记, position 设置为 0, limit 设置为 capacity, <strong>数据写入 Buffer 前调用</strong></li><li>flip(): limit 设置成 position 当前位置作为上限, position 设置为 0, <strong>Buffer 读取数据前调用</strong></li><li>rewind(): position 设置为 0, limit 不变, <strong>数据重新写入 Buffer 前调用</strong></li></ol><p>使用不同的 Channel 同时操作同一个 Buffer 可以实现文件的复制。</p><p>DEMO 参考: <a href="https://github.com/zzycreate/java-convert-example/blob/master/src/main/java/io/github/zzycreate/example/file/file2file/File2FileWithNioExample.java">File2FileWithNioExample</a></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">try (FileInputStream input = new FileInputStream("filename.txt");</span><br><span class="line"> FileOutputStream output = new FileOutputStream("filename.txt");</span><br><span class="line"> ReadableByteChannel from = input.getChannel();</span><br><span class="line"> WritableByteChannel to = output.getChannel()) {</span><br><span class="line"> ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);</span><br><span class="line"> while (from.read(buffer) != -1) {</span><br><span class="line"> // Prepare the buffer to be drained</span><br><span class="line"> buffer.flip();</span><br><span class="line"></span><br><span class="line"> // Make sure that the buffer was fully drained</span><br><span class="line"> while (buffer.hasRemaining()) {</span><br><span class="line"> to.write(buffer);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // Make the buffer empty, ready for filling</span><br><span class="line"> buffer.clear();</span><br><span class="line"> }</span><br><span class="line">} catch (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<blockquote>
<p>平时的开发中会经常遇到一些对象需要转换,本项目记录一些常见对象转换的方法,例如:文件转换、日期时间转换、stream流转换、集合对象转换等, 具体的示例代码见 github 项目:<a href="https://github.com/zzycreate/java-convert-example">zzycreate/java-convert-example</a><br>本文记录一些常用的文件操作,以备需要时直接使用</p>
</blockquote>
</summary>
<category term="编码" scheme="https://github.com/zzycreate/categories/%E7%BC%96%E7%A0%81/"/>
<category term="Java" scheme="https://github.com/zzycreate/tags/Java/"/>
<category term="java-convert-example" scheme="https://github.com/zzycreate/tags/java-convert-example/"/>
<category term="File" scheme="https://github.com/zzycreate/tags/File/"/>
<category term="NIO" scheme="https://github.com/zzycreate/tags/NIO/"/>
</entry>
<entry>
<title>mysql知识点收藏</title>
<link href="https://github.com/zzycreate/2019/04/06/mysql%E7%9F%A5%E8%AF%86%E7%82%B9%E6%94%B6%E8%97%8F/"/>
<id>https://github.com/zzycreate/2019/04/06/mysql知识点收藏/</id>
<published>2019-04-06T16:25:15.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>SQL 是后端程序员很重要的一个技能。</p></blockquote><a id="more"></a><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="comment">/* Windows服务 */</span></span><br><span class="line"><span class="comment">-- 启动MySQL</span></span><br><span class="line"> net <span class="keyword">start</span> mysql</span><br><span class="line"><span class="comment">-- 创建Windows服务</span></span><br><span class="line"> sc <span class="keyword">create</span> mysql binPath= mysqld_bin_path(注意:等号与值之间有空格)</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 连接与断开服务器 */</span></span><br><span class="line">mysql -h 地址 -P 端口 -u 用户名 -p 密码</span><br><span class="line"></span><br><span class="line"><span class="keyword">SHOW</span> <span class="keyword">PROCESSLIST</span> <span class="comment">-- 显示哪些线程正在运行</span></span><br><span class="line"><span class="keyword">SHOW</span> <span class="keyword">VARIABLES</span> <span class="comment">-- 显示系统变量信息</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 数据库操作 */</span> <span class="comment">------------------</span></span><br><span class="line"><span class="comment">-- 查看当前数据库</span></span><br><span class="line"> <span class="keyword">SELECT</span> <span class="keyword">DATABASE</span>();</span><br><span class="line"><span class="comment">-- 显示当前时间、用户名、数据库版本</span></span><br><span class="line"> <span class="keyword">SELECT</span> <span class="keyword">now</span>(), <span class="keyword">user</span>(), <span class="keyword">version</span>();</span><br><span class="line"><span class="comment">-- 创建库</span></span><br><span class="line"> <span class="keyword">CREATE</span> <span class="keyword">DATABASE</span>[ <span class="keyword">IF</span> <span class="keyword">NOT</span> <span class="keyword">EXISTS</span>] 数据库名 数据库选项</span><br><span class="line"> 数据库选项:</span><br><span class="line"> <span class="built_in">CHARACTER</span> <span class="keyword">SET</span> charset_name</span><br><span class="line"> <span class="keyword">COLLATE</span> collation_name</span><br><span class="line"><span class="comment">-- 查看已有库</span></span><br><span class="line"> <span class="keyword">SHOW</span> <span class="keyword">DATABASES</span>[ <span class="keyword">LIKE</span> <span class="string">'PATTERN'</span>]</span><br><span class="line"><span class="comment">-- 查看当前库信息</span></span><br><span class="line"> <span class="keyword">SHOW</span> <span class="keyword">CREATE</span> <span class="keyword">DATABASE</span> 数据库名</span><br><span class="line"><span class="comment">-- 修改库的选项信息</span></span><br><span class="line"> <span class="keyword">ALTER</span> <span class="keyword">DATABASE</span> 库名 选项信息</span><br><span class="line"><span class="comment">-- 删除库</span></span><br><span class="line"> <span class="keyword">DROP</span> <span class="keyword">DATABASE</span>[ <span class="keyword">IF</span> <span class="keyword">EXISTS</span>] 数据库名</span><br><span class="line"> 同时删除该数据库相关的目录及其目录内容</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 表的操作 */</span> <span class="comment">------------------</span></span><br><span class="line"><span class="comment">-- 创建表</span></span><br><span class="line"> <span class="keyword">CREATE</span> [<span class="keyword">TEMPORARY</span>] <span class="keyword">TABLE</span>[ <span class="keyword">IF</span> <span class="keyword">NOT</span> <span class="keyword">EXISTS</span>] [库名.]表名 ( 表的结构定义 )[ 表选项]</span><br><span class="line"> 每个字段必须有数据类型</span><br><span class="line"> 最后一个字段后不能有逗号</span><br><span class="line"> <span class="keyword">TEMPORARY</span> 临时表,会话结束时表自动消失</span><br><span class="line"> 对于字段的定义:</span><br><span class="line"> 字段名 数据类型 [<span class="keyword">NOT</span> <span class="literal">NULL</span> | <span class="literal">NULL</span>] [<span class="keyword">DEFAULT</span> default_value] [AUTO_INCREMENT] [<span class="keyword">UNIQUE</span> [<span class="keyword">KEY</span>] | [PRIMARY] <span class="keyword">KEY</span>] [<span class="keyword">COMMENT</span> <span class="string">'string'</span>]</span><br><span class="line"><span class="comment">-- 表选项</span></span><br><span class="line"> <span class="comment">-- 字符集</span></span><br><span class="line"> <span class="keyword">CHARSET</span> = charset_name</span><br><span class="line"> 如果表没有设定,则使用数据库字符集</span><br><span class="line"> <span class="comment">-- 存储引擎</span></span><br><span class="line"> <span class="keyword">ENGINE</span> = engine_name</span><br><span class="line"> 表在管理数据时采用的不同的数据结构,结构不同会导致处理方式、提供的特性操作等不同</span><br><span class="line"> 常见的引擎:<span class="keyword">InnoDB</span> MyISAM <span class="keyword">Memory</span>/<span class="keyword">Heap</span> BDB <span class="keyword">Merge</span> Example CSV MaxDB <span class="keyword">Archive</span></span><br><span class="line"> 不同的引擎在保存表的结构和数据时采用不同的方式</span><br><span class="line"> MyISAM表文件含义:.frm表定义,.MYD表数据,.MYI表索引</span><br><span class="line"> <span class="keyword">InnoDB</span>表文件含义:.frm表定义,表空间数据和日志文件</span><br><span class="line"> <span class="keyword">SHOW</span> <span class="keyword">ENGINES</span> <span class="comment">-- 显示存储引擎的状态信息</span></span><br><span class="line"> <span class="keyword">SHOW</span> <span class="keyword">ENGINE</span> 引擎名 {<span class="keyword">LOGS</span>|<span class="keyword">STATUS</span>} <span class="comment">-- 显示存储引擎的日志或状态信息</span></span><br><span class="line"> <span class="comment">-- 自增起始数</span></span><br><span class="line"> AUTO_INCREMENT = 行数</span><br><span class="line"> <span class="comment">-- 数据文件目录</span></span><br><span class="line"> <span class="keyword">DATA</span> <span class="keyword">DIRECTORY</span> = <span class="string">'目录'</span></span><br><span class="line"> <span class="comment">-- 索引文件目录</span></span><br><span class="line"> <span class="keyword">INDEX</span> <span class="keyword">DIRECTORY</span> = <span class="string">'目录'</span></span><br><span class="line"> <span class="comment">-- 表注释</span></span><br><span class="line"> <span class="keyword">COMMENT</span> = <span class="string">'string'</span></span><br><span class="line"> <span class="comment">-- 分区选项</span></span><br><span class="line"> <span class="keyword">PARTITION</span> <span class="keyword">BY</span> ... (详细见手册)</span><br><span class="line"><span class="comment">-- 查看所有表</span></span><br><span class="line"> <span class="keyword">SHOW</span> <span class="keyword">TABLES</span>[ <span class="keyword">LIKE</span> <span class="string">'pattern'</span>]</span><br><span class="line"> <span class="keyword">SHOW</span> <span class="keyword">TABLES</span> <span class="keyword">FROM</span> 表名</span><br><span class="line"><span class="comment">-- 查看表机构</span></span><br><span class="line"> <span class="keyword">SHOW</span> <span class="keyword">CREATE</span> <span class="keyword">TABLE</span> 表名 (信息更详细)</span><br><span class="line"> <span class="keyword">DESC</span> 表名 / <span class="keyword">DESCRIBE</span> 表名 / <span class="keyword">EXPLAIN</span> 表名 / <span class="keyword">SHOW</span> <span class="keyword">COLUMNS</span> <span class="keyword">FROM</span> 表名 [<span class="keyword">LIKE</span> <span class="string">'PATTERN'</span>]</span><br><span class="line"> <span class="keyword">SHOW</span> <span class="keyword">TABLE</span> <span class="keyword">STATUS</span> [<span class="keyword">FROM</span> db_name] [<span class="keyword">LIKE</span> <span class="string">'pattern'</span>]</span><br><span class="line"><span class="comment">-- 修改表</span></span><br><span class="line"> <span class="comment">-- 修改表本身的选项</span></span><br><span class="line"> <span class="keyword">ALTER</span> <span class="keyword">TABLE</span> 表名 表的选项</span><br><span class="line"> eg: <span class="keyword">ALTER</span> <span class="keyword">TABLE</span> 表名 <span class="keyword">ENGINE</span>=MYISAM;</span><br><span class="line"> <span class="comment">-- 对表进行重命名</span></span><br><span class="line"> <span class="keyword">RENAME</span> <span class="keyword">TABLE</span> 原表名 <span class="keyword">TO</span> 新表名</span><br><span class="line"> <span class="keyword">RENAME</span> <span class="keyword">TABLE</span> 原表名 <span class="keyword">TO</span> 库名.表名 (可将表移动到另一个数据库)</span><br><span class="line"> <span class="comment">-- RENAME可以交换两个表名</span></span><br><span class="line"> <span class="comment">-- 修改表的字段机构(13.1.2. ALTER TABLE语法)</span></span><br><span class="line"> <span class="keyword">ALTER</span> <span class="keyword">TABLE</span> 表名 操作名</span><br><span class="line"> <span class="comment">-- 操作名</span></span><br><span class="line"> <span class="keyword">ADD</span>[ <span class="keyword">COLUMN</span>] 字段定义 <span class="comment">-- 增加字段</span></span><br><span class="line"> <span class="keyword">AFTER</span> 字段名 <span class="comment">-- 表示增加在该字段名后面</span></span><br><span class="line"> <span class="keyword">FIRST</span> <span class="comment">-- 表示增加在第一个</span></span><br><span class="line"> <span class="keyword">ADD</span> PRIMARY <span class="keyword">KEY</span>(字段名) <span class="comment">-- 创建主键</span></span><br><span class="line"> <span class="keyword">ADD</span> <span class="keyword">UNIQUE</span> [索引名] (字段名)<span class="comment">-- 创建唯一索引</span></span><br><span class="line"> <span class="keyword">ADD</span> <span class="keyword">INDEX</span> [索引名] (字段名) <span class="comment">-- 创建普通索引</span></span><br><span class="line"> <span class="keyword">DROP</span>[ <span class="keyword">COLUMN</span>] 字段名 <span class="comment">-- 删除字段</span></span><br><span class="line"> <span class="keyword">MODIFY</span>[ <span class="keyword">COLUMN</span>] 字段名 字段属性 <span class="comment">-- 支持对字段属性进行修改,不能修改字段名(所有原有属性也需写上)</span></span><br><span class="line"> <span class="keyword">CHANGE</span>[ <span class="keyword">COLUMN</span>] 原字段名 新字段名 字段属性 <span class="comment">-- 支持对字段名修改</span></span><br><span class="line"> <span class="keyword">DROP</span> PRIMARY <span class="keyword">KEY</span> <span class="comment">-- 删除主键(删除主键前需删除其AUTO_INCREMENT属性)</span></span><br><span class="line"> <span class="keyword">DROP</span> <span class="keyword">INDEX</span> 索引名 <span class="comment">-- 删除索引</span></span><br><span class="line"> <span class="keyword">DROP</span> <span class="keyword">FOREIGN</span> <span class="keyword">KEY</span> 外键 <span class="comment">-- 删除外键</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 删除表</span></span><br><span class="line"> <span class="keyword">DROP</span> <span class="keyword">TABLE</span>[ <span class="keyword">IF</span> <span class="keyword">EXISTS</span>] 表名 ...</span><br><span class="line"><span class="comment">-- 清空表数据</span></span><br><span class="line"> <span class="keyword">TRUNCATE</span> [<span class="keyword">TABLE</span>] 表名</span><br><span class="line"><span class="comment">-- 复制表结构</span></span><br><span class="line"> <span class="keyword">CREATE</span> <span class="keyword">TABLE</span> 表名 <span class="keyword">LIKE</span> 要复制的表名</span><br><span class="line"><span class="comment">-- 复制表结构和数据</span></span><br><span class="line"> <span class="keyword">CREATE</span> <span class="keyword">TABLE</span> 表名 [<span class="keyword">AS</span>] <span class="keyword">SELECT</span> * <span class="keyword">FROM</span> 要复制的表名</span><br><span class="line"><span class="comment">-- 检查表是否有错误</span></span><br><span class="line"> <span class="keyword">CHECK</span> <span class="keyword">TABLE</span> tbl_name [, tbl_name] ... [<span class="keyword">option</span>] ...</span><br><span class="line"><span class="comment">-- 优化表</span></span><br><span class="line"> <span class="keyword">OPTIMIZE</span> [<span class="keyword">LOCAL</span> | <span class="keyword">NO_WRITE_TO_BINLOG</span>] <span class="keyword">TABLE</span> tbl_name [, tbl_name] ...</span><br><span class="line"><span class="comment">-- 修复表</span></span><br><span class="line"> <span class="keyword">REPAIR</span> [<span class="keyword">LOCAL</span> | <span class="keyword">NO_WRITE_TO_BINLOG</span>] <span class="keyword">TABLE</span> tbl_name [, tbl_name] ... [<span class="keyword">QUICK</span>] [<span class="keyword">EXTENDED</span>] [USE_FRM]</span><br><span class="line"><span class="comment">-- 分析表</span></span><br><span class="line"> <span class="keyword">ANALYZE</span> [<span class="keyword">LOCAL</span> | <span class="keyword">NO_WRITE_TO_BINLOG</span>] <span class="keyword">TABLE</span> tbl_name [, tbl_name] ...</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 数据操作 */</span> <span class="comment">------------------</span></span><br><span class="line"><span class="comment">-- 增</span></span><br><span class="line"> <span class="keyword">INSERT</span> [<span class="keyword">INTO</span>] 表名 [(字段列表)] <span class="keyword">VALUES</span> (值列表)[, (值列表), ...]</span><br><span class="line"> <span class="comment">-- 如果要插入的值列表包含所有字段并且顺序一致,则可以省略字段列表。</span></span><br><span class="line"> <span class="comment">-- 可同时插入多条数据记录!</span></span><br><span class="line"> <span class="keyword">REPLACE</span> 与 <span class="keyword">INSERT</span> 完全一样,可互换。</span><br><span class="line"> <span class="keyword">INSERT</span> [<span class="keyword">INTO</span>] 表名 <span class="keyword">SET</span> 字段名=值[, 字段名=值, ...]</span><br><span class="line"><span class="comment">-- 查</span></span><br><span class="line"> <span class="keyword">SELECT</span> 字段列表 <span class="keyword">FROM</span> 表名[ 其他子句]</span><br><span class="line"> <span class="comment">-- 可来自多个表的多个字段</span></span><br><span class="line"> <span class="comment">-- 其他子句可以不使用</span></span><br><span class="line"> <span class="comment">-- 字段列表可以用*代替,表示所有字段</span></span><br><span class="line"><span class="comment">-- 删</span></span><br><span class="line"> <span class="keyword">DELETE</span> <span class="keyword">FROM</span> 表名[ 删除条件子句]</span><br><span class="line"> 没有条件子句,则会删除全部</span><br><span class="line"><span class="comment">-- 改</span></span><br><span class="line"> <span class="keyword">UPDATE</span> 表名 <span class="keyword">SET</span> 字段名=新值[, 字段名=新值] [更新条件]</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 字符集编码 */</span> <span class="comment">------------------</span></span><br><span class="line"><span class="comment">-- MySQL、数据库、表、字段均可设置编码</span></span><br><span class="line"><span class="comment">-- 数据编码与客户端编码不需一致</span></span><br><span class="line"><span class="keyword">SHOW</span> <span class="keyword">VARIABLES</span> <span class="keyword">LIKE</span> <span class="string">'character_set_%'</span> <span class="comment">-- 查看所有字符集编码项</span></span><br><span class="line"> character_set_client 客户端向服务器发送数据时使用的编码</span><br><span class="line"> character_set_results 服务器端将结果返回给客户端所使用的编码</span><br><span class="line"> character_set_connection 连接层编码</span><br><span class="line"><span class="keyword">SET</span> 变量名 = 变量值</span><br><span class="line"> <span class="keyword">SET</span> character_set_client = gbk;</span><br><span class="line"> <span class="keyword">SET</span> character_set_results = gbk;</span><br><span class="line"> <span class="keyword">SET</span> character_set_connection = gbk;</span><br><span class="line"><span class="keyword">SET</span> <span class="keyword">NAMES</span> GBK; <span class="comment">-- 相当于完成以上三个设置</span></span><br><span class="line"><span class="comment">-- 校对集</span></span><br><span class="line"> 校对集用以排序</span><br><span class="line"> <span class="keyword">SHOW</span> <span class="built_in">CHARACTER</span> <span class="keyword">SET</span> [<span class="keyword">LIKE</span> <span class="string">'pattern'</span>]/<span class="keyword">SHOW</span> <span class="keyword">CHARSET</span> [<span class="keyword">LIKE</span> <span class="string">'pattern'</span>] 查看所有字符集</span><br><span class="line"> <span class="keyword">SHOW</span> <span class="keyword">COLLATION</span> [<span class="keyword">LIKE</span> <span class="string">'pattern'</span>] 查看所有校对集</span><br><span class="line"> <span class="keyword">CHARSET</span> 字符集编码 设置字符集编码</span><br><span class="line"> <span class="keyword">COLLATE</span> 校对集编码 设置校对集编码</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 数据类型(列类型) */</span> <span class="comment">------------------</span></span><br><span class="line"><span class="number">1.</span> 数值类型</span><br><span class="line"><span class="comment">-- a. 整型 ----------</span></span><br><span class="line"> 类型 字节 范围(有符号位)</span><br><span class="line"> <span class="built_in">tinyint</span> <span class="number">1</span>字节 <span class="number">-128</span> ~ <span class="number">127</span> 无符号位:<span class="number">0</span> ~ <span class="number">255</span></span><br><span class="line"> <span class="built_in">smallint</span> <span class="number">2</span>字节 <span class="number">-32768</span> ~ <span class="number">32767</span></span><br><span class="line"> mediumint <span class="number">3</span>字节 <span class="number">-8388608</span> ~ <span class="number">8388607</span></span><br><span class="line"> <span class="built_in">int</span> <span class="number">4</span>字节</span><br><span class="line"> <span class="built_in">bigint</span> <span class="number">8</span>字节</span><br><span class="line"></span><br><span class="line"> <span class="built_in">int</span>(M) M表示总位数</span><br><span class="line"> - 默认存在符号位,<span class="keyword">unsigned</span> 属性修改</span><br><span class="line"> - 显示宽度,如果某个数不够定义字段时设置的位数,则前面以<span class="number">0</span>补填,zerofill 属性修改</span><br><span class="line"> 例:<span class="built_in">int</span>(<span class="number">5</span>) 插入一个数<span class="string">'123'</span>,补填后为<span class="string">'00123'</span></span><br><span class="line"> - 在满足要求的情况下,越小越好。</span><br><span class="line"> - <span class="number">1</span>表示<span class="built_in">bool</span>值真,<span class="number">0</span>表示<span class="built_in">bool</span>值假。MySQL没有布尔类型,通过整型<span class="number">0</span>和<span class="number">1</span>表示。常用<span class="built_in">tinyint</span>(<span class="number">1</span>)表示布尔型。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- b. 浮点型 ----------</span></span><br><span class="line"> 类型 字节 范围</span><br><span class="line"> <span class="built_in">float</span>(单精度) <span class="number">4</span>字节</span><br><span class="line"> <span class="keyword">double</span>(双精度) <span class="number">8</span>字节</span><br><span class="line"> 浮点型既支持符号位 <span class="keyword">unsigned</span> 属性,也支持显示宽度 zerofill 属性。</span><br><span class="line"> 不同于整型,前后均会补填<span class="number">0.</span></span><br><span class="line"> 定义浮点型时,需指定总位数和小数位数。</span><br><span class="line"> <span class="built_in">float</span>(M, D) <span class="keyword">double</span>(M, D)</span><br><span class="line"> M表示总位数,D表示小数位数。</span><br><span class="line"> M和D的大小会决定浮点数的范围。不同于整型的固定范围。</span><br><span class="line"> M既表示总位数(不包括小数点和正负号),也表示显示宽度(所有显示符号均包括)。</span><br><span class="line"> 支持科学计数法表示。</span><br><span class="line"> 浮点数表示近似值。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- c. 定点数 ----------</span></span><br><span class="line"> <span class="built_in">decimal</span> <span class="comment">-- 可变长度</span></span><br><span class="line"> <span class="built_in">decimal</span>(M, D) M也表示总位数,D表示小数位数。</span><br><span class="line"> 保存一个精确的数值,不会发生数据的改变,不同于浮点数的四舍五入。</span><br><span class="line"> 将浮点数转换为字符串来保存,每<span class="number">9</span>位数字保存为<span class="number">4</span>个字节。</span><br><span class="line"></span><br><span class="line"><span class="number">2.</span> 字符串类型</span><br><span class="line"><span class="comment">-- a. char, varchar ----------</span></span><br><span class="line"> <span class="built_in">char</span> 定长字符串,速度快,但浪费空间</span><br><span class="line"> <span class="built_in">varchar</span> 变长字符串,速度慢,但节省空间</span><br><span class="line"> M表示能存储的最大长度,此长度是字符数,非字节数。</span><br><span class="line"> 不同的编码,所占用的空间不同。</span><br><span class="line"> <span class="built_in">char</span>,最多<span class="number">255</span>个字符,与编码无关。</span><br><span class="line"> <span class="built_in">varchar</span>,最多<span class="number">65535</span>字符,与编码有关。</span><br><span class="line"> 一条有效记录最大不能超过<span class="number">65535</span>个字节。</span><br><span class="line"> utf8 最大为<span class="number">21844</span>个字符,gbk 最大为<span class="number">32766</span>个字符,latin1 最大为<span class="number">65532</span>个字符</span><br><span class="line"> <span class="built_in">varchar</span> 是变长的,需要利用存储空间保存 <span class="built_in">varchar</span> 的长度,如果数据小于<span class="number">255</span>个字节,则采用一个字节来保存长度,反之需要两个字节来保存。</span><br><span class="line"> <span class="built_in">varchar</span> 的最大有效长度由最大行大小和使用的字符集确定。</span><br><span class="line"> 最大有效长度是<span class="number">65532</span>字节,因为在<span class="built_in">varchar</span>存字符串时,第一个字节是空的,不存在任何数据,然后还需两个字节来存放字符串的长度,所以有效长度是<span class="number">64432</span><span class="number">-1</span><span class="number">-2</span>=<span class="number">65532</span>字节。</span><br><span class="line"> 例:若一个表定义为 CREATE TABLE tb(c1 int, c2 char(30), c3 varchar(N)) charset=utf8; 问N的最大值是多少? 答:(65535-1-2-4-30*3)/3</span><br><span class="line"></span><br><span class="line"><span class="comment">-- b. blob, text ----------</span></span><br><span class="line"> blob 二进制字符串(字节字符串)</span><br><span class="line"> tinyblob, blob, mediumblob, longblob</span><br><span class="line"> text 非二进制字符串(字符字符串)</span><br><span class="line"> tinytext, text, mediumtext, longtext</span><br><span class="line"> text 在定义时,不需要定义长度,也不会计算总长度。</span><br><span class="line"> text 类型在定义时,不可给default值</span><br><span class="line"></span><br><span class="line"><span class="comment">-- c. binary, varbinary ----------</span></span><br><span class="line"> 类似于char和varchar,用于保存二进制字符串,也就是保存字节字符串而非字符字符串。</span><br><span class="line"> char, varchar, text 对应 binary, varbinary, blob.</span><br><span class="line"></span><br><span class="line">3. 日期时间类型</span><br><span class="line"> 一般用整型保存时间戳,因为PHP可以很方便的将时间戳进行格式化。</span><br><span class="line"> datetime 8字节 日期及时间 1000-01-01 00:00:00 到 9999-12-31 23:59:59</span><br><span class="line"> date 3字节 日期 1000-01-01 到 9999-12-31</span><br><span class="line"> timestamp 4字节 时间戳 19700101000000 到 2038-01-19 03:14:07</span><br><span class="line"> time 3字节 时间 -838:59:59 到 838:59:59</span><br><span class="line"> year 1字节 年份 1901 - 2155</span><br><span class="line"></span><br><span class="line">datetime YYYY-MM-DD hh:mm:ss</span><br><span class="line">timestamp YY-MM-DD hh:mm:ss</span><br><span class="line"> YYYYMMDDhhmmss</span><br><span class="line"> YYMMDDhhmmss</span><br><span class="line"> YYYYMMDDhhmmss</span><br><span class="line"> YYMMDDhhmmss</span><br><span class="line">date YYYY-MM-DD</span><br><span class="line"> YY-MM-DD</span><br><span class="line"> YYYYMMDD</span><br><span class="line"> YYMMDD</span><br><span class="line"> YYYYMMDD</span><br><span class="line"> YYMMDD</span><br><span class="line">time hh:mm:ss</span><br><span class="line"> hhmmss</span><br><span class="line"> hhmmss</span><br><span class="line">year YYYY</span><br><span class="line"> YY</span><br><span class="line"> YYYY</span><br><span class="line"> YY</span><br><span class="line"></span><br><span class="line">4. 枚举和集合</span><br><span class="line"><span class="comment">-- 枚举(enum) ----------</span></span><br><span class="line">enum(val1, val2, val3...)</span><br><span class="line"> 在已知的值中进行单选。最大数量为65535.</span><br><span class="line"> 枚举值在保存时,以2个字节的整型(smallint)保存。每个枚举值,按保存的位置顺序,从1开始逐一递增。</span><br><span class="line"> 表现为字符串类型,存储却是整型。</span><br><span class="line"> NULL值的索引是NULL。</span><br><span class="line"> 空字符串错误值的索引值是0。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 集合(set) ----------</span></span><br><span class="line"><span class="keyword">set</span>(val1, val2, val3...)</span><br><span class="line"> <span class="keyword">create</span> <span class="keyword">table</span> tab ( gender <span class="keyword">set</span>(<span class="string">'男'</span>, <span class="string">'女'</span>, <span class="string">'无'</span>) );</span><br><span class="line"> <span class="keyword">insert</span> <span class="keyword">into</span> tab <span class="keyword">values</span> (<span class="string">'男, 女'</span>);</span><br><span class="line"> 最多可以有64个不同的成员。以bigint存储,共8个字节。采取位运算的形式。</span><br><span class="line"> 当创建表时,<span class="keyword">SET</span>成员值的尾部空格将自动被删除。</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 选择类型 */</span></span><br><span class="line"><span class="comment">-- PHP角度</span></span><br><span class="line"><span class="number">1.</span> 功能满足</span><br><span class="line"><span class="number">2.</span> 存储空间尽量小,处理效率更高</span><br><span class="line"><span class="number">3.</span> 考虑兼容问题</span><br><span class="line"></span><br><span class="line"><span class="comment">-- IP存储 ----------</span></span><br><span class="line"><span class="number">1.</span> 只需存储,可用字符串</span><br><span class="line"><span class="number">2.</span> 如果需计算,查找等,可存储为<span class="number">4</span>个字节的无符号<span class="built_in">int</span>,即<span class="keyword">unsigned</span></span><br><span class="line"> <span class="number">1</span>) PHP函数转换</span><br><span class="line"> ip2long可转换为整型,但会出现携带符号问题。需格式化为无符号的整型。</span><br><span class="line"> 利用sprintf函数格式化字符串</span><br><span class="line"> sprintf(<span class="string">"%u"</span>, ip2long(<span class="string">'192.168.3.134'</span>));</span><br><span class="line"> 然后用long2ip将整型转回IP字符串</span><br><span class="line"> 2) MySQL函数转换(无符号整型,UNSIGNED)</span><br><span class="line"> INET_ATON('127.0.0.1') 将IP转为整型</span><br><span class="line"> INET_NTOA(2130706433) 将整型转为IP</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 列属性(列约束) */</span> <span class="comment">------------------</span></span><br><span class="line">1. PRIMARY 主键</span><br><span class="line"> - 能唯一标识记录的字段,可以作为主键。</span><br><span class="line"> - 一个表只能有一个主键。</span><br><span class="line"> - 主键具有唯一性。</span><br><span class="line"> - 声明字段时,用 primary key 标识。</span><br><span class="line"> 也可以在字段列表之后声明</span><br><span class="line"> 例:<span class="keyword">create</span> <span class="keyword">table</span> tab ( <span class="keyword">id</span> <span class="built_in">int</span>, stu <span class="built_in">varchar</span>(<span class="number">10</span>), primary <span class="keyword">key</span> (<span class="keyword">id</span>));</span><br><span class="line"> - 主键字段的值不能为null。</span><br><span class="line"> - 主键可以由多个字段共同组成。此时需要在字段列表后声明的方法。</span><br><span class="line"> 例:<span class="keyword">create</span> <span class="keyword">table</span> tab ( <span class="keyword">id</span> <span class="built_in">int</span>, stu <span class="built_in">varchar</span>(<span class="number">10</span>), age <span class="built_in">int</span>, primary <span class="keyword">key</span> (stu, age));</span><br><span class="line"></span><br><span class="line">2. UNIQUE 唯一索引(唯一约束)</span><br><span class="line"> 使得某字段的值也不能重复。</span><br><span class="line"></span><br><span class="line">3. NULL 约束</span><br><span class="line"> null不是数据类型,是列的一个属性。</span><br><span class="line"> 表示当前列是否可以为null,表示什么都没有。</span><br><span class="line"> null, 允许为空。默认。</span><br><span class="line"> not null, 不允许为空。</span><br><span class="line"> <span class="keyword">insert</span> <span class="keyword">into</span> tab <span class="keyword">values</span> (<span class="literal">null</span>, <span class="string">'val'</span>);</span><br><span class="line"> <span class="comment">-- 此时表示将第一个字段的值设为null, 取决于该字段是否允许为null</span></span><br><span class="line"></span><br><span class="line">4. DEFAULT 默认值属性</span><br><span class="line"> 当前字段的默认值。</span><br><span class="line"> <span class="keyword">insert</span> <span class="keyword">into</span> tab <span class="keyword">values</span> (<span class="keyword">default</span>, <span class="string">'val'</span>); <span class="comment">-- 此时表示强制使用默认值。</span></span><br><span class="line"> <span class="keyword">create</span> <span class="keyword">table</span> tab ( add_time <span class="built_in">timestamp</span> <span class="keyword">default</span> <span class="keyword">current_timestamp</span> );</span><br><span class="line"> <span class="comment">-- 表示将当前时间的时间戳设为默认值。</span></span><br><span class="line"> current_date, current_time</span><br><span class="line"></span><br><span class="line">5. AUTO_INCREMENT 自动增长约束</span><br><span class="line"> 自动增长必须为索引(主键或unique)</span><br><span class="line"> 只能存在一个字段为自动增长。</span><br><span class="line"> 默认为1开始自动增长。可以通过表属性 auto_increment = x进行设置,或 <span class="keyword">alter</span> <span class="keyword">table</span> tbl auto_increment = x;</span><br><span class="line"></span><br><span class="line">6. <span class="keyword">COMMENT</span> 注释</span><br><span class="line"> 例:<span class="keyword">create</span> <span class="keyword">table</span> tab ( <span class="keyword">id</span> <span class="built_in">int</span> ) <span class="keyword">comment</span> <span class="string">'注释内容'</span>;</span><br><span class="line"></span><br><span class="line">7. FOREIGN KEY 外键约束</span><br><span class="line"> 用于限制主表与从表数据完整性。</span><br><span class="line"> <span class="keyword">alter</span> <span class="keyword">table</span> t1 <span class="keyword">add</span> <span class="keyword">constraint</span> <span class="string">`t1_t2_fk`</span> <span class="keyword">foreign</span> <span class="keyword">key</span> (t1_id) <span class="keyword">references</span> t2(<span class="keyword">id</span>);</span><br><span class="line"> <span class="comment">-- 将表t1的t1_id外键关联到表t2的id字段。</span></span><br><span class="line"> <span class="comment">-- 每个外键都有一个名字,可以通过 constraint 指定</span></span><br><span class="line"></span><br><span class="line"> 存在外键的表,称之为从表(子表),外键指向的表,称之为主表(父表)。</span><br><span class="line"></span><br><span class="line"> 作用:保持数据一致性,完整性,主要目的是控制存储在外键表(从表)中的数据。</span><br><span class="line"></span><br><span class="line"> MySQL中,可以对InnoDB引擎使用外键约束:</span><br><span class="line"> 语法:</span><br><span class="line"> foreign key (外键字段) references 主表名 (关联字段) [主表记录删除时的动作] [主表记录更新时的动作]</span><br><span class="line"> 此时需要检测一个从表的外键需要约束为主表的已存在的值。外键在没有关联的情况下,可以设置为null.前提是该外键列,没有not null。</span><br><span class="line"></span><br><span class="line"> 可以不指定主表记录更改或更新时的动作,那么此时主表的操作被拒绝。</span><br><span class="line"> 如果指定了 on <span class="keyword">update</span> 或 <span class="keyword">on</span> <span class="keyword">delete</span>:在删除或更新时,有如下几个操作可以选择:</span><br><span class="line"> <span class="number">1.</span> <span class="keyword">cascade</span>,级联操作。主表数据被更新(主键值更新),从表也被更新(外键值更新)。主表记录被删除,从表相关记录也被删除。</span><br><span class="line"> <span class="number">2.</span> <span class="keyword">set</span> <span class="literal">null</span>,设置为<span class="literal">null</span>。主表数据被更新(主键值更新),从表的外键被设置为<span class="literal">null</span>。主表记录被删除,从表相关记录外键被设置成<span class="literal">null</span>。但注意,要求该外键列,没有<span class="keyword">not</span> <span class="literal">null</span>属性约束。</span><br><span class="line"> <span class="number">3.</span> restrict,拒绝父表删除和更新。</span><br><span class="line"></span><br><span class="line"> 注意,外键只被<span class="keyword">InnoDB</span>存储引擎所支持。其他引擎是不支持的。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 建表规范 */</span> <span class="comment">------------------</span></span><br><span class="line"> <span class="comment">-- Normal Format, NF</span></span><br><span class="line"> - 每个表保存一个实体信息</span><br><span class="line"> - 每个具有一个<span class="keyword">ID</span>字段作为主键</span><br><span class="line"> - <span class="keyword">ID</span>主键 + 原子表</span><br><span class="line"> <span class="comment">-- 1NF, 第一范式</span></span><br><span class="line"> 字段不能再分,就满足第一范式。</span><br><span class="line"> <span class="comment">-- 2NF, 第二范式</span></span><br><span class="line"> 满足第一范式的前提下,不能出现部分依赖。</span><br><span class="line"> 消除符合主键就可以避免部分依赖。增加单列关键字。</span><br><span class="line"> <span class="comment">-- 3NF, 第三范式</span></span><br><span class="line"> 满足第二范式的前提下,不能出现传递依赖。</span><br><span class="line"> 某个字段依赖于主键,而有其他字段依赖于该字段。这就是传递依赖。</span><br><span class="line"> 将一个实体信息的数据放在一个表内实现。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* SELECT */</span> <span class="comment">------------------</span></span><br><span class="line"><span class="keyword">SELECT</span> [<span class="keyword">ALL</span>|<span class="keyword">DISTINCT</span>] select_expr <span class="keyword">FROM</span> -> <span class="keyword">WHERE</span> -> <span class="keyword">GROUP</span> <span class="keyword">BY</span> [合计函数] -> <span class="keyword">HAVING</span> -> <span class="keyword">ORDER</span> <span class="keyword">BY</span> -> <span class="keyword">LIMIT</span></span><br><span class="line"></span><br><span class="line">a. select_expr</span><br><span class="line"> <span class="comment">-- 可以用 * 表示所有字段。</span></span><br><span class="line"> <span class="keyword">select</span> * <span class="keyword">from</span> tb;</span><br><span class="line"> <span class="comment">-- 可以使用表达式(计算公式、函数调用、字段也是个表达式)</span></span><br><span class="line"> <span class="keyword">select</span> stu, <span class="number">29</span>+<span class="number">25</span>, <span class="keyword">now</span>() <span class="keyword">from</span> tb;</span><br><span class="line"> <span class="comment">-- 可以为每个列使用别名。适用于简化列标识,避免多个列标识符重复。</span></span><br><span class="line"> - 使用 as 关键字,也可省略 as.</span><br><span class="line"> <span class="keyword">select</span> stu+<span class="number">10</span> <span class="keyword">as</span> add10 <span class="keyword">from</span> tb;</span><br><span class="line"></span><br><span class="line">b. FROM 子句</span><br><span class="line"> 用于标识查询来源。</span><br><span class="line"> <span class="comment">-- 可以为表起别名。使用as关键字。</span></span><br><span class="line"> <span class="keyword">SELECT</span> * <span class="keyword">FROM</span> tb1 <span class="keyword">AS</span> tt, tb2 <span class="keyword">AS</span> bb;</span><br><span class="line"> <span class="comment">-- from子句后,可以同时出现多个表。</span></span><br><span class="line"> <span class="comment">-- 多个表会横向叠加到一起,而数据会形成一个笛卡尔积。</span></span><br><span class="line"> <span class="keyword">SELECT</span> * <span class="keyword">FROM</span> tb1, tb2;</span><br><span class="line"> <span class="comment">-- 向优化符提示如何选择索引</span></span><br><span class="line"> <span class="keyword">USE</span> <span class="keyword">INDEX</span>、<span class="keyword">IGNORE</span> <span class="keyword">INDEX</span>、<span class="keyword">FORCE</span> <span class="keyword">INDEX</span></span><br><span class="line"> <span class="keyword">SELECT</span> * <span class="keyword">FROM</span> table1 <span class="keyword">USE</span> <span class="keyword">INDEX</span> (key1,key2) <span class="keyword">WHERE</span> key1=<span class="number">1</span> <span class="keyword">AND</span> key2=<span class="number">2</span> <span class="keyword">AND</span> key3=<span class="number">3</span>;</span><br><span class="line"> <span class="keyword">SELECT</span> * <span class="keyword">FROM</span> table1 <span class="keyword">IGNORE</span> <span class="keyword">INDEX</span> (key3) <span class="keyword">WHERE</span> key1=<span class="number">1</span> <span class="keyword">AND</span> key2=<span class="number">2</span> <span class="keyword">AND</span> key3=<span class="number">3</span>;</span><br><span class="line"></span><br><span class="line">c. WHERE 子句</span><br><span class="line"> <span class="comment">-- 从from获得的数据源中进行筛选。</span></span><br><span class="line"> <span class="comment">-- 整型1表示真,0表示假。</span></span><br><span class="line"> <span class="comment">-- 表达式由运算符和运算数组成。</span></span><br><span class="line"> <span class="comment">-- 运算数:变量(字段)、值、函数返回值</span></span><br><span class="line"> <span class="comment">-- 运算符:</span></span><br><span class="line"> =, <=>, <>, !=, <=, <, >=, >, !, &&, ||,</span><br><span class="line"> in (not) null, (not) like, (not) in, (not) between and, is (not), and, or, not, xor</span><br><span class="line"> is/is not 加上ture/false/unknown,检验某个值的真假</span><br><span class="line"> <=>与<>功能相同,<=>可用于null比较</span><br><span class="line"></span><br><span class="line">d. GROUP BY 子句, 分组子句</span><br><span class="line"> GROUP BY 字段/别名 [排序方式]</span><br><span class="line"> 分组后会进行排序。升序:ASC,降序:DESC</span><br><span class="line"></span><br><span class="line"> 以下[合计函数]需配合 GROUP BY 使用:</span><br><span class="line"> count 返回不同的非NULL值数目 count(*)、count(字段)</span><br><span class="line"> sum 求和</span><br><span class="line"> max 求最大值</span><br><span class="line"> min 求最小值</span><br><span class="line"> avg 求平均值</span><br><span class="line"> group_concat 返回带有来自一个组的连接的非NULL值的字符串结果。组内字符串连接。</span><br><span class="line"></span><br><span class="line">e. HAVING 子句,条件子句</span><br><span class="line"> 与 where 功能、用法相同,执行时机不同。</span><br><span class="line"> where 在开始时执行检测数据,对原数据进行过滤。</span><br><span class="line"> having 对筛选出的结果再次进行过滤。</span><br><span class="line"> having 字段必须是查询出来的,where 字段必须是数据表存在的。</span><br><span class="line"> where 不可以使用字段的别名,having 可以。因为执行WHERE代码时,可能尚未确定列值。</span><br><span class="line"> where 不可以使用合计函数。一般需用合计函数才会用 having</span><br><span class="line"> SQL标准要求HAVING必须引用GROUP BY子句中的列或用于合计函数中的列。</span><br><span class="line"></span><br><span class="line">f. ORDER BY 子句,排序子句</span><br><span class="line"> order by 排序字段/别名 排序方式 [,排序字段/别名 排序方式]...</span><br><span class="line"> 升序:ASC,降序:DESC</span><br><span class="line"> 支持多个字段的排序。</span><br><span class="line"></span><br><span class="line">g. LIMIT 子句,限制结果数量子句</span><br><span class="line"> 仅对处理好的结果进行数量限制。将处理好的结果的看作是一个集合,按照记录出现的顺序,索引从0开始。</span><br><span class="line"> limit 起始位置, 获取条数</span><br><span class="line"> 省略第一个参数,表示从索引0开始。limit 获取条数</span><br><span class="line"></span><br><span class="line">h. DISTINCT, ALL 选项</span><br><span class="line"> distinct 去除重复记录</span><br><span class="line"> 默认为 all, 全部记录</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* UNION */</span> <span class="comment">------------------</span></span><br><span class="line"> 将多个<span class="keyword">select</span>查询的结果组合成一个结果集合。</span><br><span class="line"> <span class="keyword">SELECT</span> ... <span class="keyword">UNION</span> [<span class="keyword">ALL</span>|<span class="keyword">DISTINCT</span>] <span class="keyword">SELECT</span> ...</span><br><span class="line"> 默认 <span class="keyword">DISTINCT</span> 方式,即所有返回的行都是唯一的</span><br><span class="line"> 建议,对每个<span class="keyword">SELECT</span>查询加上小括号包裹。</span><br><span class="line"> <span class="keyword">ORDER</span> <span class="keyword">BY</span> 排序时,需加上 <span class="keyword">LIMIT</span> 进行结合。</span><br><span class="line"> 需要各<span class="keyword">select</span>查询的字段数量一样。</span><br><span class="line"> 每个<span class="keyword">select</span>查询的字段列表(数量、类型)应一致,因为结果中的字段名以第一条<span class="keyword">select</span>语句为准。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 子查询 */</span> <span class="comment">------------------</span></span><br><span class="line"> - 子查询需用括号包裹。</span><br><span class="line"><span class="comment">-- from型</span></span><br><span class="line"> <span class="keyword">from</span>后要求是一个表,必须给子查询结果取个别名。</span><br><span class="line"> - 简化每个查询内的条件。</span><br><span class="line"> - <span class="keyword">from</span>型需将结果生成一个临时表格,可用以原表的锁定的释放。</span><br><span class="line"> - 子查询返回一个表,表型子查询。</span><br><span class="line"> <span class="keyword">select</span> * <span class="keyword">from</span> (<span class="keyword">select</span> * <span class="keyword">from</span> tb <span class="keyword">where</span> <span class="keyword">id</span>><span class="number">0</span>) <span class="keyword">as</span> subfrom <span class="keyword">where</span> <span class="keyword">id</span>><span class="number">1</span>;</span><br><span class="line"><span class="comment">-- where型</span></span><br><span class="line"> - 子查询返回一个值,标量子查询。</span><br><span class="line"> - 不需要给子查询取别名。</span><br><span class="line"> - where子查询内的表,不能直接用以更新。</span><br><span class="line"> <span class="keyword">select</span> * <span class="keyword">from</span> tb <span class="keyword">where</span> money = (<span class="keyword">select</span> <span class="keyword">max</span>(money) <span class="keyword">from</span> tb);</span><br><span class="line"> <span class="comment">-- 列子查询</span></span><br><span class="line"> 如果子查询结果返回的是一列。</span><br><span class="line"> 使用 in 或 not in 完成查询</span><br><span class="line"> exists 和 not exists 条件</span><br><span class="line"> 如果子查询返回数据,则返回1或0。常用于判断条件。</span><br><span class="line"> <span class="keyword">select</span> column1 <span class="keyword">from</span> t1 <span class="keyword">where</span> <span class="keyword">exists</span> (<span class="keyword">select</span> * <span class="keyword">from</span> t2);</span><br><span class="line"> <span class="comment">-- 行子查询</span></span><br><span class="line"> 查询条件是一个行。</span><br><span class="line"> <span class="keyword">select</span> * <span class="keyword">from</span> t1 <span class="keyword">where</span> (<span class="keyword">id</span>, gender) <span class="keyword">in</span> (<span class="keyword">select</span> <span class="keyword">id</span>, gender <span class="keyword">from</span> t2);</span><br><span class="line"> 行构造符:(col1, col2, ...) 或 ROW(col1, col2, ...)</span><br><span class="line"> 行构造符通常用于与对能返回两个或两个以上列的子查询进行比较。</span><br><span class="line"></span><br><span class="line"> <span class="comment">-- 特殊运算符</span></span><br><span class="line"> != all() 相当于 not in</span><br><span class="line"> = some() 相当于 in。any 是 some 的别名</span><br><span class="line"> != some() 不等同于 not in,不等于其中某一个。</span><br><span class="line"> all, some 可以配合其他运算符一起使用。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 连接查询(join) */</span> <span class="comment">------------------</span></span><br><span class="line"> 将多个表的字段进行连接,可以指定连接条件。</span><br><span class="line"><span class="comment">-- 内连接(inner join)</span></span><br><span class="line"> - 默认就是内连接,可省略inner。</span><br><span class="line"> - 只有数据存在时才能发送连接。即连接结果不能出现空行。</span><br><span class="line"> on 表示连接条件。其条件表达式与where类似。也可以省略条件(表示条件永远为真)</span><br><span class="line"> 也可用where表示连接条件。</span><br><span class="line"> 还有 using, 但需字段名相同。 using(字段名)</span><br><span class="line"></span><br><span class="line"> <span class="comment">-- 交叉连接 cross join</span></span><br><span class="line"> 即,没有条件的内连接。</span><br><span class="line"> <span class="keyword">select</span> * <span class="keyword">from</span> tb1 <span class="keyword">cross</span> <span class="keyword">join</span> tb2;</span><br><span class="line"><span class="comment">-- 外连接(outer join)</span></span><br><span class="line"> - 如果数据不存在,也会出现在连接结果中。</span><br><span class="line"> <span class="comment">-- 左外连接 left join</span></span><br><span class="line"> 如果数据不存在,左表记录会出现,而右表为null填充</span><br><span class="line"> <span class="comment">-- 右外连接 right join</span></span><br><span class="line"> 如果数据不存在,右表记录会出现,而左表为null填充</span><br><span class="line"><span class="comment">-- 自然连接(natural join)</span></span><br><span class="line"> 自动判断连接条件完成连接。</span><br><span class="line"> 相当于省略了using,会自动查找相同字段名。</span><br><span class="line"> natural join</span><br><span class="line"> natural left join</span><br><span class="line"> natural right join</span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> info.id, info.name, info.stu_num, extra_info.hobby, extra_info.sex <span class="keyword">from</span> info, extra_info <span class="keyword">where</span> info.stu_num = extra_info.stu_id;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 导入导出 */</span> <span class="comment">------------------</span></span><br><span class="line"><span class="keyword">select</span> * <span class="keyword">into</span> <span class="keyword">outfile</span> 文件地址 [控制格式] <span class="keyword">from</span> 表名; <span class="comment">-- 导出表数据</span></span><br><span class="line"><span class="keyword">load</span> <span class="keyword">data</span> [<span class="keyword">local</span>] <span class="keyword">infile</span> 文件地址 [<span class="keyword">replace</span>|<span class="keyword">ignore</span>] <span class="keyword">into</span> <span class="keyword">table</span> 表名 [控制格式]; <span class="comment">-- 导入数据</span></span><br><span class="line"> 生成的数据默认的分隔符是制表符</span><br><span class="line"> local未指定,则数据文件必须在服务器上</span><br><span class="line"> <span class="keyword">replace</span> 和 <span class="keyword">ignore</span> 关键词控制对现有的唯一键记录的重复的处理</span><br><span class="line"><span class="comment">-- 控制格式</span></span><br><span class="line"><span class="keyword">fields</span> 控制字段格式</span><br><span class="line">默认:<span class="keyword">fields</span> <span class="keyword">terminated</span> <span class="keyword">by</span> <span class="string">'\t'</span> <span class="keyword">enclosed</span> <span class="keyword">by</span> <span class="string">''</span> <span class="keyword">escaped</span> <span class="keyword">by</span> <span class="string">'\\'</span></span><br><span class="line"> <span class="keyword">terminated</span> <span class="keyword">by</span> <span class="string">'string'</span> <span class="comment">-- 终止</span></span><br><span class="line"> <span class="keyword">enclosed</span> <span class="keyword">by</span> <span class="string">'char'</span> <span class="comment">-- 包裹</span></span><br><span class="line"> <span class="keyword">escaped</span> <span class="keyword">by</span> <span class="string">'char'</span> <span class="comment">-- 转义</span></span><br><span class="line"> <span class="comment">-- 示例:</span></span><br><span class="line"> <span class="keyword">SELECT</span> a,b,a+b <span class="keyword">INTO</span> <span class="keyword">OUTFILE</span> <span class="string">'/tmp/result.text'</span></span><br><span class="line"> <span class="keyword">FIELDS</span> <span class="keyword">TERMINATED</span> <span class="keyword">BY</span> <span class="string">','</span> <span class="keyword">OPTIONALLY</span> <span class="keyword">ENCLOSED</span> <span class="keyword">BY</span> <span class="string">'"'</span></span><br><span class="line"> <span class="keyword">LINES</span> <span class="keyword">TERMINATED</span> <span class="keyword">BY</span> <span class="string">'\n'</span></span><br><span class="line"> <span class="keyword">FROM</span> test_table;</span><br><span class="line">lines 控制行格式</span><br><span class="line">默认:lines terminated by '\n'</span><br><span class="line"> terminated by 'string' <span class="comment">-- 终止</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* INSERT */</span> <span class="comment">------------------</span></span><br><span class="line"><span class="keyword">select</span>语句获得的数据可以用<span class="keyword">insert</span>插入。</span><br><span class="line"></span><br><span class="line">可以省略对列的指定,要求 <span class="keyword">values</span> () 括号内,提供给了按照列顺序出现的所有字段的值。</span><br><span class="line"> 或者使用<span class="keyword">set</span>语法。</span><br><span class="line"> <span class="keyword">INSERT</span> <span class="keyword">INTO</span> tbl_name <span class="keyword">SET</span> <span class="keyword">field</span>=<span class="keyword">value</span>,...;</span><br><span class="line"></span><br><span class="line">可以一次性使用多个值,采用(), (), ();的形式。</span><br><span class="line"> <span class="keyword">INSERT</span> <span class="keyword">INTO</span> tbl_name <span class="keyword">VALUES</span> (), (), ();</span><br><span class="line"></span><br><span class="line">可以在列值指定时,使用表达式。</span><br><span class="line"> <span class="keyword">INSERT</span> <span class="keyword">INTO</span> tbl_name <span class="keyword">VALUES</span> (field_value, <span class="number">10</span>+<span class="number">10</span>, <span class="keyword">now</span>());</span><br><span class="line">可以使用一个特殊值 DEFAULT,表示该列使用默认值。</span><br><span class="line"> <span class="keyword">INSERT</span> <span class="keyword">INTO</span> tbl_name <span class="keyword">VALUES</span> (field_value, <span class="keyword">DEFAULT</span>);</span><br><span class="line"></span><br><span class="line">可以通过一个查询的结果,作为需要插入的值。</span><br><span class="line"> <span class="keyword">INSERT</span> <span class="keyword">INTO</span> tbl_name <span class="keyword">SELECT</span> ...;</span><br><span class="line"></span><br><span class="line">可以指定在插入的值出现主键(或唯一索引)冲突时,更新其他非主键列的信息。</span><br><span class="line"> <span class="keyword">INSERT</span> <span class="keyword">INTO</span> tbl_name <span class="keyword">VALUES</span>/<span class="keyword">SET</span>/<span class="keyword">SELECT</span> <span class="keyword">ON</span> <span class="keyword">DUPLICATE</span> <span class="keyword">KEY</span> <span class="keyword">UPDATE</span> 字段=值, …;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* DELETE */</span> <span class="comment">------------------</span></span><br><span class="line"><span class="keyword">DELETE</span> <span class="keyword">FROM</span> tbl_name [<span class="keyword">WHERE</span> where_definition] [<span class="keyword">ORDER</span> <span class="keyword">BY</span> ...] [<span class="keyword">LIMIT</span> <span class="keyword">row_count</span>]</span><br><span class="line"></span><br><span class="line">按照条件删除。<span class="keyword">where</span></span><br><span class="line"></span><br><span class="line">指定删除的最多记录数。<span class="keyword">limit</span></span><br><span class="line"></span><br><span class="line">可以通过排序条件删除。<span class="keyword">order</span> <span class="keyword">by</span> + <span class="keyword">limit</span></span><br><span class="line"></span><br><span class="line">支持多表删除,使用类似连接语法。</span><br><span class="line"><span class="keyword">delete</span> <span class="keyword">from</span> 需要删除数据多表<span class="number">1</span>,表<span class="number">2</span> <span class="keyword">using</span> 表连接操作 条件。</span><br><span class="line"></span><br><span class="line"><span class="comment">/* TRUNCATE */</span> <span class="comment">------------------</span></span><br><span class="line"><span class="keyword">TRUNCATE</span> [<span class="keyword">TABLE</span>] tbl_name</span><br><span class="line">清空数据</span><br><span class="line">删除重建表</span><br><span class="line"></span><br><span class="line">区别:</span><br><span class="line"><span class="number">1</span>,<span class="keyword">truncate</span> 是删除表再创建,<span class="keyword">delete</span> 是逐条删除</span><br><span class="line"><span class="number">2</span>,<span class="keyword">truncate</span> 重置auto_increment的值。而<span class="keyword">delete</span>不会</span><br><span class="line"><span class="number">3</span>,<span class="keyword">truncate</span> 不知道删除了几条,而<span class="keyword">delete</span>知道。</span><br><span class="line"><span class="number">4</span>,当被用于带分区的表时,<span class="keyword">truncate</span> 会保留分区</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 备份与还原 */</span> <span class="comment">------------------</span></span><br><span class="line">备份,将数据的结构与表内数据保存起来。</span><br><span class="line">利用 mysqldump 指令完成。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 导出</span></span><br><span class="line">mysqldump [options] db_name [<span class="keyword">tables</span>]</span><br><span class="line">mysqldump [options] <span class="comment">---database DB1 [DB2 DB3...]</span></span><br><span class="line">mysqldump [options] <span class="comment">--all--database</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="number">1.</span> 导出一张表</span><br><span class="line"> mysqldump -u用户名 -p密码 库名 表名 > 文件名(D:/a.sql)</span><br><span class="line"><span class="number">2.</span> 导出多张表</span><br><span class="line"> mysqldump -u用户名 -p密码 库名 表<span class="number">1</span> 表<span class="number">2</span> 表<span class="number">3</span> > 文件名(D:/a.sql)</span><br><span class="line"><span class="number">3.</span> 导出所有表</span><br><span class="line"> mysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql)</span><br><span class="line"><span class="number">4.</span> 导出一个库</span><br><span class="line"> mysqldump -u用户名 -p密码 <span class="comment">--lock-all-tables --database 库名 > 文件名(D:/a.sql)</span></span><br><span class="line"></span><br><span class="line">可以-w携带<span class="keyword">WHERE</span>条件</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 导入</span></span><br><span class="line"><span class="number">1.</span> 在登录mysql的情况下:</span><br><span class="line"> <span class="keyword">source</span> 备份文件</span><br><span class="line"><span class="number">2.</span> 在不登录的情况下</span><br><span class="line"> mysql -u用户名 -p密码 库名 < 备份文件</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 事务(transaction) */</span> <span class="comment">------------------</span></span><br><span class="line">事务是指逻辑上的一组操作,组成这组操作的各个单元,要不全成功要不全失败。</span><br><span class="line"> - 支持连续<span class="keyword">SQL</span>的集体成功或集体撤销。</span><br><span class="line"> - 事务是数据库在数据晚自习方面的一个功能。</span><br><span class="line"> - 需要利用 <span class="keyword">InnoDB</span> 或 BDB 存储引擎,对自动提交的特性支持完成。</span><br><span class="line"> - <span class="keyword">InnoDB</span>被称为事务安全型引擎。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 事务开启</span></span><br><span class="line"> <span class="keyword">START</span> <span class="keyword">TRANSACTION</span>; 或者 <span class="keyword">BEGIN</span>;</span><br><span class="line"> 开启事务后,所有被执行的SQL语句均被认作当前事务内的SQL语句。</span><br><span class="line"><span class="comment">-- 事务提交</span></span><br><span class="line"> <span class="keyword">COMMIT</span>;</span><br><span class="line"><span class="comment">-- 事务回滚</span></span><br><span class="line"> <span class="keyword">ROLLBACK</span>;</span><br><span class="line"> 如果部分操作发生问题,映射到事务开启前。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 事务的特性</span></span><br><span class="line"> 1. 原子性(Atomicity)</span><br><span class="line"> 事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。</span><br><span class="line"> 2. 一致性(Consistency)</span><br><span class="line"> 事务前后数据的完整性必须保持一致。</span><br><span class="line"> - 事务开始和结束时,外部数据一致</span><br><span class="line"> - 在整个事务过程中,操作是连续的</span><br><span class="line"> 3. 隔离性(Isolation)</span><br><span class="line"> 多个用户并发访问数据库时,一个用户的事务不能被其它用户的事物所干扰,多个并发事务之间的数据要相互隔离。</span><br><span class="line"> 4. 持久性(Durability)</span><br><span class="line"> 一个事务一旦被提交,它对数据库中的数据改变就是永久性的。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 事务的实现</span></span><br><span class="line"> 1. 要求是事务支持的表类型</span><br><span class="line"> 2. 执行一组相关的操作前开启事务</span><br><span class="line"> 3. 整组操作完成后,都成功,则提交;如果存在失败,选择回滚,则会回到事务开始的备份点。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 事务的原理</span></span><br><span class="line"> 利用InnoDB的自动提交(autocommit)特性完成。</span><br><span class="line"> 普通的MySQL执行语句后,当前的数据提交操作均可被其他客户端可见。</span><br><span class="line"> 而事务是暂时关闭“自动提交”机制,需要<span class="keyword">commit</span>提交持久化数据操作。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 注意</span></span><br><span class="line"> <span class="number">1.</span> 数据定义语言(<span class="keyword">DDL</span>)语句不能被回滚,比如创建或取消数据库的语句,和创建、取消或更改表或存储的子程序的语句。</span><br><span class="line"> <span class="number">2.</span> 事务不能被嵌套</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 保存点</span></span><br><span class="line"> <span class="keyword">SAVEPOINT</span> 保存点名称 <span class="comment">-- 设置一个事务保存点</span></span><br><span class="line"> <span class="keyword">ROLLBACK</span> <span class="keyword">TO</span> <span class="keyword">SAVEPOINT</span> 保存点名称 <span class="comment">-- 回滚到保存点</span></span><br><span class="line"> <span class="keyword">RELEASE</span> <span class="keyword">SAVEPOINT</span> 保存点名称 <span class="comment">-- 删除保存点</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- InnoDB自动提交特性设置</span></span><br><span class="line"> <span class="keyword">SET</span> autocommit = <span class="number">0</span>|<span class="number">1</span>; 0表示关闭自动提交,1表示开启自动提交。</span><br><span class="line"> - 如果关闭了,那普通操作的结果对其他客户端也不可见,需要<span class="keyword">commit</span>提交后才能持久化数据操作。</span><br><span class="line"> - 也可以关闭自动提交来开启事务。但与<span class="keyword">START</span> <span class="keyword">TRANSACTION</span>不同的是,</span><br><span class="line"> <span class="keyword">SET</span> autocommit是永久改变服务器的设置,直到下次再次修改该设置。(针对当前连接)</span><br><span class="line"> 而<span class="keyword">START</span> <span class="keyword">TRANSACTION</span>记录开启前的状态,而一旦事务提交或回滚后就需要再次开启事务。(针对当前事务)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 锁表 */</span></span><br><span class="line">表锁定只用于防止其它客户端进行不正当地读取和写入</span><br><span class="line">MyISAM 支持表锁,<span class="keyword">InnoDB</span> 支持行锁</span><br><span class="line"><span class="comment">-- 锁定</span></span><br><span class="line"> <span class="keyword">LOCK</span> <span class="keyword">TABLES</span> tbl_name [<span class="keyword">AS</span> <span class="keyword">alias</span>]</span><br><span class="line"><span class="comment">-- 解锁</span></span><br><span class="line"> <span class="keyword">UNLOCK</span> <span class="keyword">TABLES</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 字符连接函数</span></span><br><span class="line"><span class="keyword">concat</span>(str1,str2,...])</span><br><span class="line"><span class="keyword">concat_ws</span>(separator,str1,str2,...)</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 分支语句</span></span><br><span class="line"><span class="keyword">if</span> 条件 <span class="keyword">then</span></span><br><span class="line"> 执行语句</span><br><span class="line">elseif 条件 <span class="keyword">then</span></span><br><span class="line"> 执行语句</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> 执行语句</span><br><span class="line"><span class="keyword">end</span> <span class="keyword">if</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 修改最外层语句结束符</span></span><br><span class="line">delimiter 自定义结束符号</span><br><span class="line"> SQL语句</span><br><span class="line">自定义结束符号</span><br><span class="line"></span><br><span class="line">delimiter ; <span class="comment">-- 修改回原来的分号</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 语句块包裹</span></span><br><span class="line"><span class="keyword">begin</span></span><br><span class="line"> 语句块</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 特殊的执行</span></span><br><span class="line"><span class="number">1.</span> 只要添加记录,就会触发程序。</span><br><span class="line"><span class="number">2.</span> <span class="keyword">Insert</span> <span class="keyword">into</span> <span class="keyword">on</span> <span class="keyword">duplicate</span> <span class="keyword">key</span> <span class="keyword">update</span> 语法会触发:</span><br><span class="line"> 如果没有重复记录,会触发 <span class="keyword">before</span> <span class="keyword">insert</span>, <span class="keyword">after</span> <span class="keyword">insert</span>;</span><br><span class="line"> 如果有重复记录并更新,会触发 before <span class="keyword">insert</span>, <span class="keyword">before</span> <span class="keyword">update</span>, <span class="keyword">after</span> <span class="keyword">update</span>;</span><br><span class="line"> 如果有重复记录但是没有发生更新,则触发 before <span class="keyword">insert</span>, <span class="keyword">before</span> <span class="keyword">update</span></span><br><span class="line"><span class="number">3.</span> <span class="keyword">Replace</span> 语法 如果有记录,则执行 <span class="keyword">before</span> <span class="keyword">insert</span>, <span class="keyword">before</span> <span class="keyword">delete</span>, <span class="keyword">after</span> <span class="keyword">delete</span>, <span class="keyword">after</span> <span class="keyword">insert</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* SQL编程 */</span> <span class="comment">------------------</span></span><br><span class="line"></span><br><span class="line"><span class="comment">--// 局部变量 ----------</span></span><br><span class="line"><span class="comment">-- 变量声明</span></span><br><span class="line"> <span class="keyword">declare</span> var_name[,...] <span class="keyword">type</span> [<span class="keyword">default</span> <span class="keyword">value</span>]</span><br><span class="line"> 这个语句被用来声明局部变量。要给变量提供一个默认值,请包含一个<span class="keyword">default</span>子句。值可以被指定为一个表达式,不需要为一个常数。如果没有<span class="keyword">default</span>子句,初始值为<span class="literal">null</span>。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 赋值</span></span><br><span class="line"> 使用 <span class="keyword">set</span> 和 <span class="keyword">select</span> <span class="keyword">into</span> 语句为变量赋值。</span><br><span class="line"></span><br><span class="line"> - 注意:在函数内是可以使用全局变量(用户自定义的变量)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">--// 全局变量 ----------</span></span><br><span class="line"><span class="comment">-- 定义、赋值</span></span><br><span class="line"><span class="keyword">set</span> 语句可以定义并为变量赋值。</span><br><span class="line"><span class="keyword">set</span> @<span class="keyword">var</span> = <span class="keyword">value</span>;</span><br><span class="line">也可以使用<span class="keyword">select</span> <span class="keyword">into</span>语句为变量初始化并赋值。这样要求<span class="keyword">select</span>语句只能返回一行,但是可以是多个字段,就意味着同时为多个变量进行赋值,变量的数量需要与查询的列数一致。</span><br><span class="line">还可以把赋值语句看作一个表达式,通过<span class="keyword">select</span>执行完成。此时为了避免=被当作关系运算符看待,使用:=代替。(<span class="keyword">set</span>语句可以使用= 和 :=)。</span><br><span class="line"><span class="keyword">select</span> @<span class="keyword">var</span>:=<span class="number">20</span>;</span><br><span class="line"><span class="keyword">select</span> @v1:=<span class="keyword">id</span>, @v2=<span class="keyword">name</span> <span class="keyword">from</span> t1 <span class="keyword">limit</span> <span class="number">1</span>;</span><br><span class="line"><span class="keyword">select</span> * <span class="keyword">from</span> tbl_name <span class="keyword">where</span> @<span class="keyword">var</span>:=<span class="number">30</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">into</span> 可以将表中查询获得的数据赋给变量。</span><br><span class="line"> -| <span class="keyword">select</span> <span class="keyword">max</span>(height) <span class="keyword">into</span> @max_height <span class="keyword">from</span> tb;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 自定义变量名</span></span><br><span class="line">为了避免<span class="keyword">select</span>语句中,用户自定义的变量与系统标识符(通常是字段名)冲突,用户自定义变量在变量名前使用@作为开始符号。</span><br><span class="line">@<span class="keyword">var</span>=<span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"> - 变量被定义后,在整个会话周期都有效(登录到退出)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">--// 控制结构 ----------</span></span><br><span class="line"><span class="comment">-- if语句</span></span><br><span class="line">if search_condition then</span><br><span class="line"> statement_list</span><br><span class="line">[elseif search_condition then</span><br><span class="line"> statement_list]</span><br><span class="line">...</span><br><span class="line">[else</span><br><span class="line"> statement_list]</span><br><span class="line"><span class="keyword">end</span> <span class="keyword">if</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- case语句</span></span><br><span class="line">CASE value WHEN [compare-value] THEN result</span><br><span class="line">[WHEN [compare-value] THEN result ...]</span><br><span class="line">[ELSE result]</span><br><span class="line"><span class="keyword">END</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">-- while循环</span></span><br><span class="line">[begin_label:] <span class="keyword">while</span> search_condition <span class="keyword">do</span></span><br><span class="line"> statement_list</span><br><span class="line"><span class="keyword">end</span> <span class="keyword">while</span> [end_label];</span><br><span class="line"></span><br><span class="line">- 如果需要在循环内提前终止 while循环,则需要使用标签;标签需要成对出现。</span><br><span class="line"></span><br><span class="line"> <span class="comment">-- 退出循环</span></span><br><span class="line"> 退出整个循环 leave</span><br><span class="line"> 退出当前循环 iterate</span><br><span class="line"> 通过退出的标签决定退出哪个循环</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">--// 内置函数 ----------</span></span><br><span class="line"><span class="comment">-- 数值函数</span></span><br><span class="line">abs(x) <span class="comment">-- 绝对值 abs(-10.9) = 10</span></span><br><span class="line">format(x, d) <span class="comment">-- 格式化千分位数值 format(1234567.456, 2) = 1,234,567.46</span></span><br><span class="line">ceil(x) <span class="comment">-- 向上取整 ceil(10.1) = 11</span></span><br><span class="line">floor(x) <span class="comment">-- 向下取整 floor (10.1) = 10</span></span><br><span class="line">round(x) <span class="comment">-- 四舍五入去整</span></span><br><span class="line">mod(m, n) <span class="comment">-- m%n m mod n 求余 10%3=1</span></span><br><span class="line">pi() <span class="comment">-- 获得圆周率</span></span><br><span class="line">pow(m, n) <span class="comment">-- m^n</span></span><br><span class="line">sqrt(x) <span class="comment">-- 算术平方根</span></span><br><span class="line">rand() <span class="comment">-- 随机数</span></span><br><span class="line"><span class="keyword">truncate</span>(x, d) <span class="comment">-- 截取d位小数</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 时间日期函数</span></span><br><span class="line"><span class="keyword">now</span>(), <span class="keyword">current_timestamp</span>(); <span class="comment">-- 当前日期时间</span></span><br><span class="line">current_date(); <span class="comment">-- 当前日期</span></span><br><span class="line">current_time(); <span class="comment">-- 当前时间</span></span><br><span class="line">date('yyyy-mm-dd hh:ii:ss'); <span class="comment">-- 获取日期部分</span></span><br><span class="line">time('yyyy-mm-dd hh:ii:ss'); <span class="comment">-- 获取时间部分</span></span><br><span class="line">date_format('yyyy-mm-dd hh:ii:ss', '%d %y %a %d %m %b %j'); <span class="comment">-- 格式化时间</span></span><br><span class="line">unix_timestamp(); <span class="comment">-- 获得unix时间戳</span></span><br><span class="line">from_unixtime(); <span class="comment">-- 从时间戳获得时间</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 字符串函数</span></span><br><span class="line">length(string) <span class="comment">-- string长度,字节</span></span><br><span class="line">char_length(string) <span class="comment">-- string的字符个数</span></span><br><span class="line">substring(str, position [,length]) <span class="comment">-- 从str的position开始,取length个字符</span></span><br><span class="line"><span class="keyword">replace</span>(<span class="keyword">str</span> ,search_str ,replace_str) <span class="comment">-- 在str中用replace_str替换search_str</span></span><br><span class="line"><span class="keyword">instr</span>(<span class="keyword">string</span> ,<span class="keyword">substring</span>) <span class="comment">-- 返回substring首次在string中出现的位置</span></span><br><span class="line"><span class="keyword">concat</span>(<span class="keyword">string</span> [,...]) <span class="comment">-- 连接字串</span></span><br><span class="line"><span class="keyword">charset</span>(<span class="keyword">str</span>) <span class="comment">-- 返回字串字符集</span></span><br><span class="line"><span class="keyword">lcase</span>(<span class="keyword">string</span>) <span class="comment">-- 转换成小写</span></span><br><span class="line"><span class="keyword">left</span>(<span class="keyword">string</span>, <span class="keyword">length</span>) <span class="comment">-- 从string2中的左边起取length个字符</span></span><br><span class="line"><span class="keyword">load_file</span>(file_name) <span class="comment">-- 从文件读取内容</span></span><br><span class="line"><span class="keyword">locate</span>(<span class="keyword">substring</span>, <span class="keyword">string</span> [,start_position]) <span class="comment">-- 同instr,但可指定开始位置</span></span><br><span class="line"><span class="keyword">lpad</span>(<span class="keyword">string</span>, <span class="keyword">length</span>, <span class="keyword">pad</span>) <span class="comment">-- 重复用pad加在string开头,直到字串长度为length</span></span><br><span class="line"><span class="keyword">ltrim</span>(<span class="keyword">string</span>) <span class="comment">-- 去除前端空格</span></span><br><span class="line"><span class="keyword">repeat</span>(<span class="keyword">string</span>, <span class="keyword">count</span>) <span class="comment">-- 重复count次</span></span><br><span class="line">rpad(<span class="keyword">string</span>, <span class="keyword">length</span>, <span class="keyword">pad</span>) <span class="comment">--在str后用pad补充,直到长度为length</span></span><br><span class="line"><span class="keyword">rtrim</span>(<span class="keyword">string</span>) <span class="comment">-- 去除后端空格</span></span><br><span class="line"><span class="keyword">strcmp</span>(string1 ,string2) <span class="comment">-- 逐字符比较两字串大小</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 流程函数</span></span><br><span class="line"><span class="keyword">case</span> <span class="keyword">when</span> [condition] <span class="keyword">then</span> <span class="keyword">result</span> [<span class="keyword">when</span> [condition] <span class="keyword">then</span> <span class="keyword">result</span> ...] [<span class="keyword">else</span> <span class="keyword">result</span>] <span class="keyword">end</span> 多分支</span><br><span class="line"><span class="keyword">if</span>(expr1,expr2,expr3) 双分支。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 聚合函数</span></span><br><span class="line"><span class="keyword">count</span>()</span><br><span class="line"><span class="keyword">sum</span>();</span><br><span class="line">max();</span><br><span class="line">min();</span><br><span class="line">avg();</span><br><span class="line">group_concat()</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 其他常用函数</span></span><br><span class="line">md5();</span><br><span class="line">default();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">--// 存储函数,自定义函数 ----------</span></span><br><span class="line"><span class="comment">-- 新建</span></span><br><span class="line"> <span class="keyword">CREATE</span> <span class="keyword">FUNCTION</span> function_name (参数列表) <span class="keyword">RETURNS</span> 返回值类型</span><br><span class="line"> 函数体</span><br><span class="line"></span><br><span class="line"> - 函数名,应该合法的标识符,并且不应该与已有的关键字冲突。</span><br><span class="line"> - 一个函数应该属于某个数据库,可以使用db_name.funciton_name的形式执行当前函数所属数据库,否则为当前数据库。</span><br><span class="line"> - 参数部分,由<span class="string">"参数名"</span>和<span class="string">"参数类型"</span>组成。多个参数用逗号隔开。</span><br><span class="line"> - 函数体由多条可用的mysql语句,流程控制,变量声明等语句构成。</span><br><span class="line"> - 多条语句应该使用 begin...end 语句块包含。</span><br><span class="line"> - 一定要有 <span class="keyword">return</span> 返回值语句。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 删除</span></span><br><span class="line"> <span class="keyword">DROP</span> <span class="keyword">FUNCTION</span> [<span class="keyword">IF</span> <span class="keyword">EXISTS</span>] function_name;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 查看</span></span><br><span class="line"> <span class="keyword">SHOW</span> <span class="keyword">FUNCTION</span> <span class="keyword">STATUS</span> <span class="keyword">LIKE</span> <span class="string">'partten'</span></span><br><span class="line"> <span class="keyword">SHOW</span> <span class="keyword">CREATE</span> <span class="keyword">FUNCTION</span> function_name;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 修改</span></span><br><span class="line"> <span class="keyword">ALTER</span> <span class="keyword">FUNCTION</span> function_name 函数选项</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">--// 存储过程,自定义功能 ----------</span></span><br><span class="line"><span class="comment">-- 定义</span></span><br><span class="line">存储存储过程 是一段代码(过程),存储在数据库中的<span class="keyword">sql</span>组成。</span><br><span class="line">一个存储过程通常用于完成一段业务逻辑,例如报名,交班费,订单入库等。</span><br><span class="line">而一个函数通常专注与某个功能,视为其他程序服务的,需要在其他语句中调用函数才可以,而存储过程不能被其他调用,是自己执行 通过<span class="keyword">call</span>执行。</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 创建</span></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">PROCEDURE</span> sp_name (参数列表)</span><br><span class="line"> 过程体</span><br><span class="line"></span><br><span class="line">参数列表:不同于函数的参数列表,需要指明参数类型</span><br><span class="line"><span class="keyword">IN</span>,表示输入型</span><br><span class="line"><span class="keyword">OUT</span>,表示输出型</span><br><span class="line">INOUT,表示混合型</span><br><span class="line"></span><br><span class="line">注意,没有返回值。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 存储过程 */</span> <span class="comment">------------------</span></span><br><span class="line">存储过程是一段可执行性代码的集合。相比函数,更偏向于业务逻辑。</span><br><span class="line">调用:<span class="keyword">CALL</span> 过程名</span><br><span class="line"><span class="comment">-- 注意</span></span><br><span class="line">- 没有返回值。</span><br><span class="line">- 只能单独调用,不可夹杂在其他语句中</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 参数</span></span><br><span class="line"><span class="keyword">IN</span>|<span class="keyword">OUT</span>|INOUT 参数名 数据类型</span><br><span class="line"><span class="keyword">IN</span> 输入:在调用过程中,将数据输入到过程体内部的参数</span><br><span class="line"><span class="keyword">OUT</span> 输出:在调用过程中,将过程体处理完的结果返回到客户端</span><br><span class="line">INOUT 输入输出:既可输入,也可输出</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 语法</span></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">PROCEDURE</span> 过程名 (参数列表)</span><br><span class="line"><span class="keyword">BEGIN</span></span><br><span class="line"> 过程体</span><br><span class="line"><span class="keyword">END</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 用户和权限管理 */</span> <span class="comment">------------------</span></span><br><span class="line"><span class="comment">-- root密码重置</span></span><br><span class="line"><span class="number">1.</span> 停止MySQL服务</span><br><span class="line"><span class="number">2.</span> [Linux] /usr/<span class="keyword">local</span>/mysql/<span class="keyword">bin</span>/safe_mysqld <span class="comment">--skip-grant-tables &</span></span><br><span class="line"> [Windows] mysqld <span class="comment">--skip-grant-tables</span></span><br><span class="line"><span class="number">3.</span> <span class="keyword">use</span> mysql;</span><br><span class="line">4. <span class="keyword">UPDATE</span> <span class="string">`user`</span> <span class="keyword">SET</span> <span class="keyword">PASSWORD</span>=<span class="keyword">PASSWORD</span>(<span class="string">"密码"</span>) <span class="keyword">WHERE</span> <span class="string">`user`</span> = <span class="string">"root"</span>;</span><br><span class="line">5. <span class="keyword">FLUSH</span> <span class="keyword">PRIVILEGES</span>;</span><br><span class="line"></span><br><span class="line">用户信息表:mysql.user</span><br><span class="line"><span class="comment">-- 刷新权限</span></span><br><span class="line"><span class="keyword">FLUSH</span> <span class="keyword">PRIVILEGES</span>;</span><br><span class="line"><span class="comment">-- 增加用户</span></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">USER</span> 用户名 <span class="keyword">IDENTIFIED</span> <span class="keyword">BY</span> [<span class="keyword">PASSWORD</span>] 密码(字符串)</span><br><span class="line"> - 必须拥有mysql数据库的全局<span class="keyword">CREATE</span> <span class="keyword">USER</span>权限,或拥有<span class="keyword">INSERT</span>权限。</span><br><span class="line"> - 只能创建用户,不能赋予权限。</span><br><span class="line"> - 用户名,注意引号:如 <span class="string">'user_name'</span>@<span class="string">'192.168.1.1'</span></span><br><span class="line"> - 密码也需引号,纯数字密码也要加引号</span><br><span class="line"> - 要在纯文本中指定密码,需忽略<span class="keyword">PASSWORD</span>关键词。要把密码指定为由<span class="keyword">PASSWORD</span>()函数返回的混编值,需包含关键字<span class="keyword">PASSWORD</span></span><br><span class="line"><span class="comment">-- 重命名用户</span></span><br><span class="line"><span class="keyword">RENAME</span> <span class="keyword">USER</span> old_user <span class="keyword">TO</span> new_user</span><br><span class="line"><span class="comment">-- 设置密码</span></span><br><span class="line"><span class="keyword">SET</span> <span class="keyword">PASSWORD</span> = <span class="keyword">PASSWORD</span>(<span class="string">'密码'</span>) <span class="comment">-- 为当前用户设置密码</span></span><br><span class="line"><span class="keyword">SET</span> <span class="keyword">PASSWORD</span> <span class="keyword">FOR</span> 用户名 = <span class="keyword">PASSWORD</span>(<span class="string">'密码'</span>) <span class="comment">-- 为指定用户设置密码</span></span><br><span class="line"><span class="comment">-- 删除用户</span></span><br><span class="line"><span class="keyword">DROP</span> <span class="keyword">USER</span> 用户名</span><br><span class="line"><span class="comment">-- 分配权限/添加用户</span></span><br><span class="line"><span class="keyword">GRANT</span> 权限列表 <span class="keyword">ON</span> 表名 <span class="keyword">TO</span> 用户名 [<span class="keyword">IDENTIFIED</span> <span class="keyword">BY</span> [<span class="keyword">PASSWORD</span>] <span class="string">'password'</span>]</span><br><span class="line"> - <span class="keyword">all</span> <span class="keyword">privileges</span> 表示所有权限</span><br><span class="line"> - *.* 表示所有库的所有表</span><br><span class="line"> - 库名.表名 表示某库下面的某表</span><br><span class="line"> <span class="keyword">GRANT</span> <span class="keyword">ALL</span> <span class="keyword">PRIVILEGES</span> <span class="keyword">ON</span> <span class="string">`pms`</span>.* <span class="keyword">TO</span> <span class="string">'pms'</span>@<span class="string">'%'</span> <span class="keyword">IDENTIFIED</span> <span class="keyword">BY</span> <span class="string">'pms0817'</span>;</span><br><span class="line"><span class="comment">-- 查看权限</span></span><br><span class="line"><span class="keyword">SHOW</span> <span class="keyword">GRANTS</span> <span class="keyword">FOR</span> 用户名</span><br><span class="line"> <span class="comment">-- 查看当前用户权限</span></span><br><span class="line"> <span class="keyword">SHOW</span> <span class="keyword">GRANTS</span>; 或 <span class="keyword">SHOW</span> <span class="keyword">GRANTS</span> <span class="keyword">FOR</span> <span class="keyword">CURRENT_USER</span>; 或 <span class="keyword">SHOW</span> <span class="keyword">GRANTS</span> <span class="keyword">FOR</span> <span class="keyword">CURRENT_USER</span>();</span><br><span class="line"><span class="comment">-- 撤消权限</span></span><br><span class="line"><span class="keyword">REVOKE</span> 权限列表 <span class="keyword">ON</span> 表名 <span class="keyword">FROM</span> 用户名</span><br><span class="line"><span class="keyword">REVOKE</span> <span class="keyword">ALL</span> <span class="keyword">PRIVILEGES</span>, <span class="keyword">GRANT</span> <span class="keyword">OPTION</span> <span class="keyword">FROM</span> 用户名 <span class="comment">-- 撤销所有权限</span></span><br><span class="line"><span class="comment">-- 权限层级</span></span><br><span class="line"><span class="comment">-- 要使用GRANT或REVOKE,您必须拥有GRANT OPTION权限,并且您必须用于您正在授予或撤销的权限。</span></span><br><span class="line">全局层级:全局权限适用于一个给定服务器中的所有数据库,mysql.user</span><br><span class="line"> <span class="keyword">GRANT</span> <span class="keyword">ALL</span> <span class="keyword">ON</span> *.*和 <span class="keyword">REVOKE</span> <span class="keyword">ALL</span> <span class="keyword">ON</span> *.*只授予和撤销全局权限。</span><br><span class="line">数据库层级:数据库权限适用于一个给定数据库中的所有目标,mysql.db, mysql.host</span><br><span class="line"> <span class="keyword">GRANT</span> <span class="keyword">ALL</span> <span class="keyword">ON</span> db_name.*和<span class="keyword">REVOKE</span> <span class="keyword">ALL</span> <span class="keyword">ON</span> db_name.*只授予和撤销数据库权限。</span><br><span class="line">表层级:表权限适用于一个给定表中的所有列,mysql.talbes_priv</span><br><span class="line"> <span class="keyword">GRANT</span> <span class="keyword">ALL</span> <span class="keyword">ON</span> db_name.tbl_name和<span class="keyword">REVOKE</span> <span class="keyword">ALL</span> <span class="keyword">ON</span> db_name.tbl_name只授予和撤销表权限。</span><br><span class="line">列层级:列权限适用于一个给定表中的单一列,mysql.columns_priv</span><br><span class="line"> 当使用<span class="keyword">REVOKE</span>时,您必须指定与被授权列相同的列。</span><br><span class="line"><span class="comment">-- 权限列表</span></span><br><span class="line"><span class="keyword">ALL</span> [<span class="keyword">PRIVILEGES</span>] <span class="comment">-- 设置除GRANT OPTION之外的所有简单权限</span></span><br><span class="line"><span class="keyword">ALTER</span> <span class="comment">-- 允许使用ALTER TABLE</span></span><br><span class="line"><span class="keyword">ALTER</span> ROUTINE <span class="comment">-- 更改或取消已存储的子程序</span></span><br><span class="line"><span class="keyword">CREATE</span> <span class="comment">-- 允许使用CREATE TABLE</span></span><br><span class="line"><span class="keyword">CREATE</span> ROUTINE <span class="comment">-- 创建已存储的子程序</span></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TEMPORARY</span> <span class="keyword">TABLES</span> <span class="comment">-- 允许使用CREATE TEMPORARY TABLE</span></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">USER</span> <span class="comment">-- 允许使用CREATE USER, DROP USER, RENAME USER和REVOKE ALL PRIVILEGES。</span></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">VIEW</span> <span class="comment">-- 允许使用CREATE VIEW</span></span><br><span class="line"><span class="keyword">DELETE</span> <span class="comment">-- 允许使用DELETE</span></span><br><span class="line"><span class="keyword">DROP</span> <span class="comment">-- 允许使用DROP TABLE</span></span><br><span class="line"><span class="keyword">EXECUTE</span> <span class="comment">-- 允许用户运行已存储的子程序</span></span><br><span class="line"><span class="keyword">FILE</span> <span class="comment">-- 允许使用SELECT...INTO OUTFILE和LOAD DATA INFILE</span></span><br><span class="line"><span class="keyword">INDEX</span> <span class="comment">-- 允许使用CREATE INDEX和DROP INDEX</span></span><br><span class="line"><span class="keyword">INSERT</span> <span class="comment">-- 允许使用INSERT</span></span><br><span class="line"><span class="keyword">LOCK</span> <span class="keyword">TABLES</span> <span class="comment">-- 允许对您拥有SELECT权限的表使用LOCK TABLES</span></span><br><span class="line">PROCESS <span class="comment">-- 允许使用SHOW FULL PROCESSLIST</span></span><br><span class="line"><span class="keyword">REFERENCES</span> <span class="comment">-- 未被实施</span></span><br><span class="line">RELOAD <span class="comment">-- 允许使用FLUSH</span></span><br><span class="line"><span class="keyword">REPLICATION</span> <span class="keyword">CLIENT</span> <span class="comment">-- 允许用户询问从属服务器或主服务器的地址</span></span><br><span class="line"><span class="keyword">REPLICATION</span> <span class="keyword">SLAVE</span> <span class="comment">-- 用于复制型从属服务器(从主服务器中读取二进制日志事件)</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="comment">-- 允许使用SELECT</span></span><br><span class="line"><span class="keyword">SHOW</span> <span class="keyword">DATABASES</span> <span class="comment">-- 显示所有数据库</span></span><br><span class="line"><span class="keyword">SHOW</span> <span class="keyword">VIEW</span> <span class="comment">-- 允许使用SHOW CREATE VIEW</span></span><br><span class="line"><span class="keyword">SHUTDOWN</span> <span class="comment">-- 允许使用mysqladmin shutdown</span></span><br><span class="line">SUPER <span class="comment">-- 允许使用CHANGE MASTER, KILL, PURGE MASTER LOGS和SET GLOBAL语句,mysqladmin debug命令;允许您连接(一次),即使已达到max_connections。</span></span><br><span class="line"><span class="keyword">UPDATE</span> <span class="comment">-- 允许使用UPDATE</span></span><br><span class="line"><span class="keyword">USAGE</span> <span class="comment">-- “无权限”的同义词</span></span><br><span class="line"><span class="keyword">GRANT</span> <span class="keyword">OPTION</span> <span class="comment">-- 允许授予权限</span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<blockquote>
<p>SQL 是后端程序员很重要的一个技能。</p>
</blockquote>
</summary>
<category term="编码" scheme="https://github.com/zzycreate/categories/%E7%BC%96%E7%A0%81/"/>
<category term="Mysql" scheme="https://github.com/zzycreate/tags/Mysql/"/>
<category term="SQL" scheme="https://github.com/zzycreate/tags/SQL/"/>
</entry>
<entry>
<title>再来一杯(Bilibili)</title>
<link href="https://github.com/zzycreate/2019/01/08/%E5%86%8D%E6%9D%A5%E4%B8%80%E6%9D%AF-Bilibili/"/>
<id>https://github.com/zzycreate/2019/01/08/再来一杯-Bilibili/</id>
<published>2019-01-08T23:36:01.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>[music~]</p></blockquote><a id="more"></a><p>曾经我觉得我被世间遗忘<br>没有人可以诉说苦闷和悲伤<br>无法去理解人情世故炎凉<br>分不清成长和伪装有什么两样<br>无处不在的好奇和打量目光<br>命令一般的关怀该如何抵抗<br>突破重重的阻挡 撕破了所有的伪装<br>终于来到这个地方</p><p>那些误解的 那些冲动的<br>那些曾经年少情况<br>每一次宣泄在悔恨后让人成长<br>那些孤独的 那些迷茫的<br>那些曾经无助彷徨<br>每一次尝试在失败后更充满希望<br>所有的苦痛烦恼忧愁与悲伤<br>随着时间长河静静的流淌<br>不间断地奔向远方</p><p>现在我觉得自己有了方向<br>到处是令人兴奋和惊奇的景象<br>第一次带着笑容进入梦乡<br>每一天都是那么令人值得期望<br>终于明白成长和伪装不一样<br>已不必在意旁人不解的目光<br>不再一个人流浪 有了专属的避风港<br>漫长人生不再漫长</p><p>那些温暖的 那些热血的<br>那些不自量力抵抗<br>每一次在柔软后都更令人坚强<br>那些快乐的 那些欢笑的<br>那些无忧无虑时光<br>每一滴泪水在感动后更充满力量<br>所有美好的喜悦勇气和希望<br>已经融入血液在体内流淌<br>不断温暖我的胸膛</p><p>道路越是煎熬 就越坦然面对微笑<br>风浪刮得越高 就要越心高气傲<br>世界有太多美好等待寻找<br>不切实际的梦才值得我们<br>去燃烧~~</p><p>那些离去的 那些消逝的<br>并肩闯荡的过往<br>感谢你曾经付出陪伴在我身旁<br>那些关怀的 那些赞许的<br>不断鞭策与鼓掌<br>感谢你给我勇气黑暗中追逐光芒<br>所有感情历经岁月后更闪亮<br>让我们携手再次举杯歌唱<br>未来一定就在前方</p><p><strong>TIP</strong>: <a href="https://www.bilibili.com/video/av17784172/" target="_blank" rel="noopener">2018bilibili新年MV《再来一杯》</a></p>]]></content>
<summary type="html">
<blockquote>
<p>[music~]</p>
</blockquote>
</summary>
<category term="歌曲" scheme="https://github.com/zzycreate/categories/%E6%AD%8C%E6%9B%B2/"/>
<category term="歌曲" scheme="https://github.com/zzycreate/tags/%E6%AD%8C%E6%9B%B2/"/>
<category term="再来一杯" scheme="https://github.com/zzycreate/tags/%E5%86%8D%E6%9D%A5%E4%B8%80%E6%9D%AF/"/>
<category term="Bilibili" scheme="https://github.com/zzycreate/tags/Bilibili/"/>
</entry>
<entry>
<title>月色真美</title>
<link href="https://github.com/zzycreate/2018/12/02/%E6%9C%88%E8%89%B2%E7%9C%9F%E7%BE%8E/"/>
<id>https://github.com/zzycreate/2018/12/02/月色真美/</id>
<published>2018-12-02T23:47:31.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>As the moon, so beautiful</p></blockquote><blockquote><p>今夜の月は綺麗ですね</p></blockquote><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/N4cp8VbGXiKmsR1.jpg" alt="月色真美.jpg" title> </div> <div class="image-caption">月色真美.jpg</div> </figure>]]></content>
<summary type="html">
<blockquote>
<p>As the moon, so beautiful</p>
</blockquote>
<blockquote>
<p>今夜の月は綺麗ですね</p>
</blockquote>
<figure class="image-bubble">
</summary>
<category term="动画" scheme="https://github.com/zzycreate/categories/%E5%8A%A8%E7%94%BB/"/>
<category term="动画" scheme="https://github.com/zzycreate/tags/%E5%8A%A8%E7%94%BB/"/>
<category term="月色真美" scheme="https://github.com/zzycreate/tags/%E6%9C%88%E8%89%B2%E7%9C%9F%E7%BE%8E/"/>
</entry>
<entry>
<title>恶魔人 Crybaby</title>
<link href="https://github.com/zzycreate/2018/11/28/%E6%81%B6%E9%AD%94%E4%BA%BA-Crybaby/"/>
<id>https://github.com/zzycreate/2018/11/28/恶魔人-Crybaby/</id>
<published>2018-11-28T17:21:26.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>《恶魔人 Crybaby》这部动画其实已经看了有几个月了,看过之后心情很复杂,整部动画故事叙述完整,有足够的矛盾冲突甚至可以说是太多了,人物塑造充分。这部作品是Netflix出品,汤浅政明导演,大河内一楼编剧,牛尾宪辅作曲的网络播放动画,全部一共十集,与 39 集的原作《恶魔人》动画相比,集数大幅缩减,汤浅政民在这种条件下完整的表现了他的恶魔人版本。本文涉及剧透,清酌情阅读。</p></blockquote><a id="more"></a><h2 id="飞鸟了-amp-不动明"><a href="#飞鸟了-amp-不动明" class="headerlink" title="飞鸟了 & 不动明"></a>飞鸟了 & 不动明</h2><blockquote><p>没有爱,不存在什么爱,所以也没有什么悲伤,我曾经这样认为。那个时候…我没能理解你到底在说什么。 ——飞鸟了</p></blockquote><p>飞鸟了与不动明作为作品的两大主角,也是最终决战的双方;本来两人一直是好友的关系,但是因为双方理念的差异,最终导致了两者的对决。</p><p>不动明本来和恶魔没有任何关系,在听了飞鸟了讲述的恶魔的事情后,信任的选择帮助飞鸟了去揭露恶魔的存在,结果自身却被恶魔安蒙附身;由于不动明坚强的内心,仅凭自己的意志就压制了恶魔的意志,成为了一个拥有恶魔强大身体能力与人类善良纯真心灵的恶魔人。</p><p>而飞鸟了作为撒旦,喜欢的是简单直接的恶魔,讨厌着虚伪善变的人类,凭着几百万年来的印象,没有选择去理解人类这种生物,而是选择颠覆人类,让地球重回恶魔时代,再去与神明战斗。不动明是飞鸟了认可的人类,所以他安排了一开始的安息日活动,让明变成了恶魔人。</p><blockquote><p>人类有着克服恐惧挺身出战的勇气,也有智慧和强大的武力,绝对可以和恶魔一较高下。 ———— 不动明<br>为了杀掉那几百只恶魔,已经牺牲了数千万的人类,本来用来保护人类的武器,却也毁灭了不少人类。 ———— 飞鸟了</p></blockquote><p>飞鸟了和不动明的冲突体现了汤浅政明想要表现的爱,了因为没有爱,所以没有任何悲伤的情感;在明死后,了感受到了悲伤,察觉到了自己对于明的爱,留下了悔恨的眼泪。</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/b91aOJPyAYwqsc7.png" alt title> </div> <div class="image-caption"></div> </figure><p>飞鸟了总是冷静的分析着客观事实,以整体的大局观去看待事物,因为对他来说,只要能完成自己的目的,可以使用任何手段,无论是在长崎光司(摄影师)家电脑中安装炸弹还是在田径大会上让幸田暴露恶魔身都是按照计划,没有任何意思犹豫,因此也就认为不存在爱。而不动明则会以来自己的想法,代入别人的立场去思考,会为别人的感情产生共鸣,会为别人而哭泣,会去思考恶魔是否有心灵,会去想着别人是否会悲伤哭泣。两者在爱的理解上有着本质的区别。</p><h2 id="奔跑"><a href="#奔跑" class="headerlink" title="奔跑"></a>奔跑</h2><p>跑步是这次改编与原作差别比较大的点,作为田径部的美树、美子、明有着相互的羁绊,而作品中也提到了”人为什么要奔跑”这一问题。</p><blockquote><p>为什么要奔跑?人再怎么跑,都比不上猫、狗甚至小鸟的身体能力,使用武器和载具才是人类最强的能力。<br> ————— 飞鸟了</p></blockquote><blockquote><p>人为何要奔跑,我不懂那些大道理,只是因为我喜欢,只要一点点,只要能向前进,我觉得只要能前进,就会有所改变,就算是微不足道的,一点点的进步,就算是一点点,一点点也可以…<br> ————— 美树</p></blockquote><p>人类的身体素质确实比不上其他很多动物,但是人类回去追求自身的极限,通过各种方式增强自身,想着自己想要实现的方向去前进。能够让自身都认可的成功不是靠简单的祈求,或者参加安息日这种迷信活动能够获得的,真正的成功应该是依靠自身的努力,一点一点的向前迈进才能达成的。 </p><!-- <figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/lNK4A1ewqS5UbW2.png" alt="" title=""> </div> <div class="image-caption"></div> </figure> –><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/JdLxnevUr5KaVlN.gif" alt="接力棒.gif" title=""> </div> <div class="image-caption">接力棒.gif</div> </figure><h2 id="死丽濡-amp-槐梦"><a href="#死丽濡-amp-槐梦" class="headerlink" title="死丽濡 & 槐梦"></a>死丽濡 & 槐梦</h2><p>明从一个什么都不知道的傻白甜变成了恶魔人,一直以来都是接受了关于恶魔的知识,对此时的明来说,恶魔代表的邪恶,人类代表的善良,自己作为恶魔人应该站在人类这一边,恶魔都应该要铲除。 </p><p>但是死丽濡和槐梦的战死让他看到了恶魔之中也会存在着爱,槐梦为了死丽濡的愿望,宁可放弃自己的生命,死丽濡最后为了战胜安蒙,确性自己的胜利即可以满足的放弃生命。</p><p>人面龟事件让明明白了人类的意志可以战胜恶魔,而死丽濡和槐梦则让明对恶魔的看法产生了触动,并开始质疑起了自己对于恶魔的偏见。其实无论是人还是恶魔都有各自的处事逻辑,世间少有非黑即白,多数遇到的都是纠缠不清的灰色。</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/oKhl2dQ4xDLfv5q.png" alt="" title=""> </div> <div class="image-caption"></div> </figure><h2 id="幸田-amp-美子"><a href="#幸田-amp-美子" class="headerlink" title="幸田 & 美子"></a>幸田 & 美子</h2><p>幸田是本作前期着重塑造的一个人物,从第一集开始就有相关的新闻事件描述,恶魔与人类明面上的冲突开始也是借由田径会时的幸田事件触发,然而很可惜最终这个人物的塑造并没有很好利用起来,也许是由于篇幅原因,后期幸田直接就是被一个镜头秒杀。</p><p>幸田和美子两个人都是安息日被恶魔附身,两人都希望获得超越他人的身体素质,两人都在获取到恶魔能力时牺牲掉了重要的人,作为主要的恶魔人角色,在人与恶魔两方阵营中,分别选择不同的阵营,两者的经历及其类似但是结果却是有着很大的不同。</p><p>美子曾今因为自己最擅长的跑步与美树之间的差距而陷入了迷茫,在看到美树作为人的信念后,希望能够让美树免受人的迫害,选择了站在人类这一边,她向美树传达了自己的信念与希望。</p><p>而幸田则是希望自己能在人与恶魔之中生存下去,最后选择加入了恶魔阵营,并在明与恶魔大战的第一时间被秒杀,弱肉强食中选择依附强者其实也没什么问题,但是动画并没有表现太多其他内容,最后也只只是一笔带过,只能说有点可惜。</p><h2 id="牧村一家"><a href="#牧村一家" class="headerlink" title="牧村一家"></a>牧村一家</h2><p>牧村美树可以说寄托了明对人类所有美好事物的希望,牧村美树能够有这样完美的人性离不开牧村家庭的影响,牧村爸爸是一个虔诚的教徒,教导美树与太郎正确的价值观。</p><p>太郎作为小孩子虽然被恶魔附身,但是依靠家庭的教育,潜意识明白应该压抑恶魔的贪欲,直到实在忍受不了饥饿才显露出恶魔的特征。牧村妈妈在发现太郎已经是恶魔身之后,毅然决定独自带领太郎离开,避免给家庭带来更多的伤害,并悉心教导太郎正确的事情。牧村爸爸在发现太郎是恶魔时的内心纠葛通过动画完美的表现出来,当你在牧村爸爸的这一情况下,又会是怎样的抉择呢?</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/btYpHL2wDxaK539.png" alt="" title=""> </div> <div class="image-caption"></div> </figure><h2 id="rap-小队"><a href="#rap-小队" class="headerlink" title="rap 小队"></a>rap 小队</h2><p>最开始的时候我并不喜欢唱 RAP 的几位小哥,但是随着动画后期这几位的表现,有几位和美树一起可以称为人类最后的良心,当第九集结尾,这几位和美树一样的结局可以说震撼到了所有看了本动画的人。</p><p>几位小哥虽然平时表现不像是好人,但是片中几位都是富有正义感,面对不怀好意的人会行驶自己的力量去抗争(虽然有个叛变了)。连带着回头再看他们前面唱的 RAP 的时候,也觉得这些歌挺好听的。他们唱的歌都是抨击的社会上不正确的现象,描述了人们内心的空虚,理解了其中的含义这种说唱会觉得特别好听。</p><h2 id="牧村美树"><a href="#牧村美树" class="headerlink" title="牧村美树"></a>牧村美树</h2><p>牧村美树是不动明寄住的牧村家的长女,和不动明是青梅竹马,全局中人类最后的良善。美树在剧中对任何任何事物都保持着善良的心去对待,面对骚扰自己的记者,她关注的是记者工作的努力,认为不算是很坏的人;在看到警察与 Rap 小队之间的冲突,也是勇敢的挺身而出,化解了一场危机;在全世界都在诋毁和攻击明的时候,也是美树勇敢的站出来向大家讲述自己眼中的不动明,虽然大多数人还是无尽的谩骂,但是仍然让有部分善良的人愿意站出来接受恶魔人。</p><p>前面对美树描述的越是善良美好,在最后美树死去的时候就越是让人感到震撼,在人们互相的猜忌下,不同于主流观点的人就成为了异端,杀死美树的不是恶魔,但是却是人们内心的恶魔。</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/fzmFNGBpuVw8XrT.png" alt="" title=""> </div> <div class="image-caption"></div> </figure><h2 id="人类的末路"><a href="#人类的末路" class="headerlink" title="人类的末路"></a>人类的末路</h2><p>人类在飞鸟了的安排计划下,亲眼看到了藏在人群中的恶魔,并由此产生了相互之间的猜疑,最终慢慢的演化为内部的战争,每个人都以为自己是正义的,然而对于人类来说什么又是真正的正义。在群众中发生的无政府狂欢,让一些本来只想安稳度日的人也只能加入其中以自保,而不愿加入其中的人则受到排挤,甚至失去姓名,在这样的恶性循环下,人们内心的恶得到了无限放大,美树美子等人什么都没做也会被当成是异类而除掉,一旦不属于这个群体的人都没有了,大概群体内又会发生内部冲突,大部分消灭小部分。这样的事情在人类的历史上并不是没有发生过的,群体的道德绑架可以说是比比皆是,当你面对这样的情况会怎么选择,是选择像反叛的那位小哥一样,接过递过来的刀,还是像协助美树逃跑的小哥,勇敢的挥舞武器坚持自己的正义?</p>-->]]></content>
<summary type="html">
<blockquote>
<p>《恶魔人 Crybaby》这部动画其实已经看了有几个月了,看过之后心情很复杂,整部动画故事叙述完整,有足够的矛盾冲突甚至可以说是太多了,人物塑造充分。这部作品是Netflix出品,汤浅政明导演,大河内一楼编剧,牛尾宪辅作曲的网络播放动画,全部一共十集,与 39 集的原作《恶魔人》动画相比,集数大幅缩减,汤浅政民在这种条件下完整的表现了他的恶魔人版本。本文涉及剧透,清酌情阅读。</p>
</blockquote>
</summary>
<category term="动画" scheme="https://github.com/zzycreate/categories/%E5%8A%A8%E7%94%BB/"/>
<category term="动画" scheme="https://github.com/zzycreate/tags/%E5%8A%A8%E7%94%BB/"/>
<category term="恶魔人Crybaby" scheme="https://github.com/zzycreate/tags/%E6%81%B6%E9%AD%94%E4%BA%BACrybaby/"/>
<category term="netflix" scheme="https://github.com/zzycreate/tags/netflix/"/>
</entry>
<entry>
<title>使用WSL在Windows中体验Linux</title>
<link href="https://github.com/zzycreate/2018/11/18/%E4%BD%BF%E7%94%A8WSL%E5%9C%A8Windows%E4%B8%AD%E4%BD%93%E9%AA%8CLinux/"/>
<id>https://github.com/zzycreate/2018/11/18/使用WSL在Windows中体验Linux/</id>
<published>2018-11-18T23:25:43.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<p>微软在 Windows 10 中增加了 WSL 这个新功能,可以跑完整的 linux 镜像,而且不像虚拟机是应用层的实现需要消耗大量资源。现在 Windows 10 的商店里面提供了 Ubuntu、Debian、Kali Linux、OpenSUSE 等 linux 发行版。</p><a id="more"></a><h2 id="WSL"><a href="#WSL" class="headerlink" title="WSL"></a>WSL</h2><p>Windows Subsystem for Linux (简称 WSL) 是为了能在 Windows10 上原生运行 Linux 二进制可执行文件 (ELF 可执行文件) 而制作的兼容层。这意味着在一些情况,不再需要使用 Linux 虚拟机、双系统、Cygwin/MSYS2 了,这样占用的资源会比虚拟机等方式要更省也更方便。</p><p>虽然WSL不是完整的Linux系统,但你依然可以做到绝大多数在完整Linux系统能做的事(比如vim, apt-get等)。</p><h2 id="安装-WSL"><a href="#安装-WSL" class="headerlink" title="安装 WSL"></a>安装 WSL</h2><p>打开 Microsoft Store ,搜索 linux 可以看见已经有很多 linux 发行版支持可以使用 WSL。我选择了安装熟悉一些的 Ubuntu。</p><p>要使用 WSL 首选需要打开系统对 Linux 子系统的支持。</p><p>在开始菜单中或者小娜那里搜索“启用或关闭 Windows 功能”,打开对应的控制面板,勾选 “适用于 Linux 的 Windows 子系统”。</p><p>在 Microsoft Store 商店中下载安装 Ubuntu。</p><p>安装完毕之后,在开始菜单中会有 Ubuntu 的磁贴,点开磁铁,会出现命令行进行安装。</p><p>等待几分钟让系统自动安装 Ubuntu。</p><p>如果安装出现了错误,可以自行搜索一下错误码,我碰到过一次是因为网络问题,一次是系统更新,需要重启。</p><p>安装完成之后,输入 WSL 的用户名和密码,再打开 Ubuntu ,你会发现命令行已经是 bash 环境,可以直接使用 bash 的命令,使用方式就跟正常的 linux 一模一样。Ubuntu 可以使用 apt 包管理软件进行各种软件安装。</p><h2 id="WSL-的文件系统"><a href="#WSL-的文件系统" class="headerlink" title="WSL 的文件系统"></a>WSL 的文件系统</h2><p>在 WSL 中,你可以看到 Windows 的所有磁盘都挂载在 /mnt/ 下面,你在 Linux 下可以正常访问所有不需要系统权限的文件和文件夹。当然,需要注意的是,如果不是用的管理员账户,在 Linux 下使用 sudo 也无法访问需要 Windows 提升权限才能访问的文件。</p><p>同样,你在Windows下也可以看到WSL里的文件,但因为其使用了NTFS的软链接机制,如果你想让一个文件出现在你的Linux目录下,那你就必须在Linux下进行操作,在Win下操作之后,在Linux下仍然是看不到的。</p><p>在 C 盘创建一个 public 的文件夹,到 bash 中执行命令 <code>ln -s /mnt/c/public ~/public</code> 创建软链接,将 windows 和 WSL 中共享的文件都放在这个目录下,方便直接访问这个目录。</p><p>更新系统和软件可以直接使用 Ubuntu 的命令:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get upgrade</span><br><span class="line"># 升级系统到最新的 Ubuntu,注意:非常耗时,WSL 的磁盘 IO 效率很低</span><br><span class="line">sudo -S apt-mark hold procps strace sudo</span><br><span class="line">sudo -S env RELEASE_UPGRADER_NO_SCREEN=1 do-release-upgrade</span><br></pre></td></tr></table></figure><h2 id="使用-ConEmu-替代-Windows-命令行"><a href="#使用-ConEmu-替代-Windows-命令行" class="headerlink" title="使用 ConEmu 替代 Windows 命令行"></a>使用 ConEmu 替代 Windows 命令行</h2><p>Windows 的命令行,尤其是 CMD 显示效果和使用体验都非常差,PowerShell 相对来说还行,但是还是没有 Linux 下的终端那种爽快感。可以选择使用 ConEmu 或者 Cmder 进行替换,提升命令行使用体验。</p><p>我选择使用 ConEmu,安装完 ConEmu 之后,进入 Setting 设置中,点开左侧导航栏的 <code>Startup > Tasks</code>。</p><p>新增一个 Task ,名称设置成 <code>{Bash::Ubuntu}</code>。</p><p>Command 命令框中输入: <code>%windir%\system32\bash.exe ~ -cur_console:p</code>,这样就可以使用 bash 直接进入用户的 home 目录。</p><p>在 ConEmu 的默认设置中选则 <code>{Bash::Ubuntu}</code> 作为启动的终端,可以在打开 ConEmu 时就能进入 bash 环境的使用。</p><h2 id="使用-zsh-替换-bash"><a href="#使用-zsh-替换-bash" class="headerlink" title="使用 zsh 替换 bash"></a>使用 zsh 替换 bash</h2><p>WSL 不能直接将 bash 替换成 zsh,可以选择在打开 bash 的时候就直接跳转到 zsh 的环境。</p><ol><li>首先安装 zsh</li></ol><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo apt-get install zsh</span><br></pre></td></tr></table></figure><ol start="2"><li>安装 oh-my-zsh 提升 zsh 的体验,使用 oh-my-zsh 官网的推荐方式进行安装</li></ol><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"># via curl</span><br><span class="line">sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"</span><br><span class="line"># 或者</span><br><span class="line"># via wget</span><br><span class="line">sh -c "$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)"</span><br></pre></td></tr></table></figure><p>如果没有自动进入 zsh 的环境,可以执行 <code>chsh -s zsh</code></p><ol start="3"><li>bash 执行即调用 zsh,修改 <code>~/.bashrc</code> 在最后面加入一下内容:</li></ol><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">if test -t 1; then</span><br><span class="line">exec zsh</span><br><span class="line">fi</span><br></pre></td></tr></table></figure><ol start="4"><li>按个人配置 zsh,我习惯使用 ys 主题,直接修改 <code>~/.zshrc</code> 进行主题插件的配置。</li></ol><h2 id="WSL-管理配置"><a href="#WSL-管理配置" class="headerlink" title="WSL 管理配置"></a>WSL 管理配置</h2><p>Windows10 自带了 wslconfig,去管理多个安装的发行版,比如卸载某个发行版,设置默认启动的发型版。</p><p>在PowerShell中输入 <code>wslconfig /?</code>, 可以看到:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">PS D:\> wslconfig /?</span><br><span class="line">在 Linux Windows 子系统上执行管理操作</span><br><span class="line"></span><br><span class="line">用法:</span><br><span class="line"> /l, /list [/all] - 列出已注册的分发内容。</span><br><span class="line"> /all - 有选择地列出所有分发内容,包括目前</span><br><span class="line"> 正安装或未安装的分发内容。</span><br><span class="line"> /s, /setdefault <DistributionName> - 将指定的分发内容设置为默认值。</span><br><span class="line"> /u, /unregister <DistributionName> - 注销分发内容。</span><br></pre></td></tr></table></figure><p>切换默认发行版:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">PS D:\> wslconfig /l</span><br><span class="line"># 适用于 Linux 的 Windows 子系统:</span><br><span class="line">Legacy (默认)</span><br><span class="line">Ubuntu</span><br><span class="line">PS D:\> wslconfig /s Ubuntu</span><br><span class="line">PS D:\> wslconfig /l</span><br><span class="line"># 适用于 Linux 的 Windows 子系统:</span><br><span class="line">Ubuntu (默认)</span><br><span class="line">Legacy</span><br></pre></td></tr></table></figure><p>在Windows 1803 后,还支持更多配置。比如网络,root 目录等。进入发行版后, 可以在 /etc/wsl.conf 中配置。 如果没有该文件,可以手动创建一个配置:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">[automount]</span><br><span class="line">enabled = true # 自动挂载 c:/ 等到 /mnt</span><br><span class="line">root = /windir/</span><br><span class="line">options = "metadata,umask=22,fmask=11"</span><br><span class="line">mountFsTab = false</span><br><span class="line"></span><br><span class="line">[network]</span><br><span class="line">generateHosts = true</span><br><span class="line">generateResolvConf = true</span><br></pre></td></tr></table></figure><h2 id="WSL-交互"><a href="#WSL-交互" class="headerlink" title="WSL 交互"></a>WSL 交互</h2><p>也是从1709开始,WSL支持在Windows 10上直接使用 Linux命令:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">PS D:\test> wsl ls -la</span><br><span class="line">total 5836</span><br><span class="line">drwxrwxrwx 1 root root 4096 Jan 25 13:20 .</span><br><span class="line">drwxrwxrwx 1 root root 4096 Apr 20 16:25 ..</span><br><span class="line">-rwxrwxrwx 1 root root 105 Oct 14 2017 03-build.ps1</span><br></pre></td></tr></table></figure><p>同样在 WSL 内也可以使用Windows应用程序,比如notepad,docker:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">root@mushroom:/mnt/d/go/src/code.teambition.com/soa/webhooks# docker.exe ps</span><br><span class="line">CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span><br><span class="line">63698edb01a8 quay.io/coreos/etcd:latest "/usr/local/bin/etcd" 2 days ago Up 27 hours 0.0.0.0:2379->2379/tcp, 2380/tcp etcd</span><br></pre></td></tr></table></figure><p>这是个非常赞的特性,极大方便了开发者。但在使用过程中发现,有个体验非常不好的地方,必须带.exe后缀才行,不然会提示找不到命令 :</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">root@mushroom:/mnt/d/go/src/code.teambition.com/soa/webhooks# docker</span><br><span class="line">The program 'docker' is currently not installed. You can install it by typing:</span><br><span class="line">apt-get install docker</span><br></pre></td></tr></table></figure><p>比如在别的 linux 系统上写了个 docker build 的脚本,放到 Windows 上后 想使用 WSL 去执行,发现必须加后缀才行,这样脚本就没办法统一了。</p><p>参考文章:</p><ol><li><a href="https://www.cnblogs.com/mushroom/p/8969338.html" target="_blank" rel="noopener">WSL与Windows交互实践</a></li><li><a href="https://wsl-guide-cn.readthedocs.io/zh_CN/latest/" target="_blank" rel="noopener">Windows Subsystem for Linux (WSL) 最佳实践指南!</a></li><li><a href="https://zhuanlan.zhihu.com/p/24537874" target="_blank" rel="noopener">简明的WSL教程</a></li></ol>]]></content>
<summary type="html">
<p>微软在 Windows 10 中增加了 WSL 这个新功能,可以跑完整的 linux 镜像,而且不像虚拟机是应用层的实现需要消耗大量资源。现在 Windows 10 的商店里面提供了 Ubuntu、Debian、Kali Linux、OpenSUSE 等 linux 发行版。</p>
</summary>
<category term="系统" scheme="https://github.com/zzycreate/categories/%E7%B3%BB%E7%BB%9F/"/>
<category term="Linux" scheme="https://github.com/zzycreate/tags/Linux/"/>
<category term="Ubuntu" scheme="https://github.com/zzycreate/tags/Ubuntu/"/>
<category term="WSL" scheme="https://github.com/zzycreate/tags/WSL/"/>
<category term="Windows" scheme="https://github.com/zzycreate/tags/Windows/"/>
</entry>
<entry>
<title>使用nvm安装nodejs</title>
<link href="https://github.com/zzycreate/2018/11/07/%E4%BD%BF%E7%94%A8nvm%E5%AE%89%E8%A3%85nodejs/"/>
<id>https://github.com/zzycreate/2018/11/07/使用nvm安装nodejs/</id>
<published>2018-11-07T00:06:25.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>nodejs 的安装通常的做法是到官网上直接下载最新版本的程序,然后进行安装,这样的安装方式可以说是很正确;<br>但是 nodejs 是一个快速更新的语言,版本更新非常快,很可能有会出现版本问题导致某些包使用时发生异常,这时候要卸载安装或者覆盖更新都是很蛋疼的一件事。<br>为了快速切换 node 版本,Node Version Manager 应运而生。</p></blockquote><h2 id="NVM"><a href="#NVM" class="headerlink" title="NVM"></a>NVM</h2><p><code>nvm</code> 的是 <code>github</code> 上的一个项目,项目地址: <a href="https://github.com/creationix/nvm">creationix/nvm</a></p><p><code>nvm</code> 项目不支持 Windows (<a href="https://github.com/creationix/nvm/issues/284">#284</a>),如果是在 Windows 环境下使用,官方推荐的项目:<a href="https://github.com/coreybutler/nvm-windows">coreybutler/nvm-windows</a> 或者 <a href="https://github.com/nullivex/nodist">nullivex/nodist</a>.</p><h3 id="nvm-的安装"><a href="#nvm-的安装" class="headerlink" title="nvm 的安装"></a>nvm 的安装</h3><p>nvm 官方提供了执行脚本。</p><p>cURL:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash</span><br></pre></td></tr></table></figure><p>Wget:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash</span><br></pre></td></tr></table></figure><p>The script clones the nvm repository to ~/.nvm and adds the source line to your profile (~/.bash_profile, ~/.zshrc, ~/.profile, or ~/.bashrc).<br>这个脚本会把 nvm 的资源加载到 <code>~/.nvm</code> 并向环境变量 (<code>~/.bash_profile</code>, <code>~/.zshrc</code>, <code>~/.profile</code>, or <code>~/.bashrc</code>) 中写入一下内容:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">export NVM_DIR="${XDG_CONFIG_HOME/:-$HOME/.}nvm"</span><br><span class="line">[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm</span><br></pre></td></tr></table></figure><p>如果要自定义 source, directory, profile 和 version 的值,需要使用对应的参数: <code>NVM_SOURCE</code>, <code>NVM_DIR</code>, <code>PROFILE</code>, and <code>NODE_VERSION</code> 。</p><p>如果安装后提示找不到指令,尝试重启终端,source 环境变量等方法。</p><h3 id="nvm-的使用"><a href="#nvm-的使用" class="headerlink" title="nvm 的使用"></a>nvm 的使用</h3><p>下载、编译、安装最新版本的 nodejs: <code>nvm install node</code><br>安装制定版本的 nodejs: <code>nvm install 6.14.4</code><br>列举可用版本: <code>nvm ls-remote</code><br>使用 nodejs: <code>nvm use node</code></p><p>这些命令中,<code>node</code> 指代最新版本的 nodejs, 也可以替换成 <code>iojs</code>、 <code>stable</code>(稳定版)、<code>unstable</code>(开发版) 或者指定的版本号。</p><p>官方文档中对各种命令进行了列举,文档说明比较清晰,而且功能也比较简单,各位可以自行尝试。</p><h2 id="nvm-windows"><a href="#nvm-windows" class="headerlink" title="nvm-windows"></a>nvm-windows</h2><p><code>nvm-windows</code> 和 <code>nvm</code> 的命令有一些区别,不过大体上是一致的。</p><h3 id="nvm-windows-的安装"><a href="#nvm-windows-的安装" class="headerlink" title="nvm-windows 的安装"></a>nvm-windows 的安装</h3><p>在项目 <a href="https://github.com/coreybutler/nvm-windows/releases">release页面</a> 可以直接下载已经发布的版本。</p><p>安装过程中会提示选择两个地址,一个是 <code>nvm</code> 程序的安装地址,一个是 <code>nodejs</code> 的安装地址。安装路径中不要含有中文,避免中文路径导致的错误。</p><p>安装完成后,使用 <code>nvm v</code> 查看 nvm 版本号,可以检查是否安装成功。</p><p>如果没有安装成功,可能需要在系统环境变量中配置 <code>%NVM_HOME%</code> 和 <code>%NVM_SYMLINK%</code> 这两个环境变量</p><h3 id="安装-npm"><a href="#安装-npm" class="headerlink" title="安装 npm"></a>安装 npm</h3><p>有时候 <code>npm</code> 的官方地址无法访问,这时候就需要设置国内的镜像源。</p><p><code>nvm</code> 路径下有个 <code>setting.txt</code> 文件,文件后面添加下面的内容进行 <code>nodejs</code> 和 <code>npm</code> 的镜像地址配置。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">node_mirror: https://npm.taobao.org/mirrors/node/</span><br><span class="line">npm_mirror: https://npm.taobao.org/mirrors/npm/</span><br></pre></td></tr></table></figure><h3 id="安装-node"><a href="#安装-node" class="headerlink" title="安装 node"></a>安装 node</h3><p>使用 <code>nvm</code> 安装 <code>nodejs</code>:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">nvm install latest # 安装最新</span><br><span class="line">nvm install 11.1.0 # 安装指定版本</span><br><span class="line">nvm install 10.0.0 32 # 安装 32 位的系统的版本</span><br></pre></td></tr></table></figure><p>对应的卸载命令就是 <code>nvm uninstall 11.1.0</code></p><p>安装完了之后还无法使用 <code>node</code> 和 <code>npm</code> 命令,因为还没有制定使用哪个 <code>nodejs</code>:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">nvm use 8.0.0</span><br></pre></td></tr></table></figure><p>其实 <code>use</code> 只是将 <code>nvm</code> 安装路径下下载的对应版本 <code>nodejs</code> 的目录超链接到上文安装 <code>nvm-windows</code> 时选择的 <code>node</code> 路径处。</p><p>这样环境变量 <code>%NVM_SYMLINK%</code> 指向的最终路径就会是 nvm use 的 nodejs 版本路径。</p><p>使用 nvm use 就可以快速切换 nodejs 版本。</p><h2 id="npm"><a href="#npm" class="headerlink" title="npm"></a>npm</h2><p>npm 的一些使用方法。</p><h3 id="设置-npm-的全局安装路径"><a href="#设置-npm-的全局安装路径" class="headerlink" title="设置 npm 的全局安装路径"></a>设置 npm 的全局安装路径</h3><p>使用 npm config 进行设置的配置:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">npm config set prefix "E:\nodejs\npm-global"</span><br></pre></td></tr></table></figure><p>这样配置之后,使用 <code>npm install -g</code> 安装的全局包就都会下载到制定的仓库目录下。这个命令会在用户文件夹的 <code>~/.npmrc</code> 文件中写入 <code>prefix=E:\nodejs\npm-global</code> 的数据。</p><p>但是下载的这些全局包可能不能直接使用对应的命令,这是因为系统环境变量的问题。</p><p>我选择在环境变量里面新定义一个变量 <code>NPM_MODULES</code>, 然后在 Path 中添加 <code>%NPM_MODULES%;</code> 变量,这样全局安装的 npm 包,就会加入到环境变量中,可以直接使用对应的命令。</p><p>使用 nvm 安装的 nodejs 都会有各自的 npm 包管理程序,所以如果你使用了 <code>nvm use</code> 进行 nodejs 的切换,上面 npm config 的配置就会变更,全局仓库就会失效了,所以一定记得在 nvm use 之后要重新设置 npm config 配置全局仓库地址。</p><h3 id="npm-下载慢的解决方法"><a href="#npm-下载慢的解决方法" class="headerlink" title="npm 下载慢的解决方法"></a>npm 下载慢的解决方法</h3><p>npm 直接连官方源是比较慢的,甚至有可能被墙,所以需要更换 npm 源。</p><p>一种方式是 <code>npm config set registry url</code> 进行注册地址的变更。</p><p>还有一种是安装 <code>cnpm</code>, 其实不太推荐这种,cnpm 可能会导致一些奇怪的问题。</p><p>另外还推荐使用 <code>nrm</code> 这个包进行源的切换,这个包可以对多个注册源进行测试,方便你选择最合适的注册源。</p><p>我另外一片文章中记录了这个内容,文章地址:<a href="https://zzycreate.github.io/2017/01/19/npm%E4%B8%8B%E8%BD%BD%E6%85%A2%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95/" target="_blank" rel="noopener">npm下载慢的解决方法</a></p><p>参考文章:</p><ol><li><a href="https://github.com/creationix/nvm/blob/master/README.md">nvm README</a></li><li><a href="https://segmentfault.com/a/1190000010596717" target="_blank" rel="noopener">Windows下安装nvm、npm及node.js</a></li><li><a href="https://segmentfault.com/a/1190000007612011" target="_blank" rel="noopener">Windows 下安装 nvm 管理 nodejs 版本</a></li></ol>]]></content>
<summary type="html">
<blockquote>
<p>nodejs 的安装通常的做法是到官网上直接下载最新版本的程序,然后进行安装,这样的安装方式可以说是很正确;<br>但是 nodejs 是一个快速更新的语言,版本更新非常快,很可能有会出现版本问题导致某些包使用时发生异常,这时候要卸载安装或者覆盖更
</summary>
<category term="编码" scheme="https://github.com/zzycreate/categories/%E7%BC%96%E7%A0%81/"/>
<category term="node" scheme="https://github.com/zzycreate/tags/node/"/>
<category term="npm" scheme="https://github.com/zzycreate/tags/npm/"/>
<category term="nvm" scheme="https://github.com/zzycreate/tags/nvm/"/>
</entry>
<entry>
<title>Manjaro的尝试</title>
<link href="https://github.com/zzycreate/2018/11/03/Manjaro%E7%9A%84%E5%B0%9D%E8%AF%95/"/>
<id>https://github.com/zzycreate/2018/11/03/Manjaro的尝试/</id>
<published>2018-11-03T14:14:12.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>linux 拥有大量的发行版,虽然都是使用的相同的 linux kernel,但是由于 linux 下软件的繁多,各种不同的发行版有着不同的软件组合和生态。大众常用的几个发行版主要有 RedHat、Fedora、CentOS、Ubuntu 等。最近发现了 ArchLinux 分支下据说最好的版本 ———— Manjaro,对其进行一番尝试。</p></blockquote><a id="more"></a><h2 id="Manjaro-的安装"><a href="#Manjaro-的安装" class="headerlink" title="Manjaro 的安装"></a>Manjaro 的安装</h2><h3 id="Manjaro-介绍"><a href="#Manjaro-介绍" class="headerlink" title="Manjaro 介绍"></a>Manjaro 介绍</h3><blockquote><p>Manjaro是一款基于Arch Linux、对用户友好、全球排名第1的Linux发行版。(排名数据源于 <a href="http://distrowatch.com/" target="_blank" rel="noopener">DistroWatch</a>,统计日期2018.03.02,时间段3个月。)<br>Manjaro 的官网是 <a href="https://manjaro.org/" target="_blank" rel="noopener">https://manjaro.org/</a>.</p></blockquote><p>在 Linux 圈,Arch 的确是一个异常强大的发行版。它有3个无与伦比的优势:</p><ul><li>滚动更新可以使软件保持最新;</li><li>AUR 软件仓库有着世界上最齐全的 Linux 软件;</li><li>丰富的 wiki 和活跃的社区让所有问题都可以快速得到满意的答案。</li></ul><p>作为准备折腾的玩物,Arch Linux 这些特性很吸引我。Arch Linux 被人诟病的最多的就是对新手不友好,安装复杂。Manjaro 的出现就是为了解决 Arch Linux 的一些操作上的不舒适。</p><h3 id="Manjaro-下载"><a href="#Manjaro-下载" class="headerlink" title="Manjaro 下载"></a>Manjaro 下载</h3><p>Manjaro 官方下载地址 <a href="https://manjaro.org/get-manjaro/" target="_blank" rel="noopener">https://manjaro.org/get-manjaro/</a>.<br>另外国内的一些下载站点也提供下载:<a href="https://mirrors.ustc.edu.cn/manjaro-cd/" target="_blank" rel="noopener">中科大镜像站</a>、<a href="https://mirrors.tuna.tsinghua.edu.cn/manjaro-cd/" target="_blank" rel="noopener">清华大学镜像站</a></p><p>Manjaro 官网提供了三种版本,分别对应了三种 linux 桌面集成版本。</p><ol><li>Manjaro XFCE版: Xfce是一个用于类UNIX操作系统的轻量级桌面环境。 它的目标是快速和系统资源低耗,同时仍然保持视觉上的吸引力和对用户友好的特性。</li><li>Manjaro KDE版: KDE是一个功能丰富多样的桌面环境,提供几种不同风格的菜单来访问应用程序。还有一个优秀的内置界面,可以方便地访问、下载、安装新的主题、小部件等。 虽然在用户友好度上做的非常好,但KDE也是相当消耗系统资源的,跟XFCE比较起来,启动程序、使用桌面环境都明显偏慢。运行Manjaro的64位KDE桌面使用大约需要550MB的内存。</li><li>Manjaro GNOME版: GNOME 桌面环境是作为 GNU 项目的一部分来开发的,它旨在简单易用,并且完全可用。 它的默认显示服务器是 Wayland。 虽然外观是独特的,它的可定制性仍然非常高。各种扩展可以从<a href="https://extensions.gnome.org/" target="_blank" rel="noopener">https://extensions.gnome.org/</a>获取。像KDE一样,它比Xfce使用更多的资源。</li></ol><p>就界面的操作逻辑来说,XFCE 类似于 Win7,KDE 类似于 Win10,Gnome 类似于 Ubuntu。</p><p><del>我选择先使用 KDE 版本尝试一番。</del> 已经更换为 gnome 主题,后文所有的内容都适用于 gnome,安装的图片还是 kde 的图片,我就不换了,注意桌面系统的区别。</p><h3 id="Manjaro-安装"><a href="#Manjaro-安装" class="headerlink" title="Manjaro 安装"></a>Manjaro 安装</h3><p>使用 VirtualBox 进行安装。</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/KPZLNraM7h3wjtn.png" alt="manjaro-install1.png" title> </div> <div class="image-caption">manjaro-install1.png</div> </figure><p>专家模式,类型 Linux,版本 Arch Linux(64-bit),内存 2048 MB。</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/4nji5I2KCDmMhSL.png" alt="manjaro-install2.png" title> </div> <div class="image-caption">manjaro-install2.png</div> </figure><p>文件大小 50 GB,虚拟硬盘文件类型 VDI,文件位置 自选。</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/EGAlQgCsXLnORJ2.png" alt="manjaro-install3.png" title> </div> <div class="image-caption">manjaro-install3.png</div> </figure><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/jtncJBSyvFPgdAs.png" alt="manjaro-install4.png" title> </div> <div class="image-caption">manjaro-install4.png</div> </figure><p>选择语言,按 <code>方向→</code> ,选择<code>中文</code>、<code>zh_CN</code>;</p><p><code>Boot: Manjaro.x86_64 kde</code> ,按<code>方向→</code> 进入安装程序。</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/mR2cnb1PkqUf4wS.png" alt="manjaro-install5.png" title> </div> <div class="image-caption">manjaro-install5.png</div> </figure><p><code>Launch at start</code> 可以选择关闭,按 <code>Launch installer</code> 或者双击桌面的 <code>Install Manjaro</code> 进入安装步骤。</p><p>选择语言键盘,图略。选择 <code>简体中文(中国)</code> ,时区选择 <code>Asia - Shanghai</code> ,键盘 <code>Chinese</code>。</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/gkrN2swcULDzWxu.png" alt="manjaro-install6.png" title> </div> <div class="image-caption">manjaro-install6.png</div> </figure><p>手动分区,注意此处左上角的 <code>BIOS</code> ,一些同学可能是<code>EFI</code>方式安装的。</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/iYEqeBso1WUvaOu.png" alt="manjaro-install7.png" title> </div> <div class="image-caption">manjaro-install7.png</div> </figure><p>新建分区表,<code>BIOS</code> 引导方式选择 <code>MBR</code> 分区表,<code>EFI</code> 引导方式选择 <code>FPT</code> 分区表。</p><p>然后对空闲空间进行分区。</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/wF2CmzjspaTht85.png" alt="manjaro-install8.png" title> </div> <div class="image-caption">manjaro-install8.png</div> </figure><p>我制作的分区最终为:</p><ol><li>挂载点:<code>/</code> ,大小:<code>36362 MiB</code>,分区类型:<code>主分区</code> ,文件类型:<code>ext4</code> , 标记:无所谓 选 <code>root</code>;用于根节点挂载</li><li>挂载点:<code>/boot</code> ,大小:<code>500 MiB</code>,分区类型:<code>主分区</code> ,文件类型:<code>ext4</code> , 标记:无所谓 选 <code>boot</code> ;用于系统引导挂载</li><li>挂载点:<code>/home</code> ,大小:<code>10240 MiB</code>,分区类型:<code>主分区</code> ,文件类型:<code>ext4</code> , 标记:无所谓 选 <code>root</code> ,用于用户目录挂载</li><li>分区类型:<code>拓展分区</code> ,文件类型:<code>ext4</code> , 标记:无所谓 选 <code>swap</code> ;在这个拓展分区下新建分区:挂载点:<code>/swap</code>,大小:<code>4096 MiB</code>,分区类型:<code>逻辑分区</code> ,文件类型:<code>linuxswap</code> , 标记:无所谓 选 <code>swap</code> ,用于内存缓存恢复,一般为内存的两倍大小</li></ol><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/VJexMlkCDjSniY6.png" alt="manjaro-install9.png" title> </div> <div class="image-caption">manjaro-install9.png</div> </figure><p>下一步选择创建用户,最后一行是创建 <code>root</code> 用户的密码,一定要记住。继续后面的步骤完成安装。</p><h2 id="Manjaro-软件折腾"><a href="#Manjaro-软件折腾" class="headerlink" title="Manjaro 软件折腾"></a>Manjaro 软件折腾</h2><h3 id="软件源"><a href="#软件源" class="headerlink" title="软件源"></a>软件源</h3><h4 id="自动方式"><a href="#自动方式" class="headerlink" title="自动方式"></a>自动方式</h4><p>Manjaro 的默认软件源在国外,速度一般不理想,需要更换国内更快的源。</p><p>使用 <code>F12</code> 可以使用下拉的 <code>Terminal</code> ,快速开启 <code>bash</code> 的命令行环境。</p><p>使用以下命令进行软件源的排列:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo pacman-mirrors -g</span><br></pre></td></tr></table></figure><p>或者使用以下命令直接测试中文源的速度,会弹出弹窗,可以进行勾选。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo pacman-mirrors -i -c China -m rank</span><br></pre></td></tr></table></figure><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/5QPnbNw1Isud6mg.png" alt="manjaro-install10.png" title> </div> <div class="image-caption">manjaro-install10.png</div> </figure><p>直接选择速度同步时间段,速度快的源。</p><h4 id="手动方式换源"><a href="#手动方式换源" class="headerlink" title="手动方式换源"></a>手动方式换源</h4><p>选择手动修改软件源。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo vi /etc/pacman.conf</span><br></pre></td></tr></table></figure><p>编辑 <code>/etc/pacman.config</code> ,在最底部添加以下描述(中科大源):</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">[archlinuxcn]</span><br><span class="line">SigLevel = Optional TrustedOnly</span><br><span class="line">Server = https://mirrors.ustc.edu.cn/archlinuxcn/<span class="variable">$arch</span></span><br><span class="line">Server = http://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/<span class="variable">$arch</span></span><br></pre></td></tr></table></figure><p>然后更新源:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo pacman -Syy && sudo pacman -S archlinuxcn-keyring</span><br></pre></td></tr></table></figure><h3 id="软件安装的方式"><a href="#软件安装的方式" class="headerlink" title="软件安装的方式"></a>软件安装的方式</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">pacman -S package_name1 package_name2 ... <span class="comment"># 安装软件</span></span><br><span class="line">pacman -R package_name <span class="comment"># 删除软件</span></span><br><span class="line">pacman -Syu <span class="comment"># 更新软件和系统</span></span><br><span class="line">pacman -Ss string1 string2 ... <span class="comment"># 搜索</span></span><br></pre></td></tr></table></figure><p><del>其他也可以添加 <code>yaourt</code> ,这个也是一个 Manjaro 上常用的包管理命令,使用上差不多。安装:</del></p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">pacman -S base-devel yaourt</span><br></pre></td></tr></table></figure><p>yaourt 已经被官方标记为 inactive,可以尝试使用 <code>yay</code> 或者 <code>aurman</code> 作为 AUR 包管理,</p><p>看了一下 github ,yay 的更新会更新一些,所以我选择装一个 <code>yay</code> 作为 AUR 的包管理,这样可以使用 AUR 源里的软件。<br><code>yay</code> 的 github 仓库地址: <a href="https://github.com/Jguer/yay">https://github.com/Jguer/yay</a></p><p>安装方式:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git clone https://aur.archlinux.org/yay.git</span><br><span class="line">cd yay</span><br><span class="line">makepkg -si</span><br></pre></td></tr></table></figure><p>yay 使用方法基本和 pacman 一致,一些定制用法:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yay <Search Term></span><br><span class="line"> Present package-installation selection menu.</span><br><span class="line"></span><br><span class="line">yay -Ps</span><br><span class="line"> Print system statistics.</span><br><span class="line"></span><br><span class="line">yay -Yc</span><br><span class="line"> Clean unneeded dependencies.</span><br><span class="line"></span><br><span class="line">yay -G <AUR Package></span><br><span class="line"> Download PKGBUILD from ABS or AUR.</span><br><span class="line"></span><br><span class="line">yay -Y --gendb</span><br><span class="line"> Generate development package database used for devel update.</span><br><span class="line"></span><br><span class="line">yay -Syu --devel --timeupdate</span><br><span class="line"> Perform system upgrade, but also check for development package updates and use</span><br><span class="line"> PKGBUILD modification time (not version number) to determine update.</span><br></pre></td></tr></table></figure><h3 id="输入法"><a href="#输入法" class="headerlink" title="输入法"></a>输入法</h3><p>Manjaro 默认有中文输入,但是使用和管理不方便,需要进行一些配置,常用的是使用 <code>fcitx</code> 或者 <code>iBus</code> 进行输入法的管理。Linux 上输入法是各大坑,需要一些尝试,我选择使用 <code>fcitx</code> 进行尝试。</p><p>安装 <code>fcitx</code> 主程序,并安装 <code>fcitx-toolconfig</code> 的配置管理程序:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo pacman -S fcitx-im</span><br><span class="line">sudo pacman -S fcitx-configtool</span><br></pre></td></tr></table></figure><p>安装完 <code>fcitx</code> 的程序,需要进行配置,使用 <code>sudo vi ~/.xprofile</code> 进行配置修改,添加以下内容。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">export</span> GTK_IM_MODULE=fcitx</span><br><span class="line"><span class="built_in">export</span> QT_IM_MODULE=fcitx</span><br><span class="line"><span class="built_in">export</span> XMODIFIERS=<span class="string">"@im=fcitx"</span></span><br></pre></td></tr></table></figure><p>中文输入法其实有很多,主要是使用的 搜狗输入法(<code>fcitx-sogoupinyin</code>)、谷歌输入法(<code>fcitx-googlepinyin</code>),sun拼音(<code>fcitx-sunpinyin</code>),另外还有 <code>fcitx-cloudpinyin</code> 可以进行云词库的搜索。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo pacman -S fcitx-sogoupinyin 或者 yaourt sogou</span><br><span class="line">sudo pacman -S fcitx-googlepinyin</span><br><span class="line">sudo pacman -S fcitx-sunpinyin</span><br><span class="line">sudo pacman -S fcitx-cloudpinyin</span><br></pre></td></tr></table></figure><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/p6jow4GrbCEtJhl.png" alt="manjaro-software1.png" title> </div> <div class="image-caption">manjaro-software1.png</div> </figure><p>如果还是无法使用,可能需要安装fcitx-gtk2:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo pacman -S fcitx-gtk2</span><br></pre></td></tr></table></figure><p>第一个为非激活状态,一般选择 <code>键盘-汉语</code> , 后面选择其他输入法,这样就可以使用 <code>Ctrl+Space</code> 进行键盘和输入法的切换(非激活状态与激活状态切换),激活状态可以使用 <code>Ctrl+Shift</code> 进行输入法的切换,很方便。</p><p>fcitx 配置可以修改快捷键,<code>Ctrl + Space</code> 可能会和 <code>Jetbrains</code> 系列产生冲突,建议修改成 <code>Ctrl + ,</code> 或者 <code>Super + Space</code>。</p><p>对于 <code>jetbrians</code> 系列 fcitx 无法跟随的情况 fcitx输入法配置>附加组件>勾选高级>xim前端>勾选on the spot</p><h3 id="Chrome"><a href="#Chrome" class="headerlink" title="Chrome"></a>Chrome</h3><p>使用 <code>pacman</code> 进行 Chrome 的安装也很简单,使用命令:</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo pacman -S google-chrome</span><br></pre></td></tr></table></figure><p>或者安装 <code>chromium</code>:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo pacman -S chromium</span><br></pre></td></tr></table></figure><h3 id="中文汉化"><a href="#中文汉化" class="headerlink" title="中文汉化"></a>中文汉化</h3><p>firefox-i18n-zh-cn : 火狐浏览器中文汉化<br>thunderbird-i18n-zh-cn : thunderbird 邮件汉化<br>gimp-help-zh_cn :<br>libreoffice-still-zh-CN : libreoffice 汉化<br>man-pages-zh_cn : man 帮助文档汉化</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo pacman -S --noconfirm firefox-i18n-zh-cn thunderbird-i18n-zh-cn gimp-help-zh_cn libreoffice-still-zh-CN man-pages-zh_cn</span><br></pre></td></tr></table></figure><p>火狐中文包安装完之后,在火狐的菜单中选择 <code>add-ons</code> 检查中文包是否安装完好;如果已经包含了,在地址栏中输入 <code>about:config</code> 。搜索 intl.locale.requested, 如果没有,则右键新建一个,修改值为 <code>zh_CN</code>,重启。</p><h3 id="Zsh"><a href="#Zsh" class="headerlink" title="Zsh"></a>Zsh</h3><p>安装 <code>oh-my-zsh</code> 作为 <code>shell</code> :</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo pacman -S zsh git</span><br><span class="line">sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"</span><br><span class="line">chsh -s /bin/zsh</span><br></pre></td></tr></table></figure><p>或者使用 aur 中 <code>oh-my-zsh-git</code> 的软件包,一键安装。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo pacman -S zsh</span><br><span class="line">sudo pacman -S oh-my-zsh-git</span><br><span class="line">cp /usr/share/oh-my-zsh/zshrc ~/.zshrc #ohmyzsh配置文件</span><br><span class="line">chsh -s /bin/zsh #替换默认shell</span><br></pre></td></tr></table></figure><h3 id="Vim"><a href="#Vim" class="headerlink" title="Vim"></a>Vim</h3><p><code>vim</code> 是 <code>vi</code> 的增强编辑器,功能强大</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo pacman -S vim</span><br></pre></td></tr></table></figure><h3 id="oracle-jdk"><a href="#oracle-jdk" class="headerlink" title="oracle jdk"></a>oracle jdk</h3><p>系统自带了 openjdk ,但是还是想使用 oracle jdk,使用命令 <code>yay -S jdk8</code> 即可安装 oracle 的 jdk8, 安装的 jdk 位置是 <code>/usr/lib/jvm/java-8-jdk/bin/java</code>, 默认的 openjdk 位置是 <code>/usr/lib/jvm/default</code></p><p>但是这样安装之后 <code>java --version</code> 还是显示的 OpenJDK。</p><p>使用 <code>archlinux-java</code> 命令进行jdk的选择,archlinux-java 的说明见:<a href="https://wiki.archlinux.org/index.php/java" target="_blank" rel="noopener">Java ArchWiki</a>、或者 <a href="https://wiki.archlinux.org/index.php/Java_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87" target="_blank" rel="noopener">Java ArchWIki(简体中文)</a>)</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">archlinux-java <COMMAND></span><br><span class="line"></span><br><span class="line">COMMAND:</span><br><span class="line">statusList installed Java environments and enabled one</span><br><span class="line">getReturn the short name of the Java environment set as default</span><br><span class="line">set <JAVA_ENV>Force <JAVA_ENV> as default</span><br><span class="line">unsetUnset current default Java environment</span><br><span class="line">fixFix an invalid/broken default Java environment configuration</span><br></pre></td></tr></table></figure><h3 id="Maven"><a href="#Maven" class="headerlink" title="Maven"></a>Maven</h3><p>安装 maven 作为 java 项目的包管理软件,执行命令 <code>yay -S maven</code>。maven 安装路径为:<code>/opt/maven</code>。</p><p>执行 <code>cp /opt/maven/conf/setting.xml ~/.m2/</code> 拷贝全局配置到当前用户目录,修改 .m2 目录中的配置文件进行个人配置修改。</p><h3 id="QQ"><a href="#QQ" class="headerlink" title="QQ"></a>QQ</h3><p>Gnome 桌面的 Manjaro 可用,KDE 桌面的 Manjaro 我试用时,无法使用,以下内容先记录下来</p><p><code>TIM</code> 是腾讯旗下的聊天工具 <code>QQ</code> 的新版设计,腾讯官方已经在 2010 年停止了 Linux 版的 QQ 更新,wine 版的 QQ是网友制作并维护的 Linux 版 QQ,不过也在 2017 年停止了更新,于是 deepin 公司维护了一个 deepin wine 系列软件,包括 QQ。</p><p><strong>deepin:</strong>如果您用的是 deepin,deepinwine 的 QQ 默认就已经安装。</p><p><strong>Arch系:</strong>如果您用的是 archlinux/antergos/manjaro,可以用 <code>yaourt</code> 命令安装它。<code>manjaro</code> 默认就开启了 <code>AUR</code>,在 <code>pamac</code> 图形管理器上搜 <code>deepin office</code>,然后切换到 AUR 标签,出来几种可用的 <code>deepin wine</code>包, <code>deepin</code> 粉丝 <a href="https://gitee.com/wszqkzqk/" target="_blank" rel="noopener">wszqkzqk</a> 最开始移植的 <code>deepin.com.qq.office</code> 和 <code>deepin.com.qq.im</code>。最新的还有 <code>countstarlight</code> 移植的2.0的 <code>tim</code> 版本。</p><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo pacman -S deepin.com.qq.office</span><br><span class="line">sudo pacman -S deepin.com.qq.im</span><br></pre></td></tr></table></figure><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/nf2gHSx5pmdDNjw.png" alt="manjaro-software2.png" title> </div> <div class="image-caption">manjaro-software2.png</div> </figure><p>虽然我在 Octopi 中找到了这两个包,也安装成功了,但是实际上 QQ 并不能打开成功,有待后续继续研究。</p><h3 id="微信"><a href="#微信" class="headerlink" title="微信"></a>微信</h3><p>微信安装的是 <code>electronic-wechat-git</code>:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo pacman -S electronic-wechat-git</span><br></pre></td></tr></table></figure><h3 id="PDF-阅读器"><a href="#PDF-阅读器" class="headerlink" title="PDF 阅读器"></a>PDF 阅读器</h3><p>可以使用强大的福昕PDF阅读器,或者使用小巧的 evince 。如果只是阅读,evince 已经够用了。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yay -S foxitreader</span><br><span class="line">yay -S evince</span><br></pre></td></tr></table></figure><h3 id="笔记工具"><a href="#笔记工具" class="headerlink" title="笔记工具"></a>笔记工具</h3><p>cherrytree 是一个以节点为管理元素的笔记软件,小巧轻便,还可以加密,推荐使用。<br>另外的为知笔记(wiznote)、蚂蚁笔记(leanote), 也都是使用比较广泛的笔记软件。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yay -S cherrytree</span><br></pre></td></tr></table></figure><h3 id="截图工具"><a href="#截图工具" class="headerlink" title="截图工具"></a>截图工具</h3><p>安装截图工具 <code>xfce4-screenshooter</code>:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo pacman -S xfce4-screenshooter</span><br></pre></td></tr></table></figure><p>设置快捷键, >键盘>应用程序快捷键,添加快捷键,命令为 <code>xfce4-screenshooter -f</code></p><p>或者安装深度的截图工具 <code>deepin-screenshot</code>:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo pacman -S deepin-screenshot</span><br></pre></td></tr></table></figure><p>设置快捷键, >键盘>应用程序快捷键,添加快捷键,命令为 <code>deepin-screenshot</code></p><p>deepin 的截图和 windows 下一般的截图工具操作体验一致,比较推荐。</p><h3 id="Guake-Tilda-yakuake"><a href="#Guake-Tilda-yakuake" class="headerlink" title="Guake/Tilda/yakuake"></a>Guake/Tilda/yakuake</h3><p>Manjaro KDE 系统默认是有快速下拉的终端 <code>Yakuake</code>, xcef 和 Gnome 版没有,可以安装 Guake 或者 Tilda 实现相同功能。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo pacman -S tilda</span><br><span class="line">sudo pacman -S guake</span><br></pre></td></tr></table></figure><p><code>tilda</code> 默认是左上角显示,使用快捷键 <code>F1</code>;<code>Guake</code> 默认是顶部显示,快捷键 <code>F12</code>。<br>可以使用快捷键,快速打开终端输入命令。</p><h3 id="快速搜索"><a href="#快速搜索" class="headerlink" title="快速搜索"></a>快速搜索</h3><p>类似于 Mac 上的 Alfred,快速搜索,可以自行在配置中添加快捷键。不是使用体验只能说还行,Gnome 自带的搜索其实也可以做到很多事情的,快捷键 <code>Super + A</code>。<br>对 synapse 有兴趣的可以尝试一下。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yay -S synapse</span><br></pre></td></tr></table></figure><p>另外还有个类似功能的软件叫 <code>Albert</code></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yay -S albert</span><br></pre></td></tr></table></figure><p>建议 <code>albert</code> 使用加快捷方式的办法,快捷方式的命令使用 <code>albert toggle</code> 或者 <code>albert show</code>。使用应用内的快捷方式实在是不怎么可靠。</p><p><code>albert</code> 相对于 <code>synapse</code> 界面要素雅一点,<code>synapse</code> 可以在界面上就控制你搜索的类型。</p><p><code>albert</code> 的自定义快捷命令用于搜索引擎的快速使用深得我心,<code>synapse</code> 找了半天没法自定义网页搜索。</p><h3 id="剪切板管理-copyq"><a href="#剪切板管理-copyq" class="headerlink" title="剪切板管理 copyq"></a>剪切板管理 copyq</h3><p>类似于 Ditto,监控管理剪切板。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yay -S copyq</span><br></pre></td></tr></table></figure><h3 id="开发工具"><a href="#开发工具" class="headerlink" title="开发工具"></a>开发工具</h3><p>开发 java 使用 IDEA .<br>开发其他脚本语言,例如 javascript, 使用 vscode .<br>连接数据库使用 dbeave (非常强大,Mysql、Oracle应有尽有)</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"># 社区版 IDEA</span><br><span class="line">yay -S intellij-idea-community-edition</span><br><span class="line"># 商业版 IDEA</span><br><span class="line">yay -S intellij-idea-ultimate-edition</span><br><span class="line"># vscode</span><br><span class="line">yay -S visual-studio-code</span><br><span class="line"># dbeaver</span><br><span class="line">yay -S dbeaver</span><br></pre></td></tr></table></figure><h3 id="gnome-主题美化"><a href="#gnome-主题美化" class="headerlink" title="gnome 主题美化"></a>gnome 主题美化</h3><p>我选择的 gnome 桌面主题组合是主题 <code>Mc-OS-themes</code> 、图标 <code>la-capitaine-icon-theme</code>和 <code>docky</code>。</p><h4 id="主题"><a href="#主题" class="headerlink" title="主题"></a>主题</h4><p>下载 <code>Mc-OS-themes</code>, 使用 git 直接下载在 github 上的源码。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git clone git@github.com:paullinuxthemer/Mc-OS-themes.git</span><br></pre></td></tr></table></figure><p>然后在 clone 下来的文件夹中选择你想要的 mac 版本样式,拷贝到 <code>~/.themes</code> 文件夹下。例如 <code>McOS-MJV-3.30</code> 是 Mojava 版本的 OS X 的仿制主题。<br>在 <code>gnome tweak</code> 中可以进行外观管理,应用程序 选择 <code>McOS-MJV-3.30</code> 即可。</p><h4 id="图标"><a href="#图标" class="headerlink" title="图标"></a>图标</h4><p>下载 <code>la-capitaine-icon-theme</code> 图标源码, 可以直接 clone 到图标文件夹:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">mkdir ~/.icons</span><br><span class="line">cd ~/.icons</span><br><span class="line">git clone git@github.com:keeferrourke/la-capitaine-icon-theme.git</span><br></pre></td></tr></table></figure><p>在 tweak 中进行外观管理,图标选择 <code>la-capitaine-icon-theme</code> 即可拥有 mac 的大图标。</p><h4 id="dock"><a href="#dock" class="headerlink" title="dock"></a>dock</h4><p>要想改得像 mac 主题,最明显的特征是那个大 dock 栏。使用 <code>docky</code> 可以拥有这种感觉。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yay -S docky</span><br></pre></td></tr></table></figure><p>安装完了之后,可以把 gnome 左侧的 dock 栏去掉了。在 tweak 设置中拓展下有个 <code>dash to dock</code>, 把这个拓展关掉就不显示左侧的 dock 栏了。</p><p>安装完之后的效果:</p><figure class="image-bubble"> <div class="img-lightbox"> <div class="overlay"></div> <img src="https://i.loli.net/2020/01/31/Gb7FyQMNJmaXdec.png" alt="manjaro-theme1.png" title> </div> <div class="image-caption">manjaro-theme1.png</div> </figure><h4 id="字体"><a href="#字体" class="headerlink" title="字体"></a>字体</h4><p>文泉系列字体:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yay -S wqy-microhei-lite</span><br><span class="line">yay -S wqy-bitmapfont </span><br><span class="line">yay -S wqy-zenhei</span><br></pre></td></tr></table></figure><p>adobe 系列字体及其他:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yay -S adobe-source-han-sans-cn-fonts </span><br><span class="line">yay -S adobe-source-han-serif-cn-fonts </span><br><span class="line">yay -S noto-fonts-cjk</span><br></pre></td></tr></table></figure><h3 id="快捷键"><a href="#快捷键" class="headerlink" title="快捷键"></a>快捷键</h3><p>打开设置>设备>Keyboard ,最下面的加号新增快捷方式 (注意是 Gnome 主题)</p><ol><li>Terminal: 命令 <code>/usr/bin/gnome-terminal</code>, 快捷键 <code>Super + T</code></li><li>synapse: 命令 <code>synapse</code>, 快捷键 <code>Super + R</code></li><li>深度截图: 命令 <code>deepin-screenshot</code>, 快捷键 <code>Ctrl + Alt + A</code></li><li>打开文件管理器: 命令 <code>nautilus</code>, 快捷键 <code>Super + E</code></li></ol><h3 id="ssr"><a href="#ssr" class="headerlink" title="ssr"></a>ssr</h3><p>安装 electron-ssr 需要安装 <code>python</code> 和 <code>shadowsocksr</code>:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yay -S python shadowsocksr</span><br></pre></td></tr></table></figure><p>去 <code>electron-ssr</code> 的 <a href="https://github.com/erguotou520/electron-ssr">github仓库</a> 中下载 release 发布包。</p><p>其中 <code>electron-ssr-0.2.4-x86_64.AppImage</code> 可以用于各种 linux 环境直接执行。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">chmod a+x electron-ssr-0.2.4-x86_64.AppImage</span><br><span class="line">./*.AppImage</span><br></pre></td></tr></table></figure><p>安装之后运行,可能在任务栏没有图标,根据 <a href="https://github.com/erguotou520/electron-ssr/blob/master/docs/FAQ.md">FAQ</a> 说明是因为环境中缺少<code>libappindicator1</code> 应用指示器。</p><p>查看到 Issue <a href="https://github.com/erguotou520/electron-ssr/issues/180">#180</a> 和 Issue <a href="https://github.com/erguotou520/electron-ssr/issues/176">#176</a>,</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">尝试安装</span><br><span class="line">sudo pacman -S libappindicator-sharp libappindicator-gtk3</span><br><span class="line">或者</span><br><span class="line">sudo pacman -S libappindicator-gtk2</span><br></pre></td></tr></table></figure><h3 id="远程连接"><a href="#远程连接" class="headerlink" title="远程连接"></a>远程连接</h3><p>远程桌面管理,支持VNC、SSH、RDP等,使用 <code>Remmina</code>,功能强大,配置简单。如果要使用 Remmina 进行 RDP 连接,需要安装 <code>freerdp</code> 。<br>管理 FTP 文件服务器,可以使用 <code>Filezilla</code>.</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yay -S freerdp remmina</span><br></pre></td></tr></table></figure><h3 id="teamviewer"><a href="#teamviewer" class="headerlink" title="teamviewer"></a>teamviewer</h3><p>teamview 是我最常用的远程控制软件,安装 teamview: <code>yay -S teamviewer</code></p><p>安装完了之后发现无法链接服务器,连本机ID都不显示了,查询了一些文档,在 <a href="https://forum.manjaro.org/t/teamviewer-beta-13-not-ready-please-check-connection/37638/3" target="_blank" rel="noopener">Teamviewer-beta 13, “Not ready, please check connection”</a> 这篇文章中找到解决方法。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo teamviewer --daemon enable</span><br><span class="line">或者</span><br><span class="line">systemctl enable teamviewerd</span><br><span class="line">systemctl start teamviewerd</span><br></pre></td></tr></table></figure><p>记得右键任务图标退出再重新打开,看能不能链接上服务器。</p><h3 id="虚拟机-virtualbox"><a href="#虚拟机-virtualbox" class="headerlink" title="虚拟机 virtualbox"></a>虚拟机 virtualbox</h3><p>具体安装参考 manjaro 的官方 wiki: <a href="https://wiki.manjaro.org/index.php?title=Virtualbox" target="_blank" rel="noopener">VirtualBox</a></p><p>首先使用 <code>uname -r</code> 查看 manjaro 的内核版本,我的是 <code>4.19.0-Manjaro</code>,在后面选择 virtualbox 模块的时候选择 <code>linux419-virtualbox-host-modules</code></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo pacman -S virtualbox</span><br></pre></td></tr></table></figure><p>还可以安装 <code>virtualbox-ext-oracle</code> Oracle 拓展包</p><h3 id="配置菜单或者启动器"><a href="#配置菜单或者启动器" class="headerlink" title="配置菜单或者启动器"></a>配置菜单或者启动器</h3><p>参考 manjaro 官方的 wiki: <a href="https://wiki.archlinux.org/index.php/Desktop_entries_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87" target="_blank" rel="noopener">Desktop entries (简体中文)</a>)<br>应用程序配置项,即 .desktop 文件是原信息资源和应用程序快捷图标的集合<br>系统程序的配置项通常位于 <code>/usr/share/applications</code> 或 <code>/usr/local/share/applications</code> 目录,单用户安装的程序位于 <code>~/.local/share/applications</code> 目录,优先使用用户的配置项。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">cd ~/.local/share/applications</span><br><span class="line"></span><br><span class="line">vi idea.desktop</span><br><span class="line"></span><br><span class="line">[Desktop Entry]</span><br><span class="line">Type=Application</span><br><span class="line">Version=1.0</span><br><span class="line">Name=IntelliJ IDEA</span><br><span class="line">Exec=/opt/ide/idea/bin/idea.sh</span><br><span class="line">Icon=/opt/ide/idea/bin/idea.png</span><br><span class="line">Terminal=false</span><br><span class="line">Categories=Development;Languages;Java;</span><br></pre></td></tr></table></figure><p>Manjaro Gnome 在 <code>~/.config/autostart</code> 目录下, 输入下列内容:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Name[zh_CN]=Guake 终端</span><br><span class="line">Name=Guake Terminal</span><br><span class="line">Comment=Use the command line in a Quake-like terminal</span><br><span class="line">TryExec=guake</span><br><span class="line">Exec=guake</span><br><span class="line">Icon=guake</span><br><span class="line">Type=Application</span><br><span class="line">Categories=GNOME;GTK;System;Utility;TerminalEmulator;</span><br><span class="line">StartupNotify=true</span><br><span class="line">X-Desktop-File-Install-Version=0.22</span><br></pre></td></tr></table></figure><p>或者在 Manjaro Gnome 中使用 tweaks 管理开机启动项,程序会创建以上内容。</p><h3 id="修改-grub2-的等待时间"><a href="#修改-grub2-的等待时间" class="headerlink" title="修改 grub2 的等待时间"></a>修改 grub2 的等待时间</h3><p>无论你的电脑是否有 2个或更多的操作系统,只要安装了 LinuxMint/Ubuntu,就必然会安装grub2作为引导管理器。grub2 启动时,会在默认的启动项上停留数秒(默认 10秒),等待用户选择。我们可以把这个时间改的更短。如果是 LinuxMint/Ubuntu 单系统,可以直接改为0,即直接进入,无需等待。<br>以管理员身份编辑 grub 配置文件,修改 GRUB_TIMEOUT 项后的数字。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sudo vi /etc/default/grub</span><br></pre></td></tr></table></figure><h3 id="个人安装记录"><a href="#个人安装记录" class="headerlink" title="个人安装记录"></a>个人安装记录</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">yay -S fcitx-im fcitx-configtool fcitx-sogoupinyin fcitx-cloudpinyin fcitx-gtk2 </span><br><span class="line">yay -S git vim zsh oh-my-zsh-git</span><br><span class="line">yay -S electronic-wechat-git deepin.com.qq.office deepin.com.qq.im telegram-desktop deepin-screenshot</span><br><span class="line">yay -S python python-pip libappindicator-sharp libappindicator-gtk3 </span><br><span class="line">yay -S guake synapse albert docky copyq screenfetch bleachbit goldendict meld gitkraken</span><br><span class="line">yay -S google-chrome firefox firefox-i18n-zh-cn thunderbird thunderbird-i18n-zh-cn man-pages-zh_cn visual-studio-code-bin netease-cloud-music smplayer</span><br><span class="line">yay -S wqy-microhei-lite wqy-bitmapfont wqy-zenhei adobe-source-han-sans-cn-fonts adobe-source-han-serif-cn-fonts noto-fonts-cjk</span><br><span class="line">yay -S jdk8 maven teamview</span><br><span class="line"></span><br><span class="line">sudo archlinux-java status</span><br><span class="line">sudo archlinux-java set java-8-jdk</span><br><span class="line"></span><br><span class="line">sudo teamviewer --daemon enable</span><br><span class="line">或者</span><br><span class="line">systemctl enable teamviewerd</span><br><span class="line">systemctl start teamviewerd</span><br><span class="line"></span><br><span class="line">sudo vi ~/.xprofile</span><br><span class="line">export GTK_IM_MODULE=fcitx</span><br><span class="line">export QT_IM_MODULE=fcitx</span><br><span class="line">export XMODIFIERS="@im=fcitx"</span><br><span class="line"></span><br><span class="line">cp /usr/share/oh-my-zsh/zshrc ~/.zshrc #ohmyzsh配置文件</span><br><span class="line">sudo chsh -s /bin/zsh #替换默认shell</span><br><span class="line"></span><br><span class="line">sudo pip install shadowsocks</span><br><span class="line"></span><br><span class="line">curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash</span><br><span class="line">sudo vi ~/.zshrc</span><br><span class="line">export NVM_DIR="$HOME/.nvm"</span><br><span class="line">[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm</span><br><span class="line">[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion</span><br><span class="line"></span><br><span class="line">nvm install node</span><br><span class="line">nvm use node</span><br><span class="line">npm config set registry https://registry.npm.taobao.org</span><br><span class="line">npm install -g nrm</span><br><span class="line">nrm test</span><br><span class="line">nrm use cnpm</span><br><span class="line"></span><br><span class="line">chmod a+x electron-ssr-0.2.4-x86_64.AppImage</span><br><span class="line">./*.AppImage</span><br><span class="line"></span><br><span class="line">mkdir ~/.themes ~/.icons ~/project</span><br><span class="line">git clone git@github.com:paullinuxthemer/Mc-OS-themes.git ~/project</span><br><span class="line">cp -r ~/project/Mc-OS-themes/McOS-MJV-3.30 ~/.themes/</span><br><span class="line">git clone git@github.com:keeferrourke/la-capitaine-icon-theme.git ~/.icons</span><br></pre></td></tr></table></figure><h3 id="其他软件"><a href="#其他软件" class="headerlink" title="其他软件"></a>其他软件</h3><p>在包管理软件中搜索或者使用 pacman/yaourt/aurman 等命令行进行搜索下载。<br>以下的软件有一些还没有试用过,在别人的文章中看到的,在此先记录一下。</p><ol><li>Teamview:PC 远程控制/远程访问软件</li><li>Steam:游戏的分发平台</li><li>goldendict:linux 一款强大的字典</li><li>franz:通讯软件集合,包括 facebook、微信、google+</li><li>intellij-idea:java 开发工具 <code>Intellij IDEA</code></li><li>netease-cloud-music:网易云音乐</li><li>smplayer: 视频播放器</li><li>masterpdfeditor 对linux用户免费的PDF浏览及编辑器,支持实时预览;</li><li>remarkable: 卓越且功能齐全的 Markdown 编辑器</li><li>uget: 媲美迅雷的下载工具;</li><li>filezilla: 强大的FTP工具;</li><li>deepin-screenshot: 深度截图工具;</li><li>shutter: 强大的截图工具,gnome-web-photo配合使用;</li><li>bleachbit: 快速释放磁盘空间并不知疲倦地守卫你的隐私。释放缓存,删除 cookie,清除互联网浏览历史,清理临时文件,删除日志,以及更多功能…</li><li>thunderbird: Mozilla 旗下的邮件管理软件</li><li>redshift: 根据你的周边调整你屏幕的色温。当你夜晚在屏幕前工作时,它也许能帮助你减少对眼睛的伤害;</li><li>wiznote 为知笔记;</li><li>meld 文本比较;</li><li>goldendict 词典软件;</li><li>easystroke 鼠标手势;</li><li>catfish 基于GTK+的非常快速,轻量级的文件搜索工具;</li><li>peek 屏幕录像工具,小巧玲珑,可保存录像为gif动图和兼容于html5的webm视频;</li><li>dbeaver 通用数据库客户端,支持多个平台及多种数据库,社区版是免费的; </li><li>nethack 经典的命令行游戏,启动命令行nethack;</li><li>gnome-mines 经典的扫雷游戏(gnome桌面自带,kde也有类似的kmines);</li><li>2048-qt 经典的2048游戏;</li><li>zaz 经典的泡泡射击游戏;</li><li>sudokuki 基于Java的跨平台的数独游戏(<a href="https://sourceforge.net/projects/sudokuki/files/sudokuki/);" target="_blank" rel="noopener">https://sourceforge.net/projects/sudokuki/files/sudokuki/);</a></li><li>wesnoth 经典的韦诺之战,Linux上比较火的游戏,回合制策略游戏;</li><li>0ad 跨平台的“帝国时代”(<a href="http://sourceforge.net/projects/zero-ad/files/releases/locales/下载对应版本的汉化放到$HOME/.local/share/0ad/mods/public/);" target="_blank" rel="noopener">http://sourceforge.net/projects/zero-ad/files/releases/locales/下载对应版本的汉化放到$HOME/.local/share/0ad/mods/public/);</a></li><li>Timeshift: 备份软件</li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Manjaro 是一个界面友好的 Linux 发行版,依赖于 Arch Linux 的 AUR 软件系统,拥有着众多的软件,及方便的使用操作。初次使用感觉还不错,众多的软件,甚至包括 Steam 都内置在了系统中。看Linux Kernel 的更新提示,Manjaro 的更新还是很频繁的,经常会有各种更新,更新的稳定性有待译后检查。在这里可以推荐给大家使用以下。</p>]]></content>
<summary type="html">
<blockquote>
<p>linux 拥有大量的发行版,虽然都是使用的相同的 linux kernel,但是由于 linux 下软件的繁多,各种不同的发行版有着不同的软件组合和生态。大众常用的几个发行版主要有 RedHat、Fedora、CentOS、Ubuntu 等。最近发现了 ArchLinux 分支下据说最好的版本 ———— Manjaro,对其进行一番尝试。</p>
</blockquote>
</summary>
<category term="系统" scheme="https://github.com/zzycreate/categories/%E7%B3%BB%E7%BB%9F/"/>
<category term="Linux" scheme="https://github.com/zzycreate/tags/Linux/"/>
<category term="ArchLinux" scheme="https://github.com/zzycreate/tags/ArchLinux/"/>
<category term="Manjaro" scheme="https://github.com/zzycreate/tags/Manjaro/"/>
</entry>
<entry>
<title>个人npm命令记录</title>
<link href="https://github.com/zzycreate/2018/10/23/%E4%B8%AA%E4%BA%BAnpm%E5%91%BD%E4%BB%A4%E8%AE%B0%E5%BD%95/"/>
<id>https://github.com/zzycreate/2018/10/23/个人npm命令记录/</id>
<published>2018-10-23T13:47:53.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>记录一些在使用 npm 时,常用的命令记录。使用任何工具最好的方式:<a href="https://docs.npmjs.com/" target="_blank" rel="noopener">npm 官网文档</a></p></blockquote><a id="more"></a><h2 id="npm-更新"><a href="#npm-更新" class="headerlink" title="npm 更新"></a>npm 更新</h2><p>使用 <code>npm -v</code> 命令进行 npm 的版本查询。</p><p>更新 npm 到最新或者指定的版本:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">npm install npm@latest -g</span><br><span class="line">npm install npm@6.3.0 -g</span><br></pre></td></tr></table></figure><p>更新 npm 全局安装的指定包:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">npm update -g <pkg...></span><br></pre></td></tr></table></figure><h2 id="npm-设置环境变量"><a href="#npm-设置环境变量" class="headerlink" title="npm 设置环境变量"></a>npm 设置环境变量</h2><p>使用 <code>npm set</code> 设置环境变量</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ npm set init-author-name 'Your name'</span><br><span class="line">$ npm set init-author-email 'Your email'</span><br><span class="line">$ npm set init-author-url 'http://yourdomain.com'</span><br><span class="line">$ npm set init-license 'MIT'</span><br></pre></td></tr></table></figure><p>上面命令等于为npm init设置了默认值,以后执行npm init的时候,package.json的作者姓名、邮件、主页、许可证字段就会自动写入预设的值。<br>这些信息会存放在用户主目录的 ~/.npmrc文件,使得用户不用每个项目都输入。如果某个项目有不同的设置,可以针对该项目运行npm config。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ npm config set save-prefix ~</span><br></pre></td></tr></table></figure><p>上面的命令使得 <code>npm install --save</code> 和 <code>npm install --save-dev</code> 安装新模块时,允许的版本范围从克拉符号(<code>^</code>)改成波浪号(<code>~</code>),即从允许小版本升级,变成只允许补丁包的升级。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ npm config set init.author.name $name</span><br><span class="line">$ npm config set init.author.email $email</span><br></pre></td></tr></table></figure><p>上面命令指定使用npm init时,生成的package.json文件的字段默认值。</p><h2 id="npm-信息查询"><a href="#npm-信息查询" class="headerlink" title="npm 信息查询"></a>npm 信息查询</h2><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">npm info <pkg> <field></span><br><span class="line"></span><br><span class="line">$ npm info underscore description</span><br><span class="line">JavaScript's functional programming helper library.</span><br><span class="line"></span><br><span class="line">$ npm info underscore homepage</span><br><span class="line">http://underscorejs.org</span><br><span class="line"></span><br><span class="line">$ npm info underscore version</span><br><span class="line">1.5.2</span><br></pre></td></tr></table></figure><p>使用 <code>npm info</code> 命令可以查看每个模块的具体信息。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ npm search <搜索词></span><br></pre></td></tr></table></figure><p>查询 <code>npm</code> 仓库中包的信息。</p><h2 id="npm-依赖结构"><a href="#npm-依赖结构" class="headerlink" title="npm 依赖结构"></a>npm 依赖结构</h2><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ npm list</span><br></pre></td></tr></table></figure><p><code>npm list</code> 命令以树型结构列出当前项目安装的所有模块,以及它们依赖的模块。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ npm list -global</span><br></pre></td></tr></table></figure><p>加上 global 参数,会列出全局安装的模块。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ npm list -global -depth 0</span><br></pre></td></tr></table></figure><p>加 <code>-depth 0</code> 指定只展示全局一级依赖。</p>]]></content>
<summary type="html">
<blockquote>
<p>记录一些在使用 npm 时,常用的命令记录。使用任何工具最好的方式:<a href="https://docs.npmjs.com/" target="_blank" rel="noopener">npm 官网文档</a></p>
</blockquote>
</summary>
<category term="收集" scheme="https://github.com/zzycreate/categories/%E6%94%B6%E9%9B%86/"/>
<category term="个人收集" scheme="https://github.com/zzycreate/tags/%E4%B8%AA%E4%BA%BA%E6%94%B6%E9%9B%86/"/>
<category term="NPM" scheme="https://github.com/zzycreate/tags/NPM/"/>
</entry>
<entry>
<title>个人IDEA插件收藏</title>
<link href="https://github.com/zzycreate/2018/10/15/%E4%B8%AA%E4%BA%BAIDEA%E6%8F%92%E4%BB%B6%E6%94%B6%E8%97%8F/"/>
<id>https://github.com/zzycreate/2018/10/15/个人IDEA插件收藏/</id>
<published>2018-10-15T22:15:48.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>IntelliJ IDEA 的插件众多,有一些插件能够提高开发人员的开发效率,本文记录一些个人使用的IDEA插件。</p></blockquote><a id="more"></a><h2 id="ignore"><a href="#ignore" class="headerlink" title=".ignore"></a>.ignore</h2><p>插件提供各种 .ignore 文件的模板。例如 .gitignore 有各种语言的模板,可以快速过滤一些工具或者语言产生的不需要提交 git 的各种文件。</p><h2 id="Alibaba-Java-Coding-Guidelines"><a href="#Alibaba-Java-Coding-Guidelines" class="headerlink" title="Alibaba Java Coding Guidelines"></a>Alibaba Java Coding Guidelines</h2><p>依照《阿里巴巴Java开发手册》进行项目代码分析,并可以根据插件进行代码优化。p3c的git地址:<a href="https://github.com/alibaba/p3c">https://github.com/alibaba/p3c</a></p><h2 id="JRebel-for-IntelliJ"><a href="#JRebel-for-IntelliJ" class="headerlink" title="JRebel for IntelliJ"></a>JRebel for IntelliJ</h2><p>JRebel 热部署插件</p><h2 id="Free-Mybatis-plugin"><a href="#Free-Mybatis-plugin" class="headerlink" title="Free Mybatis plugin"></a>Free Mybatis plugin</h2><p>Free Mybatis plugin 是 MyBatisCodeHelperPro 的免费简化版本,myabtis 插件基本需要的功能都有。</p><h2 id="Rainbow-Brackets"><a href="#Rainbow-Brackets" class="headerlink" title="Rainbow Brackets"></a>Rainbow Brackets</h2><p>Rainbow Brackets 给各种括号提供彩色配色,可以更方便的识别括号范围。</p><h2 id="Lombok-Plugin"><a href="#Lombok-Plugin" class="headerlink" title="Lombok Plugin"></a>Lombok Plugin</h2><p>Lombok Plugin 提供 lombok 的插件提供,可以省略 getter、setter、toString 等方法的书写,并提供一些常用模式的注入,例如 builder 方法、slf4j 等。</p><h2 id="Maven-Helper"><a href="#Maven-Helper" class="headerlink" title="Maven Helper"></a>Maven Helper</h2><p>Maven Helper 插件增强 maven 的 pom 文件解析,可以快速解决 maven 依赖冲突,查找依赖层级结构。</p><h2 id="CodeGlance"><a href="#CodeGlance" class="headerlink" title="CodeGlance"></a>CodeGlance</h2><p>CodeGlance 提供代码右侧导航小地图。</p><h2 id="AceJump"><a href="#AceJump" class="headerlink" title="AceJump"></a>AceJump</h2><p>AceJump 提供键盘快速查找单词的方式,当你想将光标跳到某个位置的时候,使用快捷键 <code>Ctrl + ;</code> 根据提示可以快速定位到指定的位置</p><h2 id="IdeaVim"><a href="#IdeaVim" class="headerlink" title="IdeaVim"></a>IdeaVim</h2><p>IdeaVim 给 IDEA 带来了 vim 的操作方式,适合于熟悉 vim 的开发人员。</p><h2 id="Grep-Console"><a href="#Grep-Console" class="headerlink" title="Grep Console"></a>Grep Console</h2><p>Grep Console 给控制台提供各种级别日志的背景着色,并可以根据用户进行自定义设置。</p><h2 id="String-Manipulation"><a href="#String-Manipulation" class="headerlink" title="String Manipulation"></a>String Manipulation</h2><p>String Manipulation 可以快速的将字符串转换为驼峰、小写、大写、下划线等各种格式,快捷键 <code>Alt + M</code></p><h2 id="Git-Flow"><a href="#Git-Flow" class="headerlink" title="Git Flow"></a>Git Flow</h2><p>Git Flow 提供 git flow 方式的 git 分支管理,并可以依照这种方式管理项目。</p><h2 id="Markdown-Navigation"><a href="#Markdown-Navigation" class="headerlink" title="Markdown Navigation"></a>Markdown Navigation</h2><p>Markdown Navigation 提供了 markdown 一种渲染方式,和 IDEA 默认提供的 markdown渲染插件有冲突,需要进行设置才能展示效果。</p><h2 id="Translation"><a href="#Translation" class="headerlink" title="Translation"></a>Translation</h2><p>Translation 提供了 google、有道、百度 三种翻译方式,可以快速翻译代码中的语言。</p><h2 id="ReadHub"><a href="#ReadHub" class="headerlink" title="ReadHub"></a>ReadHub</h2><p>使用 IDEA 进行新闻热点的阅读,适合用来摸鱼。</p>]]></content>
<summary type="html">
<blockquote>
<p>IntelliJ IDEA 的插件众多,有一些插件能够提高开发人员的开发效率,本文记录一些个人使用的IDEA插件。</p>
</blockquote>
</summary>
<category term="收集" scheme="https://github.com/zzycreate/categories/%E6%94%B6%E9%9B%86/"/>
<category term="个人收集" scheme="https://github.com/zzycreate/tags/%E4%B8%AA%E4%BA%BA%E6%94%B6%E9%9B%86/"/>
<category term="IDE" scheme="https://github.com/zzycreate/tags/IDE/"/>
<category term="IntelliJ IDEA" scheme="https://github.com/zzycreate/tags/IntelliJ-IDEA/"/>
<category term="插件" scheme="https://github.com/zzycreate/tags/%E6%8F%92%E4%BB%B6/"/>
</entry>
<entry>
<title>个人Linux使用命令记录</title>
<link href="https://github.com/zzycreate/2018/10/10/%E4%B8%AA%E4%BA%BALinux%E4%BD%BF%E7%94%A8%E5%91%BD%E4%BB%A4%E8%AE%B0%E5%BD%95/"/>
<id>https://github.com/zzycreate/2018/10/10/个人Linux使用命令记录/</id>
<published>2018-10-10T22:19:30.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>linux 的命令非常的多,有一些有效但是不常用的命令,可能需要临时进行翻阅,记录部分有效命令以备查阅使用</p></blockquote><a id="more"></a><h2 id="收藏"><a href="#收藏" class="headerlink" title="收藏"></a>收藏</h2><h3 id="网站"><a href="#网站" class="headerlink" title="网站"></a>网站</h3><ol><li><a href="http://linux.vbird.org/" target="_blank" rel="noopener">鳥哥的 Linux 私房菜 http://linux.vbird.org/</a></li><li><a href="http://linux.51yip.com/" target="_blank" rel="noopener">linux 命令手册 http://linux.51yip.com/</a></li></ol><h2 id="命令"><a href="#命令" class="headerlink" title="命令"></a>命令</h2><h3 id="压缩包相关"><a href="#压缩包相关" class="headerlink" title="压缩包相关"></a>压缩包相关</h3><h4 id="tar-命令"><a href="#tar-命令" class="headerlink" title="tar 命令"></a>tar 命令</h4><p><strong>tar 参数:</strong></p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"> -A, --catenate, --concatenate 追加 tar 文件至归档</span><br><span class="line">* -c, --create 创建一个新归档</span><br><span class="line"> -d, --diff, --compare 找出归档和文件系统的差异</span><br><span class="line"> --delete 从归档(非磁带!)中删除</span><br><span class="line"> -r, --append 追加文件至归档结尾</span><br><span class="line"> -t, --list 列出归档内容</span><br><span class="line"> -u, --update 仅追加比归档中副本更新的文件</span><br><span class="line">* -x, --extract, --get 从归档中解出文件</span><br><span class="line">* -v, --verbose 详细地列出处理的文件</span><br><span class="line">* -f, --file=ARCHIVE 使用归档文件或 ARCHIVE 设备,命令后必须跟文件名</span><br><span class="line">* -C, --directory=DIR 改变至目录 DIR</span><br><span class="line"> --exclude=PATTERN 排除以 PATTERN 指定的文件</span><br><span class="line"></span><br><span class="line"> -a, --auto-compress 使用归档后缀来决定压缩程序</span><br><span class="line"> -I, --use-compress-program=PROG 通过 PROG 过滤(必须是能接受 -d选项的程序)</span><br><span class="line">* -j, --bzip2 通过 bzip2 过滤归档</span><br><span class="line">* -z, --gzip, --gunzip, --ungzip 通过 gzip 过滤归档</span><br><span class="line">* -Z, --compress, --uncompress 通过 compress 过滤归档</span><br><span class="line">* -J, --xz filter the archive through xz</span><br></pre></td></tr></table></figure><h4 id="解压与解包"><a href="#解压与解包" class="headerlink" title="解压与解包"></a>解压与解包</h4><p>各种类型的包解压:</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line"><span class="comment"># *.tar 解包</span></span><br><span class="line">$ tar -xvf xx.tar [-C dir/]</span><br><span class="line"></span><br><span class="line"><span class="comment"># *.zip 解压</span></span><br><span class="line">$ unzip xx.zip dir/</span><br><span class="line"></span><br><span class="line"><span class="comment"># *.rar 解压</span></span><br><span class="line">$ rar x xx.rar</span><br><span class="line"></span><br><span class="line"><span class="comment"># *.gz 解压</span></span><br><span class="line">$ gunzip xx.gz</span><br><span class="line">或</span><br><span class="line">$ gzip -d xx.gz</span><br><span class="line"><span class="comment"># *.tar.gz 解压</span></span><br><span class="line">$ tar -xzvf xx.tar.gz [-C dir/]</span><br><span class="line"></span><br><span class="line"><span class="comment"># *.bz2 解压</span></span><br><span class="line">$ bzip2 -d xx.bz2</span><br><span class="line">或</span><br><span class="line">$ bunzip2 xx.bz2</span><br><span class="line"><span class="comment"># *.tar.bz2 解压</span></span><br><span class="line">$ tar -xjvf xx.tar.bz2 [-C dir/]</span><br><span class="line"></span><br><span class="line"><span class="comment"># *.Z 解压</span></span><br><span class="line">$ uncompress xx.Z</span><br><span class="line"><span class="comment"># *.tar.Z 解压</span></span><br><span class="line">$ tar -xZvf xx.tar.Z [-C dir/]</span><br><span class="line"></span><br><span class="line"><span class="comment"># *.xz 解压</span></span><br><span class="line">$ xz -d xx.tar.xz</span><br><span class="line"><span class="comment"># *.tar.xz 解压</span></span><br><span class="line">$ tar -xJvf xx.tar</span><br></pre></td></tr></table></figure><h4 id="压缩与打包"><a href="#压缩与打包" class="headerlink" title="压缩与打包"></a>压缩与打包</h4><p>各种类型的包压缩:</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line"><span class="comment"># *.tar 打包</span></span><br><span class="line">$ tar -cvf xx.tar file dir/ ...</span><br><span class="line"></span><br><span class="line"><span class="comment"># *.zip 压缩</span></span><br><span class="line">$ zip xx.zip file...</span><br><span class="line"></span><br><span class="line"><span class="comment"># *.rar 压缩</span></span><br><span class="line">$ rar a xx.rar file...</span><br><span class="line"></span><br><span class="line"><span class="comment"># *.gz 压缩</span></span><br><span class="line">$ gzip file</span><br><span class="line"><span class="comment"># *.tar.gz 打包压缩</span></span><br><span class="line">$ tar -czvf xx.tar.gz file dir/ ...</span><br><span class="line"></span><br><span class="line"><span class="comment"># *.bz2 压缩</span></span><br><span class="line">$ bzip2 -z file</span><br><span class="line"><span class="comment"># *.tar.bz2 打包压缩</span></span><br><span class="line">$ tar -cjvf xx.tar.bz2 file dir/ ...</span><br><span class="line"></span><br><span class="line"><span class="comment"># *.Z 压缩</span></span><br><span class="line">$ compress xx.tar.Z</span><br><span class="line"><span class="comment"># *.tar.Z 打包压缩</span></span><br><span class="line">$ tar -cZvf xx.tar.Z file dir/ ...</span><br><span class="line"></span><br><span class="line"><span class="comment"># *.xz 压缩</span></span><br><span class="line">$ xz -z xx.tar.xz</span><br><span class="line"><span class="comment"># *.tar.xz 打包压缩</span></span><br><span class="line">$ tar -cJvf xx.tar file dir/ ...</span><br></pre></td></tr></table></figure><h3 id="磁盘空间"><a href="#磁盘空间" class="headerlink" title="磁盘空间"></a>磁盘空间</h3><h4 id="df-Disk-Free"><a href="#df-Disk-Free" class="headerlink" title="df (Disk Free)"></a>df (Disk Free)</h4><p><code>df</code> 是用于整个系统的空间使用查询。<br>df命令使用的是 statfs 这个系统调用,直接读取分区的超级块信息获取分区使用情况。它的数据是基于分区元数据的,所以只能针对整个分区。由于df直接读取超级块,所以运行速度不受文件多少影响。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ df [-ahikHTm] [目录/文件名]</span><br><span class="line">选项与参数:</span><br><span class="line">-a :列出所有的文件系统,包括系统特有的 /proc 等文件系统;</span><br><span class="line">-k :以 KBytes 的容量显示各文件系统;</span><br><span class="line">-m :以 MBytes 的容量显示各文件系统;</span><br><span class="line">-h :以人类较易阅读的 GBytes, MBytes, KBytes 等格式自行显示;</span><br><span class="line">-H :以 M=1000K 取代 M=1024K 的进位方式;</span><br><span class="line">-T :连同该 partition 的 filesystem 名称 (例如 xfs) 也列出;</span><br><span class="line">-i :不用磁盘容量,而以 inode 的数量来显示</span><br></pre></td></tr></table></figure><p>常用命令:</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 以容易阅读的方式查看所有磁盘的容量</span></span><br><span class="line">$ df -ah</span><br></pre></td></tr></table></figure><h4 id="du-Disk-Usage"><a href="#du-Disk-Usage" class="headerlink" title="du (Disk Usage)"></a>du (Disk Usage)</h4><p><code>du</code> 是用于指定文件的空间使用查询。<br>du 命令会对待统计文件逐个调用 fstat 这个系统调用,获取文件大小。它的数据是基于文件获取的,所以有很大的灵活性,不一定非要针对一个分区,可以跨越多个分区操作。如果针对的目录中文件很多,du速度就会很慢了。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">$ du [-ahskm] 文件/目录名</span><br><span class="line">选项与参数:</span><br><span class="line">-a :列出所有的文件及目录容量,因为预设仅统计目录底下的文件数量而已。</span><br><span class="line">-h :以人类较容易阅读的容量格式 (G/M) 显示;</span><br><span class="line">-s :列出总量而已,而不列出每个目录占用容量;</span><br><span class="line">-S :不包括子目录下的总计,与 -s 有点差別。</span><br><span class="line">-k :以 KBytes 列出容量显示;</span><br><span class="line">-m :以 MBytes 列出容量显示;</span><br></pre></td></tr></table></figure><p>常用命令:</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 以容易阅读的方式查看当前目录所有文件的大小</span></span><br><span class="line">du -sh *</span><br></pre></td></tr></table></figure><p>以容易阅读的方式查看当前目录所有文件的大小,并且只显示一层目录:</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">du -sh --max-depth=1 *</span><br></pre></td></tr></table></figure><p>有时候需要排序现实,简单的方式是使用 <code>sort</code> 命令协助排序,因此不能使用 <code>-h</code> 参数,<code>-h</code> 参数展示的单位会影响排序结果,<br>另外再组合 head、tail 等命令只截取前后部分的数据,方便使用。</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">du -s * | sort -nr |head</span><br></pre></td></tr></table></figure><h3 id="git-命令"><a href="#git-命令" class="headerlink" title="git 命令"></a>git 命令</h3><h4 id="git-rm-删除远端已提交文件"><a href="#git-rm-删除远端已提交文件" class="headerlink" title="git rm 删除远端已提交文件"></a>git rm 删除远端已提交文件</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git rm --cached <file></span><br></pre></td></tr></table></figure><h4 id="ssh-keygen-生成ssh密钥对"><a href="#ssh-keygen-生成ssh密钥对" class="headerlink" title="ssh-keygen 生成ssh密钥对"></a>ssh-keygen 生成ssh密钥对</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">ssh-keygen -t rsa -b 4096 -C "your_email@example.com"</span><br></pre></td></tr></table></figure><h4 id="删除-git-配置"><a href="#删除-git-配置" class="headerlink" title="删除 git 配置"></a>删除 git 配置</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git config --unset user.name</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<blockquote>
<p>linux 的命令非常的多,有一些有效但是不常用的命令,可能需要临时进行翻阅,记录部分有效命令以备查阅使用</p>
</blockquote>
</summary>
<category term="收集" scheme="https://github.com/zzycreate/categories/%E6%94%B6%E9%9B%86/"/>
<category term="Linux" scheme="https://github.com/zzycreate/tags/Linux/"/>
<category term="个人收集" scheme="https://github.com/zzycreate/tags/%E4%B8%AA%E4%BA%BA%E6%94%B6%E9%9B%86/"/>
</entry>
<entry>
<title>Hexo博客添加评论系统</title>
<link href="https://github.com/zzycreate/2018/10/03/Hexo%E5%8D%9A%E5%AE%A2%E6%B7%BB%E5%8A%A0%E8%AF%84%E8%AE%BA%E7%B3%BB%E7%BB%9F/"/>
<id>https://github.com/zzycreate/2018/10/03/Hexo博客添加评论系统/</id>
<published>2018-10-03T12:24:25.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>很多人写博客的目的是给自己做记录的,例如我,但是一个使用难免会有些寂寞,有时候会想要让跟多人看见自己的成果,这时候就需要可以互动评论的系统。<br>现在的博客评论插件系统很多,尝试了一番,最终选择使用 gitalk 评论系统。</p></blockquote><a id="more"></a><h2 id="评论系统选型"><a href="#评论系统选型" class="headerlink" title="评论系统选型"></a>评论系统选型</h2><p>在之前的 <a href="https://zzycreate.github.io/2018/10/02/Hexo%E5%8D%9A%E5%AE%A2%E6%8A%98%E8%85%BE%E8%AE%B0/" target="_blank" rel="noopener">Hexo博客折腾记</a> 中,选择了一系列可以方便免费开源部署的程序部署了博客,这次也不例外,需要选择免费开源容易部署的评论系统。</p><p>我部署的 Hexo 版本为 <code>3.7.0</code>, indigo 主题版本为 <code>1.7.2</code> .<br>这版本的 indigo 主题默认就集成有多种评论系统。这些系统有:</p><ol><li><code>disqus</code> : <a href="https://disqus.com/" target="_blank" rel="noopener">disqus.com/</a> ———— 界面好看,支持 Facebook、twitter、Google+ 等账号登陆,但是 需要科学上网。</li><li><code>友言</code> : <a href="http://www.uyan.cc/" target="_blank" rel="noopener">www.uyan.cc/</a> ———— 系统已经挂了 <img class="github-emoji" title="sweat" alt="sweat" src="https://github.githubassets.com/images/icons/emoji/unicode/1f613.png?v8" height="20" width="20"></li><li><code>gitment</code> : <a href="https://github.com/imsun/gitment">gitment</a> ———— 基于 github issue 系统的评论系统, 已经很长时间没有维护了</li><li><code>valine</code> : <a href="https://valine.js.org/" target="_blank" rel="noopener">valine</a> ———— 基于 <a href="https://leancloud.cn/" target="_blank" rel="noopener">Leancloud</a> 的快速、简洁且高效的无后端评论系统</li><li><code>Hyper Comments</code> : <a href="https://www.hypercomments.com/" target="_blank" rel="noopener">HyperComments</a> ———— 已于2018.06.15起不再提供免费服务</li></ol><p>由以上已经支持的集中评论系统来看,很多已经不能使用了。<br>网上看了一下大多数的博客评论系统,以前使用 <a href="https://github.com/duoshuo">多说</a>、网易云更贴 等广受好评的评论系统也都宣布停止服务。</p><p>现在做的还可以的评论系统:</p><ol><li><code>畅言</code> : <a href="https://changyan.kuaizhan.com/" target="_blank" rel="noopener">畅言</a> ———— 搜狐出品,专业的社会化评论系统,需要备案,参考:<a href="https://www.zhihu.com/question/21367928" target="_blank" rel="noopener">知乎 - 搜狐做畅言评论系统的目的是什么?</a></li><li><code>valine</code> : <a href="https://valine.js.org/" target="_blank" rel="noopener">valine</a> ———— valine 支持匿名评论</li><li><code>来必力</code> : <a href="http://www.laibili.com.cn/" target="_blank" rel="noopener"></a> ———— 来必力是一款以社交网站评论为基础, 帮助用户之间实现自由沟通的内容平台。无需注册, 支持各种社交账号。</li><li><code>gitalk</code> : <a href="https://github.com/gitalk/gitalk">gitalk</a> ———— Gitalk 是一个基于 GitHub Issue 和 Preact 开发的评论插件。</li></ol><p>由于看到众多评论系统相继关闭和停止服务,我觉得评论系统需要有稳定的服务才能够持续为博客提供支持,最终我选择了基于 <code>Github issues</code> 的 gitalk 。毕竟一旦 github 都不能用了的话,当前基于 <code>Github Pages</code> 的博客也会无法使用 <img class="github-emoji" title="joy" alt="joy" src="https://github.githubassets.com/images/icons/emoji/unicode/1f602.png?v8" height="20" width="20"> 。</p><h2 id="Gitalk-的使用"><a href="#Gitalk-的使用" class="headerlink" title="Gitalk 的使用"></a>Gitalk 的使用</h2><h3 id="gitalk-的准备工作"><a href="#gitalk-的准备工作" class="headerlink" title="gitalk 的准备工作"></a>gitalk 的准备工作</h3><h4 id="阅读说明"><a href="#阅读说明" class="headerlink" title="阅读说明"></a>阅读说明</h4><p>gitalk 官方中文说明 : <a href="https://github.com/gitalk/gitalk/blob/master/readme-cn.md">https://github.com/gitalk/gitalk/blob/master/readme-cn.md</a> </p><h4 id="GitHub-Application"><a href="#GitHub-Application" class="headerlink" title="GitHub Application"></a>GitHub Application</h4><p><code>GitHub Application</code> 是 github 提供的应用 Oauth2 授权功能。可以用于外部应用使用 github 提供的账号授权系统。因为 gitalk 的评论使用的是 github issues ,评论必须使用 github 账号,所以用户如果需要使用 gitalk 进行评论,就必须使用自己的 github 账号给这个应用授权。</p><p>GitHub Application 的申请地址: <a href="https://github.com/settings/applications/new">Register a new OAuth application</a><br>GitHub Application 的说明文档: <a href="https://link.zhihu.com/?target=https%3A//developer.github.com/v3/oauth/" target="_blank" rel="noopener">Authorizing OAuth Apps</a><br>页面中 <code>Application name</code> 为你的应用名,在用户授权页面展示用。<br>页面中 <code>Homepage URL</code> 为主页URL。<br>页面中 <code>Application description</code> 为应用描述。<br>页面中 <code>Authorization callback URL</code> 为授权回调地址,这个最为关键,需要填写用户授权完成后回调的地址,一般来说就是你的博客地址 xxx.github.io </p><p>申请应用之后,就能获得应用的 <code>clientID</code> 和 <code>clientSecret</code> ,这两个东西需要配置到 gitalk 中,而且只会出现一次,请当时就记录下来。</p><h3 id="indigo-主题集成-gitalk"><a href="#indigo-主题集成-gitalk" class="headerlink" title="indigo 主题集成 gitalk"></a>indigo 主题集成 gitalk</h3><h4 id="gitalk-ejs"><a href="#gitalk-ejs" class="headerlink" title="gitalk.ejs"></a>gitalk.ejs</h4><p>仿照 gitment 进行改造,在 <code>themes/indigo/layout/_partial/plugins</code> 目录下可以看见 <code>gitment.ejs</code> 文件。<br>这个 ejs 文件是引入 gitment 用的。</p><p>类似的在 <code>themes/indigo/layout/_partial/plugins</code> 目录下创建一个名为 <code>gitalk.ejs</code> 的文件。<br>文件类容如下</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"><% if (theme.gitalk.enable){ %></span><br><span class="line"><section class="comments" id="comments"></span><br><span class="line"> <div id="gitalk-container"></div></span><br><span class="line"> <link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css"></span><br><span class="line"> <script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script></span><br><span class="line"> <script></span><br><span class="line"> var gitalk = new Gitalk({</span><br><span class="line"> clientID: '<%- theme.gitalk.client_id %>',</span><br><span class="line"> clientSecret: '<%- theme.gitalk.client_secret %>',</span><br><span class="line"> repo: '<%- theme.gitalk.repo %>',</span><br><span class="line"> owner: '<%- theme.gitalk.owner %>',</span><br><span class="line"> admin: '<%- theme.gitalk.admin %>',</span><br><span class="line"> id: location.pathname, // Ensure uniqueness and length less than 50</span><br><span class="line"> perPage: 50,</span><br><span class="line"> distractionFreeMode: '<%= theme.gitalk.distractionFreeMode %>'</span><br><span class="line"> })</span><br><span class="line"></span><br><span class="line"> gitalk.render('gitalk-container')</span><br><span class="line"> </script></span><br><span class="line"></section></span><br><span class="line"><% } %></span><br></pre></td></tr></table></figure><p>参见 gitalk 的引用说明: <a href="https://github.com/gitalk/gitalk/blob/master/readme-cn.md#%E5%AE%89%E8%A3%85">Gitalk 安装</a><br>引入 <code>gitalk.css</code> 样式文件、<code>gitalk.min.js</code> js 源码文件<code>、</code>script` 标签中书写 gitalk 的 js 应用代码。<br>代码里面的 clientID 和 clientSecret 是上文中申请的应用里面的 id 和密钥。<br>repo 是评论加载的仓库名,记住只是仓库名,不是 git 克隆的地址,可以直接使用 hexo 部署的 xxx.github.io 仓库,也可以另外新建一个仓库。<br>owner 是评论仓库 repo 的持有者。<br>admin 是评论的管理员,可以填多个(数组),管理员是 GitHub repository 的所有者和合作者 (对这个 repository 有写权限的用户),可以初始化文章评论。<br>id 是页面的唯一标识,一般来说一个文章的地址是唯一的,所以默认是 location.pathname 。不过 github issues 某次改版之后,这个值限制在50个字符内。<br>其他非必填字段,参考:<a href="https://github.com/gitalk/gitalk/blob/master/readme-cn.md#%E8%AE%BE%E7%BD%AE">gitalk 设置</a></p><h4 id="comment-ejs"><a href="#comment-ejs" class="headerlink" title="comment.ejs"></a>comment.ejs</h4><p>上文定义了 gitalk 插件的内容。要将插件引入进来,还需要修改 <code>comment.ejs</code> ,将 gitalk 引入进来。</p><p>参考 <code>themes/indigo/_partial/post/comment.ejs</code> 中其他部分,在其中添加一行代码:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"><%- partial('../plugins/gitalk') %></span><br></pre></td></tr></table></figure><p>这样就会将 gitalk.ejs 的代码引入进页面。</p><h4 id="config-yml"><a href="#config-yml" class="headerlink" title="_config.yml"></a>_config.yml</h4><p>在 indigo 主题的配置文件 <code>themes/indigo/_config.yml</code> 中添加上文 js 需要引用到的变量</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"># gitalk detail: https://github.com/gitalk/gitalk</span><br><span class="line">gitalk:</span><br><span class="line"> enable: true</span><br><span class="line"> client_id: xxx </span><br><span class="line"> client_secret: xxxx</span><br><span class="line"> repo: repo name # 仓库名</span><br><span class="line"> owner: repo owner # 仓库作者</span><br><span class="line"> admin: admins # 管理员</span><br><span class="line"> distractionFreeMode: false</span><br></pre></td></tr></table></figure><h2 id="集成中的问题"><a href="#集成中的问题" class="headerlink" title="集成中的问题"></a>集成中的问题</h2><h3 id="gitalk-使用的-id-超限"><a href="#gitalk-使用的-id-超限" class="headerlink" title="gitalk 使用的 id 超限"></a>gitalk 使用的 id 超限</h3><p>gitalk 使用的是 github issues ,issues 在某次更新之后,labels 的长度限制在 50 以内,因此使用 location.pathname 很容易就超过 50 字的限制。</p><p>参考 <a href="https://github.com/gitalk/gitalk/issues/102">Gitalk Issues #102</a>:</p><p>使用 md5 进行路径的加密,这样就能保证 id 在 50 字以内,并且是唯一的。</p><ol><li>从 <a href="https://github.com/blueimp/JavaScript-MD5">blueimp/JavaScript-MD5</a> 中下载 <code>md5.min.js</code> .</li><li>将js放在 <code>themes/source/js</code> 目录下 </li><li><code>gitalk.ejs</code> 文件中引入 <code><script src="/js/md5.min.js"></script></code></li><li>id 的配置改为 <code>md5(location.pathname)</code></li></ol><p>最终的 gitalk.ejs 配置如下:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"><% if (theme.gitalk.enable){ %></span><br><span class="line"><section class="comments" id="comments"></span><br><span class="line"> <div id="gitalk-container"></div></span><br><span class="line"> <link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css"></span><br><span class="line"> <script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script></span><br><span class="line"> <script src="/js/md5.min.js"></script></span><br><span class="line"> <script></span><br><span class="line"> var gitalk = new Gitalk({</span><br><span class="line"> clientID: '<%- theme.gitalk.client_id %>',</span><br><span class="line"> clientSecret: '<%- theme.gitalk.client_secret %>',</span><br><span class="line"> repo: '<%- theme.gitalk.repo %>',</span><br><span class="line"> owner: '<%- theme.gitalk.owner %>',</span><br><span class="line"> admin: '<%- theme.gitalk.admin %>',</span><br><span class="line"> id: md5(location.pathname),</span><br><span class="line"> perPage: 50,</span><br><span class="line"> distractionFreeMode: '<%= theme.gitalk.distractionFreeMode %>'</span><br><span class="line"> })</span><br><span class="line"></span><br><span class="line"> gitalk.render('gitalk-container')</span><br><span class="line"> </script></span><br><span class="line"></section></span><br><span class="line"><% } %></span><br></pre></td></tr></table></figure><p>这样在 github issues 页面就可以看见一串 md5 的 label ,并且评论不会因为 50 字限制而出现问题</p><h3 id="id-使用-pathname-而不要使用-href"><a href="#id-使用-pathname-而不要使用-href" class="headerlink" title="id 使用 pathname 而不要使用 href"></a>id 使用 pathname 而不要使用 href</h3><p>根据 <a href="https://github.com/gitalk/gitalk/issues/102">Gitalk Issues #102</a> 反馈,有些人使用微信浏览器时,url中会带有微信部分特征 url ,这会导致计算 md5 时出现异常。<br>这是因为引入 gitalk 时使用的是 location.href ,因为 href 是整个 url,而 pathname 是 url 中请求映射的部分,不带域名或者 IP 端口部分的地址,这样会屏蔽掉微信等方式导致的 id 计算异常。</p><h2 id="结束"><a href="#结束" class="headerlink" title="结束"></a>结束</h2><p>希望 gitalk 可以让我少折腾一点评论系统。如果频繁的改动评论系统,会丢失多少重要的数据,这些数据都是很宝贵的。</p>]]></content>
<summary type="html">
<blockquote>
<p>很多人写博客的目的是给自己做记录的,例如我,但是一个使用难免会有些寂寞,有时候会想要让跟多人看见自己的成果,这时候就需要可以互动评论的系统。<br>现在的博客评论插件系统很多,尝试了一番,最终选择使用 gitalk 评论系统。</p>
</blockquote>
</summary>
<category term="教程" scheme="https://github.com/zzycreate/categories/%E6%95%99%E7%A8%8B/"/>
<category term="Hexo" scheme="https://github.com/zzycreate/tags/Hexo/"/>
<category term="博客" scheme="https://github.com/zzycreate/tags/%E5%8D%9A%E5%AE%A2/"/>
<category term="教程" scheme="https://github.com/zzycreate/tags/%E6%95%99%E7%A8%8B/"/>
<category term="评论" scheme="https://github.com/zzycreate/tags/%E8%AF%84%E8%AE%BA/"/>
<category term="gitalk" scheme="https://github.com/zzycreate/tags/gitalk/"/>
</entry>
<entry>
<title>Hexo博客折腾记</title>
<link href="https://github.com/zzycreate/2018/10/02/Hexo%E5%8D%9A%E5%AE%A2%E6%8A%98%E8%85%BE%E8%AE%B0/"/>
<id>https://github.com/zzycreate/2018/10/02/Hexo博客折腾记/</id>
<published>2018-10-02T17:38:31.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>最近突然看到同事的<a href="https://mazhuang.org" target="_blank" rel="noopener">博客</a>,感慨于大佬多年来的各种记录。突然发现自己平时虽然会网上看很多东西,但都没什么整理。以前有段时间想着记录下平时的问题,还放在github上,建了个仓库,但过了一阵子又忘记了,而且用github仓库记录也不方便观看,因此又激起了折腾博客的想法,遂有了当前的这个博客。因为不知道会坚持多久,所以用了网上现在流行的 Hexo 和免费的 GitHub Pages 来搭建一个静态博客,仅以此文做配置博客的记录,希望也可以帮助到一些人。<br>接下来就是喜闻乐见的博客教学环节。</p></blockquote><a id="more"></a><h2 id="博客选型"><a href="#博客选型" class="headerlink" title="博客选型"></a>博客选型</h2><p>因为不确定对博客会有多大的热度,优先选择可以免费部署、方便拓展、技术栈熟悉的博客类型,再者依托被微软收购的 GitHub 这一大平台应该一段时间内不用担心会关闭的危险。</p><p>常见的博客框架有 <a href="https://zh-cn.wordpress.com/" target="_blank" rel="noopener">WordPress</a>(基于php)、<a href="https://github.com/jekyll/jekyll">jekyll/jekyll</a>(基于Ruby)、<a href="https://github.com/hexojs/hexo">hexojs/hexo</a>(基于Node.js)、<a href="https://github.com/getpelican/pelican">getpelican/pelican</a>(基于Python)、<a href="https://github.com/gohugoio/hugo">gohugoio/hugo</a>(基于Golang),可以看出各种动态语言在这方面都有现成的博客生成器,想了解更多博客类型:<a href="https://staticsitegenerators.net/" target="_blank" rel="noopener">Static Site Generators</a></p><p>由于对其他语言不熟,对js还算是了解一点,最终选择 Hexo 。</p><p>其实使用哪个博客对写作来说没有太大的影响,现在的博客框架基本将大多数的功能都已经完成得差不多了,专注内容的同学其实使用默认配置就足够了,但是总会有很多强迫症程序员总会有些大胆的想法,要魔改出一个独一无二的博客,这大概就需要花费很多精力了。</p><h2 id="安装准备"><a href="#安装准备" class="headerlink" title="安装准备"></a>安装准备</h2><p>Hexo 官方的文档有中文,很值得阅读一遍,内容也不算很多,照着文档过一遍就能安装部署完成。</p><p>Hexo官方网站:<a href="https://hexo.io/zh-cn/" target="_blank" rel="noopener">hexo.io</a></p><h3 id="Node-js-的安装"><a href="#Node-js-的安装" class="headerlink" title="Node.js 的安装"></a>Node.js 的安装</h3><p>由于 Hexo 是基于 Node.js 的静态博客生成框架,首先你的电脑需要安装 Node.js 的程序。</p><p>安装地址: <a href="https://nodejs.org/en/" target="_blank" rel="noopener">nodejs.org</a> , 选择LTS版本即可。或者根据 <a href="https://hexo.io/zh-cn/docs/#%E5%AE%89%E8%A3%85-Node-js" target="_blank" rel="noopener">Hexo 官方提示</a> 使用 <a href="https://github.com/creationix/nvm">nvm</a> 进行 node 的安装。</p><p>安装完成之后在命令行中使用命令 <code>node -v</code> 即可看见 node 版本号,证明你的 nodejs 安装得没有问题。<br>使用 <code>npm -v</code> 即可看见 npm 的版本号,npm 是 node 的包管理程序,在 npm 的仓库中托管着众多 node 开源项目。</p><h3 id="Git-的安装"><a href="#Git-的安装" class="headerlink" title="Git 的安装"></a>Git 的安装</h3><p>Git 是一个分布式版本控制软件,GitHub 是基于 Git 进行版本控制的软件源码托管服务平台,GitHub 中有着众多的开源软件,在你博客的安装和改造过程中肯定能给你很多帮助。</p><h3 id="hexo-cli命令"><a href="#hexo-cli命令" class="headerlink" title="hexo-cli命令"></a>hexo-cli命令</h3><p>hexo 的操作都是需要命令行来操作的,需要通过 node 和 npm 安装一个全局的 hexo 命令工具: hexo-cli 。</p><p>执行命令:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">npm install -g hexo-cli</span><br></pre></td></tr></table></figure><p>如果执行过程中报错了,很可能是 npm 的下载源比较慢的缘故,参考文章 <a href="https://zzycreate.github.io/2017/01/19/npm%E4%B8%8B%E8%BD%BD%E6%85%A2%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95/" target="_blank" rel="noopener">npm下载慢的解决方法</a> 进行配置,再执行以上命令。<br>如果还有其他问题,根据命令行的错误baidu或者google一下,一般都能找到解决方法。</p><p>安装完 hexo-cli 之后,可以使用 <code>hexo -v</code> 命令进行版本检查,使用 <code>hexo v</code> 可以获得更多相关的版本信息。</p><h2 id="Hexo-的使用"><a href="#Hexo-的使用" class="headerlink" title="Hexo 的使用"></a>Hexo 的使用</h2><p>hexo-cli 命令行安装好了之后就可以进行 hexo 的使用。</p><h3 id="博客源码的创建"><a href="#博客源码的创建" class="headerlink" title="博客源码的创建"></a>博客源码的创建</h3><p>在想放置博客源文件的目录下,使用命令行执行命令:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">hexo init <folder></span><br><span class="line">cd <folder></span><br><span class="line">npm install</span><br></pre></td></tr></table></figure><p><code>hexo init</code> 命令会在当前目录创建一个名称为 <code><folder></code> 的文件夹, <code>cd</code> 使命令行进入这个文件夹,执行 <code>npm install</code> 安装 hexo 的本地依赖。</p><p>执行完成之后,指定文件夹下会出现如下的目录结构:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">├── /.deploy_git # 博客发布的文件目录</span><br><span class="line">├── /node_modules # node.js 的包管理目录</span><br><span class="line">├── /public # 博客编译后的文件目录</span><br><span class="line">├── /scaffolds # 默认模板目录</span><br><span class="line">├── /source # 文章资源目录</span><br><span class="line">| ├── /_drafts # 草稿文章目录</span><br><span class="line">| └── /_posts # 发布文章目录</span><br><span class="line">├── /themes # 主题文件夹</span><br><span class="line">| └── /landscape # 默认主题 landscape </span><br><span class="line">├── _config.yml # 项目配置文件</span><br><span class="line">└── package.json # node.js 项目配置文件</span><br></pre></td></tr></table></figure><ol><li><code>scaffolds</code> 目录是模板目录,使用 hexo 命令行创建的页面会根据参数的不同,使用这里面的模板生成页面文件</li><li><code>source</code> 目录里面是存储博客的文章的,主要是 <code>.md</code> 后缀的 markdown 文件</li><li><code>themes</code> 目录里面是放置 hexo 主题的源码的,主题使得 hexo 的生态更加丰富多样</li><li><code>_config.yml</code> 是 hexo 的项目配置文件,主要是站点的基本信息和配置,hexo 的配置详细请参见: <a href="https://hexo.io/zh-cn/docs/configuration" target="_blank" rel="noopener">Hexo 配置</a></li></ol><p>以上四个目录或者文件是 hexo 的主要内容部分。</p><h3 id="Hexo-的命令"><a href="#Hexo-的命令" class="headerlink" title="Hexo 的命令"></a>Hexo 的命令</h3><p>Hexo 的使用都是用命令行的方式,常用的基本就几个命令。详细的命令参见: <a href="https://hexo.io/zh-cn/docs/commands" target="_blank" rel="noopener">Hexo 指令</a></p><h4 id="init"><a href="#init" class="headerlink" title="init"></a>init</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">hexo init [folder]</span><br></pre></td></tr></table></figure><p><code>init</code> 用于新建网站内容,一般就只有初始化的时候使用一次</p><h4 id="new"><a href="#new" class="headerlink" title="new"></a>new</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">hexo new [layout] <title></span><br></pre></td></tr></table></figure><p><code>new</code> 用于新建一篇文章,可以不填 layout ,默认为 post ,可以在 <code>_config.yml</code> 中进行配置。如果标题包含空格的话,请使用引号括起来。</p><p>新建了一片文章之后,会在对应的 <code>_drafts</code>、<code>_post</code>、<code>{pageName}</code>等目录下创建对应的 markdown 文件。这些 markdown 文件就是站点的主要内容。</p><h4 id="generate"><a href="#generate" class="headerlink" title="generate"></a>generate</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">hexo generate</span><br><span class="line">或者 hexo g</span><br></pre></td></tr></table></figure><p><code>generate</code> 命令用于将站点源文件生成可以发布的文件,源文件在 <code>source</code> 文件夹中,发布文件在 <code>public</code> 文件夹中。生成的文件是根据 theme 主题和源文件生成的。</p><p>使用 <code>-d</code> 参数在文件生成后直接部署,使用 <code>-w</code> 参数监控文件变动进行发布文件生成。</p><h4 id="clean"><a href="#clean" class="headerlink" title="clean"></a>clean</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">hexo clean</span><br></pre></td></tr></table></figure><p><code>clean</code> 命令用于清除生成的站点文件,和 <code>generator</code> 刚好相反,执行完 <code>clean</code> 之后 public 文件夹会被清楚</p><h4 id="server"><a href="#server" class="headerlink" title="server"></a>server</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">hexo server</span><br></pre></td></tr></table></figure><p><code>server</code> 命令在本地生成启动一个服务,用于预览生成的站点,默认访问地址为 <code>http://localhost:4000/</code></p><h4 id="deploy"><a href="#deploy" class="headerlink" title="deploy"></a>deploy</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">hexo deploy</span><br></pre></td></tr></table></figure><p><code>deploy</code> 命令用于发布站点到指定的地址,发布配置在 <code>_config.yml</code> 中可以进行配置,也可以同时发布到多个地址。</p><h4 id="其他命令"><a href="#其他命令" class="headerlink" title="其他命令"></a>其他命令</h4><p>上述几个命令是最常使用的几个命令,其他命令参考官方教程:<a href="https://hexo.io/zh-cn/docs/commands" target="_blank" rel="noopener">Hexo 指令</a></p><h2 id="Hexo-主题折腾"><a href="#Hexo-主题折腾" class="headerlink" title="Hexo 主题折腾"></a>Hexo 主题折腾</h2><p>Hexo 之所以被很多人使用,一个原因是这个框架很简洁,需要掌握的东西不多,上述几个命令基本就足够使用;另一方面是 Hexo 有足够多的成熟主题和插件供大家使用。</p><p>Hexo 官方主题页:<a href="https://hexo.io/themes/" target="_blank" rel="noopener">Hexo Themes</a><br>Hexo 官方插件页:<a href="https://hexo.io/plugins/" target="_blank" rel="noopener">Hexo Plugins</a></p><p>官方提供的插件足够多,markdown、图片懒加载、表情、图标等等各种各样的功能都有,自己也可以编写插件进行功能的补全,插件具体的我就没有怎么研究过,这部分暂不讲解。</p><p>主题方面,我尝试了一些,GitHub 按照 star 排名来看,<a href="https://github.com/iissnan/hexo-theme-next">iissnan/hexo-theme-next</a> <a href="https://github.com/theme-next/hexo-theme-next">新版NexT</a>、<a href="https://github.com/litten/hexo-theme-yilia">litten/hexo-theme-yilia</a>、<a href="https://github.com/viosey/hexo-theme-material">viosey/hexo-theme-material</a>、<a href="https://github.com/yscoder/hexo-theme-indigo">yscoder/hexo-theme-indigo</a>等主题应该是使用人群最多的。</p><p>我才刚折腾几天,暂时选择的是 <code>hexo-theme-indigo</code>,以后可能也会尝试使用其他主题 <img class="github-emoji" title="smirk" alt="smirk" src="https://github.githubassets.com/images/icons/emoji/unicode/1f60f.png?v8" height="20" width="20">。</p><h3 id="安装-indigo-主题"><a href="#安装-indigo-主题" class="headerlink" title="安装 indigo 主题"></a>安装 indigo 主题</h3><p>根据 <a href="https://github.com/yscoder/hexo-theme-indigo/wiki">Hexo indigo 主题文档</a> 进行安装。</p><p>官方推荐是使用 <code>git clone git@github.com:yscoder/hexo-theme-indigo.git themes/indigo</code> 直接将主题项目 clone 到 <code>themes/indigo</code> 目录下,这样可以根据indigo的修改进行更新。</p><p>我是直接 <code>Download ZIP</code> 包,然后将 zip 包解压到themes目录下,这样就没有 git 的信息,我就可以直接将这个目录下的内容也和我整个项目一起提交到 git 远程仓库中。</p><p>下载完了之后,在 <code>_config.yml</code> 中进行修改,将 <code>themes</code> 的值设置为 <code>indigo</code> 即可。</p><h3 id="indigo-的配置"><a href="#indigo-的配置" class="headerlink" title="indigo 的配置"></a>indigo 的配置</h3><p>indigo 的目录结构如下:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">indigo</span><br><span class="line">├── /languages # 国际化目录</span><br><span class="line">├── /layout # 布局 ejs 文件</span><br><span class="line">| └── /_partial # 布局组件 ejs 文件</span><br><span class="line">| ├── /plugin # 布局插件组件 ejs 文件</span><br><span class="line">| └── /post # 布局页面组件 ejs 文件</span><br><span class="line">├── /scriptes # 脚本</span><br><span class="line">├── /source # 文章资源目录</span><br><span class="line">| ├── /css # css资源</span><br><span class="line">| ├── /img # 图片资源</span><br><span class="line">| └── /js # js资源</span><br><span class="line">└── _config.yml # indigo 主题配置文件</span><br></pre></td></tr></table></figure><p>如果需要修改布局中的一些东西,则去 <code>layout</code> 中找到相应的组件,例如右侧的目录 toc 的组件在 <code>layout/_partial/post/toc.ejs</code> 文件中。<br>如果需要修改主题的静态资源,则去 <code>source</code> 中找到相应的资源文件,进行修改,例如: 微信二维码是 <code>source/img/wechat.jpg</code> 文件。</p><p>一些主题的数据是提供了参数进行修改的,详细参数设置:<a href="https://github.com/yscoder/hexo-theme-indigo/wiki/%E9%85%8D%E7%BD%AE">indigo 参数配置</a></p><h2 id="结束"><a href="#结束" class="headerlink" title="结束"></a>结束</h2><p>博客主题的折腾永无止境,主题也仅仅是给世人看的一副好看的匹狼,内容才是博客的灵魂,你想要记录什么样的内容给他人看到才是最重要的。</p>]]></content>
<summary type="html">
<blockquote>
<p>最近突然看到同事的<a href="https://mazhuang.org" target="_blank" rel="noopener">博客</a>,感慨于大佬多年来的各种记录。突然发现自己平时虽然会网上看很多东西,但都没什么整理。以前有段时间想着记录下平时的问题,还放在github上,建了个仓库,但过了一阵子又忘记了,而且用github仓库记录也不方便观看,因此又激起了折腾博客的想法,遂有了当前的这个博客。因为不知道会坚持多久,所以用了网上现在流行的 Hexo 和免费的 GitHub Pages 来搭建一个静态博客,仅以此文做配置博客的记录,希望也可以帮助到一些人。<br>接下来就是喜闻乐见的博客教学环节。</p>
</blockquote>
</summary>
<category term="教程" scheme="https://github.com/zzycreate/categories/%E6%95%99%E7%A8%8B/"/>
<category term="Hexo" scheme="https://github.com/zzycreate/tags/Hexo/"/>
<category term="博客" scheme="https://github.com/zzycreate/tags/%E5%8D%9A%E5%AE%A2/"/>
<category term="GitHub Pages" scheme="https://github.com/zzycreate/tags/GitHub-Pages/"/>
<category term="教程" scheme="https://github.com/zzycreate/tags/%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>注解@Autowired和@Resource的区别</title>
<link href="https://github.com/zzycreate/2018/09/28/%E6%B3%A8%E8%A7%A3-Autowired%E5%92%8C-Resource%E7%9A%84%E5%8C%BA%E5%88%AB/"/>
<id>https://github.com/zzycreate/2018/09/28/注解-Autowired和-Resource的区别/</id>
<published>2018-09-28T23:52:40.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>在spring项目中,对bean进行注入通常会看见使用@Autowired和@Resource两种注解的注入方式,虽然两者的功能是一致的,但是在使用上有一些区别。</p></blockquote><a id="more"></a><h2 id="注解-Resource"><a href="#注解-Resource" class="headerlink" title="注解 @Resource"></a>注解 @Resource</h2><p>注解 <code>@Resource</code> 是jdk1.6版本开始提供的注解,默认是使用byName的方式搜索bean,名称可以通过name属性进行指定。 </p><p>注解 <code>@Resource</code> 注意事项:</p><ol><li>如果注解指定了name,则根据name的值搜索bean进行装配。</li><li>如果没有指定name属性,当注解写在字段上时,默认取字段名,并按照名称查找,如果注解写在setter方法上默认取属性名进行装配。</li><li>当找不到与名称匹配的bean时才按照类型进行装配。</li><li><strong>注意</strong>:name属性一旦指定,就只会按照名称进行装配。</li></ol><h2 id="注解-Autowired"><a href="#注解-Autowired" class="headerlink" title="注解 @Autowired"></a>注解 @Autowired</h2><p>注解@Autowired是spring2.5版本开始提供的注解,默认是使用byType的方式(根据Bean的class类型)搜索bean。</p><p>注解 <code>@Autowired</code> 注意事项:</p><ol><li>默认是使用 byType 的方式(根据 Bean 的 class 类型)搜索bean, 如果查询结果刚好为一个,就将该 bean 装配给 @Autowired 指定的数据</li><li>如果搜索到多个 bean ,再使用 byName 的方式(根据 bean 实例上申明的名称)搜索,需要配合 <code>@Qualifier</code> 注解使用,名称写在 <code>@Qualifier</code> 注解上</li><li>如果查询的结果为空,那么会抛出异常。</li><li><code>@Autowired</code> 默认情况下要求依赖对象必须存在,如果要允许 null 值,可以设置它的 required 属性为 false</li></ol><h3 id="spring-注入-Autowired-的时机问题"><a href="#spring-注入-Autowired-的时机问题" class="headerlink" title="spring 注入 @Autowired 的时机问题"></a>spring 注入 @Autowired 的时机问题</h3><ol><li>如果在成员属性或者 setter 方法上添加 <code>@Autowired</code> 注解注入,则该属性的值是在构造器之后才会注入,如果在构造器中就要使用这个属性,则会报空指针的异常</li><li>spring4 提供了在构造器上添加 <code>@Autowired</code> 注解的方法,spring 会向构造器中的入参注入 bean 实例,之后才会执行构造器内部的代码</li><li>spring 官方推荐 spring4 及以后版本使用构造器注入 bean , IDEA 也对此提供了 Warning 级别的提示,并可以快速根据提示将注入改造为构造器注入的方式</li><li>spring的单元测试类中一般不使用构造器 <code>@Autowired</code> 注入,因为单元测试需要有无参构造器;如果要使用有参构造器,则需要在类上添加 <code>@RunWith(Parameterized.class)</code> 注解,并且增加带 <code>@Parameters</code> 注解的方法,Parameters 方法的方法签名必须是 <code>public static Collection</code>,方法不能有参数,并且 collection 元素必须是相同长度的数组,因此 spring 单元测试类一般不使用构造器注入的方式</li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>如果是要使用spring的自动装配功能,一般情况下使用 <code>@Resource</code> 和 <code>@Autowired</code> 没有区别。<code>@Autowired</code> 提供的注入方式会更多一些,另外就是默认查找 bean 的方式有区别,但两者均会通过名称或者类型进行判定,因此也没有太大区别。<code>@Autowired</code> 在没有配置 <code>requred = false</code> 时,是强制检查是否有注入对象,会对程序运行起到有效的检查作用。</p>]]></content>
<summary type="html">
<blockquote>
<p>在spring项目中,对bean进行注入通常会看见使用@Autowired和@Resource两种注解的注入方式,虽然两者的功能是一致的,但是在使用上有一些区别。</p>
</blockquote>
</summary>
<category term="编码" scheme="https://github.com/zzycreate/categories/%E7%BC%96%E7%A0%81/"/>
<category term="java" scheme="https://github.com/zzycreate/tags/java/"/>
<category term="spring" scheme="https://github.com/zzycreate/tags/spring/"/>
</entry>
<entry>
<title>修改git已提交的commit作者和邮箱</title>
<link href="https://github.com/zzycreate/2018/09/27/%E4%BF%AE%E6%94%B9git%E5%B7%B2%E6%8F%90%E4%BA%A4%E7%9A%84commit%E4%BD%9C%E8%80%85%E5%92%8C%E9%82%AE%E7%AE%B1/"/>
<id>https://github.com/zzycreate/2018/09/27/修改git已提交的commit作者和邮箱/</id>
<published>2018-09-27T16:44:59.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>当需要在一台电脑上操作不同的git仓库时,很可能会出现不同仓库,需要不同的作者身份进行提交。<br>例如:在公司使用域账号进行内网gitlab仓库的修改,而在github上又想使用网络的名称与邮箱,如果不注意提交人的信息,很可能就会导致身份错乱,暴露了一些信息。<br><a id="more"></a><br>本文参考:<a href="http://i.dotidea.cn/2015/04/git-amend-author/" target="_blank" rel="noopener">git修改提交作者和邮箱</a></p></blockquote><h2 id="良好的git操作习惯"><a href="#良好的git操作习惯" class="headerlink" title="良好的git操作习惯"></a>良好的git操作习惯</h2><p>如果有需要切换身份的要求,则必然需要养成切换代码库或克隆仓库时检查用户信息的习惯。</p><p>主动配置git的 <code>user.name</code> 和 <code>user.email</code>:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">// 设置全局</span><br><span class="line">git config --global user.name "Author Name"</span><br><span class="line">git config --global user.email "Author Email"</span><br><span class="line"> </span><br><span class="line">// 或者设置本地项目库配置</span><br><span class="line">git config user.name "Author Name"</span><br><span class="line">git config user.email "Author Email"</span><br></pre></td></tr></table></figure><h2 id="修改历史代码用户信息"><a href="#修改历史代码用户信息" class="headerlink" title="修改历史代码用户信息"></a>修改历史代码用户信息</h2><p>有时候由于疏忽,还是会有代码已经提交才反应过来需要修改用户信息的情况。</p><h3 id="最近一次commit的修改"><a href="#最近一次commit的修改" class="headerlink" title="最近一次commit的修改"></a>最近一次commit的修改</h3><p>如果只需要最近一次提交,那么很简单直接使用 <code>git commit --amend</code> 就可以搞定</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">git commit --amend --author="NewAuthor <NewEmail@address.com>"</span><br></pre></td></tr></table></figure><h3 id="多个commit的修改"><a href="#多个commit的修改" class="headerlink" title="多个commit的修改"></a>多个commit的修改</h3><p>如果是多个修改,那么就需要使用到 <code>git filter-branch</code> 这个工具来做批量修改<br>为了方便使用,封装了一个简单的shell脚本,直接修改 <code>[XXX]</code> 中的变量为对应的值即可 </p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">#!/bin/sh</span><br><span class="line"> </span><br><span class="line">git filter-branch --env-filter '</span><br><span class="line"> </span><br><span class="line">an="$GIT_AUTHOR_NAME"</span><br><span class="line">am="$GIT_AUTHOR_EMAIL"</span><br><span class="line">cn="$GIT_COMMITTER_NAME"</span><br><span class="line">cm="$GIT_COMMITTER_EMAIL"</span><br><span class="line"> </span><br><span class="line">if [ "$GIT_COMMITTER_EMAIL" = "[Your Old Email]" ]</span><br><span class="line">then</span><br><span class="line"> cn="[Your New Author Name]"</span><br><span class="line"> cm="[Your New Email]"</span><br><span class="line">fi</span><br><span class="line">if [ "$GIT_AUTHOR_EMAIL" = "[Your Old Email]" ]</span><br><span class="line">then</span><br><span class="line"> an="[Your New Author Name]"</span><br><span class="line"> am="[Your New Email]"</span><br><span class="line">fi</span><br><span class="line"> </span><br><span class="line">export GIT_AUTHOR_NAME="$an"</span><br><span class="line">export GIT_AUTHOR_EMAIL="$am"</span><br><span class="line">export GIT_COMMITTER_NAME="$cn"</span><br><span class="line">export GIT_COMMITTER_EMAIL="$cm"</span><br><span class="line">'</span><br></pre></td></tr></table></figure><h2 id="注意"><a href="#注意" class="headerlink" title="注意"></a><strong>注意</strong></h2><p>修改的commit会导致git树与原来不同,如果之前的commit已经提交,则只能强制推送覆盖远端;如果有其他人已经拉取过之前的旧commit,则在你强制推送之后,别人再进行拉取会产生大量冲突的代码,因此修改需要谨慎。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ol><li><a href="http://i.dotidea.cn/2015/04/git-amend-author/" target="_blank" rel="noopener">git修改提交作者和邮箱</a></li></ol>]]></content>
<summary type="html">
<blockquote>
<p>当需要在一台电脑上操作不同的git仓库时,很可能会出现不同仓库,需要不同的作者身份进行提交。<br>例如:在公司使用域账号进行内网gitlab仓库的修改,而在github上又想使用网络的名称与邮箱,如果不注意提交人的信息,很可能就会导致身份错乱,暴露了一些信息。<br>
</summary>
<category term="工具" scheme="https://github.com/zzycreate/categories/%E5%B7%A5%E5%85%B7/"/>
<category term="tools" scheme="https://github.com/zzycreate/tags/tools/"/>
<category term="git" scheme="https://github.com/zzycreate/tags/git/"/>
</entry>
<entry>
<title>Hello World</title>
<link href="https://github.com/zzycreate/2018/09/26/hello-world/"/>
<id>https://github.com/zzycreate/2018/09/26/hello-world/</id>
<published>2018-09-26T16:44:59.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="noopener">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="noopener">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><a id="more"></a><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="noopener">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="noopener">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="noopener">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="noopener">Deployment</a></p><h3 id="如何在文章中使用图标"><a href="#如何在文章中使用图标" class="headerlink" title="如何在文章中使用图标"></a>如何在文章中使用图标</h3><p>先到 <a href="https://fontawesome.com/icons?from=io" target="_blank" rel="noopener">fontawesome</a> 找到你需要的图标名,比如:<code>book</code>,按以下格式使用:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"><i class="icon icon-book"></i></span><br></pre></td></tr></table></figure><p>图标样式前缀均为 <code>icon</code>,此外还有 5 个图标大小调节类和 1 个间距类。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"><!-- 1.3倍大小 --></span><br><span class="line"><i class="icon icon-book icon-lg"></i></span><br><span class="line"><!-- 2倍大小 --></span><br><span class="line"><i class="icon icon-book icon-2x"></i></span><br><span class="line"><!-- 3倍大小 --></span><br><span class="line"><i class="icon icon-book icon-3x"></i></span><br><span class="line"><!-- 4倍大小 --></span><br><span class="line"><i class="icon icon-book icon-4x"></i></span><br><span class="line"><!-- 5倍大小 --></span><br><span class="line"><i class="icon icon-book icon-5x"></i></span><br><span class="line"><!-- 5px右边距 --></span><br><span class="line"><i class="icon icon-book icon-pr"></i></span><br><span class="line"><!-- 5px左边距 --></span><br><span class="line"><i class="icon icon-book icon-pl"></i></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="noopener">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="noopener">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p>
</summary>
<category term="测试" scheme="https://github.com/zzycreate/categories/%E6%B5%8B%E8%AF%95/"/>
<category term="test" scheme="https://github.com/zzycreate/tags/test/"/>
</entry>
<entry>
<title>SpringBoot属性配置</title>
<link href="https://github.com/zzycreate/2017/08/16/SpringBoot%E5%B1%9E%E6%80%A7%E9%85%8D%E7%BD%AE/"/>
<id>https://github.com/zzycreate/2017/08/16/SpringBoot属性配置/</id>
<published>2017-08-16T00:00:26.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>Spring Boot 是约定大于配置的 Spring 版本,但是这并不是说 Spring Boot 就没有配置,Spring Boot可以使用多种方式进行配置的设置。以下介绍一番 SpringBoot 各种类型的属性配置。</p></blockquote><a id="more"></a><h2 id="SpringBoot-属性配置优先级"><a href="#SpringBoot-属性配置优先级" class="headerlink" title="SpringBoot 属性配置优先级"></a>SpringBoot 属性配置优先级</h2><ol><li>命令行参数</li><li>来自 <code>java:comp/env</code> 的JNDI属性</li><li>Java系统属性(System.getProperties())</li><li>操作系统环境变量</li><li><code>RandomValuePropertySource</code> 配置的 <code>random.*</code> 属性</li><li>jar 包外部的 <code>application-{profile}.properties</code> 或 <code>application.yml</code> (带 <code>spring.profile</code>)配置文件</li><li>jar 包内部的 <code>application-{profile}.properties</code> 或 <code>application.yml</code> (带 <code>spring.profile</code>)配置文件</li><li>jar 包外部的 <code>application.properties</code> 或 <code>application.yml</code> (不带 <code>spring.profile</code>)配置文件</li><li>jar 包内部的 <code>application.properties</code> 或 <code>application.yml</code> (不带 <code>spring.profile</code>)配置文件</li><li><code>@Configuration</code> 注解类上的 <code>@PropertySource</code></li><li>通过 <code>SpringApplication.setDefaultProperties</code> 指定的默认属性</li></ol><h2 id="SpringBoot-属性配置"><a href="#SpringBoot-属性配置" class="headerlink" title="SpringBoot 属性配置"></a>SpringBoot 属性配置</h2><h3 id="命令行参数设置"><a href="#命令行参数设置" class="headerlink" title="命令行参数设置"></a>命令行参数设置</h3><p>通过 <code>Java -jar app.jar --name="Spring" --server.port=9090</code> 方式来传递参数。</p><p>其中参数用 <code>--xxx=xxx</code> 的形式传递。常见的Spring Boot默认配置参见 <a href="http://docs.spring.io/spring-boot/docs/1.2.3.RELEASE/reference/html/common-application-properties.html" target="_blank" rel="noopener">http://docs.spring.io/spring-boot/docs/1.2.3.RELEASE/reference/html/common-application-properties.html</a>。</p><p>命令行参数写在 app.jar 后面。如果要禁用命令行配置,可以通过 <code>SpringApplication.setAddCommandLineProperties(false)</code> 让命令行设置无效。</p><h3 id="Java-系统属性"><a href="#Java-系统属性" class="headerlink" title="Java 系统属性"></a>Java 系统属性</h3><p>java -Dname=”isea533” -jar app.jar –name=”Spring!”</p><p>系统属性配置方法与命令行参数设置类似,可以配置的属性也是一样的,只是优先级方式不同。</p><h3 id="操作系统环境变量"><a href="#操作系统环境变量" class="headerlink" title="操作系统环境变量"></a>操作系统环境变量</h3><p>和配置 <code>JAVA_HOME</code> 是一样的,只是例如 <code>server.port</code> 这种参数,无法支持,可以使用 <code>SERVER_PORT</code> 来配置。</p><h3 id="RandomValuePropertySource"><a href="#RandomValuePropertySource" class="headerlink" title="RandomValuePropertySource"></a>RandomValuePropertySource</h3><p>系统中用到随机数的地方,可以使用这种方式。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">my.secret=${random.value}</span><br><span class="line">my.number=${random.int}</span><br><span class="line">my.bignumber=${random.long}</span><br><span class="line">my.number.less.than.ten=${random.int(10)}</span><br><span class="line">my.number.in.range=${random.int[1024,65536]}</span><br></pre></td></tr></table></figure><p><code>random.int*</code>支持 <code>value</code> 和 <code>,max</code> 参数,当提供max参数的时候,value就是最小值。</p><h3 id="应用配置文件-properties或-yml"><a href="#应用配置文件-properties或-yml" class="headerlink" title="应用配置文件 (.properties或.yml)"></a>应用配置文件 (.properties或.yml)</h3><p>.properties配置文件:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">name=Isea533</span><br><span class="line">server.port=8080</span><br></pre></td></tr></table></figure><p>.yml配置文件:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">name: Isea533</span><br><span class="line">server:</span><br><span class="line"> port: 8080</span><br></pre></td></tr></table></figure><p><strong>注意:</strong> 使用 <code>.yml</code> 时,属性值和冒号中间必须要有空格。</p><p>spring会从classpath下的 <code>/config</code> 目录或者classpath的根目录寻找 <code>application.properties</code> 或 <code>application.yml</code>。<code>/config</code> 优先于 <code>classpath根目录</code>。</p><h3 id="PropertySource"><a href="#PropertySource" class="headerlink" title="@PropertySource"></a>@PropertySource</h3><p><code>@PropertySource</code> 这个注解可以指定具体的属性配置文件,优先级比较低。</p><h3 id="SpringApplication-setDefaultProperties"><a href="#SpringApplication-setDefaultProperties" class="headerlink" title="SpringApplication.setDefaultProperties"></a>SpringApplication.setDefaultProperties</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">SpringApplication application = new SpringApplication(Application.class);</span><br><span class="line">Map<String, Object> defaultMap = new HashMap<String, Object>();</span><br><span class="line">defaultMap.put("name", "Isea-Blog");</span><br><span class="line">//还可以是Properties对象</span><br><span class="line">application.setDefaultProperties(defaultMap);</span><br><span class="line">application.run(args);</span><br></pre></td></tr></table></figure><p>使用 <code>SpringApplication.setDefaultProperties</code> 的方式,可以设置默认属性值。</p><h2 id="SpringBoot-属性的使用"><a href="#SpringBoot-属性的使用" class="headerlink" title="SpringBoot 属性的使用"></a>SpringBoot 属性的使用</h2><h3 id="属性使用的方式"><a href="#属性使用的方式" class="headerlink" title="属性使用的方式"></a>属性使用的方式</h3><h4 id="Value-“-xxx-”"><a href="#Value-“-xxx-”" class="headerlink" title="@Value(“${xxx}”)"></a>@Value(“${xxx}”)</h4><p>使用 <code>@Value</code> 注解可以直接将属性值注入进来</p><h4 id="ConfigurationProperties"><a href="#ConfigurationProperties" class="headerlink" title="@ConfigurationProperties"></a>@ConfigurationProperties</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">my.name=Isea533</span><br><span class="line">my.port=8080</span><br><span class="line">my.servers[0]=dev.bar.com</span><br><span class="line">my.servers[1]=foo.bar.com</span><br></pre></td></tr></table></figure><p>以上的参数,使用的时候可以</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">@ConfigurationProperties(prefix="my")</span><br><span class="line">public class Config {</span><br><span class="line"> private String name;</span><br><span class="line"> private Integer port;</span><br><span class="line"> private List<String> servers = new ArrayList<String>();</span><br><span class="line"></span><br><span class="line"> public String geName(){</span><br><span class="line"> return this.name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public Integer gePort(){</span><br><span class="line"> return this.port;</span><br><span class="line"> }</span><br><span class="line"> public List<String> getServers() {</span><br><span class="line"> return this.servers;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>@ConfigurationProperties</code> 会将 <code>prefix="my"</code>的属性注入进来。并且会自动转型到类的属性值上,对象属性需要先初始化。</p><p>Spring Boot还支持嵌套属性注入。</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">name=isea533</span><br><span class="line">jdbc.username=root</span><br><span class="line">jdbc.password=root</span><br></pre></td></tr></table></figure><p>对应的配置类:</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">@ConfigurationProperties</span><br><span class="line">public class Config {</span><br><span class="line"> private String name;</span><br><span class="line"> private Jdbc jdbc;</span><br><span class="line"> class Jdbc {</span><br><span class="line"> private String username;</span><br><span class="line"> private String password;</span><br><span class="line"> //getter...</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> public Integer gePort(){</span><br><span class="line"> return this.port;</span><br><span class="line"> }</span><br><span class="line"> public Jdbc getJdbc() {</span><br><span class="line"> return this.jdbc;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>jdbc开头的属性都会注入到Jdbc对象中。Spring Boot通过getter方法获得属性值。</p><h4 id="Bean上使用-ConfigurationProperties"><a href="#Bean上使用-ConfigurationProperties" class="headerlink" title="@Bean上使用@ConfigurationProperties"></a>@Bean上使用@ConfigurationProperties</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">@ConfigurationProperties(prefix = "foo")</span><br><span class="line">@Bean</span><br><span class="line">public FooComponent fooComponent() {</span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在属性上同时使用 @ConfigurationProperties 和 @Bean 注解,可以将foo开头的属性按照名字匹配注入到FooComponent中去。</p><h3 id="属性占位符"><a href="#属性占位符" class="headerlink" title="属性占位符"></a>属性占位符</h3><p>在配置文件中可以引用前面配置过的属性,只要优先级在配置文件之前的都可以使用。</p><p>通过 ${xxx.xxx:默认名称} 方式还可以设置默认值,当找不到引用的属性时,会使用默认的属性。</p><p>由于 <code>${}</code>的方式会被maven处理。如果pom继承的 <code>spring-boot-starter-parent</code>,Spring Boot会将 <code>maven-resources-plugins</code> 默认的 ${}方式改为 <code>@ @</code> 的方式</p><h4 id="通过属性占位符缩短命令参数"><a href="#通过属性占位符缩短命令参数" class="headerlink" title="通过属性占位符缩短命令参数"></a>通过属性占位符缩短命令参数</h4><p>web默认端口使用 –server.port=9090 那么在配置上可以写</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">server.port=${port:8080}</span><br></pre></td></tr></table></figure><p>在不提供 –port=9090 的时候,使用默认值 8080。</p><h3 id="属性名匹配规则"><a href="#属性名匹配规则" class="headerlink" title="属性名匹配规则"></a>属性名匹配规则</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">@Component</span><br><span class="line">@ConfigurationProperties(prefix="person")</span><br><span class="line">public class ConnectionSettings {</span><br><span class="line"></span><br><span class="line"> private String firstName;</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>以上配置对象可以使用的属性名如下:</p><ol><li><code>person.firstName</code>,标准的驼峰式命名</li><li><code>person.first-name</code>,虚线( - )分割方式,推荐在 <code>.properties</code> 和 <code>.yml</code> 配置文件中使用</li><li><code>PERSON_FIRST_NAME</code>,大写下划线形式,建议在系统环境变量中使用。</li></ol><h3 id="属性验证"><a href="#属性验证" class="headerlink" title="属性验证"></a>属性验证</h3><p>可以使用 <code>JSR-303</code> 注解进行验证</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">@Component</span><br><span class="line">@ConfigurationProperties(prefix="connection")</span><br><span class="line">public class ConnectionSettings {</span><br><span class="line"></span><br><span class="line"> @NotNull</span><br><span class="line"> private InetAddress remoteAddress;</span><br><span class="line"></span><br><span class="line"> // ... getters and setters</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<blockquote>
<p>Spring Boot 是约定大于配置的 Spring 版本,但是这并不是说 Spring Boot 就没有配置,Spring Boot可以使用多种方式进行配置的设置。以下介绍一番 SpringBoot 各种类型的属性配置。</p>
</blockquote>
</summary>
<category term="编码" scheme="https://github.com/zzycreate/categories/%E7%BC%96%E7%A0%81/"/>
<category term="java" scheme="https://github.com/zzycreate/tags/java/"/>
<category term="SpringBoot" scheme="https://github.com/zzycreate/tags/SpringBoot/"/>
<category term="spring" scheme="https://github.com/zzycreate/tags/spring/"/>
</entry>
<entry>
<title>linux下部署多个tomcat</title>
<link href="https://github.com/zzycreate/2017/06/18/linux%E4%B8%8B%E9%83%A8%E7%BD%B2%E5%A4%9A%E4%B8%AAtomcat/"/>
<id>https://github.com/zzycreate/2017/06/18/linux下部署多个tomcat/</id>
<published>2017-06-18T23:25:59.000Z</published>
<updated>2020-05-12T01:17:23.859Z</updated>
<content type="html"><![CDATA[<blockquote><p>部署javaweb程序最常见的就是使用tomcat,而tomcat默认使用8080端口,如果要部署多个tomcat,必然需要在配置上进行修改,本文记录linux下多tomcat部署的步骤,用于参考。</p></blockquote><a id="more"></a><h2 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h2><ol><li>Centos 6.5 </li><li>tomcat-7.0.79 </li></ol><h2 id="需要解决的问题"><a href="#需要解决的问题" class="headerlink" title="需要解决的问题"></a>需要解决的问题</h2><ol><li>不同的tomcat启动和关闭监听不同的端口 </li><li>不同的tomcat的启动文件startup.sh 中要指定各自的CATALINA_HOME和CATALINA_BASE这两个环境变量。 </li></ol><h2 id="解决步骤"><a href="#解决步骤" class="headerlink" title="解决步骤"></a>解决步骤</h2><ol><li>修改/etc目录下的profile文件,添加一组java环境变量,和两组CATALINA环境变量;修改后的profile文件示例如下: </li></ol><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">JAVA_HOME=/usr/java/jdk</span><br><span class="line">CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib:$JAVA_HOME/bin</span><br><span class="line">export JAVA_HOME CLASSPATH</span><br><span class="line">CATALINA_BASE=/home/app/tomcat1</span><br><span class="line">CATALINA_HOME=/home/app/tomcat1</span><br><span class="line">export CATALINA_BASE CATALINA_HOME</span><br><span class="line">CATALINA_2_BASE=/home/app/tomcat2</span><br><span class="line">CATALINA_2_HOME=/home/app/tomcat2</span><br><span class="line">export CATALINA_2_BASE CATALINA_2_HOME</span><br><span class="line">TOMCAT_HOME=/home/app/tomcat1</span><br><span class="line">export TOMCAT_HOME</span><br><span class="line">TOMCAT_2_HOME=/home/app/tomcat2</span><br><span class="line">export TOMCAT_2_HOME</span><br></pre></td></tr></table></figure><ol start="2"><li><p>修改完毕后,source /etc/profile。可能是因为修改了profile文件的缘故?</p></li><li><p>第一个安装在/home/app/tomcat1处的tomcat,保持解压后的原状不用修改。修改第二个安装在/home/app/tomcat2处的tomcat。需要修改两个地方:</p></li></ol><p>3.1. 修改server.xml配置和第一个不同的启动、关闭监听端口。修改后示例如下: </p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"><Server port="9085" shutdown="SHUTDOWN"> 端口:8085->9085</span><br><span class="line"><!-- Define a non-SSL HTTP/1.1 Connector on port 8080 --></span><br><span class="line"> <Connector port="9080" maxHttpHeaderSize="8192" maxThreads="150" </span><br><span class="line"> minSpareThreads="25" maxSpareThreads="75" </span><br><span class="line"> enableLookups="false" redirectPort="8443" acceptCount="100" </span><br><span class="line"> connectionTimeout="20000" disableUploadTimeout="true" />端口:8080->9080</span><br></pre></td></tr></table></figure><p>3.2. 修改bin下的startup.sh和shutdown.sh。修改后的示例如下:(同样的修改)</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">export JAVA_HOME=/usr/jdk</span><br><span class="line">export PATH=$PATH:$JAVA_HOME/bin</span><br><span class="line">export CLASSPATH=$JAVA_HOME/lib</span><br><span class="line">export CATALINA_HOME=$CATALINA_2_HOME `利用profile中第二组设置</span><br><span class="line">export CATALINA_BASE=$CATALINA_2_BASE `利用profile中第二组设置</span><br></pre></td></tr></table></figure><p>在tomcat7.0中可以不修改startup.sh和shutdown.sh,只修改catalina.sh即可</p><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">CATALINA_HOME=$CATALINA_6_HOME</span><br><span class="line">CATALINA_BASE=$CATALINA_6_BASE</span><br><span class="line">export CATALINA_HOME</span><br><span class="line">export CATALINA_BASE</span><br></pre></td></tr></table></figure><ol start="4"><li><p>分别进入两个tomcat的bin目录,启动tomcat–./startup.sh</p></li><li><p>然后访问<a href="http://localhost:8080" target="_blank" rel="noopener">http://localhost:8080</a> 和 <a href="http://localhost:9080" target="_blank" rel="noopener">http://localhost:9080</a> 都可以看到熟悉的tomcat欢迎界面。</p></li><li><p>如果想启动多个可以依此法类推……</p></li></ol><blockquote><p>参考材料: <a href="http://blog.csdn.net/loadrunn/article/details/6579639" target="_blank" rel="noopener">http://blog.csdn.net/loadrunn/article/details/6579639</a></p></blockquote>]]></content>
<summary type="html">
<blockquote>
<p>部署javaweb程序最常见的就是使用tomcat,而tomcat默认使用8080端口,如果要部署多个tomcat,必然需要在配置上进行修改,本文记录linux下多tomcat部署的步骤,用于参考。</p>
</blockquote>
</summary>
<category term="系统" scheme="https://github.com/zzycreate/categories/%E7%B3%BB%E7%BB%9F/"/>
<category term="Linux" scheme="https://github.com/zzycreate/tags/Linux/"/>
<category term="Tomcat" scheme="https://github.com/zzycreate/tags/Tomcat/"/>
</entry>
</feed>