派大星的博客

很多事情不是会了才能做,而是做了才能学会


  • 首页

  • 标签

  • 分类

  • 关于

  • 搜索

数据库优化总结

发表于 2019-06-07 | 分类于 数据库

1 数据库设计方面:

a. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
b. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0

c. 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。

d. 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

e. 应尽可能的避免更新索引数据列,因为索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新索引数据列,那么需要考虑是否应将该索引建为索引。

f. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

g. 尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

h. 尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。

i. 避免频繁创建和删除临时表,以减少系统表资源的消耗。

j. 临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。

k. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。

l. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。

2 SQL语句方面:

a. 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。

b. 应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:

select id from t where num=10 or num=20

可以这样查询:

select id from t where num=10 union all select id from t where num=20

c. in 和 not in 也要慎用,否则会导致全表扫描,如:

select id from t where num in(1,2,3)

对于连续的数值,能用 between 就不要用 in 了:

select id from t where num between 1 and 3

d. 下面的查询也将导致全表扫描:

select id from t where name like ‘%abc%’

e. 如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。

然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:

select id from t where num=@num

可以改为强制查询使用索引:

select id from t with(index(索引名)) where num=@num

f. 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:

select id from t where num/2=100

应改为:

select id from t where num=100*2

g. 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:

select id from t where substring(name,1,3)=’abc’

–name以abc开头的id

select id from t where datediff(day,createdate,’2005-11-30′)=0

–‘2005-11-30’生成的id

应改为:

select id from t where name like ‘abc%’ select id from t where createdate>=’2005-11-30′ and createdate<’2005-12-1′

h. 不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

i. 不要写一些没有意义的查询,如需要生成一个空表结构:

select col1,col2 into #t from t where 1=0

这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:

create table #t(…)

j. 很多时候用 exists 代替 in 是一个好的选择:

select num from a where num in(select num from b)

用下面的语句替换:

select num from a where exists(select 1 from b where num=a.num)

k. 任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。

l. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。

m. 尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

n. 尽量避免大事务操作,提高系统并发能力。

3 java方面:重点内容

a.尽可能的少造对象。

b.合理摆正系统设计的位置。大量数据操作,和少量数据操作一定是分开的。大量的数据操作,肯定不是ORM框架搞定的。,

c.使用jDBC链接数据库操作数据

d.控制好内存,让数据流起来,而不是全部读到内存再处理,而是边读取边处理;

e.合理利用内存,有的数据要缓存

如何优化数据库,如何提高数据库的性能?

1) 硬件调整性能

最有可能影响性能的是磁盘和网络吞吐量,解决办法扩大虚拟内存,并保证有足够可以扩充的空间;把数据库服务器上的不必要服务关闭掉;把数据库服务器和主域服务器分开;把SQL数据库服务器的吞吐量调为最大;在具有一个以上处理器的机器上运行SQL。

2)调整数据库

若对该表的查询频率比较高,则建立索引;建立索引时,想尽对该表的所有查询搜索操作, 按照where选择条件建立索引,尽量为整型键建立为有且只有一个簇集索引,数据在物理上按顺序在数据页上,缩短查找范围,为在查询经常使用的全部列建立非簇集索引,能最大地覆盖查询;但是索引不可太多,执行UPDATE DELETE INSERT语句需要用于维护这些索引的开销量急剧增加;避免在索引中有太多的索引键;避免使用大型数据类型的列为索引;保证每个索引键值有少数行。

3)使用存储过程

应用程序的实现过程中,能够采用存储过程实现的对数据库的操作尽量通过存储过程来实现,因为存储过程是存放在数据库服务器上的一次性被设计、编码、测试,并被再次使用,需要执行该任务的应用可以简单地执行存储过程,并且只返回结果集或者数值,这样不仅可以使程序模块化,同时提高响应速度,减少网络流量,并且通过输入参数接受输入,使得在应用中完成逻辑的一致性实现。

4)应用程序结构和算法

建立查询条件索引仅仅是提高速度的前提条件,响应速度的提高还依赖于对索引的使用。因为人们在使用SQL时往往会陷入一个误区,即太关注于所得的结果是否正确,特别是对数据量不是特别大的数据库操作时,是否建立索引和使用索引的好坏对程序的响应速度并不大,因此程序员在书写程序时就忽略了不同的实现方法之间可能存在的性能差异,这种性能差异在数据量特别大时或者大型的或是复杂的数据库环境中(如联机事务处理OLTP或决策支持系统DSS)中表现得尤为明显。在工作实践中发现,不良的SQL往往来自于不恰当的索引设计、不充份的连接条件和不可优化的where子句。在对它们进行适当的优化后,其运行速度有了明显地提高!

原文链接:https://m.2cto.com/database/201503/381295.html

hexo中next主题配置

发表于 2019-06-03 | 分类于 工具使用

1. hexo配置

blog/_config.yml

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
# Hexo Configuration
## Docs: https://hexo.io/docs/configuration.html
## Source: https://github.com/hexojs/hexo/

# Site
# Site
# 博客名称
title: 派大星的博客
# 博客子标题
subtitle: 派大星的个人博客
# 作者描述
description:
# 站点关键词,用于搜索优化
keywords: 派大星,pibigstar
# 博主名
author: 派大星
# 站点语言
language: zh-CN
# 时区
timezone: Asia/Shanghai

# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: http://pibigstar.com
root: /
permalink: :year/:month/:day/:title/
permalink_defaults:

# Directory
source_dir: source
public_dir: public
tag_dir: tags
archive_dir: archives
category_dir: categories
code_dir: downloads/code
i18n_dir: :lang
skip_render:

# Writing
new_post_name: :title.md # File name of new posts
default_layout: post
titlecase: false # Transform title into titlecase
external_link: true # Open external links in new tab
filename_case: 0
render_drafts: false
post_asset_folder: false
relative_link: false
future: true
highlight:
enable: true
line_number: true
auto_detect: false
tab_replace:

# Home page setting
# path: Root path for your blogs index page. (default = '')
# per_page: Posts displayed per page. (0 = disable pagination)
# order_by: Posts order. (Order by date descending by default)
index_generator:
path: ''
per_page: 10
order_by: -date

# Category & Tag
default_category: uncategorized
category_map:
tag_map:

# Date / Time format
## Hexo uses Moment.js to parse and display date
## You can customize the date format as defined in
## http://momentjs.com/docs/#/displaying/format/
date_format: YYYY-MM-DD
time_format: HH:mm:ss

# Pagination
## Set per_page to 0 to disable pagination
per_page: 10
pagination_dir: page

# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: next


# 发布
## Docs: https://hexo.io/docs/deployment.html
deploy:
type: git
repo: https://github.com/pibigstar/pibigstar.github.io.git
branch: master

# 实现搜索文章的功能
search:
path: search.xml
field: post
format: html
limit: 100

# 实现博客订阅功能
feed:
type: atom
path: atom.xml
limit: 20
# 生成站点地图用于SEO优化
sitemap:
path: sitemap.xml
baidusitmap:
path: baidusitemap.xml

2. next主题配置

blog/themes/next/_config.yml

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
# ===============================================================
# ========================= ATTENTION! ==========================
# ===============================================================
# NexT repository is moving here: https://github.com/theme-next
# ===============================================================
# It's rebase to v6.0.0 and future maintenance will resume there
# ===============================================================

# ---------------------------------------------------------------
# Theme Core Configuration Settings
# ---------------------------------------------------------------

# Set to true, if you want to fully override the default configuration.
# Useful if you don't want to inherit the theme _config.yml configurations.
override: false

# ---------------------------------------------------------------
# Site Information Settings
# ---------------------------------------------------------------

# To get or check favicons visit: https://realfavicongenerator.net
# Put your favicons into `hexo-site/source/` (recommend) or `hexo-site/themes/next/source/images/` directory.

# Default NexT favicons placed in `hexo-site/themes/next/source/images/` directory.
# And if you want to place your icons in `hexo-site/source/` root directory, you must remove `/images` prefix from pathes.

# For example, you put your favicons into `hexo-site/source/images` directory.
# Then need to rename & redefine they on any other names, otherwise icons from Next will rewrite your custom icons in Hexo.
favicon:
small: /images/favicon-16x16-next.png
medium: /images/favicon-32x32-next.png
apple_touch_icon: /images/apple-touch-icon-next.png
safari_pinned_tab: /images/logo.svg
#android_manifest: /images/manifest.json
#ms_browserconfig: /images/browserconfig.xml

# Set default keywords (Use a comma to separate)
keywords: "Hexo, NexT"

# Set rss to false to disable feed link.
# Leave rss as empty to use site's feed link.
# Set rss to specific value if you have burned your feed already.
rss:

footer:
# Specify the date when the site was setup.
# If not defined, current year will be used.
#since: 2015

# Icon between year and copyright info.
icon: user

# If not defined, will be used `author` from Hexo main config.
copyright:
# -------------------------------------------------------------
# Hexo link (Powered by Hexo).
powered: true

