-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
901 lines (645 loc) · 105 KB
/
index.html
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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Rootrl's blog</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<meta property="og:type" content="website">
<meta property="og:title" content="Rootrl's blog">
<meta property="og:url" content="https://rootrl.github.com/index.html">
<meta property="og:site_name" content="Rootrl's blog">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Rootrl's blog">
<link rel="stylesheet" href="/libs/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="/libs/open-sans/styles.css">
<link rel="stylesheet" href="/libs/source-code-pro/styles.css">
<link rel="stylesheet" href="/css/style.css">
<script src="/libs/jquery/2.1.3/jquery.min.js"></script>
<link rel="stylesheet" href="/libs/lightgallery/css/lightgallery.min.css">
<link rel="stylesheet" href="/libs/justified-gallery/justifiedGallery.min.css">
</head>
<body>
<div id="container">
<header id="header">
<div id="header-main" class="header-inner">
<div class="outer">
<a href="/" id="logo">
<i class="logo"></i>
<span class="site-title">Rootrl's blog</span>
</a>
<nav id="main-nav">
<a class="main-nav-link" href="/.">Home</a>
<a class="main-nav-link" href="/archives">Archives</a>
<a class="main-nav-link" href="/categories">Categories</a>
<a class="main-nav-link" href="/tags">Tags</a>
<a class="main-nav-link" href="/about">About</a>
</nav>
<nav id="sub-nav">
<div class="profile" id="profile-nav">
<a id="profile-anchor" href="javascript:;">
<img class="avatar" src="https://raw.githubusercontent.com/rootrl/rootrl.github.io/hexo/source/images/logo.jpg" />
<i class="fa fa-caret-down"></i>
</a>
</div>
</nav>
<div id="search-form-wrap">
<form class="search-form">
<input type="text" class="ins-search-input search-form-input" placeholder="Search" />
<button type="submit" class="search-form-submit"></button>
</form>
<div class="ins-search">
<div class="ins-search-mask"></div>
<div class="ins-search-container">
<div class="ins-input-wrapper">
<input type="text" class="ins-search-input" placeholder="Type something..." />
<span class="ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
</div>
<div class="ins-section-wrapper">
<div class="ins-section-container"></div>
</div>
</div>
</div>
<script>
(function (window) {
var INSIGHT_CONFIG = {
TRANSLATION: {
POSTS: 'Posts',
PAGES: 'Pages',
CATEGORIES: 'Categories',
TAGS: 'Tags',
UNTITLED: '(Untitled)',
},
ROOT_URL: '/',
CONTENT_URL: '/content.json',
};
window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
</script>
<script src="/js/insight.js"></script>
</div>
</div>
</div>
<div id="main-nav-mobile" class="header-sub header-inner">
<table class="menu outer">
<tr>
<td><a class="main-nav-link" href="/.">Home</a></td>
<td><a class="main-nav-link" href="/archives">Archives</a></td>
<td><a class="main-nav-link" href="/categories">Categories</a></td>
<td><a class="main-nav-link" href="/tags">Tags</a></td>
<td><a class="main-nav-link" href="/about">About</a></td>
<td>
<div class="search-form">
<input type="text" class="ins-search-input search-form-input" placeholder="Search" />
</div>
</td>
</tr>
</table>
</div>
</header>
<div class="outer">
<aside id="profile">
<div class="inner profile-inner">
<div class="base-info profile-block">
<img id="avatar" src="https://raw.githubusercontent.com/rootrl/rootrl.github.io/hexo/source/images/logo.jpg" />
<h2 id="name">Rootrl</h2>
<h3 id="title">Web Developer</h3>
<span id="location"><i class="fa fa-map-marker"></i>Hefei, China</span>
<a id="follow" target="_blank" href="https://github.com/rootrl/">FOLLOW</a>
</div>
<div class="article-info profile-block">
<div class="article-info-block">
27
<span>posts</span>
</div>
<div class="article-info-block">
36
<span>tags</span>
</div>
</div>
<div class="profile-block social-links">
<table>
<tr>
<td>
<a href="http://github.com/rootrl" target="_blank" title="github" class=tooltip>
<i class="fa fa-github"></i>
</a>
</td>
<td>
<a href="/" target="_blank" title="twitter" class=tooltip>
<i class="fa fa-twitter"></i>
</a>
</td>
<td>
<a href="/" target="_blank" title="facebook" class=tooltip>
<i class="fa fa-facebook"></i>
</a>
</td>
</tr>
</table>
</div>
</div>
</aside>
<section id="main">
<article id="post-Android-Bug记:-Canvas-trying-to-use-a-recycled-bitmap-android-graphics-Bitmap" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2020/01/02/Android-Bug记:-Canvas-trying-to-use-a-recycled-bitmap-android-graphics-Bitmap/">Android Bug记 'Canvas: trying to use a recycled bitmap android.graphics.Bitmap'</a>
</h1>
<div class="article-meta">
<div class="article-date">
<i class="fa fa-calendar"></i>
<a href="/2020/01/02/Android-Bug记:-Canvas-trying-to-use-a-recycled-bitmap-android-graphics-Bitmap/">
<time datetime="2020-01-02T14:18:56.000Z" itemprop="datePublished">2020-01-02</time>
</a>
</div>
<div class="article-category">
<i class="fa fa-folder"></i>
<a class="article-category-link" href="/categories/开发语言/">开发语言</a><i class="fa fa-angle-right"></i><a class="article-category-link" href="/categories/开发语言/Android/">Android</a>
</div>
<div class="article-tag">
<i class="fa fa-tag"></i>
<a class="tag-link" href="/tags/Android/">Android</a>
</div>
</div>
</header>
<div class="article-entry" itemprop="articleBody">
<h3 id="Bug日志"><a href="#Bug日志" class="headerlink" title="Bug日志"></a>Bug日志</h3><p>最近一个项目中遇到一个诡异Bug,详细日志如下:</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><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">E/MainActivity: executeTextView: <span class="built_in">test</span> <span class="keyword">for</span> get drawable: last <span class="built_in">source</span>: android.graphics.drawable.BitmapDrawable@8c352b2</span><br><span class="line"> executeTextView: <span class="built_in">test</span> <span class="keyword">for</span> get drawable: isVisible <span class="literal">true</span> alpha: 255 last <span class="built_in">source</span>: android.graphics.drawable.BitmapDrawable@8c352b2</span><br><span class="line">W/Bitmap: Called hasAlpha() on a recycle()<span class="string">'d bitmap! This is undefined behavior!</span></span><br><span class="line"><span class="string"> Called hasAlpha() on a recycle()'</span>d bitmap! This is undefined behavior!</span><br><span class="line"> Called hasAlpha() on a recycle()<span class="string">'d bitmap! This is undefined behavior!</span></span><br><span class="line"><span class="string">W/Bitmap: Called hasAlpha() on a recycle()'</span>d bitmap! This is undefined behavior!</span><br><span class="line">E/MainActivity: Glide结束</span><br><span class="line"> executeImageView: ...</span><br><span class="line">E/MainActivity: showQrCode: 举报二维码1:</span><br><span class="line"> showQrCode: 举报二维码2: https://xxx.com/upload/equipmentWxQRCode/15776698271ada7952f9ead4d5.jpg</span><br><span class="line">D/AndroidRuntime: Shutting down VM</span><br><span class="line">E/AndroidRuntime: FATAL EXCEPTION: main</span><br><span class="line"> Process: com.rootrl.adviewer, PID: 29128</span><br><span class="line"> java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@ac257b9</span><br><span class="line"> at android.graphics.Canvas.throwIfCannotDraw(Canvas.java:1271)</span><br><span class="line"> at android.view.DisplayListCanvas.throwIfCannotDraw(DisplayListCanvas.java:257)</span><br><span class="line"> at android.graphics.Canvas.drawBitmap(Canvas.java:1415)</span><br><span class="line"> at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:528)</span><br><span class="line"> at android.widget.ImageView.onDraw(ImageView.java:1298)</span><br><span class="line"> at android.view.View.draw(View.java:17201)</span><br><span class="line"> at android.view.View.updateDisplayListIfDirty(View.java:16183)</span><br><span class="line"> at android.view.View.draw(View.java:16967)</span><br><span class="line"> at android.view.ViewGroup.drawChild(ViewGroup.java:3727)</span><br><span class="line"> at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)</span><br><span class="line"> at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:2023)</span><br><span class="line"> at android.view.View.updateDisplayListIfDirty(View.java:16178)</span><br><span class="line"> at android.view.View.draw(View.java:16967)</span><br><span class="line"> at android.view.ViewGroup.drawChild(ViewGroup.java:3727)</span><br><span class="line"> at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)</span><br><span class="line"> at androidx.constraintlayout.widget.ConstraintLayout.dispatchDraw(ConstraintLayout.java:2023)</span><br><span class="line"> at android.view.View.draw(View.java:17204)</span><br><span class="line"> at android.view.View.updateDisplayListIfDirty(View.java:16183)</span><br><span class="line"> at android.view.View.draw(View.java:16967)</span><br><span class="line"> at android.view.ViewGroup.drawChild(ViewGroup.java:3727)</span><br><span class="line"> at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)</span><br><span class="line"> at android.view.View.updateDisplayListIfDirty(View.java:16178)</span><br><span class="line"> at android.view.View.draw(View.java:16967)</span><br><span class="line"> at android.view.ViewGroup.drawChild(ViewGroup.java:3727)</span><br><span class="line"> at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)</span><br><span class="line"> at android.view.View.updateDisplayListIfDirty(View.java:16178)</span><br><span class="line"> at android.view.View.draw(View.java:16967)</span><br><span class="line"> at android.view.ViewGroup.drawChild(ViewGroup.java:3727)</span><br><span class="line"> at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)</span><br><span class="line"> at android.view.View.updateDisplayListIfDirty(View.java:16178)</span><br><span class="line"> at android.view.View.draw(View.java:16967)</span><br><span class="line"> at android.view.ViewGroup.drawChild(ViewGroup.java:3727)</span><br><span class="line"> at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)</span><br><span class="line"> at android.view.View.updateDisplayListIfDirty(View.java:16178)</span><br><span class="line"> at android.view.View.draw(View.java:16967)</span><br><span class="line"> at android.view.ViewGroup.drawChild(ViewGroup.java:3727)</span><br><span class="line"> at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3513)</span><br><span class="line"> at android.view.View.draw(View.java:17204)</span><br><span class="line"> at com.android.internal.policy.DecorView.draw(DecorView.java:754)</span><br><span class="line"> at android.view.View.updateDisplayListIfDirty(View.java:16183)</span><br><span class="line"> at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:648)</span><br><span class="line"> at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:654)</span><br><span class="line"> at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:762)</span><br><span class="line"> at android.view.ViewRootImpl.draw(ViewRootImpl.java:2800)</span><br><span class="line"> at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2608)</span><br><span class="line"> at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2215)</span><br><span class="line"> at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1254)</span><br><span class="line"> at android.view.ViewRootImpl<span class="variable">$TraversalRunnable</span>.run(ViewRootImpl.java:6338)</span><br><span class="line"> at android.view.Choreographer<span class="variable">$CallbackRecord</span>.run(Choreographer.java:874)</span><br><span class="line"> at android.view.Choreographer.doCallbacks(Choreographer.java:686)</span><br><span class="line"> at android.view.Choreographer.doFrame(Choreographer.java:621)</span><br><span class="line"> at android.view.Choreographer<span class="variable">$FrameDisplayEventReceiver</span>.run(Choreographer.java:860)</span><br><span class="line"> at android.os.Handler.handleCallback(Handler.java:755)</span><br><span class="line"> at android.os.Handler.dispatchMessage(Handler.java:95)</span><br><span class="line"> at android.os.Looper.loop(Looper.java:154)</span><br><span class="line"> at android.app.ActivityThread.main(ActivityThread.java:6121)</span><br><span class="line"> at java.lang.reflect.Method.invoke(Native Method)</span><br><span class="line"> at com.android.internal.os.ZygoteInit<span class="variable">$MethodAndArgsCaller</span>.run(ZygoteInit.java:905)</span><br><span class="line"> at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:795)</span><br><span class="line">I/Process: Sending signal. PID: 29128 SIG: 9</span><br><span class="line">Process 29128 terminated.</span><br></pre></td></tr></table></figure>
<h3 id="Bug初步分析"><a href="#Bug初步分析" class="headerlink" title="Bug初步分析"></a>Bug初步分析</h3><p>其实字面上看上去很简单。但是诡异在发生场景:</p>
<ul>
<li><p>只在安卓横屏模式下发生,竖屏模式下正常。</p>
</li>
<li><p>有一张特定图片才会出现问题,其他图片均不会。而这个图片无论分辨率大小还是文件大小均不大,其他比它大十几倍的都正常运行。</p>
</li>
</ul>
<p>报错原因从日志上看到很简单:使用了一个已经被回收的bitmap资源(我这里使用的是Glide图片处理库)。但是结合我的使用场景和发生场景(只在横屏下),再加上Glide对于我来说是一个黑箱。 种种原因结合看来是一个难调的bug。</p>
<p>后来发现发生的地方是imageView的Placeholder设置阶段。代码如下:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (currentView == AdConstant.VIEW_TYPE_TEXT_VIEW) {</span><br><span class="line"> <span class="keyword">if</span> (adImageView.getDrawable() != <span class="keyword">null</span>) {</span><br><span class="line"> requestOptions.placeholder(adImageView.getDrawable());</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>设置这个Placeholder是为了解决图片切换时的闪黑屏问题,一是去掉Glide的Animate,二是设置这个Placeholder,把当前Image View的Drawable作为默认图片。而由于我的业务逻辑复杂,有图片和视频的轮播,有可能在设置时找不到这个Drawable的Bitmap资源,好吧,说有可能是因为我也不能给个具体的原因-_-‘’,因为结合我上面提到的两个特定发生场景,实在是太诡异了。</p>
<h3 id="Bug深入分析"><a href="#Bug深入分析" class="headerlink" title="Bug深入分析"></a>Bug深入分析</h3><p>后来我看到github上官方bumptech/glide也有一大堆issues,有人说是glide版本问题,但是我更新到最新的4.10.0依旧无解。</p>
<p>最后看到官方的Common errors文档,<a href="http://bumptech.github.io/glide/doc/resourcereuse.html#common-errors" target="_blank" rel="external">http://bumptech.github.io/glide/doc/resourcereuse.html#common-errors</a></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></pre></td><td class="code"><pre><span class="line">Glide’s BitmapPool has a fixed size. When Bitmaps are evicted from the pool without being re-used, <span class="function">Glide will call <span class="title">recycle</span><span class="params">()</span>. If an application inadvertently continues to hold on to the Bitmap even after indicating to Glide that it is safe to recycle it, the application may then attempt to draw the Bitmap, resulting in a crash in <span class="title">onDraw</span><span class="params">()</span>.</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">This problem could be due to the fact that one target is being used <span class="keyword">for</span> two ImageViews, and one of the ImageViews still tries to access the recycled Bitmap after it has been put into the BitmapPool. This recycling error can be hard to reproduce, due to several factors: 1) when the bitmap is put into the pool, 2) when the bitmap is recycled, and 3) what the size of the BitmapPool and memory cache are that leads to the recycling of the Bitmap. The following snippet can be put into your GlideModule to help making <span class="keyword">this</span> problem easier to reproduce:</span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">applyOptions</span><span class="params">(Context context, GlideBuilder builder)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> bitmapPoolSizeBytes = <span class="number">1024</span> * <span class="number">1024</span> * <span class="number">0</span>; <span class="comment">// 0mb</span></span><br><span class="line"> <span class="keyword">int</span> memoryCacheSizeBytes = <span class="number">1024</span> * <span class="number">1024</span> * <span class="number">0</span>; <span class="comment">// 0mb</span></span><br><span class="line"> builder.setMemoryCache(<span class="keyword">new</span> LruResourceCache(memoryCacheSizeBytes));</span><br><span class="line"> builder.setBitmapPool(<span class="keyword">new</span> LruBitmapPool(bitmapPoolSizeBytes));</span><br><span class="line">}</span><br><span class="line">The above code makes sure that there is no memory caching and the size of the BitmapPool is zero; so Bitmap, <span class="keyword">if</span> happened to be not used, will be recycled right away. The problem will surface much quicker <span class="keyword">for</span> debugging purposes.</span><br></pre></td></tr></table></figure>
<p>第一段说明了真正原因,Bitmap在BitmapPool中被剔除而没有被重用时,Glide会调用recycle(),但是如果Application在被告知安全回收了Bitmap之后还是保留这个Bitmap,继而绘制Bitmap时,在onDraw中就会崩溃。</p>
<p>我这个Placeholder就发生在这种情况下。</p>
<h3 id="Bug解决"><a href="#Bug解决" class="headerlink" title="Bug解决"></a>Bug解决</h3><p>我这边解决思路是重新设置BitmapPool的大小,这需要重写AppGlideModule,代码如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><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">package com.rootrl.adviewer.glide;</span><br><span class="line"></span><br><span class="line">import android.content.Context;</span><br><span class="line"></span><br><span class="line">import com.bumptech.glide.GlideBuilder;</span><br><span class="line">import com.bumptech.glide.annotation.GlideModule;</span><br><span class="line">import com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool;</span><br><span class="line">import com.bumptech.glide.load.engine.cache.LruResourceCache;</span><br><span class="line">import com.bumptech.glide.module.AppGlideModule;</span><br><span class="line"></span><br><span class="line">@GlideModule</span><br><span class="line">public class AdImageGlideModule extends AppGlideModule {</span><br><span class="line"> @Override</span><br><span class="line"> public void applyOptions(Context context, GlideBuilder builder) {</span><br><span class="line"> int bitmapPoolSizeBytes = 1024 * 1024 * 200; // 200mb</span><br><span class="line"> int memoryCacheSizeBytes = 1024 * 1024 * 200; // 200mb</span><br><span class="line"> builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));</span><br><span class="line"> builder.setBitmapPool(new LruBitmapPool(bitmapPoolSizeBytes));</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这里有几点要注意,不然项目中没有GlideApp对象。</p>
<ul>
<li>类中添加@GlideModule注解</li>
<li>如同package com.rootrl.adviewer.glide,这个Module放在项目路径的glide package目录(需新建)</li>
<li>改下build.grdle配置</li>
</ul>
<p>其中第三条具体如下,注意除了glide依赖,还需annotationProcessor项:<br><figure class="highlight bash"><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">implementation <span class="string">'com.github.bumptech.glide:glide:4.10.0'</span></span><br><span class="line">annotationProcessor <span class="string">'com.github.bumptech.glide:compiler:4.10.0'</span></span><br></pre></td></tr></table></figure></p>
<p>然后,点AS的Build => Make Project,之后就可以在项目中使用集成自己GlideModule的GlideAPP了。</p>
<p>使用方式也是用GlideAPP替换原来的Glide就可以。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">// 替换前</span><br><span class="line">Glide.with(MainActivity.this).listener(...).load(uri).apply(requestOptions).into(adImageView);</span><br><span class="line"></span><br><span class="line">// 替换后</span><br><span class="line">GlideApp.with(MainActivity.this).listener(...).load(uri).apply(requestOptions).into(adImageView);</span><br></pre></td></tr></table></figure>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>其实这里还没有具体深入,因为安卓对我来说还是一个实用为主阶段。最后强调是图片处理库非常推荐Glide,它的缓存机制很实用。然后视频的缓存推荐danikula:videocache库。</p>
</div>
<footer class="article-footer">
<div class="share-container">
</div>
<a data-url="https://rootrl.github.com/2020/01/02/Android-Bug记:-Canvas-trying-to-use-a-recycled-bitmap-android-graphics-Bitmap/" data-id="ck4wtrux10000a1pnxtaoiguk" class="article-share-link"><i class="fa fa-share"></i>Share</a>
<script>
(function ($) {
// Prevent duplicate binding
if (typeof(__SHARE_BUTTON_BINDED__) === 'undefined' || !__SHARE_BUTTON_BINDED__) {
__SHARE_BUTTON_BINDED__ = true;
} else {
return;
}
$('body').on('click', function() {
$('.article-share-box.on').removeClass('on');
}).on('click', '.article-share-link', function(e) {
e.stopPropagation();
var $this = $(this),
url = $this.attr('data-url'),
encodedUrl = encodeURIComponent(url),
id = 'article-share-box-' + $this.attr('data-id'),
offset = $this.offset(),
box;
if ($('#' + id).length) {
box = $('#' + id);
if (box.hasClass('on')){
box.removeClass('on');
return;
}
} else {
var html = [
'<div id="' + id + '" class="article-share-box">',
'<input class="article-share-input" value="' + url + '">',
'<div class="article-share-links">',
'<a href="https://twitter.com/intent/tweet?url=' + encodedUrl + '" class="fa fa-twitter article-share-twitter" target="_blank" title="Twitter"></a>',
'<a href="https://www.facebook.com/sharer.php?u=' + encodedUrl + '" class="fa fa-facebook article-share-facebook" target="_blank" title="Facebook"></a>',
'<a href="http://pinterest.com/pin/create/button/?url=' + encodedUrl + '" class="fa fa-pinterest article-share-pinterest" target="_blank" title="Pinterest"></a>',
'<a href="https://plus.google.com/share?url=' + encodedUrl + '" class="fa fa-google article-share-google" target="_blank" title="Google+"></a>',
'</div>',
'</div>'
].join('');
box = $(html);
$('body').append(box);
}
$('.article-share-box.on').hide();
box.css({
top: offset.top + 25,
left: offset.left
}).addClass('on');
}).on('click', '.article-share-box', function (e) {
e.stopPropagation();
}).on('click', '.article-share-box-input', function () {
$(this).select();
}).on('click', '.article-share-box-link', function (e) {
e.preventDefault();
e.stopPropagation();
window.open(this.href, 'article-share-box-window-' + Date.now(), 'width=500,height=450');
});
})(jQuery);
</script>
<a href="https://rootrl.github.com/2020/01/02/Android-Bug记:-Canvas-trying-to-use-a-recycled-bitmap-android-graphics-Bitmap/#comments" class="article-comment-link disqus-comment-count" data-disqus-url="https://rootrl.github.com/2020/01/02/Android-Bug记:-Canvas-trying-to-use-a-recycled-bitmap-android-graphics-Bitmap/">Comments</a>
</footer>
</div>
</article>
<article id="post-FastDFS-Docker化部署-以及-Java-SpringMVC实践" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/05/22/FastDFS-Docker化部署-以及-Java-SpringMVC实践/">FastDFS Docker化部署 以及 Java SpringMVC实践</a>
</h1>
<div class="article-meta">
<div class="article-date">
<i class="fa fa-calendar"></i>
<a href="/2019/05/22/FastDFS-Docker化部署-以及-Java-SpringMVC实践/">
<time datetime="2019-05-22T13:23:39.000Z" itemprop="datePublished">2019-05-22</time>
</a>
</div>
<div class="article-category">
<i class="fa fa-folder"></i>
<a class="article-category-link" href="/categories/开发语言/">开发语言</a><i class="fa fa-angle-right"></i><a class="article-category-link" href="/categories/开发语言/Java/">Java</a>
</div>
<div class="article-tag">
<i class="fa fa-tag"></i>
<a class="tag-link" href="/tags/Docker/">Docker</a>, <a class="tag-link" href="/tags/FastDFS/">FastDFS</a>, <a class="tag-link" href="/tags/Java/">Java</a>
</div>
</div>
</header>
<div class="article-entry" itemprop="articleBody">
<p>FastDFS Docker化部署 以及 Java SpringMVC实践</p>
<h3 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h3><p>FastDFS是一个轻量级分布式文件系统。可以对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,而且可以集群部署,有高可用保障。相应的竞品有Ceph、TFS等。相比而言FastDFS对硬件的要求比较低,所以适合中小型公司。</p>
<h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><p>FastDFS服务端由两个重要部分组成:跟踪器(Tracker)和存储节点(Storage)。</p>
<p>Tracker主要做调度工作,在访问上起负载均衡的作用。Tracker可以做集群部署,各个节点之间是平等的,客户端请求时采用轮询机制,某个Tracker不能提供服务时就换另一个。Storage启动后会连接到Tracker Server告知自己的Group信息,形成映射关联,并采用心跳机制保持状态。<br>Storage存储节点负责文件的存储,Storage可以集群部署。</p>
<p>Storage集群有以下特点:</p>
<ul>
<li>以组(Group)为单位(也有称呼为卷 Volume的),集群的总容量为所有组的集合。</li>
<li>一个卷(组)内storage server之间相互通信,文件进行同步,保证卷内storage完全一致,所以一个卷的容量以最小的服务器为准。不同的卷之间相互不通信。</li>
<li>当某个卷的压力较大时可以添加storage server(纵向扩展),如果系统容量不够可以添加卷(横向扩展)。</li>
</ul>
<h3 id="上传流程"><a href="#上传流程" class="headerlink" title="上传流程"></a>上传流程</h3><p>此章节根据资料整理,可能随着版本有所改变,这里只介绍大致的,以便了解整个运作流程。如果需要深入研究,建议还是以官方文档为标准。</p>
<p>一,客户端请求会打到负载均衡层,到tracker server时,由于每个server之间是对等的关系,所以可以任意选择一个tracker server。</p>
<p>二,到storage层:tracker server接收到upload file请求时,会为该请求分配一个可以存储该文件的group。</p>
<p>分配group规则:</p>
<ul>
<li>Round robin 轮询</li>
<li>Specified group 指定一个group</li>
<li>Load balance 剩余存储空间多的group优先</li>
</ul>
<p>三,确定group后,tracker会在group内选择一个storage server给客户端。</p>
<p> 在group内选择storage server时规则:</p>
<ul>
<li>Round robin 轮询</li>
<li>First server ordered by ip 按ip排序</li>
<li>First server ordered by priority,按优先级排序(优先级在storage上配置)</li>
</ul>
<p>四,选择storage path:当分配好storage server后,客户端向storage发送写文件请求,storage将会为文件分配一个数据存储目录,支持规则如下:</p>
<ul>
<li>round robin 轮询</li>
<li>剩余存储空间最多的优先</li>
</ul>
<p>五,生成File id:选定存储目录之后,storage会为文件生成一个File id。规则如下:<br> 由storage server ip、文件创建时间、文件大小,文件crc32和一个随机数拼接而成,然后将这个二进制串进程base64编码,转换为可打印的字符串。</p>
<p>六,选择两级目录:每个存储目录下有两级256 * 256的子目录,storage会按文件Field进行两次hash,路由到其中的一个目录,然后将文件以file id为文件名存储到该子目录下。</p>
<p>一个文件路径最终由如下组成:组名/磁盘/目录/文件名</p>
<p>七,客户端upload file成功后,会拿到一个storage生成的文件名,接下来客户端根据这个文件名即可访问到该文件。</p>
<h3 id="下载流程"><a href="#下载流程" class="headerlink" title="下载流程"></a>下载流程</h3><p>下载流程如下:</p>
<p>一,选择tracker server:和upload file一样,在download file时随机选择tracker server。</p>
<p>二,选择group:tracker发送download请求给某个tracker,必须带上文件名信息,tracker从文件名中解析出group、大小、创建时间等信息,根据group信息获取对于的group。</p>
<p>三,选择storage server:从group中选择一个storage用来服务读请求。由于group内的文件同步时在后台异步进行的,所以有可能出现在读到的时候,文件还没有同步到某些storage server上,为了尽量避免反问道这样的storage,tracker按照一定的规则选择group内可读的storage。</p>
<h3 id="文件HTTP预览服务"><a href="#文件HTTP预览服务" class="headerlink" title="文件HTTP预览服务"></a>文件HTTP预览服务</h3><p>Storage还可以结合nginx的fastdfs-nginx-module提供http服务,以实现图片等预览功能。</p>
<p>这个部分这里不做介绍,后续可能单独写篇文章,因为我发现对fastDFS集群提供http服务还是挺复杂,包括我下面找的docker镜像都不完善,主要是规划的问题,包括衍生的服务,缓存,以及对图片的处理(nginx+lua)这些,后续打算研究下,重新开源个docker构建镜像。</p>
<h3 id="实战"><a href="#实战" class="headerlink" title="实战"></a>实战</h3><h4 id="安装、部署规划"><a href="#安装、部署规划" class="headerlink" title="安装、部署规划"></a>安装、部署规划</h4><p>FastDFS安装方法网上有很多教程,这里不多讲,我建议使用docker来运行FastDFS,可以自己根据安装步骤构建自己的镜像。然后在需要的机器直接运行,后续扩容也方便,再启动一个storage容器就可以了。</p>
<p>详细版安装推荐篇文章:<a href="https://segmentfault.com/a/1190000008674582" target="_blank" rel="external">https://segmentfault.com/a/1190000008674582</a></p>
<h4 id="Docker集群搭建"><a href="#Docker集群搭建" class="headerlink" title="Docker集群搭建"></a>Docker集群搭建</h4><p>我这里从github上找的一个别人构建好的镜像,可以直接使用。地址:<a href="https://github.com/luhuiguo/fastdfs-docker" target="_blank" rel="external">https://github.com/luhuiguo/fastdfs-docker</a></p>
<p>使用方法也很简单</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><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment"># 启动一个tracker服务器</span></span><br><span class="line">docker run -dti --network=host --name tracker -v /var/fdfs/tracker:/var/fdfs luhuiguo/fastdfs tracker</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动storage0</span></span><br><span class="line">docker run -dti --network=host --name storage0 -e TRACKER_SERVER=10.1.5.85:22122 -v /var/fdfs/storage0:/var/fdfs luhuiguo/fastdfs storage</span><br><span class="line"></span><br><span class="line"><span class="comment"># 再启动一个storage1</span></span><br><span class="line">docker run -dti --network=host --name storage1 -e TRACKER_SERVER=10.1.5.85:22122 -v /var/fdfs/storage1:/var/fdfs luhuiguo/fastdfs storage</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动一个新组的storage</span></span><br><span class="line">docker run -dti --network=host --name storage2 -e TRACKER_SERVER=10.1.5.85:22122 -e GROUP_NAME=group2 -e PORT=22222 -v /var/fdfs/storage2:/var/fdfs luhuiguo/fastdfs storage</span><br></pre></td></tr></table></figure>
<h4 id="部署注意点"><a href="#部署注意点" class="headerlink" title="部署注意点"></a>部署注意点</h4><p>1,原github地址上的usage介绍,启动storage0和storage1有一个参数错误(多一个-e),以我上面发的命令为准。<br>2,这里的TRACKER_SERVER注意改为你自己的,同一个网段内网ip。</p>
<p>3,实际上这里docker容器之间还是同一个物理主机上部署的(根据network而言),虽然后续可以通过加硬盘,然后新建storage绑定到新加硬盘mount上,但是如果是大公司的生产环境还是推荐建立一个overlay网络,具体见:<a href="https://www.cnblogs.com/bigberg/p/8521542.html,这样可以直接扩物理机集群了。另外这里也提供docker-compose方式启动服务,实际也不推荐使用,因为tracker和storage" target="_blank" rel="external">https://www.cnblogs.com/bigberg/p/8521542.html,这样可以直接扩物理机集群了。另外这里也提供docker-compose方式启动服务,实际也不推荐使用,因为tracker和storage</a> server以后必然是分开的,所以还是推荐单个docker容器保持灵活性。这里高级点可以用k8s进行自动扩容(后续打算重新开源个镜像)。</p>
<h3 id="Java实践"><a href="#Java实践" class="headerlink" title="Java实践"></a>Java实践</h3><h4 id="导入需要包"><a href="#导入需要包" class="headerlink" title="导入需要包"></a>导入需要包</h4><p>这里使用官方的客户端包:<a href="https://github.com/happyfish100/fastdfs-client-java" target="_blank" rel="external">https://github.com/happyfish100/fastdfs-client-java</a><br><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><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"># 下载源码</span></span><br><span class="line">git <span class="built_in">clone</span> https://github.com/happyfish100/fastdfs-client-java.git</span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> fastdfs-client-java</span><br><span class="line"></span><br><span class="line"><span class="comment"># 打jar包</span></span><br><span class="line">mvn clean install</span><br><span class="line"></span><br><span class="line"><span class="comment"># 输出目录</span></span><br><span class="line"><span class="built_in">cd</span> target</span><br><span class="line"></span><br><span class="line"><span class="comment"># 导入到本地仓库 注意这里version根据实际生成的来</span></span><br><span class="line">mvn install:install-file -DgroupId=org.csource -DartifactId=fastdfs-client-java -Dversion=1.27-SNAPSHOT -Dpackaging=jar -Dfile=fastdfs-client-java-1.27-SNAPSHOT.jar</span><br></pre></td></tr></table></figure></p>
<h4 id="在pom-xml中引入依赖"><a href="#在pom-xml中引入依赖" class="headerlink" title="在pom.xml中引入依赖"></a>在pom.xml中引入依赖</h4><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><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><dependency></span><br><span class="line"> <groupId>org.csource</groupId></span><br><span class="line"> <artifactId>fastdfs-client-java</artifactId></span><br><span class="line"> <version>1.27-SNAPSHOT</version></span><br><span class="line"></dependency></span><br><span class="line"></span><br><span class="line"><dependency></span><br><span class="line"> <groupId>commons-fileupload</groupId></span><br><span class="line"> <artifactId>commons-fileupload</artifactId></span><br><span class="line"> <version>1.3.1</version></span><br><span class="line"></dependency></span><br><span class="line"></span><br><span class="line"><dependency></span><br><span class="line"> <groupId>commons-io</groupId></span><br><span class="line"> <artifactId>commons-io</artifactId></span><br><span class="line"> <version>2.2</version></span><br><span class="line"></dependency></span><br><span class="line"></span><br><span class="line"><dependency></span><br><span class="line"> <groupId>org.apache.commons</groupId></span><br><span class="line"> <artifactId>commons-lang3</artifactId></span><br><span class="line"> <version>3.1</version></span><br><span class="line"></dependency></span><br></pre></td></tr></table></figure>
<h4 id="添加Client配置"><a href="#添加Client配置" class="headerlink" title="添加Client配置"></a>添加Client配置</h4><p>在resource目录下,添加conf/fdfs_client.conf配置文件<br><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><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">connect_timeout = 2</span><br><span class="line">network_timeout = 30</span><br><span class="line">charset = UTF-8</span><br><span class="line">http.tracker_http_port = 80</span><br><span class="line">http.anti_steal_token = no</span><br><span class="line">http.secret_key = FastDFS1234567890</span><br><span class="line"></span><br><span class="line">tracker_server = 192.168.1.163:22122</span><br></pre></td></tr></table></figure></p>
<p>测试时实际上只需关注tracker_server,并且改为你自己的tracker server</p>
<h4 id="添加文件上传bean"><a href="#添加文件上传bean" class="headerlink" title="添加文件上传bean"></a>添加文件上传bean</h4><p>applicationContext.xml配置中添加文件上传bean<br><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></pre></td><td class="code"><pre><span class="line"><bean id=<span class="string">"multipartResolver"</span> class=<span class="string">"org.springframework.web.multipart.commons.CommonsMultipartResolver"</span>></span><br><span class="line"> <property name=<span class="string">"maxUploadSize"</span> value=<span class="string">"62914560"</span> /></span><br><span class="line"> <property name=<span class="string">"defaultEncoding"</span> value=<span class="string">"UTF-8"</span> /></span><br><span class="line"></bean></span><br></pre></td></tr></table></figure></p>
<h4 id="建一个Client封装"><a href="#建一个Client封装" class="headerlink" title="建一个Client封装"></a>建一个Client封装</h4><p>建一个简单的client封装(勿作生产使用)<br>FastDFSClient.java<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.rootrl.fastDFSDemo.utiles;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.lang3.StringUtils;</span><br><span class="line"><span class="keyword">import</span> org.csource.common.NameValuePair;</span><br><span class="line"><span class="keyword">import</span> org.csource.fastdfs.*;</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.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FastDFSClient</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> StorageClient1 storageClient1 = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">// 获取配置文件</span></span><br><span class="line"> String classPath = <span class="keyword">new</span> File(FastDFSClient.class.getResource(<span class="string">"/"</span>).getFile()).getCanonicalPath();</span><br><span class="line"> String CONF_FILENAME = classPath + File.separator + <span class="string">"conf"</span> + File.separator + <span class="string">"fdfs_client.conf"</span>;</span><br><span class="line"> ClientGlobal.init(CONF_FILENAME);</span><br><span class="line"> <span class="comment">// 获取触发器</span></span><br><span class="line"> TrackerClient trackerClient = <span class="keyword">new</span> TrackerClient(ClientGlobal.g_tracker_group);</span><br><span class="line"> TrackerServer trackerServer = trackerClient.getConnection();</span><br><span class="line"> <span class="comment">// 获取存储服务器</span></span><br><span class="line"> StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);</span><br><span class="line"> storageClient1 = <span class="keyword">new</span> StorageClient1(trackerServer, storageServer);</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> System.out.println(e);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 上传文件</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> fis 文件输入流</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> fileName 文件名称</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="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">uploadFile</span><span class="params">(InputStream fis, String fileName)</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> NameValuePair[] meta_list = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//将输入流写入file_buff数组</span></span><br><span class="line"> <span class="keyword">byte</span>[] file_buff = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">if</span> (fis != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">int</span> len = fis.available();</span><br><span class="line"> file_buff = <span class="keyword">new</span> <span class="keyword">byte</span>[len];</span><br><span class="line"> fis.read(file_buff);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> String fileid = storageClient1.upload_file1(file_buff, getFileExt(fileName), meta_list);</span><br><span class="line"> <span class="keyword">return</span> fileid;</span><br><span class="line"> } <span class="keyword">catch</span> (Exception ex) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">if</span> (fis != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> fis.close();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> System.out.println(e);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><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> fileName</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="function"><span class="keyword">private</span> <span class="keyword">static</span> String <span class="title">getFileExt</span><span class="params">(String fileName)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (StringUtils.isBlank(fileName) || !fileName.contains(<span class="string">"."</span>)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">""</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> fileName.substring(fileName.lastIndexOf(<span class="string">"."</span>) + <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h4 id="建立控制器"><a href="#建立控制器" class="headerlink" title="建立控制器"></a>建立控制器</h4><p>然后建立一个File控制器,做测试用<br>FileController.java<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.rootrl.fastDFSDemo.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.rootrl.fastDFSDemo.utiles.FastDFSClient;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Controller;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestParam;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.multipart.MultipartFile;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="meta">@RequestMapping</span>(<span class="string">"fastdfs"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FileController</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@RequestMapping</span>(value = <span class="string">"upload"</span>)</span><br><span class="line"> <span class="meta">@ResponseBody</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">uploadFileSample</span><span class="params">(@RequestParam MultipartFile file)</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> String fileId = FastDFSClient.uploadFile(file.getInputStream(), file.getOriginalFilename());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> fileId;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> System.out.println(e.getMessage());</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"error"</span>;</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>
<p>然后使用postman客户端测试,url为:<a href="http://localhost:8080/fastdfs/upload.do(依据自己实际情况变更)" target="_blank" rel="external">http://localhost:8080/fastdfs/upload.do(依据自己实际情况变更)</a></p>
<p>注意postman使用post请求,然后切换到body/form-data标签项,添加一个Key为file,类型为file,然后value就可以上传文件了。成功会返回文件id,类似:group1/M00/00/00/wKgBo1zjxnOAT-k1AAAoMlb3hzU996.png</p>
<h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><p><a href="https://blog.csdn.net/yxflovegs2012/article/details/53868362" target="_blank" rel="external">https://blog.csdn.net/yxflovegs2012/article/details/53868362</a></p>
</div>
<footer class="article-footer">
<div class="share-container">
</div>
<a data-url="https://rootrl.github.com/2019/05/22/FastDFS-Docker化部署-以及-Java-SpringMVC实践/" data-id="ck4wtj7eg000b7opnp9t6tnb2" class="article-share-link"><i class="fa fa-share"></i>Share</a>
<script>
(function ($) {
// Prevent duplicate binding
if (typeof(__SHARE_BUTTON_BINDED__) === 'undefined' || !__SHARE_BUTTON_BINDED__) {
__SHARE_BUTTON_BINDED__ = true;
} else {
return;
}
$('body').on('click', function() {
$('.article-share-box.on').removeClass('on');
}).on('click', '.article-share-link', function(e) {
e.stopPropagation();
var $this = $(this),
url = $this.attr('data-url'),
encodedUrl = encodeURIComponent(url),
id = 'article-share-box-' + $this.attr('data-id'),
offset = $this.offset(),
box;
if ($('#' + id).length) {
box = $('#' + id);
if (box.hasClass('on')){
box.removeClass('on');
return;
}
} else {
var html = [
'<div id="' + id + '" class="article-share-box">',
'<input class="article-share-input" value="' + url + '">',
'<div class="article-share-links">',
'<a href="https://twitter.com/intent/tweet?url=' + encodedUrl + '" class="fa fa-twitter article-share-twitter" target="_blank" title="Twitter"></a>',
'<a href="https://www.facebook.com/sharer.php?u=' + encodedUrl + '" class="fa fa-facebook article-share-facebook" target="_blank" title="Facebook"></a>',
'<a href="http://pinterest.com/pin/create/button/?url=' + encodedUrl + '" class="fa fa-pinterest article-share-pinterest" target="_blank" title="Pinterest"></a>',
'<a href="https://plus.google.com/share?url=' + encodedUrl + '" class="fa fa-google article-share-google" target="_blank" title="Google+"></a>',
'</div>',
'</div>'
].join('');
box = $(html);
$('body').append(box);
}
$('.article-share-box.on').hide();
box.css({
top: offset.top + 25,
left: offset.left
}).addClass('on');
}).on('click', '.article-share-box', function (e) {
e.stopPropagation();
}).on('click', '.article-share-box-input', function () {
$(this).select();
}).on('click', '.article-share-box-link', function (e) {
e.preventDefault();
e.stopPropagation();
window.open(this.href, 'article-share-box-window-' + Date.now(), 'width=500,height=450');
});
})(jQuery);
</script>
<a href="https://rootrl.github.com/2019/05/22/FastDFS-Docker化部署-以及-Java-SpringMVC实践/#comments" class="article-comment-link disqus-comment-count" data-disqus-url="https://rootrl.github.com/2019/05/22/FastDFS-Docker化部署-以及-Java-SpringMVC实践/">Comments</a>
</footer>
</div>
</article>
<article id="post-Intellij-Idea-中进行-Mybatis逆向工程" class="article article-type-post" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/05/21/Intellij-Idea-中进行-Mybatis逆向工程/">Intellij Idea 中进行 Mybatis逆向工程</a>
</h1>
<div class="article-meta">
<div class="article-date">
<i class="fa fa-calendar"></i>
<a href="/2019/05/21/Intellij-Idea-中进行-Mybatis逆向工程/">
<time datetime="2019-05-21T12:45:49.000Z" itemprop="datePublished">2019-05-21</time>
</a>
</div>
<div class="article-category">
<i class="fa fa-folder"></i>
<a class="article-category-link" href="/categories/开发语言/">开发语言</a><i class="fa fa-angle-right"></i><a class="article-category-link" href="/categories/开发语言/Java/">Java</a>
</div>
<div class="article-tag">
<i class="fa fa-tag"></i>
<a class="tag-link" href="/tags/mybatis/">mybatis</a>
</div>
</div>
</header>
<div class="article-entry" itemprop="articleBody">
<h3 id="开篇"><a href="#开篇" class="headerlink" title="开篇"></a>开篇</h3><p>Mybatis有个实用的功能就是逆向工程,能根据表结构反向生成实体类,这样能避免手工生成出错。市面上的教程大多都很老了,大部分都是针对mysql5的,以下为我执行mysql8时的经验。</p>
<h3 id="引入工程"><a href="#引入工程" class="headerlink" title="引入工程"></a>引入工程</h3><p>这里使用的是maven包管理工具,在pom.xml添加以下配置,以引入mybatis.generator</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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">build</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">finalName</span>></span>SpringMVCBasic<span class="tag"></<span class="name">finalName</span>></span></span><br><span class="line"> <span class="comment"><!-- 添加mybatis-generator-maven-plugin插件 --></span></span><br><span class="line"> <span class="tag"><<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.mybatis.generator<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>mybatis-generator-maven-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.3.2<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">verbose</span>></span>true<span class="tag"></<span class="name">verbose</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">overwrite</span>></span>true<span class="tag"></<span class="name">overwrite</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">build</span>></span></span><br></pre></td></tr></table></figure>
<h3 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h3><p>在maven项目下的src/main/resources 目录下新建generatorConfig.xml和generator.properties文件</p>
<p>generator.properties</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">jdbc.driverLocation=F:\\maven-repository\\mysql\\mysql-connector-java\\8.0.16\\mysql-connector-java-8.0.16.jar</span><br><span class="line">jdbc.driverClass=com.mysql.cj.jdbc.Driver</span><br><span class="line">jdbc.connectionURL=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8</span><br><span class="line">jdbc.userId=test</span><br><span class="line">jdbc.password=test123</span><br></pre></td></tr></table></figure>
<p>注意:<br>1,generator.properties里面的jdbc.driverLocation指向是你本地maven库对应mysql-connector地址<br>2,与老版本不同,这里driversClass为com.mysql.cj.jdbc.Driver</p>
<p>generatorConfig.xml</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><?xml version="1.0" encoding="UTF-8"?></span><br><span class="line"><span class="meta"><!DOCTYPE generatorConfiguration</span></span><br><span class="line"><span class="meta"> PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"</span></span><br><span class="line"><span class="meta"> "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">generatorConfiguration</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!--导入属性配置--></span></span><br><span class="line"> <span class="tag"><<span class="name">properties</span> <span class="attr">resource</span>=<span class="string">"generator.properties"</span>></span><span class="tag"></<span class="name">properties</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!--指定特定数据库的jdbc驱动jar包的位置(绝对路径)--></span></span><br><span class="line"> <span class="tag"><<span class="name">classPathEntry</span> <span class="attr">location</span>=<span class="string">"${jdbc.driverLocation}"</span>/></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">context</span> <span class="attr">id</span>=<span class="string">"default"</span> <span class="attr">targetRuntime</span>=<span class="string">"MyBatis3"</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!-- optional,旨在创建class时,对注释进行控制 --></span></span><br><span class="line"> <span class="tag"><<span class="name">commentGenerator</span>></span></span><br><span class="line"> <span class="comment"><!--是否去掉自动生成的注释 true:是--></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"suppressDate"</span> <span class="attr">value</span>=<span class="string">"true"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"suppressAllComments"</span> <span class="attr">value</span>=<span class="string">"true"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">commentGenerator</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!--jdbc的数据库连接:驱动类、链接地址、用户名、密码--></span></span><br><span class="line"> <span class="tag"><<span class="name">jdbcConnection</span></span></span><br><span class="line"><span class="tag"> <span class="attr">driverClass</span>=<span class="string">"${jdbc.driverClass}"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">connectionURL</span>=<span class="string">"${jdbc.connectionURL}"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">userId</span>=<span class="string">"${jdbc.userId}"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">password</span>=<span class="string">"${jdbc.password}"</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">jdbcConnection</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制--></span></span><br><span class="line"> <span class="tag"><<span class="name">javaTypeResolver</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"forceBigDecimals"</span> <span class="attr">value</span>=<span class="string">"false"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">javaTypeResolver</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!-- Model模型生成器,用来生成含有主键key的类,记录类 以及查询Example类</span></span><br><span class="line"><span class="comment"> targetPackage 指定生成的model生成所在的包名</span></span><br><span class="line"><span class="comment"> targetProject 指定在该项目下所在的路径</span></span><br><span class="line"><span class="comment"> --></span></span><br><span class="line"> <span class="tag"><<span class="name">javaModelGenerator</span> <span class="attr">targetPackage</span>=<span class="string">"com.ifly.outsourcing.entity"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">targetProject</span>=<span class="string">"src/main/java"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"enableSubPackages"</span> <span class="attr">value</span>=<span class="string">"true"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"trimStrings"</span> <span class="attr">value</span>=<span class="string">"true"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">javaModelGenerator</span>></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!--Mapper映射文件生成所在的目录 为每一个数据库的表生成对应的SqlMap文件 --></span></span><br><span class="line"> <span class="tag"><<span class="name">sqlMapGenerator</span> <span class="attr">targetPackage</span>=<span class="string">"mappers"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">targetProject</span>=<span class="string">"src/main/resources"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"enableSubPackages"</span> <span class="attr">value</span>=<span class="string">"false"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">sqlMapGenerator</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!-- 客户端代码,生成易于使用的针对Model对象和XML配置文件 的代码</span></span><br><span class="line"><span class="comment"> type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象</span></span><br><span class="line"><span class="comment"> type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象</span></span><br><span class="line"><span class="comment"> type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口</span></span><br><span class="line"><span class="comment"> --></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">javaClientGenerator</span> <span class="attr">type</span>=<span class="string">"XMLMAPPER"</span> <span class="attr">targetPackage</span>=<span class="string">"com.ifly.outsourcing.dao"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">targetProject</span>=<span class="string">"src/main/java"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">property</span> <span class="attr">name</span>=<span class="string">"enableSubPackages"</span> <span class="attr">value</span>=<span class="string">"true"</span>/></span></span><br><span class="line"> <span class="tag"></<span class="name">javaClientGenerator</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="comment"><!-- 数据表进行生成操作 tableName:表名; domainObjectName:对应的DO --></span></span><br><span class="line"> <span class="tag"><<span class="name">table</span> <span class="attr">tableName</span>=<span class="string">"user"</span> <span class="attr">domainObjectName</span>=<span class="string">"user"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">enableCountByExample</span>=<span class="string">"false"</span> <span class="attr">enableUpdateByExample</span>=<span class="string">"false"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">enableDeleteByExample</span>=<span class="string">"false"</span> <span class="attr">enableSelectByExample</span>=<span class="string">"false"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">selectByExampleQueryId</span>=<span class="string">"false"</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">table</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"></<span class="name">context</span>></span></span><br><span class="line"><span class="tag"></<span class="name">generatorConfiguration</span>></span></span><br></pre></td></tr></table></figure>
<p>注意:这里主要注意修改对应的javaModelGenerator ,sqlMapGenerator,javaClientGenerator 为自己的生成路径。以及添加自己的数据表。</p>
<h3 id="在Intellij-IDEA添加一个“Run运行”选项"><a href="#在Intellij-IDEA添加一个“Run运行”选项" class="headerlink" title="在Intellij IDEA添加一个“Run运行”选项"></a>在Intellij IDEA添加一个“Run运行”选项</h3><p>点击菜单栏的run,新建一个选项为maven的configurations,name为自己方便看,比如generator,commnd line注意写为:</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">mybatis-generator:generate -e</span><br></pre></td></tr></table></figure>
<p>点击run即可生成对应文件。</p>
</div>
<footer class="article-footer">
<div class="share-container">
</div>
<a data-url="https://rootrl.github.com/2019/05/21/Intellij-Idea-中进行-Mybatis逆向工程/" data-id="ck4wtj7ej000h7opn16ldpv3b" class="article-share-link"><i class="fa fa-share"></i>Share</a>
<script>
(function ($) {
// Prevent duplicate binding
if (typeof(__SHARE_BUTTON_BINDED__) === 'undefined' || !__SHARE_BUTTON_BINDED__) {
__SHARE_BUTTON_BINDED__ = true;
} else {
return;
}
$('body').on('click', function() {
$('.article-share-box.on').removeClass('on');
}).on('click', '.article-share-link', function(e) {
e.stopPropagation();
var $this = $(this),
url = $this.attr('data-url'),
encodedUrl = encodeURIComponent(url),
id = 'article-share-box-' + $this.attr('data-id'),
offset = $this.offset(),
box;
if ($('#' + id).length) {
box = $('#' + id);
if (box.hasClass('on')){
box.removeClass('on');
return;
}
} else {
var html = [
'<div id="' + id + '" class="article-share-box">',
'<input class="article-share-input" value="' + url + '">',
'<div class="article-share-links">',
'<a href="https://twitter.com/intent/tweet?url=' + encodedUrl + '" class="fa fa-twitter article-share-twitter" target="_blank" title="Twitter"></a>',
'<a href="https://www.facebook.com/sharer.php?u=' + encodedUrl + '" class="fa fa-facebook article-share-facebook" target="_blank" title="Facebook"></a>',
'<a href="http://pinterest.com/pin/create/button/?url=' + encodedUrl + '" class="fa fa-pinterest article-share-pinterest" target="_blank" title="Pinterest"></a>',
'<a href="https://plus.google.com/share?url=' + encodedUrl + '" class="fa fa-google article-share-google" target="_blank" title="Google+"></a>',
'</div>',
'</div>'
].join('');
box = $(html);
$('body').append(box);
}
$('.article-share-box.on').hide();
box.css({
top: offset.top + 25,
left: offset.left
}).addClass('on');
}).on('click', '.article-share-box', function (e) {
e.stopPropagation();
}).on('click', '.article-share-box-input', function () {
$(this).select();
}).on('click', '.article-share-box-link', function (e) {
e.preventDefault();
e.stopPropagation();
window.open(this.href, 'article-share-box-window-' + Date.now(), 'width=500,height=450');
});
})(jQuery);
</script>
<a href="https://rootrl.github.com/2019/05/21/Intellij-Idea-中进行-Mybatis逆向工程/#comments" class="article-comment-link disqus-comment-count" data-disqus-url="https://rootrl.github.com/2019/05/21/Intellij-Idea-中进行-Mybatis逆向工程/">Comments</a>
</footer>
</div>
</article>
<nav id="page-nav">
<span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><a class="page-number" href="/page/3/">3</a><span class="space">…</span><a class="page-number" href="/page/9/">9</a><a class="extend next" rel="next" href="/page/2/">Next »</a>
</nav>
</section>
<aside id="sidebar">
<div class="widget-wrap">
<h3 class="widget-title">recent</h3>
<div class="widget">
<ul id="recent-post" class="">
<li>
<div class="item-thumbnail">
<a href="/2020/01/02/Android-Bug记:-Canvas-trying-to-use-a-recycled-bitmap-android-graphics-Bitmap/" class="thumbnail">
<span class="thumbnail-image thumbnail-none"></span>
</a>
</div>
<div class="item-inner">
<p class="item-category"><a class="article-category-link" href="/categories/开发语言/">开发语言</a><i class="fa fa-angle-right"></i><a class="article-category-link" href="/categories/开发语言/Android/">Android</a></p>
<p class="item-title"><a href="/2020/01/02/Android-Bug记:-Canvas-trying-to-use-a-recycled-bitmap-android-graphics-Bitmap/" class="title">Android Bug记 'Canvas: trying to use a recycled bitmap android.graphics.Bitmap'</a></p>
<p class="item-date"><time datetime="2020-01-02T14:18:56.000Z" itemprop="datePublished">2020-01-02</time></p>
</div>
</li>
<li>
<div class="item-thumbnail">
<a href="/2019/05/22/FastDFS-Docker化部署-以及-Java-SpringMVC实践/" class="thumbnail">
<span class="thumbnail-image thumbnail-none"></span>
</a>
</div>
<div class="item-inner">
<p class="item-category"><a class="article-category-link" href="/categories/开发语言/">开发语言</a><i class="fa fa-angle-right"></i><a class="article-category-link" href="/categories/开发语言/Java/">Java</a></p>
<p class="item-title"><a href="/2019/05/22/FastDFS-Docker化部署-以及-Java-SpringMVC实践/" class="title">FastDFS Docker化部署 以及 Java SpringMVC实践</a></p>
<p class="item-date"><time datetime="2019-05-22T13:23:39.000Z" itemprop="datePublished">2019-05-22</time></p>
</div>
</li>
<li>
<div class="item-thumbnail">
<a href="/2019/05/21/Intellij-Idea-中进行-Mybatis逆向工程/" class="thumbnail">
<span class="thumbnail-image thumbnail-none"></span>
</a>
</div>
<div class="item-inner">
<p class="item-category"><a class="article-category-link" href="/categories/开发语言/">开发语言</a><i class="fa fa-angle-right"></i><a class="article-category-link" href="/categories/开发语言/Java/">Java</a></p>
<p class="item-title"><a href="/2019/05/21/Intellij-Idea-中进行-Mybatis逆向工程/" class="title">Intellij Idea 中进行 Mybatis逆向工程</a></p>
<p class="item-date"><time datetime="2019-05-21T12:45:49.000Z" itemprop="datePublished">2019-05-21</time></p>
</div>
</li>
<li>
<div class="item-thumbnail">
<a href="/2019/04/09/关于七牛云正确使用姿势探索/" class="thumbnail">
<span class="thumbnail-image thumbnail-none"></span>
</a>
</div>
<div class="item-inner">
<p class="item-category"><a class="article-category-link" href="/categories/开发经验/">开发经验</a></p>
<p class="item-title"><a href="/2019/04/09/关于七牛云正确使用姿势探索/" class="title">关于七牛云正确使用姿势探索</a></p>
<p class="item-date"><time datetime="2019-04-09T14:51:32.000Z" itemprop="datePublished">2019-04-09</time></p>
</div>
</li>
<li>
<div class="item-thumbnail">
<a href="/2018/11/30/Linux磁盘挂载、分区、扩容操作/" class="thumbnail">
<span class="thumbnail-image thumbnail-none"></span>
</a>
</div>
<div class="item-inner">
<p class="item-category"><a class="article-category-link" href="/categories/Unix-Linux/">Unix/Linux</a></p>
<p class="item-title"><a href="/2018/11/30/Linux磁盘挂载、分区、扩容操作/" class="title">Linux磁盘挂载、分区、扩容操作</a></p>
<p class="item-date"><time datetime="2018-11-30T14:45:38.000Z" itemprop="datePublished">2018-11-30</time></p>
</div>
</li>
</ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">categories</h3>
<div class="widget">
<ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/DevOps/">DevOps</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Unix-Linux/">Unix/Linux</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/其他/">其他</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/前端/">前端</a><span class="category-list-count">6</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/前端/CSS/">CSS</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/前端/Javascript/">Javascript</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/前端/工具/">工具</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/前端/框架/">框架</a><span class="category-list-count">1</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/前端/框架/Vue/">Vue</a><span class="category-list-count">1</span></li></ul></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/团队管理/">团队管理</a><span class="category-list-count">1</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/团队管理/知识管理/">知识管理</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/安全/">安全</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/开发经验/">开发经验</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/开发语言/">开发语言</a><span class="category-list-count">7</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/开发语言/Android/">Android</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/开发语言/Golang/">Golang</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/开发语言/Java/">Java</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/开发语言/PHP/">PHP</a><span class="category-list-count">3</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/杂类/">杂类</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/虚拟机-容器/">虚拟机/容器</a><span class="category-list-count">5</span></li></ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">archives</h3>
<div class="widget">
<ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/01/">January 2020</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/05/">May 2019</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/04/">April 2019</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/11/">November 2018</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/10/">October 2018</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/09/">September 2018</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/07/">July 2018</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/06/">June 2018</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/04/">April 2018</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/11/">November 2017</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/10/">October 2017</a><span class="archive-list-count">6</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/09/">September 2017</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/08/">August 2017</a><span class="archive-list-count">3</span></li></ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">tags</h3>
<div class="widget">
<ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/Android/">Android</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/CSS/">CSS</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Css/">Css</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Docker/">Docker</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/FastDFS/">FastDFS</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Flex/">Flex</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Golang/">Golang</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java/">Java</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Javascript/">Javascript</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Laravel/">Laravel</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Linux/">Linux</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Opcodes/">Opcodes</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/PHP/">PHP</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Vagrant集群/">Vagrant集群</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Vue/">Vue</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ansible/">ansible</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/docker/">docker</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ftp/">ftp</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/github-pages/">github pages</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hexo/">hexo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/jwt/">jwt</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/linux/">linux</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mount/">mount</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mybatis/">mybatis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/">nginx</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ngrok/">ngrok</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/npm/">npm</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/shadowsocks/">shadowsocks</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/systemctl/">systemctl</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/webpack/">webpack</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/七牛云/">七牛云</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/内网穿透/">内网穿透</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/前端/">前端</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/文件上传/">文件上传</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/杂类/">杂类</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/鉴权/">鉴权</a><span class="tag-list-count">1</span></li></ul>
</div>
</div>
<div class="widget-wrap widget-list">
<h3 class="widget-title">links</h3>
<div class="widget">
<ul>
<li>
<a href="http://hexo.io">Hexo</a>
</li>
</ul>
</div>
</div>
<div id="toTop" class="fa fa-angle-up"></div>
</aside>
</div>
<footer id="footer">
<div class="outer">
<div id="footer-info" class="inner">
© 2020 Rootrl<br>
Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>. Theme by <a href="http://github.com/ppoffice">PPOffice</a>
</div>
</div>
</footer>
<script>
var disqus_config = function () {
this.page.identifier = '';
};
(function() {
var d = document, s = d.createElement('script');
s.src = '//' + 'rootrl' + '.disqus.com/count.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<script src="/libs/lightgallery/js/lightgallery.min.js"></script>
<script src="/libs/lightgallery/js/lg-thumbnail.min.js"></script>
<script src="/libs/lightgallery/js/lg-pager.min.js"></script>
<script src="/libs/lightgallery/js/lg-autoplay.min.js"></script>
<script src="/libs/lightgallery/js/lg-fullscreen.min.js"></script>
<script src="/libs/lightgallery/js/lg-zoom.min.js"></script>
<script src="/libs/lightgallery/js/lg-hash.min.js"></script>
<script src="/libs/lightgallery/js/lg-share.min.js"></script>
<script src="/libs/lightgallery/js/lg-video.min.js"></script>
<script src="/libs/justified-gallery/jquery.justifiedGallery.min.js"></script>
<!-- Custom Scripts -->
<script src="/js/main.js"></script>
</div>
</body>
</html>