-
Notifications
You must be signed in to change notification settings - Fork 0
/
local-search.xml
1188 lines (571 loc) · 504 KB
/
local-search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
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
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>在雨中说雨</title>
<link href="/2024/10/30/bitterrain/"/>
<url>/2024/10/30/bitterrain/</url>
<content type="html"><![CDATA[<div class="hbe hbe-container" id="hexo-blog-encrypt" data-wpm="密码错误,请联系站长" data-whm="OOPS, these decrypted content may changed, but you can still have a look."> <script id="hbeData" type="hbeData" data-hmacdigest="2c423542759cf7388500fc10a3ba1695e8abc6ff5a18a0e746a62ebf57106395">91abd1e8012c552ee0b98faceca842a1cec274bbfd50370bbcaf48461c8f9e4c2bade11134349f2137115f9d6042ec1eef1cfa880e595ca1fc0f2941dee4a837855856a77f0399cd30380579ce761f7045c7db7cf4b7773492aa3937210f88a099f610b6be00edbd72b73effdc90361e00109433b725798689684c044b2b22a644c2ec905fad861cf13e902569f543725308d59f4cc7c23aa7b32520440f09a54ea9820b3359a8ed0f87feadade365fb7eb7f16cd4fe7bf080144c756a75323cefcfbc104ffb71916eb22d9854306cd4c58fe19103f7f80cb0dd8d89cb50a0fecc916340e70db9040174a8e9c3f3ebd2340c07fd5a0871fbd8fa0a289fa07eaed2a7f89a0b82c67ec45b59d93a5ec67c630b6eea2ef5ea6a656172002278b22f6d1a9eaf3b2a674e459aad7b29d878360f4d093f7f69d62535c5526f082d1181c221baa93708f41390d08788090f71934a69ef8f05b01d94227ab660caf6a66d40a820ef461e05d8e81616f47d6dd62e63bf88b78c7436818d92f216aed14e0804f16c3018252db76df6a0c737c53f742d78c9f3a49db4f6a6a1aba1468aefc2bd7ac52218e18a5fab7fa698272a2b9de3df9bfa95fa7a03fad9d70def260ef45acf709048e33417e0d7d2f97bcf6098c9e75220bc1cfe7f62f4a2999e2d3092e6a787ba10e068093c636e623f2b5bb03c7be778179731547b55e8755f85f140d49050a9688840fa3c95013f4e4883a78caa3ad613fe5b539c3158de61b6780e884a9faca9ec6a441868f32e22e64598c53d6ff26207247a72a19cd57c45d41e0821c92944af182b0871b2d33cc03d2bcdb7217e113ee8105080b20f546d42c2562930873899d40d2968724ba8c4fc33c61292f2792bc24edbd36127c326d40161e854fa832506e5f7d407c3ab9ca544f8856a9a3ec9804ab258ae8ef3ea79733bc9fcead7eed5c403415029823e5634452f01f49f4a77f3f533b83348ab49209de0932848e0e9983842464ff75ad80fd84eafcf0f7d3c44cf4d26c798e1e8a733f5dc07f5b3666473a3c0c3eb1a98e6987d4495fdb3a5a390829cbaf56f65d36eeea5049d5dbdebb11681bca2027cdf0a55504453c396738bd01a6a95c8c64205dda9d3866b11646afc986626fd1f25372ad520ac1852803a0a9647fc504d9b44520d8b1170604bedbf524402ec859c97474784a6787c9d86dbf660a5d2b64b230e0dcf0e3523941d0f270711377a7c75375922e019f1dd700fc555bee51a388f12836e0d8f5bdf3e294b365729353b88ada1c52e4060bbbdef07bb9fb8fd98d3545ab2522dc3706b562270fcd3b991f41571e1a4d6e6ee5d536f0e13f1d8b39adc57b313314171a553b4a97a120f81f09712093a1ef1c804a6f0b6d764094d013375e1028a7143eb3626c6bce81924d29a1b00940775f9c48dc34ad5658822ab8e0f2031f0662b8e63a06e77ff2f0d48a903fcc86897d9b10a29d249e7c0d1d0b47eb8aa9a2f9e26c6ae90fcea87b967a21bf92a6f76922c2a155711f28c50fadfc7f86c9dc1564500f0df7effeaff2d8f61d88374dd0fb0239557487a573327580f222e5df31c35473cfe820e2776cbdd6ca7726f21c43f30d933c2f9aa871e94f821c6fc2830b4dd7922c66542482ef3d5267cab535aa58b56185bb7bd49bae24ab4cb3f19fd075d8c758f64f69c6c7d93652eb51ae76edf433c03c2dc312ebf710a3c23c48f72544b0645ae1ebb4c05b1a4cd29d950e43457736f1d18a7de2441ac25946f19122c9eccfa0cbf101bca83673720066ddac7e7da50b12697ea00bdce18c94ec79415383daeb4ba610e69ac14dd4d524e2d87875a9713b750ec0f3dd3847994ce8448ad02d1f878a0a34e9274cbc8f70c5392ceac3033005b17e3aeac3db57c31ec780c6f4fd5499785b1ce7c5a0804783a7a0ccf36ac19c55ca880fc19852939c5db99bea25c07e88f8c3a00f144858e504ead354f561a473993959bdf0854628dfec25791fcd47e58058f28a5075fe0332651f1c1e0e3466062d3664b0f94f46d1280a8d91b2d7cb87fec2af13f95b468e782a6858ab75e9ac6c3bd8d789845ae14bf885a88681a85c90c8e12985dfd82dd0171efd42c1ba245dcbf65fcace48beaf0010cde2a77488a635d63e90b31c401d86c476f1e58073bcf3206a24d5ae775415a9890cab7898a9898a893f18ae669964578e6d5f6d15bbce53fcdf42d3fb1f523f3e790b09fb471f128a18f2c452bf7e8f98f6b3d00fe31290a35d215478ae292d104a361481925c156037cb6a10c22fa056462a5159dcf5a085550569c34df85c1ff64536bd00138176ace3f4adc085c020fa11409de062198db1379c713ae782a55d671</script> <div class="hbe hbe-content"> <div class="hbe hbe-input hbe-input-default"> <input class="hbe hbe-input-field hbe-input-field-default" type="password" id="hbePass"> <label class="hbe hbe-input-label hbe-input-label-default" for="hbePass"> <span class="hbe hbe-input-label-content hbe-input-label-content-default">输入密码,查看文章</span> </label> </div> </div></div><script data-pjax src="/lib/hbe.js"></script><link href="/css/hbe.style.css" rel="stylesheet" type="text/css">]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>工作</tag>
<tag>生活随笔</tag>
</tags>
</entry>
<entry>
<title>面试中的问题</title>
<link href="/2024/10/29/interviewquestion/"/>
<url>/2024/10/29/interviewquestion/</url>
<content type="html"><![CDATA[<p>秋招马上就要结束,目前拿到了两个Offer,虽然都是大白菜,但好在是有了,先就业再择业。闲暇之余总结一些关于面试的问题,仅供参考。</p><h1 id="如何反问"><a href="#如何反问" class="headerlink" title="如何反问"></a>如何反问</h1><p>面试的反问环节取决于你想得到什么样的信息反馈。</p><h2 id="工作方面"><a href="#工作方面" class="headerlink" title="工作方面"></a>工作方面</h2><ul><li>您作为公司的一员,您觉得您所在的部门工作氛围如何?</li><li>公司的规模有多大?研发部门有多少人?主要负责哪一块的业务?</li></ul><h2 id="个人方面"><a href="#个人方面" class="headerlink" title="个人方面"></a>个人方面</h2><ul><li>公司的后端开发的技术栈是什么样的?</li><li>公司对后端技术沉淀的技术文档多吗?</li><li>如果这次面试顺利的话,最快能多久收到下一次面试的通知?</li><li>个人觉得这次面试我有点没有发挥好,您有什么建议给我吗?</li><li>在您的眼中,如果要升任这个岗位的话,最重要的几条能力是什么?</li></ul><h1 id="常问问题"><a href="#常问问题" class="headerlink" title="常问问题"></a>常问问题</h1><blockquote><p>人都有自己的阳面和阴面,要灵活改变</p></blockquote><ul><li>你期望薪资是多少?</li><li>你手头有几个offer?</li><li>你最大的缺点是什么?</li><li>你对加班和出差是如何看的?</li><li>你的职业规划是什么?</li><li>你的研究方向是什么?为什么要选择这个研究方向?</li><li>在学习和生活中遇到的最大的困难是什么?你是如何应对的?</li></ul>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>工作</tag>
<tag>面试</tag>
</tags>
</entry>
<entry>
<title>高性能MySQL</title>
<link href="/2024/10/29/effectivemysql/"/>
<url>/2024/10/29/effectivemysql/</url>
<content type="html"><![CDATA[<h1 id="MySQL的存储引擎"><a href="#MySQL的存储引擎" class="headerlink" title="MySQL的存储引擎"></a>MySQL的存储引擎</h1><h2 id="InnoDB"><a href="#InnoDB" class="headerlink" title="InnoDB"></a>InnoDB</h2><ul><li>支持事务:提供了具有提交、回滚和崩溃恢复能力的事务安全,确保数据的一致性和完整性。</li><li>行级锁定:可以在操作数据行时进行锁定,提高并发性能,减少锁冲突。</li><li>外键约束:支持外键约束,保证数据的参照完整性。</li><li>缓冲池:拥有较大的缓冲池,用于缓存数据和索引,提高数据访问速度。</li></ul><h2 id="MyISAM"><a href="#MyISAM" class="headerlink" title="MyISAM"></a>MyISAM</h2><ul><li>不支持事务:不提供事务处理功能,但在某些情况下,这可以提高性能和减少存储需求。</li><li>表级锁定:采用表级锁定机制,在写入操作时会锁定整个表,导致并发性能相对较低。</li><li>高速插入和查询:对于大量数据的插入和查询操作速度较快。</li><li>占用空间小:存储数据的方式较为紧凑,占用的磁盘空间相对较少。</li></ul><h1 id="MySQL执行计划分析"><a href="#MySQL执行计划分析" class="headerlink" title="MySQL执行计划分析"></a>MySQL执行计划分析</h1><ul><li>id 子查询的执行顺序</li><li>select_type</li><li>table 表名,别名</li><li>partitions</li><li><strong>type</strong> ALL全表数据,index遍历索引,range索引范围,const一条记录</li><li>possible_keys 可能用到的索引</li><li><strong>key</strong> 使用的索引</li><li>key_length 使用的索引长度</li><li>ref 连接匹配条件</li><li>rows 扫描行数</li><li><strong>extra</strong></li></ul><p>额外信息</p><ul><li><code>using filesort</code></li><li><code>using temporary</code></li><li><code>using index</code></li><li><code>using where</code></li><li><code>distinct</code></li></ul><h1 id="索引"><a href="#索引" class="headerlink" title="索引"></a>索引</h1><h2 id="InnoDB为什么使用B-树作为索引"><a href="#InnoDB为什么使用B-树作为索引" class="headerlink" title="InnoDB为什么使用B+树作为索引"></a>InnoDB为什么使用B+树作为索引</h2><ul><li>二叉树 不平衡</li><li>红黑树 高度太高</li><li>哈希表 有哈希冲突,仅能满足<code>=</code>,<code>IN</code>,不支持范围查询</li><li>B树 存储同样元素,高度小,效率高</li><li>B+树 叶子节点有序,连接起来</li></ul><h2 id="聚簇索引与非聚簇索引"><a href="#聚簇索引与非聚簇索引" class="headerlink" title="聚簇索引与非聚簇索引"></a>聚簇索引与非聚簇索引</h2><p><code>MyISAM</code>在data目录下会看到3类文件:<code>.frm、.myi、.myd</code>,索引和数据是分开存储的,是非聚集索引。</p><ol><li>.frm,表定义,是描述表结构的文件</li><li>.myd,D表示数据信息文件,是表的数据文件</li><li>.myi,I表示索引信息文件,是表数据文件中任何索引的数据树</li></ol><p><code>InnoDB</code>在data目录下会看到2类文件:<code>.frm、.ibd</code>,索引和数据是存储在一个文件,是聚集索引。</p><ol><li><em>.frm,表结构的文件。</em></li><li>.ibd,表数据和索引的文件。该表的索引(B+树)的每个非叶子节点存储索引,叶子节点存储索引和索引对应的数据</li></ol><h2 id="联合索引"><a href="#联合索引" class="headerlink" title="联合索引"></a>联合索引</h2><p>最左匹配原则,效率高,后面索引在索引树中没有任何顺序。</p><h1 id="MySQL日志"><a href="#MySQL日志" class="headerlink" title="MySQL日志"></a>MySQL日志</h1><p>MySQL日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。</p><p>MySQL数据库的<strong>数据备份、主备、主主、主从</strong>都离不开binlog,记录内容是语句的原始逻辑,类似于“给id=2这一行的name字段加 1”,属于<code>MySQL Server</code>层,依靠 binlog 来同步数据,保证数据一致性。</p><p>MySQL的InnoDB引擎使用 <strong>redo log(重做日志)</strong> 保证事务的<strong>持久性</strong>,使用<strong>undo log(回滚日志)</strong>来保证事务的<strong>原子性,</strong>拥有崩溃恢复能力。</p><h1 id="MVCC原理"><a href="#MVCC原理" class="headerlink" title="MVCC原理"></a>MVCC原理</h1><blockquote><p>RC(Read Commit)读已提交,RR(Repeatable Read)可重复读</p></blockquote><p><img src="https://zhaowuya.s3.bitiful.net/mvcc.jpg" alt="MVCC"></p><h2 id="三大利剑"><a href="#三大利剑" class="headerlink" title="三大利剑"></a>三大利剑</h2><p>隐藏字段,UndoLog版本链,ReadView读视图。</p><p>在每一条数据后,都有三个隐藏字段,其中较重要的是事务ID<code>db_trx_id</code>和回滚指针<code>db_roll_ptr</code>,还有一个隐式主键<code>db_row_id</code>字段在没有显示指定主键时起作用。</p><p>每当事务对数据进行修改后,会在UndoLog中生成日志,将老数据记录下来,并使用新数据的回滚指针指向老数据的地址,经过几次修改后,就会形成一个UndoLog版本链。</p><p>每当事务执行SQL语句时,会得到一个ReadView,用来做可见性判断,判断当前事务是否能看见此版本的数据。ReadView维护了4个字段,<code>trx_list</code>,<code>up_limit_id</code>,<code>low_limit_id</code>,<code>creator_trx_id</code>。</p><h2 id="读操作"><a href="#读操作" class="headerlink" title="读操作"></a>读操作</h2><ol><li>快照读(Snapshot Read),读取的是历史版本的数据,是不加锁的普通读操作。</li><li>当前读(Current Read),读取的是最新版本的数据,并加锁保证数据的一致性和事务隔离。</li></ol><h2 id="工作流程"><a href="#工作流程" class="headerlink" title="工作流程"></a>工作流程</h2><ol><li>如果事务ID小于ReadView中的最小值<code>low_limit_id</code>,说明该事务在ReadView之前已提交,可以读到。</li><li>如果事务ID大于等于<code>low_limit_id</code>,如果大于等于则代表DB_TRX_ID 所在的记录在Read View生成后才出现的,那对当前事务肯定不可见,如果小于则进入下一个判断。</li><li>如果事务ID在活跃事务列表<code>trx_list</code>中,当前事务看不见;如果不在,说明这个事务在ReadView生成之前就已经提交了,当前事务还能看见。</li></ol><h2 id="MVCC解决幻读"><a href="#MVCC解决幻读" class="headerlink" title="MVCC解决幻读"></a>MVCC解决幻读</h2><p>解决了部分场景下的幻读,下表所示的情况就没有解决。</p><div class="table-container"><table><thead><tr><th><code>BEGIN</code></th><th></th></tr></thead><tbody><tr><td><code>SELECT * FROM emp WHERE no = 4</code></td><td><strong><code>BEGIN</code></strong></td></tr><tr><td></td><td><code>INSERT INTO emp VALUES (4, '李四', 4200)</code></td></tr><tr><td><code>UPDATE emp SET ename = '李五' WHERE emp_no = 4</code></td><td></td></tr><tr><td><code>SELECT * FROM emp WHERE no = 4</code></td></tr></tbody></table></div>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>MySQL</tag>
</tags>
</entry>
<entry>
<title>Java基础</title>
<link href="/2024/10/29/javase/"/>
<url>/2024/10/29/javase/</url>
<content type="html"><![CDATA[<h1 id="浅尝JVM"><a href="#浅尝JVM" class="headerlink" title="浅尝JVM"></a>浅尝JVM</h1><h2 id="JVM内存结构"><a href="#JVM内存结构" class="headerlink" title="JVM内存结构"></a>JVM内存结构</h2><p><img src="https://zhaowuya.s3.bitiful.net/JVM.jpg" alt="JVM"></p><h2 id="类加载"><a href="#类加载" class="headerlink" title="类加载"></a>类加载</h2><p>装载,链接(验证,准备,解析),初始化。分别有什么作用?</p><h2 id="垃圾收集"><a href="#垃圾收集" class="headerlink" title="垃圾收集"></a>垃圾收集</h2><h3 id="分配对象"><a href="#分配对象" class="headerlink" title="分配对象"></a>分配对象</h3><p>Java中对象地址操作主要使用Unsafe调用了C的allocate和free两个方法,分配方法有两种:</p><ul><li>空闲链表(free list):通过额外的存储,记录</li><li>碰撞指针(bump pointer):</li></ul><h3 id="收集对象"><a href="#收集对象" class="headerlink" title="收集对象"></a>收集对象</h3><p>上图中蓝色区域为GC的主要工作区域。</p><p>ParNew : 年轻代<a href="https://so.csdn.net/so/search?q=垃圾收集器&spm=1001.2101.3001.7020">垃圾收集器</a>,多线程,采用标记—复制算法。</p><p>CMS:老年代的收集器,全称(Concurrent Mark and Sweep),是一种以获取最短回收停顿时间为目标的收集器。</p><h3 id="CMS与G1"><a href="#CMS与G1" class="headerlink" title="CMS与G1"></a>CMS与G1</h3><div class="table-container"><table><thead><tr><th>区别</th><th>CMS</th><th>G1</th></tr></thead><tbody><tr><td>回收位置</td><td>JDK5</td><td>JDK7</td></tr><tr><td>垃圾回收算法</td><td>M-S</td><td>M-C</td></tr></tbody></table></div><h1 id="并发编程"><a href="#并发编程" class="headerlink" title="并发编程"></a>并发编程</h1><blockquote><p>单核并发,多核并行,volatile关键字保证变量内存可见性(当一个线程修改了被volatile修饰的变量,其他线程能立即看到这次修改)还有防止指令重排,但是不能保证<strong>原子性。</strong></p></blockquote><h2 id="1-进程与线程的区别"><a href="#1-进程与线程的区别" class="headerlink" title="1.进程与线程的区别"></a>1.进程与线程的区别</h2><p><strong>进程</strong> : 一个运行中的程序的集合; 一个进程往往可以包含多个线程,至少包含一个线程,java默认有几个线程? 两个 main线程 gc线程。</p><p><strong>线程</strong> : 线程(thread)是操作系统能够进行运算调度的最小单位。</p><h2 id="2-用过哪些接口和类"><a href="#2-用过哪些接口和类" class="headerlink" title="2.用过哪些接口和类"></a>2.用过哪些接口和类</h2><h3 id="Lock接口"><a href="#Lock接口" class="headerlink" title="Lock接口"></a>Lock接口</h3><p>ReentrantLock</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Lock</span> </span>{<br> <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> ReentrantLock lock = <span class="hljs-keyword">new</span> ReentrantLock();<br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">m</span><span class="hljs-params">()</span></span>{<br> lock.lock();<br> <span class="hljs-keyword">try</span>{<br> System.out.println(<span class="hljs-string">"上锁"</span>);<br> } <span class="hljs-keyword">finally</span> {<br> lock.unlock();<br> }<br> }<br>}<br></code></pre></div></td></tr></table></figure><h4 id="线程安全集合"><a href="#线程安全集合" class="headerlink" title="线程安全集合"></a>线程安全集合</h4><h2 id="3-创建线程的方法有哪些?"><a href="#3-创建线程的方法有哪些?" class="headerlink" title="3.创建线程的方法有哪些?"></a>3.创建线程的方法有哪些?</h2><h4 id="3-1继承Thread类"><a href="#3-1继承Thread类" class="headerlink" title="3.1继承Thread类"></a><strong>3.1继承Thread类</strong></h4><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Cat</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Thread</span></span>{<br> <span class="hljs-meta">@override</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span></span>{<br> System.out.println(<span class="hljs-string">"喵喵喵~我是一只🐱"</span>)<br> }<br>}<br></code></pre></div></td></tr></table></figure><p>源码:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">// (1)同步</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">start</span><span class="hljs-params">()</span></span>{<br> start0();<br>}<br><span class="hljs-comment">// (2)本地方法,由c++实现,真正实现的多线程方法</span><br><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">native</span> <span class="hljs-keyword">void</span> <span class="hljs-title">start0</span><span class="hljs-params">()</span></span>;<br></code></pre></div></td></tr></table></figure><p><strong>start方法调用start0后,该线程并不一定会立马执行,只是将线程变成了可运行状态,具体什么时候执行,取决于CPU,由CPU统一调度。</strong></p><h3 id="3-2实现Runnable中的run方法(推荐)"><a href="#3-2实现Runnable中的run方法(推荐)" class="headerlink" title="3.2实现Runnable中的run方法(推荐)"></a><strong>3.2实现Runnable中的run方法(推荐)</strong></h3><p><strong>由于Java是单继承的,当我们要将a当作线程使用,而a已经继承了b,我们就不能通过继承Thread类来实现线程</strong></p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Runnable</span></span>{}<br><span class="hljs-comment">/**</span><br><span class="hljs-comment">*/</span><br>Dog dog = <span class="hljs-keyword">new</span> Dog();<br>Thread thread = <span class="hljs-keyword">new</span> Thread(dog);<br>thread.start();<br></code></pre></div></td></tr></table></figure><p>使用到了<strong>静态代理</strong>模式。</p><h3 id="3-3实现Callable接口"><a href="#3-3实现Callable接口" class="headerlink" title="3.3实现Callable接口"></a><strong>3.3实现Callable接口</strong></h3><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">FutureTask<Intger> future = <span class="hljs-keyword">new</span> FutureTask<>(() -> {<span class="hljs-keyword">return</span> <span class="hljs-number">1024</span>});<br></code></pre></div></td></tr></table></figure><p><strong>有返回值 ,能抛出异常,实现call方法</strong></p><p><code>FutureTask</code>包装一个<code>Callable</code>或<code>Runnable</code>任务,并且可以查询任务是否完成,等待任务完成,并获取结果。</p><h3 id="3-4通过JUC中的线程池"><a href="#3-4通过JUC中的线程池" class="headerlink" title="3.4通过JUC中的线程池"></a><strong>3.4通过JUC中的线程池</strong></h3><p>使用ThreadPoolExecutor线程池。</p><h2 id="4-Java线程状态有哪些,是如何转换的"><a href="#4-Java线程状态有哪些,是如何转换的" class="headerlink" title="4.Java线程状态有哪些,是如何转换的"></a>4.Java线程状态有哪些,是如何转换的</h2><div class="table-container"><table><thead><tr><th><strong>英文</strong></th><th><strong>中文</strong></th></tr></thead><tbody><tr><td>NEW</td><td>新建</td></tr><tr><td>RUNNABLE(Ready,Running)</td><td>这个状态包括了操作系统线程的就绪(ready)和运行(running)两种状态。</td></tr><tr><td>BLOCKED</td><td>阻塞</td></tr><tr><td>WAITING</td><td>等待</td></tr><tr><td>TIMED_WAITING</td><td>超时等待</td></tr><tr><td>TERMINATED</td><td>终结</td></tr></tbody></table></div><h2 id="5-sleep和wait区别"><a href="#5-sleep和wait区别" class="headerlink" title="5.sleep和wait区别"></a>5.sleep和wait区别</h2><h2 id="6-Java有哪些锁"><a href="#6-Java有哪些锁" class="headerlink" title="6.Java有哪些锁"></a>6.Java有哪些锁</h2><p><img src="https://zhaowuya.s3.bitiful.net/lock.png" alt="琐事"></p><h2 id="7-什么是AQS"><a href="#7-什么是AQS" class="headerlink" title="7.什么是AQS"></a>7.什么是AQS</h2><p>多线程中队列同步器,是一种锁机制,基础框架,例如ReentrantLock,Semaphore,CountDownLatch</p><p>state 0无锁 1有锁</p><p>线程1 -2 -3 -4 -5</p><p>队列:head,tail</p><ul><li>怎么保证原子性?<strong>CAS</strong></li><li>AQS是公平锁吗?都可以,等待/抢</li></ul><h2 id="8-ReentrantLock实现原理"><a href="#8-ReentrantLock实现原理" class="headerlink" title="8.ReentrantLock实现原理"></a>8.ReentrantLock实现原理</h2><p>主要通过CAS+AQS队列来实现,它支持非/公平,公平锁的效率通常没有非公平高。</p><h2 id="9-ConcurrentHashMap"><a href="#9-ConcurrentHashMap" class="headerlink" title="9.ConcurrentHashMap"></a>9.ConcurrentHashMap</h2><p>JDK1.8 采用的数据结构跟HashMap的结构一样</p><h3 id="加锁的方式"><a href="#加锁的方式" class="headerlink" title="加锁的方式"></a>加锁的方式</h3><ul><li>JDK1.7采用分段锁,底层使用的是ReentrantLock</li><li>JDK1.8采用<strong>CAS</strong>添加新的节点,采用<strong>syn</strong>锁定链表或哦红黑数的首节点,锁的粒度更细,效率高。</li></ul><h2 id="10-线程池的核心参数有哪些"><a href="#10-线程池的核心参数有哪些" class="headerlink" title="10.线程池的核心参数有哪些"></a>10.线程池的核心参数有哪些</h2><ol><li>corePoolSize:<strong>核心</strong>线程数,线程池正常情况下保持的线程数,大户人家“长工”的数量。</li><li>maximumPoolSize:<strong>最大</strong>线程数,当线程池繁忙时最多可以拥有的线程数,大户人家“长工”+“短工”的总数量。</li><li>keepAliveTime:空闲线程存活<strong>时间</strong>,没有活之后“短工”可以生存的最大时间。</li><li>TimeUnit:3时间<strong>单位</strong>。</li><li>BlockingQueue:线程池的任务<strong>队列</strong>,用于保存线程池待执行任务的容器。</li><li>ThreadFactory:线程工厂,用于创建线程池中线程的工厂<strong>方法</strong>,通过它可以设置线程的命名规则、优先级和线程类型。</li><li>RejectedExecutionHandler:拒绝<strong>策略</strong>,当任务量超过线程池可以保存的最大任务数时,执行的策略。</li></ol><h2 id="11-谈谈你对ThreadLocal的理解"><a href="#11-谈谈你对ThreadLocal的理解" class="headerlink" title="11.谈谈你对ThreadLocal的理解"></a>11.谈谈你对ThreadLocal的理解</h2><h2 id="12-谈谈CompletableFuture"><a href="#12-谈谈CompletableFuture" class="headerlink" title="12.谈谈CompletableFuture"></a>12.谈谈CompletableFuture</h2><p>原因:使用futureTask的get方法会阻塞线程,isDone方法会轮询CPU消耗资源。</p><p>观察者模式:可以让任务完成后通知主线程。异步任务结束后,会自动回调某个对象的方法,出错时,会自动回调某个对象方法。</p><h1 id="语言基础"><a href="#语言基础" class="headerlink" title="语言基础"></a>语言基础</h1><h2 id="自动类型转换"><a href="#自动类型转换" class="headerlink" title="自动类型转换"></a>自动类型转换</h2><p>可以支持将表数范围从小转向大的,而不能反过来,就好像大杯的水不能倒入小杯中,因为会溢出!</p><figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">short</span> s<span class="hljs-number">1</span> = <span class="hljs-number">1</span>; s<span class="hljs-number">1</span> = s<span class="hljs-number">1</span> + <span class="hljs-number">1</span>;``short s<span class="hljs-number">1</span> = <span class="hljs-number">1</span>; s<span class="hljs-number">1</span> += <span class="hljs-number">1</span>;<br></code></pre></div></td></tr></table></figure><p>对于 short s1 = 1; s1 = s1 + 1;编译出错,由于 1 是 int 类型,因此 s1+1 运算结果也是 int 型,需要强制转换类型才能赋值给 short 型。</p><h2 id="自动拆装箱"><a href="#自动拆装箱" class="headerlink" title="自动拆装箱"></a>自动拆装箱</h2><p>那什么是拆箱呢?顾名思义,跟装箱对应,就是自动将包装器类型转换为基本数据类型。</p><figure class="highlight awk"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs awk">Integer i= <span class="hljs-number">1</span>; <span class="hljs-regexp">//</span> 装箱<br>int n = i; <span class="hljs-regexp">//</span>拆箱<br></code></pre></div></td></tr></table></figure><h2 id="日期"><a href="#日期" class="headerlink" title="日期"></a>日期</h2><h2 id="集合"><a href="#集合" class="headerlink" title="集合"></a>集合</h2><h2 id="枚举"><a href="#枚举" class="headerlink" title="枚举"></a>枚举</h2><p>枚举是一种特殊的类,它不能被继承,是一组<strong>命名常量</strong>的集合。这些命名常量被称为枚举常量。例如春夏秋冬、网络状态码、订单状态码、用户标识符等,能够避免<strong>魔法数字</strong>的使用,<strong>提高代码可读性和可维护性</strong>。</p><h2 id="IO流"><a href="#IO流" class="headerlink" title="IO流"></a>IO流</h2><ul><li>字节流(二进制文件图片,视频,音频,无损操作),字符流(按字符)(文本文件效率高)</li><li>按流的角色不同为:节点流,包装流</li></ul><p><strong>按行读取</strong>取bufferReader.readLine节点流和处理流</p><h3 id="节点流"><a href="#节点流" class="headerlink" title="节点流"></a>节点流</h3><p>可以从一个特定的数据源读写数据,如FileReader,FileWriter</p><h3 id="包装流"><a href="#包装流" class="headerlink" title="包装流"></a>包装流</h3><p>也叫<strong>处理流</strong>,是连接在已存在的流之上,为程序提供更为强大的功能,如BufferedReader,BufferedWriter。</p><p>装饰器(Decorator)模式的使用</p><h3 id="对象流"><a href="#对象流" class="headerlink" title="对象流"></a>对象流</h3><p>能够将基本数据类型或者对象进行<strong>序/反序列</strong>化的操作。</p><p>注意事项:</p><ol><li>读写顺序要一致</li><li>实现Serializable接口</li><li>建议添加SerialVersionUID,提高兼容性</li><li>序列化时除了static和transient</li><li>序列化自动继承</li></ol><p>序列化就是保存数据的时候,同时保存数据的值和数据类型,反序列化就是恢复过程。可以实现Serializable和Externalizable</p><h2 id="Stream流"><a href="#Stream流" class="headerlink" title="Stream流"></a>Stream流</h2><p>JDK8新特性</p><h3 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h3><ol><li><strong>声明式编程</strong>:使用 Stream 流可以采用声明式的方式来表达对数据的处理逻辑,而不是像传统的命令式编程那样通过循环和条件语句来实现。这使得代码更加简洁、易读,并且更接近问题的本质描述。</li><li><strong>懒加载</strong>:许多 Stream 操作是懒加载的,这意味着它们只有在真正需要结果的时候才会执行。例如,当使用一系列中间操作(如过滤、映射等)后,只有在调用终端操作(如<code>forEach</code>、<code>collect</code>等)时,才会实际执行整个流的处理过程。</li><li><strong>函数式编程风格</strong></li></ol><h3 id="操作"><a href="#操作" class="headerlink" title="操作"></a>操作</h3><p>中间操作filter,map,sort</p><p>终端操作foreach,collect</p><h3 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h3><ol><li><strong>数据处理和转换</strong>:当需要对大量数据进行复杂的处理和转换时,简洁而高效的方式。</li><li><strong>集合操作</strong>:可以方便地对集合进行各种操作,如过滤、排序、分组等,可以大大简化代码。</li><li><strong>并行处理</strong>:效率高。</li></ol><h2 id="面向对象"><a href="#面向对象" class="headerlink" title="面向对象"></a>面向对象</h2><h3 id="重载与重写区别"><a href="#重载与重写区别" class="headerlink" title="重载与重写区别"></a>重载与重写区别</h3><p>在同一个类中,可能会存在同名的方法,但是他们函数签名(名字,<strong>参数列表</strong>,返回值)不同,主要是参数列表不同。</p><p>在子类中,对于父类中同一个方法(方法签名一样),会根据需求扩展或修改,以更加具体地实现父类中的方法。子类的返回值类型要<strong>小</strong>于父类,抛出比父类更<strong>小</strong>的异常,访问权限比父类<strong>大</strong>。</p><h3 id="抽象类和接口的区别"><a href="#抽象类和接口的区别" class="headerlink" title="抽象类和接口的区别"></a>抽象类和接口的区别</h3><ol><li>继承与实现</li></ol><ul><li>抽象类通过 extends 关键字被继承。一个类只能继承一个抽象类。</li><li>接口通过 implements 关键字被实现,一个类可以实现多个接口。</li><li><p>成员变量修饰符</p></li><li><p>抽象类可以有各种类型的成员变量,包括实例变量。</p></li><li>接口中的成员变量默认是 public static final 的<strong>常量</strong>。</li><li><p>方法的修饰符</p></li><li><p>抽象类中的方法可以有不同的访问修饰符,并且可以有方法体(非抽象方法)。</p></li><li>接口中的方法默认是 <em>public</em> <em>abstract</em> (在Java 8之前,Java 8开始可以有default修饰的方法———可以有实现)。</li></ul><h2 id="反射"><a href="#反射" class="headerlink" title="反射"></a>反射</h2><ol><li>使用<code>Class.forName()</code>方法获取Class对象。</li><li>获取所有<strong>公共构造函数</strong>,获取<strong>特定参数的构造函数</strong><code>getConstructor()</code>,也可以获取其他公共方法<code>getMethod()</code>。如果有重载情况,可以通过参数不一样<code>(int.class,String.class)</code>来明确要获得的具体方法。</li></ol><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">Class<?> clazz = MyClass.class;<br>Constructor<?> constructor = clazz.getConstructor(<span class="hljs-keyword">int</span>.class, String.class);<br><span class="hljs-comment">// 使用构造函数创建对象</span><br>MyClass obj = (MyClass) constructor.newInstance(<span class="hljs-number">10</span>, <span class="hljs-string">"example"</span>);<br></code></pre></div></td></tr></table></figure><ol><li>获取所有字段或者特定字段并访问其值<code>getField()</code></li></ol><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">try</span> {<br> Class<?> clazz = MyClass.class;<br> Field field = clazz.getField(<span class="hljs-string">"myField"</span>);<br> MyClass obj = <span class="hljs-keyword">new</span> MyClass();<br> Object value = field.get(obj);<br> System.out.println(<span class="hljs-string">"Field value: "</span> + value);<br>} <span class="hljs-keyword">catch</span> (NoSuchFieldException | IllegalAccessException e) {<br> e.printStackTrace();<br>}<br></code></pre></div></td></tr></table></figure><h3 id="使用场景-1"><a href="#使用场景-1" class="headerlink" title="使用场景"></a>使用场景</h3><p><strong>一、框架开发</strong></p><ol><li>依赖注入框架,如 Spring,可利用反射自动注入依赖对象。例如,根据配置查找服务类的构造函数,自动创建依赖对象并传入构造函数完成注入。</li><li>ORM 框架通过反射将数据库数据映射到 Java 对象,如 MyBatis 在查询后用反射填充对象属性。</li></ol><p>二<strong>、测试框架</strong></p><ol><li>单元测试中可通过反射访问类的私有方法和字段进行更全面测试,如在 JUnit 中调用被测试类的私有方法验证功能。</li></ol><h2 id="注解"><a href="#注解" class="headerlink" title="注解"></a>注解</h2><p><strong>一、定义注解</strong></p><p>使用<code>@interface</code>关键字来定义一个注解。例如:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">import</span> java.lang.annotation.ElementType;<br><span class="hljs-keyword">import</span> java.lang.annotation.Retention;<br><span class="hljs-keyword">import</span> java.lang.annotation.RetentionPolicy;<br><span class="hljs-keyword">import</span> java.lang.annotation.Target;<br><br><span class="hljs-meta">@Target({ElementType.METHOD, ElementType.FIELD})</span><br><span class="hljs-meta">@Retention(RetentionPolicy.RUNTIME)</span><br><span class="hljs-keyword">public</span> <span class="hljs-meta">@interface</span> MyCustomAnnotation {<br> <span class="hljs-function">String <span class="hljs-title">value</span><span class="hljs-params">()</span> <span class="hljs-keyword">default</span> ""</span>;<br>}<br></code></pre></div></td></tr></table></figure><h2 id="动态代理"><a href="#动态代理" class="headerlink" title="动态代理"></a>动态代理</h2><blockquote><p>JDK原生动态代理是Java原生支持的,不需要任何外部依赖,但是它只能基于接口进行代理;CGLIB通过继承的方式进行代理,无论目标对象有没有实现接口都可以代理,但是无法处理final的情况。</p></blockquote><h3 id="JDK"><a href="#JDK" class="headerlink" title="JDK"></a>JDK</h3><ol><li>定义一个要代理的接口</li><li>实现<code>InvocationHandler</code>接口中的<code>invoke</code>方法,表示调用接口后转发到此实现</li><li>通过<code>Proxy.newProxyInstance</code> 方法创建了一个代理实例 <code>hello</code></li></ol><h3 id="CGLIB"><a href="#CGLIB" class="headerlink" title="CGLIB"></a>CGLIB</h3>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Java</tag>
<tag>JVM</tag>
<tag>并发编程</tag>
</tags>
</entry>
<entry>
<title>二〇二五校招</title>
<link href="/2024/09/02/campus2025/"/>
<url>/2024/09/02/campus2025/</url>
<content type="html"><![CDATA[<h1 id="秋招信息"><a href="#秋招信息" class="headerlink" title="秋招信息"></a>秋招信息</h1><div class="table-container"><table><thead><tr><th>来源</th><th>网址</th></tr></thead><tbody><tr><td>B站Guangju</td><td><a href="https://www.wolai.com/curry00/i1vaQy88yECxie3N1PoBHH">25届秋招</a></td></tr><tr><td>GithubCampus2025</td><td><a href="https://campus2025.top">Campus2025</a></td></tr></tbody></table></div><p>飞书云文档: <a href="https://ri8yidgzuju.feishu.cn/wiki/ItEJwZA1fimnHOkIYoOcASy1ndg?table=tbllV4bB1GNQcoTl&view=vewNixVFJ9">秋招投递记录</a></p><h1 id="初相遇"><a href="#初相遇" class="headerlink" title="初相遇"></a>初相遇</h1><h2 id="1-投简历"><a href="#1-投简历" class="headerlink" title="1.投简历"></a>1.投简历</h2><p>校招的官网,完善简历,尽量写的全一点,把自己行业相关的荣誉奖项全写上去,有内推码就写上,不写也行。</p><h2 id="2-做题"><a href="#2-做题" class="headerlink" title="2.做题"></a>2.做题</h2><h3 id="测评"><a href="#测评" class="headerlink" title="测评"></a>测评</h3><p>测评主要是企业看你这个人有没有什么性格缺陷,有些企业是最后测评的,一般都是行测里的<strong>语言理解与表达</strong>,<strong>资料分析</strong>,<strong>图形推理</strong>。第一次写会有点懵,因为每题限时60s,但是做多了就熟练了。其实测评的占比不高,认真做了就行,非要追求一些小技巧,可以去B站看看视频<a href="https://www.bilibili.com/video/BV1f4411C7z5/?spm_id_from=333.337.search-card.all.click">刘文超资料分析</a>等一系列课程,看一点就好,或者直接去咸鱼或淘宝买北森的测评题库。</p><h3 id="笔试"><a href="#笔试" class="headerlink" title="笔试"></a>笔试</h3><p>分为基础八股和算法题,决定了你是否能参加一面,笔试分值占比大厂一般都是计算机基础30分,算法70分。所以算法还是很重要的,我开始就去背八股了,结果连一面都进不了,还谈什么Offer?</p><p>计算机基础一般包括网络、数据结构、数据库、操作系统、Linux、设计模式和对应的语言题。Java的这些我都是看的<a href="https://javaguide.cn/">JavaGuide</a>和<a href="https://javabetter.cn/xuexiluxian/">沉默王二</a>,基本上都会有覆盖,平时没事的时候可以刷着看一下,或者去<a href="https://www.nowcoder.com/exam/company">牛客网笔试真题</a>上做一下真题巩固一下。3道算法题,能AK的基本上都是拿过牌子的大佬,普通计科的同学大概做个1.5道就能进面了(有小数是因为可能有些测试用例过不了,只能过一些)。大厂算法题都是ACM模式,需要自己处理输入输出,不熟悉的同学可以去卡哥网站<a href="https://kamacoder.com/">卡码网KamaCoder</a>上练练手。</p><h1 id="青涩交流"><a href="#青涩交流" class="headerlink" title="青涩交流"></a>青涩交流</h1><p>企业筛选求职者最快的方法就是通过面对面的交流,可以从全方位的角度衡量一个人是否和当前岗位匹配。面试一般都会有多轮,每一轮你要面对的人也是不一样的,技术面试官,部门领导,HR等。</p><h2 id="技术面"><a href="#技术面" class="headerlink" title="技术面"></a>技术面</h2><p>首先就是做一个自我介绍,面试官虽然有你的简历,但是可能因为工作原因没来得及看,或者就想看看你的语言表达能力和总结能力,一定要好好准备,提前练习,有些同学在学校读书读久了,忘记如何和人沟通了。</p><p>接下来,技术面试官就会对你进行“拷打”了,包括但不限于计算机八股,项目经历,实习经历,校园经历等等,你简历上的东西都可能会问到,所以在面试之前要绞尽脑汁的站在一个面试官的角度,去对这份青涩的简历提问。</p><p>最后的就是反问环节了,具体细节可以看这篇文章(<a href="https://zhaowuya.top/2024/10/29/interviewquestion/">面试中的问题 | 庐山烟雨浙江潮</a>),笔者在此便不多赘述。</p><h2 id="部门领导面"><a href="#部门领导面" class="headerlink" title="部门领导面"></a>部门领导面</h2><p>领导主要看你整个人的气质,性格,还有工作态度是否和工作匹配,问的问题有偏技术的,也有偏工作的,因人而异。在这个阶段,我们就要事先去了解公司的业务,以及表现的落落大方,毕竟你一面都过了嘛,还有时不时的透露出自己想加入这家公司的愿望。</p><p>反问环节的问题,尽量不要和上一次一样,同样参考上一节文章。</p><h1 id="学会拉扯"><a href="#学会拉扯" class="headerlink" title="学会拉扯"></a>学会拉扯</h1><p>过五关斩六将之后,如果你成功之后,你就会收到一个Offer的意向,这个时候我们先不要答应他,如果你还有其他公司的流程在进行中并且这个公司你不太满意的话,尽可能的去拖一个确认时间。后面才会签三方协议。</p><p>说起这个三方协议,其实就是在企业,学校和你个人之间的一个约定,其实并不保护你。</p><h1 id="在雨中说雨"><a href="#在雨中说雨" class="headerlink" title="在雨中说雨"></a>在雨中说雨</h1><p><img src="https://zhaowuya.s3.bitiful.net/offer.jpg" alt="首义路"></p><p>只有经历过秋招,你才发现之前在玻璃房里欣赏的雨,是苦的味道。</p><blockquote><p>建议大家都去体验一下秋招,秋招会悄然扯下隔在成人社会和校园生活之间的那一层遮羞布,把每一个放在残酷的社会现实和市场需求这杆秤上反复掂量。人的心气在这场旷日持久的折磨中一点一滴地被消磨殆尽,迅速地冷漠,社会化。挤不进大厂,做不完的笔试,没有回音的面试,看不到希望但却要日复一日地、侥幸地碰碰运气。</p><p>秋招之前,经济下行这个词对我来说很难真情实感地身体会到;拿着父母给的生活费,做着幼稚的学术和竞赛,和好友一起在校园内外吃饭乱逛。现在来看,这样单纯宁静而乌托邦的日子再也不会回来了。企业实习了一遭,公司的正职背着绩效和考核的压力,每个人都是紧绷着的。没有早早觉醒去规划实习和未来的我,本硕的学历缩水成两张薄薄的纸片,敲不响任何一家大厂的门。</p><p>越早体会秋招的好处在于:越早面对现实惨淡,让自己的心变得冷硬起来;放下幻想,脚踏实地,去抓一些自己还能够到的东西。</p></blockquote>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>工作</tag>
<tag>面试</tag>
</tags>
</entry>
<entry>
<title>东方欲晓</title>
<link href="/2024/08/31/sunrise/"/>
<url>/2024/08/31/sunrise/</url>
<content type="html"><![CDATA[<p><img src="https://zhaowuya.s3.bitiful.net/sun.jpg" alt="凌波门日出"></p><p><img src="https://zhaowuya.s3.bitiful.net/twogirls.jpg" alt="小L和小Y"></p><p>秋招将至,秋意也从傍晚的微风中拂过我的身体。在走出了学校象牙塔后,体会到了在酷暑中高强度实习的痛苦。同小Y不经意间的聊天之中,她突然萌发了一个大胆的想法,去凌波门看日出。在拖着疲惫的嗓子“休息了一晚上”后,我们和她的朋友小L带着装备来到湖边静静等待她的到来。</p><p>我强撑着困意,在路上的时候其实天就已经蒙蒙亮了,水天相接之处,仿佛用水墨染上了一层紫色的面纱,桐秋的下弦月孤零零的挂在天空的幕布上,湖风吹过来,一下子叫醒了我。</p><p>……</p><p>天亮了,东边云层好巧不巧的挡住了太阳,丝毫没有直线与圆相交的迹象,小Y是第一次看日出,心情难免会有所失望,她们便在桥上坐着,开始分享之前看见的日出的景象。我站在一旁看附近的人和跳水,嬉闹,心情似乎也缓和了一些。</p><p>我眺望着东方,眼里的画面渐渐得被分成了三层,上边是朝阳的光茫映射出来的金黄色天空,中间是蓝灰色的云层,下边则是熙熙攘攘的人群和他们在在余晖之下的弯曲的倒影。我盯着那块云,她开始慢慢的落下帷幕,柔和且温暖的朝阳出现了!此时的她并没有正午时分那样恶劣无情,也没有夕阳西下时的壮志未酬,此刻便是无限的希望。“东方欲晓,莫道君行早。踏遍青山人未老,风景这边独好。”此刻我才明白,在洛神赋中,为什么曹植要用“远而望之,皎若太阳升朝霞”来形容宓妃了。</p><p>一波三折的过程和我研究生三年其实差不多,和整个人生也差不多。我们总是在失败中前进,在前进中失败,那些不能打败我的,终究会让我变得更强大。</p><p>小Y一直在拍照,也是激动到无以言表。我看着太阳,只是静静的看着太阳,看娇羞的她从云层后面半遮半掩,到最后光芒耀眼到我无法直视,也就仅仅过去了五六分钟而已。</p><p>最后我们仨都要走了,走向各自的方向,敢问路在何方?路在脚下。</p>]]></content>
<categories>
<category>生活</category>
</categories>
<tags>
<tag>生活随笔</tag>
</tags>
</entry>
<entry>
<title>春景</title>
<link href="/2024/08/28/springlake/"/>
<url>/2024/08/28/springlake/</url>
<content type="html"><![CDATA[<p><img src="https://zhaowuya.s3.bitiful.net/springlake.jpg" alt="春景"></p><p><center>沁湖春景</p><p><center>绿暗红稀沁水低,学忙事锁未几离。</p><p><center>今朝出世能观此,便晓春轻拂柳堤。</p>]]></content>
<categories>
<category>生活</category>
</categories>
<tags>
<tag>生活随笔</tag>
</tags>
</entry>
<entry>
<title>理解服装</title>
<link href="/2024/08/28/clothes/"/>
<url>/2024/08/28/clothes/</url>
<content type="html"><![CDATA[<p><img src="https://zhaowuya.s3.bitiful.net/suit.jpg" alt="懒而思西装"></p><p>小时候不知从什么时候开始,我妈就说我买衣服很挑剔,这也不要,那也不要,偏偏喜欢自己挑了好久的衣服。</p><p>大概是小学时候,班里谁有一件短款的风衣,谁就是班上最引人注目的对象,那个时候的我,其实对衣服是没有什么理解的,只知道这件衣服好像是电视上的黑帮老大穿过的衣服。对衣服的启蒙通常从款式开始的。</p><p>于是我便有了自己的第一件西服,黑色,平驳领,双排扣,胸前还有白色千鸟格纹。当然这些都是后来知道的,当时就只是觉得穿这件衣服可以在学校横着走,可以体现自己不一样的气质。通常的搭配都是T恤和休闲裤加纯黑的板鞋(完全是模仿黑色皮鞋)。那个时候还喜欢鲜艳的颜色搭配,我记得有一次穿了酒红色拼深灰色棒球服,藏蓝色裤子和经典高帮帆布鞋,自我感觉良好。还有黄绿色的长裤和翡翠绿的长袖,外加正红色的运动鞋。但当时的我还不知道材料对衣服质量以及穿着整体效果的影响。</p><p>到高中后,我开始在县城里面买衣服,也了解到一些衣物鞋子的品牌。但是由于太贵,不好意思向爸妈开口。不过最后还是拿着我的“奖学金”买了人生中的第一双经典帆布鞋,我经常穿着它踢球,跑步,上学,后面鲜红的小标我认为是很好看的点缀。渐渐地,衣服的款式也丰富起来。</p><p>上了大学,对衣物理解有阶段性变化。</p><p>第一阶段,看着网上琳琅满目的卖家秀,开始跟风购买,格子裤,格子假两件衬衫,高帮枫叶袜,现在看简直惨不忍睹。</p><p>第二阶段因为大学的衣物都需要自己打理,后来发现这些衣服质量都很差,不是起球就是褪色。便慢慢习惯看衣物的材料,关心它的缺点。我记得有一次买了一件杏色毛衣,以为和普通衣服一样可以放进洗衣机里,结果拿出的时候,两个袖子已经可以翩翩起舞了。那个时候颜色也是搭配多变,但基本上控制在黑白色系,大地色系和蓝色系。</p><p>第三阶段,开始喜欢衣服上的一些小细节,比如拉链,双头拉链,内衬布料,调节袖口,帽檐设计,后背伞褶,短袖领扣等等。也开始看着视频对衣服的起源和发展有了大致的了解,于是对正装萌发了深深的迷恋之情。我尝试着穿过几回,但你发现穿着战壕风衣高领黑色毛衣,黑色马丁靴的人在路上背着双肩包啃着馒头的时候,就知道有多滑稽了。</p><p>第四阶段,对黑色有种独特的见解。许多的设计了姹紫嫣红的衣服的设计师通常穿着黑色的外套,仿佛是他们对生活的态度:耐脏,易打理,从不喧宾夺主,总是在一旁做一个安安静静的观察者,对生活没有太多时间,他们要把时间一心一意放在设计上,黑色成了他们的选择。</p><p>有些人总是忧愁明天的搭配,但我们要反过来问问自己,到底是衣穿人,还是人穿衣?</p>]]></content>
<categories>
<category>生活</category>
</categories>
<tags>
<tag>生活随笔</tag>
</tags>
</entry>
<entry>
<title>Spring Boot整合Mybatis中易错点</title>
<link href="/2023/06/02/springbootandmybatis/"/>
<url>/2023/06/02/springbootandmybatis/</url>
<content type="html"><![CDATA[<h2 id="时间格式"><a href="#时间格式" class="headerlink" title="时间格式"></a>时间格式</h2><p>前端,后端,数据库中的数据格式有太多,排列组合起来就更多了,目前使用较多的时间格式是这样的。</p><ul><li><p>前端使用yyyy-MM-dd HH:mm:ss格式传入。</p></li><li><p>后端接收的时候用实体类接收,其中有一个属性为LocalDateTime,必须设置如下注解才能解析:</p></li></ul><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")</span><br><span class="hljs-keyword">private</span> LocalDateTime personBirth;<br></code></pre></div></td></tr></table></figure><ul><li>不然会报如下错误:</li></ul><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException) Text <span class="hljs-string">'1900-08-12 21:12:21'</span> could not be parsed at index <span class="hljs-number">10</span><br></code></pre></div></td></tr></table></figure><ul><li>MySQL数据库中date只能保留年月日,datetime和timestamp可以展示到时分秒。</li><li><code>2023-07-05</code></li><li><code>2023-07-05 00:00:00</code></li></ul><h2 id="SQL"><a href="#SQL" class="headerlink" title="SQL"></a>SQL</h2><p><code>${}</code>本质是字符串拼接,相当于单引号,会有SQL注入问题<br><code>#{}</code>占位符赋值</p><p>如果需要传参有数据时,按数据查找,传参为空时查找所有数据,只需添加<code><where></code>以及<code><if></code>标签,where标签在if标签判断为空时会自动消失退去。例子如下:</p><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"findDog"</span> <span class="hljs-attr">parameterType</span>=<span class="hljs-string">"String"</span> <span class="hljs-attr">resultType</span>=<span class="hljs-string">"com.example.demo.pojo.Dog"</span>></span><br> select * from t_dog<br> <span class="hljs-tag"><<span class="hljs-name">where</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">if</span> <span class="hljs-attr">test</span> = <span class="hljs-string">" name != null "</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">bind</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"dogName"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"'%' + name + '%'"</span>/></span><br> and d_name like #{dogName}<br> <span class="hljs-tag"></<span class="hljs-name">if</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">where</span>></span> <br> <span class="hljs-tag"></<span class="hljs-name">select</span>></span><br></code></pre></div></td></tr></table></figure><p>如果只是使用原本的关键字<code>where</code>而不使用标签,在if标签为空时,SQL语句中还会出现where字段,此时会报SQL语法错误。</p><figure class="highlight"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">### The error occurred while setting parameters<br>### SQL: select * from t_dog where<br>### Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax;<br></code></pre></div></td></tr></table></figure><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">bind</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"dogName"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"'%' + name + '%'"</span>/></span><br></code></pre></div></td></tr></table></figure><p>bind标签可以用于模糊查询。</p><p>新增时可以在Mapper接口层起别名,例如<code>info</code>,以便更好地引用。增删改的返回值都是受影响的行数。在修改实体类中字段后,记得修改xml文件中的映射字段,例如<code>info.guid</code>,通常这个文件不会报错,但是等到运行后再改就迟了。</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function">Integer <span class="hljs-title">addDog</span><span class="hljs-params">(<span class="hljs-meta">@Param("info")</span> Dog dog)</span></span>;<br></code></pre></div></td></tr></table></figure><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">insert</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"addDog"</span> <span class="hljs-attr">parameterType</span>=<span class="hljs-string">"com.example.demo.pojo.Dog"</span>></span><br> insert into<br> t_dog<br> values(<br> #{info.guid},<br> #{info.dogName},<br> #{info.dogAge}<br> )<br> <span class="hljs-tag"></<span class="hljs-name">insert</span>></span><br></code></pre></div></td></tr></table></figure><h2 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h2><p>Mapper.xml中select标签的id属性必须和Mapper接口中字段一致,可以通过安装插件点击若能跳转则无问题。</p><p>文件开头:</p><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-meta"><?xml version="1.0" encoding="UTF-8" ?></span><br><span class="hljs-meta"><!DOCTYPE <span class="hljs-meta-keyword">mapper</span></span><br><span class="hljs-meta"> <span class="hljs-meta-keyword">PUBLIC</span> <span class="hljs-meta-string">"-//mybatis.org//DTD Mapper 3.0//EN"</span></span><br><span class="hljs-meta"> <span class="hljs-meta-string">"http://mybatis.org/dtd/mybatis-3-mapper.dtd"</span>></span><br></code></pre></div></td></tr></table></figure><p>定义命名空间,就是找到你的对应的Mapper层下面的指定的Mapper接口:</p><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">mapper</span> <span class="hljs-attr">namespace</span>=<span class="hljs-string">"com.example.demo.mapper.DogMapper"</span>></span><br><span class="hljs-tag"></<span class="hljs-name">mapper</span>></span><br></code></pre></div></td></tr></table></figure><h2 id="注解"><a href="#注解" class="headerlink" title="注解"></a>注解</h2><p>@RequestMapping和@GetMapping的区别,@GetMapping用于将HTTP的GET请求映射到特定处理程序的方法注解。具体来说,@GetMapping是一个组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写。</p><p>通过@RequstBody接JSON对象,字段名必须严格一致(有坑看我上一篇文章),一般是POST请求。</p><p>通过RequestParam(value = “dogName” , required = false ,defaultValue = “”)接受散个字段,设置value后,使用GET请求可不带参数。</p><p>@Autowired 在控制器中记得写。</p><p>Column ‘d_name’ cannot be null 参数名写了就要对上,不然接受不到。在Postman中POST请求中,可以不写全接受类中的所有参数,匹配成功后默认为空。例如:</p><figure class="highlight json"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs json">{<br> <span class="hljs-attr">"dogName"</span>: <span class="hljs-string">"月亮"</span>,<br> <span class="hljs-attr">"dogAge"</span>: <span class="hljs-number">13</span><br>}<br></code></pre></div></td></tr></table></figure><p>接受类为:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Data</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> </span>{<br><br> <span class="hljs-keyword">private</span> String guid;<br><br> <span class="hljs-keyword">private</span> String dogName;<br><br> <span class="hljs-keyword">private</span> Integer dogAge;<br><br>}<br></code></pre></div></td></tr></table></figure><p>接收后的对象属性是这样的:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">Dog(guid=<span class="hljs-keyword">null</span>, dogName=月亮, dogAge=<span class="hljs-number">13</span>)<br>Dog(guid=36a341f97fe441498b4d8712fdea28cb, dogName=月亮, dogAge=<span class="hljs-number">13</span>)<br>Creating a <span class="hljs-keyword">new</span> SqlSession<br>==> Preparing: <span class="hljs-function">insert into t_dog <span class="hljs-title">values</span><span class="hljs-params">( ?, ?, ? )</span></span><br><span class="hljs-function"></span>==> Parameters: 36a341f97fe441498b4d8712fdea28cb(String), 月亮(String), <span class="hljs-number">13</span>(Integer)<br><== Updates: <span class="hljs-number">1</span><br></code></pre></div></td></tr></table></figure><p>之后我们可以通过设置guid,最后把整个对象新增到数据库中。</p><p>实体类类名和数据库中字段名要对上,一般是数据库中字段名用下划线分割,JavaBean中用驼峰,最后在Mybatis配置文件中开启驼峰转换。记得打开日志哦🤭!</p><figure class="highlight plain"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs yam">server:<br> port: 8081<br><br>spring:<br> # 数据源配置<br> datasource:<br> driver-class-name: com.mysql.cj.jdbc.Driver<br> url: "jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"<br> username: root<br> password: mysql1970s<br><br>mybatis:<br> # 指定 mapper.xml 的位置<br> mapper-locations: classpath:mapper/*.xml<br> #扫描实体类的位置,在此处指明扫描实体类的包,在 mapper.xml 中就可以不写实体类的全路径名# type-aliases-package: net.biancheng.www.bean<br> configuration:<br> #默认关闭驼峰命名法,设置该属性!!!!!!!!!!!!<br> map-underscore-to-camel-case: true<br> #SQL级别日志<br> log-impl: org.apache.ibatis.logging.stdout.StdOutImpl<br></code></pre></div></td></tr></table></figure><h2 id="POM文件"><a href="#POM文件" class="headerlink" title="POM文件"></a>POM文件</h2><p>整合Spring Boot的Mybatis包和单独的不一样,记得区别。以下是我的DEMO的POM文件:</p><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-meta"><?xml version="1.0" encoding="UTF-8"?></span><br><span class="hljs-tag"><<span class="hljs-name">project</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://maven.apache.org/POM/4.0.0"</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema-instance"</span></span><br><span class="hljs-tag"> <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">modelVersion</span>></span>4.0.0<span class="hljs-tag"></<span class="hljs-name">modelVersion</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">parent</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.springframework.boot<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>spring-boot-starter-parent<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">version</span>></span>2.3.1.RELEASE<span class="hljs-tag"></<span class="hljs-name">version</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">relativePath</span>/></span> <span class="hljs-comment"><!-- lookup parent from repository --></span><br> <span class="hljs-tag"></<span class="hljs-name">parent</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>com.example<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>demo<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">version</span>></span>0.0.1-SNAPSHOT<span class="hljs-tag"></<span class="hljs-name">version</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>demo<span class="hljs-tag"></<span class="hljs-name">name</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">description</span>></span>Demo project for Spring Boot<span class="hljs-tag"></<span class="hljs-name">description</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">properties</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">java.version</span>></span>1.8<span class="hljs-tag"></<span class="hljs-name">java.version</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">properties</span>></span><br><br> <span class="hljs-tag"><<span class="hljs-name">dependencies</span>></span><br><br> <span class="hljs-tag"><<span class="hljs-name">dependency</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.springframework.boot<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>spring-boot-starter-web<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">dependency</span>></span><br><br> <span class="hljs-comment"><!-- SpringBootText注解依赖 --></span><br> <span class="hljs-tag"><<span class="hljs-name">dependency</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.springframework.boot<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>spring-boot-starter-test<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">scope</span>></span>test<span class="hljs-tag"></<span class="hljs-name">scope</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">dependency</span>></span><br><br> <span class="hljs-comment"><!-- Junit依赖 --></span><br> <span class="hljs-tag"><<span class="hljs-name">dependency</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>junit<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>junit<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">scope</span>></span>test<span class="hljs-tag"></<span class="hljs-name">scope</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">dependency</span>></span><br><br> <span class="hljs-comment"><!--引入 mybatis-spring-boot-starter 的依赖--></span><br> <span class="hljs-tag"><<span class="hljs-name">dependency</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.mybatis.spring.boot<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>mybatis-spring-boot-starter<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">version</span>></span>2.2.0<span class="hljs-tag"></<span class="hljs-name">version</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">dependency</span>></span><br><br><br> <span class="hljs-tag"><<span class="hljs-name">dependency</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.projectlombok<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>lombok<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">version</span>></span>1.16.8<span class="hljs-tag"></<span class="hljs-name">version</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">dependency</span>></span><br><br> <span class="hljs-tag"><<span class="hljs-name">dependency</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>mysql<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>mysql-connector-java<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">version</span>></span>8.0.20<span class="hljs-tag"></<span class="hljs-name">version</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">dependency</span>></span><br><br><br> <span class="hljs-tag"></<span class="hljs-name">dependencies</span>></span><br><br> <span class="hljs-tag"><<span class="hljs-name">build</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">plugins</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">plugin</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.springframework.boot<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>spring-boot-maven-plugin<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">plugin</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">plugins</span>></span><br><br><br> <span class="hljs-tag"></<span class="hljs-name">build</span>></span><br><br><span class="hljs-tag"></<span class="hljs-name">project</span>></span><br><br></code></pre></div></td></tr></table></figure>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Spring Boot</tag>
<tag>Mybatis</tag>
</tags>
</entry>
<entry>
<title>关于前后端传值中的JSON转化</title>
<link href="/2023/06/02/JSON/"/>
<url>/2023/06/02/JSON/</url>
<content type="html"><![CDATA[<h1 id="前因"><a href="#前因" class="headerlink" title="前因"></a>前因</h1><p>在做Spring Boot整合Mybatis的一个小DEMO的时候,所有的分层,数据库配置都做好了,结果用Postman测试的新增的时候,传给后端一个JSON对象,后端拿不到值,离谱的是只能拿的到<code>guid</code>的值,其他两个却为<code>null</code>。请求体是这样写的:</p><figure class="highlight json"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs json">{<br> <span class="hljs-attr">"guid"</span>: <span class="hljs-string">"13"</span>,<br> <span class="hljs-attr">"dName"</span>: <span class="hljs-string">"小明"</span>,<br> <span class="hljs-attr">"dAge"</span>: <span class="hljs-number">17</span><br>}<br></code></pre></div></td></tr></table></figure><p>接受的对象是这样定义的:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Data</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dog</span> </span>{<br><br> <span class="hljs-keyword">private</span> String guid;<br><br> <span class="hljs-keyword">private</span> String dName;<br><br> <span class="hljs-keyword">private</span> Integer dAge;<br><br>}<br></code></pre></div></td></tr></table></figure><p>在控制层我特意打印出接受的对象供Debug用,结果是这样的:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">Dog(guid=<span class="hljs-number">13</span>, dName=<span class="hljs-keyword">null</span>, dAge=<span class="hljs-keyword">null</span>)<br></code></pre></div></td></tr></table></figure><p>我在此处调试了许久,一直到饭点,我才恋恋不舍地离开,路上也百思不得其解。直到晚上我看到一篇博客后恍然大悟,找到了根本原因。</p><h1 id="后果"><a href="#后果" class="headerlink" title="后果"></a>后果</h1><blockquote><p>在传输过程中dName的N,也从大写变为了小写,在进行测试时,发现所有格式为aBc的,经过JSON传值,都变为了abc,但是aaBc,经过传值后,依然是aaBc,可见,只有形如aBc这样,大写字母前只有一个小写字母的,才会出现JSON强行将大写转为小写的情况。</p></blockquote><p>前人总结的经验教训对于程序员来说参考价值极大,若后人哀之而不鉴之,亦使后人而复哀后人也。</p><p>所以,<strong>不要</strong>这样定义类的属性尽量使用驼峰时前面至少有2个小写字母,比如:<code>dogName</code>,<code>dogAge</code>,或者在实体类的get方法上加上<code>@JsonProperty("dName")</code>。</p><hr><p>全世界的程序员,联合起来!</p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>JSON</tag>
<tag>Spring Boot</tag>
<tag>前后端</tag>
</tags>
</entry>
<entry>
<title>NSGA-II</title>
<link href="/2023/03/01/nsga/"/>
<url>/2023/03/01/nsga/</url>
<content type="html"><![CDATA[<h1 id="NSGA"><a href="#NSGA" class="headerlink" title="NSGA"></a>NSGA</h1><h2 id="支配与非支配"><a href="#支配与非支配" class="headerlink" title="支配与非支配"></a>支配与非支配</h2><p>对于多个目标函数的问题,我们一般不能找到都很满足条件的解,比如手机价格低,肯定性能就差,一部性价比高的手机就能支配绝大多数手机。</p><p>一个解S1,对于任何一个目标函数,适应度都比另一个S2的要大,那么就说这个解S1<code>严格支配</code>S2。当然也有可能某一目标函数的适应度相等,那样就是<code>非严格的支配</code>。对于解S1,目标函数F1适应度优于解S2的目标函数F1适应度,但是在目标函数F2上,解S2优于解S1,这样,我们就称这两个解是互相<code>非支配</code>的。就像七个葫芦兄弟,各有本事,谁也不服谁,他们就是互相非支配的😁。</p><h3 id="如何进行非支配排序?"><a href="#如何进行非支配排序?" class="headerlink" title="如何进行非支配排序?"></a>如何进行非支配排序?</h3><ol><li>设$i=1$</li><li>对于所有的$j=1,2,3$等,且$j$不等于$i$,按照以上定义比较个体$x_i$和$x_j$之间的支配关系</li><li>如果不存在任何一个个体$x_j$支配$x_i$,则$x_i$标记为非支配个体</li><li>令$i=i+1$,转到步骤2,直到找到所有的非支配个体</li></ol><h2 id="种群分层"><a href="#种群分层" class="headerlink" title="种群分层"></a>种群分层</h2><p>通过一次上述步骤,可以得到种群的第一级非支配层,然后忽略这些被标记的个体,再次遵循步骤1到4,就会得到第二支配层。以此类推,直到整个种群被分层。</p><blockquote><p>思考一下时间复杂度是多少?</p></blockquote><p>NSGA是不带任何方法的直接非支配排序。设目标数$(F_1,F_2…F_M)$为$M$,种群个体数为$N$。一个个体进行一次排序的时间复杂度为$MN$(要与$N-1$个体比较,要比较$M$个目标)。第一轮要比较$N$个个体,因此第一轮的时间复杂度为$MN^2$。在最坏的情况下,每轮只有一个个体为当前一轮排序的非支配解,则要$O(N)$轮排序。因此NSGA的时间复杂度为$O(MN^3)$。</p><h2 id="虚拟适应度值"><a href="#虚拟适应度值" class="headerlink" title="虚拟适应度值"></a>虚拟适应度值</h2><p>种群分层结束后,需要给每级指定一个<code>虚拟适应度值</code>,级别越小,说明其中的个体越优,赋予越高的虚拟适应值,反之级别越大,赋予越低的虚拟适应值。这样可以保证在复制操作中级别越小的非支配个体有更多的机会被选择进入下一代,使得算法以最快的速度<strong>收敛</strong>于最优区域。</p><h1 id="NSGA-Ⅱ"><a href="#NSGA-Ⅱ" class="headerlink" title="NSGA-Ⅱ"></a>NSGA-Ⅱ</h1><blockquote><p>对于NSGA的三大改进,使得算法效率大大提升。</p></blockquote><h2 id="快速非支配排序"><a href="#快速非支配排序" class="headerlink" title="快速非支配排序"></a>快速非支配排序</h2><h3 id="如何体现一个快字?"><a href="#如何体现一个快字?" class="headerlink" title="如何体现一个快字?"></a>如何体现一个<strong>快</strong>字?</h3><p>对于每个个体 $i$ 都设有以下两个参数 $n(i)$ 和 $S(i)$, </p><p>$n(i)$ :在种群中支配个体$i$的解个体的<code>数量</code>number。</p><p>$S(i)$ :被个体$i$所支配的解个体的<code>集合</code>set。</p><h3 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h3><ol><li>第一轮初始化个体,$n_p$为0,$S_p$为空集。第一轮与NSGA相同,时间复杂度为$O(MN^2)$。此时将$n_p=0$的个体加入第一级非支配集$F_1$。</li><li>对上一轮集合$F_1$中,取一个个体$p$,在$p$的$S_p$集合中,依次将个体$q$的$n_q$减去一,若此时$n_q=0$,则将其加入下一轮排序的非支配解集$F_2$。这里可以将每一个个体看成一个结构体,里面包含一个变量和一个存放结构体的数组,三层集合嵌套。</li><li>重复步骤2。时间复杂度在最坏情况下,每一次只能取一个到下一层非支配解集,每一轮需要花费$O(N)$,一共需要$O(N-1)$轮,所以总的时间复杂度为$O(MN^2)=O(MN^2)+O(N^2)$。</li></ol><h2 id="拥挤度排序"><a href="#拥挤度排序" class="headerlink" title="拥挤度排序"></a>拥挤度排序</h2><p>为了保持解群体的分布性和多样性,NSGA-II提出使用计算聚集距离。分布距离的使用只是为了在后面建立偏序集所使用,优先权还是在非支配排序上。</p><p>计算方法就是利用前后个体的目标函数差值计算,可以理解为画一个矩形,顶点是前后个体,计算的就是在矩形中间的个体的拥挤度。在这之间要将同一层非支配的个体按照某一目标函数排序。</p><script type="math/tex; mode=display">P[i]_{\text {distance }}=\sum_{k=1}^{r}\left(P[i+1]_{. f_{k}}-P[i-1]_{. f_{k}}\right)</script><p><strong>如果某个方向上的距离很大,就会很大程度上影响总的距离的大小。为了使每个方向上的目标函数对拥挤距离有等效的影响力,需要每个目标函数上的距离要规则化<code>normalized</code>。所以要在最后除以如下变量:</strong></p><script type="math/tex; mode=display">P[i]_{\text {distance }}=\frac{P[i]_{\text {distance }}}{(f^{max}_k-f^{min}_k)}</script><p>在二维目标函数中:</p><script type="math/tex; mode=display">P[i]_{\text {distance }}=\left(P[i+1]_{. f_{1}}-P[i-1]_{f_{1}}\right)+\left(P[i+1]_{. f_{2}}-P[i-1]_{. f_{2}}\right)</script><h2 id="构造偏序集"><a href="#构造偏序集" class="headerlink" title="构造偏序集"></a>构造偏序集</h2><p>经过了排序和拥挤度计算,群体中的每一个个体都有两个属性:非支配序$i{rank}$和拥挤度$id$,则定义偏序关系<script type="math/tex">\prec_{n}</script>为:当满足条件<script type="math/tex">i_{rank}<j_{rank}</script>,或满足<script type="math/tex">i_{rank}=j_{rank}</script>且<script type="math/tex">i_d>j_d</script>时,定义<script type="math/tex">i\prec_{n} j</script>。也就是说:如果两个个体的非支配排序不同,取排序号较小的个体(分层排序时,先被分离出来的个体),如果两个个体在同一级,取周围较不拥挤的个体。</p><h2 id="精英策略"><a href="#精英策略" class="headerlink" title="精英策略"></a>精英策略</h2><p>NSGA-II 算法采用精英策略防止优秀个体的流失,通过将父代和子代所有个体混合后进行非支配排序的方法。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><h3 id="流程"><a href="#流程" class="headerlink" title="流程"></a>流程</h3><p>首先,随机产生规模为$N$的初始种群$P_t$,经过非支配排序、选择、交叉和变异,产生子代种群$Q_t$,并将两个种群联合在一起形成大小为$2N$的种群$R_t$。</p><p>然后,进行快速非支配排序,同时对每个非支配层中的个体进行拥挤度计算,根据非支配关系以及个体的拥挤度选取合适的个体组成新的父代种群$P_{t+1}$ 。</p><p>最后,通过遗传算法的基本操作产生新的子代种群<script type="math/tex">Q_{t+1}</script>,<script type="math/tex">P_{t+1}</script>与<script type="math/tex">Q_{t+1}</script>合并形成新的种群$R_t$,重复以上操作,直到满足程序结束的条件。</p><h3 id="时间复杂度"><a href="#时间复杂度" class="headerlink" title="时间复杂度"></a>时间复杂度</h3><p>NSGA-II的时间花费有三部分构成:</p><ol><li>快速非支配排序(non-dominated sort): </li><li>计算聚集距离(crowding distance assignment):</li><li>构造偏序集(sorting on set):</li></ol><p>所以总时间复杂度为 $O(MN^2)$。</p><p>参考文献:</p><p><a href="https://zhuanlan.zhihu.com/p/407917938">NSGA-II 解读</a></p><p><a href="https://www.bilibili.com/video/BV1ue411c7yK/?spm_id_from=333.999.0.0&vd_source=7b29f4b5d5a2e91632920e2a2814ba3c">纯小白超详细的非支配排序遗传算法原理讲解</a></p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>算法</tag>
</tags>
</entry>
<entry>
<title>模拟二进制交叉算子</title>
<link href="/2023/02/27/sbx/"/>
<url>/2023/02/27/sbx/</url>
<content type="html"><![CDATA[<h1 id="Simulated-Binary-Crossover"><a href="#Simulated-Binary-Crossover" class="headerlink" title="Simulated Binary Crossover"></a>Simulated Binary Crossover</h1><h2 id="什么是SBX"><a href="#什么是SBX" class="headerlink" title="什么是SBX"></a>什么是SBX</h2><p>SBX 是一种实值交叉算法,它模拟具有单点交叉的二进制编码 GA 的行为。</p><h2 id="为什么不直接使用二进制"><a href="#为什么不直接使用二进制" class="headerlink" title="为什么不直接使用二进制"></a>为什么不直接使用二进制</h2><p>许多复杂的现实世界问题都是约束优化问题,特别是对于工业工程领域的问题,标准的遗传算法很难像二进制字符串那样直接应用。</p><p>难以实现任意精度。固定的字符串长度限制了解决方案的精度,例如:我们需要找到最优解,自变量的范围是[1.6,2.9],如果使用二进制,很容易想到用五位来表示从<code>10000</code>到<code>11101</code>,但是,如果我们的最优解恰好就在2.1到2.2中间呢?固定的字符串长度是无法精确到任意小数的。字符串的适当长度是先验不知道的。</p><p>海明悬崖问题。在十进制中15和16相邻,但是如果使用二进制,<code>01111</code>和<code>10000</code>却大相径庭,移动到相邻位置(也许就是最优解),二进制需要改变所有位上的数字,这对于单点交叉算子具有很大难度。</p><h2 id="如何设计一个实值交叉算法"><a href="#如何设计一个实值交叉算法" class="headerlink" title="如何设计一个实值交叉算法"></a>如何设计一个实值交叉算法</h2><p>通过生物仿生学,我们也可以借鉴二进制的交叉算法来模拟实值交叉算法。</p><h3 id="二进制交叉特点"><a href="#二进制交叉特点" class="headerlink" title="二进制交叉特点"></a>二进制交叉特点</h3><p>解码参数值的平均值是相等的。很容易理解,单点交叉只是把相同位置上的数字位置进行是互换,但是他们所代表的权重并没有改变。所以有:</p><script type="math/tex; mode=display">\frac{p_1+p_2}{2}=\frac{c_1+c_2}{2}</script><p>大多数交叉事件对应的<code>扩散因子</code>$\beta$约等于1。(即孩子倾向于与父母亲近)。</p><script type="math/tex; mode=display">\beta=\left| \frac{c_1-c_2}{p_1-p_2} \right| \approx 1</script><p>有三种情况,子代在父代两外侧<code>expanding crossover</code>,$\beta>1$,两内侧<code>contracting crossover</code>,$\beta<1$,或者是子代与父代相等<code>stationary crossover</code>,$\beta=1$。</p><h3 id="扩散因子-beta-的分布"><a href="#扩散因子-beta-的分布" class="headerlink" title="扩散因子$\beta$的分布"></a>扩散因子$\beta$的分布</h3><h2 id="伪代码"><a href="#伪代码" class="headerlink" title="伪代码"></a>伪代码</h2><p><strong>Input:</strong> The parent solutions $P_1,P_2 \in R$</p><p>The distribution index $n \in R$</p><p>/<em>Normally prefer to set $n$ to the range from $2$ to $5$ </em>/</p><p><strong>Output</strong>: The children solution $C_1,C_2 \in R$</p><p>if $P_1>P_2$ then</p><p> Swap $P_1$ and $P_2$</p><p>end;</p><p>Choose a random number $u\in (0,1)$;</p><p>if $u \leq0.5$ then</p><p> $\beta = (2u)^ \frac{1}{n+1}$</p><p>else</p><p> $\beta = (\frac{1}{2-2u})^ \frac{1}{n+1}$</p><p>end;</p><p>$C_1=0.5(P_1+P_2)-0.5\beta(P_2-P_1)$</p><p>$C_2=0.5(P_1+P_2)+0.5\beta(P_2-P_1)$</p><p>Return $C_1,C_2$;</p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>算法</tag>
</tags>
</entry>
<entry>
<title>在文章中使用数学公式:MathJax</title>
<link href="/2022/12/07/mathjax/"/>
<url>/2022/12/07/mathjax/</url>
<content type="html"><![CDATA[<h1 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h1><p>最近在写一些算法方面的博客时,经常会出现比较复杂的数学公式,用键盘敲不出来,即使打出来了,效果也不是太好。最后在网上找到了<code>Mathjax</code>插件,能够比较好的在网页上渲染数学公式,就写一篇博客记录一下使用方法。</p><h1 id="基本语法"><a href="#基本语法" class="headerlink" title="基本语法"></a>基本语法</h1><ul><li><p>在正文中同一行插入LaTeX公式用,使用两个<code>$</code>包含公式可以独立一行</p><ul><li>例如语句为<code>/$ f(x) = ax+b /$</code>(这里别看/,不加/它就给我渲染了😕),显示为$ f(x) = ax+b $</li></ul></li><li><p>另起一行用两个<code>/$$</code>(这里也别看/)包含公式</p><ul><li><p>例如语句为<code>$$ \int_0^tf(x)dx $$</code>,显示为</p><script type="math/tex; mode=display">\int_0^tf(x)dx</script><p>如果想写大一点可以在行首加上<code>\huge</code>标签</p></li></ul></li></ul><h2 id="希腊字母"><a href="#希腊字母" class="headerlink" title="希腊字母"></a>希腊字母</h2><p>可以使用<code>\</code>+希腊字母的单词表示数学公式中的希腊字母</p><p>具体参考文档请看这里<a href="https://oysz2016.github.io/post/8611e6fb.html#Mathjax简介">数学公式语法——Mathjax教程 | 冲弱’s Blog</a></p><h1 id="演示"><a href="#演示" class="headerlink" title="演示"></a>演示</h1><script type="math/tex; mode=display">\Huge f^{'}(x)=ax+b+\pi+\alpha+\beta+\gamma \tag {1.1}</script><figure class="highlight taggerscript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs taggerscript"><span class="hljs-symbol">\h</span>uge f^{'}(x)=ax+b+<span class="hljs-symbol">\p</span>i+<span class="hljs-symbol">\a</span>lpha+<span class="hljs-symbol">\b</span>eta+<span class="hljs-symbol">\g</span>amma <span class="hljs-symbol">\t</span>ag {1.1}<br></code></pre></div></td></tr></table></figure><script type="math/tex; mode=display">\huge 0 \neq 1 \quad x \equiv x \quad 1 = 9 \bmod 2</script><figure class="highlight livescript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs livescript"><span class="hljs-string">\huge</span> <span class="hljs-number">0</span> <span class="hljs-string">\neq</span> <span class="hljs-number">1</span> <span class="hljs-string">\quad</span> x <span class="hljs-string">\equiv</span> x <span class="hljs-string">\quad</span> <span class="hljs-number">1</span> = <span class="hljs-number">9</span> <span class="hljs-string">\bmod</span> <span class="hljs-number">2</span><br></code></pre></div></td></tr></table></figure><script type="math/tex; mode=display">\huge \int_0^xf(x)dx</script><figure class="highlight gcode"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs gcode">\huge \i<span class="hljs-symbol">nt_0</span>^xf<span class="hljs-comment">(x)</span>dx<br></code></pre></div></td></tr></table></figure><script type="math/tex; mode=display">\huge\begin{bmatrix}1&0&0\\0&1&0\\0&0&1\\\end{bmatrix}</script><figure class="highlight dts"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs dts">\huge\begin{bmatrix}<br><span class="hljs-number">1</span><span class="hljs-variable">&0</span><span class="hljs-variable">&0</span>\\<br><span class="hljs-number">0</span><span class="hljs-variable">&1</span><span class="hljs-variable">&0</span>\\<br><span class="hljs-number">0</span><span class="hljs-variable">&0</span><span class="hljs-variable">&1</span>\\<br>\end{bmatrix}<br></code></pre></div></td></tr></table></figure><script type="math/tex; mode=display">\huge\begin{cases}a_1x+b_1y+c_1z=d_1\\a_2x+b_2y+c_2z=d_2\\a_3x+b_3y+c_3z=d_3\\\end{cases}</script><figure class="highlight routeros"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs routeros">\huge\begin{cases}<br>a_1x+b_1y+<span class="hljs-attribute">c_1z</span>=d_1\\<br>a_2x+b_2y+<span class="hljs-attribute">c_2z</span>=d_2\\<br>a_3x+b_3y+<span class="hljs-attribute">c_3z</span>=d_3\\<br>\end{cases}<br></code></pre></div></td></tr></table></figure><script type="math/tex; mode=display">\huge\overbrace{1+2+\cdots+n}^{n个}</script><figure class="highlight taggerscript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs taggerscript"><span class="hljs-symbol">\h</span>uge<span class="hljs-symbol">\o</span>verbrace{1+2+<span class="hljs-symbol">\c</span>dots+n}^{n个}<br></code></pre></div></td></tr></table></figure><script type="math/tex; mode=display">\huge x_{1},x_{2},\ldots,x_{5} \quad x_{1} + x_{2} + \cdots + x_{n}</script><figure class="highlight dust"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs dust"><span class="xml">\huge x_</span><span class="hljs-template-variable">{1}</span><span class="xml">,x_</span><span class="hljs-template-variable">{2}</span><span class="xml">,\ldots,x_</span><span class="hljs-template-variable">{5}</span><span class="xml"> \quad x_</span><span class="hljs-template-variable">{1}</span><span class="xml"> + x_</span><span class="hljs-template-variable">{2}</span><span class="xml"> + \cdots + x_</span><span class="hljs-template-variable">{n}</span><br></code></pre></div></td></tr></table></figure><script type="math/tex; mode=display">\huge \lim_{x \to \infty} x^2_{1} - \int_{x+y}^{5}x\mathrm{d}x + \sum_{n=1}^{20} n^{4} = \prod_{j=1}^{3} y_{j} + \lim_{x \to -2} \frac{x-2}{x}</script><figure class="highlight dust"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs dust"><span class="xml">\huge \lim_</span><span class="hljs-template-variable">{x \to \infty}</span><span class="xml"> x^2_</span><span class="hljs-template-variable">{1}</span><span class="xml"> - \int_</span><span class="hljs-template-variable">{x+y}</span><span class="xml">^</span><span class="hljs-template-variable">{5}</span><span class="xml">x\mathrm</span><span class="hljs-template-variable">{d}</span><span class="xml">x + \sum_</span><span class="hljs-template-variable">{n=1}</span><span class="xml">^</span><span class="hljs-template-variable">{20}</span><span class="xml"> n^</span><span class="hljs-template-variable">{4}</span><span class="xml"> = \prod_</span><span class="hljs-template-variable">{j=1}</span><span class="xml">^</span><span class="hljs-template-variable">{3}</span><span class="xml"> y_</span><span class="hljs-template-variable">{j}</span><span class="xml"> + \lim_</span><span class="hljs-template-variable">{x \to -2}</span><span class="xml"> \frac</span><span class="hljs-template-variable">{x-2}</span><span class="hljs-template-variable">{x}</span><br></code></pre></div></td></tr></table></figure><script type="math/tex; mode=display">\huge \vec{a} + \overrightarrow{AB} + \overleftarrow{DE}</script><figure class="highlight livescript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs livescript"><span class="hljs-string">\huge</span> <span class="hljs-string">\vec{a}</span> + <span class="hljs-string">\overrightarrow{AB}</span> + <span class="hljs-string">\overleftarrow{DE}</span><br></code></pre></div></td></tr></table></figure><script type="math/tex; mode=display">\huge \overline{x+y} \qquad \underline{a+b}</script><figure class="highlight livescript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs livescript"><span class="hljs-string">\huge</span> <span class="hljs-string">\overline{x+y}</span> <span class="hljs-string">\qquad</span> <span class="hljs-string">\underline{a+b}</span><br></code></pre></div></td></tr></table></figure><script type="math/tex; mode=display">\huge 0 \neq 1 \quad x \equiv x \quad 1 = 9 \bmod 2</script><figure class="highlight livescript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs livescript"><span class="hljs-string">\huge</span> <span class="hljs-number">0</span> <span class="hljs-string">\neq</span> <span class="hljs-number">1</span> <span class="hljs-string">\quad</span> x <span class="hljs-string">\equiv</span> x <span class="hljs-string">\quad</span> <span class="hljs-number">1</span> = <span class="hljs-number">9</span> <span class="hljs-string">\bmod</span> <span class="hljs-number">2</span><br></code></pre></div></td></tr></table></figure><p><code>\quad</code>代表一个空格,<code>\qquad</code>代表两个空格</p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Math</tag>
</tags>
</entry>
<entry>
<title>遗传算法</title>
<link href="/2022/10/20/ga/"/>
<url>/2022/10/20/ga/</url>
<content type="html"><![CDATA[<h1 id="遗传算法(Genetic-Algorithm)"><a href="#遗传算法(Genetic-Algorithm)" class="headerlink" title="遗传算法(Genetic Algorithm)"></a>遗传算法(Genetic Algorithm)</h1><h2 id="1-是什么?怎么来的?"><a href="#1-是什么?怎么来的?" class="headerlink" title="1.是什么?怎么来的?"></a>1.是什么?怎么来的?</h2><p>上次我们说到人们从大自然中学习到了许多问题的解决方法,这一次的遗传算法也不例外。生物在自然界中的生存繁衍,显示出了其对自然环境的自适应能力。遗传算法(Genetic Algorithm,简称GA)就是这种生物行为的计算机模拟中令人瞩目的重要成果。基于对生物遗传和进化过程的计算机模拟,遗传算法使得各种人工系统具有优良的自适应能力和优化能力。</p><p><strong>遗传算法所借鉴的生物学基础就是生物的遗传和进化。</strong></p><p>相关术语:</p><div class="table-container"><table><thead><tr><th>术语</th><th>英文</th></tr></thead><tbody><tr><td>种群</td><td>population</td></tr><tr><td>变异</td><td>mutation</td></tr><tr><td>个体</td><td>individual</td></tr><tr><td>交叉</td><td>crossover</td></tr><tr><td>选择</td><td>selection</td></tr><tr><td>繁殖</td><td>reproduction</td></tr><tr><td>代</td><td>generation</td></tr><tr><td>适应度</td><td>fitness</td></tr><tr><td>编码</td><td>coding</td></tr><tr><td>解码</td><td>decoding</td></tr></tbody></table></div><p>我们知道,求最优解或近似最优解的方法主要有三种:</p><p>枚举法、启发式算法和随机搜索算法。</p><p>随着问题种类的不同,以及问题规模的扩大,要寻求到一种能以有限的代价来解决上述最优化问题的通用方法仍是个难题。而遗传算法却为我们解决这类问题提供了一个有效的途径和通用框架,开创了一种新的全局优化搜索算法。</p><h2 id="2-怎么做?"><a href="#2-怎么做?" class="headerlink" title="2.怎么做?"></a>2.怎么做?</h2><p>文字描述,在初始种群中,不断选择个体,将其交叉,变异后依概率选择出适应度最高的个体,并产生新的一代种群。最后不断优化,收敛于最优解附近。</p><p>伪代码描述</p><figure class="highlight c"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c">编码<br>初始化种群<br>计算种群的适应度和累积概率<br><span class="hljs-keyword">while</span> iter < itermax:<br>复制 <span class="hljs-comment">//剔除适应度低的,将适应度好的复制一份</span><br>交叉 <span class="hljs-comment">//二进制数字位数交换</span><br>变异 <span class="hljs-comment">//二进制位数取否</span><br>重新计算适应度和累积概率<br>end<br>解码输出结果<br></code></pre></div></td></tr></table></figure><h3 id="2-1-编码"><a href="#2-1-编码" class="headerlink" title="2.1 编码"></a>2.1 编码</h3><p>编码的主要方式有二进制码,也是最常用的。在这一阶段是将一个变量或多个变量,根据其约束的定义域以及我们要得到的自变量的精度,选择合适的二进制位数将问题编码。</p><p>在随机初始化种群过程中,我们也必须考虑群体的数量是多少,即一个种群是由多少个个体组成的。</p><div class="note note-info"> <p>当个体数量取值较小时,可提高遗传算法的运算速度,但搜索空间分布范围有限,降低了群体的多样性,有可能会引起 遗传算法的早熟现象;<br>当个体数量取值较大时,一方面计算复杂,会使遗传算法的运行效率降低,另一方面,部分高适应值的个体可能被淘汰, 影响交叉。<br>初始种群的一般取值范围是20~100。</p> </div><h3 id="2-2-评价个体适应度"><a href="#2-2-评价个体适应度" class="headerlink" title="2.2 评价个体适应度"></a>2.2 评价个体适应度</h3><p>当为单目标优化问题时,适应度就是该点时的函数值。</p><h3 id="2-3-选择"><a href="#2-3-选择" class="headerlink" title="2.3 选择"></a>2.3 选择</h3><p>可以根据<em>轮盘赌法</em>,计算每一个个体的累积概率。就像一个圆盘上被划分成了不同大小的区域块,面积大的我们选择的几率肯定就高。在计算机中,我们把圆盘模拟成0到1的线段,把线段分为不同大小的小线段,我们可以通过让计算机产生一个0到1的随机数来模拟指针转动过程,落在那个区间里,我们就选择那个相对应的个体。比如在一个种群中,选择概率等于<strong>适应度/总适应度</strong>,累积概率等于上一个个体的累积概率加上自身的选择概率。</p><div class="table-container"><table><thead><tr><th>编号</th><th>适应度</th><th>选择概率</th><th>累积概率</th></tr></thead><tbody><tr><td>1</td><td>8</td><td>0.333</td><td>0.333</td></tr><tr><td>2</td><td>1</td><td>0.042</td><td>0.375</td></tr><tr><td>3</td><td>3</td><td>0.125</td><td>0.5</td></tr><tr><td>4</td><td>12</td><td>0.5</td><td>0.5</td></tr></tbody></table></div><h3 id="2-4-交叉"><a href="#2-4-交叉" class="headerlink" title="2.4 交叉"></a>2.4 交叉</h3><p>最常用和最基本的是单点交叉算子。</p><ol><li>对群体中的个体进行两两随机配对。若群体大小为M,则共有 [ M/2 ]对相互配对的个体组</li><li>每一对相互配对的个体,随机设置某一基因座之后的位置为交叉点。若染色体的长度为l ,则共有(l-1)个可能的交叉点位置</li><li>对每一对相互配对的个体,依设定的交叉概率pc在其交叉点处相互交换两个个体的部分染色体,从而产生出两个新的个体</li></ol><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">单点交叉运算的示例如下所示:<br>A:10110111 00 A1:10110111 11<br>B:00011100 11 B1:00011100 00<br></code></pre></div></td></tr></table></figure><h3 id="2-5-变异"><a href="#2-5-变异" class="headerlink" title="2.5 变异"></a>2.5 变异</h3><p>变异是针对个体的某一个或某一些基因座上的基因值执行的,因此变异概率pm也是针对基因而言,通常来说,这个概率非常小。在二进制编码中,简单来说就是随机将某一位基因位取反。</p><h2 id="3-代码"><a href="#3-代码" class="headerlink" title="3.代码"></a>3.代码</h2><p>解决01背包问题:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><br><span class="hljs-keyword">import</span> java.util.*;<br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GA</span> </span>{<br> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span>[] w = {<span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>};<span class="hljs-comment">//物品重量,最大装载量等于10</span><br> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span>[] v = {<span class="hljs-number">2</span>, <span class="hljs-number">5</span>, <span class="hljs-number">8</span>, <span class="hljs-number">3</span>, <span class="hljs-number">6</span>};<span class="hljs-comment">//物品价格</span><br> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> beginsum = <span class="hljs-number">100</span>; <span class="hljs-comment">//初始种群中个体数量</span><br><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{<br><br> List<String> beginlist = <span class="hljs-keyword">new</span> ArrayList<>();<br> List<String> list = <span class="hljs-keyword">new</span> ArrayList<>();<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < beginsum; i++) {<br> String s = randomlist();<br> beginlist.add(s);<br><br> }<br><br> System.out.println(beginlist);<br> <span class="hljs-keyword">int</span> iter = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">while</span> (iter < <span class="hljs-number">1000</span>) {<br><br> Iterator<String> iterator = beginlist.iterator();<br> <span class="hljs-keyword">while</span> (iterator.hasNext()) {<br> String str = iterator.next();<br> <span class="hljs-keyword">if</span> (!isLegal(str)) {<br> iterator.remove();<br> }<br> }<br><br><br> <span class="hljs-keyword">int</span> len = beginlist.size();<br><br><br> <span class="hljs-keyword">double</span> fitsum = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">double</span>[] cp = <span class="hljs-keyword">new</span> <span class="hljs-keyword">double</span>[beginsum];<span class="hljs-comment">//累积概率cp</span><br> <span class="hljs-keyword">int</span>[] select = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[beginsum];<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < len; i++) {<br> fitsum = fitsum + fitness(beginlist.get(i)); <span class="hljs-comment">//求适应度之和fitsum</span><br> }<br><br><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < len; i++) {<br> <span class="hljs-keyword">if</span> (i == <span class="hljs-number">0</span>) {<br> cp[i] = fitness(beginlist.get(i)) / fitsum;<br> } <span class="hljs-keyword">else</span> {<br> cp[i] = cp[i - <span class="hljs-number">1</span>] + fitness(beginlist.get(i)) / fitsum; <span class="hljs-comment">//求累积概率</span><br> }<br><br> }<br><br><br> <span class="hljs-comment">//筛选</span><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < beginsum; i++) {<br> <span class="hljs-keyword">double</span> random = Math.random();<br> <span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">while</span> (cp[j] < random) {<br> j++;<br> }<br> select[j]++; <span class="hljs-comment">//选择次数</span><br> }<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < beginsum; i++) {<br> Random r = <span class="hljs-keyword">new</span> Random();<br> <span class="hljs-keyword">int</span> random = r.nextInt(beginsum);<br> <span class="hljs-keyword">while</span> (select[random] == <span class="hljs-number">0</span>) {<br> random = r.nextInt(beginsum);<br> }<br> list.add(beginlist.get(random));<span class="hljs-comment">//选择优秀个体</span><br> select[random]--;<br> }<br><br><br> <span class="hljs-comment">//交叉</span><br> <span class="hljs-comment">//随机配对</span><br> <span class="hljs-keyword">boolean</span>[] cross = <span class="hljs-keyword">new</span> <span class="hljs-keyword">boolean</span>[beginsum];<br> <span class="hljs-keyword">int</span>[][] arr = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[beginsum/<span class="hljs-number">2</span>][<span class="hljs-number">2</span>];<span class="hljs-comment">//配对数组</span><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < beginsum/<span class="hljs-number">2</span>; i++) {<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j < <span class="hljs-number">2</span>; j++) {<br> Random r = <span class="hljs-keyword">new</span> Random();<br> <span class="hljs-keyword">int</span> random = r.nextInt(beginsum);<br> <span class="hljs-keyword">while</span> (cross[random] == <span class="hljs-keyword">true</span>) {<br> random = r.nextInt(beginsum);<br> }<br> cross[random] = <span class="hljs-keyword">true</span>;<br> arr[i][j] = random;<br> }<br><br> }<br><br> <span class="hljs-comment">//交换基因片段</span><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i++) {<br> Random r = <span class="hljs-keyword">new</span> Random();<br> String str, str1;<br> <span class="hljs-keyword">int</span> random = r.nextInt(<span class="hljs-number">5</span>);<span class="hljs-comment">//随机设置交叉点位置</span><br> str = list.get(arr[i][<span class="hljs-number">0</span>]);<br> str1 = list.get(arr[i][<span class="hljs-number">1</span>]);<br> String strsub = str.substring(<span class="hljs-number">0</span>, random),<br> strsub1 = str.substring(random),<br> str1sub = str1.substring(<span class="hljs-number">0</span>, random),<br> str1sub1 = str1.substring(random);<br> str = strsub + str1sub1;<br> str1 = str1sub + strsub1;<br><br><br> list.set(arr[i][<span class="hljs-number">0</span>], str);<br> list.set(arr[i][<span class="hljs-number">1</span>], str1);<br><br> }<br><br><br> <span class="hljs-comment">//变异</span><br> <span class="hljs-keyword">if</span> (Math.random() < <span class="hljs-number">0.01</span>) {<br> Random r = <span class="hljs-keyword">new</span> Random();<br> <span class="hljs-keyword">int</span> random = r.nextInt(beginsum);<span class="hljs-comment">//要变异的个体下标</span><br> <span class="hljs-keyword">int</span> random1 = r.nextInt(<span class="hljs-number">5</span>);<span class="hljs-comment">//要变异的基因位置</span><br><br> String str = list.get(random);<br> <span class="hljs-keyword">int</span> ch = ~str.charAt(random1) - <span class="hljs-string">'0'</span>;<br> StringBuilder sb = <span class="hljs-keyword">new</span> StringBuilder(str);<br> sb.setCharAt(random1, (<span class="hljs-keyword">char</span>) ch);<br> str = sb.toString();<br> list.set(random, str);<br><br> }<br><br> beginlist.clear();<span class="hljs-comment">//清空list元素</span><br><br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < beginsum; i++) {<br> beginlist.add(list.get(i));<span class="hljs-comment">//赋值给beginlist</span><br> }<br><br> list.clear();<span class="hljs-comment">//清空list元素</span><br><br> iter++;<br><br> }<br> System.out.println(beginlist);<br> System.out.println(<span class="hljs-string">"最大可以拿总价值为"</span> + fitness(beginlist.get(<span class="hljs-number">0</span>)) + <span class="hljs-string">"的物品,拿法如下(序号代表拿第几个物品):"</span>);<br> System.out.println(beginlist.get(<span class="hljs-number">0</span>));<br><br><br> }<br><br><br> <span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 是否合法</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> str</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isLegal</span><span class="hljs-params">(String str)</span> </span>{<br> <span class="hljs-keyword">int</span> sum = <span class="hljs-number">0</span>, num;<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i++) {<br> num = str.charAt(i) - <span class="hljs-string">'0'</span>;<br> sum = sum + num * w[i];<br> }<br> <span class="hljs-keyword">if</span> (sum > <span class="hljs-number">10</span>)<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;<br> }<br><br> <span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 初始化个体</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">randomlist</span><span class="hljs-params">()</span> </span>{<br> String str = <span class="hljs-string">""</span>;<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i++) {<br> <span class="hljs-keyword">int</span> num = Math.random() > <span class="hljs-number">0.5</span> ? <span class="hljs-number">1</span> : <span class="hljs-number">0</span>;<span class="hljs-comment">//随机产生1,0</span><br> str += String.valueOf(num);<br> }<br> <span class="hljs-keyword">return</span> str;<br> }<br><br> <span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 计算适应度</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> n</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">fitness</span><span class="hljs-params">(String str)</span> </span>{<br> <span class="hljs-keyword">int</span> sum = <span class="hljs-number">0</span>, num;<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">5</span>; i++) {<br> num = str.charAt(i) - <span class="hljs-string">'0'</span>;<br> sum = sum + num * v[i];<br> }<br> <span class="hljs-keyword">return</span> sum;<br> }<br><br><br>}<br><br></code></pre></div></td></tr></table></figure>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>算法</tag>
</tags>
</entry>
<entry>
<title>模拟退火算法</title>
<link href="/2022/10/14/sa/"/>
<url>/2022/10/14/sa/</url>
<content type="html"><![CDATA[<h1 id="模拟退火算法(Simulated-Annealing)"><a href="#模拟退火算法(Simulated-Annealing)" class="headerlink" title="模拟退火算法(Simulated Annealing)"></a>模拟退火算法(Simulated Annealing)</h1><h2 id="1-是什么?怎么来的?"><a href="#1-是什么?怎么来的?" class="headerlink" title="1.是什么?怎么来的?"></a>1.是什么?怎么来的?</h2><p>模拟退火是模拟物理上退火方法,通过N次迭代(退火),逼近函数的上的一个<strong>最值</strong>(最大或者最小值)。尽管可能不是最优解,但得到的是一个可行解。</p><p>很多优秀算法的设计灵感都源于自然界和社会生活当中,比如蚁群算法,遗传算法等等,模拟退火算法也不例外,在物理退火当中,先将物体加温,最后让物体自然冷却,缓缓降温,冷却后可达到最低能量状态,较为柔韧,变得更容易弯折,适用于制作各种饰品。哈哈哈大自然都知道慢工出细活😁!</p><p><strong>物理退火分为三个过程</strong></p><ul><li>加温过程——增强粒子的热运动,消除系统原先可能存在的非均匀态;</li><li>等温过程——对于与环境换热而温度不变的封闭系统,系统状态的自发变化总是朝自由能减少的方向进行,当自由能达到最小时,系统达到平衡态;</li><li>冷却过程——使粒子热运动减弱并渐趋有序,系统能量逐渐下降,从而得到低能的晶体结构。</li></ul><p>最早的想法是由N.Metropolis 等人于1953 年所提出,在当时并沒有受到重视。直到1983 年由Kirkpatrick et al. 提出蒙特卡罗模拟(MonteCarlo Simulated)概念的随机搜寻技巧,利用此方法来求解的组合优化问题时,才使此算法受到重视。</p><h2 id="2-怎么做?"><a href="#2-怎么做?" class="headerlink" title="2.怎么做?"></a>2.怎么做?</h2><h4 id="大方向"><a href="#大方向" class="headerlink" title="大方向"></a>大方向</h4><p>首先,理解一下<strong>大方向</strong>:</p><p>模拟退火就是一种<strong>循环算法</strong>。</p><ol><li>我们先设定一个初始的温度$T$(这个温度会比较高,比如2000)</li><li>每次循环都<strong>退火一次</strong>。(具体怎么操作<strong>后面详解</strong>)</li><li>然后降低T的温度,我们通过让T和一个“降温系数”△ T(一个接近1的小数,比如0.99)相乘,达到<strong>慢慢降低</strong>温度的效果,直到接近于0(我们用eps来代表一个接近0的数(比如0.00001),只要T<eps就可以退出循环了)</li></ol><p>所以总的来说,用伪代码表示退火的流程是这样的:</p><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++"><span class="hljs-keyword">double</span> T = <span class="hljs-number">2000</span>; <span class="hljs-comment">//代表开始的温度</span><br><span class="hljs-keyword">double</span> dT = <span class="hljs-number">0.99</span>; <span class="hljs-comment">//代表系数delta T</span><br><span class="hljs-keyword">double</span> eps = <span class="hljs-number">1e-14</span>; <span class="hljs-comment">//相当于0.0000000000000001</span><br><span class="hljs-keyword">while</span>(T > eps) {<br> <span class="hljs-comment">//--------------</span><br> <span class="hljs-comment">//这里是每一次退火的操作</span><br><span class="hljs-comment">//--------------</span><br> T = T * dT; <span class="hljs-comment">//温度每次下降一点点, T * 0.99</span><br>}<br></code></pre></div></td></tr></table></figure><h4 id="退火详解"><a href="#退火详解" class="headerlink" title="退火详解"></a>退火详解</h4><ol><li><p>第一步,我们需要在找到最值的那个函数里随机找到一点<code>X0</code>,作为我们的初始值。</p></li><li><p>第二步,其实我们可以把寻找最值的过程比喻成在山峦如聚中寻找最高的山峰,我们在上课时,老师也是这么说的,那么问题来了,下一步我们该往哪边走呢?假设只有一个二维的平面,往左还是往右呢?答案应该是随机的吧,因为你也不知道哪边的山会更高。那到底是怎么一个随机法呢?上课的时候这个问题难倒了不少人,同学们各抒己见。结论是:移动的<strong>幅度</strong>和<strong>当前的温度</strong>T有关。<strong>温度T越大,移动的幅度越大。温度T越小,移动的幅度就越小。</strong>这是在模拟粒子无序运动的状态。关于这一点的公式解释,我们会在后面说到。</p></li><li><p>第三步,我们需要接受更好的状态,假设我们移动到了<code>X1</code>处,此时的山峰比刚才的山峰要高,那我们就接受这个值,并将此时的值设为目前的最优解。</p></li><li><p>第四步,如果我们不小心到达了一个更低的山峰,那我们就一定抛弃这个结果吗?不一定,因为可能低谷的再往同一个方向走,就会出现更高的山峰。如果我们鼠目寸光,只盯着当前的局部最优解,很有可能随着温度的下降,移动幅度减小而陷入小山丘中。这也是人生的大智慧啊!而我们如果到了那个更低的山峰,以<strong>一定的概率接受了它</strong>(概率大小和温度以及当前的值的关键程度有关),会在跳转幅度减少之前,<strong>尽可能找到最优点,也就是那更高的山峰</strong>。</p><p>那么我们以多少的概率去接受它呢?我们用一个公式表示(这个公式我们只需记住,这是科学家推导出来的结论):</p><script type="math/tex; mode=display">\Huge e^{\frac{\Delta f}{kT}}</script></li><li><p>第五步,$\Delta f$必须是一个负数,因为概率是属于0到1的,e的0次方等于1,只要是次数大于0,这个值都会大于1,而$k$和$T$都是大于0的。所以只有当次数小于0时,这个值域才和概率相符。</p></li></ol><p>所以总结一下就是:</p><ul><li>随机后的函数值如果结果更好,我们一定选择它</li><li>随机后的函数值如果结果更差,我们以一定的概率接受它</li><li>在前期,由于T的基础数据十分大,分子十分活跃,所以即使我们取到了一个不是那么好的数据,我们接受它的概率也比较大,因为T是分母,k是常数,T变小时,$ \huge e^{\frac{\Delta f }{kT}} $就趋近于0,<strong>而且是始终小于1的</strong></li></ul><h2 id="3-例题:求-sqrt-n"><a href="#3-例题:求-sqrt-n" class="headerlink" title="3.例题:求$ \sqrt {n} $"></a>3.例题:求$ \sqrt {n} $</h2><blockquote><ol><li>rand()函数可以默认取到[0, 32767]内的随机整数</li><li>RAND_MAX = 32767,是常量</li><li>rand()*2-RAND_MAX的范围是[-32767, 32767]</li></ol></blockquote><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string"><bits/stdc++.h></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> <span class="hljs-built_in">std</span>;<br><span class="hljs-comment">//n代表我们最后函数要逼近的值</span><br><span class="hljs-keyword">double</span> n;<br><span class="hljs-comment">//x表示我们随机产生的那个数的平方和n的靠近程度</span><br><span class="hljs-function"><span class="hljs-keyword">double</span> <span class="hljs-title">func</span><span class="hljs-params">(<span class="hljs-keyword">double</span> x)</span> </span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-built_in">fabs</span>(x * x - n);<br>}<br><span class="hljs-keyword">double</span> T = <span class="hljs-number">20000</span>; <span class="hljs-comment">//初始温度,初始温度主要是看题目开始需要跳转的幅度。</span><br><span class="hljs-keyword">double</span> dT = <span class="hljs-number">0.993</span>; <span class="hljs-comment">//变化率,这里需要速度稍微慢一点,写0.995 或者 0.997都可以,但是越靠近1速度就越慢 </span><br><span class="hljs-keyword">const</span> <span class="hljs-keyword">double</span> eps = <span class="hljs-number">1e-14</span>; <span class="hljs-comment">//10的-14次方已经非常小了,写这个大概率没问题</span><br><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">SA</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-comment">//首先随机生成一个点x0,这里我用0代替。</span><br> <span class="hljs-keyword">double</span> x = <span class="hljs-number">0</span>;<br> <span class="hljs-comment">//算出x平方和n的差距f(x0)</span><br> <span class="hljs-keyword">double</span> f = func(x);<br> <span class="hljs-keyword">while</span>(T > eps) {<br> <span class="hljs-comment">//这里x0既可以变小,也可以变大,所以我们正负都要进行一个跳转,算出变换后的点dx</span><br> <span class="hljs-keyword">double</span> dx = x + (<span class="hljs-number">2</span> * rand() - RAND_MAX) * T;<br> <span class="hljs-comment">//但是请注意,dx很明显要保证 >= 0才行,因为算术平方根的定义域是>=0,因此小于0就重新随机</span><br> <span class="hljs-keyword">while</span>(dx < <span class="hljs-number">0</span>) dx = x + (<span class="hljs-number">2</span> * rand() - RAND_MAX) * T;<br> <span class="hljs-comment">//算出变换后的点dx的平方和n的差距,f(dx)</span><br> <span class="hljs-keyword">double</span> df = func(dx);<br> <span class="hljs-comment">//这里就是关键的地方了,很明显我们需要算出来的function值越小,自变量x更加接近那个根号值。</span><br> <span class="hljs-comment">//所以如果新来的值df 比 f更小,我们百分百接受</span><br> <span class="hljs-keyword">if</span>(df < f) {<br> <span class="hljs-comment">//注意更新所有变量</span><br> f = df; x = dx;<br> }<br> <span class="hljs-comment">//否则我们概率接受,这里的需要写 f - df了,因为这样才是负值。负值说明我们并不是贪心接受的,他是不太好的值。</span><br> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(<span class="hljs-built_in">exp</span>((f - df)/T) * RAND_MAX > rand()) {<br> <span class="hljs-comment">//把概率扩大32767倍,使得两边函数值域相同</span><br> <span class="hljs-comment">//注意更新所有变量</span><br> f = df; x = dx;<br> }<br> <span class="hljs-comment">//温度下降一下</span><br> T *= dT;<br> }<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%.8lf"</span>,x);<br>}<br><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span><br><span class="hljs-function"></span>{<br> <span class="hljs-built_in">cin</span> >> n;<br> SA();<br>}<br></code></pre></div></td></tr></table></figure><p>参考文章:<a href="https://www.tocry.cn/archives/simulated-annealing#toc-head-9">速通模拟退火 - Don’t Cry! (tocry.cn)</a></p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>算法</tag>
</tags>
</entry>
<entry>
<title>安装并激活Office 2021</title>
<link href="/2022/08/23/office/"/>
<url>/2022/08/23/office/</url>
<content type="html"><![CDATA[<h1 id="安装并激活Office-2021专业增强版"><a href="#安装并激活Office-2021专业增强版" class="headerlink" title="安装并激活Office 2021专业增强版"></a>安装并激活Office 2021专业增强版</h1><h2 id="卸载原有的Office"><a href="#卸载原有的Office" class="headerlink" title="卸载原有的Office"></a>卸载原有的Office</h2><p>不管你是多么舍不得你的Office,你必须从头开始,并且不能拥有任何残留的回忆,包括注册表,缓存等等。这里我推荐使用<code>Office Tool Plus</code>工具卸载,当然用<code>Geek</code>或者是微软自带的卸载程序先卸载一次当然更好。下面我们简称<code>Office Tool Plus</code>为<code>OTP</code>,给出了官方下载地址和作者的个人博客(包含了新手入门指南)。</p><ul><li><p><a href="https://otp.landian.vip/zh-cn/">Office Tool Plus 官方网站 - 一键部署 Office </a></p></li><li><p><a href="https://www.coolhub.top/">Yerong の小窝 - Love life, like coding. (coolhub.top)</a></p></li></ul><p>下载完成后我们直接运行,找到工具箱,找到移除office,一键清除的快乐谁用谁知道。</p><h2 id="安装最新版的Office"><a href="#安装最新版的Office" class="headerlink" title="安装最新版的Office"></a>安装最新版的Office</h2><p>安装方法有很多,这里我推荐直接使用OTP的部署,简单方便,还能选择只下载自己需要的软件,对于大多数学生来说,Word,Excel,PPT就够用了😎。</p><ol><li>打开OTP,找到部署界面,选择自己需要的版本,这里作者说最好用Microsoft 365,但是我用Office 2021下载也正常使用了。</li><li>选择需要下载的软件。</li><li>选择语言,简体中文。</li><li>后面的高级设置就不用看了,直接部署,Office就开始下载了。</li></ol><p>下载速度很快,大约5分钟左右就完成了。</p><h2 id="使用KMS激活Office"><a href="#使用KMS激活Office" class="headerlink" title="使用KMS激活Office"></a>使用KMS激活Office</h2><p>这里我使用OTP的一键激活,成功过了,但是我的同学使用却失败了,可能有各种各样的问题,这里我推荐使用沧海的一键激活脚本,绿色,轻便,简单。</p><ul><li><a href="https://kms.cangshui.net/">沧水的KMS服务 – Kms|Windows激活|Office激活|Windows下载|Office下载|搭建KMS服务器 (cangshui.net)</a></li></ul><p>点进去之后会有一个良心且伟大的程序员的自述,什么付费的激活都是坑人的骗子😕。</p><ol><li><p>直接点击本地下载。</p></li><li><p>下载完成后使用管理员打开脚本文件,可能会报错,把你的安全卫士全都关掉再试一次。</p></li><li><p>根据提示输入相应的序号,一路按到底。</p></li><li><p>对于本教程,便是b-a。对于其他的小工具,也可以按需使用。</p><figure class="highlight cmd"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs cmd">║【A】KMS激活Windows ║<br>║【B】KMS激活Office ║<br>║【C】清除Windows KMS ║<br>║【D】清除Office KMS ║<br>║【E】查看支持的windows版本 ║<br>╠═════════════════════════════════════其他工具═════════════════════════════════════╣<br>║【<span class="hljs-number">1</span>】去除Office显示“许可证并非正版” ║<br>║【<span class="hljs-number">2</span>】去除快捷方式小箭头 ║<br>║【<span class="hljs-number">3</span>】恢复快捷方式小箭头 ║<br>║【<span class="hljs-number">4</span>】Win11切换旧版桌面右键菜单 ║<br>║【<span class="hljs-number">5</span>】Win11恢复新版桌面右键菜单 ║<br>║【<span class="hljs-number">6</span>】去除快捷方式小盾牌 ║<br>║【<span class="hljs-number">7</span>】恢复快捷方式小盾牌 ║<br>║【<span class="hljs-number">8</span>】去除创建快捷方式时的后缀“-快捷方式” ║<br>║【<span class="hljs-number">9</span>】去除运行可执行文件时的警告弹窗 ║<br>║【<span class="hljs-number">10</span>】向桌面添加“此电脑”图标<br></code></pre></div></td></tr></table></figure></li><li><p>一般来说,最后的激活会成功的,如果实在不行,可以去沧海的博客看看评论区,总会有人和你不期而遇。</p></li><li><p>当然,我们也可以使用OTP的自带的激活,但是不用两个都用,那样就会重复了。在OTP里使用快捷键 Ctrl + Shift + P,打开命令框,复制下面的命令,粘贴后回车(Enter)以执行操作。<code>ospp /insLicID ProPlus2021Volume /sethst:kms.coolhub.top /setprt:1688 /act</code></p></li></ol><h2 id="验证激活并使用"><a href="#验证激活并使用" class="headerlink" title="验证激活并使用"></a>验证激活并使用</h2><p>任意打开一个文档,点击左上角文件,再点击左下角账户,这时我们可以观察到我们的Office 2021已经激活了,以后就可以开心👍😁敲论文了!</p><h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><div class="note note-success"> <p>KMS有效期不只180天,只要你的电脑接入了互联网,每隔7天便会更新一次,相当于永久激活了。再说,你以后工作的公司会买不起Office?🤭</p> </div>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Windows</tag>
<tag>Office</tag>
</tags>
</entry>
<entry>
<title>家书</title>
<link href="/2022/06/28/homeletter/"/>
<url>/2022/06/28/homeletter/</url>
<content type="html"><![CDATA[<p><img src="https://zhaowuya.s3.bitiful.net/homeletter.jpg" alt="一家三口"></p><p>母亲:“涯,这两天与你的谈话,以及你和张老师的通话,让我萌生了想写点东西给你看的念头。”</p><p>第一部分 孤独</p><p>好几年以前,我就在一本杂志上看到这样一句话:孤独,是一个人的狂欢;狂欢,是一群人的孤单。因为我觉得这句话很有道理,也好像触到了我的心弦,所以我便轻而易举地记住了它。当时的我也有很长一段时间的遗憾——-和你一样,遗憾我到向上中学来了没能遇见一个知音,准确地说,是没能遇见一个我满意的好朋友。读书时候的那些朋友,皆都因为地域的不同而变得遥远。就连西斋的K幺幺和洈水的Q妈妈,我都觉得和我不在同一个乡镇而导致我很多时候觉得自己是孤单的。比如,工作上的烦恼我跟她们倾诉起来就很麻烦,我得介绍我们学校的一些背景和大环境。再加上我们各自都有了家,所以约在一起的时间也只能是一年一次,甚至这都很难。那我工作之余没有晚自习的时候我就会觉得要是身边有个知音多好,可以一起散步,一起相约去逛街。可事实就是身边没有啊,怎么办呢,那我就只有降低要求了。C妈妈虽然比我大了十岁,逛街显然不是最好的伴侣,但一起散步聊天还是不错的,年纪大有年纪大的好处。从此,我就和C妈妈成为了好朋友。</p><p>你读六年级之后,我的生活中开始有了一些一个人的空间。那个时候,我一个人在家(你和你爸都有晚自习),我就时而k一会儿歌,时而看一下书或是我自己喜欢的电影电视剧。因为你爸不喜欢唱歌,而且也不喜欢听普通人k歌,那个时候,我就很珍惜一个人在家的时间,早早的关好门窗开始k歌了。那不就是一个人的狂欢吗?你看那麻将馆里的那一群群人,再看看那在一起吃夜宵,喝啤酒,称兄道弟狂欢到半夜的一堆堆人,那不就是一群人的孤单吗?当然这只是我——-一个经过岁月洗礼沉淀的人的认为,还有些阿Q吧!现在的我有了更多的自由时间,我都用来干一些必要的家务话和让我充实快乐的事情。书,我有时候读,有时候看。有声朗读我认为可以既可以训练普通话(练好了好带孙子)又可以排遣孤独。干家务的时候,打开蓝牙音箱听听歌,有时候甚至激来了兴致就k一把。每天坚持练一个小时的琴,练好一首曲子就交给老师检查。弹给自己听,活在自己的小宇宙里。</p><p>你说你没有朋友,那就把你心目中的朋友拆分成几个,那既没有太降低你择友的标准,又可以多交到几个朋友。也就是说你踢足球就找踢足球的朋友,打游戏就找打游戏的朋友,说说知心话或是相约去旅行就找你那三个老铁呀,平时吃饭、逛超市啥的随便一个认识的人都可以搭个伴,只不过与这些流动朋友相处的前期多听少建议罢了,后来也就慢慢熟了,相处也就更随便了。</p><p>第二部分 回报</p><p>我听见你跟你老师的谈话中谈到“回报父母”这个话题,我想我们有必要向你清楚地说明这个问题。我很欣慰你是个善良而又懂事孝顺的孩子。你说你想回报父母,那你想用什么样的方式回报父母呢?是想早点挣钱给父母买一些礼物或是争取以后自己买房呢?这些我们都不好奇,这些也只是你所认为的回报,那你知道我们想要的你最好的回报是什么吗?今天我来告诉你吧!</p><p>不管你以后的工资有多高,我们想要的不是你每年要给我们多大的红包或是多贵重的礼物,而是你所能做到的健康的生活方式。因为只有健康的生活习惯才能换取长久的幸福。和一份贵重的礼物比起来,我们宁愿要你一个不要频繁熬夜的就寝习惯;和一个百万甚至千万的大红包比起来,我们宁愿要你一个日后不抽烟不喝酒的好习惯;和一句节日的问候比起来,我们宁愿要你一个安全驾驶的好习惯······因为钱对于我们来说可多可少,我们的收入已足够我们的开支,再多的钱在我们眼中也只不过是夜空中的小星星——-只是在我们想看的时候就看看的东西,而你的安康才是我们冬日的暖阳——整天都想沐浴其中的暖阳。</p><p>就目前来说,我们并不希望你早早的工作挣钱回报父母,而是希望你丰满你的羽翼,为以后的人生打下坚实的基础,练就过硬的本领才能搏击长空。十六年的学习储备(本科毕业)就去工作会注定了以后飞不了多高。虽然有很多人本科毕业就去工作,以后的路他们也肯定会走下去,但大多数人要困难得多。对这接下来的三年,我们做父母的抱有美好的憧憬,相信你也会不负众望。</p><p>第三部分 规划</p><p>我这里要说的规划指的是我的后半生规划。在维护好身体健康的基础上,我会在街河市按部就班的工作生活,一直到退休。退休以后就到你所生活的城市,在离你不远的地方租一套房。如果你的收入可观的话,买房不用我们的钱,或是少用我们的钱,那我们也许还有可能是买房而不是租房。当然这不重要,我都能接受。买房我有 10%的心理准备,租房的可能性要大得多。因为现在这房价的泡沫还很多,而年轻人积攒三四年的工资远远不够房价首付。几乎所有的孩子三十岁之前买房都是父母帮的。在你居住的小区内住着,有需求就过去给你们做做饭,搞搞卫生,带带孙子;没有需求我就在家过我的晚年生活。当然这只是我个人的规划,你爸爸的还说不准呢,他还想着退休后去打工挣钱呢!</p><p>关于你谈女朋友的事,我们肯定是希望你能遇见一个相互爱慕的女孩,但我们不会去逼婚。我们鼓励你读研的时候碰到心仪的女孩就勇敢的去追,勇敢到不用担心她的家庭条件有多好或是多坏;勇敢到无论她有多优秀,你都会努力提升自己与她站在同一个平台上······谈朋友花钱是很正常的事,不要舍不得,更不要觉得用父母的钱不好意思。我决定把你每个月钱的额度上调,你自己花了也行,攒着也行。不要因为钱阻碍任何事情,不要为钱烦恼。培养大的格局,路才能走的更远。</p>]]></content>
<categories>
<category>生活</category>
</categories>
<tags>
<tag>生活随笔</tag>
</tags>
</entry>
<entry>
<title>Spring Security笔记</title>
<link href="/2022/04/16/springsecurity/"/>
<url>/2022/04/16/springsecurity/</url>
<content type="html"><![CDATA[<h1 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h1><p><code>Spring</code>是非常流行和成功的Java应用开发框架,Spring Security正是Spring家族中的成员。Spring Security基于Spring框架,提供了一套Web应用安全性的完整解决方案。</p><p><code>Spring Security</code>是Spring家族中的一个安全管理框架,实际上,在<code>Spring Boot</code>出现之前,Spring Security就已经发展了多年了,但是使用的并不多,安全管理这个领域,一直是<code>Shiro</code>的天下。相对于Shiro,在SSM中整合Spring Security都是比较麻烦的操作,所以,Spring Security虽然功能比 Shiro 强大,但是使用反而没有Shiro多(Shiro虽然功能没有Spring Security多,但是对于大部分项目而言,Shiro也够用了)。自从有了Spring Boot之后,Spring Boot对于Spring Security提供了自动化配置方案,可以使用更少的配置来使用Spring Security。</p><p>因此,一般来说,常见的安全管理技术栈的组合是这样的:</p><ul><li><p>SSM + Shiro</p></li><li><p>Spring Boot/Spring Cloud + Spring Security</p></li></ul><p><strong>以上只是一个推荐的组合而已,如果单纯从技术上来说,无论怎么组合,都是可行的。</strong></p><h1 id="快速开始"><a href="#快速开始" class="headerlink" title="快速开始"></a>快速开始</h1><ol><li><p>使用IDEA初始化一个最简单的Spring Boot项目。</p></li><li><p>引入依赖:</p><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">dependency</span>></span><br><span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.springframework.boot<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>spring-boot-starter-security<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br><span class="hljs-tag"></<span class="hljs-name">dependency</span>></span><br></code></pre></div></td></tr></table></figure><div class="note note-warning"> <p>注意:Spring Boot和Spring Security之间版本有依赖关系,各个版本不一样,详细请参考<a href="https://www.docs4dev.com/docs/zh/spring-security/5.1.2.RELEASE/reference/get-spring-security.html#release-numbering">官方文档</a>,作者Spring Boot版本是2.6,对应的Spring Security版本是5.6,由于Spring Boot提供了一个Maven BOM来Management依赖版本,因此无需指定版本。如果您想覆盖Spring Security版本,可以通过提供Maven属性来实现。</p> </div></li><li><p>编写Controller类。</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@RestController</span><br><span class="hljs-meta">@RequestMapping("/test")</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestController</span> </span>{<br><br> <span class="hljs-meta">@GetMapping("/hello")</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">hello</span><span class="hljs-params">()</span></span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-string">"hello security"</span>;<br> }<br>}<br></code></pre></div></td></tr></table></figure></li><li><p>为了防止端口冲突,最好在<code>resources</code>包下的配置文件<code>application.properties</code>里将端口号设置为其他端口号,我这里设置为8111。</p><figure class="highlight properties"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs properties"><span class="hljs-meta">server.port</span>=<span class="hljs-string">8111</span><br></code></pre></div></td></tr></table></figure></li><li><p>启动Spring Boot,在浏览器输入<a href="http://localhost:8111/test/hello">localhost:8111/test/hello</a>发现会有一个登录界面,需要输入用户名和密码。这时打开控制台发现里面有一个密码:</p><figure class="highlight plain"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs shel">Using generated security password: b1caa423-4f6c-4522-912e-79718ce46a7e<br><br>This generated password is for development use only. Your security configuration must be updated before running your application in production.<br></code></pre></div></td></tr></table></figure><p>默认的用户名是<code>user</code>,密码就是控制台里生成的密码,然后就能访问资源了😁!浏览器页面上会输出<code>hello security</code>。</p></li></ol><h1 id="基本原理"><a href="#基本原理" class="headerlink" title="基本原理"></a>基本原理</h1><p>Spring Security本质是是一个<strong>过滤器链</strong>。</p><div class="table-container"><table><thead><tr><th>过滤器</th><th>过滤器作用</th><th>默认是否加载</th></tr></thead><tbody><tr><td>ChannelProcessingFilter</td><td>过滤请求协议 HTTP 、HTTPS</td><td>NO</td></tr><tr><td><code>WebAsyncManagerIntegrationFilter</code></td><td>将 WebAsyncManger 与 SpringSecurity 上下文进行集成</td><td>YES</td></tr><tr><td><code>SecurityContextPersistenceFilter</code></td><td>在处理请求之前,将安全信息加载到 SecurityContextHolder 中</td><td>YES</td></tr><tr><td><code>HeaderWriterFilter</code></td><td>处理头信息加入响应中</td><td>YES</td></tr><tr><td>CorsFilter</td><td>处理跨域问题</td><td>NO</td></tr><tr><td><code>CsrfFilter</code></td><td>处理 CSRF 攻击</td><td>YES</td></tr><tr><td><code>LogoutFilter</code></td><td>处理注销登录</td><td>YES</td></tr><tr><td>OAuth2AuthorizationRequestRedirectFilter</td><td>处理 OAuth2 认证重定向</td><td>NO</td></tr><tr><td>Saml2WebSsoAuthenticationRequestFilter</td><td>处理 SAML 认证</td><td>NO</td></tr><tr><td>X509AuthenticationFilter</td><td>处理 X509 认证</td><td>NO</td></tr><tr><td>AbstractPreAuthenticatedProcessingFilter</td><td>处理预认证问题</td><td>NO</td></tr><tr><td>CasAuthenticationFilter</td><td>处理 CAS 单点登录</td><td>NO</td></tr><tr><td>OAuth2LoginAuthenticationFilter</td><td>处理 OAuth2 认证</td><td>NO</td></tr><tr><td>Saml2WebSsoAuthenticationFilter</td><td>处理 SAML 认证</td><td>NO</td></tr><tr><td><code>UsernamePasswordAuthenticationFilter</code></td><td>处理表单登录</td><td>YES</td></tr><tr><td>OpenIDAuthenticationFilter</td><td>处理 OpenID 认证</td><td>NO</td></tr><tr><td><code>DefaultLoginPageGeneratingFilter</code></td><td>配置默认登录页面</td><td>YES</td></tr><tr><td><code>DefaultLogoutPageGeneratingFilter</code></td><td>配置默认注销页面</td><td>YES</td></tr><tr><td>ConcurrentSessionFilter</td><td>处理 Session 有效期</td><td>NO</td></tr><tr><td>DigestAuthenticationFilter</td><td>处理 HTTP 摘要认证</td><td>NO</td></tr><tr><td>BearerTokenAuthenticationFilter</td><td>处理 OAuth2 认证的 Access Token</td><td>NO</td></tr><tr><td><code>BasicAuthenticationFilter</code></td><td>处理 HttpBasic 登录</td><td>YES</td></tr><tr><td><code>RequestCacheAwareFilter</code></td><td>处理请求缓存</td><td>YES</td></tr><tr><td><code>SecurityContextHolder<br />AwareRequestFilter</code></td><td>包装原始请求</td><td>YES</td></tr><tr><td>JaasApiIntegrationFilter</td><td>处理 JAAS 认证</td><td>NO</td></tr><tr><td><code>RememberMeAuthenticationFilter</code></td><td>处理 RememberMe 登录</td><td>NO</td></tr><tr><td><code>AnonymousAuthenticationFilter</code></td><td>配置匿名认证</td><td>YES</td></tr><tr><td>OAuth2AuthorizationCodeGrantFilter</td><td>处理OAuth2认证中授权码</td><td>NO</td></tr><tr><td><code>SessionManagementFilter</code></td><td>处理 session 并发问题</td><td>YES</td></tr><tr><td><code>ExceptionTranslationFilter</code></td><td>处理认证/授权中的异常</td><td>YES</td></tr><tr><td><code>FilterSecurityInterceptor</code></td><td>处理授权相关</td><td>YES</td></tr><tr><td>SwitchUserFilter</td><td>处理账户切换</td><td>NO</td></tr></tbody></table></div><h1 id="Web权限方案"><a href="#Web权限方案" class="headerlink" title="Web权限方案"></a>Web权限方案</h1><h2 id="设置登录用户名和密码"><a href="#设置登录用户名和密码" class="headerlink" title="设置登录用户名和密码"></a>设置登录用户名和密码</h2><h3 id="通过配置文件"><a href="#通过配置文件" class="headerlink" title="通过配置文件"></a>通过配置文件</h3><p>在<code>application.properties</code>里面加上用户名和密码。</p><figure class="highlight properties"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs properties"><span class="hljs-meta">spring.security.user.name</span>=<span class="hljs-string">zwy</span><br><span class="hljs-meta">spring.security.user.password</span>=<span class="hljs-string">123</span><br></code></pre></div></td></tr></table></figure><h3 id="通过配置类"><a href="#通过配置类" class="headerlink" title="通过配置类"></a>通过配置类</h3><p>创建一个<code>config</code>包,在包里创建一个配置类<code>SecurityConfig</code>,并实现配置。</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Configuration</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecurityConfig</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">WebSecurityConfigurerAdapter</span> </span>{<br> <span class="hljs-meta">@Override</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(AuthenticationManagerBuilder auth)</span> <span class="hljs-keyword">throws</span> Exception </span>{<br> BCryptPasswordEncoder passwordEncoder = <span class="hljs-keyword">new</span> BCryptPasswordEncoder();<br> String password = passwordEncoder.encode(<span class="hljs-string">"123"</span>);<br> auth.inMemoryAuthentication().withUser(<span class="hljs-string">"lucy"</span>).password(password).roles(<span class="hljs-string">"admin"</span>);<br> }<br> <br> <span class="hljs-meta">@Bean</span><br> <span class="hljs-function">PasswordEncoder <span class="hljs-title">password</span><span class="hljs-params">()</span></span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BCryptPasswordEncoder();<br> }<br>}<br></code></pre></div></td></tr></table></figure><h3 id="自定义编写实现类"><a href="#自定义编写实现类" class="headerlink" title="自定义编写实现类"></a>自定义编写实现类</h3><p>实现<code>UserDetailsService</code>接口,<strong>这一步是非常重要的!!</strong> 重写接口<code>loadUserByUsername</code>这个方法,在其中完成数据库的查询工作,并将得到的user返回就可以了。</p><h4 id="引入依赖"><a href="#引入依赖" class="headerlink" title="引入依赖"></a>引入依赖</h4><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-comment"><!--mybatis-plus--></span><br><span class="hljs-tag"><<span class="hljs-name">dependency</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>com.baomidou<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>mybatis-plus-boot-starter<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">version</span>></span>3.5.1<span class="hljs-tag"></<span class="hljs-name">version</span>></span><br><span class="hljs-tag"></<span class="hljs-name">dependency</span>></span><br><span class="hljs-comment"><!--mysql--></span><br><span class="hljs-tag"><<span class="hljs-name">dependency</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>mysql<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>mysql-connector-java<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br><span class="hljs-tag"></<span class="hljs-name">dependency</span>></span><br><span class="hljs-comment"><!--lombok 用来简化实体类--></span><br><span class="hljs-tag"><<span class="hljs-name">dependency</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.projectlombok<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>lombok<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br><span class="hljs-tag"></<span class="hljs-name">dependency</span>></span><br></code></pre></div></td></tr></table></figure><h4 id="编写实体类"><a href="#编写实体类" class="headerlink" title="编写实体类"></a>编写实体类</h4><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Data</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Users</span> </span>{<br> <span class="hljs-keyword">private</span> Integer id;<br> <span class="hljs-keyword">private</span> String username;<br> <span class="hljs-keyword">private</span> String password;<br>}<br></code></pre></div></td></tr></table></figure><h4 id="配置数据源"><a href="#配置数据源" class="headerlink" title="配置数据源"></a>配置数据源</h4><figure class="highlight properties"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs properties"><span class="hljs-meta">spring.datasource.driver-class-name</span>=<span class="hljs-string">com.mysql.cj.jdbc.Driver</span><br><span class="hljs-meta">spring.datasource.url</span>=<span class="hljs-string">jdbc:mysql://localhost/springsecurity?useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai</span><br><span class="hljs-meta">spring.datasource.username</span>=<span class="hljs-string">root</span><br><span class="hljs-meta">spring.datasource.password</span>=<span class="hljs-string">mysql1970s</span><br></code></pre></div></td></tr></table></figure><h4 id="使用MP定义映射"><a href="#使用MP定义映射" class="headerlink" title="使用MP定义映射"></a>使用MP定义映射</h4><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Repository</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UsersMapper</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseMapper</span><<span class="hljs-title">Users</span>> </span>{<br><br>}<br></code></pre></div></td></tr></table></figure><h4 id="实现UserDetailsService"><a href="#实现UserDetailsService" class="headerlink" title="实现UserDetailsService"></a>实现UserDetailsService</h4><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><br><span class="hljs-meta">@Service("userDetailService")</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserDetailsServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">UserDetailsService</span> </span>{<br> <span class="hljs-meta">@Autowired</span><br> <span class="hljs-keyword">private</span> UsersMapper usersMapper;<br><br><br> <span class="hljs-comment">//调用usersMapper方法</span><br> <span class="hljs-meta">@Override</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> UserDetails <span class="hljs-title">loadUserByUsername</span><span class="hljs-params">(String s)</span> <span class="hljs-keyword">throws</span> UsernameNotFoundException </span>{<br> QueryWrapper<Users> wrapper = <span class="hljs-keyword">new</span> QueryWrapper();<br> wrapper.eq(<span class="hljs-string">"username"</span>, s);<br> Users users = usersMapper.selectOne(wrapper);<br> <span class="hljs-keyword">if</span> (users == <span class="hljs-keyword">null</span>) {<br> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UsernameNotFoundException(<span class="hljs-string">"用户名不存在!"</span>);<br> }<br> System.out.println(users);<br> List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList(<span class="hljs-string">"role"</span>);<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> User(users.getUsername(), users.getPassword(), auths);<br> }<br>}<br></code></pre></div></td></tr></table></figure><h4 id="写入数据"><a href="#写入数据" class="headerlink" title="写入数据"></a>写入数据</h4><p>建立一个表,添加一条记录:</p><figure class="highlight sql"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-string">`users`</span> <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'zwy'</span>, <span class="hljs-string">'{noop}123'</span>);<br></code></pre></div></td></tr></table></figure><div class="note note-info"> <p>这里为了测试方便,并没有给数据库里的密码加密,但是在正常开发里,是必须加密的。</p> </div><p>为什么要加密?2011年12月21日,有人在网络上公开了一个包含600万个CSDN用户资料的数据库,数据全部为明文储存,包含用户名、密码以及注册邮箱。事件发生后CSDN在微博、官方网站等渠道发出了声明,解释说此数据库系2009年备份所用,因不明原因泄露,已经向警方报案,后又在官网发出了公开道歉信。在接下来的十多天里,金山、网易、京东、当当、新浪等多家公司被卷入到这次事件中。整个事件中最触目惊心的莫过于CSDN把用户密码明文存储,由于很多用户是多个网站共用一个密码,因此一个网站密码泄露就会造成很大的安全隐患。由于有了这么多前车之鉴,我们现在做系统时,密码都要加密处理。</p><p>这次泄密,也留下了一些有趣的事情,特别是对于广大程序员设置密码这一项。人们从CSDN泄密的文件中,发现了一些好玩的密码,例如如下这些:</p><ul><li><code>ppnn13%dkstFeb.1st</code> 这段密码的中文解析是:娉娉袅袅十三余,豆蔻梢头二月初。</li><li><code>csbt34.ydhl12s</code> 这段密码的中文解析是:池上碧苔三四点,叶底黄鹂一两声。</li></ul><p>等等不一而足,你会发现很多程序员的人文素养还是非常高的,让人啧啧称奇🙌。</p><p>小坑:在一开始的时候,我直接存入数据库的密码是123,但是这里会报错<code>There is no PasswordEncoder mapped for the id “null”</code>,后来查资料后发现,在Spring Security中密码的存储格式是“{id}…………”。前面的id是加密方式,id可以是bcrypt、sha256等,不加密就是noop,后面跟着的是加密后的密码。也就是说,程序拿到传过来的密码的时候,会首先查找被“{”和“}”包括起来的id,来确定后面的密码是被怎么样加密的,如果找不到就认为id是null。</p><h4 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h4><p>在登录界面输入<code>zwy</code>和<code>123</code>就可以正常访问资源了👍!</p><h2 id="自定义登录界面和规则"><a href="#自定义登录界面和规则" class="headerlink" title="自定义登录界面和规则"></a>自定义登录界面和规则</h2><p>使用<code>Thymeleaf</code>模板引擎简化开发:</p><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">dependency</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.springframework.boot<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>spring-boot-starter-thymeleaf<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br><span class="hljs-tag"></<span class="hljs-name">dependency</span>></span><br></code></pre></div></td></tr></table></figure><p>自定义登录控制器:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Controller</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginController</span> </span>{<br><br> <span class="hljs-meta">@RequestMapping("/login.html")</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">login</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-string">"login"</span>;<br> }<br>}<br></code></pre></div></td></tr></table></figure><p>前端页面:</p><figure class="highlight html"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs html"><span class="hljs-meta"><!DOCTYPE <span class="hljs-meta-keyword">html</span>></span><br><span class="hljs-tag"><<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"https://www.thymeleaf.org"</span>></span><br><span class="hljs-tag"><<span class="hljs-name">head</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">title</span>></span>登录<span class="hljs-tag"></<span class="hljs-name">title</span>></span><br><span class="hljs-tag"></<span class="hljs-name">head</span>></span><br><span class="hljs-tag"><<span class="hljs-name">body</span>></span><br><span class="hljs-tag"><<span class="hljs-name">h1</span>></span>用户登录<span class="hljs-tag"></<span class="hljs-name">h1</span>></span><br><span class="hljs-tag"><<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">th:action</span>=<span class="hljs-string">"@{/doLogin}"</span>></span><br> 用户名:<span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"uname"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>/></span><span class="hljs-tag"><<span class="hljs-name">br</span>></span><br> 密码:<span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"passwd"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>/></span><span class="hljs-tag"><<span class="hljs-name">br</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"登录"</span>/></span><br><span class="hljs-tag"></<span class="hljs-name">form</span>></span><br><span class="hljs-tag"></<span class="hljs-name">body</span>></span><br><span class="hljs-tag"></<span class="hljs-name">html</span>></span><br></code></pre></div></td></tr></table></figure><p><strong>需要注意的是</strong></p><ul><li>登录表单 method 必须为 <code>post</code>,action 的请求路径为 <code>/doLogin</code></li><li>用户名的 name 属性为 <code>uname</code></li><li>密码的 name 属性为 <code>passwd</code> ,后面会用到属性</li></ul><p>配置配置类:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Configuration</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebSecurityConfigurer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">WebSecurityConfigurerAdapter</span> </span>{<br> <span class="hljs-meta">@Override</span><br> <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception </span>{<br> http.authorizeHttpRequests()<br> .mvcMatchers(<span class="hljs-string">"/index"</span>).permitAll()<span class="hljs-comment">//放行</span><br> .mvcMatchers(<span class="hljs-string">"/login.html"</span>).permitAll()<span class="hljs-comment">//放行</span><br> .anyRequest().authenticated()<span class="hljs-comment">//其他都要认证</span><br> .and()<br> .formLogin()<br> .loginPage(<span class="hljs-string">"/login.html"</span>)<span class="hljs-comment">//指定登录界面</span><br> .loginProcessingUrl(<span class="hljs-string">"/doLogin"</span>)<span class="hljs-comment">//执行登录控制器,不用自己写👍</span><br> .usernameParameter(<span class="hljs-string">"uname"</span>)<span class="hljs-comment">//用户名参数</span><br> .passwordParameter(<span class="hljs-string">"passwd"</span>)<span class="hljs-comment">//密码变量</span><br> .successForwardUrl(<span class="hljs-string">"/index"</span>)<span class="hljs-comment">//跳转到指定页面 8080/doLogin</span><br><span class="hljs-comment">// .defaultSuccessUrl("/index")//重定向,优先跳转到之前请求的路径,如果不存在了,就到指定页面</span><br> .failureUrl(<span class="hljs-string">"/login.html"</span>)<span class="hljs-comment">//认证失败还是登录界面</span><br> .and()<br> .csrf().disable();<br><br> }<br>}<br></code></pre></div></td></tr></table></figure><p>successForwardUrl 、defaultSuccessUrl 这两个方法都可以实现成功之后跳转</p><ul><li>successForwardUrl 默认使用 <code>forward</code>跳转 <strong>注意:不会跳转到之前请求路径</strong></li><li>defaultSuccessUrl 默认使用 <code>redirect</code> 跳转 <strong>注意:如果之前请求路径,会有优先跳转之前请求路径,可以传入第二个参数进行修改</strong></li></ul><h2 id="自定义登录成功处理"><a href="#自定义登录成功处理" class="headerlink" title="自定义登录成功处理"></a>自定义登录成功处理</h2><p>有时候页面跳转并不能满足我们,特别是在前后端分离开发中就不需要成功之后跳转页面。只需要给前端返回一个 JSON 通知登录成功还是失败与否。这个时候可以通过自定义 <code>AuthenticationSucccessHandler</code> 实现。</p><p>自定义 AuthenticationSuccessHandler 实现:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyAuthenticationSuccessHandler</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">AuthenticationSuccessHandler</span> </span>{<br> <span class="hljs-meta">@Override</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onAuthenticationSuccess</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Authentication authentication)</span> <span class="hljs-keyword">throws</span> IOException, ServletException </span>{<br> Map<String, Object> result = <span class="hljs-keyword">new</span> HashMap<String, Object>();<br> result.put(<span class="hljs-string">"msg"</span>, <span class="hljs-string">"登录成功"</span>);<br> result.put(<span class="hljs-string">"status"</span>, <span class="hljs-number">200</span>);<br> response.setContentType(<span class="hljs-string">"application/json;charset=UTF-8"</span>);<br> String s = <span class="hljs-keyword">new</span> ObjectMapper().writeValueAsString(result);<br> response.getWriter().println(s);<br> }<br>}<br></code></pre></div></td></tr></table></figure><p>配置 AuthenticationSuccessHandler:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@Configuration</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebSecurityConfigurer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">WebSecurityConfigurerAdapter</span> </span>{<br> <span class="hljs-meta">@Override</span><br> <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception </span>{<br> http.authorizeHttpRequests()<br> <span class="hljs-comment">//...</span><br> .and()<br> .formLogin()<br> <span class="hljs-comment">//...</span><br> .successHandler(<span class="hljs-keyword">new</span> MyAuthenticationSuccessHandler())<br> .failureUrl(<span class="hljs-string">"/login.html"</span>)<br> .and()<br> .csrf().disable();<span class="hljs-comment">//这里先关闭 CSRF</span><br> }<br>}<br></code></pre></div></td></tr></table></figure><p>这时我们登录成功后,就会返回一个JSON数组:</p><figure class="highlight json"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs json"><span class="hljs-comment">// http://localhost:8080/doLogin</span><br>{<br> <span class="hljs-attr">"msg"</span>: <span class="hljs-string">"登录成功"</span><br> <span class="hljs-string">"status"</span>: <span class="hljs-number">200</span><br>}<br></code></pre></div></td></tr></table></figure><h2 id="自定义登录失败处理"><a href="#自定义登录失败处理" class="headerlink" title="自定义登录失败处理"></a>自定义登录失败处理</h2><h2 id="无状态登录"><a href="#无状态登录" class="headerlink" title="无状态登录"></a>无状态登录</h2><h4 id="什么是有状态"><a href="#什么是有状态" class="headerlink" title="什么是有状态"></a>什么是有状态</h4><p>有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如 Tomcat 中的 Session。例如登录:用户登录后,我们把用户的信息保存在服务端 session 中,并且给用户一个 cookie 值,记录对应的 session,然后下次请求,用户携带 cookie 值来(这一步有浏览器自动完成),我们就能识别到对应 session,从而找到用户的信息。这种方式目前来看最方便,但是也有一些缺陷,如下:</p><ul><li>服务端保存大量数据,增加服务端压力</li><li>服务端保存用户状态,不支持集群化部署</li></ul><h4 id="什么是无状态"><a href="#什么是无状态" class="headerlink" title="什么是无状态"></a>什么是无状态</h4><p>微服务集群中的每个服务,对外提供的都使用 RESTful 风格的接口。而 RESTful 风格的一个最重要的规范就是:服务的无状态性,即:</p><ul><li>服务端不保存任何客户端请求者信息</li><li>客户端的每次请求必须具备自描述信息,通过这些信息识别客户端身份</li></ul><p>那么这种无状态性有哪些好处呢?</p><ul><li>客户端请求不依赖服务端的信息,多次请求不需要必须访问到同一台服务器</li><li>服务端的集群和状态对客户端透明</li><li>服务端可以任意的迁移和伸缩(可以方便的进行集群化部署)</li><li>减小服务端存储压力</li></ul><h4 id="如何实现无状态"><a href="#如何实现无状态" class="headerlink" title="如何实现无状态"></a>如何实现无状态</h4><p>无状态登录的流程:</p><ul><li>首先客户端发送账户名/密码到服务端进行认证</li><li>认证通过后,服务端将用户信息加密并且编码成一个 token,返回给客户端</li><li>以后客户端每次发送请求,都需要携带认证的 token</li><li>服务端对客户端发送来的 token 进行解密,判断是否有效,并且获取用户登录信息</li></ul>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Java</tag>
<tag>JavaWeb</tag>
<tag>Spring</tag>
</tags>
</entry>
<entry>
<title>Filter过滤器和Listener监听器</title>
<link href="/2022/04/16/filter/"/>
<url>/2022/04/16/filter/</url>
<content type="html"><![CDATA[<h1 id="Filter"><a href="#Filter" class="headerlink" title="Filter"></a>Filter</h1><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>Filter也称之为过滤器,它是Servlet技术中最实用的技术,web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。</p><p>它主要用于对用户请求进行预处理,也可以对HttpServletResponse 进行后处理。使用Filter 的完整流程:Filter 对用户请求进行预处理,接着将请求交给Servlet 进行处理并生成响应,最后Filter 再对服务器响应进行后处理。</p><h2 id="细节"><a href="#细节" class="headerlink" title="细节"></a>细节</h2><h3 id="注解配置"><a href="#注解配置" class="headerlink" title="注解配置"></a>注解配置</h3><p>设置<code>dispatcherTypes</code>属性:</p><ul><li>REQUEST:默认值,浏览器直接请求资源</li><li>FORWARD:转发访问资源</li><li>INCLUDE:包含访问资源</li><li>ERROR:错误跳转资源</li><li>ASYNC:异步访问资源</li></ul><h3 id="web-xml配置"><a href="#web-xml配置" class="headerlink" title="web.xml配置"></a>web.xml配置</h3><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">filter</span>></span><br><span class="hljs-tag"><<span class="hljs-name">filter-name</span>></span>demo1<span class="hljs-tag"></<span class="hljs-name">filter-name</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">filter-class</span>></span>cn.filter.FilterDemo1<span class="hljs-tag"></<span class="hljs-name">filter-class</span>></span><br><span class="hljs-tag"></<span class="hljs-name">filter</span>></span><br><span class="hljs-tag"><<span class="hljs-name">filter-mapping</span>></span><br><span class="hljs-tag"><<span class="hljs-name">filter-name</span>></span>demo1<span class="hljs-tag"></<span class="hljs-name">filter-name</span>></span><br> <span class="hljs-comment"><!-- 拦截路径 --></span><br> <span class="hljs-tag"><<span class="hljs-name">url-pattern</span>></span>/*<span class="hljs-tag"></<span class="hljs-name">url-pattern</span>></span><br><span class="hljs-tag"></<span class="hljs-name">filter-mapping</span>></span><br></code></pre></div></td></tr></table></figure><h3 id="过滤器执行流程"><a href="#过滤器执行流程" class="headerlink" title="过滤器执行流程"></a>过滤器执行流程</h3><h3 id="过滤器生命周期方法"><a href="#过滤器生命周期方法" class="headerlink" title="过滤器生命周期方法"></a>过滤器生命周期方法</h3><p><code>init</code>方法,在服务器启动后,会创建Filter对象,然后调用init方法,只会执行一次,用于加载资源。</p><p><code>doFilter</code>方法,每一次请求被拦截时,会执行,执行多次。</p><p><code>destroy</code>方法,在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法,只执行一次。</p><h3 id="拦截方式"><a href="#拦截方式" class="headerlink" title="拦截方式"></a>拦截方式</h3><ul><li>具体资源路径:/index.jsp 只有访问index.jsp资源时,过滤器才会被执行</li><li>拦截目录:/user/* 访问/user下的所有资源时,过滤器都会被执行</li><li>后缀名拦截:*.jsp 访问所有后缀名为jsp资源时,过滤器都会被执行</li></ul><h3 id="过滤器链"><a href="#过滤器链" class="headerlink" title="过滤器链"></a>过滤器链</h3><ul><li><p>执行顺序</p><ol><li>过滤器1</li><li>过滤器2</li><li>资源执行</li><li>过滤器2</li><li>过滤器1</li></ol></li><li><p>过滤器的顺序</p><ol><li>注解方式:根据过滤器的名称字符串大小确定,小的先执行。</li><li>web.xml:<code><filter-mapping></code>谁定义在上面,谁先执行。</li></ol></li></ul><h1 id="Listener"><a href="#Listener" class="headerlink" title="Listener"></a>Listener</h1><h2 id="简介-1"><a href="#简介-1" class="headerlink" title="简介"></a>简介</h2><p>监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等。</p><p>事件监听机制:</p><ul><li>事件:一个事件</li><li>事件源:事件发生的地方</li><li>监听器:一个对象</li><li>注册监听:将事件,事件源,监听器绑定在一起,当事件源上发生某个事件后,执行监听器代码</li></ul><h2 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h2><p>ServletContextListener:监听ServletContext对象的创建和销毁</p><ul><li><p>方法:</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">contextDestroyed</span><span class="hljs-params">(ServletContextEvent sce)</span></span><br><span class="hljs-function"><span class="hljs-comment">//ServletContext对象被销毁之前会调用该方法</span></span><br></code></pre></div></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">contextInitialized</span><span class="hljs-params">(ServletContextEvent sce)</span></span><br><span class="hljs-function"><span class="hljs-comment">//ServletContext对象创建后会调用该方法</span></span><br></code></pre></div></td></tr></table></figure></li><li><p>步骤:</p><ol><li>定义一个类,实现ServletContextListener接口</li><li>重写方法</li><li>配置web.xml<code><listener></code>或使用注解<code>@WebListener</code></li></ol></li></ul>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Java</tag>
<tag>JavaWeb</tag>
</tags>
</entry>
<entry>
<title>消息中间件RabbitMQ</title>
<link href="/2022/04/15/rabbitmq/"/>
<url>/2022/04/15/rabbitmq/</url>
<content type="html"><![CDATA[<h2 id="MQ引言"><a href="#MQ引言" class="headerlink" title="MQ引言"></a>MQ引言</h2><h3 id="什么是MQ"><a href="#什么是MQ" class="headerlink" title="什么是MQ"></a>什么是MQ</h3><p><code>MQ</code>(Message Quene) : 翻译为 <code>消息队列</code>,通过典型的 <code>生产者</code>和<code>消费者</code>模型,生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息。因为消息的生产和消费都是异步的,而且只关心消息的发送和接收,没有业务逻辑的侵入,轻松的实现系统间解耦。别名为 <code>消息中间件</code> 通过利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。</p><h3 id="MQ有哪些"><a href="#MQ有哪些" class="headerlink" title="MQ有哪些"></a>MQ有哪些</h3><p>当今市面上有很多主流的消息中间件,如老牌的<code>ActiveMQ</code>、<code>RabbitMQ</code>,炙手可热的<code>Kafka</code>,阿里巴巴自主开发<code>RocketMQ</code>等。</p><h3 id="不同MQ特点"><a href="#不同MQ特点" class="headerlink" title="不同MQ特点"></a>不同MQ特点</h3><h4 id="ActiveMQ"><a href="#ActiveMQ" class="headerlink" title="ActiveMQ"></a>ActiveMQ</h4><p>ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。它是一个完全支持JMS规范的的消息中间件。丰富的API,多种集群架构模式让ActiveMQ在业界成为老牌的消息中间件,在中小型企业颇受欢迎!</p><h4 id="Kafka"><a href="#Kafka" class="headerlink" title="Kafka"></a>Kafka</h4><p>Kafka是LinkedIn开源的分布式发布-订阅消息系统,目前归属于Apache顶级项目。Kafka主要特点是基于Pull的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输。0.8版本开始支持复制,不支持事务,对消息的重复、丢失、错误没有严格要求,适合产生大量数据的互联网服务的数据收集业务。</p><h4 id="RocketMQ"><a href="#RocketMQ" class="headerlink" title="RocketMQ"></a>RocketMQ</h4><p>RocketMQ是阿里开源的消息中间件,它是纯Java开发,具有高吞吐量、高可用性、适合大规模分布式系统应用的特点。RocketMQ思路起源于Kafka,但并不是Kafka的一个Copy,它对消息的可靠传输及事务性做了优化,目前在阿里集团被广泛应用于交易、充值、流计算、消息推送、日志流式处理、binglog分发等场景。</p><h4 id="RabbitMQ"><a href="#RabbitMQ" class="headerlink" title="RabbitMQ"></a>RabbitMQ</h4><p>RabbitMQ是使用Erlang语言开发的开源消息队列系统,基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP协议更多用在企业系统内对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。</p><div class="note note-info"> <p>RabbitMQ比Kafka可靠,Kafka更适合IO高吞吐的处理,一般应用在大数据日志处理或对实时性(少量延迟),可靠性(少量丢数据)要求稍低的场景使用,比如ELK日志收集。</p> </div><hr><h2 id="RabbitMQ-的引言"><a href="#RabbitMQ-的引言" class="headerlink" title="RabbitMQ 的引言"></a>RabbitMQ 的引言</h2><h3 id="RabbitMQ-1"><a href="#RabbitMQ-1" class="headerlink" title="RabbitMQ"></a>RabbitMQ</h3><blockquote><p>基于<code>AMQP</code>协议,erlang语言开发,是部署最广泛的开源消息中间件,是最受欢迎的开源消息中间件之一。</p></blockquote><p><code>官网</code>: <a href="https://www.rabbitmq.com/">https://www.rabbitmq.com/</a></p><p><code>官方教程</code>: <a href="https://www.rabbitmq.com/#getstarted">https://www.rabbitmq.com/#getstarted</a></p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Java</tag>
<tag>MQ</tag>
</tags>
</entry>
<entry>
<title>JWT学习</title>
<link href="/2022/04/10/jwt/"/>
<url>/2022/04/10/jwt/</url>
<content type="html"><![CDATA[<h2 id="什么是JWT"><a href="#什么是JWT" class="headerlink" title="什么是JWT"></a>什么是JWT</h2><p><a href="[JSON Web Tokens - jwt.io](https://jwt.io/">官网</a>)</p><p>通俗解释:JWT简称JSON Web Token,也就是通过JSON形式作为Web应用中的令牌,用于在各方之间安全地将信息作为JSON对象传输。在数据传输过程中还可以完成数据加密、签名等相关处理。</p><h2 id="JWT能做什么"><a href="#JWT能做什么" class="headerlink" title="JWT能做什么"></a>JWT能做什么</h2>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title>Shiro权限管理</title>
<link href="/2022/01/15/shiro/"/>
<url>/2022/01/15/shiro/</url>
<content type="html"><![CDATA[<h1 id="Shiro"><a href="#Shiro" class="headerlink" title="Shiro"></a>Shiro</h1><h2 id="权限管理概念"><a href="#权限管理概念" class="headerlink" title="权限管理概念"></a>权限管理概念</h2><p>基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现<code>对用户访问系统的控制</code>,按照安全规则或者<a href="http://baike.baidu.com/view/160028.htm">安全策略</a>控制用户可以访问而且只能访问自己被授权的资源。权限管理包括用户<code>身份认证</code>和<code>授权</code>两部分,简称<code>认证授权</code>。对于需要访问控制的资源用户首先经过身份认证,认证通过后用户具有该资源的访问权限方可访问。</p><h2 id="Shiro-Core"><a href="#Shiro-Core" class="headerlink" title="Shiro Core"></a>Shiro Core</h2><h3 id="Subject"><a href="#Subject" class="headerlink" title="Subject"></a>Subject</h3><p><code>Subject即主体</code>,外部应用与subject进行交互,subject记录了当前操作用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序。 Subject在shiro中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权</p><h3 id="SecurityManager"><a href="#SecurityManager" class="headerlink" title="SecurityManager"></a>SecurityManager</h3><p><code>SecurityManager即安全管理器</code>,对全部的subject进行安全管理,它是shiro的核心,负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等,实质上SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。</p><p><code>SecurityManager是一个接口,继承了Authenticator, Authorizer, SessionManager这三个接口。</code></p><h3 id="Authenticator"><a href="#Authenticator" class="headerlink" title="Authenticator"></a>Authenticator</h3><p><code>Authenticator即认证器</code>,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。</p><h3 id="Authorizer"><a href="#Authorizer" class="headerlink" title="Authorizer"></a>Authorizer</h3><p><code>Authorizer即授权器</code>,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。</p><h3 id="Realm"><a href="#Realm" class="headerlink" title="Realm"></a>Realm</h3><p><code>Realm即领域</code>,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。</p><blockquote><p>注意:不要把realm理解成只是从数据源取数据,在realm中还有认证授权校验的相关的代码。</p></blockquote><h3 id="SessionManager"><a href="#SessionManager" class="headerlink" title="SessionManager"></a>SessionManager</h3><p><code>sessionManager即会话管理</code>,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。</p><h3 id="SessionDAO"><a href="#SessionDAO" class="headerlink" title="SessionDAO"></a>SessionDAO</h3><p><code>SessionDAO即会话dao</code>,是对session会话操作的一套接口,比如要将session存储到数据库,可以通过jdbc将会话存储到数据库。</p><h3 id="CacheManager"><a href="#CacheManager" class="headerlink" title="CacheManager"></a>CacheManager</h3><p><code>CacheManager即缓存管理</code>,将用户权限数据存储在缓存,这样可以提高性能。</p><h3 id="Cryptography"><a href="#Cryptography" class="headerlink" title="Cryptography"></a>Cryptography</h3><p> <code>Cryptography即密码管理</code>,shiro提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。</p><h2 id="认证"><a href="#认证" class="headerlink" title="认证"></a>认证</h2><h3 id="快速开始"><a href="#快速开始" class="headerlink" title="快速开始"></a>快速开始</h3><h4 id="1-创建项目并引入依赖"><a href="#1-创建项目并引入依赖" class="headerlink" title="1. 创建项目并引入依赖"></a>1. 创建项目并引入依赖</h4><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">dependency</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.apache.shiro<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>shiro-core<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">version</span>></span>1.5.3<span class="hljs-tag"></<span class="hljs-name">version</span>></span><br><span class="hljs-tag"></<span class="hljs-name">dependency</span>></span><br></code></pre></div></td></tr></table></figure><h4 id="2-引入shiro配置文件并配置"><a href="#2-引入shiro配置文件并配置" class="headerlink" title="2.引入shiro配置文件并配置"></a>2.引入shiro配置文件并配置</h4><figure class="highlight ini"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs ini"><span class="hljs-section">[users]</span><br><span class="hljs-attr">zwy</span>=<span class="hljs-number">123</span><br><span class="hljs-attr">fhy</span>=<span class="hljs-number">456</span><br></code></pre></div></td></tr></table></figure><h4 id="3-认证代码"><a href="#3-认证代码" class="headerlink" title="3.认证代码"></a>3.认证代码</h4><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestAuthenticator</span> </span>{<br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{<br> <span class="hljs-comment">//创建securityManager</span><br> DefaultSecurityManager defaultSecurityManager = <span class="hljs-keyword">new</span> DefaultSecurityManager();<br> defaultSecurityManager.setRealm(<span class="hljs-keyword">new</span> IniRealm(<span class="hljs-string">"classpath:shiro.ini"</span>));<br> <span class="hljs-comment">//将安装工具类中设置默认安全管理器</span><br> SecurityUtils.setSecurityManager(defaultSecurityManager);<br> <span class="hljs-comment">//获取主体对象</span><br> Subject subject = SecurityUtils.getSubject();<br> <span class="hljs-comment">//创建token令牌</span><br> UsernamePasswordToken token = <span class="hljs-keyword">new</span> UsernamePasswordToken(<span class="hljs-string">"zwy"</span>, <span class="hljs-string">"123"</span>);<br> <span class="hljs-keyword">try</span> {<br> subject.login(token);<span class="hljs-comment">//用户登录</span><br> System.out.println(<span class="hljs-string">"登录成功!"</span>);<br> } <span class="hljs-keyword">catch</span> (UnknownAccountException e) {<br> e.printStackTrace();<br> System.out.println(<span class="hljs-string">"用户名错误!!"</span>);<br> }<span class="hljs-keyword">catch</span> (IncorrectCredentialsException e){<br> e.printStackTrace();<br> System.out.println(<span class="hljs-string">"密码错误!!!"</span>);<br> }<br> }<br>}<br></code></pre></div></td></tr></table></figure><p>分析源码可知:</p><ol><li>最终执行用户名比较<code>SimpleAccountRealm</code>,<code>doGetAuthenticationinfo</code>在这个方法中完成用户名校验。</li><li>最终密码校验是在<code>AuthenticatingRealm</code>中<code>assertCredentialIsMatch</code>。</li></ol><p>总结,<code>AuthenticatingRealm</code>认证realm,<code>doGetAuthenticationInfo</code>,<code>AuthorizingRealm</code>授权realm,<code>doGetAuthorizzationInfo</code>。</p><h3 id="MD5和Salt"><a href="#MD5和Salt" class="headerlink" title="MD5和Salt"></a>MD5和Salt</h3><p><code>MD5</code>算法,一般用于加密或者签名(校验和),特点是:MD5算法不可逆,内容相同无论执行多少次MD5生成的结果始终是一致的。可以用来校验文件是否完整(验证游戏完整性)。网站上有的解密算法,都是通过穷举法来的,比如一些简单的密码,“123”,“123456”等等。所以密码最好加上自己的一些信息。<strong>生成的结果: 不管源文件有多大多小,始终是一个16进制32位长度字符串。</strong></p><p><code>Salt</code>盐,给用户密码加点盐,就是在原先的明文密码后加一串随机字符串,更咸了,密码也就更复杂了一些。所以在数据库里要加盐,并在数据库中保存下来。虽然不能确保系统的百分之百安全,但是能更加相对安全,因为不知道盐加在那个位置,生成了几次。</p><ol><li>用户注册时,通过服务层加盐,确定业务规则,并将盐保存在数据库中。</li><li>用户登录时,首先根据用户名查询是否存在,然后比较密码,此时也需要加保存在数据库中的盐,注意业务规则要一致,比如注册时加在后面,登陆认证时也要加在后面。</li></ol><p>所以要在注入realm之后根据需要是否使用MD5加密,是否加盐,散列多少次都需要明确指出。</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">//创建安全管理器</span><br> DefaultSecurityManager defaultSecurityManager = <span class="hljs-keyword">new</span> DefaultSecurityManager();<br><br> <span class="hljs-comment">//注入realm</span><br> CustomerMd5Realm realm = <span class="hljs-keyword">new</span> CustomerMd5Realm();<br><br> <span class="hljs-comment">//设置realm使用hash凭证匹配器</span><br> HashedCredentialsMatcher credentialsMatcher = <span class="hljs-keyword">new</span> HashedCredentialsMatcher();<br> <span class="hljs-comment">//使用算法</span><br> credentialsMatcher.setHashAlgorithmName(<span class="hljs-string">"md5"</span>);<br> <span class="hljs-comment">//散列次数</span><br> credentialsMatcher.setHashIterations(<span class="hljs-number">1024</span>);<br> realm.setCredentialsMatcher(credentialsMatcher);<br> defaultSecurityManager.setRealm(realm);<br><br> <span class="hljs-comment">//将安全管理器注入安全工具</span><br> SecurityUtils.setSecurityManager(defaultSecurityManager);<br><br> <span class="hljs-comment">//通过安全管理器获取subject</span><br> Subject subject = SecurityUtils.getSubject();<br></code></pre></div></td></tr></table></figure><p>指出加盐。</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">protected</span> AuthenticationInfo <span class="hljs-title">doGetAuthenticationInfo</span><span class="hljs-params">(AuthenticationToken token)</span> <span class="hljs-keyword">throws</span> AuthenticationException </span>{<br> String principal = (String) token.getPrincipal();<br> <span class="hljs-keyword">if</span>(<span class="hljs-string">"zwy"</span>.equals(principal)){<br> String password = <span class="hljs-string">"e4f9bf3e0c58f045e62c23c533fcf633"</span>;<br> String salt = <span class="hljs-string">"X0*7ps"</span>;<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> SimpleAuthenticationInfo(principal,password, ByteSource.Util.bytes(salt),<span class="hljs-keyword">this</span>.getName());<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;<br> }<br></code></pre></div></td></tr></table></figure><h2 id="授权"><a href="#授权" class="headerlink" title="授权"></a>授权</h2><p>授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的。</p><h3 id="关键对象"><a href="#关键对象" class="headerlink" title="关键对象"></a>关键对象</h3><p><strong>授权可简单理解为Who对What进行How操作:</strong></p><p><code>Who,即主体(Subject)</code>,主体需要访问系统中的资源。</p><p><code>What,即资源(Resource)</code>,如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括<code>资源类型</code>和<code>资源实例</code>,比如<code>商品信息为资源类型</code>,类型为t01的商品为<code>资源实例</code>,编号为001的商品信息也属于资源实例。</p><p><code>How,权限/许可(Permission)</code>,规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可。</p><h3 id="授权流程"><a href="#授权流程" class="headerlink" title="授权流程"></a>授权流程</h3><p><img src="/img/pic030.jpg" alt="授权流程"></p><h3 id="授权方式"><a href="#授权方式" class="headerlink" title="授权方式"></a>授权方式</h3><ul><li><p><strong>基于角色的访问控制</strong></p><ul><li><p>RBAC基于角色的访问控制(Role-Based Access Control)是以角色为中心进行访问控制</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">if</span>(subject.hasRole(<span class="hljs-string">"admin"</span>)){<br> <span class="hljs-comment">//操作什么资源</span><br>}<br></code></pre></div></td></tr></table></figure></li></ul></li><li><p><strong>基于资源的访问控制</strong></p><ul><li><p>RBAC基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">if</span>(subject.isPermission(<span class="hljs-string">"user:update:01"</span>)){ <span class="hljs-comment">//资源实例</span><br> <span class="hljs-comment">//对01用户进行修改</span><br>}<br><span class="hljs-keyword">if</span>(subject.isPermission(<span class="hljs-string">"user:update:*"</span>)){ <span class="hljs-comment">//资源类型</span><br> <span class="hljs-comment">//对01用户进行修改</span><br>}<br></code></pre></div></td></tr></table></figure></li></ul></li></ul><h3 id="权限字符串"><a href="#权限字符串" class="headerlink" title="权限字符串"></a>权限字符串</h3><p> 权限字符串的规则是:<strong>资源标识符:操作:资源实例标识符</strong>,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用*通配符。</p><p>例子:</p><ul><li>用户创建权限:user:create,或user:create:*</li><li>用户修改实例001的权限:user:update:001</li><li>用户实例001的所有权限:user:*:001</li></ul><h3 id="编程实现方式"><a href="#编程实现方式" class="headerlink" title="编程实现方式"></a>编程实现方式</h3><ul><li><p>编程式</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">Subject subject = SecurityUtils.getSubject();<br><span class="hljs-keyword">if</span> (subject.hasRole(<span class="hljs-string">"admin"</span>)){<br> <span class="hljs-comment">//有权限</span><br>} <span class="hljs-keyword">else</span> {<br> <span class="hljs-comment">//无权限</span><br>}<br></code></pre></div></td></tr></table></figure></li><li><p>注解式</p><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-meta">@RequiresRoles("admin")</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">hello</span><span class="hljs-params">()</span></span>{<br> <span class="hljs-comment">//有权限</span><br>}<br></code></pre></div></td></tr></table></figure></li><li><p>标签式</p><figure class="highlight jsp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs jsp">JSP标签:在JSP页面通过相应的标签完成<br><shiro:hasRole name=<span class="hljs-string">"admin"</span>><br> <!- 有权限-><br></shiro:hasRole><br>注意!Thymeleaf中使用shiro需要额外集成<br></code></pre></div></td></tr></table></figure></li></ul><h3 id="开发授权"><a href="#开发授权" class="headerlink" title="开发授权"></a>开发授权</h3>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title>子网掩码的理解</title>
<link href="/2021/10/28/subnet-mask/"/>
<url>/2021/10/28/subnet-mask/</url>
<content type="html"><![CDATA[<p>首先子网掩码这名字取得很好,它是用来划分<strong>子网</strong>的网段和<strong>遮掩</strong>部分IP地址。换个说法就是:<strong>它是用来划分IP地址中哪一部分是网络号,哪一部分是机器号</strong>。</p><p>那么,问题来了 :</p><p><strong>怎么划分子网网段?</strong></p><p><strong>为什么要遮掩IP地址?怎么个遮掩法?</strong></p><p>现在我们有这么个<strong>IP地址</strong>:192.168.1.129</p><p>我们并不知道它的网络号,也不知道它属于哪部分子网网段。我们现在就需要一个东西来划分出子网网段,这个东西就叫:<strong>子网掩码</strong>。</p><p>再,我们给出具体<strong>子网掩码</strong>:255.255.255.0</p><p>什么要这么给?因为子网掩码的长度要和IP地址相同32位,每8位预先被划分为一段。255的二进制就是1111 1111。</p><p>那么我们把子网掩码设置为255.255.255.193行不行?</p><p>这需要看它的二进制,子网掩码还需要满足一个条件才可以使用:它的二进制中1和0必须是<code>连续</code>的。</p><p>255.255.255.193的二进制:</p><p>1111 1111.1111 1111.1111 1111.1100 0001</p><p>可以看出它1并不连续,所以255.255.255.193不能作为子网掩码使用。</p><p>255.255.255.0就很符合条件。</p><p>那子网掩码怎么用?</p><p>答:用与运算来遮掩IP地址。1&1=1、1&0=0、0&0=0、0&1=0</p><p>IP地址:192.168.1.129</p><p>二进制:</p><p>1100 0000.1010 1000.0000 0001.1000 0001</p><p>子网掩码:255.255.255.0</p><p>二进制:</p><p>1111 1111.1111 1111.1111 1111.0000 0000</p><p>计算:</p><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++"><span class="hljs-number">1100</span> <span class="hljs-number">0000.1010</span> <span class="hljs-number">1000.0000</span> <span class="hljs-number">0001.1000</span> <span class="hljs-number">0001</span><br><span class="hljs-number">1111</span> <span class="hljs-number">1111.1111</span> <span class="hljs-number">1111.1111</span> <span class="hljs-number">1111.0000</span> <span class="hljs-number">0000</span><br>———————————————————————————————————————<br><span class="hljs-number">1100</span> <span class="hljs-number">0000.1010</span> <span class="hljs-number">1000.0000</span> <span class="hljs-number">0001.0000</span> <span class="hljs-number">0000</span><br></code></pre></div></td></tr></table></figure><p>计算后的这段二进制代码相比于原来的IP地址,后面8位被用0遮掩了。</p><p>为什么要遮掩?因为我们不必关心后面8位是1还是0了。子网网段已经被划分出来了。</p><p>1100 0000.1010 1000.0000 0001.0000 0000的十进制:192.168.1.0</p><p>也就是说,从192.168.1.0到192.168.1.255都是同一个子网网段,里面的0-255号可以分配给不同的机器,并且它们之间可以直接相互访问。</p><p>0—255号都是机器的号码,IP地址显示的就是其中129号。</p><p>192.168.1.0就是所谓的<strong>网络号</strong>,也可以写作192.168.1或者192.168.1.0\24(24指的是IP地址中有24位未被遮掩)</p><p>IP地址的意思就很明白了,网段(网络号)加上机器号码。同一个IP地址根据不同子网掩码,会划分出不同的网络号和机器号。</p><p>—————————————————————————————————————</p><p>但是,现在就出现了个问题,我子网掩码的最后8位全是0,要是最后8位不全为0怎么办?又是什么意思呢?</p><p>现在我们就要看上面子网掩码为255.255.255.0的时候机器号码是从0到255的,那如果我想在0到255里再划分一部分呢?</p><p>给出<strong>新IP地址</strong>:192.168.1.188 再给出<strong>新的子网掩码</strong>:255.255.255.224</p><p>现在IP的网络号就不是192.168.1.0了,不再是网段192.168.1.0到192.168.1.255了</p><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++"><span class="hljs-number">1100</span> <span class="hljs-number">0000.1010</span> <span class="hljs-number">1000.0000</span> <span class="hljs-number">0001.1011</span> <span class="hljs-number">1100</span> <br><span class="hljs-number">1111</span> <span class="hljs-number">1111.1111</span> <span class="hljs-number">1111.1111</span> <span class="hljs-number">1111.1110</span> <span class="hljs-number">0000</span> <br>———————————————————————————————————————<br><span class="hljs-number">1100</span> <span class="hljs-number">0000.1010</span> <span class="hljs-number">1000.0000</span> <span class="hljs-number">0001.1010</span> <span class="hljs-number">0000</span><br></code></pre></div></td></tr></table></figure><p>不再是24位未被遮掩了,而是27位未被遮掩。被遮掩的后5位,我们不必再关心它是1还是0了。</p><p>这就意味着:后5位不论怎么变换,都是在同一个网段里。</p><p>后5位的变化是在</p><p>1100 0000.1010 1000.0000 0001.101<strong>0 0000</strong></p><p>到</p><p>1100 0000.1010 1000.0000 0001.101<strong>1 1111</strong></p><p>之间的。</p><p>它的十进制:192.168.1.160到192.168.1.191是由<strong>新的子网掩码</strong>划分出来的子网网段。</p><p>我们称192.168.1.160\27是它的网络号,它的机器号是在160到191之间任意分配出去。之前的IP地址:192.168.1.188属于其中。</p><p>总结:子网掩码就是用来遮掩IP地址并划分网段的工具,根据<strong>遮掩的位数不同</strong>来划分不同的网段,不能单独看待。</p><p>📢📢📢:文章来源于<a href="https://www.zhihu.com/people/pu-ji-yan-93">知乎用户纪言</a>,修改了几处表述不恰当的地方。</p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>计算机网络</tag>
<tag>子网掩码</tag>
</tags>
</entry>
<entry>
<title>Git入门</title>
<link href="/2021/07/08/git/"/>
<url>/2021/07/08/git/</url>
<content type="html"><![CDATA[<h1 id="初始化本地仓库"><a href="#初始化本地仓库" class="headerlink" title="初始化本地仓库"></a>初始化本地仓库</h1><ul><li><p>创建一个文件目录</p><figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">mkdir</span> <span class="hljs-number">7</span>.<span class="hljs-number">8</span>study<br></code></pre></div></td></tr></table></figure></li><li><p>进入这个文件目录</p><figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">cd</span> <span class="hljs-number">7</span>.<span class="hljs-number">8</span>study<br></code></pre></div></td></tr></table></figure></li><li><p>初始化Git本地仓库</p><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp">git <span class="hljs-keyword">init</span><br></code></pre></div></td></tr></table></figure></li><li><p>在本地仓库里新建一个myfile.txt文件,右键新建就行</p></li><li><p>在文件中写入一段文字,也就是对文件进行修改</p><figure class="highlight plain"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs plain">连猴子都懂的Git命令<br></code></pre></div></td></tr></table></figure></li></ul><h1 id="提交修改"><a href="#提交修改" class="headerlink" title="提交修改"></a>提交修改</h1><ul><li><p>先将文件添加到Git控制系统中来</p><figure class="highlight dockerfile"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs dockerfile">git <span class="hljs-keyword">add</span><span class="bash"> myfile.txt</span><br></code></pre></div></td></tr></table></figure></li><li><p>提交到Git系统中,并添加信息,方便以后查看每一步干了些什么</p><figure class="highlight nginx"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs nginx"><span class="hljs-attribute">git</span> commit -m <span class="hljs-string">"第一次提交"</span><br></code></pre></div></td></tr></table></figure></li><li><p>结果</p><figure class="highlight sql"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs sql">[master (root-<span class="hljs-keyword">commit</span>) <span class="hljs-number">268</span>c96e] 第一次提交<br> <span class="hljs-number">1</span> <span class="hljs-keyword">file</span> <span class="hljs-keyword">changed</span>, <span class="hljs-number">1</span> insertion(+)<br> <span class="hljs-keyword">create</span> <span class="hljs-keyword">mode</span> <span class="hljs-number">100644</span> myfile.txt<br></code></pre></div></td></tr></table></figure></li><li><p>目前历史是这样的</p></li></ul><h1 id="创建分支"><a href="#创建分支" class="headerlink" title="创建分支"></a>创建分支</h1><p>由于我们有时候需要多人协同开发,每个组都有自己的分支,这样可以提升开发效律。</p><ul><li><p>创建名为dev1的分支</p><figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">git</span> branch dev<span class="hljs-number">1</span><br></code></pre></div></td></tr></table></figure></li><li><p>查看所有分支</p><figure class="highlight ebnf"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs ebnf"><span class="hljs-attribute">git branch</span><br></code></pre></div></td></tr></table></figure></li><li><p>结果</p><figure class="highlight asciidoc"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs asciidoc"><span class="hljs-code"> dev1</span><br><span class="hljs-bullet">* </span>master<br></code></pre></div></td></tr></table></figure></li><li><p>目前历史是这样的</p></li></ul><h1 id="切换分支"><a href="#切换分支" class="headerlink" title="切换分支"></a>切换分支</h1><p>如果想要在新创建的分支上提交,我们需要切换到那个分支上去。在切换到dev1分支的状态下提交,历史记录会被记录到dev1分支。</p><ul><li><p>切换到dev1分支上去</p><figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">git</span> checkout dev<span class="hljs-number">1</span><br></code></pre></div></td></tr></table></figure></li><li><p>在checkout命令指定 -b选项执行,可以创建分支dev2并进行切换</p><figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">git</span> checkout -b dev<span class="hljs-number">2</span><br></code></pre></div></td></tr></table></figure></li><li><p>目前的历史记录是这样的</p></li><li><p>在dev1上给myfile.txt文件添加add的使用说明</p><figure class="highlight dockerfile"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs dockerfile">连猴子都懂的Git命令<br><span class="hljs-keyword">add</span><span class="bash"> 把变更录入到索引中</span><br></code></pre></div></td></tr></table></figure></li><li><p>然后添加和提交</p><figure class="highlight dockerfile"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs dockerfile">git <span class="hljs-keyword">add</span><span class="bash"> myfile.txt</span><br>git commit -m <span class="hljs-string">"添加add的说明"</span><br></code></pre></div></td></tr></table></figure></li><li><p>目前的历史记录是这样的</p></li></ul><h1 id="合并分支"><a href="#合并分支" class="headerlink" title="合并分支"></a>合并分支</h1><p>向master分支合并dev1分支,这里我们切换到dev1分支,打开myfile.txt文件,可以看到add的说明。但是我们现在切回到master分支,会发现并没有add说明,现在假设我们已近完成了开发,就要把dev1合并到master上,这样我们切到master时,文件的进度就和dev1上的一样了,也就是我们也能看见add说明了。</p><ul><li><p>先回到master上</p><figure class="highlight crmsh"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs crmsh">git checkout <span class="hljs-literal">master</span><br></code></pre></div></td></tr></table></figure></li><li><p>在主分支上合并dev1分支</p><figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">git</span> merge dev<span class="hljs-number">1</span><br></code></pre></div></td></tr></table></figure></li><li><p>结果</p><figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">Updating</span> <span class="hljs-number">268</span>c<span class="hljs-number">96</span>e..eaec<span class="hljs-number">4</span>a<span class="hljs-number">7</span><br><span class="hljs-attribute">Fast</span>-forward<br> <span class="hljs-attribute">myfile</span>.txt | <span class="hljs-number">3</span> ++-<br> <span class="hljs-attribute">1</span> file changed, <span class="hljs-number">2</span> insertions(+), <span class="hljs-number">1</span> deletion(-)<br></code></pre></div></td></tr></table></figure></li><li><p>master分支指向的提交移动到和issue1同样的位置,这个是fast-forward(快进)合并</p></li></ul><ul><li><p>取消合并</p><figure class="highlight pgsql"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs pgsql">git <span class="hljs-keyword">reset</span> <span class="hljs-comment">--hard HEAD~</span><br></code></pre></div></td></tr></table></figure></li></ul><h1 id="删除分支"><a href="#删除分支" class="headerlink" title="删除分支"></a>删除分支</h1><p>既然dev1分支的内容已经顺利地合并到master分支了,现在可以将其删除了。</p><ul><li><p>删除dev1分支</p><figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">git</span> branch -d dev<span class="hljs-number">1</span><br></code></pre></div></td></tr></table></figure></li><li><p>确认一下,查看分支列表</p><figure class="highlight ebnf"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs ebnf"><span class="hljs-attribute">git branch</span><br></code></pre></div></td></tr></table></figure></li></ul><h1 id="多个分支"><a href="#多个分支" class="headerlink" title="多个分支"></a>多个分支</h1><p>有时候我们需要多个分支来加快进度,不过最后合并的时候比较容量冲突。先新创建dev2,dev3分支,并切换到dev2分支。</p><ul><li><p>命令行如下</p><figure class="highlight smali"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs smali">git branch dev2<br>git branch dev3<br>git checkout dev2<br>Switched to branch 'dev2'<br>git branch<br>* dev2<br> dev3<br> master<br></code></pre></div></td></tr></table></figure></li><li><p>在dev2分支的myfile.txt添加commit命令的说明后提交</p><figure class="highlight dockerfile"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs dockerfile">连猴子都懂的Git命令<br><span class="hljs-keyword">add</span><span class="bash"> 把变更录入到索引中</span><br>commit 记录索引的状态<br></code></pre></div></td></tr></table></figure><figure class="highlight dockerfile"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs dockerfile">git <span class="hljs-keyword">add</span><span class="bash"> myfile.txt</span><br>git commit -m <span class="hljs-string">"添加commit的说明"</span><br></code></pre></div></td></tr></table></figure></li><li><p>切换到dev3分支,给myfile.txt添加pull命令的说明后提交</p><figure class="highlight dockerfile"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs dockerfile">git checkout dev3<br><br>连猴子都懂的Git命令<br><span class="hljs-keyword">add</span><span class="bash"> 把变更录入到索引中</span><br>pull 取得远端数据库的内容<br><br>git <span class="hljs-keyword">add</span><span class="bash"> myfile.txt</span><br>git commit -m <span class="hljs-string">"添加pull的说明"</span><br></code></pre></div></td></tr></table></figure></li></ul><p>这样,添加commit的说明的操作,和添加pull的说明的操作就并行进行了。</p><h1 id="解决冲突"><a href="#解决冲突" class="headerlink" title="解决冲突"></a>解决冲突</h1><p>把dev2分支和dev3分支的修改合并到master。先切换到master分支后,与dev2分支合并。</p><figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">git</span> checkout master<br><span class="hljs-attribute">Switched</span> to branch 'master'<br><span class="hljs-attribute">git</span> merge dev<span class="hljs-number">2</span><br><span class="hljs-attribute">Updating</span> b<span class="hljs-number">2</span>b<span class="hljs-number">23</span>c<span class="hljs-number">4</span>..<span class="hljs-number">8</span>f<span class="hljs-number">7</span>aa<span class="hljs-number">27</span><br><span class="hljs-attribute">Fast</span>-forward<br> <span class="hljs-attribute">myfile</span>.txt | <span class="hljs-number">2</span> ++<br> <span class="hljs-attribute">1</span> files changed, <span class="hljs-number">2</span> insertions(+), <span class="hljs-number">0</span> deletions(-)<br></code></pre></div></td></tr></table></figure><p>执行fast-forward(快进)合并。</p><p>接着合并dev3分支。</p><figure class="highlight pgsql"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs pgsql">git merge dev3<br>Auto-merging myfile.txt<br><span class="hljs-keyword">CONFLICT</span> (content): Merge <span class="hljs-keyword">conflict</span> <span class="hljs-keyword">in</span> myfile.txt<br>Automatic merge failed; fix conflicts <span class="hljs-keyword">and</span> <span class="hljs-keyword">then</span> <span class="hljs-keyword">commit</span> the result.<br></code></pre></div></td></tr></table></figure><p>自动合并失败。由于在同一行进行了修改,所以产生了冲突。这时myfile.txt的内容如下:</p><figure class="highlight asciidoc"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs asciidoc">连猴子都懂的Git命令<br>add 把变更录入到索引中<br><<<<<<< HEAD<br>commit 记录索引的状态<br>=======<br>pull 取得远端数据库的内容<br>>>>>>>> dev3<br></code></pre></div></td></tr></table></figure><p>在发生冲突的地方,Git生成了内容的差异。请做以下修改:</p><figure class="highlight dockerfile"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs dockerfile">连猴子都懂的Git命令<br><span class="hljs-keyword">add</span><span class="bash"> 把变更录入到索引中</span><br>commit 记录索引的状态<br>pull 取得远端数据库的内容<br></code></pre></div></td></tr></table></figure><p>修改冲突的部分,重新提交。</p><figure class="highlight pgsql"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs pgsql">git <span class="hljs-keyword">add</span> myfile.txt<br>git <span class="hljs-keyword">commit</span> -m "合并dev3分支"<br># <span class="hljs-keyword">On</span> branch master<br><span class="hljs-keyword">nothing</span> <span class="hljs-keyword">to</span> <span class="hljs-keyword">commit</span> (working directory clean)<br></code></pre></div></td></tr></table></figure><p>历史记录如下图所示。因为在这次合并中修改了冲突部分,所以会重新创建合并修改的提交记录。这样,master的HEAD就移动到这里了。这种合并不是fast-forward合并,而是non fast-forward合并。</p><h1 id="个人常用命令"><a href="#个人常用命令" class="headerlink" title="个人常用命令"></a>个人常用命令</h1><p>查看远端仓库地址</p><figure class="highlight shell"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs shell">git remote -v<br></code></pre></div></td></tr></table></figure><p>撤回add操作</p><figure class="highlight shell"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs shell">git reset .<br></code></pre></div></td></tr></table></figure><p>拉取远端仓库后默认只有main分支,在本地新建分支并关联,第二种默认分支名为远端分支</p><figure class="highlight shell"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs shell">git checkout -b zwy origin/zwy<br>git checkout -t origin/feature<br></code></pre></div></td></tr></table></figure><p>使用第一种方法时,如果本地分支名和远端不一样,会出现<code>The upstream branch of your current branch does not match the name of your current branch</code>,分支尽量名称保持一致</p><p>查看本地分支和远程分支关联情况</p><figure class="highlight shell"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs shell">git branch -vv <br></code></pre></div></td></tr></table></figure><p>关联到远端分支</p><p>强制删除分支(在桥上时不要炸桥)</p><figure class="highlight shell"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs shell">git branch -D zwy<br></code></pre></div></td></tr></table></figure><p>在远端删除分支后,本地使用<code>git branch -a</code>未能及时更新</p><figure class="highlight shell"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs shell">git fetch --prune<br></code></pre></div></td></tr></table></figure><p>恢复工作区中的文件到最近的提交状态(即丢弃对文件的所有未提交更改)</p><figure class="highlight shell"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs shell">git restore zwy.md<br>git status<br>nothing to commit, working tree clean<br></code></pre></div></td></tr></table></figure><p>显示分支提交树</p><figure class="highlight shell"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs shell">git log --oneline --graph --decorate --all<br><br>--oneline 日志单行显示<br>--graph分支图显示<br>--decorate 可显示分支名称<br>--all显示所有分支<br></code></pre></div></td></tr></table></figure>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title>Maven笔记</title>
<link href="/2021/05/15/maven/"/>
<url>/2021/05/15/maven/</url>
<content type="html"><![CDATA[<h1 id="Maven简介"><a href="#Maven简介" class="headerlink" title="Maven简介"></a>Maven简介</h1><div class="note note-primary"> <p>如果拿一个普通的JavaWeb项目和一个由maven工程搭建的项目相比较,你会发现maven项目要小的多!原因主要是因为前面WEB程序要运行,我们必须将项目运行所需的Jar包复制到工程目录中,从而导致了工程很大。而maven项目通过在<code>pom.xml</code>文件中添加所需jar包的坐标,这样就很好的避免了jar直接引入进来,在需要用到jar包的时候,只要查找<code>pom.xml</code>文件,再通过<code>pom.xml</code>文件中的坐标,到一个专门用于存放jar包的仓库(maven仓库)中根据坐标从而找到这些jar包,再把这jar包拿去运行,当然就很小了。</p> </div><p>maven在美国是一个口语化的词语,代表专家、内行的意思。一个对maven比较正式的定义是这么说的:maven是一个项目管理工具,它包含了一个<strong>项目对象模型</strong> (POM:Project Object Model),一组<strong>标准集合</strong>,一个<strong>项目生命周期</strong>(Project Lifecycle),一个<strong>依赖管理系统</strong>(Dependency Management System),和用来运行定义在<strong>生命周期阶段</strong>(phase)中<strong>插件</strong>(plugin)<strong>目标</strong>(goal)的逻辑。</p><p>maven的一个核心特性就是依赖管理。当我们涉及到多模块的项目(包含成百个模块或者子项目),管理依赖就变成一项困难的任务。maven展示出了它对处理这种情形的高度控制。</p><h1 id="Maven的使用"><a href="#Maven的使用" class="headerlink" title="Maven的使用"></a>Maven的使用</h1><p>我们一般从官网(<a href="https://maven.apache.org/">Maven – Welcome to Apache Maven</a>)下载最新版的maven解压到一个没有空隔没有中文的路径下就好了,一定要记住这个路径,以后会经常用到的。</p><p>然后我们需要配置好环境变量,和配置JDK环境变量一样,为了让电脑能识别到它,配好之后打开命令行,输入<code>mvn -v</code>,如果弹出一些版本信息,说明你已经配置好了。我的是这样的:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">C:\Users\Chris>mvn -v<br>Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)<br>Maven home: D:\Development\Maven\apache-maven-3.6.3\bin\..<br>Java version: 1.8.0_251, vendor: Oracle Corporation, runtime: D:\Development\Java\JDK8\jre<br>Default locale: zh_CN, platform encoding: GBK<br>OS name: <span class="hljs-string">"windows 10"</span>, version: <span class="hljs-string">"10.0"</span>, arch: <span class="hljs-string">"amd64"</span>, family: <span class="hljs-string">"windows"</span><br></code></pre></div></td></tr></table></figure><p>最开始的时候,我们是不用IDEA运行的,直接在命令行输入指令。</p><h1 id="Maven的目录结构"><a href="#Maven的目录结构" class="headerlink" title="Maven的目录结构"></a>Maven的目录结构</h1><p>打开maven目录,或者在该目录下打开命令行输入<code>tree</code>,我们可以看到:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">D:\Development\Maven\apache-maven-3.6.3>tree<br>├─bin<br>├─boot<br>├─conf<br>│ └─logging<br>└─lib<br> ├─ext<br> └─jansi-native<br> ├─freebsd32<br> ├─freebsd64<br> ├─linux32<br> ├─linux64<br> ├─osx<br> ├─windows32<br> └─windows64<br><br></code></pre></div></td></tr></table></figure><p>分别来解释一下各个目录的大概作用。</p><div class="table-container"><table><thead><tr><th>目录</th><th>作用</th></tr></thead><tbody><tr><td>bin</td><td>存放了maven命令,比如mvn tomcat:run</td></tr><tr><td>boot</td><td>存放了一些maven本身的引导程序,如类加载器等</td></tr><tr><td>conf</td><td>存放了maven的一些配置文件,如setting.xml</td></tr><tr><td>lib</td><td>存放了maven本身运行所需要的一些jar包</td></tr></tbody></table></div><h1 id="Maven仓库"><a href="#Maven仓库" class="headerlink" title="Maven仓库"></a>Maven仓库</h1><p>maven仓库一般分为三种:</p><h2 id="1-本地仓库"><a href="#1-本地仓库" class="headerlink" title="1.本地仓库"></a>1.本地仓库</h2><p>用来存储从<span class="label label-primary">远程仓库</span>或<span class="label label-info">中央仓库</span>下载的插件和jar包,项目使用一些插件或jar包,优先从本地仓库查找<br>默认本地仓库位置在 <code>${user.dir}/.m2/repository</code>,${user.dir}表示 Windows 用户目录。比如我的就是<code>C:\Users\Chris</code>。</p><h2 id="2-远程仓库"><a href="#2-远程仓库" class="headerlink" title="2.远程仓库"></a>2.远程仓库</h2><p>如果本地需要插件或者jar包,本地仓库没有,默认去远程仓库下载。远程仓库可以在互联网内也可以在局域网内。公司里面一般为了在没网的时候也能写项目,用得就是这个。</p><h2 id="3-中央仓库"><a href="#3-中央仓库" class="headerlink" title="3.中央仓库"></a>3.中央仓库</h2><p>在maven软件中内置一个远程仓库地址 <a href="https://repo1.maven.org/maven2">https://repo1.maven.org/maven2</a> ,它是中央仓库,服务于整个互联网,它是由maven团队自己维护,里面存储了非常全的jar包,加起来有几个G了,它包含了世界上大部分流行的开源项目构件。当然我们平时写代码肯定只用了其中的一小部分。</p><h1 id="Maven常用命令"><a href="#Maven常用命令" class="headerlink" title="Maven常用命令"></a>Maven常用命令</h1><p>我们可以在命令行中通过一系列的maven命令来对我们的maven-helloworld工程进行编译、测试、运行、打包、安装、部署。</p><h2 id="mvn-compile"><a href="#mvn-compile" class="headerlink" title="mvn compile"></a>mvn compile</h2><p>compile是maven工程的编译命令,执行<code>mvn compile</code>后,将src/main/java下的文件编译为class文件输出到target目录下。</p><h2 id="mvn-test"><a href="#mvn-test" class="headerlink" title="mvn test"></a>mvn test</h2><p>test是maven工程的测试命令,<code>mvn test</code>会执行src/test/java下的单元测试类。作用除了编译src/main/java下的文件,同时也编译了src/main/test下的文件,输出到target目录下。</p><h2 id="mvn-package"><a href="#mvn-package" class="headerlink" title="mvn package"></a>mvn package</h2><p>package是maven工程的打包命令,对于Java工程执行 <code>mvn package</code>打成jar包,对于WEB工程打成war包。</p><h2 id="mvn-install"><a href="#mvn-install" class="headerlink" title="mvn install"></a>mvn install</h2><p>install是maven工程的安装命令,执行 <code>mvn install</code> 将maven打成jar包或war包发布到本地仓库。</p><blockquote><p>从运行结果中,不难看出,当后面的命令执行时,前面的操作过程也都会自动执行。</p></blockquote><h2 id="mvn-clean"><a href="#mvn-clean" class="headerlink" title="mvn clean"></a>mvn clean</h2><p>clean是maven工程的清理命令,执行<code>mvn clean</code>会删除target目录及内容。</p><h1 id="Maven生命周期"><a href="#Maven生命周期" class="headerlink" title="Maven生命周期"></a>Maven生命周期</h1><p>我第一次听到<code>生命周期</code>这个词时就觉得很生动,把项目构建的过程比作一个人的生命历程,从出生到童年,到少年,到中年,到老年,最后死亡🏃♂️。</p><p>maven对项目构建过程分为三套相互独立的生命周期,请注意这里说的是“三套”,而且“相互独立”,这三套生命周期分别是:</p><ul><li><p>Clean Lifecycle 在进行真正的构建之前进行一些清理工作。</p></li><li><p>Default Lifecycle 构建的核心部分,编译,测试,打包,部署等等。</p></li><li><p>Site Lifecycle 生成项目报告,站点,发布站点。</p></li></ul><h2 id="1-Clean-Lifecycle"><a href="#1-Clean-Lifecycle" class="headerlink" title="1.Clean Lifecycle"></a>1.Clean Lifecycle</h2><p>clean生命周期的目的是<strong>清理项目</strong>,它包含三个阶段:</p><ul><li><code>pre-clean</code>执行一些清理前需要完成的工作。</li><li><code>clean</code>清理上一次构建生成的文件。</li><li><code>post-clean</code>执行一些清理后需要完成的工作。</li></ul><h2 id="2-Default-Lifecycle"><a href="#2-Default-Lifecycle" class="headerlink" title="2.Default Lifecycle"></a>2.Default Lifecycle</h2><p>default 生命周期定义了<strong>真正构建时所需要执行的所有步骤</strong>,它是所有生命周期中最核心的部分,其包含的阶段如下,这里只对重要的阶段进行解释:</p><ul><li><code>validate</code></li><li><code>initialize</code></li><li><code>generate-sources</code></li><li><code>process-sources</code>处理项目主资源文件。一般来说,是对<code>src/main/resources</code>目录的内容进行变量替换等工作后,复制到项目输出的主<code>classpath</code>目录中。</li><li><code>generate-resources</code></li><li><code>process-resources</code></li><li><code>compile</code>编译项目的主源码。一般来说,是编译<code>src/main/java</code>目录下的<code>Java</code>文件至项目输出的主<code>classpath</code>目录中。</li><li><code>process-classes</code></li><li><code>generate-test-sources</code></li><li><code>process-test-sources</code>处理项目测试资源文件。一般来说,是对<code>src/test/resources</code>目录的内容进行变量替换等工作后,复制到项目输出的测试<code>classpath</code>目录中。</li><li><code>generate-test-resources</code></li><li><code>process-test-resources</code></li><li><code>test-compile</code>编译项目的测试代码。一般来说,是编译src/test/java目录下的Java文件至项目输出的测试classpath目录中。</li><li><code>process-test-classes</code></li><li><code>test</code>使用单元测试框架运行测试,测试代码不会被打包或部署。</li><li><code>prepare-package</code></li><li><code>package</code>接受编译好的代码,打包成可发布的格式,如JAR。</li><li><code>pre-integration-test</code></li><li><code>integration-test</code></li><li><code>post-integration-test</code></li><li><code>verify</code></li><li><code>install</code>将包安装到Maven本地仓库,供本地其他Maven项目使用。</li><li><code>deploy</code>将最终的包复制到远程仓库,供其他开发人员和Maven项目使用。</li></ul><h2 id="3-Site-Lifecycle"><a href="#3-Site-Lifecycle" class="headerlink" title="3.Site Lifecycle"></a>3.Site Lifecycle</h2><p>site生命周期的目的是<strong>建立和发布项目站点</strong>。该生命周期包含如下阶段:</p><ul><li><code>pre-site</code>执行一些在生成项目站点之前需要完成的工作。</li><li><code>site</code>生成项目站点文档。</li><li><code>post-site</code>执行一些在生成项目站点之后需要完成的工作。</li><li><code>site-deploy</code>将生成的项目站点发布到服务器上。</li></ul><p>参考博客:<a href="https://blog.csdn.net/wangdong5678999/article/details/72848044">Maven生命周期_栋先生-CSDN博客</a></p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Java</tag>
<tag>JavaWeb</tag>
<tag>Maven</tag>
</tags>
</entry>
<entry>
<title>MySQL中MD5加密</title>
<link href="/2021/05/13/md5/"/>
<url>/2021/05/13/md5/</url>
<content type="html"><![CDATA[<h1 id="MD5"><a href="#MD5" class="headerlink" title="MD5"></a>MD5</h1><p>MySQL的SQL语句中,除了标准的SQL语句之外,另外增加了很多功能的内容,比如一些全局变量、函数等。在JAVA EE的学习中,需要创建用户表并进行加密,这里简答介绍一个在MySQL中用来进行md5加密的函数,函数名为<code>md5</code>。</p><h1 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h1><p>一般来说有两种方法,第一个就是用户表中已经存在了一个用户的用户名和密码,我们现在想把密码加密,第二种就是我们需要插入一个用户信息并且想在插入时就加密密码。来看例子:</p><h2 id="1-更新"><a href="#1-更新" class="headerlink" title="1.更新"></a>1.更新</h2><figure class="highlight plain"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs mysql">update admin set password=md5('123456') where username='zhaowuya';<br></code></pre></div></td></tr></table></figure><p>这样就把admin表中的用户名为zhoawuya,原密码为123456的用户的密码成功加密了。</p><p>结果为:</p><div class="table-container"><table><thead><tr><th>username</th><th>password</th></tr></thead><tbody><tr><td>zhaowuya</td><td>e10adc3949ba59abbe56e057f20f883e</td></tr></tbody></table></div><h2 id="2-插入"><a href="#2-插入" class="headerlink" title="2.插入"></a>2.插入</h2><figure class="highlight plain"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs mysql">insert into admin(username,password) values('tutu',md5('12'));<br></code></pre></div></td></tr></table></figure><p>这样我们就成功插入了用户名为tutu的,原密码为12的用户,并且加密了密码,在数据库里变成了一大串的数字字母组合。</p><p>结果为:</p><div class="table-container"><table><thead><tr><th>username</th><th>password</th></tr></thead><tbody><tr><td>tutu</td><td>c20ad4d76fe97759aa27a0c99bff6710</td></tr></tbody></table></div><div class="note note-info"> <p>这样存放在数据中的密码信息是保密存放的,但是通过md5加密后的数据是不能逆向使用的,也就是说如果想查询用户的密码信息,则需要通过数据查询匹配来实现。</p> </div><h1 id="检查"><a href="#检查" class="headerlink" title="检查"></a>检查</h1><p>如需要进行用户身份认证,则需要执行下面查询语句:</p><figure class="highlight plain"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs mysql">select * from admin where username='zhaowuya' and passwd=md5('123456');<br></code></pre></div></td></tr></table></figure><p>结果为:</p><div class="table-container"><table><thead><tr><th>username</th><th>password</th></tr></thead><tbody><tr><td>admin</td><td>e10adc3949ba59abbe56e057f20f883e</td></tr></tbody></table></div><p><a class="btn" href="https://www.bilibili.com/video/BV1uJ411k7wy" title="JavaWeb视频">点击前往B站</a></p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>MySQL</tag>
</tags>
</entry>
<entry>
<title>Fluid小技巧</title>
<link href="/2021/05/12/hexotips/"/>
<url>/2021/05/12/hexotips/</url>
<content type="html"><![CDATA[<h1 id="Fluid-Tag插件"><a href="#Fluid-Tag插件" class="headerlink" title="Fluid Tag插件"></a>Fluid Tag插件</h1><p>最近在写文章的时候,长篇大论,颜色单一,很难有读下去的欲望。于是准备去Fluid的配置指南找点灵感。咦!还真找到了Tag插件,有7种颜色可以选择,彩虹🌈面板不再是梦想。</p><h2 id="便签"><a href="#便签" class="headerlink" title="便签"></a>便签</h2><p>在 markdown 中加入如下的代码来使用便签:</p><figure class="highlight markdown"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs markdown">{% note success %}<br>文字 或者 markdown 均可<br>{% endnote %}<br></code></pre></div></td></tr></table></figure><figure class="highlight html"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"note note-primary"</span>></span>标签<span class="hljs-tag"></<span class="hljs-name">p</span>></span><br></code></pre></div></td></tr></table></figure><p>第一种是我最近经常用到的,感觉比HTML来的快。</p><p>可选便签:</p><div class="note note-primary"> <p>primary</p> </div><div class="note note-secondary"> <p>secondary</p> </div><div class="note note-success"> <p>success</p> </div><div class="note note-danger"> <p>danger</p> </div><div class="note note-warning"> <p>warning</p> </div><div class="note note-info"> <p>info</p> </div><div class="note note-light"> <p>light</p> </div><p>使用时 <code>{% note primary %} {% endnote %}</code> 这两块代码需要单独一行,否则会出现问题。源码例如:</p><figure class="highlight markdown"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs markdown">{% note info %}<br>info<br>{% endnote %}<br></code></pre></div></td></tr></table></figure><h2 id="行内标签"><a href="#行内标签" class="headerlink" title="行内标签"></a>行内标签</h2><p>在 markdown 中加入如下的代码来使用 Label:</p><figure class="highlight markdown"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs markdown">{% label primary @text %}<br></code></pre></div></td></tr></table></figure><p>或者使用 HTML 形式:</p><figure class="highlight html"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"label label-primary"</span>></span>Label<span class="hljs-tag"></<span class="hljs-name">span</span>></span><br></code></pre></div></td></tr></table></figure><p>可选Label有<code>primary</code>,<code>default</code>,<code>info</code>,<code>success</code>,<code>warning</code>,<code>danger</code>。</p><span class="label label-primary">primary</span><span class="label label-default">default</span><span class="label label-info">info</span><span class="label label-success">success</span><span class="label label-warning">warning</span><span class="label label-danger">danger</span><h2 id="按钮"><a href="#按钮" class="headerlink" title="按钮"></a>按钮</h2><p>你可以在markdown中加入如下的代码来使用Button:</p><figure class="highlight markdown"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs markdown">{% btn url, text, title %}{% btn url, text, title %}<br></code></pre></div></td></tr></table></figure><p>或者使用HTML形式:</p><figure class="highlight html"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"title"</span>></span>text<span class="hljs-tag"></<span class="hljs-name">a</span>></span><br></code></pre></div></td></tr></table></figure><div class="table-container"><table><thead><tr><th>属性</th><th>含义</th></tr></thead><tbody><tr><td>url</td><td>跳转链接</td></tr><tr><td>text</td><td>显示的文字</td></tr><tr><td>title</td><td>鼠标悬停时显示的文字(可选)</td></tr></tbody></table></div><p><a class="btn" href="https://www.bilibili.com/video/BV1UA411376M" title="元气小姐姐哦">点击前往B站</a></p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Hexo</tag>
<tag>Fluid</tag>
</tags>
</entry>
<entry>
<title>Linux初体验</title>
<link href="/2021/05/07/linuxshell/"/>
<url>/2021/05/07/linuxshell/</url>
<content type="html"><![CDATA[<h1 id="Linux与Shell编程"><a href="#Linux与Shell编程" class="headerlink" title="Linux与Shell编程"></a>Linux与Shell编程</h1><h2 id="Linux介绍"><a href="#Linux介绍" class="headerlink" title="Linux介绍"></a>Linux介绍</h2><h3 id="历史"><a href="#历史" class="headerlink" title="历史"></a>历史</h3><p>1991年,芬兰赫尔辛基大学的学生🧑Linus Torvalds在Intel 386个人计算机上开发了Linux核心,并利用Internet发布了源码,从而创建了Linux操作系统。之后,有许多大佬给它不断完善,改进和提高。近年来,Linux得到了许多硬件公司的支持,他们开发Linux应用软件,将Linux系统的应用推向各个领域。Linux成功的意义不仅在于Linux操作系统本身,还在于Linus多建立的全新的软件开发方法和GNU精神。自由软件从此变得流行起来。</p><h3 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h3><ol><li><p>与UNIX系统兼容。现在的Linux已经具有了全部UNIX的特征,遵循IEEE POSIX标准的操作系统。Linux系统上使用的命令多数与UNIX命令在名称,格式,功能上相同。</p></li><li><p>自由软件和源码公开。这也是我们经常说的,不像Windows操作系统是封闭的,Linux是开放的。从一开始它就与GNU项目紧密结合起来,许多重要组成部分直接来自于GNU项目。任何人都可以自由使用Linux源程序来开发,激发了全世界人们的创造力。而且通过Internet,这一软件得到迅速传播和广泛使用。</p></li><li><p>性能高和安全性强。在相同硬件环境下,Linux也可以提供各种高性能的服务。Linux还提供了先进的网络支持。因为源码是公开的,所以可以消除系统中是否有“后门”的疑惑。</p></li><li><p>互操作性高。Linux能够以不同的方式实现与非Linux系统的不同层次的互操作。比如客户-服务器,工作站,仿真等。</p></li><li>全面多任务和真正的32位操作系统。Linux允许多个用户同时在一个系统上运行多道程序,支持多种硬件平台。</li></ol><h3 id="版本"><a href="#版本" class="headerlink" title="版本"></a>版本</h3><p>Linux有两种版本:核心(Kernel)版本和发行(Distribution)版本。</p><p>核心版本主要是Linux内核,创始人在不断开发和推出新的内核,内核版本由Linus Torvalds本人维护着。版本号由三部分数字构成,其形式为:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">major.minor.patchlevel<br></code></pre></div></td></tr></table></figure><p>其中,major为主版本号,minor为次版本号,patchlevel表示对当前版本的修订次数。</p><p>发行版本是由各个公司推出的版本,通常将安装界面,系统设定,管理工具集成在一起,构成一个套件,从而方便用户使用,尽管这样,普通用户使用Linux发行版本的人数还是很少,软件支持的也少。目前,有Red Hat,Debian,Ubuntu,红旗Linux,Deepin等发行版。</p><h2 id="Linux命令"><a href="#Linux命令" class="headerlink" title="Linux命令"></a>Linux命令</h2><h3 id="简单命令"><a href="#简单命令" class="headerlink" title="简单命令"></a>简单命令</h3><h4 id="1-who"><a href="#1-who" class="headerlink" title="1.who"></a>1.who</h4><p><code>who</code>列出所有正在使用系统的用户,所用终端名和注册到系统的时间。而<code>whoami</code>将列出当前用户信息。</p> <figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ who<br>chris :0 2021-05-07 17:43 (:0)<br>$ whoami <br>chris<br></code></pre></div></td></tr></table></figure><h4 id="2-echo"><a href="#2-echo" class="headerlink" title="2.echo"></a>2.echo</h4><p>将命令行中参数标准输出,相当于<code>cout</code>,<code>printf</code>。要注意空格折叠的问题,例如:</p> <figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">echo</span> Hello world<br>Hello world<br>$ <span class="hljs-built_in">echo</span> <span class="hljs-string">'bye bye'</span><br><span class="hljs-built_in">bye</span> <span class="hljs-built_in">bye</span><br>$ <span class="hljs-built_in">echo</span> <span class="hljs-built_in">bye</span> <span class="hljs-built_in">bye</span><br><span class="hljs-built_in">bye</span> <span class="hljs-built_in">bye</span><br></code></pre></div></td></tr></table></figure><h4 id="3-date"><a href="#3-date" class="headerlink" title="3.date"></a>3.date</h4><p>用来显示当前日期和时间,例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ date<br>Fri May 7 17:14:49 CST 2021<br></code></pre></div></td></tr></table></figure><h4 id="4-cal"><a href="#4-cal" class="headerlink" title="4.cal"></a>4.cal</h4><p>用来显示公元1~9999年中任意一年或者一个月的日历,第一个参数为月份(也可以用英文缩写表示),第二参数为年份,若不写参数,则显示当前月份的日历,例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ cal 2 2021<br> February 2021<br>Su Mo Tu We Th Fr Sa<br> 1 2 3 4 5 6<br> 7 8 9 10 11 12 13<br>14 15 16 17 18 19 20<br>21 22 23 24 25 26 27<br>28<br></code></pre></div></td></tr></table></figure><h4 id="5-clear"><a href="#5-clear" class="headerlink" title="5.clear"></a>5.clear</h4><p>用来清除屏幕上的信息。清屏后,提示符移到屏幕左上角。例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ clear<br>$ _<br></code></pre></div></td></tr></table></figure><h4 id="6-passwd"><a href="#6-passwd" class="headerlink" title="6.passwd"></a>6.passwd</h4><p>用来修改口令,也就是密码。Linux的安全特性允许用户控制自己的口令,输入后,按照提示来就可修改密码,出于安全考虑,输入的密码都不会在屏幕上显示,所以不要以为自己的键盘⌨坏了哟。例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ passwd<br>Change password <span class="hljs-keyword">for</span> user chris<br>(current) UNIX password:<br>New UNIX password:<br>Retype new UNIX password:<br>passwd:all authentication tokens updated successfully.<br></code></pre></div></td></tr></table></figure><h4 id="7-pwd"><a href="#7-pwd" class="headerlink" title="7.pwd"></a>7.pwd</h4><p>用来显示当前工作目录,全称为<code>Print Working Directory</code>。例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">pwd</span><br>/home/chris/Downloads<br></code></pre></div></td></tr></table></figure><h4 id="8-cd"><a href="#8-cd" class="headerlink" title="8.cd"></a>8.cd</h4><p>用来进入某个文件夹,全称为<code>Change Directory</code>,也就是改变工作目录。例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">~$ <span class="hljs-built_in">cd</span> Downloads<br>Downloads$ _<br></code></pre></div></td></tr></table></figure><h4 id="9-rm"><a href="#9-rm" class="headerlink" title="9.rm"></a>9.rm</h4><p>用来删除文件或者目录下的文件,不加任何参数的话,只能删除文件,不能删除文件夹,全称为<code>Remove</code>。注意, 该命令是一个危险的命令,使用的时候要特别当心,尤其对于新手,否则整个系统就会毁在这个命令(比如在根目录下执行<code>rm -rf /*</code>)。所以,我们在执行rm之前最好先确认一下在哪个目录,到底要删除什么东西,操作时保持高度清醒的头脑。</p><div class="table-container"><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-f</td><td>忽略不存在的文件,不会出现警告信息</td></tr><tr><td>-r</td><td>递归删除,后可接上文件夹</td></tr><tr><td>-v</td><td>显示指令的详细执行过程</td></tr><tr><td>-i</td><td>删除前会询问用户是否操作</td></tr></tbody></table></div><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ rm -r Study<br>$ rm hello.c<br></code></pre></div></td></tr></table></figure><h4 id="10-cp"><a href="#10-cp" class="headerlink" title="10.cp"></a>10.cp</h4><p>用来对文件进行复制,全称为<code>Copy</code>。后面的文件可以不存在,系统会帮你创建。例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ cp hello.c h.c<br></code></pre></div></td></tr></table></figure><h4 id="11-mv"><a href="#11-mv" class="headerlink" title="11.mv"></a>11.mv</h4><p>用来对文件或文件夹进行移动,全称为<code>Move</code>如果文件或文件夹存在于当前工作目录,还可以对文件或文件夹进行重命名。例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ mv hello.c /home/chris/Downloads<br></code></pre></div></td></tr></table></figure><h4 id="12-cat"><a href="#12-cat" class="headerlink" title="12.cat"></a>12.cat</h4><p>用来在标准输出(监控器或屏幕)上查看文件内容,全称为<code>Concatenate and Print Files</code>。例如:</p><figure class="highlight c"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c">$ cat hello.c<br><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span><span class="hljs-meta-string"><stdio.h></span></span><br><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Hello World!"</span>);<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></div></td></tr></table></figure><h3 id="快乐命令"><a href="#快乐命令" class="headerlink" title="快乐命令"></a>快乐命令</h3><h4 id="1-sl"><a href="#1-sl" class="headerlink" title="1.sl"></a>1.sl</h4><p>你会看到火车🚄从屏幕右边开往左边。相关的参数可以去搜一下。</p><p>安装:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ sudo apt-get install sl<br></code></pre></div></td></tr></table></figure><p>运行:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ sl<br></code></pre></div></td></tr></table></figure><p>可以来个恶作剧,把<code>ls</code>和<code>sl</code>绑定在一起哈哈哈哈。</p><h4 id="2-fortune"><a href="#2-fortune" class="headerlink" title="2.fortune"></a>2.fortune</h4><p>输出一句话,有笑话🤗,名人名言🙍♂️,唐诗宋词📔等等。</p><p>安装:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ sudo apt-get install fortune<br></code></pre></div></td></tr></table></figure><p>运行:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ fortune<br></code></pre></div></td></tr></table></figure><h4 id="3-cowsay"><a href="#3-cowsay" class="headerlink" title="3.cowsay"></a>3.cowsay</h4><p>用ASCII字符打印牛🐂,羊🐏等动物,哈哈哈,快来试试吧!</p><p>安装:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ sudo apt-get install cowsay<br></code></pre></div></td></tr></table></figure><p>运行:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ cowsay <span class="hljs-string">"I am a cool boy"</span><br>$ cowsay -f tux <span class="hljs-string">"wuwuwu"</span><br></code></pre></div></td></tr></table></figure><h2 id="重定向"><a href="#重定向" class="headerlink" title="重定向"></a>重定向</h2><p>标准输入重定向(STDIN,文件描述符为0):默认从键盘输入,也可从其他文件或命令中输入。</p><p>标准输出重定向(STDOUT,文件描述符为1):默认输出到屏幕。</p><p>错误输出重定向(STDERR,文件描述符为2):默认输出到屏幕。</p><p>常用小技巧😄,将命令执行的标准输出重定向到一个文件中(清空原有文件的数据),例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">pwd</span> > file.txt<br>$ cat file.txt<br>/home/chris<br></code></pre></div></td></tr></table></figure><p>将错误输出重定向到一个文件中(清空原有文件的数据),例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">pwd</span> 2> file.txt<br></code></pre></div></td></tr></table></figure><p>将标准输出重定向到一个文件中,注意和第一个不同,这个<code>>></code>是追加到原有内容的后面,不会清空原有数据,同理,也能将错误输出重定向到文件中(追加),继续上面的操作来,例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">pwd</span> >> file.txt<br>$ cat file.txt<br>/home/chris<br>/home/chris<br>$ <span class="hljs-built_in">pwd</span> 2>> file.txt<br></code></pre></div></td></tr></table></figure><p>最后是将标准输出与错误输出共同写入到文件中(追加到原有内容的后面用<code>>></code>,覆盖原有用<code>></code>),有两种方法,例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">pwd</span> >> file.txt 2>&1<br>$ <span class="hljs-built_in">pwd</span> &>> file.txt<br></code></pre></div></td></tr></table></figure><h2 id="管道符"><a href="#管道符" class="headerlink" title="管道符"></a>管道符</h2><p><code>|</code>在键盘上👆按下<kbd>Shift</kbd>+<kbd>\</kbd>就可以看到管道符啦。其执行格式为<code>oder A | oder B</code>。管道符的作用,用我们老师的话来说就是把前一个命令的输出当作后一个命令的输入,是不是好懂些了?例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ ls -l | wc -l <br></code></pre></div></td></tr></table></figure><p>这个命令的解释就是列出当前目录的文件,然后统计其行数,当然,文件list是不会在屏幕上显示的,因为它又被当作输入了。因此,最后的结果仅仅为一个数。</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">7<br></code></pre></div></td></tr></table></figure><p>这个管道符就像一个法宝,可以将它套用到其他不同的命令上。</p><h2 id="通配符"><a href="#通配符" class="headerlink" title="通配符"></a>通配符</h2><p>大家可能都有提笔忘字的时候,程序员也不例外,当然,我们是敲盘忘字。比如说我们想找一个文件名以a开头的文件,又隐隐约约记不得后面的单词了,这个时候,通配符就可以大展身手了🤝。</p><div class="table-container"><table><thead><tr><th>通配符</th><th>匹配含义</th></tr></thead><tbody><tr><td>*</td><td>任意字符</td></tr><tr><td>?</td><td>单个任意字符</td></tr><tr><td>[a-z]</td><td>单个小写字母</td></tr><tr><td>[A-Z]</td><td>单个大写字母</td></tr><tr><td>[0-9]</td><td>单个数字</td></tr><tr><td>[:alpha:]</td><td>任意字母</td></tr><tr><td>[:upper:]</td><td>任意大写字母</td></tr><tr><td>[:lower:]</td><td>任意小写字母</td></tr><tr><td>[:digit:]</td><td>所有数字</td></tr><tr><td>[:alnum:]</td><td>任意字母加数字</td></tr><tr><td>[:punct:]</td><td>标点符号</td></tr></tbody></table></div><p>通配符还可以和大括号<code>{}</code>结合起来用,字段之间用逗号<code>,</code>间隔,例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">echo</span> file{1,2,3,4}<br>file1 file2 file3 file4<br></code></pre></div></td></tr></table></figure><h2 id="转义符"><a href="#转义符" class="headerlink" title="转义符"></a>转义符</h2><p>为了能够更好地理解用户的表达,Shell解释器还提供了特别丰富的转义字符来处理输入的特殊数据。在网上找到了4个最常用的转义字符🙋♂️!</p><ul><li><p>反斜杠(\):使反斜杠后面的一个变量变为<strong>单纯的字符</strong>。</p></li><li><p>单引号(’’):转义其中所有的变量为<strong>单纯的字符串</strong>。</p></li><li><p>双引号(””):<strong>保留</strong>其中的变量属性,不进行转义处理。</p></li><li><p>反引号(``):把其中的命令<strong>执行后返回结果</strong>,其中放的是像ls,pwd,date类似的命令。</p></li></ul><p>下面看几个例子:<br><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ price=2<br>$ <span class="hljs-built_in">echo</span> <span class="hljs-string">"Price is <span class="hljs-variable">$price</span>"</span><br>Price is 5<br></code></pre></div></td></tr></table></figure></p><p>可以看到我们想要输出的美元符号不见了,不标明货币单位,那有时候可能会出大问题的哦👊。那我们想要输出美元符号,应该怎么做呢?聪明的你应该猜到了。</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"Price is $<span class="hljs-variable">$price</span>"</span><br>Price is 3577price<br></code></pre></div></td></tr></table></figure><p>很不幸的是,$$刚好是显示当前程序的进程ID号码,所以结果还是不对。正确的应该是这样的:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"Price is \$<span class="hljs-variable">$price</span>"</span><br>Price is <span class="hljs-variable">$5</span><br></code></pre></div></td></tr></table></figure><p>反引号的例子如下:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">echo</span> `<span class="hljs-built_in">pwd</span>`<br>/home/chris/bin<br></code></pre></div></td></tr></table></figure><p>就是先执行反引号里的命令,然后再标准输出到屏幕上。</p><p>单引号是最简单的啦,最单纯的,不管里面有啥东西,照搬着输出就可以了。例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">echo</span> <span class="hljs-string">'$price is \$price'</span><br><span class="hljs-variable">$price</span> is \<span class="hljs-variable">$price</span><br></code></pre></div></td></tr></table></figure><p>以上的转义字符都不容易出错,而什么时候该用双引号却是一个问题。因为好像大多数情况下加不加效果都一样:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">echo</span> <span class="hljs-string">"aaa bbb ccc"</span><br>aaa bbb ccc<br>$ <span class="hljs-built_in">echo</span> aaa bbb ccc<br>aaa bbb ccc<br></code></pre></div></td></tr></table></figure><p>区别在于用户无法得知第一种执行方式中到底有几个参数,是的,不能确定!因为有可能把“aaa bbb ccc”当作了一个参数整体直接输出到了屏幕,也有可能是分别将aaa、bbb和ccc输出到了屏幕。</p><figure class="highlight markdown"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs markdown">{% note success %}<br><br>给大家总结一个简单小技巧,就是参数中如果出现了空格,那么就加双引号,如果参数中没有空格,那就不用加。(来自刘遄老师的小提示)<br><br>{% endnote %}<br></code></pre></div></td></tr></table></figure><h2 id="环境变量"><a href="#环境变量" class="headerlink" title="环境变量"></a>环境变量</h2><p>变量是计算机系统里用于保存可变值的数据类型。在Linux系统中,变量名称一般都是大写的,而命令都是小写的,也算一种规范了。下面我们来看看最基本的变量。如下表所示:</p><div class="table-container"><table><thead><tr><th>变量名称</th><th>作用</th></tr></thead><tbody><tr><td>HOME</td><td>用户的主目录(家目录)</td></tr><tr><td>SHELL</td><td>用户在使用的Shell解释器名称</td></tr><tr><td>HISTSIZE</td><td>输出的历史命令记录条数</td></tr><tr><td>MAIL</td><td>邮件保存路径</td></tr><tr><td>LANG</td><td>系统语言</td></tr><tr><td>RANDOM</td><td>随机数字</td></tr><tr><td>PATH</td><td>定义解释器搜索用户执行命令的路径</td></tr><tr><td>PS1</td><td>Bash解释器的提示符</td></tr><tr><td>EDITOR</td><td>用户默认文本编辑器</td></tr></tbody></table></div><div class="note note-warning"> <p>Linux作为一个多用户多任务的操作系统,能够为每个用户提供独立的、合适的工作运行环境,因此,一个相同的变量会因为用户身份的不同而具有不同的值。</p> </div><p>我们可以使用下述命令来查看变量的值:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">echo</span> <span class="hljs-variable">$HOME</span><br>/home/chris<br></code></pre></div></td></tr></table></figure><p>其实变量是由固定的变量名与用户或者系统设置的变量两部分组成的,完全可以自行创建变量。例如设置名叫<code>WORKDIR</code>的变量:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ mkdir /home/workdir<br>$ WORKDIR=/home/workdir<br>$ <span class="hljs-built_in">cd</span> <span class="hljs-variable">$WORKDIR</span><br>$ <span class="hljs-built_in">pwd</span><br>/home/workdir<br></code></pre></div></td></tr></table></figure><p>但是此时的变量不具有全局性,格局小了呀🤨,不能被其他用户使用,但是我们可以使用<code>export</code>命令将其提升为全局变量。</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">export</span> WORKDIR<br>$ su ordinary<br>$ <span class="hljs-built_in">cd</span> <span class="hljs-variable">$WORKDIR</span><br>$ <span class="hljs-built_in">pwd</span><br>/home/workdir<br></code></pre></div></td></tr></table></figure><p>后面要是不用这个变量了,也可以取消它:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ <span class="hljs-built_in">unset</span> WORKDIR<br></code></pre></div></td></tr></table></figure><div class="note note-warning"> <p>直接在终端设置的变量能够立即生效,但重启服务器后就会消失掉,因此我们需要将变量和变量值写入到.bashrc或者.bash_profile文件中以确保永久能使用它们。</p> </div><h2 id="Vim技巧"><a href="#Vim技巧" class="headerlink" title="Vim技巧"></a>Vim技巧</h2><p>在Linux中,命令行中也能编辑文本,这时就能用到vim了。基本上vim共分为三种模式,分别是<strong>命令模式(Command mode)</strong>,<strong>输入模式(Insert mode)</strong>和<strong>底线命令模式(Last line mode)</strong>。</p><h3 id="命令模式"><a href="#命令模式" class="headerlink" title="命令模式"></a>命令模式</h3><p>当我们打开vim编辑文件的时候,我们首先进入的就是命令模式,此时你按键盘输入,文本上是不会显示的,而是被当作一个命令。常用的有:</p><ul><li><code>i</code> 切换到输入模式,以输入字符。</li><li><code>x</code> 删除当前光标所在处的字符,最后还是停留在命令模式。</li><li><code>:</code> 切换到底线命令模式,以在最底一行输入命令。</li></ul><h3 id="输入模式"><a href="#输入模式" class="headerlink" title="输入模式"></a>输入模式</h3><p>基本就是正常输入,有几个要注意的:</p><ul><li>按下<kbd>Insert</kbd>,切换光标为输入/替换模式。</li><li>按下<kbd>Esc</kbd>,退出输入模式,切换到命令模式。</li></ul><h3 id="底线命令模式"><a href="#底线命令模式" class="headerlink" title="底线命令模式"></a>底线命令模式</h3><p>在命令模式下按下<code>:</code>就进入了底线命令模式。底线命令模式可以输入单个或多个字符的命令,可用的命令非常多。</p><p>在底线命令模式中,基本的命令有(已经省略了冒号):</p><ul><li><code>w</code>将编辑的数据写入硬件中,也就是保存。</li><li><code>q</code>离开退出vim。</li><li><code>q!</code>强制退出vim,没有保存修改。</li><li><code>wq</code>保存退出。</li><li><code>ZZ</code>大写的Z,如果修改过,保存当前文件,然后退出。</li><li><code>dd</code>删除光标所在的一整行。</li><li><code>set nu</code>为vim设置行号。</li><li><code>set nonu</code>取消vim中的行号。</li></ul><h2 id="Shell编程"><a href="#Shell编程" class="headerlink" title="Shell编程"></a>Shell编程</h2><h3 id="Shell简介"><a href="#Shell简介" class="headerlink" title="Shell简介"></a>Shell简介</h3><p>shell可以理解为一种脚本语言,像javascript等其它脚本语言一样,只需要一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以shell脚本的本质是:以某种语法格式将shell命令组织起来的由shell程序解析执行的脚本文本文件。主要包括三个部分:</p><ol><li><strong>shell命令</strong>:即<code>ls/cd</code>等linux命令,详细可参考<a href="http://codetoolchains.readthedocs.io/en/latest/4-Linux/2-shellcmd/index.html">shell命令</a>。</li><li><strong>shell解释器</strong>:即<code>sh/bash/zsh</code>等shell应用程序,详细可参考<a href="http://codetoolchains.readthedocs.io/en/latest/4-Linux/1-shellenv/1-shellsoft/index.html">shell应用程序。</a></li><li><strong>shell语法</strong>:即<code>数据类型/变量/控制流语句/函数</code>等编程语法。</li></ol><h3 id="脚本结构"><a href="#脚本结构" class="headerlink" title="脚本结构"></a>脚本结构</h3><p>像学习我们的第一门编程语言,C语言时,我们现在也来模仿着写一个Hello World的程序,虽然可能现在搞不明白它的结构和过程,但是没关系,大家都是这么过来的。先创建一个demo.sh文件,然后进去编辑它:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ vim demo.sh<br></code></pre></div></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><span class="hljs-meta">#!/bin/bash</span><br><span class="hljs-comment"># 这行是注释信息</span><br>str=<span class="hljs-string">"Hello World"</span><br><br><span class="hljs-function"><span class="hljs-title">test</span></span>(){<br> <span class="hljs-built_in">echo</span> <span class="hljs-variable">$str</span><br>}<br><br><span class="hljs-built_in">test</span> echo_str<br></code></pre></div></td></tr></table></figure><p>写完后输入<code>:wq</code>保存退出,然后运行脚本。脚本都以<code>#!/bin/bash</code>开头,<code>#</code>称为<code>sharp</code>,<code>!</code>在unix行话里称为<code>bang</code>,合起来简称就是常见的<code>shabang</code>。是不是很搞笑,同时也突然觉得自己变成高手了🐶。而运行脚本文件的方法有两种:</p><ol><li>将脚本作为bash解释器的参数执行:此时首行的<code>#!/bin/bash</code>shabang可以不用写。</li><li><code>chmod +x demo.sh</code>:给脚本添加执行权限,<code>./demo.sh</code>:执行脚本文件。</li></ol><p>最后Hello World就会出现在终端上:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">Hello World<br></code></pre></div></td></tr></table></figure><h3 id="Shell变量"><a href="#Shell变量" class="headerlink" title="Shell变量"></a>Shell变量</h3><div class="table-container"><table><thead><tr><th>变量</th><th>含义</th></tr></thead><tbody><tr><td>$$</td><td>Shell本身的PID</td></tr><tr><td>$!</td><td>Shell最后运行的后台Process的PID</td></tr><tr><td>$?</td><td>最后运行代码的返回值</td></tr><tr><td>$*</td><td>所有参数列表</td></tr><tr><td>$@</td><td>所有参数列表(好像并没有什么不同,我也不知道)</td></tr><tr><td>$#</td><td>参数的个数</td></tr><tr><td>$0</td><td>Shell脚本的文件名</td></tr><tr><td>$1~n</td><td>各个参数的值</td></tr></tbody></table></div><p>例如:</p><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash"><span class="hljs-meta">#!/bin/bash</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"$$"</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"$!"</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"$?"</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"$*"</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$@</span>"</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$#</span>"</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$0</span>"</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$2</span>"</span><br></code></pre></div></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">$ bash demo.sh zwy 2<br>91<br><br>0<br>zwy 2<br>zwy 2<br>2<br>demo.sh<br>zwy<br>2<br></code></pre></div></td></tr></table></figure>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Shell</tag>
</tags>
</entry>
<entry>
<title>ABP框架初体验</title>
<link href="/2021/01/11/abp/"/>
<url>/2021/01/11/abp/</url>
<content type="html"><![CDATA[<h1 id="ABP"><a href="#ABP" class="headerlink" title="ABP"></a>ABP</h1><p>简介:</p><p>ABP(ASP.NET Boilerplate Project (ASP.NET样板项目)<br>ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点,它旨在成为一个通用的WEB应用程序框架和项目模板。<br><strong>框架</strong><br>ABP是基于最新的ASP.NET CORE,ASP.NET MVC和Web API技术的应用程序框架。并使用流行的框架和库,它提供了便于使用的授权,依赖注入,验证,异常处理,本地化,日志记录,缓存等常用功能。<br><strong>架构</strong><br>ABP实现了多层架构(领域层,应用层,基础设施层和表示层),以及领域驱动设计(实体,存储库,领域服务,应用程序服务,DTO等)。还实现和提供了良好的基础设施来实现最佳实践,如依赖注入。<br><strong>模板</strong><br>ABP轻松地为您的项目创建启动模板。它默认包括最常用的框架和库。还允许您选择单页(Angularjs)或多页架构,EntityFramework或NHibernate作为ORM。<br>访问<a href="https://aspnetboilerplate.com/">官网</a>,了解更多。</p><h2 id="Application-应用层"><a href="#Application-应用层" class="headerlink" title="Application 应用层"></a>Application 应用层</h2><p>在这里写接口。</p><p>新建两个文件,文件里面实现一个接口和一个实例,<code>IUserAppService.cs</code>和<code>UserAppService.cs</code>。</p><h3 id="Dto"><a href="#Dto" class="headerlink" title="Dto"></a>Dto</h3><p>数据传输对象DTO(Data Transfer Object),是一种设计模式之间传输数据的软件应用系统。</p><ul><li><p>Dto命名格式:ABP建议命名输入/输出参数为:MethodName<strong>Input</strong>和MethodName<strong>Output</strong></p></li><li><p>并为每个应用服务方法定义单独的输入和输出DTO(如果为每个方法的输入输出都定义一个dto,那将有一个庞大的dto类需要定义维护。一般通过定义一个公用的dto进行共用)</p></li><li><p>即使你的方法只接受/返回一个参数,也最好是创建一个DTO类</p></li><li><p>一般会在对应实体的应用服务文件夹下新建Dtos文件夹来管理Dto类。</p></li></ul><div class="table-container"><table><thead><tr><th>传值方式</th><th>命名格式(一般情况)</th></tr></thead><tbody><tr><td>POST</td><td>Create,Insert,Change,Reset开头的</td></tr><tr><td>DELETE</td><td>Delete,Remove开头的</td></tr><tr><td>GET</td><td>Get开头的</td></tr><tr><td>PUT</td><td>Put,Update开头的</td></tr></tbody></table></div><p>“<code>=></code>”是<strong>C# 3.0</strong>新增的,告诉编译器我们正在使用<code>Lambda</code>表达式。”<code>=></code>”可以读作”<code>goes to</code>”。</p><p>B站视频后端部分<a href="https://www.bilibili.com/video/BV155411W7yL?p=2&t=2762">ABP全栈开发</a> <code>80:22</code>,<code>62:45</code>。</p><h3 id="映射"><a href="#映射" class="headerlink" title="映射"></a>映射</h3><h4 id="自动映射"><a href="#自动映射" class="headerlink" title="自动映射"></a>自动映射</h4><p>映射时,可以在视图模型里告诉数据来自哪个模型。<code>给</code>和<code>来自</code>于不一样。</p><figure class="highlight c#"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c#">[<span class="hljs-meta">AutoMapFrom(typeof(Task))</span>]<br>[<span class="hljs-meta">AutoMapTo(typeof(Task))</span>]<br></code></pre></div></td></tr></table></figure><h4 id="自定义映射"><a href="#自定义映射" class="headerlink" title="自定义映射"></a>自定义映射</h4><p>简单地映射可能不适用于一些场景,如,两个类的属性名称有些不同或你可能想要在映射过程中忽略一些属性,这些情况下可以直接使用AutoMapper的Api来自定义映射关系,不过Abp.AutoMapper包定义了更模块化的API。</p><h3 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h3><p>生成动态API接口时,我们的自己写的接口需要继承的一个更往后的接口<code>AppService</code>。只有继承这个接口,我们在创建时,才能够找到API,把它给创建出来。</p><p>例如:</p><figure class="highlight c#"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c#"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IUserAppService</span>:<span class="hljs-title">IAppService</span> {}<br></code></pre></div></td></tr></table></figure><h3 id="实例"><a href="#实例" class="headerlink" title="实例"></a>实例</h3><p>继承于<code>项目名+AppServiceBase</code>和<code>IUserAppService</code>,只有继承了这两个接口,在创建时,被发现才能映射到前面去。Test是我自己的项目名。</p><figure class="highlight c#"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c#"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">TaskAppService</span> : <span class="hljs-title">TestAppServiceBase</span>, <span class="hljs-title">ITaskAppService</span> {}<br></code></pre></div></td></tr></table></figure><p>然后依赖注入</p><p>打开Swagger UI 找到自己的接口,try一下。如果数据库有数据,会按照json格式显示出来。</p><h3 id="仓储"><a href="#仓储" class="headerlink" title="仓储"></a>仓储</h3><p>仓储(Repository) 用来操作数据库进行数据存取。仓储接口在领域层定义,而仓储的实现类应该写在基础设施层。</p><p>在ABP中,仓储类要实现<code>IRepository</code>接口,接口定义了常用的增删改查以及聚合方法,其中包括同步及异步方法。如果业务简单,那ABP自带的泛型仓储就足够用了。<code>IRepository</code>定义了从<strong>数据库</strong>中检索实体的常用方法。下面列举一些常用的方法。</p><h4 id="查询"><a href="#查询" class="headerlink" title="查询"></a>查询</h4><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp"><span class="hljs-function">TEntity <span class="hljs-title">Get</span>(<span class="hljs-params">TPrimaryKey id</span>)</span>;<br></code></pre></div></td></tr></table></figure><p>Get方法被用于根据主键值(Id)取得对应的<strong>单一实体</strong>。当数据库中根据主键值找不到相符合的实体时,它会抛出异常。</p><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp"><span class="hljs-function">List<TEntity> <span class="hljs-title">GetAllList</span>(<span class="hljs-params"></span>)</span>;<br></code></pre></div></td></tr></table></figure><p>GetAllList方法被用于从数据库中检索<strong>所有实体</strong>。重载并且提供过滤实体的功能(相当于条件查询)。例如:</p><figure class="highlight c#"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c#"><span class="hljs-keyword">var</span> allPeople = _personRepository.GetAllList();<br><span class="hljs-keyword">var</span> somePeople = _personRepository.GetAllList(person => person.IsActive && person.Age > <span class="hljs-number">42</span>);<br></code></pre></div></td></tr></table></figure><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp"><span class="hljs-function">IQueryable<TEntity> <span class="hljs-title">GetAll</span>(<span class="hljs-params"></span>)</span>;<br></code></pre></div></td></tr></table></figure><p>GetAll方法返回IQueryable\<T>类型的<strong>对象</strong>。因此我们可以在调用完这个方法之后进行Linq操作。例如:</p><figure class="highlight c#"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c#"><span class="hljs-keyword">var</span> query = <span class="hljs-keyword">from</span> p <span class="hljs-keyword">in</span> _personRepository.GetAll()<br><span class="hljs-keyword">where</span> p.Age == <span class="hljs-number">20</span><br><span class="hljs-keyword">orderby</span> p.Name<br><span class="hljs-keyword">select</span> p;<br></code></pre></div></td></tr></table></figure><p>说明:关于IQueryable\<T> 当你调用GetAll这个方法在Repository对象以外的地方,必定会开启数据库连接。这是因为IQueryable\<T>允许延迟执行。它会<strong>直到</strong>你调用ToList方法或在forEach循环上(或是一些存取已查询的对象方法)使用IQueryable\<T>时,才会实际<strong>执行数据库的查询</strong>。因此,当你调用ToList方法时,数据库连接必需是启用状态。总结,GetAll方法不会查询数据库,而是知道之行到ToList方法时才会与查询数据库。</p><h4 id="新增"><a href="#新增" class="headerlink" title="新增"></a>新增</h4><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp"><span class="hljs-function">TEntity <span class="hljs-title">Insert</span>(<span class="hljs-params">TEntity entity</span>)</span>;<br><span class="hljs-function">TPrimaryKey <span class="hljs-title">InsertAndGetId</span>(<span class="hljs-params">TEntity entity</span>)</span>;<br><span class="hljs-function">TEntity <span class="hljs-title">InsertOrUpdate</span>(<span class="hljs-params">TEntity entity</span>)</span>;<br><span class="hljs-function">TPrimaryKey <span class="hljs-title">InsertOrUpdateAndGetId</span>(<span class="hljs-params">TEntity entity</span>)</span>;<br></code></pre></div></td></tr></table></figure><p>新增方法会新增实体到数据库并且返回相同的已新增实体。InsertAndGetId方法返回新增实体的标识符(Id)。当我们采用自动递增标识符值且需要取得实体的新产生标识符值时非常好用。InsertOfUpdate会新增或更新实体,选择那一种是根据Id是否有值来决定。最后,InsertOrUpdatedAndGetId会在实体被新增或更新后返回Id值。总结,注意参数和返回值,基本上和查询系列方法类似。</p><h4 id="更新"><a href="#更新" class="headerlink" title="更新"></a>更新</h4><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp"><span class="hljs-function">TEntity <span class="hljs-title">Update</span>(<span class="hljs-params">TEntity entity</span>)</span>;<br></code></pre></div></td></tr></table></figure><p>IRepository定义一个方法来实现更新一个<strong>已存在</strong>于数据库中的实体。它更新实体并返回相同的实体对象。</p><h4 id="删除"><a href="#删除" class="headerlink" title="删除"></a>删除</h4><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">Delete</span>(<span class="hljs-params">TEntity entity</span>)</span>;<br><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">Delete</span>(<span class="hljs-params">TPrimaryKey id</span>)</span>;<br><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">Delete</span>(<span class="hljs-params">Expression<Func<TEntity, <span class="hljs-built_in">bool</span>>> predicate</span>)</span>;<br></code></pre></div></td></tr></table></figure><p>上面两个方法一个是删除实体,一个是通过Id删除,第三个方法接受一个条件来删除符合条件的实体。要注意,所有符合predicate表达式的实体会<strong>先被检索而后删除</strong>。</p><h4 id="其它方法"><a href="#其它方法" class="headerlink" title="其它方法"></a>其它方法</h4><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-built_in">int</span> <span class="hljs-title">Count</span>(<span class="hljs-params"></span>)</span>;<br><span class="hljs-function"><span class="hljs-built_in">int</span> <span class="hljs-title">Count</span>(<span class="hljs-params">Expression<Func<TEntity, <span class="hljs-built_in">bool</span>>> predicate</span>)</span>;<br><span class="hljs-function">Long <span class="hljs-title">LongCount</span>(<span class="hljs-params"></span>)</span>;<br><span class="hljs-function">Long <span class="hljs-title">LongCount</span>(<span class="hljs-params">Expression<Func<TEntity, <span class="hljs-built_in">bool</span>>> predicate</span>)</span>;<br></code></pre></div></td></tr></table></figure><p>IRepository也提供一些方法来取得数据表中实体的数量。要注意的同删除系列的predicate表达式。</p><h2 id="Core-领域层"><a href="#Core-领域层" class="headerlink" title="Core 领域层"></a>Core 领域层</h2><p>在这里写实体类,写各种限制。</p><h3 id="实体类"><a href="#实体类" class="headerlink" title="实体类"></a>实体类</h3><p>我们定义一个实体类Person,并且为它定义两个属性。父类Entity具有主键属性Id。所有继承Entity类的子类都将具有主键为Id的属性。</p><p>Id数据类型可以被更改。默认是 int类型。如果你想给 Id 定义其它类型,你应该像下面示例一样来指定 Id 的类型。</p><figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> : <span class="hljs-title">Entity</span><<span class="hljs-title">long</span>> <br></code></pre></div></td></tr></table></figure><p>C#语法中一个个问号(?)的运算符是指:可以为 null 的类型。 </p><figure class="highlight c#"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c#"><span class="hljs-keyword">public</span> DateTime? CreateTime {<span class="hljs-keyword">get</span>;<span class="hljs-keyword">set</span>;} <br></code></pre></div></td></tr></table></figure><h3 id="领域模型和视图模型"><a href="#领域模型和视图模型" class="headerlink" title="领域模型和视图模型"></a>领域模型和视图模型</h3><div class="table-container"><table><thead><tr><th style="text-align:left">领域模型</th><th>视图模型</th></tr></thead><tbody><tr><td style="text-align:left">在Core层定义了领域模型,在基础设施层的上下文写入,用DbSet方式把领域模型注入进数据库,在应用层使用时,用仓储来获取对当前的数据库的CRUD,总的来说,领域模型是和数据库进行交互的。</td><td>跟视图进行交互,跟前端进行数据交互。要和领域模型产生一个明显的切割,其次,前端拿数据表时字段不是完全按照领域模型来的。前端传回数据也需要视图模型。</td></tr></tbody></table></div><h2 id="EntityFramework-基础设施层"><a href="#EntityFramework-基础设施层" class="headerlink" title="EntityFramework 基础设施层"></a>EntityFramework 基础设施层</h2><p>写数据库上下文类DbSet。</p><h2 id="Web-Host-Web-Core-展现层"><a href="#Web-Host-Web-Core-展现层" class="headerlink" title="Web Host Web Core 展现层"></a>Web Host Web Core 展现层</h2><p>写网页配置,前端开发。</p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>ASP.NET</tag>
</tags>
</entry>
<entry>
<title>我的父亲</title>
<link href="/2020/12/03/myman/"/>
<url>/2020/12/03/myman/</url>
<content type="html"><![CDATA[<p>最近几天一直在忙着复习,做网站搭建,突然老爸在微信上给我发来一条消息,“吃饭了没有?要注意身体啊!”,我猛地抬头,仔细一想,好像是有两个多星期没和家里打电话了,这才急急忙忙跑到图书馆的楼梯口,给他们打了电话,他们正在散步,没有风,时不时还有我老妈的声音在旁边传来,其实也没聊什么,这几天武汉突然降温,搞得我有点猝不及防,我就把在学校的一些大事小事都说给他们听。</p><p>回寝室的路上,突然循环到Jony J的My Man,这种走心的文字其实很容易让人产生共鸣,于是我决定记录下来,每当我心情不好的时候就过来看看也好。</p><div class="note note-success"> <p>网页音乐链接:<a href="https://music.163.com/#/song?id=1325896303">My Man</a></p> </div><h1 id="My-Man"><a href="#My-Man" class="headerlink" title="My Man"></a>My Man</h1><p>突然就想给你打个电话<br>弹个视频来跟你聊聊天<br>其实有时没有那么忙我只是忘了关心<br>你以为我真的没时间<br>过去几年一个人在外面大起大落的过<br>有时迷失有时看破<br>为了我想要的我想做的我跟自己发的誓<br>我有时很拼也有时犯错<br>我比以前更加懂你在长大以后<br>只想给你更多不想再索求<br>我想像你对我那样对你让你过的更加安逸<br>不被现实的压力左右<br>我也想过如何才能成为你的骄傲<br>让你可以提到我就嘴角带着笑<br>还是学不会你跟我说的做人不要那么高调<br>有些毛病我就是改不掉<br>我也常常想到过去就后悔<br>让你为了我在深夜里皱眉<br>没能管住跟你叛逆时的臭嘴<br>以前无知对你说的气话现在我想全部收回<br>离开家以后 外面很美<br>有了新的朋友新的称谓<br>被人羡慕过被泼过冷水<br>后来才体会到家多珍贵<br>我知道你一直担心我选择走的路<br>原则性的问题能不能守得住<br>你不用担心 我在心里有个数<br>虽然也在party上被人搂着吐<br>我也知道外面世界有点复杂像个丛林<br>但现实从来不对弱者同情<br>走在布满雷的游戏中我必须变的聪明<br>但一如既往还是保持憧憬</p><p>你能每天过得好是我的愿望<br>我只希望你跟妈妈开心健康<br>我已经有了能为你承担的肩膀<br>全部都交给我 虽然我身在远方</p><p>偶尔听到你的催促<br>那方面的进度怎么还是龟速<br>看我朋友们都陆续找到归宿<br>说我玩心大到像是还没恢复<br>像责任不敢背负<br>我只是还没碰到我的那个她<br>让我感觉强烈到想跟她有个家<br>做个单身汉的感觉其实还不错<br>起码自己赚的钱都给我自己花<br>很多话跟镜子说<br>交了更多朋友但能聊的并不多<br>还好我有我的团队让我信得过<br>我把不好意思跟你聊的放在歌里说<br>现在做我想做的 过我想过的<br>每一步都走得清楚不会轻易闯祸了<br>为了告诉那些预言家们他们想错了<br>曾经蔑视我的预言全都被我打破了<br>我扬起我的帆<br>做好一切准备已经开动我的船<br>跟我想的不一样这江湖不好玩<br>长大之后越来越能明白你的难<br>那就让我把这生存游戏规则搞熟<br>好在新科技的世界里面做你导游<br>我想为你做到我能做的毫无保留<br>毕竟你是这世界上我最爱的老头 </p>]]></content>
<categories>
<category>生活</category>
</categories>
<tags>
<tag>Hip hop</tag>
</tags>
</entry>
<entry>
<title>Hexo发布时的问题</title>
<link href="/2020/11/25/smallproblem/"/>
<url>/2020/11/25/smallproblem/</url>
<content type="html"><![CDATA[<p>最近一直在修改自己的博客,提升访问速度,突然有一天,我在本地预览的颜色和样式都和预期的一样,但是成功上传之后还是没变化?我直接挠头,按浏览器左上角的刷新按钮也没用,于是上网搜索。恍然大悟,原来需要对浏览器强制刷新!基本的用法我居然不知道,惭愧惭愧。</p><p><kbd>Shift</kbd>+<kbd>F5</kbd></p><p>强制刷新的艺术🤔</p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Hexo</tag>
</tags>
</entry>
<entry>
<title>前端与.Net笔记</title>
<link href="/2020/11/25/webstudy/"/>
<url>/2020/11/25/webstudy/</url>
<content type="html"><![CDATA[<!-- .NET 复习文档,仅供参考。努力学习 JavaScript,才能成为大佬。more --><h1 id="复习大纲"><a href="#复习大纲" class="headerlink" title="复习大纲"></a>复习大纲</h1><h2 id="HTML"><a href="#HTML" class="headerlink" title="HTML"></a>HTML</h2><h3 id="常见的块级元素和行内元素"><a href="#常见的块级元素和行内元素" class="headerlink" title="常见的块级元素和行内元素"></a>常见的块级元素和行内元素</h3><h4 id="块级元素"><a href="#块级元素" class="headerlink" title="块级元素"></a>块级元素</h4><p>div、p、h1~h6、ul、ol、dl(描述列表)、li、dd(描述)、table、hr(分隔)、blockquote(块引用)、address、table、menu、pre(预格式化的文本,保留空格),HTML5 新增的 header、section、aside(侧边栏)、footer。</p><h4 id="行内元素"><a href="#行内元素" class="headerlink" title="行内元素"></a>行内元素</h4><p>span、img、a、lable、input、abbr(缩写)、em(强调)、big、cite(引用)、i(斜体)、q(短引用)、textarea、select、small、sub、sup,strong、u(下划线)、button(默认 display:inline-block)</p><h3 id="ul-和-ol-区别"><a href="#ul-和-ol-区别" class="headerlink" title="ul 和 ol 区别"></a>ul 和 ol 区别</h3><p>ul 是项目列表,li 做列表项,每一项的符号默认是小黑圆点;ol 是编号列表,li 做列表项,每一项的符号默认是数字;li 是 list item 即列表项,但列表有很两种,所以外面得有 ul 或者 ol 用来区别无序列表(小点点)和有序列表(1,2,3)。</p><h3 id="video-标签支持的视频格式"><a href="#video-标签支持的视频格式" class="headerlink" title="video 标签支持的视频格式"></a>video 标签支持的视频格式</h3><div class="table-container"><table><thead><tr><th>格式</th><th>描述</th></tr></thead><tbody><tr><td>MP4</td><td>MPEG4 文件使用 H264 视频编解码器和 AAC 音频编解码器</td></tr><tr><td>WebM</td><td>WebM 文件使用 VP8 视频编解码器和 Vorbis 音频编解码器</td></tr><tr><td>Ogg</td><td>Ogg 文件使用 Theora 视频编解码器和 Vorbis 音频编解码器</td></tr></tbody></table></div><p>通过上面的信息我们会发现只有 h264 编码的 MP4 视频(MPEG-LA 公司)、VP8 编码的 webm 格式的视频(Google 公司)和 Theora 编码的 ogg 格式的视频(iTouch 开发)可以支持 HTML5 的 video 标签。</p><h3 id="input-标签"><a href="#input-标签" class="headerlink" title="input 标签"></a>input 标签</h3><div class="table-container"><table><thead><tr><th>类型</th><th>描述</th></tr></thead><tbody><tr><td>text</td><td>单行的输入文本字段,用户可在其中输入文本。默认宽度为 20 个字符。单行文本字段。换行符将自动从输入值中删除。</td></tr><tr><td>checkbox</td><td>复选框。 允许选择/取消选择单个值的复选框。</td></tr><tr><td>password</td><td>定义密码字段。该字段中的字符被掩码。值被隐藏的单行文本字段。使用 maxlength 和 minlength 属性指定 可输入值的最大长度。</td></tr><tr><td>hidden</td><td>隐藏的输入值: 定义隐藏的输入字段。不显示但其值提交给服务器的控件。</td></tr><tr><td>file</td><td>选择文件. 定义输入字段和 “浏览”按钮,供文件上传。允许用户选择文件的控件。 使用 accept 属性定义控件可以选择的文件类型。</td></tr><tr><td>button</td><td>可点击的按钮。一个没有默认行为的按钮。</td></tr><tr><td>radio</td><td>单选按钮。一个单选按钮,允许从多个选项中选择一个值。</td></tr><tr><td>reset</td><td>重置按钮。重置按钮会 清除表单中的所有数据。将表单内容重置为默认值的按钮。</td></tr><tr><td>submit</td><td>提交按钮。提交按钮会把表单数据发送到服务器。提交表单的按钮。</td></tr><tr><td>image</td><td>图像形式的提交按钮。一个图形化的提交按钮。必须使用 src 属性定义图像的源,使用 alt 属性定义替代文本。可以使用 height 高度和 width 宽度属性,以像素为单位,定义图像的大小。</td></tr></tbody></table></div><h3 id="form-标签"><a href="#form-标签" class="headerlink" title="form 标签"></a>form 标签</h3><div class="table-container"><table><thead><tr><th>标签</th><th>描述</th></tr></thead><tbody><tr><td>select</td><td>定义了下拉选项列表</td></tr><tr><td>input</td><td>创建一个最简单的文本输入框</td></tr><tr><td>textarea</td><td>输入多行、多字数文本</td></tr><tr><td>label</td><td>label 是 input 的描述,它本身不会有特殊效果</td></tr></tbody></table></div><h3 id="锚点"><a href="#锚点" class="headerlink" title="锚点"></a>锚点</h3><p>跳转到当前页面的一个锚点,一般用<code>id</code>值。</p><figure class="highlight html"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#post"</span>></span>第三段<span class="hljs-tag"></<span class="hljs-name">a</span>></span> 点击跳到第三段部分<br><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"post"</span>></span>文章第三段<span class="hljs-tag"></<span class="hljs-name">div</span>></span><br><span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>></span> TOP<span class="hljs-tag"></<span class="hljs-name">a</span>></span> 点击跳到顶部<br></code></pre></div></td></tr></table></figure><h3 id="HTML-DOM"><a href="#HTML-DOM" class="headerlink" title="HTML DOM"></a>HTML DOM</h3><p>在 HTML DOM 中,所有事物都是节点。DOM 是被视为节点树的 HTML。</p><div class="note note-info"> <p>HTML 文档中的所有内容都是节点:整个文档是一个文档节点,每个 HTML 元素是元素节点,HTML 元素内的文本是文本节点,每个 HTML 属性是属性节点,注释是注释节点。</p> </div><h4 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h4><p>element 的<code>innerHTML</code>属性设置或获取 HTML 语法表示的元素的后代。用 innerHTML 插入文本到网页中并不罕见。但这有可能成为网站攻击的媒介,从而产生潜在的安全风险问题。</p><p>tr 的<code>rowIndex</code>属性,返回某一行(rows)在表格的行集合中的位置(row index),索引从零开始。</p><p>table 的<code>deleteRow()</code>方法,用于从表格删除指定位置的行。</p><p>HTMLSelectElement的<code>selectedIndex</code>属性是一个长整型数,它反映了被选中的第一个option元素的下标值。值为-1时表明没有元素被选中。</p><h2 id="CSS"><a href="#CSS" class="headerlink" title="CSS"></a>CSS</h2><h3 id="作用"><a href="#作用" class="headerlink" title="作用"></a>作用</h3><p>CSS 是 Cascading Style Sheets(层叠样式表单)的简称,CSS 就是一种叫做样式表(stylesheet)的技术,也有的人称之为“层叠样式表”(Cascading Stylesheet)。</p><p>在主页制作时采用 CSS 技术,可以有效地对页面的布局、字体、颜色、背景和其它效果实现更加精确的控制。</p><p>只要对相应的代码做一些简单的修改,就可以改变同一页面的不同部分,或者页数不同的网页的外观和格式。</p><p>CSS 大部分代码对大小写不敏感。</p><h3 id="常用选择器"><a href="#常用选择器" class="headerlink" title="常用选择器"></a>常用选择器</h3><div class="table-container"><table><thead><tr><th>选择器</th><th>描述</th></tr></thead><tbody><tr><td>类选择器</td><td>通过类名进行选择.test</td></tr><tr><td>id 选择器</td><td>通过 id 进行选择#test</td></tr><tr><td>标签选择器</td><td>通过 id 进行选择 span</td></tr><tr><td>分组选择器</td><td>可一次选择多个标签以设置相同样式 p,a,li</td></tr><tr><td>后代选择器</td><td>选择某个标签的所有后代以设置相同样式 div ul li</td></tr><tr><td>通用选择器</td><td>选择所有标签以设置相同样式*</td></tr><tr><td>兄弟选择器</td><td>选择兄弟关系的标签设置样式 p+a</td></tr><tr><td>直接父子选择器</td><td>选择父子关系的标签中子标签设置样式 div->p</td></tr></tbody></table></div><h3 id="常用属性"><a href="#常用属性" class="headerlink" title="常用属性"></a>常用属性</h3><h4 id="text-align"><a href="#text-align" class="headerlink" title="text-align"></a>text-align</h4><p>属性定义行内内容如何相对它的块父元素对齐。text-align并不控制块元素自己的对齐,只控制它的行内内容的对齐。center为居中对齐,right为右对齐,justify为两端对齐文本效果。</p><h4 id="text-decoration"><a href="#text-decoration" class="headerlink" title="text-decoration"></a>text-decoration</h4><p>设置文本的修饰线外观,none就是没有下划线,underline为下划线,overline为上划线,line-through为删除线,默认值为underline。</p><h4 id="line-height"><a href="#line-height" class="headerlink" title="line-height"></a>line-height</h4><p>行高,通常用来设置垂直居中。</p><h4 id="text-shadow"><a href="#text-shadow" class="headerlink" title="text-shadow"></a>text-shadow</h4><p>速写属性依次为:阴影,水平方向偏移量,垂直方向偏移量,模糊度,阴影颜色。</p><h4 id="background-repeat"><a href="#background-repeat" class="headerlink" title="background-repeat"></a>background-repeat</h4><p>表示设置该元素平铺的方式,默认值为repeat。no-repeat,图片不会重复,space,图片会尽可能重复,但不会裁剪,repeat-x或-y,在水平方向或者垂直方向上重复。</p><h4 id="list-style-type"><a href="#list-style-type" class="headerlink" title="list-style-type"></a>list-style-type</h4><p>设置列表元素的marker,比如圆点、符号、或者自定义计数器样式。disc为实心圆点 (默认值),circle为空心圆点,square为实心方块,decimal为十进制阿拉伯数字。</p><h3 id="盒模型"><a href="#盒模型" class="headerlink" title="盒模型"></a>盒模型</h3><p>box:盒子,每一个元素在页面中都会生成一个矩形区域(盒子)。</p><p>盒子类型:</p><ol><li><p>行盒,display 等于 inline 元素</p></li><li><p>块盒,display 等于 block 元素</p></li></ol><div class="note note-success"> <p>行盒在页面中不换行,块盒独占一行。</p><p>display 默认值是 inline。</p><p>浏览器默认样式表设置的块盒:容器元素,h1~h2,p。</p><p>常见的行盒:span,a,img,video,audio。</p> </div><h4 id="盒子的组成部分"><a href="#盒子的组成部分" class="headerlink" title="盒子的组成部分"></a>盒子的组成部分</h4><p>无论是行盒,还是块盒,都由下面几个部分组成,从内到外分别是:</p><ol><li>内容 content<br>width,height,设置的是盒子的内容的宽高。</li><li>填充 padding<br>padding 的简写属性,写四个,代表上,右,下,左。写两个,代表上下,左右,写一个,代表上下左右等宽,三个代表,上,左右,下。<br>padding-top,padding-right,padding-bottom,padding-left。<br>填充区+内容区= <strong>填充盒 padding-box</strong>。</li><li>边框 border<br>没有设置颜色,默认字体颜色<br>有箭头,表示这个属性为速写属性,同上 padding。<br>border:宽度 样式 颜色。</li><li>外边距 margin<br>盒子与盒子之间的距离。</li></ol><h3 id="定位"><a href="#定位" class="headerlink" title="定位"></a>定位</h3><p>CSS 中 position 属性用于指定一个元素在文档中的定位方式。top,right,bottom 和 left 属性则决定了该元素的最终位置。</p><h4 id="常见语法"><a href="#常见语法" class="headerlink" title="常见语法"></a>常见语法</h4><figure class="highlight coq"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs coq">static | <span class="hljs-type">relative</span> | <span class="hljs-type">absolute</span> | <span class="hljs-type">sticky</span> | <span class="hljs-type">fixed</span><br></code></pre></div></td></tr></table></figure><h5 id="相对定位"><a href="#相对定位" class="headerlink" title="相对定位"></a>相对定位</h5><p>相对定位的元素是在文档中的正常位置偏移给定的值,但是不影响其他元素的偏移。</p><h5 id="绝对定位"><a href="#绝对定位" class="headerlink" title="绝对定位"></a>绝对定位</h5><p>相对定位的元素并未脱离文档流,而绝对定位的元素则脱离了文档流。在布置文档流中其它元素时,绝对定位元素不占据空间。绝对定位元素相对于最近的非 static 祖先元素定位。当这样的祖先元素不存在时,则相对于 ICB(inital container block, 初始包含块)。</p><h3 id="浮动"><a href="#浮动" class="headerlink" title="浮动"></a>浮动</h3><p>CSS 中的 float 属性指定一个元素应沿其容器的左侧或右侧放置,允许文本和内联元素环绕它。该元素从网页的正常流动(文档流)中移除,尽管仍然保持部分的流动性。</p><h4 id="常见语法-1"><a href="#常见语法-1" class="headerlink" title="常见语法"></a>常见语法</h4><figure class="highlight coq"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs coq"><span class="hljs-built_in">right</span> | <span class="hljs-type">left</span> | <span class="hljs-type">none</span> | <span class="hljs-type">inline</span>-start | <span class="hljs-type">inline</span>-<span class="hljs-keyword">end</span><br></code></pre></div></td></tr></table></figure><h4 id="清除浮动"><a href="#清除浮动" class="headerlink" title="清除浮动"></a>清除浮动</h4><p>元素浮动之后,周围的元素会重新排列,为了避免这种情况,使用 clear 属性。<br>clear 属性指定元素两侧不能出现浮动元素。</p><h3 id="更新"><a href="#更新" class="headerlink" title="更新"></a>更新</h3><p>关键帧<code>@keyframes</code>规则通过在动画序列中定义关键帧(或 waypoints)的样式来控制 CSS 动画序列中的中间步骤。和转换 transition 相比,关键帧可以控制动画序列的中间步骤。具体<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/@keyframes">请看这里</a>。</p><p>动画<code>animation</code>JavaScript 动画是通过对元素样式的逐渐变化进行编程来完成的。更改由计时器调用。当计时器间隔小时,动画看起来是连续的。具体<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Animation">请看这里</a>。</p><p>变换<code>transform</code>属性允许你旋转,缩放,倾斜或平移给定元素。这是通过修改 CSS 视觉格式化模型的坐标空间来实现的。具体<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/transform">请看这里</a>。</p><p>实现一个圆形转动的动态加载效果。</p><figure class="highlight css"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs css"><<span class="hljs-selector-tag">style</span>><br> <span class="hljs-selector-class">.loader</span>{<br> <span class="hljs-attribute">border</span>: <span class="hljs-number">16px</span> solid <span class="hljs-number">#008c8c</span>;<br> <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;<br> <span class="hljs-attribute">border-top</span>: <span class="hljs-number">16px</span> solid <span class="hljs-number">#ed4b82</span>;<br> <span class="hljs-attribute">width</span>: <span class="hljs-number">90px</span>;<br> <span class="hljs-attribute">height</span>: <span class="hljs-number">90px</span>;<br> <span class="hljs-attribute">animation</span>: spin <span class="hljs-number">2s</span> linear infinite;<br> }<br> <span class="hljs-keyword">@keyframes</span> spin {<br> 0%{<br> <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">rotate</span>(<span class="hljs-number">0deg</span>);<br> }<br> 100%{<br> <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">rotate</span>(<span class="hljs-number">360deg</span>);<br> }<br> }<br></<span class="hljs-selector-tag">style</span>><br></code></pre></div></td></tr></table></figure><figure class="highlight html"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">body</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"loader"</span>></span><span class="hljs-tag"></<span class="hljs-name">div</span>></span><br><span class="hljs-tag"></<span class="hljs-name">body</span>></span><br></code></pre></div></td></tr></table></figure><h2 id="JS"><a href="#JS" class="headerlink" title="JS"></a>JS</h2><h3 id="入门"><a href="#入门" class="headerlink" title="入门"></a>入门</h3><p>JavaScript(缩写:JS)是一门完备的 动态编程语言。当应用于 HTML 文档时,可为网站提供动态交互特性。</p><h4 id="变量"><a href="#变量" class="headerlink" title="变量"></a>变量</h4><p>变量是存储值的容器。要声明一个变量,先输入关键字 let 或 var,然后输入合适的名称。</p><figure class="highlight js"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs js"><span class="hljs-keyword">let</span> myVariable;<br></code></pre></div></td></tr></table></figure><div class="table-container"><table><thead><tr><th>变量</th><th>解释</th><th>示例</th></tr></thead><tbody><tr><td>String</td><td>字符串(一串文本):字符串的值必须用引号(单双均可,必须成对)扩起来。</td><td>let myVariable = ‘赵吴涯’;</td></tr><tr><td>Number</td><td>数字:无需引号。</td><td>let myVariable = 10;</td></tr><tr><td>Boolean</td><td>布尔值(真 / 假): true/false 是 JS 里的特殊关键字,无需引号。</td><td>let myVariable = true;</td></tr><tr><td>Array</td><td>数组:用于在单一引用中存储多个值的结构。</td><td>let myVariable = [1, ‘赵吴涯’, ‘徐付瑞’, 10];</td></tr><tr><td>Object</td><td>对象:JavaScript 里一切皆对象,一切皆可储存在变量里。这一点要牢记于心。</td><td>let myVariable = document.querySelector(‘h1’);以及上面所有示例都是对象。</td></tr></tbody></table></div><h4 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h4><p>和 C,Java 一样,JS 也可以自定义函数。</p><figure class="highlight js"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">multiply</span>(<span class="hljs-params">num1, num2</span>) </span>{<br> <span class="hljs-keyword">let</span> result = num1 * num2;<br> <span class="hljs-keyword">return</span> result;<br>}<br></code></pre></div></td></tr></table></figure><h5 id="常用函数"><a href="#常用函数" class="headerlink" title="常用函数"></a>常用函数</h5><p>WindowOrWorkerGlobalScope的<code>setInterval()</code>方法重复调用一个函数或执行一个代码段,在每次调用之间具有固定的时间延迟。<br><figure class="highlight js"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs js"><span class="hljs-keyword">var</span> intervalID = scope.setInterval(func, delay, [arg1, arg2, ...]);<br><span class="hljs-keyword">var</span> intervalID = scope.setInterval(code, delay);<br></code></pre></div></td></tr></table></figure></p><ul><li>func:执行时触发的函数。</li><li>code:可选,传递一个字符串来代替一个函数对象。</li><li>delay:延迟的秒数,单位时毫秒。</li><li>arg:当定时器过期的时候,将被传递给func指定函数的附加参数。</li></ul><div class="note note-warning"> <p>setInterval()方法会不停地调用函数,直到clearInterval()被调用或窗口被关闭。由 setInterval()返回的 ID 值可用作 clearInterval()方法的参数。</p><p>如果你只想执行一次可以使用setTimeout()方法。</p> </div><h4 id="Web-API接口"><a href="#Web-API接口" class="headerlink" title="Web API接口"></a>Web API接口</h4><p>window.location只读属性,返回一个 Location 对象,其中包含有关文档当前位置的信息。</p><p>简单例子,显示当前网站的URL。<br><figure class="highlight js"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs js">alert(location); <br></code></pre></div></td></tr></table></figure><br>一般用法,导航到一个新的界面。<br><figure class="highlight js"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs js"><span class="hljs-built_in">window</span>.location = <span class="hljs-string">"http://www.example.com"</span><br></code></pre></div></td></tr></table></figure><br>强制从服务器重新加载当前页面<br><figure class="highlight js"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs js"><span class="hljs-built_in">window</span>.location.reload(<span class="hljs-literal">true</span>);<br></code></pre></div></td></tr></table></figure><br>更多用法<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Window/location">请看这里</a>。</p><p>Node.parentElement返回当前节点的父元素节点,如果该元素没有父节点,或者父节点不是一个 DOM 元素,则返回 null。</p><p>Node.insertBefore()方法在参考节点之前插入一个拥有指定父节点的子节点。如果给定的子节点是对文档中现有节点的引用,insertBefore()会将其从当前位置移动到新位置,用来冒泡排序中的交换最好不过了。</p><h4 id="事件"><a href="#事件" class="headerlink" title="事件"></a>事件</h4><p>事件能为网页添加真实的交互能力。它可以捕捉浏览器操作并运行一些代码做为响应。最简单的事件是点击事件,鼠标的点击操作会触发该事件。</p><figure class="highlight js"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs js"><span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"html"</span>).onclick = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<br> alert(<span class="hljs-string">"Hello World"</span>);<br>};<br></code></pre></div></td></tr></table></figure><p>将事件与元素绑定有许多方法。在这里选用了html元素,把一个匿名函数(就是没有命名的函数,这里的匿名函数包含单击鼠标时要运行的代码)赋值给了 html 的 onclick 属性。</p><div class="table-container"><table><thead><tr><th>事件</th><th>解释</th></tr></thead><tbody><tr><td>onkeyup</td><td>当用户释放键盘按钮时执行</td></tr><tr><td>onkeydown</td><td>当用户按下所有键盘按钮时执行</td></tr><tr><td>onkeypress</td><td>当键盘按键被按下并释放一个键时执行</td></tr><tr><td>onchange</td><td>当用户改变 input 输入框内容时执行</td></tr></tbody></table></div><div class="note note-warning"> <p>onkeyup,onkeypress 仅对文本按键有效,<br>当按下不属于文本显示的按键(比如 Tab 键,Del 键,Shift 键)时,onkeydown 执行,而 onkeypress,onkeyup 不执行,Enter 键除外。</p> </div><h3 id="JSON"><a href="#JSON" class="headerlink" title="JSON"></a>JSON</h3><h4 id="JSON语法"><a href="#JSON语法" class="headerlink" title="JSON语法"></a>JSON语法</h4><p>JSON语法是JS对象表示语法的子集,有如下特点:</p><ul><li>数据在键值对中(键名即属性名必须加双引号)</li><li>数据由逗号分隔</li><li>花括号保存对象</li><li>方括号保存数组</li></ul><p>JSON可通过JavaScript进行解析,JSON值可以是:数字、字符串、逻辑值、数组(在中括号中)、对象(在大括号中)、null。</p><div class="note note-warning"> <p>注意JSON不能存储Date对象,如果需要则用字符串表示。</p> </div><p><code>JSON.stringify()</code>方法将一个 JavaScript 对象或值转换为 JSON 字符串,如果指定了一个 replacer 函数,则可以选择性地替换值,或者指定的 replacer 是数组,则可选择性地仅包含数组指定的属性。</p><h4 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h4><h3 id="正则表达式"><a href="#正则表达式" class="headerlink" title="正则表达式"></a>正则表达式</h3><h4 id="开始"><a href="#开始" class="headerlink" title="开始"></a>开始</h4><p>使用一个正则表达式字面量,其由包含在斜杠之间的模式组成,如下所示:</p><figure class="highlight js"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs js"><span class="hljs-keyword">var</span> re = <span class="hljs-regexp">/ab+c/</span>;<br></code></pre></div></td></tr></table></figure><p>脚本加载后,正则表达式字面量就会被编译。当正则表达式保持不变时,使用此方法可获得更好的性能。</p><p>或者调用 RegExp 对象的构造函数,如下所示:</p><figure class="highlight js"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs js"><span class="hljs-keyword">var</span> re = <span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">"ab+c"</span>);<br></code></pre></div></td></tr></table></figure><p>在脚本运行过程中,用构造函数创建的正则表达式会被编译。如果正则表达式将会改变,或者它将会从用户输入等来源中动态地产生,就需要使用构造函数来创建正则表达式。</p><h4 id="转义字符"><a href="#转义字符" class="headerlink" title="转义字符"></a>转义字符</h4><figure class="highlight js"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs js">\d:数字 <span class="hljs-number">0</span>-<span class="hljs-number">9</span><br>\D:非数字<br>\s:空格<br>\S:非空格<br>\w: 字符( 字母a-z 数字<span class="hljs-number">0</span>-<span class="hljs-number">9</span> 下划线_ )<br>\W: 非字符<br>\b: 端点 ( 起始、结束、空格 )<br>\B: 非端点<br></code></pre></div></td></tr></table></figure><h4 id="修饰符"><a href="#修饰符" class="headerlink" title="修饰符"></a>修饰符</h4><figure class="highlight js"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs js">i:执行对大小写不敏感的匹配。<br>g:执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。<br>m:执行多行匹配。<br></code></pre></div></td></tr></table></figure><h2 id="Ajax"><a href="#Ajax" class="headerlink" title="Ajax"></a>Ajax</h2><p>Asynchronous JavaScript + XML(异步 JavaScript 和 XML), 其本身不是一种新技术,而是一个在 2005 年被 Jesse James Garrett 提出的新术语,用来描述一种使用现有技术集合的新方法,包括:HTML 或 XHTML,CSS,JavaScript,DOM,XML,XSLT,,以及最重要的 XMLHttpRequest。当使用结合了这些技术的 AJAX 模型以后,网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面。这使得程序能够更快地回应用户的操作。</p><h2 id="LINQ"><a href="#LINQ" class="headerlink" title="LINQ"></a>LINQ</h2><p>LINQ 是 .NET Framework 3.5 的新特性,其全称是 Language Integrated Query,即语言集成查询,是指将查询功能和语言结合起来。从而为我们提供一种统一的方式,让我们能在 C#或 VB.NET 语言中直接查询和操作各种数据。</p><h3 id="开始-1"><a href="#开始-1" class="headerlink" title="开始"></a>开始</h3><p>LINQ 中最基本的数据单元是 sequences 和 elements。一个 sequence 是实现了 IEnumerable\<T>的对象,而一个 element 是 sequence 中的每一个元素。如下,names 就是一个 sequence,“Tom”,“Dick”和“Harry”则是 elements。</p><figure class="highlight c#"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c#"><span class="hljs-built_in">string</span>[] names = { <span class="hljs-string">"Tom"</span>, <span class="hljs-string">"David"</span>, <span class="hljs-string">"Jack"</span> };<br></code></pre></div></td></tr></table></figure><h3 id="查询"><a href="#查询" class="headerlink" title="查询"></a>查询</h3><p>查询表达式是一种使用查询语法表示的表达式,它用于查询和转换来自任意支持 LINQ 的数据源中的数据。查询表达式使用许多常见的 C#语言构造,易读简洁,容易掌握。它由一组类似于 SQL 或 XQuery 的声明性语法编写的子句组成。每一个子句可以包含一个或多个 C#表达式。这些 C#表达式本身也可能是查询表达式或包含查询表达式。</p><div class="note note-warning"> <p>查询表达式必须以 from 子句开头,以 select 或 group 子句结束。第一个 from 子句和最后一个 select 子句或 group 子句之间,可以包含一个活多个 where 子句、let 子句、join 子句、orderby 子句和 group 子句,甚至还可以是 from 子句。</p> </div><ul><li>from 子句:指定查询操作的数据源和范围变量。</li><li>select 子句:指定查询结果的类型和表现形式。</li><li>where 子句:指定筛选元素的逻辑条件。</li><li>let 子句:引入用来临时保存查询表达式中的字表达式结果的范围变量。</li><li>orderby 子句:对查询结果进行排序操作,包括升序和降序。</li><li>group 子句:对查询结果进行分组。</li><li>into 子句:提供一个临时标识符。join 子句、group 子句或 select 子句可以通过该标识符引用查询操作中的中间结果。</li><li>join 子句:连接多个用于查询操作的数据源。</li></ul><div class="note note-warning"> <p>注意:orderby 子句默认排序方式为升序。</p> </div><figure class="highlight c#"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c#"><span class="hljs-keyword">var</span> gb = <span class="hljs-keyword">from</span> u <span class="hljs-keyword">in</span> db.Guestbooks<br> <span class="hljs-keyword">where</span> u.IsPass == <span class="hljs-literal">true</span> && u.UserId == UserId<br> <span class="hljs-keyword">orderby</span> u.CreatedOn <span class="hljs-keyword">descending</span><br> <span class="hljs-keyword">select</span> u;<br></code></pre></div></td></tr></table></figure><p>常用的语句:u.Name.Contains(“zhao”)名字包含 zhao 的。</p><h2 id="EF"><a href="#EF" class="headerlink" title="EF"></a>EF</h2><p>Entity Framework 是一个被微软支持的为 .NET 程序服务的开源的 ORM 框架。它使开发者能够用特定域的类对象来工作,而不是把精力集中在底层的数据表和数据存储的列上面。有了 Entity Framework ,开发者在处理数据时能够工作在一个更高的抽象层面上,并且能够用比传统程序更少的代码来创建和维护面向数据的程序。</p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Web</tag>
<tag>HTML</tag>
<tag>CSS</tag>
<tag>JS</tag>
<tag>.Net</tag>
</tags>
</entry>
<entry>
<title>基于ASP.NET MVC5的留言板系统</title>
<link href="/2020/11/24/aspnetmvc5/"/>
<url>/2020/11/24/aspnetmvc5/</url>
<content type="html"><![CDATA[<h1 id="MVC"><a href="#MVC" class="headerlink" title="MVC"></a>MVC</h1><p>模型有 GuestBook 留言类,和 User 类。</p><p>视图有控制器相应的视图,就不一一列出了。</p><p>控制器有 Home 主页控制器,Account 账户控制器,User 用户操作控制器,Admin 管理员操作控制器。</p><h1 id="Code-First"><a href="#Code-First" class="headerlink" title="Code First"></a>Code First</h1><ul><li>DB First 模式:以数据库为基础,并根据数据库自动生成实体数据模型</li><li>Code First 模式:先写好实体模型类代码,然后生成数据库和表</li></ul><p>主要步骤</p><ol><li>创建数据模型类</li><li>创建数据库上下文类</li><li>添加 EntityFramework 依赖</li><li>添加数据库连接字符串</li><li>数据库迁移</li></ol><h1 id="项目实例"><a href="#项目实例" class="headerlink" title="项目实例"></a>项目实例</h1><h2 id="GuestBook-类"><a href="#GuestBook-类" class="headerlink" title="GuestBook 类"></a>GuestBook 类</h2><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs C++"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Guestbook</span></span><br><span class="hljs-class">{</span><br> <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> GuestbookId { get; <span class="hljs-built_in">set</span>; }<br><br> [Required(ErrorMessage = <span class="hljs-string">"留言标题不能为空"</span>)]<br> [MaxLength(<span class="hljs-number">20</span>, ErrorMessage = <span class="hljs-string">"留言标题不超过20个字符"</span>)]<br> <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Title { get; <span class="hljs-built_in">set</span>; } <span class="hljs-comment">//留言标题</span><br><br><br><br> [Required(ErrorMessage = <span class="hljs-string">"留言内容不能为空"</span>)]<br> [MinLength(<span class="hljs-number">10</span>, ErrorMessage = <span class="hljs-string">"留言内容不少于10个字符"</span>)]<br> <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Content { get; <span class="hljs-built_in">set</span>; } <span class="hljs-comment">//留言内容</span><br><br><br><br> [Required(ErrorMessage = <span class="hljs-string">"留言人的邮箱不能为空"</span>)]<br> [EmailAddress(ErrorMessage = <span class="hljs-string">"email格式不对"</span>)]<br> <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> AuthorEmail { get; <span class="hljs-built_in">set</span>; } <span class="hljs-comment">//留言邮箱</span><br><br><br><br> [DatabaseGenerated(DatabaseGeneratedOption.Computed)]<br> <span class="hljs-keyword">public</span> DateTime CreatedOn { get; <span class="hljs-built_in">set</span>; } <span class="hljs-comment">//创建日期时间</span><br><br> <span class="hljs-keyword">public</span> Boolean IsPass { get; <span class="hljs-built_in">set</span>; }<span class="hljs-comment">//审核功能</span><br><br> <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> UserId { get; <span class="hljs-built_in">set</span>; }<br> <span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> User User { get; <span class="hljs-built_in">set</span>; }<br>}<br><br></code></pre></div></td></tr></table></figure><p>这里面做了一些限制,相当于数据库建表时候的那些限制,之后在页面上如果格式不对,就弹出这个错误信息。</p><h2 id="User-类"><a href="#User-类" class="headerlink" title="User 类"></a>User 类</h2><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs C++"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span></span><br><span class="hljs-class">{</span><br> <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> UserId { get; <span class="hljs-built_in">set</span>; }<br> [Display(Name = <span class="hljs-string">"留言人邮箱"</span>, Order = <span class="hljs-number">15000</span>)]<br> <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Email { get; <span class="hljs-built_in">set</span>; }<br> <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Name { get; <span class="hljs-built_in">set</span>; }<br> [DataType(DataType.Password)]<br> <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Password { get; <span class="hljs-built_in">set</span>; }<br> <span class="hljs-keyword">public</span> SystemRole SRole { get; <span class="hljs-built_in">set</span>; }<br> <span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> ICollection<Guestbook> Guestbooks { get; <span class="hljs-built_in">set</span>; }<br>}<br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">SystemRole</span> {</span> 普通用户, 管理员 }<br></code></pre></div></td></tr></table></figure><p>这里面我加了角色<code>Role</code>,方便以后判断登陆跳转。</p><h2 id="GBSDBContext-类"><a href="#GBSDBContext-类" class="headerlink" title="GBSDBContext 类"></a>GBSDBContext 类</h2><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GBSDBContext</span> :</span> DbContext<br>{<br> <span class="hljs-keyword">public</span> DbSet<Guestbook> Guestbooks { get; <span class="hljs-built_in">set</span>; }<br><br> <span class="hljs-keyword">public</span> DbSet<User> Users { get; <span class="hljs-built_in">set</span>; }<br><br>}<br></code></pre></div></td></tr></table></figure><p>数据库上下文类,数据库上下文类是继承 DbContext 类的,此时应该安装 EntityFramework 包,打开 NuGet 包管理器,输入</p><figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">Install</span>-Package EntityFramework -Version <span class="hljs-number">6</span>.<span class="hljs-number">4</span>.<span class="hljs-number">4</span><br></code></pre></div></td></tr></table></figure><p>安装成功后,GBSDBContext.cs 就可顺利编译。</p><h2 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h2><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">connectionStrings</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">add</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"GBSDBContext"</span></span><br><span class="hljs-tag"> <span class="hljs-attr">connectionString</span>=<span class="hljs-string">"Data Source=(LocalDb)\MSSQLLocalDB;</span></span><br><span class="hljs-tag"><span class="hljs-string"> AttachDbFilename=|DataDirectory|\GBSDB.mdf;</span></span><br><span class="hljs-tag"><span class="hljs-string"> Initial Catalog=GBS;</span></span><br><span class="hljs-tag"><span class="hljs-string"> Integrated Security=True"</span></span><br><span class="hljs-tag"> <span class="hljs-attr">providerName</span>=<span class="hljs-string">"System.Data.SqlClient"</span> /></span><br><span class="hljs-tag"></<span class="hljs-name">connectionStrings</span>></span><br><br></code></pre></div></td></tr></table></figure><p>把这些放在Web.config中<code><configuration></configuration></code>标签里</p><ul><li>GBSDBContext 是数据库上下文。</li><li>GBSDB.mdf 是数据库文件名(存放在 app_data 中),需要手动添加现有项到解决方案资源管- 理器中,才看得见。</li><li>GBS 是数据库名(服务器中)。</li><li>Integrated Security=True”代表用当前 Windows 帐户凭据进行身份验证。(不用输入数据库服务器用户名和密码即可登录)</li></ul><h2 id="数据库迁移"><a href="#数据库迁移" class="headerlink" title="数据库迁移"></a>数据库迁移</h2><p>三行搞定,出金不要慌,出红就重来吧 🤨</p><figure class="highlight pgsql"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs pgsql"><span class="hljs-keyword">Enable</span>-Migrations<br><span class="hljs-keyword">Add</span>-Migration InitialCreate<br><span class="hljs-keyword">Update</span>-<span class="hljs-keyword">Database</span><br></code></pre></div></td></tr></table></figure><p>然后数据库就生成了,要搞清楚这两个表之间的关系,UserId 是 GuestBook 的外键,要保证实体完整性。开始需要手动添加管理员信息,毕竟管理员也不能注册对吧!</p><h2 id="登录登出"><a href="#登录登出" class="headerlink" title="登录登出"></a>登录登出</h2><p>头是 Controller,下面是 Action。(下面的结构也一样)</p><p>Account</p><ul><li>Login</li><li>Logout</li></ul><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++">[HttpPost]<br><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">Login</span><span class="hljs-params">(User user)</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">if</span> (ModelState.IsValid)<br> {<br> var dbUser = db.Users.Where(a => a.Name == user.Name && a.Password == user.Password).FirstOrDefault();<br> <span class="hljs-keyword">if</span> (dbUser != null)<br> {<br> FormsAuthenticationTicket authTicket = <span class="hljs-keyword">new</span> FormsAuthenticationTicket(<br> <span class="hljs-number">1</span>, dbUser.UserId.ToString(), DateTime.Now, DateTime.Now.AddMinutes(<span class="hljs-number">20</span>), <span class="hljs-literal">false</span>, dbUser.SRole.ToString());<br><br> <span class="hljs-built_in">string</span> encryptedTicket = FormsAuthentication.Encrypt(authTicket);<br><br> HttpCookie authCookie = <span class="hljs-keyword">new</span> HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);<br><br> authCookie.HttpOnly = <span class="hljs-literal">true</span>;<br><br> System.Web.HttpContext.Current.Response.Cookies.Add(authCookie);<br><br> <span class="hljs-keyword">if</span> (dbUser.SRole.ToString() == <span class="hljs-string">"管理员"</span>)<br> {<br> <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"Index"</span>, <span class="hljs-string">"Admin"</span>);<br> }<br> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (dbUser.SRole.ToString() == <span class="hljs-string">"普通用户"</span>)<br> {<br> Session[<span class="hljs-string">"UserId"</span>] = dbUser.UserId;<br> <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"AllWords"</span>, <span class="hljs-string">"User"</span>);<br> }<br> }<br> }<br> }<br> ModelState.AddModelError(<span class="hljs-string">""</span>, <span class="hljs-string">"用户名或密码错误"</span>);<br> <span class="hljs-keyword">return</span> View(user);<br>}<br></code></pre></div></td></tr></table></figure><p>这里要获取 UserId,不然之后无法通过 UserId 选择当前用户自己的留言,也无法发布留言,因为外键为空,不符合实体完整性。具体方法就是通过 Seesion 将 UserId 保存起来,后面有用嘿嘿嘿。还有获取 Cookies 和将其加密。</p><p>如果要身份验证,加了<code>[Authorize]</code>要在解决方案资源管理器的最后一项文件的Web.config 里加表单验证,放在<code><system.web></system.web></code>标签里面不然会报错 401。loginUrl 是非法访问时跳转的登录界面。</p><figure class="highlight xml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">authentication</span> <span class="hljs-attr">mode</span>=<span class="hljs-string">"Forms"</span>></span><span class="hljs-comment"><!--有4种--></span><br> <span class="hljs-tag"><<span class="hljs-name">forms</span> <span class="hljs-attr">loginUrl</span>=<span class="hljs-string">"~/Account/Login"</span> <span class="hljs-attr">defaultUrl</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">timeout</span>=<span class="hljs-string">"2880"</span> /></span><br><span class="hljs-tag"></<span class="hljs-name">authentication</span>></span><br></code></pre></div></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs C++"><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">Logout</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> FormsAuthentication.SignOut();<br> <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"Login"</span>, <span class="hljs-string">"Account"</span>);<br>}<br></code></pre></div></td></tr></table></figure><p>还要避免普通用户正常登录后,通过浏览器地址栏进去后台管理,Admin 控制器也要加身份验证<code>[Authorize (Roles ="管理员")]</code>,加上后在 Global.asax 文件中加这一个方法,具体原理还在研究中。</p><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Application_AuthorizeRequest</span><span class="hljs-params">(object sender, System.EventArgs e)</span></span><br><span class="hljs-function"></span>{<br> HttpApplication App = (HttpApplication)sender;<br> HttpContext Ctx = App.Context; <span class="hljs-comment">//获取本次Http请求相关的HttpContext对象</span><br> <span class="hljs-keyword">if</span> (Ctx.Request.IsAuthenticated == <span class="hljs-literal">true</span>) <span class="hljs-comment">//验证过的用户才进行role的处理</span><br> {<br> FormsIdentity Id = (FormsIdentity)Ctx.User.Identity;<br> FormsAuthenticationTicket Ticket = Id.Ticket; <span class="hljs-comment">//取得身份验证票</span><br> <span class="hljs-built_in">string</span>[] Roles = Ticket.UserData.Split(<span class="hljs-string">','</span>); <span class="hljs-comment">//将身份验证票中的role数据转成字符串数组</span><br> Ctx.User = <span class="hljs-keyword">new</span> GenericPrincipal(Id, Roles); <span class="hljs-comment">//将原有的Identity加上角色信息新建一个GenericPrincipal表示当前用户,这样当前用户就拥有了role信息</span><br> }<br>}<br></code></pre></div></td></tr></table></figure><p>用户必须点击登出按钮登出,会清除 Cookies,之后不能通过浏览器地址访问用户个人主页。</p><h2 id="用户注册"><a href="#用户注册" class="headerlink" title="用户注册"></a>用户注册</h2><p>Account</p><ul><li>RegisterIndex</li><li>Register</li></ul><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++">[AllowAnonymous]<br><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">RegisterIndex</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">return</span> View();<br>}<br>[AllowAnonymous]<br><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">Register</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">return</span> View();<br>}<br>[AllowAnonymous]<br>[HttpPost]<br><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">Register</span><span class="hljs-params">(User user)</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">if</span> (ModelState.IsValid)<br> {<br> db.Users.Add(user);<br> db.SaveChanges();<br> <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"Login"</span>, <span class="hljs-string">"Account"</span>);<br> }<br> <span class="hljs-keyword">return</span> View();<br>}<br></code></pre></div></td></tr></table></figure><p>通过表单提交 post 请求,插入一行记录,完成后跳到登录界面</p><h2 id="删除留言"><a href="#删除留言" class="headerlink" title="删除留言"></a>删除留言</h2><h3 id="用户删除自己留言"><a href="#用户删除自己留言" class="headerlink" title="用户删除自己留言"></a>用户删除自己留言</h3><p>User</p><ul><li>MyWords</li><li>Delete</li><li>DeleteConfired</li></ul><p>先通过 UserId 选择出只有自己留言的页面</p><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">MyWords</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">int</span> UserId = (<span class="hljs-keyword">int</span>)Session[<span class="hljs-string">"UserId"</span>];<br> var gb = from u in db.Guestbooks<br> where u.IsPass == <span class="hljs-literal">true</span> && u.UserId == UserId<br> orderby u.CreatedOn descending<br> select u;<br><br> <span class="hljs-keyword">return</span> View(<span class="hljs-string">"MyWords"</span>, gb.ToList());<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">Delete</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span></span><br><span class="hljs-function"></span>{<br> var gb = db.Guestbooks.Find(id);<br> <span class="hljs-keyword">return</span> View(gb);<br>}<br><br>[HttpPost, ActionName(<span class="hljs-string">"Delete"</span>)]<br><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">DeleteConfired</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span></span><br><span class="hljs-function"></span>{<br> var gb = db.Guestbooks.Find(id);<br> db.Guestbooks.Remove(gb);<br> db.SaveChanges();<br> <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"MyWords"</span>, <span class="hljs-string">"User"</span>);<br>}<br></code></pre></div></td></tr></table></figure><p>选择删除,确认删除。</p><h3 id="管理员删除留言"><a href="#管理员删除留言" class="headerlink" title="管理员删除留言"></a>管理员删除留言</h3><p>Admin</p><ul><li>DeleteIndex</li><li>Delete</li><li>DeleteConfired</li></ul><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">DeleteIndex</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> var gb = from u in db.Guestbooks<br> where u.IsPass == <span class="hljs-literal">true</span><br> orderby u.CreatedOn descending<br> select u;<br> <span class="hljs-keyword">return</span> View(gb.ToList());<br>}<br><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">Delete</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span></span><br><span class="hljs-function"></span>{<br> var gb = db.Guestbooks.Find(id);<br> <span class="hljs-keyword">return</span> View(gb);<br>}<br><br>[HttpPost, ActionName(<span class="hljs-string">"Delete"</span>)]<br><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">DeleteConfired</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span></span><br><span class="hljs-function"></span>{<br> var gb = db.Guestbooks.Find(id);<br> db.Guestbooks.Remove(gb);<br> db.SaveChanges();<br> <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"DeleteIndex"</span>,<span class="hljs-string">"Admin"</span>);<br><br>}<br></code></pre></div></td></tr></table></figure><p>原理和上面一样</p><h2 id="增加留言"><a href="#增加留言" class="headerlink" title="增加留言"></a>增加留言</h2><p>User</p><ul><li>Create</li></ul><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">Create</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">return</span> View();<br>}<br><br>[HttpPost]<br><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">Create</span><span class="hljs-params">(Guestbook gb)</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">if</span> (ModelState.IsValid)<br> {<br> <span class="hljs-comment">//gb.CreatedOn = System.DateTime.Now;</span><br> gb.UserId = (<span class="hljs-keyword">int</span>)Session[<span class="hljs-string">"UserId"</span>];<br> gb.IsPass = <span class="hljs-literal">false</span>;<br> db.Guestbooks.Add(gb);<br> db.SaveChanges();<br> <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"AllWords"</span>);<br> }<br> <span class="hljs-keyword">return</span> View();<br>}<br></code></pre></div></td></tr></table></figure><p>原理同用户注册,注意要把刚刚登录时获取到的 UserId 传进去,外键不能为空,否则会报错。<br><figure class="highlight sql"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs sql">SqlException: The <span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">statement</span> conflicted <span class="hljs-keyword">with</span> the <span class="hljs-keyword">FOREIGN</span> <span class="hljs-keyword">KEY</span> <br></code></pre></div></td></tr></table></figure><br>另外,用户发布的留言需要管理员审核通过才可以展示到主页上,IsPass 设置默认值为 false。</p><h2 id="审核留言"><a href="#审核留言" class="headerlink" title="审核留言"></a>审核留言</h2><p>Admin</p><ul><li>CheckIndex</li><li>CheckMessage</li><li>CheckMessage1</li></ul><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">CheckIndex</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> var gb = from u in db.Guestbooks<br> where u.IsPass == <span class="hljs-literal">false</span><br> orderby u.CreatedOn descending<br> select u;<br><br> <span class="hljs-keyword">return</span> View(<span class="hljs-string">"CheckIndex"</span>, gb.ToList());<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">CheckMessage</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span></span><br><span class="hljs-function"></span>{<br> var gb = db.Guestbooks.Find(id);<br> <span class="hljs-keyword">return</span> View(gb);<br>}<br>[HttpPost, ActionName(<span class="hljs-string">"CheckMessage"</span>)]<br><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">CheckMessage1</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span><span class="hljs-comment">//通过审核方法</span></span><br><span class="hljs-function"></span>{<br> var gb = db.Guestbooks.Find(id);<br> gb.IsPass = <span class="hljs-literal">true</span>;<br> db.SaveChanges();<br> <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"CheckIndex"</span>, <span class="hljs-keyword">new</span> { target = <span class="hljs-string">"fc"</span> });<br>}<br></code></pre></div></td></tr></table></figure><p>管理员点击审核通过后,执行方法,将 IsPass 设置为 True,主页就可以正常显示该留言了。</p><h2 id="用户管理"><a href="#用户管理" class="headerlink" title="用户管理"></a>用户管理</h2><p>Admin</p><ul><li>UserManger</li><li>DeleteUser</li></ul><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">UserManage</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> var user = from u in db.Users<br> select u;<br> <span class="hljs-keyword">return</span> View(<span class="hljs-string">"UserManage"</span>, user.ToList());<br>}<br><br><br><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">DeleteUser</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span></span><br><span class="hljs-function"></span>{<br> User user = db.Users.Find(id);<br> <span class="hljs-keyword">if</span> (user != null)<br> {<br> db.Users.Remove(user);<br> db.SaveChanges();<br> }<br> <span class="hljs-keyword">return</span> RedirectToAction(<span class="hljs-string">"UserManage"</span>);<br>}<br></code></pre></div></td></tr></table></figure><p>选择所有用户,遍历每一行,显示在页面上,删除同删除留言,通过主键删除。</p><h2 id="留言统计"><a href="#留言统计" class="headerlink" title="留言统计"></a>留言统计</h2><p>Admin</p><ul><li>CommentSummary</li></ul><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-keyword">public</span> ActionResult <span class="hljs-title">CommentSummary</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> var gb = from u in db.Guestbooks<br> where u.IsPass == <span class="hljs-literal">true</span><br> orderby u.CreatedOn descending<br> select u;<br> <span class="hljs-keyword">int</span> count = gb.Count();<br><br> var gb2 = from u in db.Guestbooks<br> where u.IsPass == <span class="hljs-literal">false</span><br> orderby u.CreatedOn descending<br> select u;<br> <span class="hljs-keyword">int</span> count2 = gb2.Count();<br><br> ViewBag.count = count;<br> ViewBag.count2 = count2;<br> <span class="hljs-keyword">return</span> View();<br><br>}<br></code></pre></div></td></tr></table></figure><p>通过数据库筛选,分别得出审核通过和待审核的留言,前端显示。</p><h1 id="项目总结"><a href="#项目总结" class="headerlink" title="项目总结"></a>项目总结</h1><p>项目地址:<a href="https://github.com/chris2000520/GuestBookSystem">留言板系统</a></p><p>理解 ASP .NET MVC 开发,软件工程模式,尝试用 Git 进行分布式管理。</p><p>学海无涯苦作舟。加油 😶</p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>ASP.NET</tag>
<tag>C#</tag>
<tag>MVC</tag>
</tags>
</entry>
<entry>
<title>基于Java的校园招聘系统</title>
<link href="/2020/09/21/swingjdbcmysql/"/>
<url>/2020/09/21/swingjdbcmysql/</url>
<content type="html"><![CDATA[<h1 id="确定设计模式"><a href="#确定设计模式" class="headerlink" title="确定设计模式"></a>确定设计模式</h1><p>在学习之前,都没有听说过的MVC。</p><h2 id="MVC模式"><a href="#MVC模式" class="headerlink" title="MVC模式"></a>MVC模式</h2><p>MVC模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。</p><p>Model(模型):模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。</p><p>View(视图):视图代表模型包含的数据的可视化。</p><p>Controller(控制器):控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。</p><p>所以我们根据这个模式先创建了一个Java工程和四个包,分别是com.java.Dao,com.java.Model,com.java.Util,com.java.View。</p><h2 id="DAO模式"><a href="#DAO模式" class="headerlink" title="DAO模式"></a>DAO模式</h2><p>DAO(DataAccessobjects 数据存取对象)是指位于业务逻辑和持久化数据之间实现对持久化数据的访问。通俗来讲,就是将数据库操作都封装起来。因为当时是跟着做的,不知道为啥要写这个包,现在来弄明白来。</p><p>DAO接口:把对数据库的所有操作定义成抽象方法,可以提供多种实现。</p><p>DAO实现类:针对不同数据库给出DAO接口定义方法的具体实现。<br>实体类:用于存放与传输对象数据。</p><p>数据库连接和关闭工具类:避免了数据库连接和关闭代码的重复使用,方便修改。</p><h1 id="连接数据库"><a href="#连接数据库" class="headerlink" title="连接数据库"></a>连接数据库</h1><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.java1234.util;<br><br><span class="hljs-keyword">import</span> java.sql.Connection;<br><span class="hljs-keyword">import</span> java.sql.DriverManager;<br><br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DbUtil</span> </span>{<br><span class="hljs-keyword">private</span> String driver=<span class="hljs-string">"com.mysql.cj.jdbc.Driver"</span>;<span class="hljs-comment">//驱动名称</span><br> <span class="hljs-keyword">private</span> String url=<span class="hljs-string">"jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT"</span>;<br> <span class="hljs-keyword">private</span> String user=<span class="hljs-string">"root"</span>;<span class="hljs-comment">//数据库用户</span><br> <span class="hljs-keyword">private</span> String psd=<span class="hljs-string">"mysql1970s"</span>;<span class="hljs-comment">//数据库密码</span><br> <br> <br> <span class="hljs-function"><span class="hljs-keyword">public</span> Connection <span class="hljs-title">getCon</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception</span>{<br> Class.forName(driver);<br> Connection con=DriverManager.getConnection(url,user,psd);<br> <span class="hljs-keyword">return</span> con;<br> }<br> <br> <br> <span class="hljs-comment">/*</span><br><span class="hljs-comment"> 关闭数据库</span><br><span class="hljs-comment"> */</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">closeCon</span><span class="hljs-params">(Connection con)</span><span class="hljs-keyword">throws</span> Exception </span>{<br> <span class="hljs-keyword">if</span>(con!=<span class="hljs-keyword">null</span>) {<br> con.close();<br> }<br> }<br> <span class="hljs-comment">//Alt + / 是自动提示</span><br> <span class="hljs-comment">//main syso</span><br> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{<br> DbUtil dbUtil=<span class="hljs-keyword">new</span> DbUtil();<br> <span class="hljs-keyword">try</span> {<br> dbUtil.getCon();<br> System.out.println(<span class="hljs-string">"数据库连接成功!"</span>);<br> }<span class="hljs-keyword">catch</span> (Exception e) {<br> e.printStackTrace();<br> System.out.println(<span class="hljs-string">"数据库连接失败!"</span>);<br> }<br><br>}<br><br>}<br><br></code></pre></div></td></tr></table></figure><p>首先我们需要将mysql-connector-java-8.0.19.jar包添加到Bulid Path里面,然后加载驱动<code>"com.mysql.cj.jdbc.Driver"</code>。那些URL都是有固定格式的,可以上网查一下,URL那里把demo换成自己的数据库名就可以了。用完数据库后要断开连接,释放资源,直接<code>con.close</code>就可以。我们在捕获异常里写一个输出,来显示异常。</p><h1 id="创建登陆窗口"><a href="#创建登陆窗口" class="headerlink" title="创建登陆窗口"></a>创建登陆窗口</h1><p>我们用Eclipse里的插件<a href="https://blog.csdn.net/xueba8/article/details/78561351">WindowBuilder</a>来实现图形化编程,可以说很方便了,在设计界面直接拖拽,勾选,修改,都会在源码界面直接生成代码,但是要自己写各个块的功能。<br><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">loginActionPerfromed</span><span class="hljs-params">(ActionEvent evt)</span> </span>{<br>String username=<span class="hljs-keyword">this</span>.textField.getText();<br>String password=<span class="hljs-keyword">new</span> String(<span class="hljs-keyword">this</span>.passwordField.getPassword());<br><span class="hljs-comment">/*</span><br><span class="hljs-comment"> 判空事件</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">if</span>(StringUtil.isEmpty(username)) {<br>JOptionPane.showMessageDialog(<span class="hljs-keyword">null</span>,<span class="hljs-string">"用户名不能为空!"</span>);<br>}<br><span class="hljs-keyword">if</span>(StringUtil.isEmpty(password)) {<br>JOptionPane.showMessageDialog(<span class="hljs-keyword">null</span>, <span class="hljs-string">"密码不能为空!"</span>);<br>}<br><span class="hljs-comment">/*</span><br><span class="hljs-comment"> 登陆验证</span><br><span class="hljs-comment"> */</span><br>User user=<span class="hljs-keyword">new</span> User(username,password);<br>Connection con=<span class="hljs-keyword">null</span>;<br><span class="hljs-keyword">try</span> {<br>con=dbUtil.getCon();<br>User currentUser=userdao.login(con, user);<br><span class="hljs-keyword">if</span>(currentUser!=<span class="hljs-keyword">null</span>) {<br>JOptionPane.showMessageDialog(<span class="hljs-keyword">null</span>, <span class="hljs-string">"登陆成功!"</span>);<br><br>dispose();<span class="hljs-comment">//销毁窗口</span><br><br><span class="hljs-keyword">new</span> MainFrame().setVisible(<span class="hljs-keyword">true</span>);<span class="hljs-comment">//诱导新窗口</span><br><br>}<span class="hljs-keyword">else</span> {<br>JOptionPane.showMessageDialog(<span class="hljs-keyword">null</span>, <span class="hljs-string">"用户名或密码错误!"</span>);<br>}<br><br>}<span class="hljs-keyword">catch</span>(Exception e) {<br>e.printStackTrace();<br>}<span class="hljs-keyword">finally</span> {<br><span class="hljs-keyword">try</span> {<br>dbUtil.closeCon(con);<br>} <span class="hljs-keyword">catch</span> (Exception e) {<br><span class="hljs-comment">// TODO Auto-generated catch block</span><br>e.printStackTrace();<br>}<br>}<br><br><br>}<br></code></pre></div></td></tr></table></figure><br><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">login</span><span class="hljs-params">(Connection con ,User user)</span><span class="hljs-keyword">throws</span> Exception</span>{<br>User resultUser=<span class="hljs-keyword">null</span>;<br>String sql=<span class="hljs-string">"select * from userlog where uname=? and upsd=?"</span>;<br>PreparedStatement pstmt=con.prepareStatement(sql);<br>pstmt.setString(<span class="hljs-number">1</span>, user.getUsername());<br>pstmt.setString(<span class="hljs-number">2</span>, user.getPassword());<br>ResultSet rs=pstmt.executeQuery();<br><span class="hljs-keyword">if</span>(rs.next()) {<br>resultUser=<span class="hljs-keyword">new</span> User();<br>resultUser.setId(rs.getInt(<span class="hljs-string">"id"</span>));<br>resultUser.setUsername(rs.getString(<span class="hljs-string">"uname"</span>));<br>resultUser.setPassword(rs.getString(<span class="hljs-string">"upsd"</span>));<br><br>}<br><span class="hljs-keyword">return</span> resultUser;<br>}<br></code></pre></div></td></tr></table></figure><br>登陆的逻辑就很简单直接取出两个文本框里的内容去登陆表里一个一个去比较,这里的login就是在UserDao里实现的抽象方法,登陆成功后,要跳转到新的页面,就在登陆按钮的事件里新建一个Jframe窗口,再把登陆的Jframe窗口销毁,就能做出跳转的样子了。对了,说一下PreparedStatement这个类,在数据库的操作过程中,PreparedStatement 对象是一个很不起眼但是记为重要的接口对象,它继承于Statement,并与之在两方面有所不同:</p><p>1)PreparedStatement 实例包含已编译的 SQL 语句。这就是使语句“准备好”。包含于 PreparedStatement 对象中的 SQL 语句可具有一个或多个 IN 参数。IN参数的值在 SQL 语句创建时未被指定。相反的,该语句为每个 IN 参数保留一个问号(“?”)作为占位符。每个问号的值必须在该语句执行之前,通过适当的setXXX 方法来提供。</p><p>2)由于 PreparedStatement 对象已预编译过,所以其执行速度要快于 Statement 对象。因此,多次执行的 SQL 语句经常创建为 PreparedStatement 对象,以提高效率。</p><p>作为 Statement 的子类,PreparedStatement 继承了 Statement 的所有功能。同时,三种方法 execute、 executeQuery 和 executeUpdate 已被更改以使之不再需要参数。这些方法的 Statement 形式(接受 SQL 语句参数的形式)不应该用于 PreparedStatement 对象。</p><h1 id="主页面的功能"><a href="#主页面的功能" class="headerlink" title="主页面的功能"></a>主页面的功能</h1><p> 这里我们用到了JMenu,菜单有二级,三级等等,我的系统实现很简单,主页面就只有退出,添加,修改密码,查询,删除这几个功能。</p><h1 id="添加职位信息"><a href="#添加职位信息" class="headerlink" title="添加职位信息"></a>添加职位信息</h1> <figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">workAddActionPerformed</span><span class="hljs-params">(ActionEvent evt)</span> </span>{<br>String wname=<span class="hljs-keyword">this</span>.textField.getText();<br>String waddress=<span class="hljs-keyword">this</span>.textField_1.getText();<br>String wpost=<span class="hljs-keyword">this</span>.textField_2.getText();<br><span class="hljs-keyword">if</span>(StringUtil.isEmpty(wname)||StringUtil.isEmpty(waddress)||StringUtil.isEmpty(wpost)) {<br>JOptionPane.showMessageDialog(<span class="hljs-keyword">null</span>, <span class="hljs-string">"这三个选项为必填选项!"</span>);<br>}<span class="hljs-keyword">else</span> {<br> WorkType workType=<span class="hljs-keyword">new</span> WorkType(wname, waddress, wpost);<br> Connection con=<span class="hljs-keyword">null</span>;<br> <span class="hljs-keyword">try</span> {<br> con=dbUtil.getCon();<br> <span class="hljs-keyword">int</span> n=workDao.add(con, workType);<br> <span class="hljs-keyword">if</span>(n==<span class="hljs-number">1</span>) {<br> JOptionPane.showMessageDialog(<span class="hljs-keyword">null</span>, <span class="hljs-string">"成功添加一条记录!"</span>);<br> <span class="hljs-keyword">this</span>.resetValue();<br> }<span class="hljs-keyword">else</span> {<br> JOptionPane.showMessageDialog(<span class="hljs-keyword">null</span>, <span class="hljs-string">"添加记录失败!"</span>);<br> }<br> <br> }<span class="hljs-keyword">catch</span>(Exception e) {<br> e.printStackTrace();<br> }<span class="hljs-keyword">finally</span> {<br> <span class="hljs-keyword">try</span> {<br>dbUtil.closeCon(con);<br>} <span class="hljs-keyword">catch</span> (Exception e) {<br><span class="hljs-comment">// TODO Auto-generated catch block</span><br>e.printStackTrace();<br>}<br>}<br> }<br>}<br><span class="hljs-comment">// TODO Auto-generated method stub</span><br><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">resetValue</span><span class="hljs-params">()</span> </span>{<br><span class="hljs-keyword">this</span>.textField.setText(<span class="hljs-keyword">null</span>);<br><span class="hljs-keyword">this</span>.textField_1.setText(<span class="hljs-keyword">null</span>);<br><span class="hljs-keyword">this</span>.textField_2.setText(<span class="hljs-keyword">null</span>);<br>}<br><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">resetValueActionPerformed</span><span class="hljs-params">(ActionEvent evt)</span> </span>{<br> <span class="hljs-keyword">this</span>.resetValue();<br>}<br></code></pre></div></td></tr></table></figure> <figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">add</span><span class="hljs-params">(Connection con,WorkType work)</span><span class="hljs-keyword">throws</span> Exception</span>{<br>String sql=<span class="hljs-string">"insert into work values(?,?,?)"</span>;<br><span class="hljs-comment">//依次是名称,地址,岗位</span><br>PreparedStatement pstmt=con.prepareStatement(sql);<br>pstmt.setString(<span class="hljs-number">1</span>, work.getWname());<br>pstmt.setString(<span class="hljs-number">2</span>, work.getWaddress());<br>pstmt.setString(<span class="hljs-number">3</span>, work.getWpost());<br><span class="hljs-keyword">return</span> pstmt.executeUpdate();<br>}<br></code></pre></div></td></tr></table></figure><p>这里还是用到了DAO的设计模式,将添加操作定义为一种抽像方法,几乎就体会不到数据库的存在了。</p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Java</tag>
<tag>SQL</tag>
<tag>JDBC</tag>
</tags>
</entry>
<entry>
<title>算法总结</title>
<link href="/2020/06/28/mytest/"/>
<url>/2020/06/28/mytest/</url>
<content type="html"><![CDATA[<p>这学期的考试我就没出现过写不完的情况,然而事情就的的确确发生在我头上了。算法考试题基本上都是策略分析题,总共加起来得有两千多字了。<br><a id="more"></a></p><h1 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h1><p>算法是由若干条指令组成的序列,且满足有输入、输出、可行性、有穷性和确定性五个特性。</p><p>评价算法的主要标准是算法实现的时间,算法实现的存储空间和代码要易于理解。</p><p>贪心法,分治法,和动态规划法的区别和联系:<br>分治法与动态规划都是将问题分解成若干个较小规模的子问题。而分治法是将原问题分解为多个子问题,通过计算出子问题的结果构造出最优解,分治法分解后的子问题被看成是相互独立的。动态规划通过迭代法自底向上求解,动态规划将分解后的子问题理解为相互有联系。贪心算法是依赖于当前已经做出的选择,采用自顶向下的解决方法。具体分析请看这里:<a href="https://zhuanlan.zhihu.com/p/33048876">贪心法,分治法,和动态规划法</a>。</p><h1 id="算法分析"><a href="#算法分析" class="headerlink" title="算法分析"></a>算法分析</h1><h2 id="开灯问题"><a href="#开灯问题" class="headerlink" title="开灯问题"></a>开灯问题</h2><p>有n盏灯,编号为1~n,每个灯有个开关,按一下打开,再按一下关闭,再按一下打开。第1个人把所有灯打开,第2个人按下编号为2的倍数的灯的开关,第3个人按下编号为3的倍数的灯的开关,依此类推,一共有k个人,问最后有哪些灯开着?输入n和k,输出开着的灯的编号。k<=n<=1000。</p><p>将灯的状态存入一维数组中,设灯亮的状态为1,第一层循环为从第1个人到第k个人(i代表第几个人),第二层循环为在所有的n盏灯中(j代表第几盏灯),当第i个人按i的倍数的开关时,即灯的编号能整除i,此时灯的状态取反。代码如下:<br><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs C++"><span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">1</span>;i<=k;i++)<br><span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> j=<span class="hljs-number">1</span>;j<=n;j++)<br><span class="hljs-keyword">if</span>(j%i==<span class="hljs-number">0</span>)<br>a[j]=!a[j];<br></code></pre></div></td></tr></table></figure><br>可以优化第二层循环,不用判断,直接修改数组值。<br><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs C++"><span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">2</span>;i<=k;i++)<br><span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> j=i;j<=n;j+=i)<br>a[j]=!a[j];<br></code></pre></div></td></tr></table></figure><br>最后遍历输出值为1的数组下标即可。更多讨论请看这里<a href="https://www.nowcoder.com/questionTerminal/406a54ff2b354bdcb1b1077605620465">开灯问题</a>。</p><h2 id="博弈问题"><a href="#博弈问题" class="headerlink" title="博弈问题"></a>博弈问题</h2><p>给定N(N>20) 张牌,两个人轮流取牌,每人每次最少取 1 张牌,最多取 5 张牌。我们判定取完最后一张牌的人输。请你给出两人的最佳博弈方法。</p><p>考试之前以为不知道有多难呢,结果下来一看解析,哦豁,懂了。</p><p>思路:<br>首先N=1+4=5</p><p>(54-1)/5=10余3</p><p>故先拿牌者取3张即可稳保胜利。</p><p>操作如下:</p><p>先手拿三张后,执行如下原则:</p><p>玩家拿1张,先手拿4张;</p><p>玩家拿2张,先手拿3张;</p><p>玩家拿3张,先手拿2张;</p><p>玩家拿4张,先手拿1张;</p><p>就是保持每轮双方一共拿走5张牌,这样先手最后一次取牌后扑克牌就只剩一张,玩家必输。</p><p>要保证每轮拿牌总数在自己控制之内,所以每轮拿5张牌,对方拿N张,则自己拿5-N张,十轮可以拿50张牌,所以问题相当于,一共54-50=4张牌,自己先拿,要给对方省一张牌,所以第一次自己拿3张,以后每次都拿5-N张,其中N为对方拿牌数,1 <= n <= 4。<br>代码参考<a href="https://blog.csdn.net/u011262780/article/details/52698975?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase">此博客</a>。</p><h2 id="4色图问题"><a href="#4色图问题" class="headerlink" title="4色图问题"></a>4色图问题</h2><p>4色地图问题的优化求解算法可由( )设计实现</p><h2 id="N皇后问题"><a href="#N皇后问题" class="headerlink" title="N皇后问题"></a>N皇后问题</h2><h2 id="12银币问题"><a href="#12银币问题" class="headerlink" title="12银币问题"></a>12银币问题</h2><h2 id="给余猜数问题"><a href="#给余猜数问题" class="headerlink" title="给余猜数问题"></a>给余猜数问题</h2><p>有一堆苹果,3 个 3 个地数,最后余 2 个;5 个 5 个地数,最后余 3 个;7 个 7 个地数,最后余 4 个。<br>问这堆苹果最少有多少个。</p><h2 id="约瑟夫环问题"><a href="#约瑟夫环问题" class="headerlink" title="约瑟夫环问题"></a>约瑟夫环问题</h2><h2 id="残缺棋盘问题"><a href="#残缺棋盘问题" class="headerlink" title="残缺棋盘问题"></a>残缺棋盘问题</h2><h2 id="算法优劣问题"><a href="#算法优劣问题" class="headerlink" title="算法优劣问题"></a>算法优劣问题</h2><h1 id="算法设计"><a href="#算法设计" class="headerlink" title="算法设计"></a>算法设计</h1><h2 id="分治法求最值"><a href="#分治法求最值" class="headerlink" title="分治法求最值"></a>分治法求最值</h2><h2 id="走格子问题"><a href="#走格子问题" class="headerlink" title="走格子问题"></a>走格子问题</h2><h1 id="考试小结"><a href="#考试小结" class="headerlink" title="考试小结"></a>考试小结</h1><p>我做算法题竟然做出了当年语文考试的样子,最后时刻快交卷了,我还有好多策略原理题没写(别问为什么不写代码,问就是不会),就开始狂草起来,那速度,没得说,那字,估计也没得看,想的啥就写啥,跟语文考试写作文写不完的时候一模(mu)一样,就离谱。哎呀,我裂开了呀。最后还是没写完!</p><p>其实还是知识点掌握的不够牢固。</p>]]></content>
<categories>
<category>算法</category>
</categories>
<tags>
<tag>算法</tag>
</tags>
</entry>
<entry>
<title>个人博客图片存储问题</title>
<link href="/2020/06/25/solvepic/"/>
<url>/2020/06/25/solvepic/</url>
<content type="html"><![CDATA[<h1 id="个人博客图片存储问题"><a href="#个人博客图片存储问题" class="headerlink" title="个人博客图片存储问题"></a>个人博客图片存储问题</h1><p>之前搭建博客的时候,只顾美化主题,一些普通的逻辑结构没有完成,就去整那些花里胡哨的主页,实在有点本末倒置,美化的一个大组成成分就是图片,而图片一般比代码和文章要大多了,就导致每次加载网页时都时非常慢的。而我们写思路的的时候,又不得不去使用一些图片,我所知道的有两种方式。</p><h2 id="本地上传"><a href="#本地上传" class="headerlink" title="本地上传"></a>本地上传</h2><p>当我们只需要使用少量图片时,可以本地上传,在文章中的markdown语法中,我们可以使用<br><figure class="highlight arcade"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs arcade">![缩略图](<span class="hljs-regexp">/images/</span>pic.png)<br></code></pre></div></td></tr></table></figure><br>这样的语法,来插入图片。[]里的文字就是当图片加载出问题时,显示的文字,后面的链接是主题配置文件里的source/images/文件名.png。</p><h2 id="使用图床"><a href="#使用图床" class="headerlink" title="使用图床"></a>使用图床</h2><p>知乎上有个大佬写的各种各样的图床的一篇文章,<a href="https://zhuanlan.zhihu.com/p/35270383">盘点国内免费好用的图床</a>。可以借鉴一下,然后呢,我一个一个试了好多,有的需要钱,有的只有几个月,要不就是很复杂,我呢,只想简简单单在描述算法或解决问题的方法时偶尔添加一些图片来加强理解,思来想去我就使用了这个,<a href="https://imgchr.com">路过图床</a>。</p><h2 id="更新"><a href="#更新" class="headerlink" title="更新"></a>更新</h2><p>由于担心图床跑路,图片加载也不是很快,我看别人的博客加载很快(<a href="http://sloving.gitee.io/">SlovinG的博客</a>),完全看不到加载项,原理是直接部署到Gitee码云代码仓库里,国内的Gitee码云速度是真的快,然而我迁移后,发现不能绑定个人域名,详细请看这篇<a href="https://yyqx.online/posts/%E7%BD%91%E7%AB%99%E8%BF%81%E7%A7%BB%E8%87%B3gitee/">博客</a>。</p><p>然而我还是舍不得我用了好久的域名,然后我就用Coding了,图片都上传到Coding上,毕竟是国内的网站,加载图片还是可以的。</p><p>小测试:</p><p>由于评论区是Valine,语法支持Markdown,所以只需要输入一下代码就可以获得一只猫,快来试试!<br><figure class="highlight markdown"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs Markdown">[<span class="hljs-string">![Nssgde.th.png</span>](<span class="hljs-link">https://s1.ax1x.com/2020/06/26/Nssgde.th.png</span>)](<span class="hljs-link">https://imgchr.com/i/Nssgde</span>)<br></code></pre></div></td></tr></table></figure></p>]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>Hexo</tag>
<tag>博客</tag>
</tags>
</entry>
<entry>
<title>数塔问题-简单的动态规划</title>
<link href="/2020/06/25/numbertower/"/>
<url>/2020/06/25/numbertower/</url>
<content type="html"><![CDATA[<p>如下图是一个数塔,从顶部出发在每一个节点可以选择向左或者向右走,一直走到底层,要求找出一条路径,使得路径上的数字之和最大。</p><figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">9</span><br><span class="hljs-attribute">12</span><span class="hljs-number">15</span><br><span class="hljs-attribute">10</span><span class="hljs-number">6</span><span class="hljs-number">8</span><br><span class="hljs-attribute">2</span><span class="hljs-number">18</span><span class="hljs-number">9</span><span class="hljs-number">5</span><br><span class="hljs-attribute">19</span><span class="hljs-number">7</span><span class="hljs-number">10</span><span class="hljs-number">4</span><span class="hljs-number">16</span><br></code></pre></div></td></tr></table></figure><h2 id="算法分析"><a href="#算法分析" class="headerlink" title="算法分析"></a>算法分析</h2><p>我们可以这样想,从最后一层倒过来看,到倒数第二层,可以选择一个较大的路径,例如,假设我们一步走到了2这里,下一步应该怎么走?只有19或7这两种选择,既然我们想让总的路径之和最大,那我们肯定每一步都要选大的。我们人脑编译器是很简单的,每次只需要倒着推,到最后一个数据就是我们的最大路径。</p><h2 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h2><p>假设这个数塔的层数是N,我们可以将这个数塔放在一个NxN的data数组里,也许只需要下三角矩阵i>=j。另外,我们还就可以将每一步最大的路径的数据保存在dp数组里。用两重循环来遍历数组,我们要倒着推,所有要i—,二维的j是从左往右,j++。</p><div class="table-container"><table><thead><tr><th style="text-align:center">data</th><th style="text-align:center"></th><th style="text-align:center"></th><th style="text-align:center"></th><th style="text-align:center"></th></tr></thead><tbody><tr><td style="text-align:center">9</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">12</td><td style="text-align:center">15</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">10</td><td style="text-align:center">6</td><td style="text-align:center">8</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">2</td><td style="text-align:center">18</td><td style="text-align:center">9</td><td style="text-align:center">5</td></tr><tr><td style="text-align:center">19</td><td style="text-align:center">7</td><td style="text-align:center">10</td><td style="text-align:center">4</td><td style="text-align:center">16</td><td></td></tr></tbody></table></div><div class="table-container"><table><thead><tr><th style="text-align:center">dp</th><th style="text-align:center"></th><th style="text-align:center"></th><th style="text-align:center"></th><th style="text-align:center"></th></tr></thead><tbody><tr><td style="text-align:center">59</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">50</td><td style="text-align:center">49</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">38</td><td style="text-align:center">34</td><td style="text-align:center">29</td><td style="text-align:center"></td></tr><tr><td style="text-align:center">21</td><td style="text-align:center">28</td><td style="text-align:center">19</td><td style="text-align:center">21</td></tr><tr><td style="text-align:center">19</td><td style="text-align:center">7</td><td style="text-align:center">10</td><td style="text-align:center">4</td><td style="text-align:center">16</td><td></td></tr></tbody></table></div><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs C++"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> N 101 </span><br><span class="hljs-comment">//最后一层的我们需要多加一层空白数据,不然会数组下标错误</span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> <span class="hljs-built_in">std</span>;<br><br><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">max</span><span class="hljs-params">(<span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b)</span></span>{<br> <span class="hljs-keyword">return</span> a>b?a:b;<br>}<br><br><span class="hljs-keyword">int</span> data[N][N];<span class="hljs-comment">//全局变量已初始化0</span><br><span class="hljs-keyword">int</span> dp[N][N];<br><br><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> <span class="hljs-keyword">int</span> n;<br> <span class="hljs-built_in">cout</span><<<span class="hljs-string">"请输入数塔的层数:(不超过100)"</span><<<span class="hljs-built_in">endl</span>;<br> <span class="hljs-built_in">cin</span>>>n;<br> <span class="hljs-built_in">cout</span><<<span class="hljs-string">"请输入塔的数据"</span><<<span class="hljs-built_in">endl</span>;<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < n ; ++i) {<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j <= i ; ++j) {<br> <span class="hljs-built_in">cin</span>>>a[i][j];<br> }<br> }<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = n<span class="hljs-number">-1</span>; i >=<span class="hljs-number">0</span> ; --i) {<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j <= i ; ++j) {<br> dp[i][j]=max(dp[i+<span class="hljs-number">1</span>][j],dp[i+<span class="hljs-number">1</span>][j+<span class="hljs-number">1</span>])+data[i][j];<br> <span class="hljs-comment">//最后一层dp数据和data一样max(0,0)</span><br> }<br> }<br> <span class="hljs-built_in">cout</span><<<span class="hljs-string">"最大的路径和是:"</span><<dp[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>];<br> <br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br><br><br></code></pre></div></td></tr></table></figure><p>输出<br><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs C++">最大路径和是:<span class="hljs-number">59</span><br></code></pre></div></td></tr></table></figure></p><h2 id="优化"><a href="#优化" class="headerlink" title="优化"></a>优化</h2><h3 id="输出路径"><a href="#输出路径" class="headerlink" title="输出路径"></a>输出路径</h3><p>题目可能会要求我们输出我们是怎么走的,在两个表都填写完整后,第一步不用说,肯定的是data[0][0],之后,我们用dp[i][j](还是从dp[0][0]开始)数据减去data数组的这一个位置的数据,我们可以倒着想,我们是用下面两个数据的较大的一个加上data[i][j]数据得到这个dp[i][j]。相减的结果就是较大的那个dp[i+1][j]或者是dp[i+1][j+1]。我们就可以确定是选择了这个路径data[i+1][j]或data[i+1][j+1]。因为这一次我们是正着走的,一条路走到底,每次都选dp大的那一个data数据,只需要循环N-1次就可以了(第一步已确定)。<br><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs C++"><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">print</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">int</span> node_value;<br> <span class="hljs-comment">// 首先输出塔顶元素</span><br> <span class="hljs-built_in">cout</span> << <span class="hljs-string">"最大路径:"</span> << data[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>];<br> <span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < n<span class="hljs-number">-1</span>; ++i)<br> {<br> node_value = dp[i][j] - data[i][j];<br> <span class="hljs-keyword">if</span> (node_value == dp[i][j + <span class="hljs-number">1</span>]){<br> j++;<span class="hljs-comment">//记录节点的列,输出要用</span><br> <span class="hljs-built_in">cout</span> << <span class="hljs-string">"->"</span> << data[i+<span class="hljs-number">1</span>][j];<br> }<span class="hljs-comment">//右边的大,应该往右走</span><br> <span class="hljs-keyword">else</span>{<br> <span class="hljs-built_in">cout</span> << <span class="hljs-string">"->"</span> << data[i+<span class="hljs-number">1</span>][j];<br> }<span class="hljs-comment">//左边的大,应该往左走 </span><br> }<br> <span class="hljs-built_in">cout</span> << <span class="hljs-built_in">endl</span>;<br>}<br></code></pre></div></td></tr></table></figure><br>输出<br><figure class="highlight c++"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs C++">最大路径:<span class="hljs-number">9</span>-><span class="hljs-number">12</span>-><span class="hljs-number">10</span>-><span class="hljs-number">2</span>-><span class="hljs-number">19</span><br></code></pre></div></td></tr></table></figure></p><h3 id="空间优化"><a href="#空间优化" class="headerlink" title="空间优化"></a>空间优化</h3><p>其实dp数组里的数据不需要每一层都储存起来,用过之后就没用了,我们可以用覆盖的方法将二维数组优化为一维数组,也就是滚动数组。</p><p>参考博客:<br><a href="https://blog.csdn.net/theonegis/article/details/45801201">动态规划:数塔问题——卡尔曼和玻尔兹曼谁曼</a></p>]]></content>
<categories>
<category>算法</category>
</categories>
<tags>
<tag>算法</tag>
<tag>动态规划</tag>
</tags>
</entry>
<entry>
<title>回溯法经典例题</title>
<link href="/2020/06/16/magicnumber/"/>
<url>/2020/06/16/magicnumber/</url>
<content type="html"><![CDATA[<p>编写一个由1-9组成的9位数,并且数字不重复,前N项能被N整除。</p><figure class="highlight cpp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string"><iostream></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> <span class="hljs-built_in">std</span>;<br><br><span class="hljs-keyword">int</span> number = <span class="hljs-number">0</span>;<br><span class="hljs-keyword">int</span> visited[<span class="hljs-number">10</span>] = {<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>};<br><br><span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">makenumber</span><span class="hljs-params">(<span class="hljs-keyword">int</span> n)</span> </span>{<br> <span class="hljs-keyword">if</span> (n < <span class="hljs-number">1</span>) {<br> <span class="hljs-built_in">cout</span> << <span class="hljs-string">"ERROR!"</span> << <span class="hljs-built_in">endl</span>;<br> <span class="hljs-keyword">return</span>;<br> }<br> <span class="hljs-keyword">if</span> (n == <span class="hljs-number">10</span>) {<br> <span class="hljs-built_in">cout</span> << number << <span class="hljs-built_in">endl</span>;<br> }<br> <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">1</span>; j <= <span class="hljs-number">9</span>; ++j) {<br> <span class="hljs-keyword">if</span> (!visited[j]) {<br> <span class="hljs-keyword">int</span> temp = number;<br> temp = temp * <span class="hljs-number">10</span> + j;<br> <span class="hljs-keyword">if</span> (temp % n == <span class="hljs-number">0</span>) {<br> number = temp;<br> visited[j] = <span class="hljs-number">1</span>;<br> makenumber(n + <span class="hljs-number">1</span>);<br> number = number / <span class="hljs-number">10</span>;<br> visited[j] = <span class="hljs-number">0</span>;<span class="hljs-comment">//BackTracking</span><br> }<br> }<br> }<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> makenumber(<span class="hljs-number">1</span>);<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br><br></code></pre></div></td></tr></table></figure><p>本题主要是采用了递归回溯法,读者需自行分析。我没有进行数学分析,只是盲目的暴力枚举。</p>]]></content>
<categories>
<category>算法</category>
</categories>