theme:
# Theme & scheme info link (Theme - NexT.scheme).
enable: true
# Version info of NexT after scheme info (vX.X.X).
version: true
# -------------------------------------------------------------
# Any custom text can be defined here.
#custom_text: Hosted by <a target="_blank" href="https://pages.github.com">GitHub Pages</a>

# ---------------------------------------------------------------
# SEO Settings
# ---------------------------------------------------------------

# Canonical, set a canonical link tag in your hexo, you could use it for your SEO of blog.
# See: https://support.google.com/webmasters/answer/139066
# Tips: Before you open this tag, remember set up your URL in hexo _config.yml ( ex. url: http://yourdomain.com )
canonical: true

# Change headers hierarchy on site-subtitle (will be main site description) and on all post/pages titles for better SEO-optimization.
# 开启seo优化
seo: true

# If true, will add site-subtitle to index page, added in main hexo config.
# subtitle: Subtitle
# 网页搜索及标签页显示副标题
index_with_subtitle: ture


# ---------------------------------------------------------------
# Menu Settings
# ---------------------------------------------------------------

# When running the site in a subdirectory (e.g. domain.tld/blog), remove the leading slash from link value (/archives -> archives).
# Usage: `Key: /link/ || icon`
# Key is the name of menu item. If translate for this menu will find in languages - this translate will be loaded; if not - Key name will be used. Key is case-senstive.
# Value before `||` delimeter is the target link.
# Value after `||` delimeter is the name of FontAwesome icon. If icon (with or without delimeter) is not specified, question icon will be loaded.
menu:
home: / || 主页
schedule: /schedule/ || 时间轴
tags: /tags/ || 标签
categories: /categories/ || 分类
# archives: /archives/ || 档案
sitemap: /sitemap.xml || 站点地图
about: /about/ || 关于我
# commonweal: /404/ || heartbeat

# Enable/Disable menu icons.
menu_icons:
enable: true


# ---------------------------------------------------------------
# Scheme Settings
# ---------------------------------------------------------------

# 主题风格
#scheme: Muse
#scheme: Mist
#scheme: Pisces
scheme: Gemini


# ---------------------------------------------------------------
# Sidebar Settings
# ---------------------------------------------------------------

# Social Links.
# Usage: `Key: permalink || icon`
# Key is the link label showing to end users.
# Value before `||` delimeter is the target permalink.
# Value after `||` delimeter is the name of FontAwesome icon. If icon (with or without delimeter) is not specified, globe icon will be loaded.
#social:
#GitHub: https://github.com/yourname || github
#E-Mail: mailto:yourname@gmail.com || envelope
#Google: https://plus.google.com/yourname || google
#Twitter: https://twitter.com/yourname || twitter
#FB Page: https://www.facebook.com/yourname || facebook
#VK Group: https://vk.com/yourname || vk
#StackOverflow: https://stackoverflow.com/yourname || stack-overflow
#YouTube: https://youtube.com/yourname || youtube
#Instagram: https://instagram.com/yourname || instagram
#Skype: skype:yourname?call|chat || skype

social_icons:
enable: true
icons_only: false
transition: false

# Blog rolls
links_icon: link
links_title: Links
links_layout: block
#links_layout: inline
#links:
#Title: http://example.com/

# 头像设置
# in theme directory(source/images): /images/avatar.gif
# in site directory(source/uploads): /uploads/avatar.gif
avatar: /images/qq.png

# Table Of Contents in the Sidebar
toc:
enable: true

# Automatically add list number to toc.
number: true

# If true, all words will placed on next lines if header width longer then sidebar width.
wrap: false

# Creative Commons 4.0 International License.
# http://creativecommons.org/
# Available: by | by-nc | by-nc-nd | by-nc-sa | by-nd | by-sa | zero
#creative_commons: by-nc-sa
#creative_commons:

sidebar:
# Sidebar Position, available value: left | right (only for Pisces | Gemini).
position: left
#position: right

# Sidebar Display, available value (only for Muse | Mist):
# - post expand on posts automatically. Default.
# - always expand for all pages automatically
# - hide expand only when click on the sidebar toggle icon.
# - remove Totally remove sidebar including sidebar toggle.
display: post
#display: always
#display: hide
#display: remove

# Sidebar offset from top menubar in pixels (only for Pisces | Gemini).
offset: 12

# Back to top in sidebar (only for Pisces | Gemini).
b2t: false

# Scroll percent label in b2t button.
scrollpercent: false

# Enable sidebar on narrow view (only for Muse | Mist).
onmobile: false


# ---------------------------------------------------------------
# Post Settings
# ---------------------------------------------------------------

# Automatically scroll page to section which is under <!-- more --> mark.
scroll_to_more: true

# Automatically saving scroll position on each post/page in cookies.
save_scroll: false

# Automatically excerpt description in homepage as preamble text.
excerpt_description: true

# Automatically Excerpt. Not recommend.
# Please use <!-- more --> in the post to control excerpt accurately.
auto_excerpt:
enable: false
length: 150

# Post meta display settings
post_meta:
item_text: true
created_at: true
updated_at: false
categories: true

# Post wordcount display settings
# Dependencies: https://github.com/willin/hexo-wordcount
post_wordcount:
item_text: true
wordcount: false
min2read: false
totalcount: false
separated_meta: true

# Wechat Subscriber
#wechat_subscriber:
#enabled: true
#qcode: /path/to/your/wechatqcode ex. /uploads/wechat-qcode.jpg
#description: ex. subscribe to my blog by scanning my public wechat account

# Reward
#reward_comment: Donate comment here
#wechatpay: /images/wechatpay.jpg
#alipay: /images/alipay.jpg
#bitcoin: /images/bitcoin.png

# Declare license on posts
post_copyright:
enable: false
license: CC BY-NC-SA 3.0
license_url: https://creativecommons.org/licenses/by-nc-sa/3.0/


# ---------------------------------------------------------------
# Misc Theme Settings
# ---------------------------------------------------------------

# Reduce padding / margin indents on devices with narrow width.
mobile_layout_economy: false

# Android Chrome header panel color ($black-deep).
android_chrome_color: "#222"

# Custom Logo.
# !!Only available for Default Scheme currently.
# Options:
# enabled: [true/false] - Replace with specific image
# image: url-of-image - Images's url
custom_logo:
enabled: false
image:

# 代码高亮分割
# Available value:
# normal | night | night eighties | night blue | night bright
# https://github.com/chriskempson/tomorrow-theme
highlight_theme: night eighties


# ---------------------------------------------------------------
# Font Settings
# - Find fonts on Google Fonts (https://www.google.com/fonts)
# - All fonts set here will have the following styles:
# light, light italic, normal, normal italic, bold, bold italic
# - Be aware that setting too much fonts will cause site running slowly
# - Introduce in 5.0.1
# ---------------------------------------------------------------
# CAUTION! Safari Version 10.1.2 bug: https://github.com/iissnan/hexo-theme-next/issues/1844
# To avoid space between header and sidebar in Pisces / Gemini themes recommended to use Web Safe fonts for `global` (and `logo`):
# Arial | Tahoma | Helvetica | Times New Roman | Courier New | Verdana | Georgia | Palatino | Garamond | Comic Sans MS | Trebuchet MS
# ---------------------------------------------------------------
font:
enable: false

# Uri of fonts host. E.g. //fonts.googleapis.com (Default).
host:

# Font options:
# `external: true` will load this font family from `host` above.
# `family: Times New Roman`. Without any quotes.
# `size: xx`. Use `px` as unit.

# Global font settings used on <body> element.
global:
external: true
family: Lato
size:

# Font settings for Headlines (h1, h2, h3, h4, h5, h6).
# Fallback to `global` font settings.
headings:
external: true
family:
size:

# Font settings for posts.
# Fallback to `global` font settings.
posts:
external: true
family:

# Font settings for Logo.
# Fallback to `global` font settings.
logo:
external: true
family:
size:

# Font settings for <code> and code blocks.
codes:
external: true
family:
size:


# ---------------------------------------------------------------
# Third Party Services Settings
# ---------------------------------------------------------------

# MathJax Support
mathjax:
enable: false
per_page: false
cdn: //cdn.bootcss.com/mathjax/2.7.1/latest.js?config=TeX-AMS-MML_HTMLorMML

# Han Support docs: https://hanzi.pro/
han: false

# Swiftype Search API Key
#swiftype_key:

# Baidu Analytics ID
#baidu_analytics:

# Duoshuo ShortName
#duoshuo_shortname:

# Disqus
disqus:
enable: false
shortname:
count: true

# Hypercomments
#hypercomments_id:

# changyan
changyan:
enable: false
appid:
appkey:


# Valine.
# You can get your appid and appkey from https://leancloud.cn
# more info please open https://valine.js.org
valine:
enable: false
appid: # your leancloud application appid
appkey: # your leancloud application appkey
notify: false # mail notifier , https://github.com/xCss/Valine/wiki
verify: false # Verification code
placeholder: Just go go # comment box placeholder
avatar: mm # gravatar style
guest_info: nick,mail,link # custom comment header
pageSize: 10 # pagination size


