-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
1282 lines (1282 loc) · 424 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
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"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>https://fairyeye.github.io</id>
<title>人生当苦, 良人当归</title>
<subtitle></subtitle>
<icon>https://fairyeye.github.io/images/favicon.ico</icon>
<link href="https://fairyeye.github.io" />
<author>
<name>有李说不清</name>
</author>
<updated>2024-07-09T03:09:01.791Z</updated>
<entry>
<id>https://fairyeye.github.io/2024/07/09/N%20N/</id>
<title>say something</title>
<link rel="alternate" href="https://fairyeye.github.io/2024/07/09/N%20N/"/>
<content type="html"><h2 id="a"><a class="anchor" href="#a">#</a> A</h2>
<p>延迟队列?15 天 并且可以重置<br />
提醒续命 (记录)<br />
通知 =&gt; +1 天 通知 + 短信 =&gt; +2 天 发给紧急联系人()<br />
可以关闭掉<br />
如果恢复,打上标记 或者删掉这条记录 --- 打上标记</p>
<p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">[</span><span class="punctuation">&#123;</span><span class="attr">&quot;type&quot;</span><span class="punctuation">:</span><span class="string">&quot;text&quot;</span><span class="punctuation">,</span><span class="attr">&quot;value&quot;</span><span class="punctuation">:</span><span class="string">&quot;222&quot;</span><span class="punctuation">,</span><span class="attr">&quot;timestamp&quot;</span><span class="punctuation">:</span><span class="string">&quot;2024-10-08 16:22:11.421&quot;</span><span class="punctuation">,</span><span class="attr">&quot;synced&quot;</span><span class="punctuation">:</span><span class="literal"><span class="keyword">true</span></span><span class="punctuation">&#125;</span><span class="punctuation">,</span><span class="punctuation">&#123;</span><span class="attr">&quot;type&quot;</span><span class="punctuation">:</span><span class="string">&quot;text&quot;</span><span class="punctuation">,</span><span class="attr">&quot;value&quot;</span><span class="punctuation">:</span><span class="string">&quot;1111&quot;</span><span class="punctuation">,</span><span class="attr">&quot;timestamp&quot;</span><span class="punctuation">:</span><span class="string">&quot;2024-10-08 16:21:50.566&quot;</span><span class="punctuation">,</span><span class="attr">&quot;synced&quot;</span><span class="punctuation">:</span><span class="literal"><span class="keyword">true</span></span><span class="punctuation">&#125;</span><span class="punctuation">]</span></span><br></pre></td></tr></table></figure></p>
<h2 id="b"><a class="anchor" href="#b">#</a> B</h2>
</content>
<updated>2024-07-09T03:09:01.791Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2024/07/03/Arch%20Linux/</id>
<title>Arch Linux安装</title>
<link rel="alternate" href="https://fairyeye.github.io/2024/07/03/Arch%20Linux/"/>
<content type="html"><p><span class="exturl" data-url="aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTAzODM0NjcvYXJ0aWNsZS9kZXRhaWxzLzEzNTg3NjY4Mg==">很详细的链接</span></p>
<h2 id="制作u盘"><a class="anchor" href="#制作u盘">#</a> 制作 U 盘</h2>
<p>使用 <span class="exturl" data-url="aHR0cHM6Ly9ydWZ1cy5pZS8=">Rufus</span></p>
<p><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3BiYXRhcmQvcnVmdXMvcmVsZWFzZXMvZG93bmxvYWQvdjQuNS9ydWZ1cy00LjUuZXhl">下载链接 v4.5 </span></p>
<h2 id="使用-archinstall-安装"><a class="anchor" href="#使用-archinstall-安装">#</a> 使用 archInstall 安装</h2>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">archinstall</span><br><span class="line"><span class="comment"># 设置一下即可</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 必选:设置硬盘、root密码 网络!! 选第二个</span></span><br><span class="line"><span class="comment"># 可选:时区</span></span><br></pre></td></tr></table></figure></p>
<p><img data-src="https://s3.bmp.ovh/imgs/2024/07/04/977f126f1c2f2a59.png" alt="" /></p>
<h2 id="启用ssh"><a class="anchor" href="#启用ssh">#</a> 启用 SSH</h2>
<p>如果你安装完系统后无法通过 SSH 远程登录,可能是由于 SSH 服务未安装、未启动或防火墙配置问题。以下是一些可能的解决方法:</p>
<h3 id="1-检查并安装-openssh"><a class="anchor" href="#1-检查并安装-openssh">#</a> 1. 检查并安装 OpenSSH</h3>
<p>确保 OpenSSH 已安装:</p>
<p>安装 <code>sshd</code></p>
<p><code>sudo pacman -S openssh</code></p>
<h3 id="2-启动并启用-ssh-服务"><a class="anchor" href="#2-启动并启用-ssh-服务">#</a> 2. 启动并启用 SSH 服务</h3>
<p>启动 SSH 服务:</p>
<p><code>sudo systemctl start sshd</code></p>
<p>启用 SSH 服务,使其在系统启动时自动运行:</p>
<p><code>sudo systemctl enable sshd</code></p>
<h3 id="3-检查防火墙设置"><a class="anchor" href="#3-检查防火墙设置">#</a> 3. 检查防火墙设置</h3>
<p>如果你启用了防火墙,需要确保允许 SSH 端口(默认端口 22)的连接。例如,如果你使用 <code>ufw</code> 作为防火墙,可以使用以下命令:</p>
<p><code>sudo ufw allow ssh</code></p>
<p>如果使用 <code>iptables</code> ,可以使用以下命令:</p>
<p><code>sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT</code></p>
<h3 id="4-检查-ssh-配置文件"><a class="anchor" href="#4-检查-ssh-配置文件">#</a> 4. 检查 SSH 配置文件</h3>
<p>检查 SSH 配置文件 <code>/etc/ssh/sshd_config</code> 是否正确配置。例如,确保以下行没有被注释掉(去掉前面的 <code>#</code> ):</p>
<p><code>Port 22 PermitRootLogin yes # 如果你需要以 root 登录 PasswordAuthentication yes # 如果你使用密码登录</code></p>
<p>编辑完配置文件后,重新启动 SSH 服务以应用更改:</p>
<p><code>sudo systemctl restart sshd</code></p>
<h3 id="5-检查网络连接"><a class="anchor" href="#5-检查网络连接">#</a> 5. 检查网络连接</h3>
<p>确保你的计算机在网络中是可访问的,可以通过以下命令查看 IP 地址:</p>
<p><code>ip addr show</code></p>
<p>确保你使用的是正确的 IP 地址和端口连接。</p>
<h3 id="6-检查-ssh-客户端输出"><a class="anchor" href="#6-检查-ssh-客户端输出">#</a> 6. 检查 SSH 客户端输出</h3>
<p>如果仍然无法连接,使用 SSH 客户端连接时查看详细输出,以获取更多调试信息。例如,在 Linux 或 macOS 上,可以使用以下命令:</p>
<p><code>ssh -v user@hostname</code></p>
<p>这个命令会显示详细的连接过程,有助于找出问题所在。</p>
<h3 id="7-确保-ssh-服务在运行"><a class="anchor" href="#7-确保-ssh-服务在运行">#</a> 7. 确保 SSH 服务在运行</h3>
<p>使用以下命令检查 SSH 服务状态:</p>
<p><code>sudo systemctl status sshd</code></p>
<p>确保显示的状态为 <code>active (running)</code> 。如果不是,请检查日志文件以获取更多信息:</p>
<p><code>sudo journalctl -u sshd</code></p>
<h3 id="8-确保主机名解析正常"><a class="anchor" href="#8-确保主机名解析正常">#</a> 8. 确保主机名解析正常</h3>
<p>确保你连接的主机名可以正确解析。如果你使用主机名连接,尝试改用 IP 地址连接,以排除 DNS 解析问题。</p>
<h3 id="9-确保网络没有阻塞-ssh-端口"><a class="anchor" href="#9-确保网络没有阻塞-ssh-端口">#</a> 9. 确保网络没有阻塞 SSH 端口</h3>
<p>某些网络环境(如企业网络或公共 WiFi)可能会阻止 SSH 端口的流量。尝试在不同的网络环境中进行连接测试。</p>
<h3 id="10-检查用户权限"><a class="anchor" href="#10-检查用户权限">#</a> 10. 检查用户权限</h3>
<p>确保你使用的用户在目标机器上存在,并且具有适当的权限。你可以使用以下命令查看当前用户列表:</p>
<p><code>cat /etc/passwd</code></p>
<p>确保用户存在并且可以登录。</p>
<h2 id="启用并启动显示管理器"><a class="anchor" href="#启用并启动显示管理器">#</a> 启用并启动显示管理器</h2>
<p>假设你选择了 GDM 作为显示管理器:</p>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl <span class="built_in">enable</span> gdm</span><br><span class="line">sudo systemctl start gdm</span><br></pre></td></tr></table></figure></p>
<p>如果选择了 SDDM:</p>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl <span class="built_in">enable</span> sddm</span><br><span class="line">sudo systemctl start sddm</span><br></pre></td></tr></table></figure></p>
<p>安装缺失的软件包:</p>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">sudo pacman -S gnome # 安装 GNOME</span><br><span class="line">sudo pacman -S plasma # 安装 KDE Plasma</span><br><span class="line">sudo pacman -S gdm # 安装 GDM</span><br><span class="line">sudo pacman -S sddm # 安装 SDDM</span><br></pre></td></tr></table></figure></p>
<p>到这里 系统就算安装完成了</p>
<h2 id="安装hyprland-报错中"><a class="anchor" href="#安装hyprland-报错中">#</a> 安装 Hyprland 报错中</h2>
<p>需要创建一个非 root 用户</p>
<p>给 sudo 权限</p>
<p>需要安装编辑器 vim 或者 nano</p>
</content>
<category term="杂项" scheme="https://fairyeye.github.io/categories/%E6%9D%82%E9%A1%B9/" />
<updated>2024-07-03T13:04:21.000Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2024/06/13/%E5%BC%80%E5%8F%91%E6%97%A5%E5%BF%97/</id>
<title>开发日志</title>
<link rel="alternate" href="https://fairyeye.github.io/2024/06/13/%E5%BC%80%E5%8F%91%E6%97%A5%E5%BF%97/"/>
<content type="html"><h2 id="备份部分代码"><a class="anchor" href="#备份部分代码">#</a> 备份部分代码</h2>
<p><code>MainActivity.java</code> 实用源生安卓来处理模糊,但是还是慢</p>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.li.ying; </span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> android.graphics.Bitmap; </span><br><span class="line"><span class="keyword">import</span> android.graphics.BitmapFactory; </span><br><span class="line"><span class="keyword">import</span> android.os.Bundle; </span><br><span class="line"><span class="keyword">import</span> androidx.annotation.NonNull; </span><br><span class="line"><span class="keyword">import</span> androidx.annotation.Nullable; </span><br><span class="line"><span class="keyword">import</span> io.flutter.embedding.android.FlutterActivity; </span><br><span class="line"><span class="keyword">import</span> io.flutter.embedding.engine.FlutterEngine; </span><br><span class="line"><span class="keyword">import</span> io.flutter.plugin.common.MethodCall; </span><br><span class="line"><span class="keyword">import</span> io.flutter.plugin.common.MethodChannel; </span><br><span class="line"><span class="keyword">import</span> android.renderscript.*; </span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> java.io.File; </span><br><span class="line"><span class="keyword">import</span> java.io.FileOutputStream; </span><br><span class="line"><span class="keyword">import</span> java.io.IOException; </span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MainActivity</span> <span class="keyword">extends</span> <span class="title class_">FlutterActivity</span> &#123; </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">CHANNEL</span> <span class="operator">=</span> <span class="string">&quot;image_processing&quot;</span>; </span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span> </span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">configureFlutterEngine</span><span class="params">(<span class="meta">@NonNull</span> FlutterEngine flutterEngine)</span> &#123; </span><br><span class="line"> <span class="built_in">super</span>.configureFlutterEngine(flutterEngine); </span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">MethodChannel</span>(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL) </span><br><span class="line"> .setMethodCallHandler( </span><br><span class="line"> (call, result) -&gt; &#123; </span><br><span class="line"> <span class="keyword">if</span> (call.method.equals(<span class="string">&quot;blurImage&quot;</span>)) &#123; </span><br><span class="line"> <span class="type">String</span> <span class="variable">imagePath</span> <span class="operator">=</span> call.argument(<span class="string">&quot;imagePath&quot;</span>); </span><br><span class="line"> <span class="type">int</span> <span class="variable">radius</span> <span class="operator">=</span> call.argument(<span class="string">&quot;radius&quot;</span>); </span><br><span class="line"> <span class="keyword">try</span> &#123; </span><br><span class="line"> result.success(blurImage(imagePath, radius)); </span><br><span class="line"> &#125; <span class="keyword">catch</span> (IOException e) &#123; </span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(e); </span><br><span class="line"> &#125; </span><br><span class="line"> &#125; <span class="keyword">else</span> &#123; </span><br><span class="line"> result.notImplemented(); </span><br><span class="line"> &#125; </span><br><span class="line"> &#125; </span><br><span class="line"> ); </span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> String <span class="title function_">blurImage</span><span class="params">(String imagePath, <span class="type">int</span> radius)</span> <span class="keyword">throws</span> IOException &#123; </span><br><span class="line"> <span class="type">Bitmap</span> <span class="variable">bitmap</span> <span class="operator">=</span> BitmapFactory.decodeFile(imagePath); </span><br><span class="line"> <span class="type">RenderScript</span> <span class="variable">rs</span> <span class="operator">=</span> RenderScript.create(<span class="built_in">this</span>); </span><br><span class="line"> <span class="type">Allocation</span> <span class="variable">input</span> <span class="operator">=</span> Allocation.createFromBitmap(rs, bitmap); </span><br><span class="line"> <span class="type">Allocation</span> <span class="variable">output</span> <span class="operator">=</span> Allocation.createTyped(rs, input.getType()); </span><br><span class="line"> <span class="type">ScriptIntrinsicBlur</span> <span class="variable">script</span> <span class="operator">=</span> ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); </span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 多次应用高斯模糊 </span></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123; </span><br><span class="line"> script.setRadius(radius); </span><br><span class="line"> script.setInput(input); </span><br><span class="line"> script.forEach(output); </span><br><span class="line"> output.copyTo(bitmap); </span><br><span class="line"> input.copyFrom(bitmap); </span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line"> rs.destroy(); </span><br><span class="line"> </span><br><span class="line"> <span class="type">File</span> <span class="variable">outputDir</span> <span class="operator">=</span> getCacheDir(); </span><br><span class="line"> <span class="type">File</span> <span class="variable">outputFile</span> <span class="operator">=</span> File.createTempFile(<span class="string">&quot;blurred_&quot;</span>, <span class="string">&quot;.png&quot;</span>, outputDir); </span><br><span class="line"> <span class="type">FileOutputStream</span> <span class="variable">out</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(outputFile); </span><br><span class="line"> bitmap.compress(Bitmap.CompressFormat.PNG, <span class="number">100</span>, out); </span><br><span class="line"> out.close(); </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> outputFile.getAbsolutePath(); </span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p><code>main.dart</code> 调用源生安卓</p>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">// static const platform = MethodChannel(&#x27;image_processing&#x27;); </span><br><span class="line">// </span><br><span class="line">// 这种方法 调用了安卓原生代码 速度更快 但是快不过缩小图片模糊 </span><br><span class="line">// 并且radius最大25 模糊效果不尽人意 </span><br><span class="line">// File? _blurredImage; </span><br><span class="line">// </span><br><span class="line">// Future&lt;void&gt; _blurImage(String imagePath) async &#123; </span><br><span class="line">// try &#123; </span><br><span class="line">// final String blurredImagePath = await platform.invokeMethod( </span><br><span class="line">// &#x27;blurImage&#x27;, </span><br><span class="line">// &#123;&#x27;imagePath&#x27;: imagePath, &#x27;radius&#x27;: 25&#125;, </span><br><span class="line">// ); </span><br><span class="line">// setState(() &#123; </span><br><span class="line">// _blurredImage = File(blurredImagePath); </span><br><span class="line">// &#125;); </span><br><span class="line">// &#125; on PlatformException catch (e) &#123; </span><br><span class="line">// print(&quot;Failed to blur image: &#x27;$&#123;e.message&#125;&#x27;.&quot;); </span><br><span class="line">// &#125; </span><br><span class="line">// &#125;</span><br></pre></td></tr></table></figure></p>
</content>
<updated>2024-06-13T08:42:20.913Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2024/06/08/%E8%8B%8F%E5%B7%9E%E4%B8%80%E6%97%A5%E6%B8%B8/</id>
<title>苏州一日游</title>
<link rel="alternate" href="https://fairyeye.github.io/2024/06/08/%E8%8B%8F%E5%B7%9E%E4%B8%80%E6%97%A5%E6%B8%B8/"/>
<content type="html"><h4 id="洞泾-上海松江站-苏州站-720-820-02车"><a class="anchor" href="#洞泾-上海松江站-苏州站-720-820-02车">#</a> 洞泾 - 上海松江站 - 苏州站 (7.20-8.20 02 车)</h4>
<p>21 分钟(5.1 公里)- 8.50 左右</p>
<p><img data-src="https://s3.bmp.ovh/imgs/2024/06/08/32faa5d56b5ec6fc.png" alt="" /></p>
<h4 id="平江路"><a class="anchor" href="#平江路">#</a> 平江路</h4>
<p>吃早点,逛一逛 (1.5h - 9.30 左右)</p>
<p><img data-src="https://s3.bmp.ovh/imgs/2024/06/08/546339c0896af6e9.png" alt="" /></p>
<p>从南 - &gt; 北</p>
<h5 id="苏香记"><a class="anchor" href="#苏香记">#</a> 苏香记</h5>
<h5 id="梅月轩"><a class="anchor" href="#梅月轩">#</a> 梅月轩</h5>
<h5 id="苏州打卡墙"><a class="anchor" href="#苏州打卡墙">#</a> 苏州打卡墙</h5>
<h5 id="桃花源记"><a class="anchor" href="#桃花源记">#</a> 桃花源记</h5>
<h5 id="通利桥"><a class="anchor" href="#通利桥">#</a> 通利桥</h5>
<h5 id="胡厢使桥"><a class="anchor" href="#胡厢使桥">#</a> 胡厢使桥</h5>
<h5 id="猫咖狗咖"><a class="anchor" href="#猫咖狗咖">#</a> 猫咖狗咖</h5>
<h4 id="西园寺"><a class="anchor" href="#西园寺">#</a> 西园寺</h4>
<p>交通:最好打车</p>
<p>素面</p>
<h4 id="虎丘"><a class="anchor" href="#虎丘">#</a> 虎丘</h4>
<h4 id="东方之门"><a class="anchor" href="#东方之门">#</a> 东方之门</h4>
<h4 id="七里山塘景区-夜景"><a class="anchor" href="#七里山塘景区-夜景">#</a> 七里山塘景区 夜景</h4>
<h5 id="蟹皇捞-江南蟹黄面"><a class="anchor" href="#蟹皇捞-江南蟹黄面">#</a> 蟹皇捞・江南蟹黄面</h5>
<h4 id="苏州站-上海站-地铁-2115-2222"><a class="anchor" href="#苏州站-上海站-地铁-2115-2222">#</a> 苏州站 - 上海站 - 地铁 (21.15-22.22)</h4>
</content>
<category term="旅游" scheme="https://fairyeye.github.io/tags/%E6%97%85%E6%B8%B8/" />
<updated>2024-06-08T13:52:56.000Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2024/05/28/HY2.0/</id>
<title>hy2.0</title>
<link rel="alternate" href="https://fairyeye.github.io/2024/05/28/HY2.0/"/>
<content type="html"><h2 id="flask-python-服务器部署"><a class="anchor" href="#flask-python-服务器部署">#</a> Flask Python 服务器部署</h2>
<h3 id="1-准备服务器"><a class="anchor" href="#1-准备服务器">#</a> 1. 准备服务器</h3>
<p>首先,你需要一个可以运行 Python 的服务器。你可以使用以下服务:</p>
<ul>
<li><strong>云服务提供商</strong>:如 AWS、阿里云、DigitalOcean 等。</li>
<li><strong>VPS 提供商</strong>:如 Linode、Vultr 等。</li>
</ul>
<p>确保服务器上安装了 Python 和 pip。</p>
<h3 id="2-连接到服务器"><a class="anchor" href="#2-连接到服务器">#</a> 2. 连接到服务器</h3>
<p>使用 SSH 连接到你的服务器:</p>
<p><code>ssh username@your_server_ip</code></p>
<h3 id="3-安装依赖"><a class="anchor" href="#3-安装依赖">#</a> 3. 安装依赖</h3>
<p>在服务器上,确保你已经安装了 Python 和 pip。你可以使用以下命令检查:</p>
<p><code>python3 --version pip3 --version</code></p>
<p>如果没有安装,可以使用以下命令安装:</p>
<p><code>sudo apt update sudo apt install python3 python3-pip</code></p>
<h3 id="4-上传代码"><a class="anchor" href="#4-上传代码">#</a> 4. 上传代码</h3>
<p>将你的 Flask 应用代码上传到服务器。可以使用 SCP、FTP 或 Git 来上传文件。下面是使用 SCP 的示例:</p>
<p><code>scp -r /path/to/your/project username@your_server_ip:/path/to/target/directory</code></p>
<h3 id="5-创建虚拟环境"><a class="anchor" href="#5-创建虚拟环境">#</a> 5. 创建虚拟环境</h3>
<p>在你的项目目录中创建一个虚拟环境:</p>
<p><code>cd /path/to/target/directory python3 -m venv venv source venv/bin/activate</code></p>
<h3 id="6-安装项目依赖"><a class="anchor" href="#6-安装项目依赖">#</a> 6. 安装项目依赖</h3>
<p>在虚拟环境中安装你的项目依赖:</p>
<p><code>pip install -r requirements.txt</code></p>
<h3 id="7-运行-flask-应用"><a class="anchor" href="#7-运行-flask-应用">#</a> 7. 运行 Flask 应用</h3>
<p>在开发环境中,你可以使用以下命令运行 Flask 应用:</p>
<p><code>python app.py</code></p>
<p>但是在生产环境中,最好使用 WSGI 服务器(如 Gunicorn)来运行 Flask 应用:</p>
<p><code>pip install gunicorn gunicorn -w 4 app:app --bind 0.0.0.0:5000</code></p>
<p>这里 <code>-w 4</code> 表示使用 4 个工作进程,你可以根据需要调整。</p>
<h3 id="8-配置反向代理可选"><a class="anchor" href="#8-配置反向代理可选">#</a> 8. 配置反向代理(可选)</h3>
<p>为了在 80 或 443 端口上提供服务,建议使用 Nginx 作为反向代理:</p>
<h4 id="安装-nginx"><a class="anchor" href="#安装-nginx">#</a> 安装 Nginx</h4>
<p><code>sudo apt install nginx</code></p>
<h4 id="配置-nginx"><a class="anchor" href="#配置-nginx">#</a> 配置 Nginx</h4>
<p>创建一个新的 Nginx 配置文件,例如 <code>/etc/nginx/sites-available/my_flask_app</code> :</p>
<p>nginx</p>
<p>复制代码</p>
<p><code>server &#123; listen 80; server_name your_server_ip; # 或者你的域名 location / &#123; proxy_pass http://127.0.0.1:5000; # Flask 应用的地址 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; &#125; &#125;</code></p>
<p>创建符号链接到 <code>sites-enabled</code> :</p>
<p><code>sudo ln -s /etc/nginx/sites-available/my_flask_app /etc/nginx/sites-enabled</code></p>
<p>测试 Nginx 配置并重启服务:</p>
<p><code>sudo nginx -t sudo systemctl restart nginx</code></p>
<h3 id="9-配置防火墙可选"><a class="anchor" href="#9-配置防火墙可选">#</a> 9. 配置防火墙(可选)</h3>
<p>确保服务器的防火墙允许 HTTP 和 HTTPS 流量:</p>
<p><code>sudo ufw allow 'Nginx Full'</code></p>
<h3 id="10-访问你的应用"><a class="anchor" href="#10-访问你的应用">#</a> 10. 访问你的应用</h3>
<p>现在,你应该能够通过浏览器访问你的 Flask 应用,使用服务器的 IP 地址或域名。</p>
<h3 id="额外建议"><a class="anchor" href="#额外建议">#</a> 额外建议</h3>
<ul>
<li><strong>使用 HTTPS</strong>:在生产环境中,强烈建议使用 HTTPS。可以使用 Let’s Encrypt 来免费申请 SSL 证书。</li>
<li><strong>监控和日志</strong>:考虑使用工具来监控应用的性能和日志,以便及时发现问题。</li>
</ul>
<h2 id="python"><a class="anchor" href="#python">#</a> python</h2>
<p>好的,这里是一个详细的 Python 方案,包括登录页面、选择文件夹、处理 PDF 文件并将数据存储到 SQLite 数据库,以及在线更新功能。</p>
<h3 id="1-环境配置和库安装"><a class="anchor" href="#1-环境配置和库安装">#</a> 1. 环境配置和库安装</h3>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install PyInstaller PyUpdater PyPDF2 pdfminer.six pymupdf tkinter requests</span><br></pre></td></tr></table></figure></p>
<h3 id="2-登录页面和主程序逻辑"><a class="anchor" href="#2-登录页面和主程序逻辑">#</a> 2. 登录页面和主程序逻辑</h3>
<h4 id="21-创建登录界面"><a class="anchor" href="#21-创建登录界面">#</a> 2.1. 创建登录界面</h4>
<p>创建一个文件 <code>login.py</code> 用于实现登录界面:</p>
<p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> tkinter <span class="keyword">as</span> tk</span><br><span class="line"><span class="keyword">from</span> tkinter <span class="keyword">import</span> messagebox</span><br><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">LoginApp</span>:</span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, root</span>):</span><br><span class="line"> self.root = root</span><br><span class="line"> self.root.title(<span class="string">&quot;登录&quot;</span>)</span><br><span class="line"> self.root.geometry(<span class="string">&quot;300x150&quot;</span>)</span><br><span class="line"></span><br><span class="line"> self.username_label = tk.Label(root, text=<span class="string">&quot;用户名&quot;</span>)</span><br><span class="line"> self.username_label.pack()</span><br><span class="line"> self.username_entry = tk.Entry(root)</span><br><span class="line"> self.username_entry.pack()</span><br><span class="line"></span><br><span class="line"> self.password_label = tk.Label(root, text=<span class="string">&quot;密码&quot;</span>)</span><br><span class="line"> self.password_label.pack()</span><br><span class="line"> self.password_entry = tk.Entry(root, show=<span class="string">&quot;*&quot;</span>)</span><br><span class="line"> self.password_entry.pack()</span><br><span class="line"></span><br><span class="line"> self.login_button = tk.Button(root, text=<span class="string">&quot;登录&quot;</span>, command=self.login)</span><br><span class="line"> self.login_button.pack()</span><br><span class="line"></span><br><span class="line"> <span class="keyword">def</span> <span class="title function_">login</span>(<span class="params">self</span>):</span><br><span class="line"> username = self.username_entry.get()</span><br><span class="line"> password = self.password_entry.get()</span><br><span class="line"> <span class="comment"># 假设存在一个登录接口</span></span><br><span class="line"> login_url = <span class="string">&quot;http://example.com/api/login&quot;</span></span><br><span class="line"> response = requests.post(login_url, json=&#123;<span class="string">&quot;username&quot;</span>: username, <span class="string">&quot;password&quot;</span>: password&#125;)</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> response.status_code == <span class="number">200</span> <span class="keyword">and</span> response.json().get(<span class="string">&quot;status&quot;</span>) == <span class="string">&quot;success&quot;</span>:</span><br><span class="line"> messagebox.showinfo(<span class="string">&quot;成功&quot;</span>, <span class="string">&quot;登录成功&quot;</span>)</span><br><span class="line"> self.root.destroy()</span><br><span class="line"> <span class="keyword">import</span> main</span><br><span class="line"> main.run_app()</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> messagebox.showerror(<span class="string">&quot;错误&quot;</span>, <span class="string">&quot;用户名或密码错误&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">run_login_app</span>():</span><br><span class="line"> root = tk.Tk()</span><br><span class="line"> app = LoginApp(root)</span><br><span class="line"> root.mainloop()</span><br></pre></td></tr></table></figure></p>
<h4 id="22-主程序逻辑"><a class="anchor" href="#22-主程序逻辑">#</a> 2.2. 主程序逻辑</h4>
<p>创建 <code>main.py</code> 实现主程序逻辑:</p>
<p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> fitz <span class="comment"># PyMuPDF</span></span><br><span class="line"><span class="keyword">import</span> sqlite3</span><br><span class="line"><span class="keyword">import</span> tkinter <span class="keyword">as</span> tk</span><br><span class="line"><span class="keyword">from</span> tkinter <span class="keyword">import</span> filedialog, messagebox</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">select_folder</span>():</span><br><span class="line"> folder_path = filedialog.askdirectory(title=<span class="string">&quot;选择包含PDF文件的文件夹&quot;</span>)</span><br><span class="line"> <span class="keyword">return</span> folder_path</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">extract_text_from_pdf</span>(<span class="params">pdf_path</span>):</span><br><span class="line"> doc = fitz.<span class="built_in">open</span>(pdf_path)</span><br><span class="line"> text = <span class="string">&quot;&quot;</span></span><br><span class="line"> <span class="keyword">for</span> page <span class="keyword">in</span> doc:</span><br><span class="line"> text += page.get_text()</span><br><span class="line"> <span class="keyword">return</span> text</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">store_data_to_db</span>(<span class="params">data</span>):</span><br><span class="line"> conn = sqlite3.connect(<span class="string">&#x27;extracted_data.db&#x27;</span>)</span><br><span class="line"> cursor = conn.cursor()</span><br><span class="line"> cursor.execute(<span class="string">&#x27;&#x27;&#x27;CREATE TABLE IF NOT EXISTS pdf_data</span></span><br><span class="line"><span class="string"> (id INTEGER PRIMARY KEY, file_name TEXT, content TEXT)&#x27;&#x27;&#x27;</span>)</span><br><span class="line"> cursor.execute(<span class="string">&#x27;INSERT INTO pdf_data (file_name, content) VALUES (?, ?)&#x27;</span>, data)</span><br><span class="line"> conn.commit()</span><br><span class="line"> conn.close()</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">process_pdfs</span>(<span class="params">folder_path</span>):</span><br><span class="line"> <span class="keyword">for</span> file_name <span class="keyword">in</span> os.listdir(folder_path):</span><br><span class="line"> <span class="keyword">if</span> file_name.endswith(<span class="string">&#x27;.pdf&#x27;</span>):</span><br><span class="line"> pdf_path = os.path.join(folder_path, file_name)</span><br><span class="line"> text = extract_text_from_pdf(pdf_path)</span><br><span class="line"> store_data_to_db((file_name, text))</span><br><span class="line"> messagebox.showinfo(<span class="string">&quot;处理完成&quot;</span>, <span class="string">f&quot;文件 <span class="subst">&#123;file_name&#125;</span> 处理完成&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">run_app</span>():</span><br><span class="line"> root = tk.Tk()</span><br><span class="line"> root.withdraw()</span><br><span class="line"> folder_path = select_folder()</span><br><span class="line"> <span class="keyword">if</span> folder_path:</span><br><span class="line"> process_pdfs(folder_path)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> messagebox.showinfo(<span class="string">&quot;提示&quot;</span>, <span class="string">&quot;没有选择文件夹&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line"> run_login_app()</span><br></pre></td></tr></table></figure></p>
<h4 id="23-在线更新功能"><a class="anchor" href="#23-在线更新功能">#</a> 2.3. 在线更新功能</h4>
<p>创建 <code>client_config.py</code> 配置 PyUpdater:</p>
<p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">from</span> pyupdater.client <span class="keyword">import</span> Client</span><br><span class="line"></span><br><span class="line">APP_NAME = <span class="string">&quot;PDFExtractorApp&quot;</span></span><br><span class="line">APP_VERSION = <span class="string">&quot;0.1.0&quot;</span></span><br><span class="line">UPDATE_URLS = [<span class="string">&#x27;http://your-update-server.com/&#x27;</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ClientConfig</span>:</span><br><span class="line"> PUBLIC_KEY = <span class="string">&quot;your-public-key&quot;</span></span><br><span class="line"> APP_NAME = APP_NAME</span><br><span class="line"> COMPANY_NAME = <span class="string">&quot;YourCompany&quot;</span></span><br><span class="line"> UPDATE_URLS = UPDATE_URLS</span><br><span class="line"> MAX_DOWNLOAD_RETRIES = <span class="number">3</span></span><br><span class="line"> USE_PATCHES = <span class="literal">True</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">check_for_updates</span>():</span><br><span class="line"> client = Client(ClientConfig(), refresh=<span class="literal">True</span>)</span><br><span class="line"> app_update = client.update_check(ClientConfig.APP_NAME, ClientConfig.APP_VERSION)</span><br><span class="line"> <span class="keyword">if</span> app_update <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line"> app_update.download()</span><br><span class="line"> <span class="keyword">if</span> app_update.is_downloaded():</span><br><span class="line"> app_update.extract_restart()</span><br></pre></td></tr></table></figure></p>
<p>在 <code>main.py</code> 的 <code>run_app</code> 函数中加入更新检查:</p>
<p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">run_app</span>():</span><br><span class="line"> <span class="keyword">from</span> client_config <span class="keyword">import</span> check_for_updates</span><br><span class="line"> check_for_updates()</span><br><span class="line"></span><br><span class="line"> root = tk.Tk()</span><br><span class="line"> root.withdraw()</span><br><span class="line"> folder_path = select_folder()</span><br><span class="line"> <span class="keyword">if</span> folder_path:</span><br><span class="line"> process_pdfs(folder_path)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> messagebox.showinfo(<span class="string">&quot;提示&quot;</span>, <span class="string">&quot;没有选择文件夹&quot;</span>)</span><br></pre></td></tr></table></figure></p>
<h4 id="24-打包应用程序"><a class="anchor" href="#24-打包应用程序">#</a> 2.4. 打包应用程序</h4>
<p>创建一个 <code>spec</code> 文件来配置打包设置( <code>your_script.spec</code> ):</p>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"># your_script.spec</span><br><span class="line"># -*- mode: python ; coding: utf-8 -*-</span><br><span class="line"></span><br><span class="line">block_cipher = None</span><br><span class="line"></span><br><span class="line">a = Analysis([&#x27;main.py&#x27;],</span><br><span class="line"> pathex=[],</span><br><span class="line"> binaries=[],</span><br><span class="line"> datas=[],</span><br><span class="line"> hiddenimports=[],</span><br><span class="line"> hookspath=[],</span><br><span class="line"> runtime_hooks=[],</span><br><span class="line"> excludes=[],</span><br><span class="line"> win_no_prefer_redirects=False,</span><br><span class="line"> win_private_assemblies=False,</span><br><span class="line"> cipher=block_cipher,</span><br><span class="line"> noarchive=False)</span><br><span class="line"></span><br><span class="line">pyz = PYZ(a.pure, a.zipped_data,</span><br><span class="line"> cipher=block_cipher)</span><br><span class="line"></span><br><span class="line">exe = EXE(pyz,</span><br><span class="line"> a.scripts,</span><br><span class="line"> [],</span><br><span class="line"> exclude_binaries=True,</span><br><span class="line"> name=&#x27;PDFExtractorApp&#x27;,</span><br><span class="line"> debug=False,</span><br><span class="line"> bootloader_ignore_signals=False,</span><br><span class="line"> strip=False,</span><br><span class="line"> upx=True,</span><br><span class="line"> upx_exclude=[],</span><br><span class="line"> runtime_tmpdir=None,</span><br><span class="line"> console=False)</span><br><span class="line"></span><br><span class="line">coll = COLLECT(exe,</span><br><span class="line"> a.binaries,</span><br><span class="line"> a.zipfiles,</span><br><span class="line"> a.datas,</span><br><span class="line"> strip=False,</span><br><span class="line"> upx=True,</span><br><span class="line"> upx_exclude=[],</span><br><span class="line"> name=&#x27;PDFExtractorApp&#x27;)</span><br></pre></td></tr></table></figure></p>
<p>然后使用 <code>pyinstaller</code> 打包:</p>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pyinstaller your_script.spec</span><br></pre></td></tr></table></figure></p>
<h3 id="3-配置和初始化pyupdater"><a class="anchor" href="#3-配置和初始化pyupdater">#</a> 3. 配置和初始化 PyUpdater</h3>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">pyupdater init</span><br><span class="line">pyupdater pkg --process</span><br><span class="line">pyupdater pkg --sign</span><br><span class="line">pyupdater pkg --upload</span><br><span class="line">pyupdater keys --create</span><br><span class="line">pyupdater settings</span><br></pre></td></tr></table></figure></p>
<h3 id="4-部署和测试"><a class="anchor" href="#4-部署和测试">#</a> 4. 部署和测试</h3>
<p>将生成的可执行文件和更新配置上传到你的服务器。然后运行打包好的应用程序,确保登录功能、PDF 处理功能和在线更新功能都正常工作。</p>
<p>这样,你就有了一个带有登录功能的 Windows 应用程序,可以选择文件夹中的 PDF 文件进行处理,并支持在线更新。</p>
<h2 id="要读取多个excel文件并两两判断它们之间是否存在高度重复的数据可以按以下步骤进行"><a class="anchor" href="#要读取多个excel文件并两两判断它们之间是否存在高度重复的数据可以按以下步骤进行">#</a> 要读取多个 Excel 文件并两两判断它们之间是否存在高度重复的数据,可以按以下步骤进行</h2>
<p>:</p>
<ol>
<li><strong>读取所有 Excel 文件</strong>。</li>
<li><strong>提取并整理数据</strong>。</li>
<li><strong>比较每对 Excel 文件的数据</strong>。</li>
<li><strong>计算重复率</strong>。</li>
<li><strong>输出比较结果</strong>。</li>
</ol>
<p>可以使用 <code>pandas</code> 库来处理 Excel 文件,利用 <code>pandas</code> 的 DataFrame 结构进行数据比较和重复率计算。</p>
<h3 id="1-安装必要的库"><a class="anchor" href="#1-安装必要的库">#</a> 1. 安装必要的库</h3>
<p>首先,确保你已经安装了 <code>pandas</code> 和 <code>openpyxl</code> 库:</p>
<p>bash</p>
<p>复制代码</p>
<p><code>pip install pandas openpyxl</code></p>
<h3 id="2-读取所有excel文件"><a class="anchor" href="#2-读取所有excel文件">#</a> 2. 读取所有 Excel 文件</h3>
<p>使用 <code>pandas</code> 读取 Excel 文件,并提取数据。</p>
<p>python</p>
<p>复制代码</p>
<p><code>import os import pandas as pd def read_excel_files(folder_path): excel_files = [os.path.join(folder_path, f) for f in os.listdir(folder_path) if f.endswith('.xlsx')] dataframes = &#123;f: pd.read_excel(f) for f in excel_files&#125; return dataframes folder_path = 'your_folder_with_excel_files' dataframes = read_excel_files(folder_path)</code></p>
<h3 id="3-比较每对excel文件的数据"><a class="anchor" href="#3-比较每对excel文件的数据">#</a> 3. 比较每对 Excel 文件的数据</h3>
<p>定义一个函数来比较两个 DataFrame,计算重复率。</p>
<p>python</p>
<p>复制代码</p>
<p><code>def calculate_similarity(df1, df2): # 确保两者都有相同的列 common_columns = df1.columns.intersection(df2.columns) if len(common_columns) == 0: return 0.0 # 选择共同的列进行比较 df1_common = df1[common_columns] df2_common = df2[common_columns] # 合并两个数据集,保留重复项 combined = pd.concat([df1_common, df2_common]) duplicates = combined.duplicated(keep=False) # 计算重复率 similarity = duplicates.sum() / len(combined) return similarity def compare_excel_files(dataframes): results = [] files = list(dataframes.keys()) for i in range(len(files)): for j in range(i + 1, len(files)): df1 = dataframes[files[i]] df2 = dataframes[files[j]] similarity = calculate_similarity(df1, df2) results.append((files[i], files[j], similarity)) return results similarity_results = compare_excel_files(dataframes)</code></p>
<h3 id="4-输出比较结果"><a class="anchor" href="#4-输出比较结果">#</a> 4. 输出比较结果</h3>
<p>将比较结果输出,显示每对 Excel 文件的相似度。</p>
<p>python</p>
<p>复制代码</p>
<p><code>for file1, file2, similarity in similarity_results: print(f&quot;文件 &#123;file1&#125; 和文件 &#123;file2&#125; 的相似度为: &#123;similarity:.2%&#125;&quot;)</code></p>
<h3 id="完整代码"><a class="anchor" href="#完整代码">#</a> 完整代码</h3>
<p>python</p>
<p>复制代码</p>
<p><code>import os import pandas as pd def read_excel_files(folder_path): excel_files = [os.path.join(folder_path, f) for f in os.listdir(folder_path) if f.endswith('.xlsx')] dataframes = &#123;f: pd.read_excel(f) for f in excel_files&#125; return dataframes def calculate_similarity(df1, df2): common_columns = df1.columns.intersection(df2.columns) if len(common_columns) == 0: return 0.0 df1_common = df1[common_columns] df2_common = df2[common_columns] combined = pd.concat([df1_common, df2_common]) duplicates = combined.duplicated(keep=False) similarity = duplicates.sum() / len(combined) return similarity def compare_excel_files(dataframes): results = [] files = list(dataframes.keys()) for i in range(len(files)): for j in range(i + 1, len(files)): df1 = dataframes[files[i]] df2 = dataframes[files[j]] similarity = calculate_similarity(df1, df2) results.append((files[i], files[j], similarity)) return results folder_path = 'your_folder_with_excel_files' dataframes = read_excel_files(folder_path) similarity_results = compare_excel_files(dataframes) for file1, file2, similarity in similarity_results: print(f&quot;文件 &#123;file1&#125; 和文件 &#123;file2&#125; 的相似度为: &#123;similarity:.2%&#125;&quot;)</code></p>
<h3 id="注意事项"><a class="anchor" href="#注意事项">#</a> 注意事项</h3>
<ul>
<li><strong>列对齐</strong>:确保所有比较的数据具有相同的列。</li>
<li><strong>数据清理</strong>:在实际使用中,可能需要对数据进行清理和预处理,以确保比较的准确性。</li>
<li><strong>优化</strong>:对于大型数据集,计算重复率可能会很耗时。可以考虑优化算法或使用更高效的数据结构。</li>
</ul>
<p>通过这些步骤,你可以实现读取多个 Excel 文件并两两判断是否有高度重复的数据,并计算和输出相似度。</p>
</content>
<updated>2024-05-28T12:12:46.003Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2024/03/20/AA/</id>
<title>拉勾训练营5期</title>
<link rel="alternate" href="https://fairyeye.github.io/2024/03/20/AA/"/>
<content type="html"><h1 id="jdbc"><a class="anchor" href="#jdbc">#</a> JDBC</h1>
<p>需要手动引入 Mysql 的 jar 包</p>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">JDBCDemo</span> &#123; </span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ClassNotFoundException, SQLException &#123; </span><br><span class="line"> <span class="comment">// 加载驱动 </span></span><br><span class="line"> Class.forName(<span class="string">&quot;com.mysql.jdbc.Driver&quot;</span>); </span><br><span class="line"> <span class="comment">// 建立连接 </span></span><br><span class="line"> <span class="type">Connection</span> <span class="variable">connection</span> <span class="operator">=</span> DriverManager.getConnection(<span class="string">&quot;jdbc:mysql://localhost:3306/test&quot;</span>, <span class="string">&quot;root&quot;</span>, <span class="string">&quot;12345678&quot;</span>); </span><br><span class="line"> <span class="comment">// 定义SQL语句 </span></span><br><span class="line"> <span class="type">String</span> <span class="variable">sql</span> <span class="operator">=</span> <span class="string">&quot;select * from db_account where id = 4&quot;</span>; </span><br><span class="line"> <span class="comment">// 获取预处理prepareStatement </span></span><br><span class="line"> <span class="type">PreparedStatement</span> <span class="variable">preparedStatement</span> <span class="operator">=</span> connection.prepareStatement(sql); </span><br><span class="line"> <span class="comment">// 设置参数 </span></span><br><span class="line"> <span class="comment">// preparedStatement.setInt(1, 4); </span></span><br><span class="line"> <span class="comment">// 执行查询 得到结果 </span></span><br><span class="line"> <span class="type">ResultSet</span> <span class="variable">resultSet</span> <span class="operator">=</span> preparedStatement.executeQuery(sql); </span><br><span class="line"> <span class="comment">// 处理结果 </span></span><br><span class="line"> <span class="keyword">while</span> (resultSet.next()) &#123; </span><br><span class="line"> System.out.println(<span class="string">&quot;id:&quot;</span> + resultSet.getInt(<span class="string">&quot;id&quot;</span>)); </span><br><span class="line"> System.out.println(<span class="string">&quot;email:&quot;</span> + resultSet.getString(<span class="string">&quot;email&quot;</span>)); </span><br><span class="line"> &#125; </span><br><span class="line"> &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<ol>
<li>为什么要有 ORM 框架</li>
</ol>
<ul>
<li>驱动 uri、数据库地址、账号密码,硬编码,不灵活</li>
<li>重复的建立连接</li>
<li>处理结果集麻烦</li>
</ul>
<h2 id="自定义"><a class="anchor" href="#自定义">#</a> 自定义</h2>
<h3 id="创建两个工程"><a class="anchor" href="#创建两个工程">#</a> 创建两个工程</h3>
<ul>
<li>IPersistence、IPersistence_Test</li>
</ul>
<h4 id="ipersistence_test-使用端"><a class="anchor" href="#ipersistence_test-使用端">#</a> IPersistence_Test 使用端</h4>
<h4 id="ipersistence-自定义框架"><a class="anchor" href="#ipersistence-自定义框架">#</a> IPersistence 自定义框架</h4>
<h5 id="根据配置文件的路径将配置文件加载成字节输入流存储在内存中"><a class="anchor" href="#根据配置文件的路径将配置文件加载成字节输入流存储在内存中">#</a> 根据配置文件的路径,将配置文件加载成字节输入流,存储在内存中</h5>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Resources.getResourceAsStream(String path)</span><br></pre></td></tr></table></figure></p>
<ol>
<li>获得 sqlSession 对象</li>
</ol>
<p>sqlSession 通过 sqlSessionFatory.open 获得<br />
sqlSessionFatory 通过 sqlSessionFatoryBuilder.build (configuration) 获得<br />
build 需要获取数据库信息</p>
<ul>
<li>创建 SqlSessionFactoryBuilder</li>
<li>通过 SqlSessionFatoryBuilder.build () 获得 SqlSessionFatory</li>
<li>通过 DefaultSqlSessionFactory.open () 获得 SqlSession</li>
<li>创建 DefaultSqlSession 实现基础方法 selectAll,selectList</li>
</ul>
<ol start="2">
<li>执行 JDBC 逻辑</li>
</ol>
<p>创建 Executor、Executor 实现类,执行 CURD</p>
<ol start="3">
<li>处理返回结果</li>
</ol>
<p>通过反射或内省 + SQLID 上的 resultType 全路径,处理返参</p>
<ul>
<li>问题 1:数据库类型与实体类型不一致<br />
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Exception in thread &quot;main&quot; java.lang.IllegalArgumentException: argument type mismatch at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498)</span><br></pre></td></tr></table></figure></li>
<li>问题 2:数据库版本与驱动版本不一致</li>
</ul>
<p>无法获取数据库连接,报错信息和获取连接方法有关</p>
<p>使用 C3P0 连接池是报错:<br />
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java.sql.SQLException: Connections could not be acquired from the underlying database!</span><br></pre></td></tr></table></figure></p>
<p>使用 DriverManager 直接连接时:<br />
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Client does not support authentication protocol requested by server; consider upgrading MySQL client</span><br><span class="line"></span><br></pre></td></tr></table></figure></p>
<ol start="4">
<li>持久层实现</li>
</ol>
<p>通过 mapper 接口,数据库的交互</p>
<p>SqlSession 中创建一个 getMapper 方法,获取 mapper 的代理类,执行被代理类的方法</p>
<h1 id="mybatis"><a class="anchor" href="#mybatis">#</a> Mybatis</h1>
<h3 id="概念"><a class="anchor" href="#概念">#</a> 概念</h3>
<p>基于 ORM 的 <code>半自动</code> 轻量级持久层框架。</p>
<h3 id="缓存"><a class="anchor" href="#缓存">#</a> 缓存</h3>
<p><strong>底层数据结构:</strong> 就是一个 HashMap。</p>
<p><code>先去缓存中查,然后到数据库中,如果缓存中有,就直接返回,不再去数据库查询。</code></p>
<h4 id="一级缓存-sqlsession级别"><a class="anchor" href="#一级缓存-sqlsession级别">#</a> <strong>一级缓存 - SqlSession 级别</strong></h4>
<p><strong>是否启用:</strong> 默认开启</p>
<p><code>cacheKey: org.apache.ibatis.executor.BaseExecutor#createCacheKey</code></p>
<p>增删改操作时,会刷新缓存(<strong>全部缓存</strong>)</p>
<h4 id="二级缓存-namespace级别"><a class="anchor" href="#二级缓存-namespace级别">#</a> <strong>二级缓存 - NameSpace 级别</strong></h4>
<p><strong>是否启用:</strong> 默认关闭,需要手动开启</p>
<ul>
<li>
<p>[I] 二级缓存是在 SqlSession 事务提交时写入的</p>
</li>
<li>
<p>[!] 二级缓存在分布式的情况下,可能有问题。</p>
</li>
</ul>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">secondLevelCacheTest</span><span class="params">()</span> <span class="keyword">throws</span> IOException &#123; </span><br><span class="line"> <span class="type">InputStream</span> <span class="variable">inputStream</span> <span class="operator">=</span> Resources.getResourceAsStream(<span class="string">&quot;sqlMapConfig.xml&quot;</span>); </span><br><span class="line"> <span class="type">SqlSessionFactory</span> <span class="variable">sqlSessionFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SqlSessionFactoryBuilder</span>().build(inputStream); </span><br><span class="line"> </span><br><span class="line"> <span class="type">SqlSession</span> <span class="variable">sqlSession1</span> <span class="operator">=</span> sqlSessionFactory.openSession(); </span><br><span class="line"> <span class="type">SqlSession</span> <span class="variable">sqlSession2</span> <span class="operator">=</span> sqlSessionFactory.openSession(); </span><br><span class="line"> </span><br><span class="line"> <span class="type">IUserMapper</span> <span class="variable">mapper1</span> <span class="operator">=</span> sqlSession1.getMapper(IUserMapper.class); </span><br><span class="line"> <span class="type">IUserMapper</span> <span class="variable">mapper2</span> <span class="operator">=</span> sqlSession2.getMapper(IUserMapper.class); </span><br><span class="line"> </span><br><span class="line"> <span class="type">User</span> <span class="variable">user1</span> <span class="operator">=</span> mapper1.selectByPrimaryKey(<span class="number">1</span>); </span><br><span class="line"> <span class="comment">// 这样是不会查到二级缓存的,需要事务提交或者关闭后才可以</span></span><br><span class="line"> <span class="comment">// sqlSession1.commit(); </span></span><br><span class="line"> <span class="comment">// sqlSession1.close(); </span></span><br><span class="line"> </span><br><span class="line"> <span class="type">User</span> <span class="variable">user2</span> <span class="operator">=</span> mapper2.selectByPrimaryKey(<span class="number">1</span>); </span><br><span class="line"> </span><br><span class="line"> System.out.println(user1==user2); </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p><strong>结论:</strong> 节省了数据库的交互</p>
<p><strong>Q:</strong><br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">firstLevelCacheTest3</span><span class="params">()</span> <span class="keyword">throws</span> IOException &#123; </span><br><span class="line"> <span class="type">InputStream</span> <span class="variable">inputStream</span> <span class="operator">=</span> Resources.getResourceAsStream(<span class="string">&quot;sqlMapConfig.xml&quot;</span>); </span><br><span class="line"> <span class="type">SqlSessionFactory</span> <span class="variable">sqlSessionFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SqlSessionFactoryBuilder</span>().build(inputStream); </span><br><span class="line"> </span><br><span class="line"> <span class="type">SqlSession</span> <span class="variable">sqlSession</span> <span class="operator">=</span> sqlSessionFactory.openSession(<span class="literal">true</span>); </span><br><span class="line"> <span class="type">SqlSession</span> <span class="variable">sqlSession2</span> <span class="operator">=</span> sqlSessionFactory.openSession(<span class="literal">true</span>); </span><br><span class="line"> </span><br><span class="line"> <span class="type">IUserMapper</span> <span class="variable">mapper</span> <span class="operator">=</span> sqlSession.getMapper(IUserMapper.class); </span><br><span class="line"> <span class="type">IUserMapper</span> <span class="variable">mapper2</span> <span class="operator">=</span> sqlSession2.getMapper(IUserMapper.class); </span><br><span class="line"> </span><br><span class="line"> <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> mapper.selectByPrimaryKey(<span class="number">1</span>); </span><br><span class="line"> System.out.println(user); </span><br><span class="line"> mapper2.updateUserByPrimaryKey(<span class="keyword">new</span> <span class="title class_">User</span>(<span class="number">1</span>, <span class="string">&quot;gaga&quot;</span>)); </span><br><span class="line"> <span class="type">User</span> <span class="variable">user1</span> <span class="operator">=</span> mapper.selectByPrimaryKey(<span class="number">1</span>); </span><br><span class="line"> System.out.println(user1); </span><br><span class="line"> System.out.println(<span class="string">&quot;user == user1: &quot;</span> + (user == user1)); </span><br><span class="line"> sqlSession.close(); </span><br><span class="line"> sqlSession2.close(); </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// User&#123;id=1, name=&#x27;haha&#x27;&#125;</span></span><br><span class="line"><span class="comment">// User&#123;id=1, name=&#x27;haha&#x27;&#125;</span></span><br><span class="line"><span class="comment">// user == user1: true</span></span><br><span class="line"></span><br></pre></td></tr></table></figure></p>
<h3 id="插件"><a class="anchor" href="#插件">#</a> 插件</h3>
<ul>
<li>[I] 需要在 SqlMapConfig.xml 中启用</li>
</ul>
<p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">plugins</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">plugin</span> <span class="attr">interceptor</span>=<span class="string">&quot;com.li.plugin.MyPlugin&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">plugin</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h4 id="分页插件"><a class="anchor" href="#分页插件">#</a> 分页插件</h4>
<p><strong>拦截器实现</strong></p>
<ul>
<li>
<p>[*] <code>com.github.pagehelper.PageHelper</code></p>
</li>
<li>
<p>[*] 入口: <code>com.github.pagehelper.SqlUtil#_processPage</code></p>
</li>
<li>
<p>[*] 增加 COUNTSQL: <code>com.github.pagehelper.MSUtils#processCountMappedStatement(MappedStatement ms, SqlSource sqlSource, Object[] args)</code></p>
</li>
<li>
<p>countSql 返回结果大于 0 时,执行分页,将总数设置到 page 对象中</p>
</li>
<li>
<p>替换参数 <code>com.github.pagehelper.MSUtils#processPageMappedStatement(MappedStatement ms, SqlSource sqlSource, Page page, Object[] args)</code></p>
</li>
<li>
<p>创建新的 mapperStatement,执行分页 SQL</p>
</li>
<li>
<p>设置分页参数: <code>com.github.pagehelper.MSUtils#setPageParameter</code></p>
</li>
</ul>
<h4 id="通用mapper"><a class="anchor" href="#通用mapper">#</a> 通用 Mapper</h4>
<h3 id="架构原理"><a class="anchor" href="#架构原理">#</a> 架构原理</h3>
<h4 id="架构设计"><a class="anchor" href="#架构设计">#</a> 架构设计</h4>
<h5 id="接口"><a class="anchor" href="#接口">#</a> 接口</h5>
<ul>
<li>通过 sqlSession.method (statementId) 或者 Mapper 代理类调用方法,执行主句的增删改查。</li>
<li>调用接口修改配置信息等。</li>
</ul>
<h5 id="数据处理"><a class="anchor" href="#数据处理">#</a> 数据处理</h5>
<ul>
<li>请求参数处理 (@Param):ParameterHandler</li>
<li>SQL 解析 (处理占位符、Mapper 标签):SqlSource</li>
<li>SQL 执行 (JDBC):Executor</li>
<li>返回结果处理 (类型转换等):ResultSetHandler</li>
</ul>
<h5 id="框架支撑"><a class="anchor" href="#框架支撑">#</a> 框架支撑</h5>
<ul>
<li>事务管理</li>
<li>连接池管理</li>
<li>缓存机制</li>
</ul>
<h4 id="主要构件"><a class="anchor" href="#主要构件">#</a> 主要构件</h4>
<ul>
<li>
<p>SqlSession:session 表示与数据库的连接</p>
</li>
<li>
<p>Executor:执行器</p>
</li>
<li>
<p>StatementHandler:</p>
</li>
<li>
<p>ParameterHandler:</p>
</li>
<li>
<p>BoundSql:</p>
</li>
<li>
<p>ResultSetHander:</p>
</li>
<li>
<p>TypeHandler:数据库类型与 JavaBean 类型的转换</p>
</li>
<li>
<p>MappedStatement:</p>
</li>
<li>
<p>SqlSource:</p>
</li>
</ul>
<h4 id="总体流程"><a class="anchor" href="#总体流程">#</a> 总体流程</h4>
<ol>
<li>SqlSessionFactoryBuilder 获取 SqlSessionFactory</li>
<li>SqlSessionFactory.openSession 获取 SqlSession 对象</li>
<li>通过 getMapper 获取 Mapper 代理对象</li>
<li>执行代理 Mapper 的方法</li>
<li>=&gt; Executor Mybatis 的执行器</li>
<li>=&gt; StatementHandler 与 JDBC Statement 的交互</li>
<li>=&gt; ParameterHandler 处理方法中携带的参数,拼接到 Sql 中</li>
<li>=&gt; 执行 JDBC 流程(加载驱动、建立连接、定义 Sql、获取预处理对象、处理参数、执行、处理返回结果)</li>
<li>=&gt; 处理 Java 类型和数据库类型映射</li>
</ol>
<h3 id="源码分析"><a class="anchor" href="#源码分析">#</a> 源码分析</h3>
<h4 id="getmapper"><a class="anchor" href="#getmapper">#</a> getMapper</h4>
<p>扫描 @Mapper 注解、从 sqlMapConfigXml 中读取 Mapper 包名,或者 Mapper 接口,将其存到 MapperRegistry.knownMappers 中<br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Map&lt;Class&lt;?&gt;, MapperProxyFactory&lt;?&gt;&gt; knownMappers = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br></pre></td></tr></table></figure></p>
<p>value 值存储的是一个工厂类,有个 <code>Class&lt;T&gt;</code> 的变量,和 <code>newInstance(SqlSession sqlSession)</code> 方法,用于给 Mapper 创建代理对象</p>
<ul>
<li>[*] <code>Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]&#123;mapperInterface&#125;, mapperProxy);</code></li>
</ul>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// JDK动态代理 生成代理对象</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * loader 类加载器</span></span><br><span class="line"><span class="comment"> * interfaces 代理对象类型</span></span><br><span class="line"><span class="comment"> * h InvocationHandler接口的实现类,需要实现invoke方法</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">newProxyInstance(ClassLoader loader, </span><br><span class="line"> Class&lt;?&gt;[] interfaces, </span><br><span class="line"> InvocationHandler h)</span><br></pre></td></tr></table></figure></p>
<h4 id="二级缓存"><a class="anchor" href="#二级缓存">#</a> 二级缓存</h4>
<ul>
<li>
<p>[*] <code>org.apache.ibatis.executor.CachingExecutor#flushCacheIfRequired</code></p>
</li>
<li>
<p>[*] <code>org.apache.ibatis.builder.MapperBuilderAssistant#addMappedStatement(java.lang.String, org.apache.ibatis.mapping.SqlSource, org.apache.ibatis.mapping.StatementType, org.apache.ibatis.mapping.SqlCommandType, java.lang.Integer, java.lang.Integer, java.lang.String, java.lang.Class&lt;?&gt;, java.lang.String, java.lang.Class&lt;?&gt;, org.apache.ibatis.mapping.ResultSetType, boolean, boolean, boolean, org.apache.ibatis.executor.keygen.KeyGenerator, java.lang.String, java.lang.String, java.lang.String, org.apache.ibatis.scripting.LanguageDriver, java.lang.String)</code></p>
</li>
<li>
<p>[?] 二级缓存需要再事务提交后或者关闭后生效</p>
</li>
</ul>
<p><code>org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler, org.apache.ibatis.cache.CacheKey, org.apache.ibatis.mapping.BoundSql)</code></p>
<p>=&gt; 使用 <code>CachingExecutor.query()</code> <br />
=&gt; 清空缓存<br />
=&gt;<br />
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">// 从二级缓存中,获取结果</span><br><span class="line">List&lt;E&gt; list = (List&lt;E&gt;) tcm.getObject(cache, key);</span><br><span class="line">getObject =&gt; TransactionalCacheManager.transactionalCaches.delegate中获取缓存</span><br><span class="line"></span><br><span class="line">// 如果没有取到 去一级缓存中取</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">// 缓存查询结果 </span><br><span class="line">tcm.putObject(cache, key, list);</span><br><span class="line"></span><br><span class="line">=&gt; 实际是存到了entriesToAddOnCommit中</span><br><span class="line"></span><br><span class="line">transactionalCaches中有一个:</span><br><span class="line">private final Map&lt;Object, Object&gt; entriesToAddOnCommit;</span><br><span class="line"></span><br><span class="line">public void putObject(Cache cache, CacheKey key, Object value) &#123; </span><br><span class="line"> // 存入TransactionalCache的缓存中 </span><br><span class="line"> getTransactionalCache(cache).putObject(key, value); </span><br><span class="line">&#125;</span><br><span class="line">=&gt; </span><br><span class="line">entriesToAddOnCommit.put(key, object);</span><br><span class="line"></span><br><span class="line">transactionalCaches中有一个flushPendingEntries方法,该方法会在事务提交、关闭时会调用,这也是二级缓存需要在事务提交或者关闭后才能查到的原因</span><br><span class="line">// 将 entriesToAddOnCommit、entriesMissedInCache 刷入 delegate(cache) 中 </span><br><span class="line">flushPendingEntries();</span><br><span class="line"></span><br></pre></td></tr></table></figure></p>
<ul>
<li>[?] 二级缓存为什么使用的是 <code>CachingExecutor</code></li>
</ul>
<p>sqlSessionFactory.openSession () 时会 new Executor<br />
<code>org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource</code></p>
<p><code>org.apache.ibatis.session.Configuration#newExecutor(org.apache.ibatis.transaction.Transaction, org.apache.ibatis.session.ExecutorType)</code></p>
</content>
<category term="学习" scheme="https://fairyeye.github.io/tags/%E5%AD%A6%E4%B9%A0/" />
<updated>2024-03-20T08:15:40.000Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2024/03/13/Spring%20Boot%20Admin/</id>
<title>Spring Boot Admin</title>
<link rel="alternate" href="https://fairyeye.github.io/2024/03/13/Spring%20Boot%20Admin/"/>
<content type="html"><h3 id="服务端配置"><a class="anchor" href="#服务端配置">#</a> 服务端配置</h3>
<p>新建一个 SpringBoot 项目</p>
<p><code>pom.xml</code></p>
<p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--如果不需要鉴权 可以不加Security依赖--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>de.codecentric<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-admin-starter-server<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-security<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p><code>application.properties</code></p>
<p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 端口</span></span><br><span class="line"><span class="attr">server.port</span>=<span class="string">20000 </span></span><br><span class="line"><span class="attr">server.servlet.context-path</span>=<span class="string">/admin</span></span><br></pre></td></tr></table></figure></p>
<p>启动类加上 <code>@EnableAdminServer</code> 注解</p>
<p>如果不需要鉴权 到这里就结束了,运行项目,然后访问 <code>localhost:20000/admin</code> 就可以看到 SBA 的 UI</p>
<p><img data-src="https://s3.bmp.ovh/imgs/2024/03/13/b436a3855a95e5cb.png" alt="" /></p>
<h4 id="非必须项"><a class="anchor" href="#非必须项">#</a> 非必须项</h4>
<p>引入 Security,开启认证登录,下面是一个简单的样例</p>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration(proxyBeanMethods = false)</span> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SecuritySecureConfig</span> <span class="keyword">extends</span> <span class="title class_">WebSecurityConfigurerAdapter</span> &#123; </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> AdminServerProperties adminServer; </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">SecuritySecureConfig</span><span class="params">(AdminServerProperties adminServer)</span> &#123; </span><br><span class="line"> <span class="built_in">this</span>.adminServer = adminServer; </span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span> </span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception &#123; </span><br><span class="line"> <span class="type">SavedRequestAwareAuthenticationSuccessHandler</span> <span class="variable">successHandler</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SavedRequestAwareAuthenticationSuccessHandler</span>(); </span><br><span class="line"> successHandler.setTargetUrlParameter(<span class="string">&quot;redirectTo&quot;</span>); </span><br><span class="line"> successHandler.setDefaultTargetUrl(<span class="built_in">this</span>.adminServer.path(<span class="string">&quot;/&quot;</span>)); </span><br><span class="line"> </span><br><span class="line"> http.authorizeRequests() </span><br><span class="line"> .antMatchers(<span class="built_in">this</span>.adminServer.path(<span class="string">&quot;/assets/**&quot;</span>)).permitAll() </span><br><span class="line"> .antMatchers(<span class="built_in">this</span>.adminServer.path(<span class="string">&quot;/login&quot;</span>)).permitAll() </span><br><span class="line"> .anyRequest().authenticated() </span><br><span class="line"> .and() </span><br><span class="line"> .formLogin().loginPage(<span class="built_in">this</span>.adminServer.path(<span class="string">&quot;/login&quot;</span>)).successHandler(successHandler).and() </span><br><span class="line"> .logout().logoutUrl(<span class="built_in">this</span>.adminServer.path(<span class="string">&quot;/logout&quot;</span>)).and() </span><br><span class="line"> .httpBasic().and() </span><br><span class="line"> .csrf() </span><br><span class="line"> .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) </span><br><span class="line"> .ignoringRequestMatchers( </span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">AntPathRequestMatcher</span>(<span class="built_in">this</span>.adminServer.path(<span class="string">&quot;/instances&quot;</span>), HttpMethod.POST.toString()), </span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">AntPathRequestMatcher</span>(<span class="built_in">this</span>.adminServer.path(<span class="string">&quot;/instances/*&quot;</span>), HttpMethod.DELETE.toString()), </span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">AntPathRequestMatcher</span>(<span class="built_in">this</span>.adminServer.path(<span class="string">&quot;/actuator/**&quot;</span>)) </span><br><span class="line"> ) </span><br><span class="line"> .and() </span><br><span class="line"> .rememberMe().key(UUID.randomUUID().toString()).tokenValiditySeconds(<span class="number">1209600</span>); </span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span> </span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">configure</span><span class="params">(AuthenticationManagerBuilder auth)</span> <span class="keyword">throws</span> Exception &#123; </span><br><span class="line"> auth.inMemoryAuthentication().withUser(<span class="string">&quot;user&quot;</span>).password(<span class="string">&quot;&#123;noop&#125;passwd&quot;</span>).roles(<span class="string">&quot;USER&quot;</span>); </span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>运行项目,然后访问 <code>localhost:20000/admin</code> 需要登录</p>
</content>
<category term="java" scheme="https://fairyeye.github.io/categories/java/" />
<category term="日常记录" scheme="https://fairyeye.github.io/tags/%E6%97%A5%E5%B8%B8%E8%AE%B0%E5%BD%95/" />
<updated>2024-03-13T09:11:02.629Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2024/02/22/security/</id>
<title>security</title>
<link rel="alternate" href="https://fairyeye.github.io/2024/02/22/security/"/>
<content type="html"><h2 id="1"><a class="anchor" href="#1">#</a> 1.</h2>
<p>引入依赖:<br />
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-security<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>一些必要的配置:</p>
<p>新建一个配置类 <code>WebSecurityConfig</code> 继承 <code>WebSecurityConfigurerAdapter</code> 重写 <code>configure</code> 方法。(<strong>重要</strong>)</p>
<ul>
<li>是 SpringSecurity 的核心</li>
</ul>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebSecurityConfig</span> <span class="keyword">extends</span> <span class="title class_">WebSecurityConfigurerAdapter</span> &#123; </span><br><span class="line"> <span class="meta">@Override</span> </span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception &#123; </span><br><span class="line"> <span class="comment">// 开启登录 </span></span><br><span class="line"> http.formLogin(); </span><br><span class="line">&#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>新建一个 controller 用来测试登录</p>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhanghuapeng </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2024/1/28 </span></span><br><span class="line"><span class="comment"> */</span><span class="meta">@RestController</span> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserController</span> &#123; </span><br><span class="line"> </span><br><span class="line"> <span class="comment">/** </span></span><br><span class="line"><span class="comment"> * 获取当前登录用户信息 </span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"> <span class="meta">@GetMapping(&quot;/user-info&quot;)</span> </span><br><span class="line"> <span class="keyword">public</span> Authentication <span class="title function_">getUserInfo</span><span class="params">(Authentication authentication)</span> &#123; </span><br><span class="line"> <span class="keyword">return</span> authentication; </span><br><span class="line"> &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br />
启动项目:终端会有这么一段日志<br />
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Using generated security password: f429b724-db54-4a56-ae82-7ebb63f22d69</span><br></pre></td></tr></table></figure><br />
表示:没有设置用户信息,给出了一个默认用户及密码,默认用户 <code>user</code></p>
<p>登录之后,默认会跳转到 Index 页面,但是目前没有这个页面,所以会报错。<br />
暂不处理。</p>
<p>访问: <code>http://localhost:8080/user-info</code> <br />
返回结果:<br />
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span><span class="attr">&quot;credentials&quot;</span><span class="punctuation">:</span><span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span><span class="attr">&quot;details&quot;</span><span class="punctuation">:</span><span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span><span class="attr">&quot;authenticated&quot;</span><span class="punctuation">:</span><span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span><span class="attr">&quot;authorities&quot;</span><span class="punctuation">:</span><span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span><span class="attr">&quot;principal&quot;</span><span class="punctuation">:</span><span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span><span class="attr">&quot;name&quot;</span><span class="punctuation">:</span><span class="string">&quot;not login!&quot;</span><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure></p>
<p>可以通过 <code>http://localhost:8080/logount</code> 退出登录</p>
<p>之后在访问 user-info 接口,发现不在包含用户信息</p>
<h2 id="2"><a class="anchor" href="#2">#</a> 2.</h2>
<p>实际使用中 没有登录的用户是不能访问接口的</p>
<p>修改 <code>WebSecurityConfig</code> <br />
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">@Configuration </span><br><span class="line">public class WebSecurityConfig extends WebSecurityConfigurerAdapter &#123; </span><br><span class="line"> @Override </span><br><span class="line"> protected void configure(HttpSecurity http) throws Exception &#123; </span><br><span class="line"> // 开启登录 </span><br><span class="line"> http.formLogin(); </span><br><span class="line"> // 设置访问权限 任何请求均需要认证(登录成功)才能访问 </span><br><span class="line">http.authorizeRequests().anyRequest().authenticated(); &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>重启项目<br />
此时,访问: <code>http://localhost:8080/user-info</code> <br />
发现会直接跳转到登录页面</p>
<h2 id="增加一些细节"><a class="anchor" href="#增加一些细节">#</a> 增加一些细节</h2>
<h3 id="依赖"><a class="anchor" href="#依赖">#</a> 依赖</h3>
<p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span> </span><br><span class="line"> <span class="comment">&lt;!-- Web --&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">exclusions</span>&gt;</span> <span class="tag">&lt;<span class="name">exclusion</span>&gt;</span> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-tomcat<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;/<span class="name">exclusion</span>&gt;</span> <span class="tag">&lt;/<span class="name">exclusions</span>&gt;</span> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="comment">&lt;!-- Undertow --&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-undertow<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="comment">&lt;!-- Security --&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-security<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="comment">&lt;!-- Test --&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="comment">&lt;!--lombok--&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.projectlombok<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>lombok<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>provided<span class="tag">&lt;/<span class="name">scope</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="comment">&lt;!--mybatis--&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>mysql<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mysql-connector-java<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">scope</span>&gt;</span>runtime<span class="tag">&lt;/<span class="name">scope</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.mybatis.spring.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mybatis-spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.2.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="comment">&lt;!-- 添加jwt的依赖 --&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.auth0<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>java-jwt<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.11.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="comment">&lt;!--Redis--&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-data-redis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span> </span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<h3 id="配置"><a class="anchor" href="#配置">#</a> 配置</h3>
<p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">server:</span> </span><br><span class="line"> <span class="attr">port:</span> <span class="number">8080</span> </span><br><span class="line"> </span><br><span class="line"><span class="attr">spring:</span> </span><br><span class="line"> <span class="attr">output:</span> </span><br><span class="line"> <span class="attr">ansi:</span> </span><br><span class="line"> <span class="attr">enabled:</span> <span class="string">always</span> <span class="comment"># 强制启用 ansi 输出 </span></span><br><span class="line"> <span class="attr">datasource:</span> </span><br><span class="line"> <span class="attr">driver-class-name:</span> <span class="string">com.mysql.cj.jdbc.Driver</span> </span><br><span class="line"> <span class="attr">url:</span> <span class="string">jdbc:mysql://127.0.0.1:3306/security_study?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai</span> </span><br><span class="line"> <span class="attr">username:</span> <span class="string">root</span> </span><br><span class="line"> <span class="attr">password:</span> <span class="number">12345678</span> </span><br><span class="line"> <span class="attr">redis:</span> </span><br><span class="line"> <span class="attr">host:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span> </span><br><span class="line"> <span class="attr">port:</span> <span class="number">6379</span> </span><br><span class="line"> <span class="attr">database:</span> <span class="number">1</span> </span><br><span class="line"><span class="attr">jwt:</span> </span><br><span class="line"> <span class="attr">secretKey:</span> <span class="string">a3e4cd2d191a017bf49dbdf49a4c62b1fb292c5b112d6a51bdc4e2ea5052e816</span> </span><br><span class="line"> <span class="attr">expiration:</span> <span class="number">3600</span> </span><br><span class="line"> </span><br><span class="line"><span class="attr">logging:</span> </span><br><span class="line"> <span class="attr">pattern:</span> </span><br><span class="line"> <span class="comment"># 控制台日志格式 </span></span><br><span class="line"> <span class="attr">console:</span> <span class="string">&quot;%clr(%d&#123;yyyy-MM-dd HH:mm:ss.SSS&#125;)&#123;faint&#125; %clr(%5p) %clr($&#123;PID:- &#125;)&#123;magenta&#125; %clr(%-40.40logger&#123;39&#125;)&#123;cyan&#125; : %msg%n&quot;</span> </span><br><span class="line"> </span><br><span class="line"><span class="attr">mybatis:</span> </span><br><span class="line"> <span class="attr">type-aliases-package:</span> <span class="string">com.li.entity</span> </span><br><span class="line"> <span class="attr">configuration:</span> </span><br><span class="line"> <span class="attr">map-underscore-to-camel-case:</span> <span class="literal">true</span> </span><br><span class="line"> <span class="attr">log-impl:</span> <span class="string">org.apache.ibatis.logging.stdout.StdOutImpl</span> </span><br><span class="line"> <span class="attr">mapper-locations:</span> <span class="string">classpath:mapper/*.xml</span></span><br></pre></td></tr></table></figure></p>
<ol>
<li>
<p>在 <code>com.li</code> 新建 <code>utils</code> 包,新建 <code>JwtUtils</code> <br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span> </span><br><span class="line"><span class="meta">@Slf4j</span> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">JwtUtils</span> &#123; </span><br><span class="line"> <span class="comment">//算法密钥 </span></span><br><span class="line"> <span class="meta">@Value(&quot;$&#123;jwt.secretKey&#125;&quot;)</span> </span><br><span class="line"> <span class="keyword">private</span> String jwtSecretKey; </span><br><span class="line"> <span class="comment">// 过期时间 </span></span><br><span class="line"> <span class="meta">@Value(&quot;$&#123;jwt.expiration&#125;&quot;)</span> </span><br><span class="line"> <span class="keyword">private</span> <span class="type">long</span> expiration; </span><br><span class="line"> </span><br><span class="line"> <span class="comment">/** </span></span><br><span class="line"><span class="comment"> * 创建jwt </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> userInfo 用户信息 </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> authList 用户权限列表 </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> 返回jwt(JSON WEB TOKEN) </span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">createToken</span><span class="params">(String userInfo, List&lt;String&gt; authList)</span> &#123; </span><br><span class="line"> <span class="comment">//创建时间 </span></span><br><span class="line"> <span class="type">Date</span> <span class="variable">currentTime</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Date</span>(); </span><br><span class="line"> <span class="comment">//过期时间,5分钟后过期 </span></span><br><span class="line"> <span class="type">Date</span> <span class="variable">expireTime</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Date</span>(currentTime.getTime() + expiration); </span><br><span class="line"> <span class="comment">//jwt 的header信息 </span></span><br><span class="line"> Map&lt;String, Object&gt; headerClaims = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(); </span><br><span class="line"> headerClaims.put(<span class="string">&quot;type&quot;</span>, <span class="string">&quot;JWT&quot;</span>); </span><br><span class="line"> headerClaims.put(<span class="string">&quot;alg&quot;</span>, <span class="string">&quot;HS256&quot;</span>); </span><br><span class="line"> <span class="comment">//创建jwt </span></span><br><span class="line"> <span class="keyword">return</span> JWT.create() </span><br><span class="line"> .withHeader(headerClaims) <span class="comment">// 头部 </span></span><br><span class="line"> .withIssuedAt(currentTime) <span class="comment">//已注册声明:签发日期,发行日期 </span></span><br><span class="line"> .withExpiresAt(expireTime) <span class="comment">//已注册声明 过期时间 </span></span><br><span class="line"> .withIssuer(<span class="string">&quot;thomas&quot;</span>) <span class="comment">//已注册声明,签发人 </span></span><br><span class="line"> .withClaim(<span class="string">&quot;userInfo&quot;</span>, userInfo) <span class="comment">//私有声明,可以自己定义 </span></span><br><span class="line"> .withClaim(<span class="string">&quot;authList&quot;</span>, authList) <span class="comment">//私有声明,可以自定义 </span></span><br><span class="line"> .sign(Algorithm.HMAC256(jwtSecretKey)); <span class="comment">// 签名,使用HS256算法签名,并使用密钥 </span></span><br><span class="line"><span class="comment">// HS256是一种对称算法,这意味着只有一个密钥,在双方之间共享。 使用相同的密钥生成签名并对其进行验证。 应特别注意钥匙是否保密。 </span></span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line"> <span class="comment">/** </span></span><br><span class="line"><span class="comment"> * 验证jwt的签名,简称验签 </span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> token 需要验签的jwt </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> 验签结果 </span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">verifyToken</span><span class="params">(String token)</span> &#123; </span><br><span class="line"> <span class="comment">//获取验签类对象 </span></span><br><span class="line"> <span class="type">JWTVerifier</span> <span class="variable">jwtVerifier</span> <span class="operator">=</span> JWT.require(Algorithm.HMAC256(jwtSecretKey)).build(); </span><br><span class="line"> <span class="keyword">try</span> &#123; </span><br><span class="line"> <span class="comment">//验签,如果不报错,则说明jwt是合法的,而且也没有过期 </span></span><br><span class="line"> <span class="type">DecodedJWT</span> <span class="variable">decodedJWT</span> <span class="operator">=</span> jwtVerifier.verify(token); </span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>; </span><br><span class="line"> &#125; <span class="keyword">catch</span> (JWTVerificationException e) &#123; </span><br><span class="line"> <span class="comment">//如果报错说明jwt 为非法的,或者已过期(已过期也属于非法的) </span></span><br><span class="line"> log.error(<span class="string">&quot;验签失败:&#123;&#125;&quot;</span>, token); </span><br><span class="line"> &#125; </span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>; </span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line"> <span class="comment">/** </span></span><br><span class="line"><span class="comment"> * 获取用户id </span></span><br><span class="line"><span class="comment"> * * <span class="doctag">@param</span> token jwt </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> 用户id </span></span><br><span class="line"><span class="comment"> */</span> <span class="keyword">public</span> String <span class="title function_">getUserInfo</span><span class="params">(String token)</span> &#123; </span><br><span class="line"> <span class="comment">//创建jwt验签对象 </span></span><br><span class="line"> <span class="type">JWTVerifier</span> <span class="variable">jwtVerifier</span> <span class="operator">=</span> JWT.require(Algorithm.HMAC256(jwtSecretKey)).build(); </span><br><span class="line"> <span class="keyword">try</span> &#123; </span><br><span class="line"> <span class="comment">//验签 </span></span><br><span class="line"> <span class="type">DecodedJWT</span> <span class="variable">decodedJWT</span> <span class="operator">=</span> jwtVerifier.verify(token); </span><br><span class="line"> <span class="comment">//获取payload中userInfo的值,并返回 </span></span><br><span class="line"> <span class="keyword">return</span> decodedJWT.getClaim(<span class="string">&quot;userInfo&quot;</span>).asString(); </span><br><span class="line"> &#125; <span class="keyword">catch</span> (JWTVerificationException e) &#123; </span><br><span class="line"> log.error(<span class="string">&quot;getUserInfo error&quot;</span>, e); </span><br><span class="line"> &#125; </span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>; </span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line"> <span class="comment">/** </span></span><br><span class="line"><span class="comment"> * 获取用户权限 </span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> token </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> </span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"> <span class="keyword">public</span> List&lt;String&gt; <span class="title function_">getUserAuth</span><span class="params">(String token)</span> &#123; </span><br><span class="line"> <span class="comment">//创建jwt验签对象 </span></span><br><span class="line"> <span class="type">JWTVerifier</span> <span class="variable">jwtVerifier</span> <span class="operator">=</span> JWT.require(Algorithm.HMAC256(jwtSecretKey)).build(); </span><br><span class="line"> <span class="keyword">try</span> &#123; </span><br><span class="line"> <span class="comment">//验签 </span></span><br><span class="line"> <span class="type">DecodedJWT</span> <span class="variable">decodedJWT</span> <span class="operator">=</span> jwtVerifier.verify(token); </span><br><span class="line"> <span class="comment">//获取payload中的自定义数据authList(权限列表),并返回 </span></span><br><span class="line"> <span class="keyword">return</span> decodedJWT.getClaim(<span class="string">&quot;authList&quot;</span>).asList(String.class); </span><br><span class="line"> &#125; <span class="keyword">catch</span> (JWTVerificationException e) &#123; </span><br><span class="line"> log.error(<span class="string">&quot;getUserAuth error&quot;</span>, e); </span><br><span class="line"> &#125; </span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>; </span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
</li>
<li>
<p>在 <code>com.li</code> 新建 <code>filter</code> 包,新建 <code>SaySomethingJWTFilter</code> <br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/** </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> zhanghuapeng </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2024/2/22 </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@desc</span> 一次性请求过滤器 </span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"><span class="meta">@Component</span> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SaySomethingJWTFilter</span> <span class="keyword">extends</span> <span class="title class_">OncePerRequestFilter</span> &#123; </span><br><span class="line"> <span class="meta">@Resource</span> </span><br><span class="line"> <span class="keyword">private</span> ObjectMapper objectMapper; </span><br><span class="line"> <span class="meta">@Resource</span> </span><br><span class="line"> <span class="keyword">private</span> StringRedisTemplate stringRedisTemplate; </span><br><span class="line"> <span class="meta">@Resource</span> </span><br><span class="line"> <span class="keyword">private</span> JwtUtils jwtUtils; </span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span> </span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doFilterInternal</span><span class="params">(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)</span> <span class="keyword">throws</span> ServletException, IOException &#123; </span><br><span class="line"> <span class="comment">//获取请求uri </span></span><br><span class="line"> <span class="type">String</span> <span class="variable">requestURI</span> <span class="operator">=</span> request.getRequestURI(); </span><br><span class="line"> <span class="comment">// 如果是登录页面,放行 </span></span><br><span class="line"> <span class="keyword">if</span> (requestURI.equals(<span class="string">&quot;/login&quot;</span>)) &#123; </span><br><span class="line"> filterChain.doFilter(request, response); </span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line"> &#125; </span><br><span class="line"> <span class="comment">//获取请求头中的Authorization </span></span><br><span class="line"> <span class="type">String</span> <span class="variable">authorization</span> <span class="operator">=</span> request.getHeader(<span class="string">&quot;Authorization&quot;</span>); </span><br><span class="line"> <span class="comment">//如果Authorization为空,那么不允许用户访问,直接返回 </span></span><br><span class="line"> <span class="keyword">if</span> (!StringUtils.hasText(authorization)) &#123; </span><br><span class="line"> printFront(response, <span class="string">&quot;没有登录!&quot;</span>); </span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//Authorization 去掉头部的Bearer 信息,获取token值 </span></span><br><span class="line"> <span class="type">String</span> <span class="variable">jwtToken</span> <span class="operator">=</span> authorization.replace(<span class="string">&quot;Bearer &quot;</span>, <span class="string">&quot;&quot;</span>); </span><br><span class="line"> <span class="comment">//验签 </span></span><br><span class="line"> <span class="type">boolean</span> <span class="variable">verifyTokenResult</span> <span class="operator">=</span> jwtUtils.verifyToken(jwtToken); </span><br><span class="line"> <span class="comment">//验签不成功 </span></span><br><span class="line"> <span class="keyword">if</span> (!verifyTokenResult) &#123; </span><br><span class="line"> printFront(response, <span class="string">&quot;jwtToken 已过期&quot;</span>); </span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//从payload中获取userInfo </span></span><br><span class="line"> <span class="type">String</span> <span class="variable">userInfo</span> <span class="operator">=</span> jwtUtils.getUserInfo(jwtToken); </span><br><span class="line"> <span class="comment">//从payload中获取授权列表 </span></span><br><span class="line"> List&lt;String&gt; userAuth = jwtUtils.getUserAuth(jwtToken); </span><br><span class="line"> <span class="comment">//创建登录用户 </span></span><br><span class="line"> <span class="type">SysUser</span> <span class="variable">sysUser</span> <span class="operator">=</span> objectMapper.readValue(userInfo, SysUser.class); </span><br><span class="line"> <span class="type">SecurityUser</span> <span class="variable">securityUser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SecurityUser</span>(sysUser); </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//设置权限 </span></span><br><span class="line"> List&lt;SimpleGrantedAuthority&gt; authList = userAuth.stream().map(SimpleGrantedAuthority::<span class="keyword">new</span>).collect(Collectors.toList()); </span><br><span class="line"> securityUser.setAuthorities(authList); </span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="type">UsernamePasswordAuthenticationToken</span> <span class="variable">usernamePasswordAuthenticationToke</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">UsernamePasswordAuthenticationToken</span>(securityUser </span><br><span class="line"> , <span class="literal">null</span>, authList); </span><br><span class="line"> <span class="comment">//通过安全上下文设置认证信息 </span></span><br><span class="line"> SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToke); </span><br><span class="line"> <span class="comment">//继续访问相应的rul等 </span></span><br><span class="line"> filterChain.doFilter(request, response); </span><br><span class="line"> </span><br><span class="line"> &#125; </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">printFront</span><span class="params">(HttpServletResponse response, String message)</span> <span class="keyword">throws</span> IOException &#123; </span><br><span class="line"> response.setCharacterEncoding(<span class="string">&quot;UTF-8&quot;</span>); </span><br><span class="line"> response.setContentType(<span class="string">&quot;application/json;charset=utf-8&quot;</span>); </span><br><span class="line"> <span class="type">PrintWriter</span> <span class="variable">writer</span> <span class="operator">=</span> response.getWriter(); </span><br><span class="line"> <span class="type">HttpResult</span> <span class="variable">httpResult</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HttpResult</span>(); </span><br><span class="line"> httpResult.setCode(-<span class="number">1</span>); </span><br><span class="line"> httpResult.setMsg(message); </span><br><span class="line"> </span><br><span class="line"> writer.print(objectMapper.writeValueAsString(httpResult)); </span><br><span class="line"> writer.flush(); </span><br><span class="line"> &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
</li>
<li>
<p>调整 <code>SecurityConfig</code> , 将过滤器添加到配置中<br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Resource</span> </span><br><span class="line"><span class="keyword">private</span> SaySTokenFilter saySTokenFilter;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span> </span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception &#123; </span><br><span class="line"> <span class="comment">// 增加配置</span></span><br><span class="line"> http.addFilterBefore(saySomethingJWTFilter, UsernamePasswordAuthenticationFilter.class); </span><br><span class="line"><span class="comment">// ...原来的配置</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
</li>
</ol>
<h5 id="调试"><a class="anchor" href="#调试">#</a> 调试</h5>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># 不携带token访问http://localhost:8080/user-info</span><br><span class="line">返回:&#123;&quot;code&quot;:-1,&quot;msg&quot;:&quot;没有登录!&quot;,&quot;data&quot;:null&#125;</span><br><span class="line"># 携带错误token访问http://localhost:8080/user-info</span><br><span class="line">返回:&#123;&quot;code&quot;:-1,&quot;msg&quot;:&quot;jwtToken 已过期&quot;,&quot;data&quot;:null&#125;</span><br></pre></td></tr></table></figure></p>
<ol start="4">
<li>在 <code>com.li.config</code> , 新建 <code>SaySAuthenticationSuccessHandler</code></li>
</ol>
<h4 id="设置权限"><a class="anchor" href="#设置权限">#</a> 设置权限</h4>
<p><strong>在 loadUserByUsername 中获取权限,并设置到 SecurityUser 中</strong></p>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// com.li.service.impl.UserServiceImpl</span></span><br><span class="line"></span><br><span class="line"><span class="type">SecurityUser</span> <span class="variable">securityUser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SecurityUser</span>(sysUser); </span><br><span class="line"><span class="comment">// 获取权限信息 </span></span><br><span class="line">List&lt;String&gt; authList = sysMenuDao.queryPermissionByUserId(sysUser.getUserId()); </span><br><span class="line"><span class="keyword">if</span> (!CollectionUtils.isEmpty(authList)) &#123; </span><br><span class="line"> List&lt;SimpleGrantedAuthority&gt; authorities = authList.stream().map(SimpleGrantedAuthority::<span class="keyword">new</span>).collect(toList()); </span><br><span class="line"> <span class="comment">// 设置权限 </span></span><br><span class="line"> securityUser.setAuthorities(authorities); </span><br><span class="line">&#125; </span><br><span class="line"><span class="keyword">return</span> securityUser;</span><br></pre></td></tr></table></figure></p>
<p>在 SaySAuthenticationSuccessHandler.onAuthenticationSuccess 中,生成 Token 时,可以将权限信息一起放入 Token 中。</p>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">List&lt;String&gt; authList = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;(); </span><br><span class="line"><span class="comment">// 获取权限 </span></span><br><span class="line">List&lt;SimpleGrantedAuthority&gt; authorities = (List&lt;SimpleGrantedAuthority&gt;) securityUser.getAuthorities(); </span><br><span class="line"><span class="keyword">if</span> (!CollectionUtils.isEmpty(authorities)) &#123; </span><br><span class="line"> <span class="comment">// 转成String 用于生成Token </span></span><br><span class="line"> authList = authorities.stream().map(SimpleGrantedAuthority::getAuthority).collect(Collectors.toList()); </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建Token 增加authList参数</span></span><br><span class="line"><span class="type">String</span> <span class="variable">token</span> <span class="operator">=</span> saySJwtUtils.createToken(userInfo, authList);</span><br></pre></td></tr></table></figure></p>
<h4 id="注销处理"><a class="anchor" href="#注销处理">#</a> 注销处理</h4>
<p><strong>Jwt 本质上是一个字符串,无法手动将其过期,也就是说,即使手动退出登录,对于 Token 来说,还是一个有效的 Token,可以通过接入 Redis 来解决这一问题</strong></p>
<ol>
<li>
<p>登录成功时,将 Token 写入 Redis<br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// SaySAuthenticationSuccessHandler</span></span><br><span class="line"><span class="comment">// 设置过期时间 </span></span><br><span class="line"><span class="meta">@Value(&quot;$&#123;jwt.expiration&#125;&quot;)</span> </span><br><span class="line"><span class="keyword">private</span> <span class="type">long</span> expiration;</span><br><span class="line"><span class="comment">// 引入StringRedisTemplate</span></span><br><span class="line"><span class="meta">@Resource</span> </span><br><span class="line"><span class="keyword">private</span> StringRedisTemplate stringRedisTemplate;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 在创建Token之后,将Token存到Redis中</span></span><br><span class="line"></span><br><span class="line">onAuthenticationSuccess()&#123;</span><br><span class="line"><span class="comment">// 创建Token </span></span><br><span class="line"><span class="type">String</span> <span class="variable">token</span> <span class="operator">=</span> saySJwtUtils.createToken(userInfo, authList);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 写入Redis </span></span><br><span class="line">stringRedisTemplate.opsForValue().set(<span class="string">&quot;login_token:&quot;</span> + token, objectMapper.writeValueAsString(authentication), expiration, TimeUnit.MILLISECONDS);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></p>
</li>
<li>
<p>校验 Token 时,先验签,再去 Redis 中判断 Token 是否还存在</p>
</li>
</ol>
<ul>
<li>如果验签成功,但是 Redis 中不存在,说明 Token 被手动过期了<br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">doFilterInternal()&#123;</span><br><span class="line">...</span><br><span class="line"><span class="comment">// 从Redis获取token并校验 </span></span><br><span class="line"><span class="type">String</span> <span class="variable">tokenInRedis</span> <span class="operator">=</span> stringRedisTemplate.opsForValue().get(<span class="string">&quot;login_token:&quot;</span> + jwtToken); </span><br><span class="line"><span class="keyword">if</span> (!StringUtils.hasText(tokenInRedis)) &#123; </span><br><span class="line"> printFront(response, <span class="string">&quot;用户已退出,请重新登录&quot;</span>); </span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line">&#125;</span><br><span class="line">...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ul>
<p>在 <code>com.li.config</code> ,新建 <code>SaysLogoutSuccessHandler</code> <br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"> </span><br><span class="line"><span class="comment">/** </span></span><br><span class="line"><span class="comment"> * 退出成功处理器,用户退出成功后,执行此处理器 </span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"><span class="meta">@Component</span> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SaysLogoutSuccessHandler</span> <span class="keyword">implements</span> <span class="title class_">LogoutSuccessHandler</span> &#123; </span><br><span class="line"> <span class="comment">//使用此工具类的对象进行序列化操作 </span></span><br><span class="line"> <span class="meta">@Resource</span> </span><br><span class="line"> <span class="keyword">private</span> ObjectMapper objectMapper; </span><br><span class="line"> <span class="meta">@Resource</span> </span><br><span class="line"> <span class="keyword">private</span> StringRedisTemplate stringRedisTemplate; </span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span> </span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">onLogoutSuccess</span><span class="params">(HttpServletRequest request, HttpServletResponse response, Authentication authentication)</span> <span class="keyword">throws</span> IOException, ServletException &#123; </span><br><span class="line"> <span class="comment">//从请求头中获取Authorization信息 </span></span><br><span class="line"> <span class="type">String</span> <span class="variable">authorization</span> <span class="operator">=</span> request.getHeader(<span class="string">&quot;Authorization&quot;</span>); </span><br><span class="line"> <span class="comment">//如果授权信息为空,返回前端 </span></span><br><span class="line"> <span class="keyword">if</span> (<span class="literal">null</span> == authorization) &#123; </span><br><span class="line"> response.setCharacterEncoding(<span class="string">&quot;UTF-8&quot;</span>); </span><br><span class="line"> response.setContentType(<span class="string">&quot;application/json;charset=utf-8&quot;</span>); </span><br><span class="line"> <span class="type">HttpResult</span> <span class="variable">httpResult</span> <span class="operator">=</span> HttpResult.builder().code(-<span class="number">1</span>).msg(<span class="string">&quot;token不能为空&quot;</span>).build(); </span><br><span class="line"> <span class="type">PrintWriter</span> <span class="variable">writer</span> <span class="operator">=</span> response.getWriter(); </span><br><span class="line"> writer.write(objectMapper.writeValueAsString(httpResult)); </span><br><span class="line"> writer.flush(); </span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line"> &#125; </span><br><span class="line"> <span class="comment">//如果Authorization信息不为空,去掉头部的Bearer字符串 </span></span><br><span class="line"> <span class="type">String</span> <span class="variable">token</span> <span class="operator">=</span> authorization.replace(<span class="string">&quot;Bearer &quot;</span>, <span class="string">&quot;&quot;</span>); </span><br><span class="line"> </span><br><span class="line"> <span class="comment">//redis中删除token,这是关键点 </span></span><br><span class="line"> stringRedisTemplate.delete(<span class="string">&quot;login_token:&quot;</span> + token); </span><br><span class="line"> </span><br><span class="line"> response.setCharacterEncoding(<span class="string">&quot;UTF-8&quot;</span>); </span><br><span class="line"> response.setContentType(<span class="string">&quot;application/json;charset=utf-8&quot;</span>); </span><br><span class="line"> <span class="type">HttpResult</span> <span class="variable">httpResult</span> <span class="operator">=</span> HttpResult.builder().code(<span class="number">200</span>).msg(<span class="string">&quot;退出成功&quot;</span>).build(); </span><br><span class="line"> <span class="type">PrintWriter</span> <span class="variable">writer</span> <span class="operator">=</span> response.getWriter(); </span><br><span class="line"> writer.write(objectMapper.writeValueAsString(httpResult)); </span><br><span class="line"> writer.flush(); </span><br><span class="line"> &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>调整 <code>SecurityConfig</code> <br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="meta">@Resource</span> </span><br><span class="line"><span class="keyword">private</span> SaysLogoutSuccessHandler saysLogoutSuccessHandler;</span><br><span class="line"></span><br><span class="line">configure()&#123;</span><br><span class="line">http.logout().logoutSuccessHandler(saysLogoutSuccessHandler);</span><br><span class="line"><span class="comment">// 禁用跨域请求保护 要不然logout不能访问(目前体现是弹出了确认退出登录的确认框 </span></span><br><span class="line">http.csrf().disable();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p><code>org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider#authenticate</code> <br />
<code>org.springframework.security.authentication.dao.DaoAuthenticationProvider#retrieveUser</code></p>
<p><code>org.springframework.security.authentication.dao.DaoAuthenticationProvider#additionalAuthenticationChecks</code></p>
</content>
<updated>2024-02-22T11:26:20.691Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2024/01/19/Leetcode/</id>
<title></title>
<link rel="alternate" href="https://fairyeye.github.io/2024/01/19/Leetcode/"/>
<content type="html"><h3 id="2171-拿出最少得魔法豆"><a class="anchor" href="#2171-拿出最少得魔法豆">#</a> 2171 拿出最少得魔法豆</h3>
<p><img data-src="https://s3.bmp.ovh/imgs/2024/01/19/2f204f7d3bbeef18.png" alt="" /></p>
</content>
<updated>2024-01-19T01:20:19.000Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2024/01/03/%E6%95%B0%E7%BB%84%E4%B8%8E%E9%93%BE%E8%A1%A8/</id>
<title></title>
<link rel="alternate" href="https://fairyeye.github.io/2024/01/03/%E6%95%B0%E7%BB%84%E4%B8%8E%E9%93%BE%E8%A1%A8/"/>
<content type="html"></content>
<updated>2024-01-03T02:14:03.735Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2023/12/25/Algo/</id>
<title>Hello Algo</title>
<link rel="alternate" href="https://fairyeye.github.io/2023/12/25/Algo/"/>
<content type="html"><p>二分搜索、插入排序、贪心</p>
<p>迭代、递归</p>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># n &gt;= 1 时</span><br><span class="line">T(n) = 3+2n &lt;= 3n+2n = 5n</span><br><span class="line">T(n) &lt;= c * f(n)</span><br><span class="line">T(n) = O(f(n))</span><br></pre></td></tr></table></figure></p>
<h3 id="kmp"><a class="anchor" href="#kmp">#</a> KMP</h3>
<h4 id="求next"><a class="anchor" href="#求next">#</a> 求 <code>next[]</code></h4>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">next[]:找出一个以0下标(必须0下标)开始,以j-1下标结束的两个相同子串</span><br><span class="line">=&gt;next[j-1] =&gt; k-1</span><br></pre></td></tr></table></figure></p>
<p><img data-src="https://s3.bmp.ovh/imgs/2023/12/28/114225dc0dc58919.png" alt="" /></p>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line">哈哈 k x j </span><br><span class="line">下标k 0 1 2 3 4 5 6 7 8 9 10 11 12 13</span><br><span class="line">数组p a b a b c a b c d a b c d e</span><br><span class="line">next数组 -1 0 0 1 2 0 1 2 0 0 1 2 0 0</span><br><span class="line"></span><br><span class="line">j++</span><br><span class="line">下标0 = a</span><br><span class="line">当 j = 3:</span><br><span class="line"> 下标j-1=2 -&gt; a 可以找到 a、aba、a 但是aba不满足条件 =&gt; 1</span><br><span class="line">当 j = 4:</span><br><span class="line"> 下标j-1=3 -&gt; b 可以找到 ab、abab 但是abab不满足条件 =&gt; 2</span><br><span class="line">当 j = 5:</span><br><span class="line"> 下标j-1=4 -&gt; c 可以找到 ababc 不满足条件 =&gt; 0</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">哈哈 k x j </span><br><span class="line">下标k 0 1 2 3 4 5 6 7 8 9 10 11 12 13</span><br><span class="line">数组p a b a b c a b a d a b c d e</span><br><span class="line">next数组 -1 0 0 1 2 0 1 2 3 0 1 2 0 0</span><br><span class="line"></span><br><span class="line">已知条件:</span><br><span class="line">以0下标(必须0下标)开始,以j-1下标结束的两个相同子串</span><br><span class="line">p[0]..p[k-1] = p[x]..p[j-1]</span><br><span class="line">得出:</span><br><span class="line">=&gt; k-1-0 = j-1-x </span><br><span class="line">=&gt; k = j-x</span><br><span class="line">=&gt; x = j-k</span><br><span class="line">==&gt; p[0]..p[k-1] = p[j-k]..p[j-1]</span><br><span class="line">假设:p[k] = p[j]</span><br><span class="line">=&gt; p[0]..p[k] = p[j-k]..p[j]</span><br><span class="line">所以 next[j] = k </span><br><span class="line"></span><br><span class="line">k-1 = next[j-1]</span><br><span class="line">p[0]..p[k-1] = p[x]..p[j-1]</span><br><span class="line">假设:p[k] = p[j]</span><br><span class="line">p[0]..p[k-1]p[k] = p[x]..p[j-1]p[j]</span><br><span class="line">p[0]..p[k] = p[j-k]..p[j]</span><br><span class="line">k = next[j]</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure></p>
<h3 id="数组"><a class="anchor" href="#数组">#</a> 数组</h3>
<p>优点:</p>
<ul>
<li>空间效率高</li>
<li>支持随机访问</li>
<li>缓存局部性?<br />
缺点:</li>
<li>插入与删除效率低</li>
<li>长度不可变</li>
<li>空间浪费<br />
典型应用:</li>
<li>随机访问</li>
<li>排序、搜索</li>
<li>查找表</li>
<li>机器学习</li>
<li>数据结构实现</li>
</ul>
<h3 id="链表"><a class="anchor" href="#链表">#</a> 链表</h3>
<h3 id="数组-vs-链表"><a class="anchor" href="#数组-vs-链表">#</a> 数组 vs 链表</h3>
<ul>
<li>存储方式</li>
<li>容量扩展</li>
<li>内存效率</li>
<li>访问元素</li>
<li>添加元素</li>
<li>删除元素</li>
</ul>
</content>
<category term="学习" scheme="https://fairyeye.github.io/tags/%E5%AD%A6%E4%B9%A0/" />
<updated>2023-12-25T08:04:09.000Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2023/10/27/%E6%96%87%E7%AB%A0%E5%90%8D%E7%A7%B0/</id>
<title>测试</title>
<link rel="alternate" href="https://fairyeye.github.io/2023/10/27/%E6%96%87%E7%AB%A0%E5%90%8D%E7%A7%B0/"/>
<content type="html"><p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(Objects.nonNull(prLine)&amp;&amp;Objects.nonNull(prLine.getPurchaseAgentId()))&#123;</span><br><span class="line"> poHeaderDetailDTO.setAgentId(prLine.getPurchaseAgentId());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
</content>
<updated>2023-10-27T03:08:31.251Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2023/10/25/Mac%E4%BD%BF%E7%94%A8%E8%AE%B0%E5%BD%95/</id>
<title>Mac使用记录</title>
<link rel="alternate" href="https://fairyeye.github.io/2023/10/25/Mac%E4%BD%BF%E7%94%A8%E8%AE%B0%E5%BD%95/"/>
<content type="html"><h2 id="软件"><a class="anchor" href="#软件">#</a> 软件</h2>
<h3 id="ttygif"><a class="anchor" href="#ttygif">#</a> ttygif</h3>
<ul>
<li>终端录制工具</li>
</ul>
<h4 id="安装教程"><a class="anchor" href="#安装教程">#</a> 安装教程</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew install ttygif</span><br></pre></td></tr></table></figure></p>
<h4 id="使用"><a class="anchor" href="#使用">#</a> 使用</h4>
<p><figure class="highlight bash"><figcaption><span>命令行提示符 command:("[root@localhost] $":1,9-10||"[admin@remotehost] #":4-6)</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ttyrec myrecording</span><br></pre></td></tr></table></figure></p>
<h3 id="sshx"><a class="anchor" href="#sshx">#</a> sshx</h3>
<ul>
<li>终端共享</li>
</ul>
<h4 id="使用-2"><a class="anchor" href="#使用-2">#</a> 使用</h4>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">zhanghuapengdeMacBook-Pro :: Downloads/work_space/AA % sshx</span><br><span class="line"></span><br><span class="line"> sshx v0.2.1</span><br><span class="line"></span><br><span class="line"> ➜ Link: https://sshx.io/s/ZtVval8VO2<span class="comment">#e9o4sruIiflVdh</span></span><br><span class="line"> ➜ Shell: /bin/zsh</span><br></pre></td></tr></table></figure></p>
<h2 id="flutter"><a class="anchor" href="#flutter">#</a> Flutter</h2>
<h4 id="环境安装"><a class="anchor" href="#环境安装">#</a> 环境安装:</h4>
<p><span class="exturl" data-url="aHR0cHM6Ly9kb2NzLmZsdXR0ZXIuZGV2L2dldC1zdGFydGVkL2luc3RhbGwvbWFjb3M=">官方说明</span></p>
<h2 id="环境"><a class="anchor" href="#环境">#</a> 环境</h2>
<p>python 环境</p>
<p>虚拟环境:~/</p>
<p>DP:DrissionPage</p>
<h2 id="lua"><a class="anchor" href="#lua">#</a> LUA</h2>
<p><span class="exturl" data-url="aHR0cHM6Ly9tcC53ZWl4aW4ucXEuY29tL3MvQWc1RTZEODFkaUU2TS11ZWhXbG9KUQ==">lua+redis 限流</span></p>
<h2 id="cargo"><a class="anchor" href="#cargo">#</a> Cargo</h2>
<p><span class="exturl" data-url="aHR0cHM6Ly9kb2MucnVzdC1sYW5nLm9yZy9jYXJnby9nZXR0aW5nLXN0YXJ0ZWQvaW5zdGFsbGF0aW9uLmh0bWw=">install cargo</span></p>
<h2 id="破解软件打不开"><a class="anchor" href="#破解软件打不开">#</a> 破解软件打不开</h2>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 这个好像没生效</span></span><br><span class="line">Mac :: ~ % sudo spctl --global-disable</span><br><span class="line">Password:</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将软件拖进来</span></span><br><span class="line">Mac :: ~ % sudo xattr -r -c /Applications/Navicat\ Premium.app</span><br></pre></td></tr></table></figure></p>
<h2 id="jrebel-激活"><a class="anchor" href="#jrebel-激活">#</a> Jrebel 激活</h2>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">docker pull qierkang/golang-reverseproxy</span><br><span class="line">docker run -d -p 8888:8888 qierkang/golang-reverseproxy</span><br><span class="line"></span><br><span class="line">#licene</span><br><span class="line">http://127.0.0.1:8888/7a14c9f7-8a27-46d6-bb50-2b30c19e766c</span><br></pre></td></tr></table></figure></p>
<h3 id="一行命令下载全网视频"><a class="anchor" href="#一行命令下载全网视频">#</a> 一行命令下载全网视频</h3>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ pip3 install you-get</span><br></pre></td></tr></table></figure><br />
<strong> 如何下载</strong></p>
<p><em><strong>1.</strong></em> 可通过如下命令查看该视频的详细信息。<br />
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">you-get -i <span class="string">&#x27;视频url&#x27;</span></span><br></pre></td></tr></table></figure><br />
<em><strong>2.</strong></em> 下载方式更简单,只需一行命令即可下载了:</p>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">you-get <span class="string">&#x27;视频url&#x27;</span></span><br></pre></td></tr></table></figure></p>
<h3 id="jan-将人工智能带入您的桌面"><a class="anchor" href="#jan-将人工智能带入您的桌面">#</a> Jan - 将人工智能带入您的桌面</h3>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><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><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br></pre></td><td class="code"><pre><span class="line">```</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">## Sonoma系统退回到Catalina</span><br><span class="line"></span><br><span class="line">![](https://s3.bmp.ovh/imgs/2024/03/18/26d4edbd95ba29b0.png)</span><br><span class="line"></span><br><span class="line">20款MacBook Pro,使用Sonoma系统感觉有点卡顿,晚上说是新系统对旧Mac兼容不是很好,决定退回Catalina版本,最后一个Inter电脑发布的系统</span><br><span class="line"></span><br><span class="line">准备:U盘(32G)(没有也行</span><br><span class="line">时间机器:(没有也行 主打一个凑合</span><br><span class="line">电脑硬盘:这个得有</span><br><span class="line">Catalina系统安装器(去App Store下载好</span><br><span class="line">0. 先分区</span><br><span class="line"> - 有U盘的情况,直接新建一个系统分区就好(`APFS`格式)</span><br><span class="line"> - 无U盘的情况,先建一个系统分区,再用至少20G空间做一个引导系统分区,格式选(Mac OS日志)</span><br><span class="line"> - 分区的时候,该抹掉就抹掉,只要别把当前系统抹掉就行</span><br><span class="line"></span><br><span class="line">1. 制作引导系统 (这步记不太清楚了</span><br><span class="line"></span><br><span class="line">有U盘的情况下,重启电脑,按`option`键,显示小地球图标(没有图),大概就是下面的这种,</span><br><span class="line">![](https://s3.bmp.ovh/imgs/2024/03/18/5ad8cd52fe6b475c.png)</span><br><span class="line"></span><br><span class="line">2. 分区</span><br><span class="line">3. 安装到分区上</span><br><span class="line">4. 用Catalina系统制作时间机器,保证时间机器分区是Mac OS 扩展(日志式)</span><br><span class="line">5. 将Sonoma系统数据备份到时间机器</span><br><span class="line">6. 到Catalina系统,用迁移助理将数据迁移过来</span><br><span class="line">7. 后续看情况删除Sonoma系统分区</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">## Docker</span><br><span class="line"></span><br><span class="line">### QL</span><br><span class="line"></span><br><span class="line">#### dailycheckin</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">```python</span><br><span class="line">&quot;&quot;&quot;</span><br><span class="line">获取i茅台账号cookie</span><br><span class="line">&quot;&quot;&quot;</span><br><span class="line">import hashlib</span><br><span class="line"></span><br><span class="line">import json</span><br><span class="line"></span><br><span class="line">import time</span><br><span class="line"></span><br><span class="line">import requests</span><br><span class="line"></span><br><span class="line">&quot;&quot;&quot;</span><br><span class="line"></span><br><span class="line">获取地点信息,这里用的高德 api,需要自己去高德开发者平台申请自己的 key</span><br><span class="line"></span><br><span class="line">&quot;&quot;&quot;</span><br><span class="line"></span><br><span class="line">AMAP_KEY = &quot;d13d06ac58fd360776f58583254c0079&quot;</span><br><span class="line"></span><br><span class="line">SALT = &quot;2af72f100c356273d46284f6fd1dfc08&quot;</span><br><span class="line"></span><br><span class="line">CURRENT_TIME = str(int(time.time() * 1000))</span><br><span class="line"></span><br><span class="line">headers = &#123;&#125;</span><br><span class="line"></span><br><span class="line">mt_version = json.loads(</span><br><span class="line"></span><br><span class="line">requests.get(&quot;https://itunes.apple.com/cn/lookup?id=1600482450&quot;).text</span><br><span class="line"></span><br><span class="line">)[&quot;results&quot;][0][&quot;version&quot;]</span><br><span class="line"></span><br><span class="line">header_context = &quot;&quot;&quot;</span><br><span class="line"></span><br><span class="line">MT-Lat: 28.499562</span><br><span class="line"></span><br><span class="line">MT-K: 1675213490331</span><br><span class="line"></span><br><span class="line">MT-Lng: 102.182324</span><br><span class="line"></span><br><span class="line">Host: app.moutai519.com.cn</span><br><span class="line"></span><br><span class="line">MT-User-Tag: 0</span><br><span class="line"></span><br><span class="line">Accept: */*</span><br><span class="line"></span><br><span class="line">MT-Network-Type: WIFI</span><br><span class="line"></span><br><span class="line">MT-Token: 1</span><br><span class="line"></span><br><span class="line">MT-Team-ID: 1</span><br><span class="line"></span><br><span class="line">MT-Info: 028e7f96f6369cafe1d105579c5b9377</span><br><span class="line"></span><br><span class="line">MT-Device-ID: 2F2075D0-B66C-4287-A903-DBFF6358342A</span><br><span class="line"></span><br><span class="line">MT-Bundle-ID: com.moutai.mall</span><br><span class="line"></span><br><span class="line">Accept-Language: en-CN;q=1, zh-Hans-CN;q=0.9</span><br><span class="line"></span><br><span class="line">MT-Request-ID: 167560018873318465</span><br><span class="line"></span><br><span class="line">MT-APP-Version: 1.3.7</span><br><span class="line"></span><br><span class="line">User-Agent: iOS;16.3;Apple;?unrecognized?</span><br><span class="line"></span><br><span class="line">MT-R: clips_OlU6TmFRag5rCXwbNAQ/Tz1SKlN8THcecBp/HGhHdw==</span><br><span class="line"></span><br><span class="line">Content-Length: 93</span><br><span class="line"></span><br><span class="line">Accept-Encoding: gzip, deflate, br</span><br><span class="line"></span><br><span class="line">Connection: keep-alive</span><br><span class="line"></span><br><span class="line">Content-Type: application/json</span><br><span class="line"></span><br><span class="line">userId: 2</span><br><span class="line"></span><br><span class="line">&quot;&quot;&quot;</span><br><span class="line"></span><br><span class="line"># 初始化请求头</span><br><span class="line"></span><br><span class="line">def init_headers(</span><br><span class="line"></span><br><span class="line">user_id: str = &quot;1&quot;, token: str = &quot;2&quot;, lat: str = &quot;29.83826&quot;, lng: str = &quot;119.74375&quot;</span><br><span class="line"></span><br><span class="line">):</span><br><span class="line"></span><br><span class="line">for k in header_context.strip().split(&quot;\n&quot;):</span><br><span class="line"></span><br><span class="line">temp_l = k.split(&quot;: &quot;)</span><br><span class="line"></span><br><span class="line">dict.update(headers, &#123;temp_l[0]: temp_l[1]&#125;)</span><br><span class="line"></span><br><span class="line">dict.update(headers, &#123;&quot;userId&quot;: user_id&#125;)</span><br><span class="line"></span><br><span class="line">dict.update(headers, &#123;&quot;MT-Token&quot;: token&#125;)</span><br><span class="line"></span><br><span class="line">dict.update(headers, &#123;&quot;MT-Lat&quot;: lat&#125;)</span><br><span class="line"></span><br><span class="line">dict.update(headers, &#123;&quot;MT-Lng&quot;: lng&#125;)</span><br><span class="line"></span><br><span class="line">dict.update(headers, &#123;&quot;MT-APP-Version&quot;: mt_version&#125;)</span><br><span class="line"></span><br><span class="line"># 用高德api获取地图信息</span><br><span class="line"></span><br><span class="line">def select_geo(i: str):</span><br><span class="line"></span><br><span class="line"># 校验高德api是否配置</span><br><span class="line"></span><br><span class="line">if AMAP_KEY is None:</span><br><span class="line"></span><br><span class="line">print(&quot;!!!!请配置 AMAP_KEY (高德地图的MapKey)&quot;)</span><br><span class="line"></span><br><span class="line">raise ValueError</span><br><span class="line"></span><br><span class="line">resp = requests.get(</span><br><span class="line"></span><br><span class="line">f&quot;https://restapi.amap.com/v3/geocode/geo?key=&#123;AMAP_KEY&#125;&amp;output=json&amp;address=&#123;i&#125;&quot;</span><br><span class="line"></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">geocodes: list = resp.json()[&quot;geocodes&quot;]</span><br><span class="line"></span><br><span class="line">return geocodes</span><br><span class="line"></span><br><span class="line">def signature(data: dict):</span><br><span class="line"></span><br><span class="line">keys = sorted(data.keys())</span><br><span class="line"></span><br><span class="line">temp_v = &quot;&quot;</span><br><span class="line"></span><br><span class="line">for item in keys:</span><br><span class="line"></span><br><span class="line">temp_v += data[item]</span><br><span class="line"></span><br><span class="line">text = SALT + temp_v + CURRENT_TIME</span><br><span class="line"></span><br><span class="line">hl = hashlib.md5()</span><br><span class="line"></span><br><span class="line">hl.update(text.encode(encoding=&quot;utf8&quot;))</span><br><span class="line"></span><br><span class="line">md5 = hl.hexdigest()</span><br><span class="line"></span><br><span class="line">return md5</span><br><span class="line"></span><br><span class="line"># 获取登录手机验证码</span><br><span class="line"></span><br><span class="line">def get_vcode(mobile: str):</span><br><span class="line"></span><br><span class="line">params = &#123;&quot;mobile&quot;: mobile&#125;</span><br><span class="line"></span><br><span class="line">md5 = signature(params)</span><br><span class="line"></span><br><span class="line">dict.update(</span><br><span class="line"></span><br><span class="line">params, &#123;&quot;md5&quot;: md5, &quot;timestamp&quot;: CURRENT_TIME, &quot;MT-APP-Version&quot;: mt_version&#125;</span><br><span class="line"></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">responses = requests.post(</span><br><span class="line"></span><br><span class="line">&quot;https://app.moutai519.com.cn/xhr/front/user/register/vcode&quot;,</span><br><span class="line"></span><br><span class="line">json=params,</span><br><span class="line"></span><br><span class="line">headers=headers,</span><br><span class="line"></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">if responses.status_code != 200:</span><br><span class="line"></span><br><span class="line">print(</span><br><span class="line"></span><br><span class="line">f&quot;get v_code : params : &#123;params&#125;, response code : &#123;responses.status_code&#125;, response body : &#123;responses.text&#125;&quot;</span><br><span class="line"></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"># 执行登录操作</span><br><span class="line"></span><br><span class="line">def login(mobile: str, v_code: str):</span><br><span class="line"></span><br><span class="line">params = &#123;&quot;mobile&quot;: mobile, &quot;vCode&quot;: v_code, &quot;ydToken&quot;: &quot;&quot;, &quot;ydLogId&quot;: &quot;&quot;&#125;</span><br><span class="line"></span><br><span class="line">md5 = signature(params)</span><br><span class="line"></span><br><span class="line">dict.update(</span><br><span class="line"></span><br><span class="line">params, &#123;&quot;md5&quot;: md5, &quot;timestamp&quot;: CURRENT_TIME, &quot;MT-APP-Version&quot;: mt_version&#125;</span><br><span class="line"></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">responses = requests.post(</span><br><span class="line"></span><br><span class="line">&quot;https://app.moutai519.com.cn/xhr/front/user/register/login&quot;,</span><br><span class="line"></span><br><span class="line">json=params,</span><br><span class="line"></span><br><span class="line">headers=headers,</span><br><span class="line"></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">if responses.status_code != 200:</span><br><span class="line"></span><br><span class="line">print(</span><br><span class="line"></span><br><span class="line">f&quot;login : params : &#123;params&#125;, response code : &#123;responses.status_code&#125;, response body : &#123;responses.text&#125;&quot;</span><br><span class="line"></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">dict.update(headers, &#123;&quot;MT-Token&quot;: responses.json()[&quot;data&quot;][&quot;token&quot;]&#125;)</span><br><span class="line"></span><br><span class="line">dict.update(headers, &#123;&quot;userId&quot;: responses.json()[&quot;data&quot;][&quot;userId&quot;]&#125;)</span><br><span class="line"></span><br><span class="line">return responses.json()[&quot;data&quot;][&quot;token&quot;], responses.json()[&quot;data&quot;][&quot;userId&quot;]</span><br><span class="line"></span><br><span class="line">def get_location():</span><br><span class="line"></span><br><span class="line">while 1:</span><br><span class="line"></span><br><span class="line">location = input(</span><br><span class="line"></span><br><span class="line">&quot;请输入精确小区位置,例如[小区名称],为你自动预约附近的门店:&quot;</span><br><span class="line"></span><br><span class="line">).strip()</span><br><span class="line"></span><br><span class="line">selects = select_geo(location)</span><br><span class="line"></span><br><span class="line">a = 0</span><br><span class="line"></span><br><span class="line">for item in selects:</span><br><span class="line"></span><br><span class="line">formatted_address = item[&quot;formatted_address&quot;]</span><br><span class="line"></span><br><span class="line">province = item[&quot;province&quot;]</span><br><span class="line"></span><br><span class="line">print(f&quot;&#123;a&#125; : [地区:&#123;province&#125;,位置:&#123;formatted_address&#125;]&quot;)</span><br><span class="line"></span><br><span class="line">a += 1</span><br><span class="line"></span><br><span class="line">user_select = input(&quot;请选择位置序号,重新输入请输入[-]:&quot;).strip()</span><br><span class="line"></span><br><span class="line">if user_select == &quot;-&quot;:</span><br><span class="line"></span><br><span class="line">continue</span><br><span class="line"></span><br><span class="line">select = selects[int(user_select)]</span><br><span class="line"></span><br><span class="line">formatted_address = select[&quot;formatted_address&quot;]</span><br><span class="line"></span><br><span class="line">province = select[&quot;province&quot;]</span><br><span class="line"></span><br><span class="line">print(f&quot;已选择 地区:&#123;province&#125;,[&#123;formatted_address&#125;]附近的门店&quot;)</span><br><span class="line"></span><br><span class="line">return select</span><br><span class="line"></span><br><span class="line">if __name__ == &quot;__main__&quot;:</span><br><span class="line"></span><br><span class="line">items = []</span><br><span class="line"></span><br><span class="line">while 1:</span><br><span class="line"></span><br><span class="line">init_headers()</span><br><span class="line"></span><br><span class="line">location_select: dict = get_location()</span><br><span class="line"></span><br><span class="line">province = location_select[&quot;province&quot;]</span><br><span class="line"></span><br><span class="line">city = location_select[&quot;city&quot;]</span><br><span class="line"></span><br><span class="line">location: str = location_select[&quot;location&quot;]</span><br><span class="line"></span><br><span class="line">mobile = input(&quot;输入手机号[18888888888]:&quot;).strip()</span><br><span class="line"></span><br><span class="line">get_vcode(mobile)</span><br><span class="line"></span><br><span class="line">code = input(f&quot;输入 [&#123;mobile&#125;] 验证码[8888]:&quot;).strip()</span><br><span class="line"></span><br><span class="line">token, userId = login(mobile, code)</span><br><span class="line"></span><br><span class="line">item = &#123;</span><br><span class="line"></span><br><span class="line">&quot;city&quot;: str(city),</span><br><span class="line"></span><br><span class="line">&quot;lat&quot;: location.split(&quot;,&quot;)[1],</span><br><span class="line"></span><br><span class="line">&quot;lng&quot;: location.split(&quot;,&quot;)[0],</span><br><span class="line"></span><br><span class="line">&quot;mobile&quot;: str(mobile),</span><br><span class="line"></span><br><span class="line">&quot;province&quot;: province,</span><br><span class="line"></span><br><span class="line">&quot;token&quot;: str(token),</span><br><span class="line"></span><br><span class="line">&quot;userid&quot;: str(userId),</span><br><span class="line"></span><br><span class="line">&quot;reserve_rule&quot;: 0,</span><br><span class="line"></span><br><span class="line">&quot;item_codes&quot;: [&quot;10941&quot;, &quot;10942&quot;],</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">items.append(item)</span><br><span class="line"></span><br><span class="line">condition = input(&quot;是否继续添加账号[y/n]:&quot;).strip()</span><br><span class="line"></span><br><span class="line">with open(&quot;account.json&quot;, &quot;w&quot;) as f:</span><br><span class="line"></span><br><span class="line">f.write(json.dumps(items, ensure_ascii=False, indent=4))</span><br><span class="line"></span><br><span class="line">if condition.lower() == &quot;n&quot;:</span><br><span class="line"></span><br><span class="line">break</span><br></pre></td></tr></table></figure></p>
<h2 id="scrcpy"><a class="anchor" href="#scrcpy">#</a> Scrcpy</h2>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 手机息屏启动</span></span><br><span class="line">scrcpy --turn-screen-off</span><br></pre></td></tr></table></figure></p>
<h2 id="服务器frp"><a class="anchor" href="#服务器frp">#</a> 服务器 FRP</h2>
<h5 id="path-homelifrpc"><a class="anchor" href="#path-homelifrpc">#</a> path: <code>/home/li/frpc</code></h5>
</content>
<category term="日常记录" scheme="https://fairyeye.github.io/tags/%E6%97%A5%E5%B8%B8%E8%AE%B0%E5%BD%95/" />
<updated>2023-10-25T03:31:59.000Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2023/10/12/Centos/</id>
<title>Centos</title>
<link rel="alternate" href="https://fairyeye.github.io/2023/10/12/Centos/"/>
<content type="html"><h3 id="1frpc内网穿透"><a class="anchor" href="#1frpc内网穿透">#</a> 1.frpc 内网穿透</h3>
<h3 id="2-青龙"><a class="anchor" href="#2-青龙">#</a> 2. 青龙</h3>
<h3 id="3xdd-plus"><a class="anchor" href="#3xdd-plus">#</a> 3.xdd-plus</h3>
<p><span class="exturl" data-url="aHR0cHM6Ly93d3cucXFtYXRlLmNuLzY1Mi5odG1s">https://www.qqmate.cn/652.html</span><br />
1. 进入 xdd 目录找到 device.json 文件<br />
2. 双击打开,修改: “protocol”:0, 改为 &quot;protocol&quot;:2,</p>
<h2 id="frpc"><a class="anchor" href="#frpc">#</a> FRPC</h2>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">1. 在`frpc.exe`所在的文件夹中,右键点击空白处,选择“新建” -&gt; “快捷方式”。</span><br><span class="line">2. 在创建快捷方式向导中,浏览并选择`frpc.exe`文件,然后点击“下一步”。</span><br><span class="line">3. 给快捷方式命名,然后点击“完成”。</span><br><span class="line">4. 找到刚刚创建的快捷方式,右键点击它,选择“属性”。</span><br><span class="line">5. 在“快捷方式”标签页下,找到“目标”字段。默认情况下,它应该只包含`&quot;C:\Path\To\frpc.exe&quot;`(假设`frpc.exe`在`C:\Path\To`目录下)。</span><br><span class="line">6. 在“目标”字段的末尾,添加一个空格,然后输入`-c frpc.toml`,确保整个命令看起来像这样:`&quot;C:\Path\To\frpc.exe&quot; -c frpc.toml`。</span><br><span class="line">7. 点击“应用”和“确定”保存更改。</span><br><span class="line">8. 将这个修改过的快捷方式拖放到“启动”文件夹中。这样,每次您登录Windows时,`frpc.exe`都会以`frpc.toml`作为配置文件运行。</span><br><span class="line"></span><br><span class="line">请注意,这种方法不会在后台静默运行`frpc.exe`,它会在用户登录时打开一个命令行窗口。如果您想要`frpc.exe`在后台运行而不显示命令行窗口,您应该考虑使用任务计划程序或将其安装为服务。</span><br></pre></td></tr></table></figure></p>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">1. **使用任务计划程序**:</span><br><span class="line"> </span><br><span class="line"> - 打开“任务计划程序”(可以在开始菜单中搜索“任务计划程序”来找到它)。</span><br><span class="line"> - 创建一个新的基本任务,设置触发器按照您的需要启动任务(例如,计算机启动时)。</span><br><span class="line"> - 在操作步骤中,选择“启动程序”,然后浏览并选择`frpc.exe`,并在“添加参数(可选)”中输入`-c frpc.toml`。</span><br><span class="line">2. **使用Windows服务**:</span><br><span class="line"> </span><br><span class="line"> - 使用第三方工具如[nssm](https://nssm.cc/)(Non-Sucking Service Manager)将`frpc.exe`安装为一个服务。</span><br><span class="line"> - 下载并解压`nssm.exe`。</span><br><span class="line"> - 打开命令提示符或PowerShell,导航到`nssm.exe`所在的文件夹。</span><br><span class="line"> - 运行命令`nssm install &lt;ServiceName&gt;`来创建新的服务,然后`nssm set &lt;ServiceName&gt; AppPath &lt;PathTofrpc.exe&gt;`设置应用路径,接着`nssm set &lt;ServiceName&gt; AppParameters -c frpc.toml`设置参数。</span><br><span class="line"> - 最后,启动服务使用`nssm start &lt;ServiceName&gt;`。</span><br><span class="line">3. **使用批处理文件**:</span><br><span class="line"> </span><br><span class="line"> - 创建一个批处理文件(`.bat`),在其中写入`frpc.exe -c frpc.toml`。</span><br><span class="line"> - 将批处理文件放置在`frpc.exe`相同的文件夹中。</span><br><span class="line"> - 您可以双击运行此批处理文件,或者将其添加到启动文件夹以在用户登录时自动运行。</span><br></pre></td></tr></table></figure></p>
<h2 id="端口"><a class="anchor" href="#端口">#</a> 端口</h2>
<h5 id="3001"><a class="anchor" href="#3001">#</a> 3001</h5>
<p><code>账号:li gz123456</code></p>
<h2 id=""><a class="anchor" href="#">#</a> </h2>
<p>开机启动 frpc 全部服务</p>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line">Description=Frp Multiple Client Services</span><br><span class="line">After=network.target</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">Type=simple</span><br><span class="line">ExecStart=/root/frpc/frpc/start_all_frpc.sh</span><br><span class="line">Restart=on-failure</span><br><span class="line">RestartSec=5s</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</span><br></pre></td></tr></table></figure></p>
<p>start_all_frpc.sh</p>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line">/root/frpc/frpc -c /root/frpc/frpc/frpc.toml &amp;</span><br><span class="line">/root/frpc/frpc -c /root/frpc/frpc/frpc-29252.toml &amp;</span><br><span class="line">/root/frpc/frpc -c /root/frpc/frpc/frpc-3001.toml &amp;</span><br><span class="line"></span><br><span class="line"><span class="built_in">wait</span></span><br></pre></td></tr></table></figure></p>
<h2 id="nginx"><a class="anchor" href="#nginx">#</a> Nginx</h2>
<h4 id="安装"><a class="anchor" href="#安装">#</a> 安装</h4>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">sudo yum install nginx</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如果报错:没有可用软件包 nginx</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">sudo vi /etc/yum.repos.d/nginx.repo</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">[nginx-stable]</span><br><span class="line">name=nginx stable repo</span><br><span class="line">baseurl=http://nginx.org/packages/centos/<span class="variable">$releasever</span>/<span class="variable">$basearch</span>/</span><br><span class="line">gpgcheck=1</span><br><span class="line">enabled=1</span><br><span class="line">gpgkey=https://nginx.org/keys/nginx_signing.key</span><br><span class="line">module_hotfixes=<span class="literal">true</span></span><br><span class="line"></span><br></pre></td></tr></table></figure></p>
<h4 id="使用"><a class="anchor" href="#使用">#</a> 使用</h4>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">curl localhost可以</span><br><span class="line">curl ip 不可以</span><br><span class="line"></span><br><span class="line">修改配置文件</span><br><span class="line"></span><br><span class="line">/etc/nginx/config.d/default.conf</span><br></pre></td></tr></table></figure></p>
<h2 id="github-page"><a class="anchor" href="#github-page">#</a> GitHub Page</h2>
<h4 id="nginx配置"><a class="anchor" href="#nginx配置">#</a> NGINX 配置</h4>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">listen 80;</span><br><span class="line">server_name 10.213.42.79;</span><br><span class="line"></span><br><span class="line">#access_log /var/log/nginx/host.access.log main;</span><br><span class="line"></span><br><span class="line">location / &#123;</span><br><span class="line"> root /usr/share/nginx/fairyeye.github.io;</span><br><span class="line"> index index.html index.htm;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>分之: <code>master</code> <br />
位置: <code>/usr/share/nginx/fairyeye.github.io</code></p>
<ul class="task-list">
<li>
<p>[/] 未实现部分</p>
</li>
<li class="task-list-item">
<p><input type="checkbox" id="cbx_0" disabled="true" /><label for="cbx_0"> 自动拉代码</label></p>
</li>
<li class="task-list-item">
<p><input type="checkbox" id="cbx_1" disabled="true" /><label for="cbx_1"> 本地每天部署一遍</label></p>
</li>
<li class="task-list-item">
<p><input type="checkbox" id="cbx_2" disabled="true" /><label for="cbx_2"> 更新图片地址</label></p>
</li>
</ul>
<h2 id="windows开机启动虚拟机"><a class="anchor" href="#windows开机启动虚拟机">#</a> Windows 开机启动虚拟机</h2>
<p>在虚拟机安装目录新建 <code>start_vm.bat</code> ,</p>
<p>ps:如果 vmx 文件包含中文,保存编码选择 GB 开头的格式</p>
<p><figure class="highlight bat"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">@<span class="built_in">echo</span> off</span><br><span class="line"></span><br><span class="line">.\vmrun.exe <span class="built_in">start</span> &quot;D:\Centos\CentOS <span class="number">7</span> <span class="number">64</span>位.vmx&quot;</span><br><span class="line"></span><br><span class="line"><span class="keyword">exit</span></span><br><span class="line"></span><br></pre></td></tr></table></figure></p>
</content>
<updated>2023-10-12T08:12:32.000Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2023/09/25/231104/</id>
<title>231104</title>
<link rel="alternate" href="https://fairyeye.github.io/2023/09/25/231104/"/>
<content type="html"><h3 id="pur-24166"><a class="anchor" href="#pur-24166">#</a> pur-24166</h3>
<p>返回消息:<br />
scux.spuc.lotus_nyo_no_enabled_master_enable_bank<br />
scux.spuc.lotus_nyo_no_erp_supplier<br />
埋点:<br />
SPUC_SUBMIT_PO</p>
<h3 id="pur-26089"><a class="anchor" href="#pur-26089">#</a> pur-26089</h3>
<p>组合业务对象:<br />
SRM_C_SRM_SODR_PO_HEADER<br />
个性化单元:<br />
SODR.ORDER_TRACKING_LIST.EXPORT</p>
<h3 id="pur-25937"><a class="anchor" href="#pur-25937">#</a> pur-25937</h3>
<p>平台供应商多语言待确定</p>
<p>页面个性化:<br />
SODR.WORKSPACE_DETAILALL.SEARCH</p>
<h3 id="pur-26467"><a class="anchor" href="#pur-26467">#</a> pur-26467</h3>
<p>独立脚本 + API 发布:<br />
SCUX_LDJT_QUERY_LAST_PURCHASE_PRICE</p>
<h3 id="pur-26322"><a class="anchor" href="#pur-26322">#</a> pur-26322</h3>
<p>独立脚本 + API:<br />
SCUX_WATSONS_UPDATE_ATTACHMENT_WFL<br />
适配器:<br />
SCUX_MTC_PO_HEADER_INFO<br />
SPUC_ORDER_QUERY_PROCESS_ACTION</p>
<h3 id="pur-26427"><a class="anchor" href="#pur-26427">#</a> pur-26427</h3>
<p>配置表:<br />
scux_srm_carlsberg_contract_amount_change_record<br />
适配器:<br />
SPUC_ORDER_SYNC_IMP_INSERT_PROCESS<br />
SPUC_BEFORE_ERP_CLOSE_OR_CANCEL_PO</p>
<p>更新时:判断取消状态和表里的取消状态</p>
<h3 id="pur-26689"><a class="anchor" href="#pur-26689">#</a> pur-26689</h3>
<p>独立脚本:<br />
SCUX_VN_SCM_PO_RETURN_OA<br />
适配器:<br />
重新同步:SPUC_RE_SYNC_ERP</p>
<p>值集:<br />
SPUC.SYNC_EXP_TYPE<br />
SPUC.SYNC_INTERFACE_TYPE</p>
<h3 id="pur-26080"><a class="anchor" href="#pur-26080">#</a> pur-26080</h3>
<p>适配器:<br />
SPUC_SUBMIT_PO<br />
SPUC_ORDER_APPROVED_EVENT</p>
<h3 id="pur-26150"><a class="anchor" href="#pur-26150">#</a> pur-26150</h3>
<pre><code>配置表:
scux_srm_sanning_fee_info
scux_srm_sanning_fee_calculate_type
API:
查询(返回配置表数据,且翻译税率、关联协议:SCUX_SANNING_FEE_INFO_QUERY /marmot-api/v49ECXUYP60iaTD6VDYCeIrqbnlzgazaL5HYWyv9ScGg
查询2 及币种精度、CNY币种ID、CNY、费用计算类型对应关系 SCUX_SANNING_FEE_OTHER_QUERY
保存 有ID是更新,没有ID是新增 SCUX_SANNING_FEE_INFO_SAVE_OR_UPDATE /marmot-api/v49ECXUYP60iaTD6VDYCeIpQpEumLeekdKWnTERvKJjibX4rd3PkiakwNOzdMU5JBn8
删除 根据ID删除,支持批量删除 SCUX_SANNING_FEE_INFO_DEL /marmot/v1/20990/marmot-api/v49ECXUYP60iaTD6VDYCeIiab6r6sOKdPfrdSqia2ePicuU
更新预付标识:SCUX_SANNING_FEE_INFO_UPDATE_PAY_FLAG
查询: 给结算用 SCUX_SANNING_FEE_INFO_QUERY_FOR_SETTLE
QB:SCUX_SANNING_FEE_INFO_QUERY_FOR_SETTLE
独立脚本:
SCUX_SANNING_FEE_INFO_QUERY
SCUX_SANNING_FEE_OTHER_QUERY
SCUX_SANNING_FEE_INFO_SAVE_OR_UPDATE
SCUX_SANNING_FEE_INFO_DEL
埋点:
保存、提交计算头个性化字段金额:SPUC_ORDER_PRICE_SOURCE_TYPE
整单取消:SPUC_ALL_CANCEL_PO_HEADER
按行取消:SPUC_LINE_CANCEL_PO_LINE
复制:
SPUC_ORDER_SAVE_DATA_CONVERSION_AFTER(写入数据
SPUC_ORDER_SAVE_DATA_CONVERSION_NEWPRICE_AFTER
SCUX_ORDER_PO_COPY_LINE(记录订单行ID
</code></pre>
<h3 id="pur-27164"><a class="anchor" href="#pur-27164">#</a> pur-27164</h3>
<pre><code> 适配器:
SPUC_ORDER_SYNC_IMP_INSERT_PROCESS
SPUC_ORDER_SYNC_IMP_UPDATE_PROCESS
配置表:
scux_srm_daqo_po_drawing_info
API+独立脚本
查询:SCUX_DAQO_PO_DRAWING_INFO_QUERY
导出:SCUX_DAQO_PO_DRAWING_INFO_EXPORT
下载:
</code></pre>
<h3 id="bug-pur-26901-spuc_order_batch_submit_handle"><a class="anchor" href="#bug-pur-26901-spuc_order_batch_submit_handle">#</a> BUG pur-26901 SPUC_ORDER_BATCH_SUBMIT_HANDLE</h3>
<p><img data-src="https://s3.bmp.ovh/imgs/2023/10/25/4c3f3f9377020435.png" alt="" /></p>
<p><span class="kbd">Ctrl</span> + <span class="kbd red">C</span></p>
</content>
<category term="work" scheme="https://fairyeye.github.io/tags/work/" />
<category term="迭代" scheme="https://fairyeye.github.io/tags/%E8%BF%AD%E4%BB%A3/" />
<updated>2023-09-25T01:36:59.000Z</updated>
</entry>
<entry>
<id>https://fairyeye.github.io/2023/06/17/GIT/</id>
<title>Git</title>
<link rel="alternate" href="https://fairyeye.github.io/2023/06/17/GIT/"/>
<content type="html"><h3 id="gitee-go"><a class="anchor" href="#gitee-go">#</a> Gitee Go</h3>
<h4 id="流水线"><a class="anchor" href="#流水线">#</a> 流水线</h4>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># 官方文档</span><br><span class="line">https://blog.gitee.com/2022/11/23/pipeline/</span><br></pre></td></tr></table></figure></p>
<h4 id="前端ci"><a class="anchor" href="#前端ci">#</a> 前端 CI</h4>
<p>手动创建流水线,选择部署分之,需要手动增加部署阶段</p>
<h5 id="添加部署阶段"><a class="anchor" href="#添加部署阶段">#</a> 添加部署阶段</h5>
<ol>
<li>
<p>点击发布后面的+ 添加新阶段</p>
</li>
<li>
<p>点击部署 点击主机部署</p>
</li>
</ol>
<p><img data-src="https://s3.bmp.ovh/imgs/2023/06/17/2e1e2d665f8fcd29.png" alt="" /></p>
<ol start="3">
<li>选择执行主机组(如果没有就先去添加主机,选择</li>
</ol>
<p><img data-src="https://s3.bmp.ovh/imgs/2023/06/17/d1715a1b2ec593f8.png" alt="" /></p>
<ol start="4">
<li>填写部署脚本,前端项目把上游构建的包,解压到服务器指定路径即可</li>
</ol>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 功能:部署脚本会在部署主机组的每台机器上执行</span></span><br><span class="line"><span class="comment"># 使用场景:先将制品包解压缩到指定目录中,再执行启动脚本deploy.sh,脚本示例地址:https://gitee.com/gitee-go/spring-boot-maven-deploy-case/blob/master/deploy.sh</span></span><br><span class="line"><span class="comment"># mkdir -p /home/admin/app</span></span><br><span class="line"><span class="comment"># tar zxvf ~/gitee_go/deploy/output.tar.gz -C /home/admin/app</span></span><br><span class="line"><span class="comment"># sh /home/admin/app/deploy.sh restart</span></span><br><span class="line"><span class="comment"># 如果你是php之类的无需制品包的制品方式,可以使用 git clone 或者 git pull 将源代码更新到服务器,再执行其他命令</span></span><br><span class="line"><span class="comment"># git clone ***@***.git</span></span><br><span class="line">tar zxvf ~/gitee_go/deploy/output.tar.gz -C /home/ubuntu </span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure></p>
<h4 id="添加主机"><a class="anchor" href="#添加主机">#</a> 添加主机</h4>
<ol>
<li>点击新建主机组</li>
</ol>
<p><img data-src="https://s3.bmp.ovh/imgs/2023/06/17/e0925018357ec4d5.png" alt="" /></p>
<ol start="2">
<li>选择新建类型(以腾讯云为例),填写基本信息(以 Linux 为例),点击确认</li>
</ol>
<p><img data-src="https://s3.bmp.ovh/imgs/2023/06/17/09807a134b458ca9.png" alt="" /></p>
<ol start="3">
<li>添加主机</li>
</ol>
<p>点击添加 Linux 主机,选择通过命令行逐台添加,</p>
<p>复制命令到目标腾讯云主机命令行</p>
<p>刷新页面即可见关联服务器信息</p>
<p><img data-src="https://s3.bmp.ovh/imgs/2023/06/17/ba5c1004444b1e6a.png" alt="" /></p>
<p><img data-src="https://s3.bmp.ovh/imgs/2023/06/17/b3943c35c7f70d3b.png" alt="" /></p>
<h4 id="后端ci"><a class="anchor" href="#后端ci">#</a> 后端 CI</h4>
<h5 id="部署脚本"><a class="anchor" href="#部署脚本">#</a> 部署脚本</h5>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~/gitee_go/deploy/</span><br><span class="line"><span class="built_in">ls</span></span><br><span class="line">tar -zxf API.tar.gz</span><br><span class="line"><span class="built_in">cd</span> target</span><br><span class="line">pid=`ps -ef|grep smart-admin-api-1.0.0|grep -v grep|awk <span class="string">&#x27;&#123;print $2&#125;&#x27;</span>`</span><br><span class="line"><span class="keyword">if</span> [ <span class="variable">$pid</span> ]</span><br><span class="line"><span class="keyword">then</span></span><br><span class="line">sudo <span class="built_in">kill</span> -15 <span class="variable">$pid</span> </span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line">sudo <span class="built_in">nohup</span> /usr/lib/jvm/jdk1.8.0_341/bin/java -jar smart-admin-api-1.0.0.jar &gt;/home/ubuntu/log.log &amp;</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure></p>
<p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~/gitee_go/deploy/</span><br><span class="line"><span class="built_in">ls</span></span><br><span class="line">tar -zxf API.tar.gz</span><br><span class="line"><span class="built_in">cd</span> target</span><br><span class="line">pid=`ps -ef|grep smart-admin-api-1.0.0|grep -v grep|awk <span class="string">&#x27;&#123;print $2&#125;&#x27;</span>`</span><br><span class="line"><span class="keyword">if</span> [ <span class="variable">$pid</span> ]</span><br><span class="line"><span class="keyword">then</span></span><br><span class="line">sudo <span class="built_in">kill</span> -15 <span class="variable">$pid</span> </span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line">sudo <span class="built_in">nohup</span> /usr/lib/jvm/jdk1.8.0_341/bin/java -jar smart-admin-api-1.0.0.jar</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&gt; /home/ubuntu/log.log 2&gt;&amp;1 &amp;</span><br><span class="line"></span><br></pre></td></tr></table></figure></p>
<h3 id="开源项目"><a class="anchor" href="#开源项目">#</a> 开源项目</h3>
<h4 id="免费的-api-学习平台apihub"><a class="anchor" href="#免费的-api-学习平台apihub">#</a> 免费的 API 学习平台:apihub</h4>
<p><img data-src="https://mmbiz.qpic.cn/mmbiz_png/xBgIbW1vdNMmicoKVicSqSt2t1qze8SqazYXhvBicx42j1w1VoJxibgWuibmQQxMRxyu7qn0eH0iczKLicS0Z0iaRkFEfg/640?wx_fmt=png&amp;from=appmsg&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" /></p>
<p><strong>主语言:JavaScript</strong>,<strong>Star:6.4k</strong>,<strong>周增长:1k</strong></p>
<p>这是一个功能齐全的 API 学习平台,支持多种编程语言(Node.js、Python、Go 等)的 API 开发和学习。它免费提供丰富的 API 集合,涉及社交媒体集成、支付网关、物联网设备连接和机器学习等领域。你可以在该平台获取 API 开发的各类资源,包括详细教程、接口文档、代码示例和在线尝试。除了使用在线服务外,强烈推荐用户选择本地部署,以避免官网服务每两小时重置数据的限制。</p>
<blockquote>
<p>GitHub <span class="exturl" data-url="aHR0cDovL3huLS1naXRodWItaG4yYzY1MDViZWVhLmNvbS9oaXRlc2hjaG91ZGhhcnkvYXBpaHVi">地址→github.com/hiteshchoudhary/apihub</span></p>
</blockquote>
<h4 id="轻松启动本地-https-代理的工具ophiuchi-desktop"><a class="anchor" href="#轻松启动本地-https-代理的工具ophiuchi-desktop">#</a> 轻松启动本地 HTTPS 代理的工具:ophiuchi-desktop</h4>
<p><img data-src="https://mmbiz.qpic.cn/mmbiz_png/xBgIbW1vdNMmicoKVicSqSt2t1qze8SqazefXibHqfAB99pX4ibia4L8kia5ic1tyuxO8hBYqHFVuNH30R50h583EoS1Q/640?wx_fmt=png&amp;from=appmsg&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" /></p>
<p><strong>主语言:TypeScript</strong>,<strong>Star:928</strong></p>
<p>这是一个本地 HTTPS 代理服务器管理工具,无需复杂配置即可轻松设置本地 HTTPS 代理。它使用 Docker 作为后端,并采用 Tauri 编写 GUI 界面,极大地简化了本地 HTTPS 代理的配置流程。不过,使用前需确保本机已安装 Docker。</p>
<blockquote>
<p>GitHub <span class="exturl" data-url="aHR0cDovL3huLS1naXRodWItaG4yYzY1MDViZWVhLmNvbS9hcGlseWxhYnMvb3BoaXVjaGktZGVza3RvcA==">地址→github.com/apilylabs/ophiuchi-desktop</span></p>
</blockquote>
<h4 id="一个鼠标操作多个电脑"><a class="anchor" href="#一个鼠标操作多个电脑">#</a> 一个鼠标操作多个电脑</h4>
<p>Deskflow 帮助用户<strong>在多台计算机(包括 Windows、macOS 和 Linux)之间共享键盘和鼠标</strong>,就像软件版的 KVM(但不包含视频功能)。</p>
<p><img data-src="https://mmbiz.qpic.cn/sz_mmbiz_png/ePw3ZeGRruxEzPa6F6qa1cut1bqhYJhHt83ekve7dmia3gKf5o4uBmB4SopibY3E3bhsHjBFbyh3HOP89dlLvBmA/640?wx_fmt=png&amp;from=appmsg&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" /></p>
<p>它支持 TLS 加密、Wayland 显示协议,<strong>并且具备剪贴板共享功能</strong>。作为社区驱动项目,Deskflow 鼓励用户参与开发和改进,同时与类似的开源项目合作,如 Synergy 和 Input Leap。用户可以通过安装包或源码编译来使用该软件。</p>
<blockquote>
<p>开源地址:<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2Rlc2tmbG93L2Rlc2tmbG93">https://github.com/deskflow/deskflow</span></p>
</blockquote>
<h4 id="beszel轻量级高颜值的-docker-监控平台"><a class="anchor" href="#beszel轻量级高颜值的-docker-监控平台">#</a> beszel:轻量级高颜值的 Docker 监控平台。</h4>
<p>这是一个轻量级的服务器监控平台,包括 Docker 统计、历史数据和警报功能。它拥有友好的 Web 界面,配置简单、开箱即用,支持自动备份、多用户、OAuth 认证和 API 访问等功能。</p>
<p><img data-src="https://mmbiz.qpic.cn/mmbiz_png/xBgIbW1vdNOh3AWZPLqMIsPX4YffnmwYV9dDjYm6WqUcYibM871CUYI68LMkXoulEEic338TkicJff30ibJQ7aL0kg/640?wx_fmt=png&amp;from=appmsg&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" /></p>
<blockquote>
<p>地址:<span class="exturl" data-url="aHR0cDovL2dpdGh1Yi5jb20vaGVucnlnZC9iZXN6ZWw=">github.com/henrygd/beszel</span></p>
</blockquote>
<h4 id="mame开源的街机模拟器"><a class="anchor" href="#mame开源的街机模拟器">#</a> mame:开源的街机模拟器。</h4>
<p>这是一款支持海量街机游戏的模拟器。它通过模拟多种硬件平台,实现了在电脑上运行各种复古软件的功能。不仅支持街机,还有老式电脑和游戏机。</p>
<p><img data-src="https://mmbiz.qpic.cn/mmbiz_png/xBgIbW1vdNOh3AWZPLqMIsPX4YffnmwYtkutJpJlCCvRfNLkleaadxwjQAkL97nicmVqVgIM4vYtcALQCfUk5FA/640?wx_fmt=png&amp;from=appmsg&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" /></p>
<blockquote>
<p>地址:<span class="exturl" data-url="aHR0cDovL2dpdGh1Yi5jb20vbWFtZWRldi9tYW1l">github.com/mamedev/mame</span></p>
</blockquote>
<h4 id="shadps4开源的-ps4-模拟器"><a class="anchor" href="#shadps4开源的-ps4-模拟器">#</a> shadPS4:开源的 PS4 模拟器。</h4>
<p>这是用 C++ 编写的 PlayStation 4(PS4)模拟器,支持在 Windows、Linux 和 macOS 系统上玩 PS4 游戏。虽然项目仍处于早期开发阶段,能运行的游戏有限,但最新版已经能够成功运行《血源诅咒》和《黑暗之魂 II》等游戏。</p>
<p><img data-src="https://mmbiz.qpic.cn/mmbiz_png/xBgIbW1vdNOTjhAHG3PgHxdZU0es1tDH182TnOW81kW8UAfmVEShP3jgU8sAxFnbh2yVowy3PEhfuqD9SNbkqw/640?wx_fmt=png&amp;from=appmsg&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" /></p>
<blockquote>
<p>地址:<span class="exturl" data-url="aHR0cDovL2dpdGh1Yi5jb20vc2hhZHBzNC1lbXUvc2hhZFBTNA==">github.com/shadps4-emu/shadPS4</span></p>
</blockquote>
<h4 id="索尼-ps1-模拟器开源项目"><a class="anchor" href="#索尼-ps1-模拟器开源项目">#</a> 索尼 PS1 模拟器 “开源” 项目</h4>
<p>Duckstation 是由 stenzek 开发的索尼 PS 模拟器,适用于 x86-64/AArch32/AArch64/RV64。</p>
<p>这开源项目<strong>专注于可玩性,速度,目标是尽可能让相对低端的设备也能玩 PS 游戏。默认设置即可运行所有支持的游戏,仅有部分兼容性问题。</strong></p>
<p><img data-src="https://mmbiz.qpic.cn/sz_mmbiz_png/ePw3ZeGRruw20geLdOwGhgyiaOuZa8ibWic1akIEo730UbTvrwbFk6ciaX2DOjYAF8WBgoibj50s7V1DyAwO8r27Zfw/640?wx_fmt=png&amp;from=appmsg&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" /></p>
<blockquote>
<p>“开源” 地址:<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3N0ZW56ZWsvZHVja3N0YXRpb24=">https://github.com/stenzek/duckstation</span></p>
</blockquote>
<h4 id="omakub精美的-ubuntu-配置方案"><a class="anchor" href="#omakub精美的-ubuntu-配置方案">#</a> omakub:精美的 Ubuntu 配置方案。</h4>
<p>该项目可以将全新的 Ubuntu 24.04 系统配置成美观、功能齐全、适合 Web 开发的系统。只需简单的一条命令,即可拥有配置好的 GNOME 桌面环境、窗口管理工具、Alacritty 终端、Neovim 和 VSCode 编辑器等应用,还会将 Chrome 设置成默认浏览器。</p>
<p><img data-src="https://mmbiz.qpic.cn/mmbiz_png/xBgIbW1vdNNHACLhrT0cZJ0t608OhI2GWqg5Bc66ZrtqTLuGkxpEYw2bs1ib2YcGFevbjsxMvWOCAribDibZXWniaw/640?wx_fmt=png&amp;from=appmsg&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片" /></p>
<blockquote>
<p>地址:<span class="exturl" data-url="aHR0cDovL2dpdGh1Yi5jb20vYmFzZWNhbXAvb21ha3Vi">github.com/basecamp/omakub</span></p>
</blockquote>
<h4 id="oshi"><a class="anchor" href="#oshi">#</a> <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL29zaGkvb3NoaQ==">Oshi</span></h4>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">获取操作系统和硬件信息的 Java 库。这是一个基于 JNA 实现的获取本机操作系统和硬件信息的库,支持操作系统版本、进程、内存、 CPU 使用率、磁盘和分区、设备、传感器等信息。</span><br></pre></td></tr></table></figure></p>
<h4 id="playedu"><a class="anchor" href="#playedu">#</a> <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL1BsYXlFZHUvUGxheUVkdQ==">PlayEdu</span></h4>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">一款 Java 写的内部培训系统。这是一款基于 SpringBoot+React 开发而成的视频培训系统,它界面清爽、交互流畅,支持上传资源、创建部门、添加学员、指派课程等功能,可用于企业和机构搭建内部培训平台。</span><br></pre></td></tr></table></figure></p>
<h4 id="holer"><a class="anchor" href="#holer">#</a> <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3dpc2RvbS1wcm9qZWN0cy9ob2xlcg==">Holer</span></h4>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">一个将局域网中的应用映射到公网访问的端口映射软件,支持转发基于 TCP 协议的报文。内网穿透工具,包含 Web 后台管理系统。用到的技术如下:</span><br><span class="line"></span><br><span class="line">- 服务端采用 SpringBoot 和 Netty 实现</span><br><span class="line">- 客户端采用 Java Netty 和 Go 语言实现</span><br></pre></td></tr></table></figure><br />
<img data-src="https://s3.bmp.ovh/imgs/2023/09/13/e1c366275bdb16f6.png" alt="" /></p>
<h4 id="solopo"><a class="anchor" href="#solopo">#</a> <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2FsaXBheS9Tb2xvUGk=">SoloPo</span></h4>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">一个不需要连接电脑、非侵入式的 Android 自动化工具。公测版拥有录制回放、性能测试、一机多控三项主要功能,能为测试开发人员节省宝贵时间。安卓版本多、终端型号多,一个成熟安卓应用的上线需要进行大量测试,而很多测试都是属于重复操作,通过此工具可以极大简化测试人员的工作量</span><br></pre></td></tr></table></figure><br />
<img data-src="https://s3.bmp.ovh/imgs/2023/09/13/f9f815c624347451.png" alt="" /></p>
<h4 id="hitomi"><a class="anchor" href="#hitomi">#</a> <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL0t1cnRCZXN0b3IvSGl0b21pLURvd25sb2FkZXI=">Hitomi</span></h4>
<p><strong>本周 star 增长数:400+</strong>,<strong>主语言:Python</strong></p>
<p>Hitomi-Downloader 知名下载工具,只需要一个 url 就能下载对应的图片、视频、音频。部分特性:</p>
<ul>
<li>
<p>简洁的用户界面</p>
</li>
<li>
<p>支持下载加速,也支持限速</p>
</li>
<li>
<p>支持单任务由 24 个线程</p>
</li>
<li>
<p>支持多种下载方式</p>
</li>
</ul>
<h4 id="python-搞定-uinicegui"><a class="anchor" href="#python-搞定-uinicegui">#</a> Python 搞定 UI:nicegui</h4>
<p><strong>本周 star 增长数:850+</strong>,<strong>主语言:Python、JavaScript</strong></p>
<p><code>New</code> 用 Python 搞定 Web UI,有了它,你可以用 Python 创建按钮、对话框、Markdown 文件、3D 场景。</p>
<blockquote>
<p>GitHub 地址→https://github.com/zauberzeug/nicegui</p>
</blockquote>
<p><img data-src="https://s3.bmp.ovh/imgs/2023/09/22/65aeeb9f2a95da35.png" alt="" /></p>
<h4 id="炫酷的-windows-终端软件fluentterminal"><a class="anchor" href="#炫酷的-windows-终端软件fluentterminal">#</a> 炫酷的 Windows 终端软件:FluentTerminal</h4>
<p><strong>主语言:C#</strong></p>
<p>基于 UWP 的 Windows 终端应用,拥有强大的自定义主题模块,能够轻松定制出风格各异的主题。提供了中文选项,支持多窗口、SSH 和搜索等功能。</p>
<blockquote>
<p>HG 评价地址→https://hellogithub.com/repository/352150f3034742cbbf67d301a86973ca</p>
</blockquote>
<h4 id="ai-生图controlnet"><a class="anchor" href="#ai-生图controlnet">#</a> AI 生图:ControlNet</h4>
<p><strong>主语言:Python</strong></p>
<p><code>New</code> 上周线稿上色的 style2paints 在 ControlNet 面前可能只是个弟弟。ControlNet 是一种通过添加额外条件来控制扩散模型的神经网络结构。为什么说 style2paints 是个弟弟呢?这是 ControlNet 的社生成效果图,从线稿到成品,一句话搞点。</p>
<blockquote>
<p>GitHub 地址→https://github.com/lllyasviel/ControlNet</p>
</blockquote>
<h4 id="1panel"><a class="anchor" href="#1panel">#</a> <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tLzFQYW5lbC1kZXYvMVBhbmVs">1Panel</span></h4>
<p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">[1Panel Log]: 1Panel 服务启动成功!</span><br><span class="line">[1Panel Log]:</span><br><span class="line">[1Panel Log]: =================感谢您的耐心等待,安装已经完成==================</span><br><span class="line">[1Panel Log]:</span><br><span class="line">[1Panel Log]: 请用浏览器访问面板:</span><br><span class="line">[1Panel Log]: 面板地址: http://$LOCAL_IP:29252/821d637d70</span><br><span class="line">[1Panel Log]: 用户名称: e0ae9ef986</span><br><span class="line">[1Panel Log]: 用户密码: zhang...1997</span><br><span class="line">[1Panel Log]:</span><br><span class="line">[1Panel Log]: 项目官网: https://1panel.cn</span><br><span class="line">[1Panel Log]: 项目文档: https://1panel.cn/docs</span><br><span class="line">[1Panel Log]: 代码仓库: https://github.com/1Panel-dev/1Panel</span><br><span class="line">[1Panel Log]:</span><br><span class="line">[1Panel Log]: 如果使用的是云服务器,请至安全组开放 29252 端口</span><br><span class="line">[1Panel Log]:</span><br><span class="line">[1Panel Log]: ================================================================</span><br></pre></td></tr></table></figure></p>
<h4 id="nezha"><a class="anchor" href="#nezha">#</a> <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL25haWJhL25lemhh">Nezha</span> 国产的轻量级服务器监控工具。</h4>
<p>这是一款名为 “哪吒” 的服务器监控面板,它安装简单、开箱即用,支持监控多个服务器的系统状态、SSL 证书状态、报警通知、流量监控、设置定时任务等功能,适用于 Linux、Windows、macOS、OpenWRT 等主流系统。</p>
<p><img data-src="https://s3.bmp.ovh/imgs/2023/10/12/87fe9705e1078ecc.png" alt="" /></p>
<h4 id="deskreen将任何屏幕变成你的扩展显示器"><a class="anchor" href="#deskreen将任何屏幕变成你的扩展显示器">#</a> Deskreen:将任何屏幕变成你的扩展显示器</h4>