# Support for youyan comments system.
# You can get your uid from http://www.uyan.cc
#youyan_uid: your uid

# Support for LiveRe comments system.
# You can get your uid from https://livere.com/insight/myCode (General web site)
#livere_uid: your uid

# Gitment
# Introduction: https://imsun.net/posts/gitment-introduction/
# You can get your Github ID from https://api.github.com/users/<Github username>
gitment:
enable: false
mint: true # RECOMMEND, A mint on Gitment, to support count, language and proxy_gateway
count: true # Show comments count in post meta area
lazy: false # Comments lazy loading with a button
cleanly: false # Hide 'Powered by ...' on footer, and more
language: # Force language, or auto switch by theme
github_user: # MUST HAVE, Your Github ID
github_repo: # MUST HAVE, The repo you use to store Gitment comments
client_id: # MUST HAVE, Github client id for the Gitment
client_secret: # EITHER this or proxy_gateway, Github access secret token for the Gitment
proxy_gateway: # Address of api proxy, See: https://github.com/aimingoo/intersect
redirect_protocol: # Protocol of redirect_uri with force_redirect_protocol when mint enabled

# Baidu Share
# Available value:
# button | slide
# Warning: Baidu Share does not support https.
#baidushare:
## type: button

# Share
# This plugin is more useful in China, make sure you known how to use it.
# And you can find the use guide at official webiste: http://www.jiathis.com/.
# Warning: JiaThis does not support https.
#jiathis:
##uid: Get this uid from http://www.jiathis.com/
#add_this_id:

# Share
#duoshuo_share: true

# NeedMoreShare2
# This plugin is a pure javascript sharing lib which is useful in China.
# See: https://github.com/revir/need-more-share2
# Also see: https://github.com/DzmVasileusky/needShareButton
# iconStyle: default | box
# boxForm: horizontal | vertical
# position: top / middle / bottom + Left / Center / Right
# networks: Weibo,Wechat,Douban,QQZone,Twitter,Linkedin,Mailto,Reddit,
# Delicious,StumbleUpon,Pinterest,Facebook,GooglePlus,Slashdot,
# Technorati,Posterous,Tumblr,GoogleBookmarks,Newsvine,
# Evernote,Friendfeed,Vkontakte,Odnoklassniki,Mailru
needmoreshare2:
enable: false
postbottom:
enable: false
options:
iconStyle: box
boxForm: horizontal
position: bottomCenter
networks: Weibo,Wechat,Douban,QQZone,Twitter,Facebook
float:
enable: false
options:
iconStyle: box
boxForm: horizontal
position: middleRight
networks: Weibo,Wechat,Douban,QQZone,Twitter,Facebook

# Google Webmaster tools verification setting
# See: https://www.google.com/webmasters/
#google_site_verification:

# Google Analytics
#google_analytics:

# Bing Webmaster tools verification setting
# See: https://www.bing.com/webmaster/
#bing_site_verification:

# Yandex Webmaster tools verification setting
# See: https://webmaster.yandex.ru/
#yandex_site_verification:

# CNZZ count
#cnzz_siteid:

# Application Insights
# See https://azure.microsoft.com/en-us/services/application-insights/
# application_insights:

# Make duoshuo show UA
# user_id must NOT be null when admin_enable is true!
# you can visit http://dev.duoshuo.com get duoshuo user id.
duoshuo_info:
ua_enable: true
admin_enable: false
user_id: 0
#admin_nickname: Author

# Post widgets & FB/VK comments settings.
# ---------------------------------------------------------------
# Facebook SDK Support.
# https://github.com/iissnan/hexo-theme-next/pull/410
facebook_sdk:
enable: false
app_id: #<app_id>
fb_admin: #<user_id>
like_button: #true
webmaster: #true

# Facebook comments plugin
# This plugin depends on Facebook SDK.
# If facebook_sdk.enable is false, Facebook comments plugin is unavailable.
facebook_comments_plugin:
enable: false
num_of_posts: 10 # min posts num is 1
width: 100% # default width is 550px
scheme: light # default scheme is light (light or dark)

# VKontakte API Support.
# To get your AppID visit https://vk.com/editapp?act=create
vkontakte_api:
enable: false
app_id: #<app_id>
like: true
comments: true
num_of_posts: 10

# Star rating support to each article.
# To get your ID visit https://widgetpack.com
rating:
enable: false
id: #<app_id>
color: fc6423
# ---------------------------------------------------------------

# Show number of visitors to each article.
# You can visit https://leancloud.cn get AppID and AppKey.
leancloud_visitors:
enable: false
app_id: #<app_id>
app_key: #<app_key>

# Another tool to show number of visitors to each article.
# visit https://console.firebase.google.com/u/0/ to get apiKey and projectId
# visit https://firebase.google.com/docs/firestore/ to get more information about firestore
firestore:
enable: false
collection: articles #required, a string collection name to access firestore database
apiKey: #required
projectId: #required
bluebird: false #enable this if you want to include bluebird 3.5.1(core version) Promise polyfill

# Show PV/UV of the website/page with busuanzi.
# Get more information on http://ibruce.info/2015/04/04/busuanzi/
busuanzi_count:
# count values only if the other configs are false
enable: false
# custom uv span for the whole site
site_uv: true
site_uv_header: <i class="fa fa-user"></i>
site_uv_footer:
# custom pv span for the whole site
site_pv: true
site_pv_header: <i class="fa fa-eye"></i>
site_pv_footer:
# custom pv span for one page only
page_pv: true
page_pv_header: <i class="fa fa-file-o"></i>
page_pv_footer:


# Tencent analytics ID
# tencent_analytics:

# Tencent MTA ID
# tencent_mta:


# Enable baidu push so that the blog will push the url to baidu automatically which is very helpful for SEO
baidu_push: false

# Google Calendar
# Share your recent schedule to others via calendar page
#
# API Documentation:
# https://developers.google.com/google-apps/calendar/v3/reference/events/list
calendar:
enable: false
calendar_id: <required>
api_key: <required>
orderBy: startTime
offsetMax: 24
offsetMin: 4
timeZone:
showDeleted: false
singleEvents: true
maxResults: 250

# Algolia Search
algolia_search:
enable: false
hits:
per_page: 10
labels:
input_placeholder: Search for Posts
hits_empty: "We didn't find any results for the search: ${query}"
hits_stats: "${hits} results found in ${time} ms"

# Local search
# Dependencies: https://github.com/flashlab/hexo-generator-search
local_search:
enable: false
# if auto, trigger search by changing input
# if manual, trigger search by pressing enter key or search button
trigger: auto
# show top n results per article, show all results by setting to -1
top_n_per_article: 1


# ---------------------------------------------------------------
# Tags Settings
# ---------------------------------------------------------------

# External URL with BASE64 encrypt & decrypt.
# Usage: {% exturl text url "title" %}
# Alias: {% extlink text url "title" %}
exturl: false

# Note tag (bs-callout).
note:
# Note tag style values:
# - simple bs-callout old alert style. Default.
# - modern bs-callout new (v2-v3) alert style.
# - flat flat callout style with background, like on Mozilla or StackOverflow.
# - disabled disable all CSS styles import of note tag.
style: simple
icons: false
border_radius: 3
# Offset lighter of background in % for modern and flat styles (modern: -12 | 12; flat: -18 | 6).
# Offset also applied to label tag variables. This option can work with disabled note tag.
light_bg_offset: 0

# Label tag.
label: true

# Tabs tag.
tabs:
enable: true
transition:
tabs: false
labels: true
border_radius: 0


#! ---------------------------------------------------------------
#! DO NOT EDIT THE FOLLOWING SETTINGS
#! UNLESS YOU KNOW WHAT YOU ARE DOING
#! ---------------------------------------------------------------

# Use velocity to animate everything.
motion:
enable: true
async: false
transition:
# Transition variants:
# fadeIn | fadeOut | flipXIn | flipXOut | flipYIn | flipYOut | flipBounceXIn | flipBounceXOut | flipBounceYIn | flipBounceYOut
# swoopIn | swoopOut | whirlIn | whirlOut | shrinkIn | shrinkOut | expandIn | expandOut
# bounceIn | bounceOut | bounceUpIn | bounceUpOut | bounceDownIn | bounceDownOut | bounceLeftIn | bounceLeftOut | bounceRightIn | bounceRightOut
# slideUpIn | slideUpOut | slideDownIn | slideDownOut | slideLeftIn | slideLeftOut | slideRightIn | slideRightOut
# slideUpBigIn | slideUpBigOut | slideDownBigIn | slideDownBigOut | slideLeftBigIn | slideLeftBigOut | slideRightBigIn | slideRightBigOut
# perspectiveUpIn | perspectiveUpOut | perspectiveDownIn | perspectiveDownOut | perspectiveLeftIn | perspectiveLeftOut | perspectiveRightIn | perspectiveRightOut
post_block: fadeIn
post_header: slideDownIn
post_body: slideDownIn
coll_header: slideLeftIn
# Only for Pisces | Gemini.
sidebar: slideUpIn

# Fancybox
fancybox: true

# Progress bar in the top during page loading.
pace: false
# Themes list:
#pace-theme-big-counter
#pace-theme-bounce
#pace-theme-barber-shop
#pace-theme-center-atom
#pace-theme-center-circle
#pace-theme-center-radar
#pace-theme-center-simple
#pace-theme-corner-indicator
#pace-theme-fill-left
#pace-theme-flash
#pace-theme-loading-bar
#pace-theme-mac-osx
#pace-theme-minimal
# For example
# pace_theme: pace-theme-center-simple
pace_theme: pace-theme-minimal

# Canvas-nest
canvas_nest: false

# three_waves
three_waves: false

# canvas_lines
canvas_lines: false

# canvas_sphere
canvas_sphere: false

# Only fit scheme Pisces
# Canvas-ribbon
# size: The width of the ribbon.
# alpha: The transparency of the ribbon.
# zIndex: The display level of the ribbon.
canvas_ribbon:
enable: false
size: 300
alpha: 0.6
zIndex: -1

# Script Vendors.
# Set a CDN address for the vendor you want to customize.
# For example
# jquery: https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js
# Be aware that you should use the same version as internal ones to avoid potential problems.
# Please use the https protocol of CDN files when you enable https on your site.
vendors:
# Internal path prefix. Please do not edit it.
_internal: lib

# Internal version: 2.1.3
jquery:

# Internal version: 2.1.5
# See: http://fancyapps.com/fancybox/
fancybox:
fancybox_css:

# Internal version: 1.0.6
# See: https://github.com/ftlabs/fastclick
fastclick:

# Internal version: 1.9.7
# See: https://github.com/tuupola/jquery_lazyload
lazyload:

# Internal version: 1.2.1
# See: http://VelocityJS.org
velocity:

# Internal version: 1.2.1
# See: http://VelocityJS.org
velocity_ui:

# Internal version: 0.7.9
# See: https://faisalman.github.io/ua-parser-js/
ua_parser:

# Internal version: 4.6.2
# See: http://fontawesome.io/
fontawesome:

# Internal version: 1
# https://www.algolia.com
algolia_instant_js:
algolia_instant_css:

# Internal version: 1.0.2
# See: https://github.com/HubSpot/pace
# Or use direct links below:
# pace: //cdn.bootcss.com/pace/1.0.2/pace.min.js
# pace_css: //cdn.bootcss.com/pace/1.0.2/themes/blue/pace-theme-flash.min.css
pace:
pace_css:

# Internal version: 1.0.0
# https://github.com/hustcc/canvas-nest.js
canvas_nest:

# three
three:

# three_waves
# https://github.com/jjandxa/three_waves
three_waves:

# three_waves
# https://github.com/jjandxa/canvas_lines
canvas_lines:

# three_waves
# https://github.com/jjandxa/canvas_sphere
canvas_sphere:

# Internal version: 1.0.0
# https://github.com/zproo/canvas-ribbon
canvas_ribbon:

# Internal version: 3.3.0
# https://github.com/ethantw/Han
han:

# needMoreShare2
# https://github.com/revir/need-more-share2
needMoreShare2:


# Assets
css: css
js: js
images: images

# Theme version
version: 5.1.4

python打包成exe可执行文件

发表于 2019-06-02 | 分类于 pyhton

安装 pyinstaller

1
pip install pyinstaller

打包

1
pyinstaller -F hello.py

打包好的exe文件放在dist文件夹中

打包时加入-w 参数,那么执行 exe文件时将不会有小黑窗

1
pyinstaller -F -w hello.py

注意

如果打包过程中出现ModuleNotFoundError: No module named 'setuptools._vendor' 错误,那么执行下列命令即可:

1
pip install --upgrade setuptools

Linux下搭建ftp服务器

发表于 2019-06-02 | 分类于 Linux

[TOC]

1. 安装vsftpd

1
yum install vsftpd -y

2. 启动服务

1
service vsftpd start

3. vsftpd的配置

 ftp的配置文件主要有三个,位于/etc/vsftpd/目录下,分别是:

  • ftpusers 该文件用来指定那些用户不能访问ftp服务器。
  • user_list 该文件用来指示的默认账户在默认情况下也不能访问ftp
  • vsftpd.conf vsftpd的主配置文件

4. 修改登录方式

默认是匿名登录的,如果你想通过账户去登录则修改vsftpd.conf文件

1
2
3
4
5
6
7
8
9
10
11
12
# 允许匿名登录 
anonymous_enable=YES
# 设置匿名用户的登录目录
anon_root=/var/ftp/pub
# 打开匿名用户的上传权限
anon_upload_enable=YES
# 开启匿名用户的下载权限
anon_world_readable_only=no
# 打开匿名用户创建目录的权限
anon_mkdir_write_enable=YES
# 打开匿名用户删除和重命名的权限
anon_other_write_enable=YES

注意:里面有的配置可能vsftpd.conf 里面没有,则需要你手动添加

5. 创建匿名用户可上传文件夹

默认情况下,ftp的根目录为/var/ftp,为了安全,这个目录默认不允许设置为777权限,否则ftp将无法访问。但是我们要匿名上传文件,需要“other”用户的写权限,正确的做法:
在/var/ftp中建立一个upload(名子自己起吧)文件夹,将个文件夹权限设置为777(视具体需要自己设),在upload这个文件夹中,匿名用户可以上传文件、创建文件夹、删除文件等。

1
2
3
cd /var/ftp/pub
mkdir upload
chmod 777 upload

6. 非匿名账户的创建与使用

1
2
useradd pibigstar
passwd pibigstar #为pibigstar用户创建密码

7. 访问

浏览器或者计算机文件管理系统中输入
ftp://你服务器的IP地址

注意:这里默认访问的是 /var/ftp/pub 文件夹下

常见正则表达式剖析

发表于 2019-06-02 | 分类于 Java,正则

没错,又是正则,没办法,这东西入门很简单,但真正能写好,那是真心难,继续学吧。。。
基本语法我在这里就不赘述了,需要的话可以关注我公众号,里面有很详细的语法介绍和示例。

今天我们来针对几个常见的正则来慢慢刨析

电话号码

这个应该是最常用的,没有之一了吧

  • 手机号

中国的手机号码都是11位数字,所以,最简单的表达式就是:

1
[0-9]{11}

不过,目前手机号第1位都是1,第2位取值为3、4、5、7、8之一,所以,更精确的表达式是:

1
1[3|4|5|7|8|][0-9]{9}

为方便表达手机号,手机号中间经常有连字符(即减号’-‘),形如:
186-1234-5678

为表达这种可选的连字符,表达式可以改为:

1
1[3|4|5|7|8|][0-9]-?[0-9]{4}-?[0-9]{4}

在手机号前面,可能还有0、+86或0086,和手机号码之间可能还有一个空格,比如:
018612345678
+86 18612345678
0086 18612345678

为表达这种形式,可以在号码前加如下表达式:

1
((0|\+86|0086)\s?)?

如果为了抽取,也要在左右加环视边界匹配,左右不能是数字。所以,完整的表达式为:

1
(?<![0-9])((0|\+86|0086)\s?)?1[3|4|5|7|8|][0-9]-?[0-9]{4}-?[0-9]{4}(?![0-9])

用Java表示的代码为:

1
2
3
4
5
public static Pattern MOBILE_PHONE_PATTERN = Pattern.compile(
"(?<![0-9])" // 左边不能有数字
+ "((0|\\+86|0086)\\s?)?" // 0 +86 0086
+ "1[3|4|5|7|8|][0-9]-?[0-9]{4}-?[0-9]{4}" // 186-1234-5678
+ "(?![0-9])"); // 右边不能有数字
  • 固定电话

不考虑分机,中国的固定电话一般由两部分组成:区号和市内号码,区号是3到4位,市内号码是7到8位。区号以0开头,表达式可以为:

1
0[0-9]{2,3}

市内号码表达式为:

1
[0-9]{7,8}

区号可能用括号包含,区号与市内号码之间可能有连字符,如以下形式:
010-62265678
(010)62265678

整个区号是可选的,所以整个表达式为:

1
(\(?0[0-9]{2,3}\)?-?)?[0-9]{7,8}

再加上左右边界环视,完整的Java表示为:

1
2
3
4
5
public static Pattern FIXED_PHONE_PATTERN = Pattern.compile(
"(?<![0-9])" // 左边不能有数字
+ "(\\(?0[0-9]{2,3}\\)?-?)?" // 区号
+ "[0-9]{7,8}"// 市内号码
+ "(?![0-9])"); // 右边不能有数字

身份证号码

身份证有一代和二代之分,一代是15位数字,二代是18位,都不能以0开头,对于二代身份证,最后一位可能为x或X,其他是数字。

一代身份证表达式可以为:

1
[1-9][0-9]{14}

二代身份证可以为:

1
[1-9][0-9]{16}[0-9xX]

这两个表达式的前面部分是相同的,二代身份证多了如下内容:

1
[0-9]{2}[0-9xX]

所以,它们可以合并为一个表达式,即:

1
[1-9][0-9]{14}([0-9]{2}[0-9xX])?

加上左右边界环视,完整的Java表示为:

1
2
3
4
5
public static Pattern ID_CARD_PATTERN = Pattern.compile(
"(?<![0-9])" // 左边不能有数字
+ "[1-9][0-9]{14}" // 一代身份证
+ "([0-9]{2}[0-9xX])?" // 二代身份证多出的部分
+ "(?![0-9])"); // 右边不能有数字

符合这个要求的就一定是身份证号码吗?当然不是,身份证还有一些其他的要求,这里就不探究了

邮箱

完整的Email规范比较复杂,我们先看一些实际中常用的。

比如新浪邮箱,它的格式如:

1
abc@sina.com

对于用户名部分,它的要求是:4-16个字符,可使用英文小写、数字、下划线,但下划线不能在首尾。
怎么验证用户名呢?可以为:

1
[a-z0-9][a-z0-9_]{2,14}[a-z0-9]

新浪邮箱的完整Java表达式为:

1
2
3
4
public static Pattern SINA_EMAIL_PATTERN = Pattern.compile(
"[a-z0-9]"
+ "[a-z0-9_]{2,14}"
+ "[a-z0-9]@sina\\.com");

我们再来看QQ邮箱,它对于用户名的要求为:

  1. 3-18字符,可使用英文、数字、减号、点或下划线
  2. 必须以英文字母开头,必须以英文字母或数字结尾
  3. 点、减号、下划线不能连续出现两次或两次以上

如果只有第一条,可以为:

1
[-0-9a-zA-Z._]{3,18}

为满足第二条,可以改为:

1
[a-zA-Z][-0-9a-zA-Z._]{1,16}[a-zA-Z0-9]

怎么满足第三条呢?可以使用边界环视,左边加如下表达式:

1
(?![-0-9a-zA-Z._]*(--|\.\.|__))

完整表达式可以为:

1
(?![-0-9a-zA-Z._]*(--|\.\.|__))[a-zA-Z][-0-9a-zA-Z._]{1,16}[a-zA-Z0-9]

QQ邮箱的完整Java表达式为:

1
2
3
4
5
public static Pattern QQ_EMAIL_PATTERN = Pattern.compile(
"(?![-0-9a-zA-Z._]*(--|\\.\\.|__))" // 点、减号、下划线不能连续出现两次或两次以上
+ "[a-zA-Z]" // 必须以英文字母开头
+ "[-0-9a-zA-Z._]{1,16}" // 3-18位 英文、数字、减号、点、下划线组成
+ "[a-zA-Z0-9]@qq\\.com"); // 由英文字母、数字结尾

以上都是特定邮箱服务商的要求,一般的邮箱是什么规则呢?一般而言,以@作为分隔符,前面是用户名,后面是域名。
用户名的一般规则是:

  1. 由英文字母、数字、下划线、减号、点号组成
  2. 至少1位,不超过64位
  3. 开头不能是减号、点号和下划线

比如:
pibigstar@example.com

这个表达式可以为:

1
[0-9a-zA-Z][-._0-9a-zA-Z]{0,63}

域名部分以点号分隔为多个部分,至少有两个部分。最后一部分是顶级域名,由2到3个英文字母组成,表达式可以为:

1
[a-zA-Z]{2,3}

对于域名的其他点号分隔的部分,每个部分一般由字母、数字、减号组成,但减号不能在开头,长度不能超过63个字符,表达式可以为:

1
[0-9a-zA-Z][-0-9a-zA-Z]{0,62}

所以,域名部分的表达式为:

1
([0-9a-zA-Z][-0-9a-zA-Z]{0,62}\.)+[a-zA-Z]{2,3}

完整的Java表示为:

1
2
3
4
5
public static Pattern GENERAL_EMAIL_PATTERN = Pattern.compile(
"[0-9a-zA-Z][-._0-9a-zA-Z]{0,63}" // 用户名
+ "@"
+ "([0-9a-zA-Z][-0-9a-zA-Z]{0,62}\\.)+" // 域名部分
+ "[a-zA-Z]{2,3}"); // 顶级域名

日期

日期的表示方式有很多种,我们只看一种,形如:
2017-06-21
2016-11-1

年月日之间用连字符分隔,月和日可能只有一位。
最简单的正则表达式可以为:

1
\d{4}-\d{1,2}-\d{1,2}

年一般没有限制,但月只能取值1到12,日只能取值1到31,怎么表达这种限制呢?

对于月,有两种情况,1月到9月,表达式可以为:

1
0?[1-9]

10月到12月,表达式可以为:

1
1[0-2]

所以,月的表达式为:

1
(0?[1-9]|1[0-2])

对于日,有三种情况:
1到9号,表达式为:0?[1-9]
10号到29号,表达式为:[1-2][0-9]
30号和31号,表达式为:3[01]
所以,整个表达式为:

1
\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2][0-9]|3[01])

加上左右边界环视,完整的Java表示为:

1
2
3
4
5
6
public static Pattern DATE_PATTERN = Pattern.compile(
"(?<![0-9])" // 左边不能有数字
+ "\\d{4}-" // 年
+ "(0?[1-9]|1[0-2])-" // 月
+ "(0?[1-9]|[1-2][0-9]|3[01])"// 日
+ "(?![0-9])"); // 右边不能有数字

URL

URL的格式比较复杂,我们只考虑http协议,其通用格式是:

1
http://<host>:<port>/<path>?<searchpart>

开始是http://,接着是主机名,主机名之后是可选的端口,再之后是可选的路径,路径后是可选的查询字符串,以?开头。

主机名中的字符可以是字母、数字、减号和点号,所以表达式可以为:

1
[-0-9a-zA-Z.]+

端口部分可以写为:

1
(:\d+)?

路径由多个子路径组成,每个子路径以/开头,后跟零个或多个非/的字符,简单的说,表达式可以为:

1
(/[^/]*)*

更精确的说,把所有允许的字符列出来,表达式为:

1
(/[-\w$.+!*'(),%;:@&=]

对于查询字符串,简单的说,由非空字符串组成,表达式为:

1
\?[\S]*

更精确的,把所有允许的字符列出来,表达式为:

1
\?[-\w$.+!*'(),%;:@&=]*

路径和查询字符串是可选的,且查询字符串只有在至少存在一个路径的情况下才能出现,其模式为:

1
(/<sub_path>(/<sub_path>)*(\?<search>)?)?

所以,路径和查询部分的简单表达式为:

1
(/[^/]*(/[^/]*)*(\?[\S]*)?)?

精确表达式为:

1
(/[-\w$.+!*'(),%;:@&=]*(/[-\w$.+!*'(),%;:@&=]*)*(\?[-\w$.+!*'(),%;:@&=]*)?)?

HTTP的完整Java表达式为:

1
2
3
4
5
6
7
8
public static Pattern HTTP_PATTERN = Pattern.compile(
"http://" + "[-0-9a-zA-Z.]+" // 主机名
+ "(:\\d+)?" // 端口
+ "(" // 可选的路径和查询 - 开始
+ "/[-\\w$.+!*'(),%;:@&=]*" // 第一层路径
+ "(/[-\\w$.+!*'(),%;:@&=]*)*" // 可选的其他层路径
+ "(\\?[-\\w$.+!*'(),%;:@&=]*)?" // 可选的查询字符串
+ ")?"); // 可选的路径和查询 - 结束

IP地址

IP地址格式如下:

1
192.168.112.110

点号分隔,4段数字,每个数字范围是0到255。最简单的表达式为:

1
(\d{1,3}\.){3}\d{1-3}

\d{1,3}太简单,没有满足0到255之间的约束,要满足这个约束,就要分多种情况考虑。

值是1位数,前面可能有0到2个0,表达式为:

1
0{0,2}[0-9]

值是两位数,前面可能有一个0,表达式为:

1
0?[0-9]{2}

值是三位数,又要分为多种情况。以1开头的,后两位没有限制,表达式为:

1
1[0-9]{2}

以2开头的,如果第二位是0到4,则第三位没有限制,表达式为:

1
2[0-4][0-9]

如果第二位是5,则第三位取值为0到5,表达式为:

1
25[0-5]

所以,\d{1,3}更为精确的表示为:

1
(0{0,2}[0-9]|0?[0-9]{2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])

所以,加上左右边界环视,IP地址的完整Java表示为:

1
2
3
4
5
public static Pattern IP_PATTERN = Pattern.compile(
"(?<![0-9])" // 左边不能有数字
+ "((0{0,2}[0-9]|0?[0-9]{2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}"
+ "(0{0,2}[0-9]|0?[0-9]{2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])"
+ "(?![0-9])"); // 右边不能有数字

MySQL实战45讲学习笔记(1~7)

发表于 2019-05-27 | 分类于 数据库,面试,mysql

本文为极客时间《MySQL实战45讲》的总结笔记,如有侵权,请通知我,将立马删除。建议大家去购买这套课程,真的是物有所值。

1、2一条语句的执行过程

1. Mysql结构

数据库总共分为两大部分:Server层和存储层,其中Server层又分为:连接器、(查询缓存)、分析器、优化器和执行器。存储层是以插件的形式,常见的有InnoDB和MyISAM。

2. 查询语句(select * from T where id = 2)

  1. 通过连接器获取连接
  2. 查看语句是存在于查询缓存中,如果存在则直接返回,不存在则进行 步骤3,Mysql 8.0版本之后已经去掉了查询缓存功能
  3. 通过分析器判断SQL语句是否正确(要做什么)
  4. 通过优化器判断使用哪个索引去查询(怎么做)
  5. 执行器判断是否拥有该表权限,如果有则调用存储引擎的拿第一条数据的接口,判断id是否是等于2,如果不等则调用拿下一条数据的接口,如果等于则将结果放入到结果集中,继续判断下一条。

3. 日志

mysql中的日志分为两个部分:redo log 和 binlog。
redo log :这个服务于存储引擎, 这个是InnoDB引擎特有的日志系统
binlog : 这个服务于Server层,是所有引擎都可以使用的。

redo log 是为了减少磁盘的读写和crash-safe而产生的,它记录了更新、删除、插入语句,当Mysql空闲时就从redo log中读取这些日志,把数据更新到磁盘中。而binlog是记录做了哪些事情,当我们恢复备份信息时,可以读取binlog中的记录,然后去执行redo log中的记录去恢复信息。

4. 更新语句(update T c = c+1 where id = 2)

  1. 执行器找存储引擎拿到 id = 2 这一行记录,id是主键,存储引擎直接通过树搜索找到这一行记录,如果这一行所在的数据页在内存中则直接返回,如果不在则去读取磁盘到内存中再返回。
  2. 执行器拿到这一行记录,将 c 列的值 +1 得到一行新数据,然后再调用存储引擎接口写入这行新数据
  3. 存储引擎拿到这行数据写入到内存中,同时将这个更新操作记录到redo log日志中,此时redo log处于prepare状态,并告诉执行器可以提交事务了
  4. 执行器生成这个操作的binlog,并把binlog写入到磁盘中。
  5. 执行器调用存储引擎的提交事务的接口,存储引擎把刚刚写入的redo log日志状态更新为commit,这也就是两阶段提交

3. 事务隔离

3.1 事务隔离的特性

ACID:原子性、一致性、隔离性、持久性

3.2 事务的隔离级别

  • 读未提交:一个事务还未提交,其他事务就可以看到它做的更改
  • 读已提交:一个事务在提交之后,其他事务才能看到它的更改
  • 可重复读:一个事务是启动和提交之间读到数据是一致的,它在未提交时,其他事务无法看到它做的更改
  • 串行化:对同一行记录,写会加写锁,读会加读锁,当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完才能继续执行。

修改隔离级别:设置参数:transaction-isolation

3.3 事务隔离的实现

每条记录在更新的时候都会记录一条回滚操作,记录上的最新值通过回滚操作都能回到它上一个版本,同一条记录在系统中可以存在多个版本,这就是数据库的多版本并发控制(MVCC)

3.4 回滚日志

  • 回滚日志什么时候删除?
    系统会判断当没有实物需要用到这些回滚日志的时候,回滚日志会被删除。
  • 什么时候不需要?
    当系统中没有比这个回滚日志更早的read-view的时候

    3.5 为什么尽量不使用长事务?

    长事务意味着系统里面会存在很老的事务视图,在这个事务提交之前,回滚记录都要保留,这会导致大量占用存储空间。除此之外,长事务还会占用锁资源,可能会拖垮整个库。

4、5 深入浅出索引(上,下)

4.1 索引的实现方式有哪些

  • 哈希表

    将值放到数组里,然后用哈希函数将key换算为一个确定的位置 ,将value放到数组的这个位置,当哈希冲突时,会拉出一个链表进行保存。适用场景:只适合等值查询情况,不适合用于范围查询

  • 有序数组

    将值按顺序放入到数组中,可采用二分法查询,时间复杂度为O(lg(N)),但是插入比较麻烦,需要移动很多值。适用场景:不再变化的值。

  • 二叉树搜索树

    每个结点的左儿子小于父节点,右儿子大于父节点,平衡二叉树是搜索速度最快的数据结构,但是索引不仅存在于内存,也要存储到硬盘中,如果用平衡二叉树,那么100万的数据就是一个树高20的二叉树,对应磁盘就是20个数据块,要查询一个数据要访问20个数据块,这就很慢了。

  • N叉树

    N叉树顾名思义就是每个节点有N儿子,儿子之间从左到右递增。它是为了解决二叉树占用数据块太多而产生的。

4.2 Innodb引擎使用的索引

Innodb是使用B+树来存储数据的。每一张表其实就是由多个B+树组成的,树结点的key值就是某一行的主键,value是该行的其他数据。每一个索引都会创建一个B+树。

4.3 索引的类型

索引分为主键索引和非主键索引,主键索引的叶子结点存放的是这一行的数据,而非主键索引的叶子结点存放的是主键索引的值。当使用主键索引去查询时可以直接获取到该行数据,而使用非主键索引去查询时,先拿到主键的值,再根据主键获取到该行数据,这个过程被称为回表

4.4 覆盖索引

表 user,id(主键),name(普通索引)

当我们想查询 name = 张三 的id 时我们可以使用

1
select * from user where name = '张三'

这条语句的执行过程为:先去索引树name中找到张三拿到张三的id,再去主键索引树中根据id拿到这条记录,而我们只是需要它的id的,使用这条语句会进行一次回表操作,所以我们可以改为下面语句:

1
select id from user where name = '张三'

这种方式就叫做覆盖索引,我们可以通过一些联合索引的方式去避免进行二次回表操作。

4.5 索引最左前缀

表 user,id(主键),gender(性别),name(姓名),age(年龄)
联合索引(name,age)

当我们查询姓张并且年龄为10岁的男孩时:

1
select * from user where name like '张%' and age = 10 and gender = 1

它会先找到第一个姓张的记录,然后再向后依次遍历,这种就避免了全表扫描。

一般来说如果建立了 (a,b)联合索引,就不需要在a上单独建立一个索引了,但是如果是根据b来查,那么还是需要在b上建立索引。

6.全局锁和表级锁

61. 全局锁

全局锁即是锁住整个数据库,mysql提供了一个加全局读锁的语句(FTWRL):

1
flush table with read lock

加完全局读锁之后,数据库整个的更新,删除,添加语句都会被阻塞,这个使用场景就是数据库备份。但是让数据库处于只读状态,这种方式就会让所有更新被阻塞,整个业务就会停摆。这时我们可以使用官方为我们提供的数据库备份工具mysqldump,通过--single-transaction参数来确保拿到一致性视图:

1
2
备份:mysqldump --single-transaction -u用户名 -p密码 数据库名 > back.sql
恢复:mysql -u用户名 -p密码 -f 数据库名< back.sql

这样在备份数据库之前就会启动一个事务,来确保拿到一致性视图,采用这种方式数据库也可以正常更新的。但这种方式有种局限性,那就是必须支持事务,而myisam存储引擎就不支持事务,所以还是得采用全局锁的方式。

问 : 让数据库处于只读状态为什么不用set global readonly=true ?
这是因为使用readonly的话,一旦客户端出现异常,那么整个数据库都处于不可用状态了,而使用 FTWRL一旦客户端出现异常,那么就会自动释放这个锁,整个数据库即可恢复到正常状态(可读可写)。

6.2 表级锁

mysql中的表级锁有两种,一种就是表锁,另一种是元数据锁(MDL):meta data lock。

6.2.1 表锁

mysql添加表锁可采用下面语句

1
lock tables 表名 read,表名 write

释放锁和FTWRL类似,当客户端出现异常后也会自动释放锁。也可手动释放:

1
unlock tables 表名

6.2.2 元数据锁(MDL)

元数据锁是隐式锁,当访问某一张表时,数据库自动加的锁。

  • 当对表增删改查时:加MDL读锁
  • 当更改表结构时:加MDL写锁

读锁之间不互斥,也就是多个线程可以同时对一个表进行增删改查,但是读写锁和写写锁之间互斥,也即是当更改表结构时要等待读锁或写锁释放后才能进行更改。

问:为什么我就给表加个字段,数据库就崩了?
如果在更改表结构之前有一个长事务在操作表(MDL读锁),当我们去添加表中一个字段时那么这个操作会添加一个MDL写锁,由于读写锁互斥,那么这个MDL写锁就会被阻塞,以至于后面的增删改查操作要加MDL读锁的都会被阻塞下去。

为了更加安全的更改表结构我们可以使用下面语句:

1
alert table 表名 wait 5 add colunm 列名

这个会等待5秒,如果5秒钟拿不到MDL写锁,那么就不再继续阻塞,也就可以后面的操作继续进行下去。

7. 行锁

行锁是在引擎层实现的,但不是每个引擎都支持行锁,像MyISAM引擎就不支持行锁,它想控制并发就只能加表锁。

行锁是有需要时才添加的,但释放是在事务提交之后才进行释放的(两阶段锁),根据这个特性,如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。

举个例子:用户A在电影院B买一张电影票(3元)需要下面三个过程:

  1. 从用户A账户中扣掉 3 元
  2. 在电影院B的余额中增加 3 元
  3. 记录一条交易日志

这个三个过程是放在一个事务中的,但是 2 过程是最可能造成锁冲突的,因为其他用户买了票之后也要在电影院B的余额中增加 3 元,所以我们要把最可能造成锁冲突的放在后面,这样电影院B余额这一行的锁时间就最少,我们调整顺序为:3 、 1 、 2

7.1 死锁和死锁检测

事务A在等待事务B释放id=2的行锁,而事务B在等待事务A释放id=1的行锁,事务A和事务B互相等待对方的资源释放,这就造成了死锁。

死锁解决

  1. 超时释放
    设置超时时间,通过参数innodb_lock_wait_timeout设置,当超过这个时间之后将自动释放锁资源。默认是50s
  2. 死锁检测
    设置innodb_deadlock_detect为on来开启死锁检测,但它会造成额外的负担,每当一个事务被锁的时候,就要看看它所依赖的线程有没有被别人锁住,如此循环,最后判断是否出现了循环等待,也就是死锁。

JS操作表格常用操作及事件委派

发表于 2019-05-24 | 分类于 js

JS操作表格常用操作及事件委派

1. 点击添加一行表格

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
function addRow() {
// 获取当前有多少行(查找第一列序号值)
last_num = $("#myTabletr:last-child").children("td").find("input").val();
if (last_num == null) {
last_num = 1;
}
else {
last_num = parseInt(last_num);
last_num += 1;
}
// 获取表格对象
let table = document.getElementById("myTable");
// 插入一行
let row = table.insertRow();
// 插入四列
let cell0 = row.insertCell();//序号
let cell1= row.insertCell(); //名称
let cell2 = row.insertCell();//年龄
let cell3 = row.insertCell();//操作
// 插入列的内容
cell0.innerHTML = '<input readonly="true" value='+ last_num +'>';
cell1.innerHTML = '<input name="username"placeholder="输名称">';
cell2.innerHTML = '<input name="age" placeholder="输入年龄">';
cell3.innerHTML = '<a class="btn-link deleteRowInfo">删除</a>';
}

2. 删除一行

1
2
3
4
5
6
7
8
9
10
11
12
13
 $(document).on('click','.deleteRowInfo',function() {
// 获取当前点击的哪一行
let currentTrIndex = $(this).parent().parent().index();
// 获取表格对象
let table = document.getElementById("myTable");
// 删除行
table.deleteRow(index);
// 更新序号
$("#myTable").find("tr").each(function(index,item){
let tdArr = $(this).children();
tdArr.eq(0).find("input").val(index + 1);
});
});

3. 获取表格中的值转为JSON字符串

1
2
3
4
5
6
7
8
9
10
11
 function getData() {
let data = [];
$("#myTable").find("tr").each(function (i) {
data[i] = new Object();
data[i].username= $(this).find("input[name='username']").val()
data[i].age= $(this).find("input[name='age']").val()
});
// 转为json字符串
let strData = JSON.stringify(data);
return strData;
}

4. 添加一列

姓名 派大星 海绵宝宝
年龄 22 25
1
2
3
4
5
6
7
8
9
 $(".addBtn").click(function () {
// 获取模态框中输入值
let username= $(".username").val();
let age= $(".age").val();
// 第一行添加一列
$("#usernameTr").append('<td>'+username+'<i class="icon-delete deleteCellInfo hidden"></i></td>');
// 第二行添加一列
$("#ageTr").append('<td>'+age+'</td>');
});

5. 删除一列

1
2
3
4
5
6
7
8
9
10
11
// 当鼠标移动到每一列时会有个删除按钮显示,点击这个删除按钮,删除此列
$(document).on('click','.deleteCellInfo',function() {
// 获取当前点击的是第几列
var currentCell =$("#usernameTr td i").index(this) + 1;
// 获取表格对象
let table=document.getElementById("myTable");
// 删除第一行中此列
table.rows[0].deleteCell(currentCell);
// 删除第二行中此列
table.rows[1].deleteCell(currentCell);
});

6. 事件委派

因为是动态添加的表格,所以没办法直接为新添加的元素添加事件监听,这个时候就需要用到了事件委派。其实也就是为页面渲染完成后添加的新元素加上事件。

上面新添加列,我们为每一个新添加的列都添加一个鼠标移入移出事件,当鼠标移入到此列上时将删除图标显示出来。

jQuery写法:使用delegate

1
2
3
4
5
6
7
8
// 鼠标移入时将删除hidden属性将删除图标显示出来
$('#usernameTr').delegate('td', 'mouseover', function(ev){
$(this).find("i").removeClass("hidden");
});
// 鼠标移出时将删除图标隐藏
$('#usernameTr').delegate('td', 'mouseout', function(ev){
$(this).find("i").addClass("hidden");
});

Nginx使用总结

发表于 2019-05-24 | 分类于 Java,nginx

@[toc]

前期准备

windows

1.下载nginx, 点击下载

  1. 解压并启动nginx, 双击nginx.exe
  2. 测试是否启动,访问 http://127.0.0.1
  3. 下载tomcat8111(端口为8111的tomcat)点击 这里下载
  4. 下载tomcat8222(端口为8222的tomcat)点击这里下载

linux

1
2
3
4
5
6
7
8
9
10
11
12
# 安装Nginx源库
yum install epel-release
# 安装Nginx
yum install nginx
# 查看是否安装成功
nginx -v
# 查看配置文件地址
nginx -t
# 启动
nginx
# 停止
nginx -s stop

1. 反向代理

1.1 概念

先说正向代理,比如要访问youtube,但是不能直接访问,只能先找个翻墙软件,通过翻墙软件才能访问youtube. 翻墙软件就叫做正向代理。
所谓的反向代理,指的是用户要访问youtube,但是youtube悄悄地把这个请求交给bilibili来做,那么bilibili就是反向代理了。
在当前教程指的就是访问nginx,但是nginx把请求交给tomcat来做。

1.2 实现

修改 nginx.conf 文件

1
2
3
location / {
proxy_pass http://127.0.0.1:8111;
}

location / 表示处理所有请求
proxy_pass http://127.0.0.1:8111 表示把请求都交给:http://127.0.0.1:8111 (tomcat的访问地址)来处理

1.3 访问

1、启动tomcat (端口为8111)
2、 重启nginx

1
nginx -s reload

3、 访问地址
http://127.0.0.1 就会发现已经反向代理到:http://127.0.0.1:8111

2. 动静分离

2.1 概念

所谓的动静分离就是指图片,css, js之类的都交给nginx来处理,nginx处理不了的,比如jsp 就交给tomcat来处理~

好处是nginx处理静态内容的吞吐量很高,比tomcat高多了,这样无形中提升了性能。

2.2 实现

修改nginx.conf文件

在locaction下面添加一个新的location:

1
2
3
   location ~\.(css|js|png)$ {
root D:/tomcat_8111/webapps/ROOT;
}

这表示所有的css js png访问都由nginx来做,访问的地址是:
D:/tomcat_8111/webapps/ROOT

jsp中:

3. 负载均衡

3.1 概念

负载均衡的概念就是当访问量很大的时候,一个 Tomcat 吃不消了,这时候就准备多个 Tomcat,由Nginx按照权重来对请求进行分配,从而缓解单独一个Tomcat受到的压力

3.2 启动两个tomcat

记得要修改两个tomcat的端口,两个tomcat的端口不能一样,
这里我们使用8111端口和8222端口

3.3 修改nginx.conf文件

首先增加一个upstream ,用来指向这两个tomcat

1
2
3
4
upstream tomcat_8111_8222{
server 127.0.0.1:8111 weight=1;
server 127.0.0.1:8222 weight=2;
}

然后修改location,反向代理到上述配置。

1
2
3
     location / {
proxy_pass http://tomcat_8111_8222;
}

weight表示权重,值越大,被分配到的几率越大。

3.4 重启nginx并访问

4. session共享

4.1 概念

通过负载均衡课程,我们可以把请求分发到不同的 Tomcat 来缓解服务器的压力,但是这里存在一个问题: 当同一个用户第一次访问tomcat_8111 并且登录成功, 而第二次访问却被分配到了tomcat_8222, 这里并没有记录他的登陆状态,那么就会呈现未登录状态了,严重伤害了用户体验。

4.2 解决办法(一)

通过ip地址标记用户,如果多次请求都是从同一个ip来的,那么就都分配到同一个tomcat.
这样就不会出现负载均衡 session问题了. 处理手段也很简单,在nginx.conf 文件中修改upstream结点。如图所示在upstream最后加上ip_hash;就行了。

1
2
3
4
5
upstream tomcat_8111_8222{
server 127.0.0.1:8111 weight=1;
server 127.0.0.1:8222 weight=2;
ip_hash;
}

不过这种方案并不完美,当如下几种情况发生时就有问题:

  1. 大量请求来之某个局域网,那么相当于就没有负载均衡了
  2. 如果tomcat_8111 挂了,那么此时nginx只能把请求交给tomcat_8222,但是这里却没有记录session,用户体验依然受影响。

4.3 解决方法(二)

用Redis来存取session.

Redis是什么呢?说简单点就是个独立的Hashmap,用来存放键值对的。
这样当tomcat1需要保存session值的时候,就可以把它放在Redis上,需要取的时候,也从Redis上取。

那么考虑这个情景:

  1. 用户提交账号密码的行为被分配在了tomcat8111上,登陆信息被存放在redis里。
  2. 当用户第二次访问的时候,被分配到了tomcat8222上
  3. 那么此时tomcat8222就会从redis去获取相关信息,一看有对应信息,那么就会呈现登陆状态。

这样就规避了解决办法一: ip_hash里会出现的两种问题了。

4.3.1 启动redis

1.点击下载
2.解压
3.双击 start.bat 启动

4.3.2 下载jar包

Tomcat需要链接 redis,所以需要专门的jar包,这些包都放在了右上角的tomcat-redis.rar里。 一共
有3个jar包:
jedis-2.5.2.jar,
commons-pool2-2.0.jar,
tomcat-redis-session-manager1.2.jar。
点击 这里下载
下载解压后,放在tomat8111的lib目录下。注:不要放在webapp里面去了
下载解压后,放在tomat8222的lib目录下。注:不要放在webapp里面去了
两个tomcat都要放

4.3.3 修改context.xml文件

修改tomcat/conf/context.xml ,增加下面内容

1
2
3
4
5
6
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />  
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="127.0.0.1"
port="6379"
database="0"
maxInactiveInterval="60" />

两个tomcat都要改

4.3.4 重启tomcat

两个tomcat都要重启

启动完就大功告成了

Centos和Ubuntu安装kubeadm

发表于 2019-05-24 | 分类于 k8s

必须需要更换kubeadm下载源才能安装到

Centos

更换源

1
2
3
4
5
6
7
8
9
10
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

安装

1
yum install kubeadm

Ubuntu

更换源

1
2
3
cat <<EOF > /etc/apt/sources.list.d/kubernetes.list
deb http://mirrors.ustc.edu.cn/kubernetes/apt kubernetes-xenial main
EOF

更新系统源

1
apt-get update

如果提示签名无法验证,则执行下面语句,将 JC054F7C为你执行时显示出的 NO_PUBKEY 的后八位

1
2
gpg --keyserver keyserver.ubuntu.com --recv-keys JC054F7C
gpg --export --armor BA07F4FB | sudo apt-key add -

再次更新

1
apt-get update

安装

1
apt-get install kubeadm

使用java画一张海报

发表于 2019-05-24 | 分类于 Java,java工具类

PS: 没找到合适的海报背景,就随便找了一张,使用技术都是相同的

1. 添加依赖

这俩其实跟本章节的核心技术没有关系,是为了获取QQ昵称和QQ头像而引入的。

1
2
3
4
5
6
7
8
9
10
11
12
<!-- jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>

talk is cheap, show me the code

2.上代码

我就不多说了,注释已经写得很清楚了

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
package com.pibgstar.demo.utils;

import com.alibaba.fastjson.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

/**
* @author pibigstar
* @desc 海报生成工具
**/
public class PosterUtil {
private static final String BACKGROUND_IMG = "images/bg.jpg"; // 背景图片
private static final String result_img = "D:/tmp/images/result.jpg"; // 最终输出图片
private static final String QQ = "741047261";
private static final String avatar_img = "http://q1.qlogo.cn/g?b=qq&nk="+QQ+"&s=100";//QQ获取头像接口
private static final String signature = "魔前一叩三千年,回首凡尘不做仙。"; // 个性签名

public static void main(String[] args){
drawPoster();
}

/**
* @Author:pibigstar
* @Description: 画海报
*/
public static void drawPoster(){
try {
long startTime = System.currentTimeMillis();
// 1. 创建画布
BufferedImage backgroundImg = ImageIO.read(getInputStream(BACKGROUND_IMG));
BufferedImage canvas = new BufferedImage(backgroundImg.getWidth(),backgroundImg.getHeight(),BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) canvas.getGraphics();
// 设置抗锯齿
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);

// 2. 将头像设置为圆角
BufferedImage avatar = ImageIO.read(new URL(avatar_img));
BufferedImage newAvatar = new BufferedImage(avatar.getWidth(), avatar.getHeight(), BufferedImage.TYPE_INT_ARGB);
Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, avatar.getWidth(), avatar.getHeight());
Graphics2D g2 = newAvatar.createGraphics();
newAvatar = g2.getDeviceConfiguration().createCompatibleImage(avatar.getWidth(), avatar.getHeight(), Transparency.TRANSLUCENT);
g2 = newAvatar.createGraphics();
g2.setComposite(AlphaComposite.Clear);
g2.fill(new Rectangle(newAvatar.getWidth(), newAvatar.getHeight()));
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 1.0f));
g2.setClip(shape);
// 使用 setRenderingHint 设置抗锯齿
g2 = newAvatar.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.fillRoundRect(0, 0,avatar.getWidth(), avatar.getHeight(), 150, 150);
g2.setComposite(AlphaComposite.SrcIn);
g2.drawImage(avatar, 0, 0, avatar.getWidth(), avatar.getHeight(), null);
g2.dispose();

// 3. 将背景图和头像结合
// 画背景
g.drawImage(backgroundImg.getScaledInstance(backgroundImg.getWidth(), backgroundImg.getHeight(), Image.SCALE_DEFAULT), 0, 0, null);
// 背景上画头像
g.drawImage(newAvatar.getScaledInstance(100, 100, Image.SCALE_DEFAULT), 42, 35, null);

// 4. 写字(昵称)
g.setColor(new Color(33, 33, 33, 128));
g.setFont(getFont(2, 32.0f));
g.drawString(getNickName(QQ), 200, 75);

// 5. 画个性签名
g.setColor(new Color(33, 33, 33, 128));
g.setFont(getFont(1, 40.0f));
// 画竖着的文字
int x = 240; // 起始位置
int length = signature.length();//字符总长度
int size = length/2; //一竖列的长度
int j = 0; // 读取到那个字符了
for (int i=0; i<2; i++) {//两竖列
int y = 300;
for (;j < size; j++) {
String c = String.valueOf(signature.charAt(j));
y += 40;
g.drawString(c,x,y);
}
size = length;
x += 70;//竖列之间的距离
}
g.dispose();
File resultImg = new File(result_img);
ImageIO.write(canvas, "png", resultImg);

System.out.println("生成成功!");
System.out.println("耗时: " + (System.currentTimeMillis()-startTime)/1000.0 + "s");
System.out.println("生成文件路径: " + resultImg.getAbsolutePath());
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description: 获取QQ昵称,无意间发现的QQ音乐的一个漏洞
*/
private static String getNickName(String qq){
String api = "https://c.y.qq.com/rsc/fcgi-bin/fcg_get_profile_homepage.fcg?cid=205360838&ct=20&userid="+qq+"&reqfrom=1";
String nick = "";
JSONObject creatorObject = null;
try {
Document document = Jsoup.connect(api).ignoreContentType(true).timeout(10000).get();
String body = document.body().text();
JSONObject jsonObject = JSONObject.parseObject(body);
JSONObject dataObject = (JSONObject) jsonObject.get("data");
creatorObject = (JSONObject) dataObject.get("creator");
nick = creatorObject.get("nick").toString();
}catch (Exception e) {
e.printStackTrace();
}
return nick;
}

/**
* 根据字体类型获取字体
* @param type 字体类型
* @param size 字体大小
*/
private static Font getFont(int type, float size) {
// 字体路径
String path;
switch (type) {
case 1:
path = "ttf/JianTi.ttf";
break;
case 2:
path = "ttf/PingFang.ttf";
break;
default:
path = "ttf/JianTi.ttf";
}
InputStream inputStream = null;
try {
inputStream = getInputStream(path);
Font font = Font.createFont(Font.TRUETYPE_FONT, inputStream);
font = font.deriveFont(size);
return font;
} catch (FontFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}

/**
* 获取resources下的文件输入流
*/
private static InputStream getInputStream(String fileName) {
return PosterUtil.class.getClassLoader().getResourceAsStream(fileName);
}
}

3. 目录结构

4. 最终效果

1…678…14
派大星

派大星

137 日志
64 分类
230 标签
GitHub CSDN
© 2019 派大星