-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
1063 lines (1063 loc) · 372 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[SpringMVC请求json,客户端显示406状态码]]></title>
<url>%2F2018%2F03%2F28%2FSpringMVC%E8%AF%B7%E6%B1%82json%EF%BC%8C%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%98%BE%E7%A4%BA406%E7%8A%B6%E6%80%81%E7%A0%81%2F</url>
<content type="text"><![CDATA[问题描述 主要配置: 1234567891011121314151617181920<mvc:message-converters register-defaults="true"> <!-- StringHttpMessageConverter编码为UTF-8,防止乱码 --> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <constructor-arg value="UTF-8"/> <property name = "supportedMediaTypes"> <list> <value>text/plain;charset=UTF-8</value> <value>text/html;charset=UTF-8</value> </list> </property> </bean> <!-- 避免IE执行AJAX时,返回JSON出现下载文件 --> <bean id="fastJsonHttpMessageConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>application/json;charset=UTF-8</value> </list> </property> </bean></mvc:message-converters> 主要方法: 123456789101112131415161718/** * 新增 */@RequestMapping(value = "ajaxCreate", method = RequestMethod.POST)@ResponseBodypublic AjaxResponse ajaxCreate(@Valid @ModelAttribute("m") Sample m, BindingResult result) throws AjaxException { if (permissionList != null) { this.permissionList.assertHasCreatePermission(); } if (hasError(m, result)) { return AjaxResponse.fail(getErrors(result)); } baseService.save(m); return AjaxResponse.ok("新增成功");} 客户端请求: 请求方法 123456789$.ajax({ url: '/showcase/sample/ajaxCreate', type: 'POST', data: form, dataType: 'json', success: function(ret) { // ... }}) 解决过程 这个406错误码几乎没有碰到过,都不知道是什么意思,搜索了解释: HTTP 错误 406406 不可接受根据此请求中所发送的“接受”标题,此请求所标识的资源只能生成内容特征为“不可接受”的响应实体。如果问题依然存在,请与服务器的管理员联系。 顿时懵逼了,不知如何下手,于是谷歌半天,查到如下解决方案 由于使用的是fastjson,所以在官网github上找到了相应的办法 Spring4 MVC json问题(406 Not Acceptable) …… 网络上查询到的解决方案大致都是一样的思路,然而在我的项目中并不起作用,折腾了一下午,解决思路都是围绕着后台,最好我尝试着重请求端去查找问题,于是我比对了以下正常请求与该请求,发现了一个不同: 圈红框的地方就是不同之处,正常的请求头比异常的少了一块 Accept: application/json, text/javascript, */*; q=0.01,试着从此处入手,修改了ajax请求,添加了Accept头: 123456789101112$.ajax({ url: '/showcase/sample/ajaxCreate', type: 'POST', data: form, dataType: 'json', headers: { Accept: 'application/json; charset=utf-8' }, success: function(ret) { // ... }}) 问题解决了 总结有时候解决问题不能太局限了,一开始是围绕着SpringMVC后台去查找问题,各种谷歌、StackOverflow的搜索,也尝试了找到的解决方案,由于每个人的场景肯不一样,所以找到的答案并不一定可以解决你的问题,所以这个时候就需要换个思路去想问题,既然406这个状态码是客户端请求错误,那么可以重客户端请求方面查找问题!]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Java</tag>
<tag>SpringMVC</tag>
<tag>Ajax</tag>
<tag>406</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Java中Bean属性的getter方法定义导致json数据缺失]]></title>
<url>%2F2018%2F03%2F22%2FJava%E4%B8%ADBean%E5%B1%9E%E6%80%A7%E7%9A%84getter%E6%96%B9%E6%B3%95%E5%AE%9A%E4%B9%89%E5%AF%BC%E8%87%B4json%E6%95%B0%E6%8D%AE%E7%BC%BA%E5%A4%B1%2F</url>
<content type="text"><![CDATA[问题描述手头上有一个项目,使用的是 jsp 写的,数据都是使用 jsp 标签来处理的,现在想使用 ajax 请求。有一个页面用到了zTree,数据是用 c:forEach 标签封装的,如下: 12345var zNodes =[ <c:forEach items="${trees}" var="m"> { id:${m.id}, pId:${m.pId}, name:"${m.name}", iconSkin:"${m.iconSkin}", open: true, root : ${m.root},isParent:${m.isParent}}, </c:forEach>]; javaBean如下: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475public class ZTree<ID extends Serializable> implements Serializable { private ID id; private ID pId; private String name; private String iconSkin; private boolean open; private boolean root; private boolean isParent; private boolean nocheck = false; public ID getId() { return id; } public void setId(ID id) { this.id = id; } public ID getpId() { return pId; } public void setpId(ID pId) { this.pId = pId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getIconSkin() { return iconSkin; } public void setIconSkin(String iconSkin) { this.iconSkin = iconSkin; } public boolean isOpen() { return open; } public void setOpen(boolean open) { this.open = open; } public boolean isRoot() { return root; } public void setRoot(boolean root) { this.root = root; } public boolean isIsParent() { return isParent; } public void setIsParent(boolean isParent) { this.isParent = isParent; } public boolean isNocheck() { return nocheck; } public void setNocheck(boolean nocheck) { this.nocheck = nocheck; }} 后台使用 ajax 异步请求该 javaBean 列表,发现 json 有一个属性 pId 始终没有返回,,在返回对象前都有数据,但是到了页面就没有了。 解决办法检查了配置文件,调试了半天,只能从源头查找问题,看到bean,看到 pId,突然想起来getter、setter方法大小写的问题,试着将getter、setter方法修改如下: 1234567public ID getPId() { return pId;}public void setPId(ID pId) { this.pId = pId;} 再ajax请求,数据原样返回来了。 2018-03-23 后来发现使用的 fastjson 的版本太低了,只需要更新 fastjson 的版本,无须修改bean,同样可以解决问题 问题原因javaBean规范javabean规范文档:http://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/,里面的有以下两个章节降到了具体的命名规则: 8.3.1 Simple properties 8.3.2 Boolean properties 8.8 Capitalization of inferred names. 这个文档里面说明了,从getter和setter方法名如何推倒出propertyName: 一般情况,把除去get或者is(如果是boolean类型)后的部分首字母转成小写即可,比如:getFoo –> foo 如果除去get和is后端的部分,首字母和第二个字母都是大写,不作转换即可,比如:getXPath –> XPath 例如: 123456789101112private String getepath --> getGetepath()private String getEpath --> getGetEpath()private String epath --> getEpath() private String ePath --> getePath() // 首字母不用大写private String Epath --> getEpath() // 和epath的getter方法是一样的private String EPath --> getEPath()private boolean isenable --> isIsenable()private boolean isEnable --> isEnable() // 不是把首字母大写并在前面加is,其结果和enable的getter方法相同private boolean enable --> isEnable()private boolean eNable --> iseNable() // 首字母不用大写private boolean Enable --> isEnable() // 和enable的getter方法相同private boolean ENable --> isENable() // 什么时候你需要关注getter和setter方法的生成规则? 想要序列化为json对象时,如果你使用gson的话,基本没啥问题,但要是你使用了低版本的fastjson,那么可能会中枪了 要自己写代码拼装出getter和setter方法名,以此来通过反射查找Method时 编码规范 属性的前两个都以小写开头 boolean类型不要用is开头 参考文章:http://rongmayisheng.com/post/java%E4%B8%AD%E5%9D%91%E7%88%B9%E7%9A%84getter%E3%80%81setter%E6%96%B9%E6%B3%95%E7%9A%84%E6%BD%9C%E8%A7%84%E5%88%99]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Java</tag>
<tag>JSON</tag>
</tags>
</entry>
<entry>
<title><![CDATA[MySQL-筛选出每个人的时间最新的一条记录]]></title>
<url>%2F2018%2F03%2F22%2FMySQL-%E7%AD%9B%E9%80%89%E5%87%BA%E6%AF%8F%E4%B8%AA%E4%BA%BA%E7%9A%84%E6%97%B6%E9%97%B4%E6%9C%80%E6%96%B0%E7%9A%84%E4%B8%80%E6%9D%A1%E8%AE%B0%E5%BD%95%2F</url>
<content type="text"><![CDATA[场景: 查询每个学生最新的成绩记录 表结构 12345678CREATE TABLE `student` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `no` varchar(9) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `score` decimal(3, 1) NULL DEFAULT NULL, `date` datetime(0) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE) 表数据: 12345678910111213141 600040407 王玲 80 2011-06-21 22:34:002 600040407 王玲 56 2011-06-24 10:21:003 600040407 王玲 64 2011-12-07 10:45:004 600040407 王玲 84 2012-01-15 14:01:005 600040407 王玲 62 2012-12-26 14:11:006 600040408 魏武 58 2011-06-21 22:36:007 600040408 魏武 75 2013-11-15 10:46:008 600040408 魏武 68 2014-01-19 09:12:009 600040408 魏武 99 2014-01-10 13:57:0010 600040408 魏武 73 2014-01-22 10:08:0011 600040435 于洋 86 2011-06-22 12:54:0012 600040435 于洋 77 2013-03-11 09:16:0013 600040435 于洋 68 2014-01-10 11:18:0014 600040435 于洋 88 2013-12-20 15:09:00 SQL实现: 12345678910111213-- 方法1select a.* from student awhere not exists( select 1 from student b where b.no=a.no and b.date>a.date)-- 方法2select a.* from student ainner join ( select no,max(date) 'maxdate' from student group by no) b on a.no=b.no and a.date=b.maxdate 查询结果 1235 600040407 王玲 62 2012-12-26 14:11:0010 600040408 魏武 73 2014-01-22 10:08:0013 600040435 于洋 68 2014-01-10 11:18:00]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Database</tag>
<tag>MySQL</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Git学习笔记(4)-导出新修改的文件]]></title>
<url>%2F2018%2F02%2F27%2FGit%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-4-%E5%AF%BC%E5%87%BA%E6%96%B0%E4%BF%AE%E6%94%B9%E7%9A%84%E6%96%87%E4%BB%B6%2F</url>
<content type="text"><![CDATA[在 bash 窗口中执行以下命令 1git archive -o update.zip HEAD $(git diff --name-only HEAD)]]></content>
</entry>
<entry>
<title><![CDATA[Java使用jsoup提取mht文件中图片]]></title>
<url>%2F2018%2F01%2F30%2FJava%E4%BD%BF%E7%94%A8jsoup%E6%8F%90%E5%8F%96mht%E6%96%87%E4%BB%B6%E4%B8%AD%E5%9B%BE%E7%89%87%E5%BC%82%E5%B8%B8%2F</url>
<content type="text"><![CDATA[jsoup读取mht文件方法12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879/** * 解析mht文件,包括提取图片 */@SuppressWarnings("unchecked")private static String parseMhtToHtml(String fileName) throws Exception { // 读取文件内容 List<String> lines = FileUtils.readLines(new File(fileName), "GBK"); Map<String, Object> map = new HashMap<>(); List<Map<String, Object>> list = new ArrayList<>(); for (int i = 6; i < lines.size(); i++) { String line = lines.get(i).trim(); if (line.startsWith("----boundary")) { map = new HashMap<>(); map.put("headers", new HashMap<>()); map.put("content", new ArrayList<>()); list.add(map); } if (!line.startsWith("----boundary") && !"".equals(line)) { if (line.contains(":")) { String[] kv = line.split(":"); ((Map<String, String>) map.get("headers")).put(kv[0], kv[1].trim()); } else { ((List<String>) map.get("content")).add(line); } } } Map<String, String> resultMap = new HashMap<>(); list.forEach(m -> { Map<String, String> headers = (Map<String, String>) m.get("headers"); List<String> content = (List<String>) m.get("content"); if (!headers.isEmpty() && !content.isEmpty()) { String cid = headers.get("Content-ID"); String html = StringUtils.join(content, ""); if (cid != null) { String prefix = "data:"+headers.get("Content-Type")+";"+headers.get("Content-Transfer-Encoding")+","; resultMap.put(cid.substring(1, cid.length()-1), prefix + html); } else { resultMap.put("html", html); } } }); String html = new String(Base64.getDecoder().decode(resultMap.get("html")), "GBK"); Pattern compile = Pattern.compile("cid:(\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12})"); Matcher matcher = compile.matcher(html); while (matcher.find()) { html = html.replaceAll(matcher.group(), resultMap.get(matcher.group(1))); } return html;}/** * 解析html(doc转html)到map中 */private static Map<String, Object> parseMhtToMap() { String html = parseMhtToHtml("/path/to/hmt/file"); Document doc = Jsoup.parse(html); Element body = doc.body(); // 基本信息 START Map<String, String> map = new HashMap<>(); // 提取头像 String image = body.select("img").attr("src"); map.put(AVATAR, image); return map;} 注意:在解析文件中,发现图片无法显示,最后分析原始html和经过jsoup解析的html(Jsoup.parse),发现BASE64图片图片长度不一致,导致无法再网页中显示,解决方法就是更新jsoup依赖版本,如下 >12345<dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.11.1</version></dependency> 改为: 12345<dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.11.2</version></dependency>]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Java</tag>
<tag>Jsoup</tag>
<tag>mht</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Java开发问题集锦]]></title>
<url>%2F2018%2F01%2F09%2FJava%E5%BC%80%E5%8F%91%E9%97%AE%E9%A2%98%E9%9B%86%E9%94%A6%2F</url>
<content type="text"><![CDATA[Failed to load class “org.slf4j.impl.StaticLoggerBinder”问题描述123SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".SLF4J: Defaulting to no-operation (NOP) logger implementationSLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. 解决办法12345678910<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.5</version></dependency><dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.5</version></dependency>]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title><![CDATA[[转]微信小程序之使用本地接口开发]]></title>
<url>%2F2018%2F01%2F05%2F%E8%BD%AC-%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%B9%8B%E4%BD%BF%E7%94%A8%E6%9C%AC%E5%9C%B0%E6%8E%A5%E5%8F%A3%E5%BC%80%E5%8F%91%2F</url>
<content type="text"><![CDATA[原文地址:https://www.cnblogs.com/xcsn/p/7538371.html 本文主要讲解如何使用本地接口进行开发,很多人都会遇到这个问题,特别是小程序上线后。 一、解决思路在小程序开发工具设置网络代理,然后再通过Charles设置代理,将https域名转为本地接口进行访问。 以下示例的环境为win7 + 老版本的微信开发工具 二、准备工作 配置https域名 为小程序配置request合法域名,在登录公众号平台去设置。 安装Charles 下载地址:https://www.charlesproxy.com/download/ 三、配置Charles 安装根证书 首先,打开 Charles,Help->SSL Proxying->Install Charles Root Certificate 安装证书到本地,指定位置到受信任的根证书颁发机构,否则需要进行下一步操作。 然后,按住 win+r, 在输入运行窗口输入 certmgr.msc 回车,在证书界面找到 中级证书颁发机构=》证书 找到证书 Chambers of Commerce Root - 2008,然后拖到 受信任的根证书颁发机构=》证书,在弹出框点击 “是”。 映射https域名到本地访问地址 打开 Tools->Map Remote 添加线上域名于本地(开发环境)服务的映射 代理设置 打开 Proxy->Proxy Settings,该端口号后面会用到 SSL代理设置(重要) 打开 Proxy->SSL Proxying Settings, 没有设置此步骤,将会出现 SSL Proxying not enabled for this host: enable in Proxy Settings, SSL locations 的错误 以下例子中 host 为*,即过滤所有https,实际操作时指定为您的https地址即可 打开 Proxy->Windows Proxy 启用本地的代理服务 四、配置开发工具 选择手动设置代理,然后填写本地的IP,以及前边在Charles中设置的代理端口号 在开发工具的最左侧菜单的 设置 进入,如下设置 以往的坑 在微信开发者工具中,可以临时开启 开发环境不校验请求域名、TLS版本及HTTPS证书 选项,跳过服务器域名的校验。=》在不填appId时创建的项目下可以调试本地接口,但是微信接口都调用不了 参考: http://www.cnblogs.com/jiasm/archive/2016/11/14/6063317.html https://github.com/nighthary/someutil/blob/master/doc/charles%E6%8A%93%E5%8C%85https%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98.md]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>微信</tag>
<tag>小程序</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Git学习笔记-3-将项目提交到两个git仓库]]></title>
<url>%2F2018%2F01%2F04%2FGit%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-3-%E5%B0%86%E9%A1%B9%E7%9B%AE%E6%8F%90%E4%BA%A4%E5%88%B0%E4%B8%A4%E4%B8%AAgit%E4%BB%93%E5%BA%93%2F</url>
<content type="text"><![CDATA[方案一: git remote add 查看远程主机 123$ git remote -vorigin https://github.com/username/repository.git (fetch)origin https://github.com/username/repository.git (push) 添加远程主机 1$ git remote add oschina https://git.oschina.net/username/repository.git 查看远程主机 12345$ git remote -vorigin https://github.com/username/repository.git (fetch)origin https://github.com/username/repository.git (push)oschina https://git.oschina.net/username/repository.git (fetch)oschina https://git.oschina.net/username/repository.git (push) 推送到远程主机 1234$ git add .$ git commit -m 'test'$ git push -u origin master$ git push -u oschina master 方案二: git remote set-url 查看远程主机 123$ git remote -vorigin https://github.com/username/repository.git (fetch)origin https://github.com/username/repository.git (push) 使用 git remote set-url 命令 1$ git remote set-url --add origin https://git.oschina.net/username/repository.git 查看远程主机 1234$ git remote -vorigin https://github.com/username/repository.git (fetch)origin https://github.com/username/repository.git (push)origin https://git.oschina.net/username/repository.git (push) 参考 http://feitianbenyue.iteye.com/blog/2376791]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title><![CDATA[JavaWeb文件下载知识整理]]></title>
<url>%2F2017%2F12%2F28%2FJavaWeb%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD%E7%9F%A5%E8%AF%86%E6%95%B4%E7%90%86%2F</url>
<content type="text"><![CDATA[中文文件名乱码JAVA文件下载时乱码有两种情况: 下载时中文文件名乱码 解决方法: 12345678910111213String userAgent = request.getHeader("User-Agent");String fileName = "中文文件名称";// 针对IE或者以IE为内核的浏览器:if (userAgent.contains("MSIE") || userAgent.contains("Trident")) { fileName = java.net.URLEncoder.encode(fileName, "UTF-8");} else { // 非IE浏览器的处理: fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");}response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", fileName + ".xls"));response.setContentType("application/vnd.ms-excel;charset=utf-8");response.setCharacterEncoding("UTF-8"); 下载时因为路径中包含中文文件名乱码,提示找不到文件 解决方法:修改Tomcat配置文件 ${CATLINA_HOME}/conf/server.xml ,如下内容 12345<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" /> Content-Disposition的作用以及attachment、inline的区别 Content-Disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。当浏览器接收到头时,它会激活文件下载对话框,它的文件名框自动填充了头中指定的文件名。 服务端向客户端游览器发送文件时,如果是浏览器支持的文件类型,一般会默认使用浏览器打开,比如txt、jpg等,会直接在浏览器中显示,如果需要提示用户保存,就要利用 Content-Disposition 进行一下处理,关键在于一定要加上 attachment : 1response.setHeader("Content-Disposition", "attachment;filename=FileName.txt"); 备注:这样浏览器会提示保存还是打开,即使选择打开,也会使用相关联的程序比如记事本打开,而不是IE直接打开了。 Java Web中下载文件时,我们一般设置 Content-Disposition 告诉浏览器下载文件的名称,是否在浏览器中内嵌显示. Content-Disposition: inline;filename=foobar.pdf 表示浏览器内嵌显示一个文件,Content-Type 值为 application/octet-stream 除外 Content-Disposition: attachment;filename=foobar.pdf 表示会下载文件,如火狐浏览器中]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Windows命令集合]]></title>
<url>%2F2017%2F12%2F27%2FWindows%E5%91%BD%E4%BB%A4%E9%9B%86%E5%90%88%2F</url>
<content type="text"><![CDATA[ipconfig———查看本机IP信息 (Linux系统下是ifonfig) ping———检查网络是否连通 tracert———查询从本机到该IP地址所在的电脑要经过的路由器及其IP地址 winver———检查Windows版本 wmimgmt.msc—-打开windows管理体系结构(WMI) wupdmgr——–windows更新程序 wscript——–windows脚本宿主设置 write———-写字板 winmsd———系统信息 dxdiag———检查DirectX信息 drwtsn32—— 系统医生 devmgmt.msc— 设备管理器 dfrg.msc——-磁盘碎片整理程序 diskmgmt.msc—磁盘管理实用程序 dcomcnfg——-打开系统组件服务 ddeshare——-打开DDE共享设置 dvdplay——–DVD播放器 tsshutdn——-60秒倒计时关机命令 taskmgr——–任务管理器 regedit.exe—-注册表 rsop.msc——-组策略结果集 regedt32——-注册表编辑器 rononce -p —-15秒关机 osk————打开屏幕键盘 odbcad32——-ODBC数据源管理器 oobe/msoobe /a—-检查XP是否激活 lusrmgr.msc—-本机用户和组 logoff———注销命令 iexpress——-木马捆绑工具,系统自带 Nslookup——-IP地址侦测器 fsmgmt.msc—–共享文件夹管理器 utilman——–辅助工具管理器 gpedit.msc—–组策略 services、msc—本地服务设置]]></content>
<categories>
<category>Windows</category>
</categories>
<tags>
<tag>Windows</tag>
</tags>
</entry>
<entry>
<title><![CDATA[好用的网盘搜索引擎搜藏]]></title>
<url>%2F2017%2F12%2F15%2F%E5%A5%BD%E7%94%A8%E7%9A%84%E7%BD%91%E7%9B%98%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%E6%90%9C%E8%97%8F%2F</url>
<content type="text"><![CDATA[网盘搜索引擎 电驴 http://www.verycd.com 城通网盘 https://www.ctfile.com 盘多多 http://www.panduoduo.net 西林街 http://www.xilinjie.com 胖次网盘搜索引擎 http://www.panc.cc 呆木瓜 http://md5.daimugua.com (关停) 盘搜 http://www.pansou.com 网盘搜 http://www.wangpansou.cn 盘易搜 http://panyisou.com (不可用) 网盘搜啦 http://www.bdsola.com 盘盘搜 http://www.panpanso.com 特百度 http://www.tebaidu.com 搜百度盘 http://www.sobaidupan.com 我的盘 http://www.wodepan.com 网盘007 http://wangpan007.com 天天搜 http://www.daysou.com 网盘屋 http://www.wangpanwu.com 百度网盘之家 http://wowenda.com 盘优搜 http://www.panuso.com 百度云搜 http://www.baiduyunso.com 去转盘网 http://www.quzhuanpan.com 百度云搜索 http://www.down20.com 实用网站 PDF导航 https://pdfcandy.com/tw 一个十分全面的PDF导航网站,各种对PDF的编辑和转化,相信完全满足你对PDF的需求;真的十分强大的网站 V视频助手 http://v.ranks.xin 支持下载腾讯视频、秒拍视频、微博视频、今日头条、阳光宽频网、快手、微信、百度视频、梨视频、西瓜视频等;用了就知道好用,十分方便你对各种视频的下载 在线录屏、视频下载 https://www.videograbber.net/zh 在线下载优酷、爱奇艺、哔哩哔哩等主流视频网站的视频。并且支持在线录屏和在线音视频格式转换,十分良心 迅捷PDF在线编辑器 http://app.xunjiepdf.com PDF文件需要编辑或者转换不用花时间去找一些软件或者花钱去进行转换,这个网站可以轻松帮你解决! 电影资源网站 电影街 http://t.cn/Rcs5iFq 深影论坛 http://t.cn/RA2E8Ta BT之家 http://t.cn/RSmcbGy 电影港 http://t.cn/RAkhAeF 小浣熊 http://t.cn/RLF7zy5 QVOCD http://t.cn/zOueO0J 嘎嘎影视 http://t.cn/RvfQBPZ BT家 http://t.cn/RSPW1hq 无极论坛 http://t.cn/RUV9YeG 蚂蚁高清 http://t.cn/RSmcbGA ed2000 http://t.cn/hiVAw ed2kfile http://t.cn/zRT4D78 8688 http://t.cn/RSmcbGJ A站 http://t.cn/hiIr5 B站 http://t.cn/hbJPuO 小调网 http://www.xiaopian.com 全集网 http://www.quanji.la 电影港 http://www.dygang.com 泡饭影视 http://www.chapaofan.com 电影天堂2018 http://www.dy2018.com LOL电影天堂 http://www.loldytt.com 龙部落 http://www.lbldy.com 飘花电影网 http://www.piaohua.com 6V电影 http://www.6vhao.net 电影家园 http://www.dy1234.net 天天电影 http://www.tiantiandy.com 电影天堂 http://www.dygod.net 破晓电影 http://www.poxiao.com 查片源 https://www.chapianyuan.com 茶杯狐 https://www.cupfox.com SOS导航 http://lovedali.cn 发烧屋影视网 http://www.hifiwu.com 放肆够 http://vip.fansg.top/ 追剧追番影视网站 五杀电影院 http://www.lol5s.com 电影首发站 http://www.dysfz.cc 迅影网 http://www.xunyingwang.com Neets http://neets.cc CK部落电影 http://www.ck180.net 新视觉影视 http://www.yy6080.org 看看屋 http://www.kankanwu.com 视频解析网站http://bbs.chongbuluo.com/thread-3301-1-1.html 会员影视中心 http://97ym.cn/vip 闽视网-F站 http://www.fjyxdm.cn/vip http://www.kilikili.top/vip 我爱分享网 http://www.5ifxw.com/vip 有范全网通VIP http://vip.ufanw.com 08影院 http://v.hzui.com 旋风动漫 http://api.xfsub.com FreeVideo搜索通用版 http://v.cnm.asia 够低调解析-vip视频在线解析 http://www.goudidiao.com/ 超级看VIP视频 http://vip.deepba.com 九会员VIP视频解析站 http://yy.9vip.top/ 人人VIP视频网站解析 http://v.renrenfabu.com/ 会员影视中心 http://tejiamai.top/v/ 爱6网 http://dy.a6vip.cn/ 福利吧 http://f.uliba.net/jiexi.php 小淘圈影院 http://www.52xtq.net/vip/ 全民vip视频在线解析 http://www.qmaile.com/ 屌丝青年VIP视频解析 http://tv.dsqndh.com/]]></content>
<categories>
<category>网站整理</category>
</categories>
<tags>
<tag>网站整理</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Mybatis单个参数的if判断(针对异常:There is no getter for property..)]]></title>
<url>%2F2017%2F11%2F23%2FMybatis%E5%8D%95%E4%B8%AA%E5%8F%82%E6%95%B0%E7%9A%84if%E5%88%A4%E6%96%AD%EF%BC%88%E9%92%88%E5%AF%B9%E5%BC%82%E5%B8%B8%EF%BC%9AThere-is-no-getter-for-property-%EF%BC%89%2F</url>
<content type="text"><![CDATA[MyBatis在进行参数判断的时候,可以直接使用传入entity实体属性名或者map的键名,如下: 常规代码 123456789101112<update id="update" parameterType="com.demo.entity.Test"> UPDATE t_test <set> <if test="field1 != null"> field1 = #{field1,jdbcType=VARCHAR}, </if> <if test="field2 != null"> field2 = #{field2,jdbcType=INTEGER}, </if> </set> WHERE id = #{id,jdbcType=INTEGER}</update> 但是单个参数和多参数的判断有个不同点,当我们的入参为entity实体,或者map的时候,使用 if 参数判断没任何问题。 但是当我们的入参为 java.lang.Integer 或者 java.lang.String 的时候,这时候就需要注意一些事情了,代码如下: 错误代码 123456<select id="select" parameterType="java.lang.Integer" resultType="java.lang.Integer"> SELECT field FROM t_test WHERE <if test="id != null"> AND id = #{id} </if></select> 上述代码存在一些问题,首先入参是 java.lang.Integer,而不是map或者实体的入参方式,对于这类单个入参然后用 if 判断的,MyBatis有自己的内置对象 如果你在 if 判断里面写的是你的入参的对象名,那就报异常:Internal error : nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'langId' in 'class java.lang.Integer' 正确代码: 123456<select id="select" parameterType="java.lang.Integer" resultType="java.lang.Integer"> SELECT field FROM t_test WHERE <if test="_parameter != null"> AND id = #{id,jdbcType=INTEGER} </if></select> 这里MyBatis有内置对象 _parameter,对于单个参数的传入和判断,必须用 _parameter 来处理,而不是传入对象名 id 在使用传入参数时,需要加上参数对于数据库类型 参考:https://www.2cto.com/database/201505/401604.html]]></content>
</entry>
<entry>
<title><![CDATA[SSH公钥中保存多个git账号]]></title>
<url>%2F2017%2F08%2F15%2FSSH%E5%85%AC%E9%92%A5%E4%B8%AD%E4%BF%9D%E5%AD%98%E5%A4%9A%E4%B8%AAgit%E8%B4%A6%E5%8F%B7%2F</url>
<content type="text"><![CDATA[问题描述之前生成了GitHub的ssh公钥,可以免登陆提交代码,后来在oschina上也需要生成ssh公钥,发现GitHub的公钥就无法使用了,需要重新生成,但是又会将oschina的公钥覆盖掉。 解决办法 创建不同的ssh公钥,修改默认文件路径 123456789101112131415161718192021➜ ~ ssh-keygen -t rsa -C "[email protected]"Generating public/private rsa key pair.Enter file in which to save the key (/Users/xxx/.ssh/id_rsa): /Users/xxx/.ssh/id_rsa_oschinaEnter passphrase (empty for no passphrase):Enter same passphrase again:Your identification has been saved in /Users/xxx/.ssh/id_rsa_oschina.Your public key has been saved in /Users/xxx/.ssh/id_rsa_oschina.pub.The key fingerprint is:SHA256:xVDjp+8X5x6YWx9gaxSpXo3Oj+ra0usZ9IwPtzYv8mk [email protected] key's randomart image is:\+---[RSA 2048]----+| ..o || + . . || + + || . * . || S = = || . X =.=. || .+ X X+o || ..o*EX .oo || .=XXX++oo |\+----[SHA256]-----+ 添加生成的公钥 1$ ssh-add ~/.ssh/id_rsa_oschina 添加之前可以删除缓存的公钥 1$ ssh-add -D 添加之后查看添加的公钥 1$ ssh-add -l 将对应的ssh公钥添加到git账号上去 1➜ cat ~/.ssh/id_rsa_oschina | pbcopy 验证 12➜ .ssh ssh -T [email protected] to Git@OSC, xxx! 参考https://gist.github.com/Bobjoy/57d520585565e8afdc61495f7e71c3e6]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title><![CDATA[记一次Spring注入Bean异常]]></title>
<url>%2F2017%2F08%2F03%2F%E8%AE%B0%E4%B8%80%E6%AC%A1Spring%E6%B3%A8%E5%85%A5Bean%E5%BC%82%E5%B8%B8%2F</url>
<content type="text"><![CDATA[问题描述1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userLastOnlineController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.bfl.sa.common.web.controller.BaseCRUDController.setBaseService(com.bfl.sa.common.service.BaseService); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.bfl.sa.common.service.BaseService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) ~[spring-context-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) ~[spring-context-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:667) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:633) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:681) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:552) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:493) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE] at javax.servlet.GenericServlet.init(GenericServlet.java:158) ~[servlet-api.jar:3.1.FR] at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1227) ~[catalina.jar:8.0.37] at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1140) ~[catalina.jar:8.0.37] at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1027) ~[catalina.jar:8.0.37] at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5038) ~[catalina.jar:8.0.37] at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5348) ~[catalina.jar:8.0.37] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145) ~[catalina.jar:8.0.37] at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725) ~[catalina.jar:8.0.37] at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701) ~[catalina.jar:8.0.37] at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717) ~[catalina.jar:8.0.37] at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1696) ~[catalina.jar:8.0.37] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_101] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_101] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_101] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_101] at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300) ~[tomcat-coyote.jar:8.0.37] at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) ~[?:1.8.0_101] at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) ~[?:1.8.0_101] at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:484) ~[catalina.jar:8.0.37] at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:433) ~[catalina.jar:8.0.37] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_101] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_101] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_101] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_101] at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300) ~[tomcat-coyote.jar:8.0.37] at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) ~[?:1.8.0_101] at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) ~[?:1.8.0_101] at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468) ~[?:1.8.0_101] at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76) ~[?:1.8.0_101] at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309) ~[?:1.8.0_101] at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1401) ~[?:1.8.0_101] at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829) ~[?:1.8.0_101] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_101] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_101] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_101] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_101] at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:324) ~[?:1.8.0_101] at sun.rmi.transport.Transport$1.run(Transport.java:200) ~[?:1.8.0_101] at sun.rmi.transport.Transport$1.run(Transport.java:197) ~[?:1.8.0_101] at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_101] at sun.rmi.transport.Transport.serviceCall(Transport.java:196) ~[?:1.8.0_101] at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568) ~[?:1.8.0_101] at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826) ~[?:1.8.0_101] at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683) ~[?:1.8.0_101] at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_101] at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682) [?:1.8.0_101] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_101] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_101] at java.lang.Thread.run(Thread.java:745) [?:1.8.0_101]Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.bfl.sa.common.web.controller.BaseCRUDController.setBaseService(com.bfl.sa.common.service.BaseService); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.bfl.sa.common.service.BaseService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:661) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] ... 65 moreCaused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.bfl.sa.common.service.BaseService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:618) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ~[spring-beans-4.2.5.RELEASE.jar:4.2.5.RELEASE] ... 65 more 解决方法 BaseCRUDController 类主要代码如下: 1234567891011121314/** * 基础CRUD 控制器 */public abstract class BaseCRUDController<E extends BaseEntity, ID extends Serializable> extends BaseController<E> { protected BaseService<E, ID> baseService; @Autowired public void setBaseService(BaseService<E, ID> baseService) { this.baseService = baseService; } // 以下忽略一些代码} 在 BaseCRUDController.setBaseService(BaseService<E, ID> baseService) 方法处断点调试 断点调试发现在实例化 PermissionController 和 UserController 时,对应的 Service 都是可以正常注入的,但是当实例化 UserLastOnlineController 时,就出现了以上描述的异常。 Controller 1234@Controller@RequestMapping(value = "/admin/sys/permission/permission")public class PermissionController extends BaseCRUDController<Permission, Long> {} 1234@Controller("adminUserController")@RequestMapping(value = "/admin/sys/user")public class UserController extends BaseCRUDController<User, Long> {} 1234@Controller@RequestMapping(value = "/admin/sys/user/lastOnline")public class UserLastOnlineController extends BaseCRUDController<UserLastOnline, Long> {} Service 123@Servicepublic class PermissionService extends BaseService<Permission, Long> {} 123@Servicepublic class UserService extends BaseService<User, Long> {} 123@Servicepublic class UserLastOnlineService extends BaseService<UserLastOnline, String> {} 仔细比对 Controller 和 Service ,发现都只是简单的继承基础类,不过仔细观察,发现 UserLastOnlineController 和 UserLastOnlineService 中基类泛型中主键类型不同,然后将 UserLastOnlineService 中的主键类型修改为 Long 后,再调试就OK了]]></content>
</entry>
<entry>
<title><![CDATA[MySQL-使用问题记录-持续更新]]></title>
<url>%2F2017%2F07%2F28%2FMySQL-%E4%BD%BF%E7%94%A8%E9%97%AE%E9%A2%98%E8%AE%B0%E5%BD%95-%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0%2F</url>
<content type="text"><![CDATA[SQL语句中delete语句中别名引发的问题 SQL语句 1DELETE FROM sys_auth t WHERE t.id=1 错误提示 1[42000][1064] You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 't where t.id=111' at line 1 解决方法 1DELETE FROM sys_auth WHERE id=1 或者 1DELETE t FROM sys_auth t WHERE t.id=1 问题原因 别名使用姿势不对 MySQL5.6参考手册 Sonar报错问题处理 错误描述 123ERROR: Error during SonarQube Scanner executionERROR: Failed to upload report - 500: An error has occurred. Please contact your administrator 问题原因:mysql参数设置问题 检查mysql参数: 1mysql> SHOW VARIABLES LIKE 'max_allowed_packet'; 修改/etc/my.cnf文件: 1max_allowed_packet = 50M 无法删除数据库 ERROR 1010 (HY000)在做数据库删除时出现这种提示,其原因是在database下面含有自己放进去的文件,譬如.txt文件或.sql文件等,只要进去把这个文件删了在执行 1drop database database_name; MySQL 命令行创建数据库12345CREATE DATABASE dbname CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;CREATE USER 'dbuser' IDENTIFIED BY 'dbpwd';GRANT ALL ON dbname.* TO 'dbuser'@'%' IDENTIFIED BY 'dbpwd';GRANT ALL ON dbname.* TO 'dbuser'@'localhost' IDENTIFIED BY 'dbpwd';FLUSH PRIVILEGES;]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Database</tag>
<tag>MySQL</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Java读取INI文件时返回空]]></title>
<url>%2F2017%2F07%2F26%2FJava%E8%AF%BB%E5%8F%96INI%E6%96%87%E4%BB%B6%E6%97%B6%E8%BF%94%E5%9B%9E%E7%A9%BA%2F</url>
<content type="text"><![CDATA[问题描述Java 读取 INI配置 文件时,返回内容为空,也没有报错,配置内容如下 12345[base_auth]/static/** = anon/u/** = anon/open/** = anon/user/** = kickout,simple,login 解决方法去除配置文件中每一行 ‘=’ 号两边的空格]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>Java</tag>
<tag>INI</tag>
</tags>
</entry>
<entry>
<title><![CDATA[GIT使用问题记录(持续更新)]]></title>
<url>%2F2017%2F07%2F23%2FGIT%E4%BD%BF%E7%94%A8%E9%97%AE%E9%A2%98%E8%AE%B0%E5%BD%95-%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0%2F</url>
<content type="text"><![CDATA[Git submodule add: “a git directory is found locally” issue问题描述1234567git submodule add https://github.com/iissnan/hexo-theme-next.git themes/next --branch masterA git directory for 'themes/next' is found locally with remote(s): origin https://github.com/XXX/hexo-theme-next.gitIf you want to reuse this local git directory instead of cloning again from https://github.com/iissnan/hexo-theme-next.gituse the '--force' option. If the local git directory is not the correct repoor you are unsure what this means choose another name with the '--name' option. 解决方法 git rm –-cached themes/next 删除 .gitmodules 文件中如下内容: 123[submodule "themes/next"] path = themes/next url = https://github.com/XXX/hexo-theme-next.git 删除 .git/config 文件中如下内容: 12[submodule "path_to_submodule"] url = https://github.com/XXX/hexo-theme-next.git 运行 rm -rf .git/modules/themes/next 重新添加子模块 git submodule add https://github.com/iissnan/hexo-theme-next.git 参考文章 https://stackoverflow.com/questions/20929336/git-submodule-add-a-git-directory-is-found-locally-issue git中不记录子模块中文件的修改问题描述在自己的git项目中添加了外部的git项目,有时候需要修改子模块中的文件,但是执行 git status 时又不想看到子模块文件的修改 解决办法在 .gitmodules 中添加 ignore = dirty 设置,如下 12345[submodule "themes/next"] path = themes/next url = https://github.com/iissnan/hexo-theme-next.git branch = master ignore = dirty]]></content>
<categories>
<category>Git</category>
</categories>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title><![CDATA[[转]一个命令永久禁用Win10驱动程序强制签名]]></title>
<url>%2F2017%2F07%2F23%2F%E8%BD%AC-%E4%B8%80%E4%B8%AA%E5%91%BD%E4%BB%A4%E6%B0%B8%E4%B9%85%E7%A6%81%E7%94%A8Win10%E9%A9%B1%E5%8A%A8%E7%A8%8B%E5%BA%8F%E5%BC%BA%E5%88%B6%E7%AD%BE%E5%90%8D%2F</url>
<content type="text"><![CDATA[原文地址:https://www.ithome.com/html/win10/196402.htm 在Win10中,未经签名的驱动程序不能使用,这会导致部分硬件出现问题,此时就需要手动关闭Windows10的默认驱动验证。好在这个永久关闭验证的方法很简单,只需一个命令就可以搞定。 ▲要关闭强制验证只需执行第一个命令 步骤如下: 在开始按钮点击右键,选择“命令提示符(管理员)” 执行以下命令(复制后,在命令提示符中单击鼠标右键即可完成粘贴,然后按回车键执行): 1bcdedit.exe /set nointegritychecks on 命令瞬间执行完毕,若想恢复默认验证,执行如下命令即可: 1bcdedit.exe /set nointegritychecks off 如果你有未签名的硬件驱动需要使用,不妨尝试运行一下第一个命令,也许由此引发的问题就可以暂时解决。不过微软的驱动强制签名政策也是出于安全考虑,如果你没遇到类似问题,还是别关闭签名验证为好。]]></content>
</entry>
<entry>
<title><![CDATA[记一次OPPO R9s清除锁屏密码即刷机过程]]></title>
<url>%2F2017%2F07%2F23%2F%E8%AE%B0%E4%B8%80%E6%AC%A1OPPO-R9s%E5%88%B7%E6%9C%BA%E8%BF%87%E7%A8%8B%2F</url>
<content type="text"><![CDATA[事情缘由事情经过是这样的,今天有人拿来一部手机给我,他说他忘记了锁屏的密码,让我帮忙解决一下,起初我想,不就是去除锁屏密码吗,对于我这个刷机无数的人来说小case。 解决办法首先我们需要直到手机的品牌及型号,这个你可以通过查看手机知道,如果型号看不出来,你可以尝试连接电脑,豌豆荚会告诉你的,以下就是针对OPPO R9s的解决办法。 方法一:双清安卓手机忘记解锁密码最用的解决办法就是进行双清操作了,它相当于恢复出厂设置,这种方法会导致个人数据丢失,双清之前,需要确保备份过数据或者手机中无重要数据。 双清操作方法: 首先将手机关机,长按「电源键」+「音量键+」不放,直到出现Recovery界面为止,进入Recovery模式,Recovery模式下使用音量键移动,电源键确认,按照下图的指示对手机进行清空数据和缓存操作,完成后重启手机即可, 注意:如果「电源键」+「音量键+」不能进入Recovery界面的话,可以尝试「电源键」+「音量键+」+「音量键-」 方法就是这么简单。。。。。 然鹅,事情并不是这么简单,选择「清除数据」电源键确认后,提示输入开机密码,只能另寻蹊径了 方法二:借助刷机工具如今很多安卓手机刷机工具都内置了解锁工具,可以快速清除手机密码,但前提是您的OPPO手机要能够正常连接电脑。只要你的OPPO R9s手机已经开启了USB调试模式,就可以将OPPO手机通过数据线连接电脑,然后通过电脑上的刷机精灵等工具,一键完成清空解锁密码。 注:也可以通过adb命令清除密码,adb工具上图中有,可自行搜索使用方法 然鹅鹅鹅,too easy,too young,该手机并没有开启USB调试模式,而且在锁屏情况下也无法开启USB调试模式,开来只能出杀手锏了—刷机。 方法三:刷机该方法中的手机比较特殊,如果使用刷机工具的话,必须开启USB调试模式,这里使用了针对OPPO(网传说OnePlus手机也可行)刷机。 准备工具 高通9008驱动,下载地址:http://pan.baidu.com/s/1mhLJxl2 密码: 2dt7 刷机工具包,下载地址:http://pan.baidu.com/s/1mi7M4re 密码: 8i8b 安装工具 如果你有未签名的硬件驱动需要使用,不妨尝试运行一下第一个命令,也许由此引发的问题就可以暂时解决。不过微软的驱动强制签名政策也是出于安全考虑,如果你没遇到类似问题,还是别关闭签名验证为好。 在开始按钮点击右键,选择“命令提示符(管理员)” 执行以下命令(复制后,在命令提示符中单击鼠标右键即可完成粘贴,然后按回车键执行): 1bcdedit.exe /set nointegritychecks on 命令瞬间执行完毕,若想恢复默认验证,执行如下命令即可: 1bcdedit.exe /set nointegritychecks off 高通9008驱动 检查是否安装成功,手机开机并连接电脑,打开设备管理器,如果列表中有「端口(COM和LPT)」,则说明安装成功 3. 打开刷机工具开始刷机 解压刷机工具包,其中包含三个文件 打开MsmDownloadTool工具 手机关机状态下,「电源键」+「音量键+」连接电脑,点击MsmDownloadTool工具中的刷新按钮,连接状态显示已连接(如上图)即可,按F5可选择写入的文件,如果需要清除密码的话,需要勾选userdata项 点击工具上的开始按钮,开始刷机,等待几分钟后刷机结束。 手机重启后,会进入ColorOS升级界面,等待升级完成后进入系统就大功告成了。 参考 安卓刷机网 古连网 IT之家 手机中国论坛]]></content>
<categories>
<category>随笔</category>
</categories>
<tags>
<tag>随笔</tag>
<tag>刷机</tag>
<tag>OPPO R9s</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Java连接MySQL数据库,提示Establishing SSL connection without警告]]></title>
<url>%2F2017%2F07%2F11%2FJava%E8%BF%9E%E6%8E%A5MySQL%E6%95%B0%E6%8D%AE%E5%BA%93-%E6%8F%90%E7%A4%BAEstablishing-SSL-connection-without%E8%AD%A6%E5%91%8A%2F</url>
<content type="text"><![CDATA[问题描述Java在连接MySQL数据库时,输出如下警告信息 12345678910Tue Jul 11 18:04:07 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.Tue Jul 11 18:04:07 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.Tue Jul 11 18:04:07 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.Tue Jul 11 18:04:07 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.Tue Jul 11 18:04:07 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.Tue Jul 11 18:04:07 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.Tue Jul 11 18:04:07 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.Tue Jul 11 18:04:07 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.Tue Jul 11 18:04:07 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.Tue Jul 11 18:04:07 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification. 解决办法 在jdbc连接后添加 useSSL=false 参数 1url=jdbc:mysql://localhost:3306/es?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&useSSL=false 如果以上办法无效,则需要替换 mysql-connector-java 依赖版本为 5.1.38 以下,如下 12345<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version></dependency>]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title><![CDATA[百度网盘无法访问]]></title>
<url>%2F2017%2F07%2F08%2F%E7%99%BE%E5%BA%A6%E7%BD%91%E7%9B%98%E6%97%A0%E6%B3%95%E8%AE%BF%E9%97%AE%2F</url>
<content type="text"><![CDATA[访问百度网盘下载文件,网站内容如下 解决办法如下: 将IP地址添加到hosts文件(C:\WINDOWS\system32\drivers\etc\hosts)中 1119.75.220.50 pan.baidu.com 刷新页面就可以正常访问了 后来发现,不仅网盘,贴吧也出现相同的情况,归根揭底是因为在网络连接中配置了,将其改为自动获取或者其他DNS服务器地址]]></content>
<categories>
<category>随笔</category>
</categories>
<tags>
<tag>随笔</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Hexo命令server无效]]></title>
<url>%2F2017%2F06%2F28%2FHexo%E5%91%BD%E4%BB%A4server%E6%97%A0%E6%95%88%2F</url>
<content type="text"><![CDATA[按照好 hexo-cli 后, hexo new 创建一篇文章,然后 hexo server 本地运行调试,但是试了好几次都没反应,控制台直接打印帮助文档,然后命令帮助中也没有发现 server 命令,然后各种google,发现hexo3中 server 模块已经独立出来需要单独安装。 npm install hexo-server 安装后再运行 hexo server ,然鹅并没有什么卵用,继续google,发现一些hexo问题中提到plugins的配置,于是抱着试一试的态度将 _config.yml 中的plugins配置注释掉 123#plugins:#- hexo-generator-feed#- hexo-generator-sitemap 再这运行,O啦 2017-07-08 18:15 更新 如果出现如下错误 1234...TypeError: Cannot set property 'lastIndex' of undefined at highlight (/home/rapiz/Blog/node_modules/highlight.js/lib/highlight.js:514:35)... 则需要将 _config.yml 中的以下配置 12highlight: auto_detect: true 修改为 12highlight: auto_detect: false]]></content>
<categories>
<category>Hexo</category>
</categories>
<tags>
<tag>Hexo</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Hibernate查询MySQL抛出StringIndexOutOfBoundsException异常]]></title>
<url>%2F2017%2F06%2F28%2FHibernate%E6%9F%A5%E8%AF%A2MySQL%E6%8A%9B%E5%87%BAStringIndexOutOfBoundsException%E5%BC%82%E5%B8%B8%2F</url>
<content type="text"><![CDATA[问题排查 查看数据表中是否有类型为char的字段A; 检查是否存在该字段A为空的记录; 处理方法 将该字段A为空的记录删除或者填充数据; 将char类型转换为varchar,比如:select CONCAT(c, '') str from demo; 问题原因 MySQL中char为固定长度,不能为空; Hibernate中 org.hibernate.type.descriptor.java.CharacterTypeDescriptor 将char类型转换为java中的类型,会截取第一个字符 Character.valueOf(str.charAt(0)) ,如果为空,则会出现下标越界 StringIndexOutOfBoundsException 123456789101112131415public <X> Character wrap(X value, WrapperOptions options) { if(value == null) { return null; } else if(Character.class.isInstance(value)) { return (Character)value; } else if(String.class.isInstance(value)) { String str = (String)value; return Character.valueOf(str.charAt(0)); } else if(Number.class.isInstance(value)) { Number nbr = (Number)value; return Character.valueOf((char)nbr.shortValue()); } else { throw this.unknownWrap(value.getClass()); }}]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title><![CDATA[解决git fatal: Unable to find remote helper for 'https'问题]]></title>
<url>%2F2016%2F07%2F29%2F%E8%A7%A3%E5%86%B3git-fatal-Unable-to-find-remote-helper-for-https-%E9%97%AE%E9%A2%98%2F</url>
<content type="text"><![CDATA[登陆到远程linux服务器上,使用git, clone的时候报“fatal: Unable to find remote helper for ‘https’”错,没管,绕过,使用git clone git://….协议download下来项目。 但是到提交完要push回服务器的时候,必须得用https,搜了一下问题,是系统中没有curl,都是要装curl的,比如: 1$ yum install curl-devel #Ubuntu使用apt-get 如果有如下提示: 1E: Unable to locate package curl-devel 则需自己安装curl,从http://curl.haxx.se/download.html下载到最新的curl包: 1curl-7.41.0.tar.gz 解压,然后make并安装: 123$ ./configure --prefix=/usr/local/curl/$ make$ make install 安装好后,再尝试git push,还是报一样的错。 想到应该需要重新编译并安装git,执行: 1$ ./configure --prefix=/usr/local/git/ --with-curl=/usr/local/curl/ 注意这里一定要使用--with-curl参数,指定到上面安装的curl目录,git只有与curl库做link之后,才能使用https功能。 再次make & make install git push成功。 本次解决问题的经验教训: 实际上是重新编译时先使用./configure --prefix=/usr/local/git/未果后才思考的,执行./configure --prefix=/usr/local/git/ &> config.log,把log重定向到这个文件里打开,搜curl,发现curl的状态是no,表明这个configure没有找到curl,那么自然后面在make的时候也就无法完成link,然后./configure -h,看到--with-curl参数,想起需要指定,才搞定问题。 参考链接:http://stackoverflow.com/questions/8329485/git-clone-fatal-unable-to-find-remote-helper-for-https]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Web API接口之MutationObserver]]></title>
<url>%2F2016%2F07%2F18%2FWeb-API%E6%8E%A5%E5%8F%A3%E4%B9%8BMutationObserver%2F</url>
<content type="text"><![CDATA[原文地址:https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver MutationObserver给开发者们提供了一种能在某个范围内的DOM树发生变化时作出适当反应的能力.该API设计用来替换掉在DOM3事件规范中引入的Mutation事件. 构造函数MutationObserver()该构造函数用来实例化一个新的Mutation观察者对象. 123MutationObserver( function callback); 参数callback 该回调函数会在指定的DOM节点(目标节点)发生变化时被调用.在调用时,观察者对象会传给该函数两个参数,第一个参数是个包含了若干个MutationRecord对象的数组,第二个参数则是这个观察者对象本身. 实例方法 void observe( Node target, optional MutationObserverInit options ); void disconnect(); Array takeRecords(); observe()给当前观察者对象注册需要观察的目标节点,在目标节点(还可以同时观察其后代节点)发生DOM变化时收到通知. 1234void observe( Node target, optional MutationObserverInit options); 参数target 观察该节点是否会发生DOM变化. options 一个MutationObserverInit对象,指定要观察的DOM变化类型. >注:向一个元素添加 observer 和 addEventListener 类似,注册多次不会有任何影响。即是说,如果你注册了两次,回掉函数不会被调用两次,你也不必执行两次 disconnect() 以停止观察。换句话说,一旦某个元素被注册观察后,使用相同的 observer 实例再次注册不会发生任何变化。当然,如果回调对象不同,那么他会向这个元素添加另一个观察者。 disconnect()让该观察者对象停止观察指定目标的DOM变化.直到再次调用其observe()方法,该观察者对象包含的回调函数都不会再被调用. 1void disconnect(); takeRecords()清空观察者对象的记录队列,并返回里面的内容. 1Array takeRecords(); 返回值返回一个包含了MutationRecords对象的数组. MutationObserverInitMutationObserverInit是一个用来配置观察者对象行为的对象,该对象可以拥有下面这些属性: >注: childList, attributes, 或者characterData三个属性中必须至少有一个为true.否则,会抛出异常”An invalid or illegal string was specified”. 属性 描述 childList 如果需要观察目标节点的子节点(新增了某个子节点,或者移除了某个子节点),则设置为true. attributes 如果需要观察目标节点的属性节点(新增或删除了某个属性,以及某个属性的属性值发生了变化),则设置为true. characterData 如果目标节点为characterData节点(一种抽象接口,具体可以为文本节点,注释节点,以及处理指令节点)时,也要观察该节点的文本内容是否发生变化,则设置为true. subtree 除了目标节点,如果还需要观察目标节点的所有后代节点(观察目标节点所包含的整棵DOM树上的上述三种节点变化),则设置为true. attributeOldValue 在attributes属性已经设为true的前提下,如果需要将发生变化的属性节点之前的属性值记录下来(记录到下面MutationRecord对象的oldValue属性中),则设置为true. characterDataOldValue 在characterData属性已经设为true的前提下,如果需要将发生变化的characterData节点之前的文本内容记录下来(记录到下面MutationRecord对象的oldValue属性中),则设置为true. attributeFilter 一个属性名数组(不需要指定命名空间),只有该数组中包含的属性名发生变化时才会被观察到,其他名称的属性发生变化后会被忽略. MutationRecordMutationRecord对象会作为第一个参数传递给观察者对象包含的回调函数,该对象有下面这些属性: 属性 类型 描述 type String 如果是属性发生变化,则返回attributes.如果是一个CharacterData节点发生变化,则返回characterData,如果是目标节点的某个子节点发生了变化,则返回childList. target Node 返回此次变化影响到的节点,具体返回那种节点类型是根据type值的不同而不同的. 如果type为attributes,则返回发生变化的属性节点所在的元素节点,如果type值为characterData,则返回发生变化的这个characterData节点.如果type为childList,则返回发生变化的子节点的父节点. addedNodes NodeList 返回被添加的节点,或者为null. removedNodes NodeList 返回被删除的节点,或者为null. previousSibling Node 返回被添加或被删除的节点的前一个兄弟节点,或者为null. nextSibling Node 返回被添加或被删除的节点的后一个兄弟节点,或者为null. attributeName String 返回变更属性的本地名称,或者为null. attributeNamespace String 返回变更属性的命名空间,或者为null. oldValue String 根据type值的不同,返回的值也会不同.如果type为 attributes,则返回该属性变化之前的属性值.如果type为characterData,则返回该节点变化之前的文本数据.如果type为childList,则返回null. 例子下面的例子来自这篇博文. 123456789101112131415161718192021// Firefox和Chrome早期版本中带有前缀var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver// 选择目标节点var target = document.querySelector('#some-id');// 创建观察者对象var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { console.log(mutation.type); });});// 配置观察选项:var config = { attributes: true, childList: true, characterData: true }// 传入目标节点和观察选项observer.observe(target, config);// 随后,你还可以停止观察observer.disconnect(); 假设target为当前文档中某个已知的节点,observer为某个已经实例化的MutationObserver观察者对象,则: 12345678910111213141516171819202122232425262728observer.observe(target, {childList:true}) //childList属性只观察子节点的新建与删除,子节点本身的任何变化都不会去理会target.appendChild(document.createElement("div")) //添加了一个元素子节点,触发回调函数.target.appendChild(document.createTextNode("foo")) //添加了一个文本子节点,触发回调函数.target.removeChild(target.childNodes[0]) //移除第一个子节点,触发回调函数.target.childNodes[0].appendChild(document.createElement("div")) //为第一个子节点添加一个子节点,不会触发回调函数,如果需要触发,则需要设置subtree属性为true.observer.observe(target, {childList:true,subtree:true}) //subtree属性让观察行为进行"递归",这时,以target节点为根节点的整棵DOM树发生的变化都可能会被观察到observer.observe(document, {childList:true,subtree:true}) //如果target为document或者document.documentElement,则当前文档中所有的节点添加与删除操作都会被观察到observer.observe(document, {childList:true,attributes:true,characterData:true,subtree:true}) //当前文档中几乎所有类型的节点变化都会被观察到(包括属性节点的变化和文本节点的变化等)observer.observe(target, {childList:true}) //假设此时target的outHTML内容为<div>foo<div>,则:target.childNodes[0].data = "bar" //不会触发回调函数,因为childList只观察节点的新建与删除,而这里target节点的子节点仍然只有一个,没有多,没有少observer.observe(target, {childList:true,characterData:true}) //加上characterData属性,允许观察文本节点的变化,行不行?target.childNodes[0].data = "bar" //还是不会触发回调函数,因为发生变化的是target节点的子节点,我们目前的目标节点只有一个,就是target.observer.observe(target, {childList:true,characterData:true,subtree:true}) //加上subtree属性,观察所有后代节点target.childNodes[0].data = "bar" //触发了回调函数,发生变化的是target节点的文本子节点(必须同时有characterData和subtree属性,才能观察到一个元素目标节点里的文本内容的变化)observer.observe(target, {attributes:true}) //只观察目标节点的属性节点target.setAttribute("foo","bar") //不管foo属性存在不存在,都会触发回调函数target.setAttribute("foo","bar") //即使前后两次的属性值一样,还是会触发回调函数target.removeAttribute("foo") //移除foo属性节点,触发回调函数target.removeAttribute("foo") //不会触发回调函数,因为已经没有属性节点可移除了observer.observe(target, {attributes:true,attributeFilter:["bar"]}) //指定要观察的属性名target.setAttribute("foo","bar") //不会触发回调函数,因为attributeFilter数组不包含"foo"target.setAttribute("bar","foo") //触发了回调函数,因为attributeFilter数组包含了"bar" 外部链接 A brief overview A more in-depth discussion A screencast by Chromium developer Rafael Weinstein The mutation summary library The DOM4 specification which defines the MutationObserver interface]]></content>
</entry>
<entry>
<title><![CDATA[[转]基于视窗单位的排版]]></title>
<url>%2F2016%2F07%2F14%2F%E8%BD%AC-%E5%9F%BA%E4%BA%8E%E8%A7%86%E7%AA%97%E5%8D%95%E4%BD%8D%E7%9A%84%E6%8E%92%E7%89%88%2F</url>
<content type="text"><![CDATA[我之前有写过基于rem和em的[响应式排版],并且也有写过两篇有关模块化组件的博客。在这些文章中,有关视窗单位的评论不可避免的形成了一个话题。 曾经一段时间我十分抵制使用视窗单位,因为其中的计算实在让人感到十分痛苦。 上周,我终于克服了这个困难,决定探索一下视窗单位以及如何在响应式排版中使用它们。 在我们开始探索视窗单位以及如何运用它们之前,让我们先了解一下什么是视窗单位。 什么是视窗单位? 现在CSS中有关于视窗单位的可用种类主要有四种,他们是: vw:视窗宽度的百分比 vh:视窗高度的百分比 vmin:当前较小的vw和vh vmax:当前较大的vw和vh 在这种情况下,视窗,指的是浏览器屏幕。1vw就意味着1%的浏览器的宽度。100vw将意味着整个浏览器宽度。]]></content>
</entry>
<entry>
<title><![CDATA[SublimeText常用插件]]></title>
<url>%2F2016%2F06%2F30%2FSublimeText%E5%B8%B8%E7%94%A8%E6%8F%92%E4%BB%B6%2F</url>
<content type="text"><![CDATA[1. Package Control作为安装 Sublime Text 插件的必备利器,Package Control 是这款编辑器的标配,可以方便开发人员快速安装需要的插件。 2. EmmetEmmet (前身为 Zen Coding) 是一个能大幅度提高前端开发效率的一个工具: 基本上,大多数的文本编辑器都会允许你存储和重用一些代码块,我们称之为“片段”。虽然片段能很好地推动你得生产力,但大多数的实现都有这样一个缺点:你必须先定义你得代码片段,并且不能再运行时进行拓展。 Emmet把片段这个概念提高到了一个新的层次:你可以设置CSS形式的能够动态被解析的表达式,然后根据你所输入的缩写来得到相应的内容。Emmet是很成熟的并且非常适用于编写HTML/XML 和 CSS 代码的前端开发人员,但也可以用于编程语言。 3. Seti_UI它不仅色彩漂亮、看着舒适,还支持很多文件类型图标,让整个编辑器焕然一新。Seti UI 最初是 Atom 编辑器上的主题,但很快被开发者移植到了 Sublime Text 和 WebStorm 等编辑器上,甚至 iTerm(终端)上也有。下面分别介绍 Seti UI 在这些编辑器上的主题设置。 4. All AutocompleteSublime Text 默认的 Autocomplete 功能只考虑当前的文件,而 AllAutocomplete 插件会搜索所有打开的文件来寻找匹配的提示词。 5. SublimeREPL这可能是对程序员最有用的插件。SublimeREPL 允许你在 Sublime Texxt 中运行各种语言(NodeJS , Python,Ruby, Scala 和 Haskell 等等)。 6. DocBlockr如果你遵循的编码的风格很严格,这款插件能够使你的任务更容易。DocBlokr 帮助你创造你的代码注释,通过解析功能,参数,变量,并且自动添加基本项目。 7. Terminal当你想要打开在当前文件所在的目录的终端,这个插件可以帮助你。不过,在默认情况下,它设置按 Ctrl / Cmd + Shift + T 键的快捷方式打开终端。不过这也是打开上次关闭的文件的快捷方式,你需要修改一个快捷键来兼容两个功能。]]></content>
</entry>
<entry>
<title><![CDATA[JS正则表达式]]></title>
<url>%2F2016%2F06%2F29%2FJS%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%2F</url>
<content type="text"><![CDATA[正则表达式中的特殊字符 字符 含意 \ 做为转意,即通常在”\”后面的字符不按原来意义解释,如/b/匹配字符”b”,当b前面加了反斜杆后/\b/,转意为匹配一个单词的边界。 -或- 对正则表达式功能字符的还原,如”“匹配它前面元字符0次或多次,/a/将匹配a,aa,aaa,加了”\”后,/a*/将只匹配”a*”。 ^ 匹配一个输入或一行的开头,/^a/匹配”an A”,而不匹配”An a” $ 匹配一个输入或一行的结尾,/a$/匹配”An a”,而不匹配”an A” * 匹配前面元字符0次或多次,/ba*/将匹配b,ba,baa,baaa + 匹配前面元字符1次或多次,/ba*/将匹配ba,baa,baaa ? 匹配前面元字符0次或1次,/ba*/将匹配b,ba (x) 匹配x保存x在名为$1…$9的变量中 xly 匹配x或y(l代表竖线) {n} 精确匹配n次 {n,} 匹配n次以上 {n,m} 匹配n-m次 [xyz] 字符集(character set),匹配这个集合中的任一一个字符(或元字符) [^xyz] 不匹配这个集合中的任何一个字符 [\b] 匹配一个退格符 \b 匹配一个单词的边界 \B 匹配一个单词的非边界 \cX 这儿,X是一个控制符,/\cM/匹配Ctrl-M \d 匹配一个字数字符,/\d/ = /[0-9]/ \D 匹配一个非字数字符,/\D/ = /[^0-9]/ \n 匹配一个换行符 \r 匹配一个回车符 \s 匹配一个空白字符,包括\n,\r,\f,\t,\v等 \S 匹配一个非空白字符,等于/[^\n\f\r\t\v]/ \t 匹配一个制表符 \v 匹配一个重直制表符 \w 匹配一个可以组成单词的字符(alphanumeric,这是我的意译,含数字),包括下划线,如[\w]匹配”$5.98”中的5,等于[a-zA-Z0-9] \W 匹配一个不可以组成单词的字符,如[\W]匹配”$5.98”中的$,等于[^a-zA-Z0-9]。 用re = new RegExp(“pattern”,[“flags”]) 的方式比较好pattern : 正则表达式flags: g (全文查找出现的所有 pattern)i (忽略大小写)m (多行查找) vaScript动态正则表达式问题请问正则表达式可以动态生成吗?例如JavaScript中:var str = “strTemp”;要生成:var re = /strTemp/;如果是字符连接:var re = “/“ + str + “/“即可但是要生成表达式,可以实现吗?怎样实现? 正则表达式是一个描述字符模式的对象。JavaScript的RegExp对象和String对象定义了使用正则表达式来执行强大的模式匹配和文本检索与替换函数的方法.在JavaScript中,正则表达式是由一个RegExp对象表示的.当然,可以使用一个RegExp()构造函数来创建RegExp对象,也可以用JavaScript 1.2中的新添加的一个特殊语法来创建RegExp对象.就像字符串直接量被定义为包含在引号内的字符一样,正则表达式直接量也被定义为包含在一对斜杠(/)之间的字符.所以,JavaScript可能会包含如下的代码: 1var pattern = /s$/; 这行代码创建一个新的RegExp对象,并将它赋给变量parttern.这个特殊的RegExp对象和所有以字母”s”结尾的字符串都匹配.用RegExp()也可以定义一个等价的正则表达式,代码如下: 1var pattern = new RegExp("s$"); 无论是用正则表达式直接量还是用构造函数RegExp(),创建一个RegExp对象都是比较容易的.较为困难的任务是用正则表达式语法来描述字符的模式. JavaScript采用的是Perl语言正则表达式语法的一个相当完整的子集.正则表达式的模式规范是由一系列字符构成的.大多数字符(包括所有字母数字字符)描述的都是按照字面意思进行匹配的字符.这样说来,正则表达式/java/就和所有包含子串 “java” 的字符串相匹配.虽然正则表达式中的其它字符不是按照字面意思进行匹配的,但它们都具有特殊的意义.正则表达式 /s$/ 包含两个字符. 第一个特殊字符 “s” 是按照字面意思与自身相匹配.第二个字符 “$” 是一个特殊字符,它所匹配的是字符串的结尾.所以正则表达式 /s$/ 匹配的就是以字母 “s” 结尾的字符串. 1.直接量字符 我们已经发现了,在正则表达式中所有的字母字符和数字都是按照字面意思与自身相匹配的.JavaScript的正则表达式还通过以反斜杠()开头的转义序列支持某些非字母字符.例如,序列 “\n” 在字符串中匹配的是一个直接量换行符.在正则表达式中,许多标点符号都有特殊的含义.下面是这些字符和它们的含义:正则表达式的直接量字符 字符 匹配 字母数字字符 自身 \f 换页符 \n 换行符 \r 回车 \t 制表符 \v 垂直制表符 \/ 一个 / 直接量 \ 一个 \ 直接量 . 一个 . 直接量 * 一个 * 直接量 + 一个 + 直接量 \? 一个 ? 直接量 \l 一个 l 直接量(竖线) ( 一个 ( 直接量 ) 一个 ) 直接量 [ 一个 [ 直接量 ] 一个 ] 直接量 { 一个 { 直接量 } 一个 } 直接量 \XXX 由十进制数 XXX 指 定的ASCII码字符 \Xnn 由十六进制数 nn 指定的ASCII码字符 \cX 控制字符^X. 例如, \cI等价于 \t, \cJ等价于 \n 如果想在正则表达式中使用特殊的标点符号,必须在它们之前加上一个 “\” . 2.字符类将单独的直接符放进中括号内就可以组合成字符类.一个字符类和它所包含的任何一个字符都匹配,所以正则表达式 / [abc] / 和字母 “a” , “b” , “c” 中的任何一个都匹配.另外还可以定义否定字符类,这些类匹配的是除那些包含在中括号之内的字符外的所有字符.定义否定字符尖时,要将一个 ^ 符号作为从左中括号算起的第一个字符.正则表达式的集合是 / [a-zA-z0-9] / .由于某些字符类非常常用,所以JavaScript的正则表达式语法包含一些特殊字符和转义序列来表示这些常用的类.例如, \s 匹配的是空格符,制表符和其它空白符, \s 匹配的则是空白符之外的任何字符.正则表灰式的字符类字符 匹配 […] 位于括号之内的任意字符[^…] 不在括号之中的任意字符. 除了换行符之外的任意字符,等价于[^\n]\w 任何单字字符, 等价于[a-zA-Z0-9]\W 任何非单字字符,等价于[^a-zA-Z0-9]\s 任何空白符,等价于[\ t \ n \ r \ f \ v]\S 任何非空白符,等价于[^\ t \ n \ r \ f \ v]\d 任何数字,等价于[0-9]\D 除了数字之外的任何字符,等价于[^0-9][\b] 一个退格直接量(特例) 3.复制用以上的正则表式的语法,可以把两位数描述成 / \ d \ d /,把四位数描述成 / \d \ d \ d \ d /.但我们还没有一种方法可以用来描述具有任意多数位的数字或者是一个字符串.这个串由三个字符以及跟随在字母之后的一位数字构成.这些复杂的模式使用的正则表达式语法指定了该表达式中每个元素要重复出现的次数.指定复制的字符总是出现在它们所作用的模式后面.由于某种复制类型相当常用.所以有一些特殊的字符专门用于表示它们.例如: +号匹配的就是复制前一模式一次或多次的模式.下面的表列出了复制语法.先看一个例子:/\d{2, 4}/ //匹配2到4间的数字./\w{3} \d?/ //匹配三个单字字符和一个任意的数字./\s+java\s+/ //匹配字符串”java” ,并且该串前后可以有一个或多个空格./[^”] * / //匹配零个或多个非引号字符. 正则表达式的复制字符字符 含义 {n, m} 匹配前一项至少n次,但是不能超过m次{n, } 匹配前一项n次,或者多次{n} 匹配前一项恰好n次? 匹配前一项0次或1次,也就是说前一项是可选的. 等价于 {0, 1} 匹配前一项1次或多次,等价于{1,} 匹配前一项0次或多次.等价于{0,} 4.选择,分组和引用 正则表达式的语法还包括指定选择项,对子表达式分组和引用前一子表达式的特殊字符.字符| 用于分隔供选择的字符.例如: /ab|cd|ef/ 匹配的是字符串 “ab”,或者是字符串 “cd”,又或者 “ef”. /\d{3}|[a-z]{4}/ 匹配的是要么是一个三位数,要么是四个小写字母.在正则表达式中括号具有几种作用.它的主要作用是把单独的项目分组成子表达式,以便可以像处理一个独立的单元那种用 *、+或? 来处理那些项目.例如: /java(script) ?/ 匹配的是字符串 “java”,其后既可以有 “script”,也可以没有. / (ab|cd) + |ef) / 匹配的既可以是字符串 “ef”,也可以是字符串”ab” 或者 “cd” 的一次或多次重复.在正则表达式中,括号的第二个用途是在完整的模式中定义子模式。当一个正则表达式成功地和目标字符串相匹配时,可以从目标串中抽出和括号中的子模式相匹配的部分.例如,假定我们正在检索的模式是一个或多个字母后面跟随一位或多位数字,那么我们可以使用模式 / [a-z] + \ d+/.但是由于假定我们真正关心的是每个匹配尾部的数字,那么如果我们将模式的数字部分放在括号中 (/ [a-z] + (\d+)/) ,我们就可以从所检索到的任何匹配中抽取数字了,之后我们会对此进行解析的.代括号的子表达式的另一个用途是,允许我们在同一正则表达式的后面引用前面的子表达式.这是通过在字符串 \ 后加一位或多位数字来实现的.数字指的是代括号的子表达式在正则表达式中的位置.例如: \1 引用的是第一个代括号的子表达式. \3 引用的是第三个代括号的子表达式.注意,由于子表达式可以嵌套在其它子表达式中,所以它的位置是被计数的左括号的位置. 例如:在下面的正则表达式被指定为 \2: 1/([Jj]ava([Ss]cript)) \sis \s (fun\w*) / 对正则表达式中前一子表达式的引用所指定的并不是那个子表达式的模式,而是与那个模式相匹配的文本.这样,引用就不只是帮助你输入正则表达式的重复部分的快捷方式了,它还实施了一条规约,那就是一个字符串各个分离的部分包含的是完全相同的字符.例如:下面的正则表达式匹配的就是位于单引号或双引号之内的所有字符.但是,它要求开始和结束的引号匹配(例如两个都是双引号或者都是单引号): 1/[' "] [^ ' "]*[' "]/ 如果要求开始和结束的引号匹配,我们可以使用如下的引用: 1/( [' "] ) [^ ' "] * \1/ \1匹配的是第一个代括号的子表达式所匹配的模式.在这个例子中,它实施了一种规约,那就是开始的引号必须和结束的引号相匹配.注意,如果反斜杠后跟随的数字比代括号的子表达式数多,那么它就会被解析为一个十进制的转义序列,而不是一个引用.你可以坚持使用完整的三个字符来表示转义序列,这们就可以避免混淆了.例如, 使用 \044,而不是\44.下面是正则表达式的选择、分组和引用字符: 字符 含义 \ 选择.匹配的要么是该符号左边的子表达式,要么它右边的子表达式 (…) 分组.将几个项目分为一个单元.这个单元可由 *、+、?和 等符号使用,而且还可以记住和这个组匹配的字符以供此后引 用使用\n | 和第n个分组所匹配的字符相匹配.分组是括号中的子表达式(可能是嵌套的).分组号是从左到右计数的左括号数 5.指定匹配的位置 我们已经看到了,一个正则表达式中的许多元素才能够匹配字符串的一个字符.例如: \s 匹配的只是一个空白符.还有一些正则表达式的元素匹配的是字符之间宽度为0的空间,而不是实际的字符例如: \b 匹配的是一个词语的边界,也就是处于一个/w字字符和一个\w非字字符之间的边界.像\b 这样的字符并不指定任何一个匹配了的字符串中的字符,它们指定的是匹配所发生的合法位置.有时我们称这些元素为正则表达式的锚.因为它们将模式定位在检索字符串中的一个特定位置.最常用的锚元素是 ^, 它使模式依赖于字符串的开头,而锚元素$则使模式定位在字符串的末尾. 例如:要匹配词 “javascript” ,我们可以使用正则表达式 /^ javascript $/. 如果我们想检索 “java” 这个词自身 (不像在 “javascript” 中那样作为前缀),那么我们可以使用模式 /\s java \s /, 它要求在词语java之前和之后都有空格.但是这样作有两个问题.第一: 如果 “java” 出现在一个字符的开头或者是结尾.该模式就不会与之匹配,除非在开头和结尾处有一个空格. 第二: 当这个模式找到一个与之匹配的字符时,它返回的匹配的字符串前端和后端都有空格,这并不是我们想要的.因此,我们使用词语的边界 \b 来代替真正的空格符 \s 进行匹配. 结果表达式是 /\b java \b/.下面是正则表达式的锚字符: 字符 含义 ^ 匹配的是字符的开头,在多行检索中,匹配的是一行的开头 $ 匹配的是字符的结尾,在多行检索中,匹配的是一行的结尾 \b 匹配的是一个词语的边界.简而言之就是位于字符\w 和 \w之间的位置(注意:[\b]匹配的是退格符) \B 匹配的是非词语的边界的字符 6.属性 有关正则表达式的语法还有最后一个元素,那就是正则表达式的属性,它说明的是高级模式匹配的规则.和其它正则表达式语法不同,属性是在 / 符号之外说明的.即它们不出现在两个斜杠之间,而是位于第二个斜杠之后.javascript 1.2支持两个属性.属性 i 说明模式匹配应该是大小写不敏感的.属性 g 说明模式匹配应该是全局的.也就是说,应该找出被检索的字符串中所有的匹配.这两种属性联合起来就可以执行一个全局的,大小写不敏感的匹配. 例如: 要执行一个大小不敏感的检索以找到词语 “java” (或者是 “java” 、”JAVA”等) 的第一个具体值,我们可以使用大小不敏感的正则表达式 /\b java\b/i .如果要在一个字符串中找到 “java” 所有的具体值,我们还可以添加属性 g, 即 /\b java \b/gi . 以下是正则表达式的属性: 字符 含义 i 执行大小写不敏感的匹配 g 执行一个全局的匹配,简而言之,就是找到所有的匹配,而不是在找到第一个之后就停止了 除属性 g 和 i 之外,正则表达式就没有其它像属性一样的特性了.如果将构造函数 RegExp 的静态属性 multiline 设置为 true ,那么模式匹配将以多行的模式进行.在这种模式下,锚字符 ^ 和 $ 匹配的不只是检索字符串的开头和结尾,还匹配检索字符串内部的一行的开头和结尾.例如: 模式 /Java$/ 匹配的是 “Java”,但是并不匹配“Java\nis fun” .如果我们设置了 multiline 属性,那么后者也将被匹配: 1RegExp.multiline = true; 在JAVASCRIPT里面判断一个字符串是否是电子邮件的格式: 代码如下: 12345678910111213141516if(formname.email.value != formname.email.value.match(/^\w +[@]\w +[.][\w.] +$/)){ alert("您的电子邮件格式错误!"); formname.email.focus(); return false;}function dateVerify(date) { var reg = /^(\d{4})(-)(\d{2})\2(\d{2})$/; var r = date.match(reg); if(r == null) return false; var d = new Date(r[1], r[3]-1,r[4]); var newStr = d.getFullYear()+r[2]+(d.getMonth()+1)+r[2]+d.getDate(); date = r[1]+r[2]+((r[3]-1)+1)+r[2]+((r[4]-1)+1); return newStr == date;} javascript的17种正则表达式 1234567891011121314151617"^\\d+$" //非负整数(正整数 + 0)"^[0-9]*[1-9][0-9]*$" //正整数"^((-\\d+)|(0+))$" //非正整数(负整数 + 0)"^-[0-9]*[1-9][0-9]*$" //负整数"^-?\\d+$" //整数"^\\d+(\\.\\d+)?$" //非负浮点数(正浮点数 + 0)"^(([0-9]+\\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\\.[0-9]+)|([0-9]*[1-9][0-9]*))$" //正浮点数"^((-\\d+(\\.\\d+)?)|(0+(\\.0+)?))$" //非正浮点数(负浮点数 + 0)"^(-(([0-9]+\\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\\.[0-9]+)|([0-9]*[1-9][0-9]*)))$" //负浮点数"^(-?\\d+)(\\.\\d+)?$" //浮点数"^[A-Za-z]+$" //由26个英文字母组成的字符串"^[A-Z]+$" //由26个英文字母的大写组成的字符串"^[a-z]+$" //由26个英文字母的小写组成的字符串"^[A-Za-z0-9]+$" //由数字和26个英文字母组成的字符串"^\\w+$" //由数字、26个英文字母或者下划线组成的字符串"^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$" //email地址"^[a-zA-z]+://(\\w+(-\\w+)*)(\\.(\\w+(-\\w+)*))*(\\?\\S*)?$" //url 正则表达式对象的属性及方法 预定义的正则表达式拥有有以下静态属性:input, multiline, lastMatch, lastParen, leftContext, rightContext和$1到$9。其中input和multiline可以预设置。其他属性的值在执行过exec或test方法后被根据不同条件赋以不同的值。许多属性同时拥有长和短(perl风格)的两个名字,并且,这两个名字指向同一个值。(JavaScript模拟perl的正则表达式) 正则表达式对象的属性 属性 含义 $1…$9 如果它(们)存在,是匹配到的子串 $_ 参见input $* 参见multiline $& 参见lastMatch $+ 参见lastParen $` 参见leftContext $’’ 参见rightContext constructor 创建一个对象的一个特殊的函数原型 global 是否在整个串中匹配(bool型) ignoreCase 匹配时是否忽略大小写(bool型) input 被匹配的串 lastIndex 最后一次匹配的索引 lastParen 最后一个括号括起来的子串 leftContext 最近一次匹配以左的子串 multiline 是否进行多行匹配(bool型) prototype 允许附加属性给对象 rightContext 最近一次匹配以右的子串 source 正则表达式模式 lastIndex 最后一次匹配的索引 正则表达式对象的方法 方法 含义 compile 正则表达式比较 exec 执行查找 test 进行匹配 toSource 返回特定对象的定义(literal representing),其值可用来创建一个新的对象。重载Object.toSource方法得到的。 toString 返回特定对象的串。重载Object.toString方法得到的。 valueOf 返回特定对象的原始值。重载Object.valueOf方法得到 例子 代码如下: 123456<script language = "JavaScript"> var myReg = /(w+)s(w+)/; var str = "John Smith"; var newstr = str.replace(myReg, "$2, $1"); document.write(newstr);</script> 将输出”Smith, John” javascript正则表达式检验 代码如下: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263//校验是否全由数字组成function isDigit(s) { var patrn = /^[0-9]{1,20}$/; if (!patrn.exec(s)) return false return true}//校验登录名:只能输入5-20个以字母开头、可带数字、“_”、“.”的字串function isRegisterUserName(s) { var patrn = /^[a-zA-Z]{1}([a-zA-Z0-9]|[._]){4,19}$/; if (!patrn.exec(s)) return false return true;}//校验用户姓名:只能输入1-30个以字母开头的字串function isTrueName(s) { var patrn = /^[a-zA-Z]{1,30}$/; if (!patrn.exec(s)) return false return true;}//校验密码:只能输入6-20个字母、数字、下划线function isPasswd(s) { var patrn = /^(\w){6,20}$/; if (!patrn.exec(s)) return false return true;}//校验普通电话、传真号码:可以“+”开头,除数字外,可含有“-”function isTel(s) { //var patrn = /^[+]{0,1}(\d){1,3}[ ]?([-]?(\d){1,12})+$/; var patrn = /^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/; if (!patrn.exec(s)) return false return true}//校验手机号码:必须以数字开头,除数字外,可含有“-”function isMobil(s) { var patrn = /^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/; if (!patrn.exec(s)) return false return true}//校验邮政编码function isPostalCode(s) { //var patrn = /^[a-zA-Z0-9]{3,12}$/; var patrn = /^[a-zA-Z0-9 ]{3,12}$/; if (!patrn.exec(s)) return false return true}//校验搜索关键字function isSearch(s) { var patrn = /^[^`~!@#$%^&*()+=|\\\][\]\{\}:;'\,.<>/?]{1}[^`~!@$%^&()+=|\\\][\]\{\}:;'\,.<>?]{0,19}$/; if (!patrn.exec(s)) return false return true}function isIP(s) //by zergling{ var patrn = /^[0-9.]{1,20}$/; if (!patrn.exec(s)) return false return true} 正则表达式regular expression详述(一) 正则表达式是regular expression,看来英文比中文要好理解多了,就是检查表达式符不符合规定!!正则表达式有一个功能十分强大而又十分复杂的对象RegExp,在JavaScript1.2 版本以上提供。 下面我们看看有关正则表达式的介绍: 正则表达式对象用来规范一个规范的表达式(也就是表达式符不符合特定的要求,比如是不是Email地址格式等),它具有用来检查给出的字符串是否符合规则的属性和方法。 除此之外,你用RegExp构造器建立的个别正则表达式对象的属性,就已经预先定义好了正则表达式对象的静态属性,你可以随时使用它们。 核心对象: 在JavaScript 1.2, NES 3.0以上版本提供。 在JavaScript 1.3以后版本增加了toSource方法。 建立方法: 文字格式或RegExp构造器函数。 文字建立格式使用以下格式: 1/pattern/flags即/模式/标记 构造器函数方法使用方法如下: 1new RegExp("pattern"[, "flags"])即new RegExp("模式"[,"标记"]) 参数: pattern(模式) 表示正则表达式的文本 flags(标记) 如果指定此项,flags可以是下面值之一: g: global match(全定匹配) i: ignore case(忽略大小写) gi: both global match and ignore case(匹配所有可能的值,也忽略大小写)注意:文本格式中的参数不要使用引号标记,而构造器函数的参数则要使用引号标记。所以下面的表达式建立同样的正则表达式:12/ab+c/inew RegExp("ab+c", "i") 描述: 当使用构造函数的时候,必须使用正常的字符串避开规则(在字符串中加入前导字符\ )是必须的。 例如,下面的两条语句是等价的: 12re = new RegExp("\\w+")re = /\w+/ 下面的提供了在正则表达式中能够使用的完整对特殊字符的一个完整的列表和描述。 表1.3:正则表达式中的特殊字符: 字符\ 意义:对于字符,通常表示按字面意义,指出接着的字符为特殊字符,\不作解释。 例如:/b/匹配字符’b’,通过在b 前面加一个反斜杠\,也就是/\b/,则该字符变成特殊字符,表示匹配一个单词的分界线。 或者: 对于几个字符,通常说明是特殊的,指出紧接着的字符不是特殊的,而应该按字面解释。 例如:是一个特殊字符,匹配任意个字符(包括0个字符);例如:/a/意味匹配0个或多个a。 为了匹配字面上的,在a前面加一个反斜杠;例如:/a\/匹配’a*’。 字符^ 意义:表示匹配的字符必须在最前边。 例如:/^A/不匹配”an A,”中的’A’,但匹配”An A.”中最前面的’A’。 字符$ 意义:与^类似,匹配最末的字符。 例如:/t$/不匹配”eater”中的’t’,但匹配”eat”中的’t’。 字符* 意义:匹配*前面的字符0次或n次。 例如:/bo*/匹配”A ghost booooed”中的’boooo’或”A bird warbled”中的’b’,但不匹配”A goat grunted”中的任何字符。 字符+ 意义:匹配+号前面的字符1次或n次。等价于{1,}。 例如:/a+/匹配”candy”中的’a’和”caaaaaaandy.”中的所有’a’。 字符? 意义:匹配?前面的字符0次或1次。 例如:/e?le?/匹配”angel”中的’el’和”angle.”中的’le’。 字符. 意义:(小数点)匹配除换行符外的所有单个的字符。 例如:/.n/匹配”nay, an apple is on the tree”中的’an’和’on’,但不匹配’nay’。 字符(x) 意义:匹配’x’并记录匹配的值。 例如:/(foo)/匹配和记录”foo bar.”中的’foo’。匹配子串能被结果数组中的素[1], …, [n] 返回,或被RegExp对象的属性$1, …, $9返回。 字符x|y 意义:匹配’x’或者’y’。 例如:/green|red/匹配”green apple”中的’green’和”red apple.”中的’red’。 字符{n} 意义:这里的n是一个正整数。匹配前面的n个字符。 例如:/a{2}/不匹配”candy,”中的’a’,但匹配”caandy,” 中的所有’a’和”caaandy.”中前面的两个‘a’。 字符{n,} 意义:这里的n是一个正整数。匹配至少n个前面的字符。 例如:/a{2,}不匹配”candy”中的’a’,但匹配”caandy”中的所有’a’和”caaaaaaandy.”中的所有’a’ 字符{n,m} 意义:这里的n和m都是正整数。匹配至少n个最多m个前面的字符。 例如:/a{1,3}/不匹配”cndy”中的任何字符,但匹配 “candy,”中的’a’,”caandy,” 中的前面两个‘a’和”caaaaaaandy”中前面的三个’a’,注意:即使”caaaaaaandy” 中有很多个’a’,但只匹配前面的三个’a’即”aaa”。 字符[xyz] 意义:一字符列表,匹配列出中的任一字符。你可以通过连字符-指出一个字符范围。 例如:[abcd]跟[a-c]一样。它们匹配”brisket”中的’b’和”ache”中的’c’。 字符[^xyz] 意义:一字符补集,也就是说,它匹配除了列出的字符外的所有东西。 你可以使用连字符-指出一 字符范围。 例如:[^abc]和[^a-c]等价,它们最早匹配”brisket”中的’r’和”chop.”中的’h’。 字符[\b] 意义:匹配一个空格(不要与\b混淆) 字符\b 意义:匹配一个单词的分界线,比如一个空格(不要与[\b]混淆) 例如:/\bn\w/匹配”noonday”中的’no’,/\wy\b/匹配”possibly yesterday.”中的’ly’。 字符\B 意义:匹配一个单词的非分界线 例如:/\w\Bn/匹配”noonday”中的’on’,/y\B\w/匹配”possibly yesterday.”中的’ye’。 字符\cX 意义:这里的X是一个控制字符。匹配一个字符串的控制字符。 例如:/\cM/匹配一个字符串中的control-M。 字符\d 意义:匹配一个数字,等价于[0-9]。 例如:/\d/或/[0-9]/匹配”B2 is the suite number.”中的’2’。 字符\D 意义:匹配任何的非数字,等价于[^0-9]。 例如:/\D/或/[^0-9]/匹配”B2 is the suite number.”中的’B’。 字符\f 意义:匹配一个表单符 字符\n 意义:匹配一个换行符 字符\r 意义:匹配一个回车符 字符\s 意义:匹配一个单个white空格符,包括空格,tab,form feed,换行符,等价于[ \f\n\r\t\v]。 例如:/\s\w*/匹配”foo bar.”中的’ bar’。 字符\S 意义:匹配除white空格符以外的一个单个的字符,等价于[^ \f\n\r\t\v]。 例如:/\S/\w*匹配”foo bar.”中的’foo’。 字符\t 意义:匹配一个制表符 字符\v 意义:匹配一个顶头制表符 字符\w 意义:匹配所有的数字和字母以及下划线,等价于[A-Za-z0-9_]。 例如:/\w/匹配”apple,”中的’a’,”$5.28,”中的’5’和”3D.”中的’3’。 字符\W 意义:匹配除数字、字母外及下划线外的其它字符,等价于[^A-Za-z0-9_]。 例如:/\W/或者/[^$A-Za-z0-9_]/匹配”50%.”中的’%’。 字符\n 意义:这里的n是一个正整数。匹配一个正则表达式的最后一个子串的n的值(计数左圆括号)。 例如:/apple(,)\sorange\1/匹配”apple, orange, cherry, peach.”中的’apple, orange’,下面有一个更加完整的例子。 注意:如果左圆括号中的数字比\n指定的数字还小,则\n取下一行的八进制escape作为描述。 字符\ooctal和\xhex 意义:这里的\ooctal是一个八进制的escape值,而\xhex是一个十六进制的escape值,允许在一个正则表达式中嵌入ASCII码。 当表达式被检查的时候,文字符号提供了编辑正则表达式的方法。利用文字符号可以使到正则表达式保持为常数。例如,如果你在一个循环中使用文字符号来构造一个正则表达式,正则表达式不需进行反复编译。正则表达式对象构造器,例如,new RegExp(“ab+c”),提供正则表达式的运行时编译。当你知道正则表达式的模式会变化的时候,应该使用构造函数,或者你不知道正则表达式的模式,而它们是从另外的源获得的时候,比如由用户输入时。一旦你定义好了正则表达式,该正则表达式可在任何地方使用,并且可以改变,你可以使用编译方法来编译一个新的正则表达式以便重新使用。 一个分离预先定义的RegExp对象可以在每个窗口中使用;也就是说,每个分离的JavaScript线程运行以获得自己的RegExp对象。因为每个脚本在一个线程中是不可中断的,这就确保了不同的脚本不会覆盖RegExp对象的值。预定义的RegExp对象包含的静态属性:input, multiline, lastMatch,lastParen, leftContext, rightContext, 以及从$1到$9。input和multiline属性能被预设。其它静态属性的值是在执行个别正则表达式对象的exec和test方法后,且在执行字符串的match和replace方法后设置的。 属性 注意RegExp对象的几个属性既有长名字又有短名字(象Perl)。这些名字都是指向相同的值。Perl是一种编程语言,而JavaScript模仿了它的正则表达式。 属性$1, …, $9 取得匹配的子串,如果有的话 属性$_ 参考input属性$*参考multiline属性$&参考lastMatch属性$+参考lastParen属性$`参考leftContext属性$’参考rightContext属性constructor指定用来建立对象原型函属性global决定是否测试正则表达式是否不能匹配所有的字符串,或者只是与最先的冲突。属性ignoreCase决定试图匹配字符串的时候是否忽略大小写属性input当正则表达式被匹配的时候,为相反的字符串。属性lastIndex决定下一次匹配从那里开始属性lastMatch最后一个匹配的字符属性lastParen子串匹配的时候,最后一个parenthesized,如果有的话。属性leftContext最近一次匹配前的子串。属性multiline是否在串的多行中搜索。属性prototype允许附加属性到所有的对象属性rightContext最近一次匹配后的的子串。属性source模式文本方法compile方法编译一个正则表达式对象exec方法运行正则表达式匹配test方法测试正则达式匹配toSource方法返回一个对象的文字描述指定的对象;你可以使用这个值来建立一个新的对象。不考虑Object.toSource方法。toString方法返回一个字符串描述指定的对象,不考虑Object.toString对象。valueOf方法返回指定对角的原始值。不考虑Object.valueOf方法。另外,这个对象继承了对象的watch和unwatch方法 例子:例1、下述示例脚本使用replace方法来转换串中的单词。在替换的文本中,脚本使用全局 RegExp对象的$1和$2属性的值。注意,在作为第二个参数传递给replace方法的时候,RegExp对象的$属性的名称。 123456<SCRIPT LANGUAGE="JavaScript1.2">re = /(\w+)\s(\w+)/;str = "John Smith";newstr=str.replace(re,"$2, $1");document.write(newstr)</SCRIPT> 显示结果:”Smith, John”.例2、下述示例脚本中,RegExp.input由Change事件处理句柄设置。在getInfo函数中,exec 方法使用RegExp.input的值作为它的参数,注意RegExp预置了$属性。 1234567891011<SCRIPT LANGUAGE="JavaScript1.2">function getInfo(abc) { re = /(\w+)\s(\d+)/; re.exec(abc.value); window.alert(RegExp.$1 + ", your age is " + RegExp.$2);}</SCRIPT>请输入你的姓和年龄,输入完后按回车键。<FORM> <INPUT TYPE="TEXT" NAME="NameAge" onChange="getInfo(this);"></FORM> $1, …, $9属性 用圆括号括着的匹配子串,如果有的话。 是RegExp的属性 静态,只读 在JavaScript 1.2, NES 3.0以上版本提供 描述:因为input是静态属性,不是个别正则表达式对象的属性。你可以使用RegExp.input 访问该属性。 能加上圆括号的子串的数量不受限制,但正则表达式对象只能保留最后9 条。如果你要访问所有的圆括号内的匹配字串,你可以使用返回的数组。 这些属性能用在RegExp.replace方法替换后的字符串(输出结果)。当使用这种方式的时候,不用预 先考虑RegExp对象。下面给出例子。当正则表达式中没有包含圆括号的时候,该脚本解释成$n的字面意义。(这里的n是一个正整数)。 例如: 下例脚本使用replace 方法来交换串中单词的位置。在替换后的文本字串中,脚本使用正则表达式RegExp对象的$1和$2属性的值。注意:当它们向replace方法传递参数的时候,这里没有考虑 $ 属性的RegExp对象的名称。 123456<SCRIPT LANGUAGE="JavaScript1.2"> re = /(\w+)\s(\w+)/; str = "John Smith"; newstr = str.replace(re,"$2, $1"); document.write(newstr)</SCRIPT> 显示的输出结果为:Smith, John。 正则表达式regular expression详述(二) 正则表达式详述(二) 以下这些不是正则表达式的新增对象请参阅对应的JavaScript对象的属性 $_属性 参考input $*属性参考multiline $&属性 参考lastMatch $+属性 参考lastParen $`属性参考leftContext $’属性 参考rightContext compile方法 在脚本运行期间编译正则表达式对象属于RegExp的方法 在JavaScript 1.2, NES 3.0以上版本提供 语法:regexp.compile(pattern[, flags]) 以数: regexp 正则表达式的名称,可以是变量名或文字串。pattern 正则表达式的定义文本。 flags 如果指定的话,可以是下面其中的一个: “g”: 匹配所有可能的字串“i”: 忽略大小写 “gi”: 匹配所有可能的字串及忽略大小写 描述:使用compile方法来编译一个正则表达式 created with the RegExp constructor function。这样就强制正则表达式只编译一次,而不是每次遇到正则表达式的时候都编译一次。当你确认正则表达式能保持不变的时候可使用compile 方法来编译它(在获得它的匹配模式后),这样就可以在脚本中重复多次使用它。你亦可以使用compile 方法来改变在运行期间改变正则表达式。例如,假如正则表达式发生变化,你可以使用compile方法来重新编译该对象来提高使用效率。使用该方法将改变正则表达式的source, global和ignoreCasesource属性的值。 constructor指出建立对象原型的function。注意这个属性的值由函数本身提供,而不是一个字串包含RegExp的name.Property提供。在JavaScript 1.1, NES 2.0以上版本提供 ECMA版本ECMA-262 描述:参考Object.constructor.exec方法 在指定的字符串运行匹配搜索。返回一个结果数组。 是RegExp的方法在JavaScript 1.2, NES 3.0以上版本提供 语法: regexp.exec([str])regexp([str])参数: regexp,正则表达式的名称,可以是一个变量名或文字定义串。str,要匹配正则表达式的字符串,如果省略,将使用RegExp.input的值。描述:就如在语法描述中的一样,正则表达工的exec方法能够被直接调用(使用regexp.exec(str))或者间接调用(使用regexp(str))。假如你只是运行以找出是否匹配,可以使用String搜索方法。假如匹配成功,exec方法返回一个数组并且更新正则表达式对象属性的值和预先定义的正则表达式对象、RegExp。如果匹配失败,exec方法返回null。请看下例: //匹配一个b接着一个或多个d,再接着一个b//忽略大小写 myRe=/d(b+)(d)/ig; myArray = myRe.exec(“cdbBdbsbz”); 下面是该脚本的返回值:对象 属性/Index 描述 例子myArraymyArray的内容 [“dbBd”, “bB”, “d”]index基于0的匹配index 1input原始字符串 cdbBdbsbz[0]最后匹配的字符 dbBd[1], …[n]用圆括号括住的匹配字符串,如果有的话。不限制括号的个数。 [1] = bB[2] = dmyRelastIndex开始下次匹配操作的index值 5ignoreCase指出”i”是否使用以忽略大小写 trueglobal指出是否使用”g”标记来进行匹配所有可能的字串 truesource定义模式的文本字符串 d(b+)(d)RegExplastMatch$&最后匹配的字符 dbBdleftContext$\Q最新匹配前面的子串 crightContext$’最新匹配后面的子串 bsbz$1, …$9圆括号内的匹配子串,如果有的话。圆括号的个数不受限制,但RegExp只能保留最后9个 $1 = bB$2 = dlastParen $+最后一个加上圆括号的匹配子串,如果有的话 d假如你的正则表达式使用了”g”标记,你可以多次使用exec 方法来连续匹配相同的串。当你这样做的时候,新的匹配将从由正则表达式的lastIndex 属性值确定的子串中开始。例如,假定你使用下面的脚本: myRe=/ab*/g;str = “abbcdefabh”myArray = myRe.exec(str);document.writeln(“Found “+myArray[0]+”. Next match starts at “+myRe.lastIndex)mySecondArray = myRe.exec(str);document.writeln(“Found “+mySecondArray[0]+”. Next match starts at “+myRe.lastIndex)这个脚本显示如下结果: Found abb. Next match starts at 3Found ab. Next match starts at 9 例子:在下面的例子中,用户输入一个名字,脚本根据输入执行匹配操作。接着检查数组看是否和其它用户的名字匹配。本脚本假定已注册的用户的姓已经存进了数组A中,或许从一个数据库中取得。 A = [“zhao”,”qian”,”sun”,”li”,”liang”]function lookup() { firstName = /\w+/i(); if (!firstName)window.alert (RegExp.input + “非法输入”); else { count=0;for (i=0;i 输入你的姓然后按回车键。 global属性 正则表达式中是否使用了”g”标记。 RegExp属性,只读在JavaScript 1.2, NES 3.0以上版本提供 描述: global是一个个别正则表达式对象的属性如果使用了”g”标记,global的值为true;否则为 false。”g”标记指定正则表达式测试所有可能的匹配。你不能直接改变该属性的值,但可以调用compile方法来改变它。 ignoreCase 检查正则表达式是否使用了”i”标记RegExp属性,只读 在JavaScript 1.2, NES 3.0以上版本提供 描述:ignoreCase是个别正则表达式对象的一个属性。如果使用了”i”标记,则返回true,否则返回false。”i”标记指示在进行匹配的时候忽略大小写。你不能直接改变该属性的值,但可以通过调用compile方法来改变它 input 指出正则表达式要测试那个字串。$_是这个属性的另一个名字。RegExp的属性,静态 在JavaScript 1.2, NES 3.0以上版本提供描述:因为input是静态的,不是某个个别的正则表达式对象的属性。你也可以使用 RegExp.input来表示。如果没有给正则表达式的exec或test方法提供字符串,并且RegExp.input中有值,则使用它的值来调用该方法。脚本或浏览器能够预置input属性。如果被预置了值且调用exec或 test方法的时候没有提供字符串则调用exec或test的时候使用input的值。input可以被浏览器以下面的方式设置:当text表单域处理句柄被调用的时候,input被设置为该text输入的字串。当textarea表单域处理句柄被调用的时候,input被设置为textarea域内输入的字串。注意multiline亦被设置成true从而能匹配多行文本。 当select表单域处理句柄被调用的时候,input被设置成selected text的值。当链接对象的处理句柄被调用的时候,input被设置成和之间的字符串。事件理现句柄处理完毕后,input属性的值被清除。 lastIndex 可读/可写的一个整数属性,指出下一次匹配从哪里开始。RegExp的属性 在JavaScript 1.2, NES 3.0以上版本提供描述:lastIndex 是个别的正则表达式对象的属性。 这个属性只有当正则表达式的”g”标记被使用以进行全串匹配的时候才被设置。实行以下规则:如果lastIndex大小字符串的长度,regexp.test和regexp.exec失败,且lastIndex被设为0。如果lastIndex等于字串的长度且正则表达式匹配空字符串,则正则表达式从lastIndex的位置开始匹配。如果lastIndex等于字符串的长度且正则表达式不匹配空字符串,则正则表达式不匹配input,且lastIndex被置为0。否则,lastIndex被设置成最近一次匹配的下一点。 例如,按下面的顺序执行脚本: re = /(hi)?/g 匹配空字符串re(“hi”) 返回[“hi”, “hi”],lastIndex置为2re(“hi”) 返回[“”],一个空数组,它的下标为0的元素就是匹配字符串。在这种情况下,返回空串是因为lastIndex等于2(且仍然是2),并且”hi”的长度也是2。 lastMatch 最后一次匹配字符串,$&是同样的意思。RegExp的属性,静态,只读 在JavaScript 1.2, NES 3.0以上版本提供描述:因为lastMatch是静态的,所以它不是个别指定正则表达式的属性。你也可以使用RegExp.lastMatch。 lastParen最后一次加上括号的匹配字符串,如果有的话。$+是同样的意思。 RegExp属性,静态,只读在JavaScript 1.2, NES 3.0以上版本提供描述:因为lastParen是静态的,它不是某个个别正则式的属性,你可以使用RegExp.lastParen 表达同样的意思。leftContext 最近一次匹配前面的子串,$`具有相同的意思。 RegExp的属性,静态,只读在JavaScript 1.2, NES 3.0以上版本提供描述:因为leftContext是静态的,不是某一个正则表达式的属性,所以可以使用RegExp.leftContext来表达想同的意思。multiline 反映是否匹配多行文本,$*是相同的意思。 RegExp的属性,静态在JavaScript 1.2, NES 3.0以上版本提供描述:因为multiline是静态的,而不是某个个别正则表达式的属性,所以能够用RegExp.multiline表达相同的意思。如果允许匹配多行文本,则multiline为true,如果搜索必须在换行时停止,则为false。脚本或浏览器能够设置multiline属性。当一个textarea的事件处理句柄被调用的时候,multiline被置为true。在事件处理句柄处理完毕后,multiline属性值被清除。也就是说,如果你设置了multiline为true,则执行任何的事件处理句柄后,multiline被置为false。 prototype描绘类的原型。你可以根据要求使用prototype来增加类的属性或方法。为了获得prototypes 的资料,请参阅RegExp的Function.prototype.Property属性。 从JavaScript 1.1, NES 2.0版本开始提供ECMA版本ECMA-262 rightContext 最后一次匹配的右边的字符串,$’是同样的效果。RegExp的属性,静态,只读 从 JavaScript 1.2, NES 3.0以上版本开始提供描述:因为rightContext是静态的,不是某个个别正则表达工的属性,可以使用RegExp.rightContext来达到相同的效果。source 一个只读属性,包含正则表达式定义的模式,不包侨forward slashes和”g”或”i”标记。 RegExp的属性,只读从JavaScript 1.2, NES 3.0以上版本开始提供描述:source是个别正则表达式对象的属性,你不能直接改变它的值,但可以通过调用compile 方法来改变它。 test执行指定字符串的正则表达式匹配搜索,返回true或false。 RegExp的方法从JavaScript 1.2, NES 3.0以上版本开始提供 语法:regexp.test([str])参数:regexp,正则表达式的名称,可以是变量名或正则表达式定义文字串str,要匹配的字符串,如果省略,将使用RegExp.input的值为作参数描述:当你需要知道一个字符串能否匹配某个正则表达工,可以使用test方法(与String.search方法类似); 为了获得更多的信息(但速度将变慢),可以使用exec方法(与String.match方法类似)。 例子:下面的例子显示test是否成功的提示:function testinput(re, str){if (re.test(str)) midstring = “ contains “;else midstring = “ does not contain “;document.write (str + midstring + re.source); } toSource返回一个字符串象征对象的源码 RegExp的方法 从JavaScript 1.3以上版本开始提供 语法:toSource()参数:没有 描述:toSource方法返回下述的值: 对于内置的RegExp对象,toSource返回下面的字符象征源码不可用:function Boolean(){ [native code] }在RegExp场合中, toSource返回象征源码的字符串,通常这个方法是由JavaScript内部自动调用而不是不代码中显式调用。更多请看Object.toSource toString 返回描绘指定对象的字符串。 RegExp的方法从JavaScript 1.1, NES 2.0开始提供 ECMA版本ECMA-262 语法:toString() 参数:无描述:RegExp对象不考虑Object对象的toString方法;它不继承Object.toString,对于RegExp 对象,toString方法返回一个代表该对象的字符串。 例如:下面的例子显示象征RegExp对象的字符串myExp = new RegExp(“a+b+c”); alert(myExp.toString())displays “/a+b+c/“ 更多请看:Object.toString valueOf 返回一个RegExp对象的原始值RegExp的方法 从JavaScript 1.1版本开始提供 ECMA版本:ECMA-262 语法:valueOf()参数:无 描述:RegExp的valueOf方法以字符串形式返回RegExp对象的原始值,这个值与RegExp.toString相等。该方法通常由JavaScript内部自动调用而不是显式调用 例子: myExp = new RegExp(“a+b+c”);alert(myExp.valueOf()) displays “/a+b+c/“ 正则表达式在javascript中的几个实例1(转) ! 去除字符串两端空格的处理 如果采用传统的方式,就要可能就要采用下面的方式了 代码如下: 1234567891011121314151617181920212223242526272829303132333435363738// 清除左边空格function js_ltrim(deststr) { if (deststr == null) return ""; var pos = 0; var retStr = new String(deststr); if (retStr.lenght == 0) return retStr; while (retStr.substring(pos, pos + 1) == " ") pos++; retStr = retStr.substring(pos); return (retStr);}// 清除右边空格function js_rtrim(deststr) { if (deststr == null) return ""; var retStr = new String(deststr); var pos = retStr.length; if (pos == 0) return retStr; while (pos && retStr.substring(pos - 1, pos) == " ") pos--; retStr = retStr.substring(0, pos); return (retStr);}// 清除左边和右边空格function js_trim(deststr) { if (deststr == null) return ""; var retStr = new String(deststr); var pos = retStr.length; if (pos == 0) return retStr; retStr = js_ltrim(retStr); retStr = js_rtrim(retStr); return retStr;} 采用正则表达式,来去除两边的空格,只需以下代码 123String.prototype.trim = function() { return this.replace(/(^\s*)|(\s*$)/g, "");} 一句就搞定了, 可见正则表达式为我们节省了相当的编写代码量 ! 移动手机号的校验 如果采用传统的校验方式至少就要完成下面三步的校验, (1). 是否是数字 (2).是否是11位 (3).数字的第三位是否是5,6,7,8,9 如果采用正则表达式校验,只需以下代码 1234567891011function checkMobile1(form) { if (form.mobile.value > "") { var reg = /13[5,6,7,8,9]\d{8}/; if (form.mobile.value.match(reg) == null) { alert("请输入正确的移动手机号码!"); form.mobile.focus(); return false; } } return true;} 从上面的代码可以看出校验移动手机号只需定义一个var reg=/13[5,6,7,8,9]\d{8}/;模式匹配串就可以完成合法性校验了! URL的校验,条件:必须以http:// 或 https:// 开头, 端口号必须为在1-65535 之间, 以下代码完成了合法性校验复制代码 代码如下: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546// obj:数据对象// dispStr :失败提示内容显示字符串function checkUrlValid(obj, dispStr) { if (obj == null) { alert("传入对象为空"); return false; } var str = obj.value; var urlpatern0 = /^https?:\/\/.+$/i; if (!urlpatern0.test(str)) { alert(dispStr + "不合法:必须以'http:\/\/'或'https:\/\/'开头!"); obj.focus(); return false; } var urlpatern2 = /^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?.+$/i; if (!urlpatern2.test(str)) { alert(dispStr + "端口号必须为数字且应在1-65535之间!"); obj.focus(); return false; } var urlpatern1 = /^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$/i; if (!urlpatern1.test(str)) { alert(dispStr + "不合法,请检查!"); obj.focus(); return false; } var s = "0"; var t = 0; var re = new RegExp(":\\d+", "ig"); while ((arr = re.exec(str)) != null) { s = str.substring(RegExp.index + 1, RegExp.lastIndex); if (s.substring(0, 1) == "0") { alert(dispStr + "端口号不能以0开头!"); obj.focus(); return false; } t = parseInt(s); if (t < 1 || t > 65535) { alert(dispStr + "端口号必须为数字且应在1-65535之间!"); obj.focus(); return false; } } return true;} 对url的校验,看上去有很多的代码,这是因为要给予出错提示, 否则只需 1var urlpatern1 =/^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$/i; 一句就可以校验出url合法性了 正则表达式在JavaScript应用 去掉字符串头尾多余的空格 /g是全文查找所有匹配 123function String.prototype.Trim(){return this.replace(/(^\s*)|(\s*$)/g, "");}function String.prototype.LTrim(){return this.replace(/(^\s*)/g, "");}function String.prototype.RTrim(){return this.replace(/(\s*$)/g, "");} 应用:计算字符串的长度(一个双字节字符长度计2,ASCII字符计1) 12345String.prototype.len=function(){return this.replace([^\x00-\xff]/g,"aa").length;}``--------------------------------------------------------------应用:javascript中没有像vbscript那样的trim函数,我们就可以利用这个表达式来实现,如下: String.prototype.trim = function() {return this.replace(/(^\s)|(\s$)/g, “”);}12得用正则表达式从URL地址中提取文件名的javascript程序,如下结果为page1 s=”http://www.jb51.net/page1.htm“s=s.replace(/(.\/){0,}([^.]+)./ig,”$2”)alert(s)12345678910111213141516##利用正则表达式限制网页表单里的文本框输入内容:--------------------------------------------------------------用正则表达式限制只能输入中文:`onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,'))"`--------------------------------------------------------------用正则表达式限制只能输入全角字符: `onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\uFF00-\uFFFF]/g,'))"`--------------------------------------------------------------用正则表达式限制只能输入数字:`onkeyup="value=value.replace(/[^\d]/g,') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,'))"`--------------------------------------------------------------用正则表达式限制只能输入数字和英文:`onkeyup="value=value.replace(/[\W]/g,') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,'))" `用正则表达式和javascript对表单进行全面验证使用时请将下面的javascript代码存到一个单一的js文件中。1、表单要求 12345678910111213141516171819202122232425将对表单中的所有以下类型的域依次验证,所有验证是去除了前导和后缀空格的,要注意是区分大小写的。2、空值验证表单中任意域加上emptyInfo属性将对此域是否为空进行验证(可以和最大长度验证\一般验证方式同时使用)。无此属性视为此域允许空值。如:`<input type="text" name="fieldNamename" emptyInfo="字段不能为空!">`3、最大长度验证(可以和空值验证、一般验证方式同时使用):`<input type="text" name="fieldNamename" maxlength="20" lengthInfo="最大长度不能超过20!"> `或,`<textarea maxlength="2000" lengthInfo="最大长度不能超过2000!">`3、一般验证方式(不对空值做验证):如:`<input type="text" validator="^(19|20)[0-9]{2}$" errorInfo="不正确的年份!" >`4、标准验证(不与其它验证方式同时使用):全部通过`<input type="hidden">`来实现,并且不需要name属性以免提交到服务器。4.1、合法日期验证: 注:这里也可以是,以下同 12345yearfieldName、monthfieldName、dayfieldName分别为年月日字段,月和日可以是两位(MM)或一位格式(M),此处不对每个字段分别检验(如果要检验,请在年月日三个域分别使用前面的一般验证方式),只对日期的最大值是否合法检查;4.2、日期格式验证(请注意,此验证不对日期是否有效进行验证,还未找到从格式中得到年月日数据的方法^_^): 123456其中格式仅对y、M、d、H、m、s进行支持(其它字符视为非时间的字符)4.3、列表验证:检验列表(checkbox、redio、select)是否至少选中了一条记录(对select主要用于多项选择) 1234其中validatorType可以是Checkbox、R、Select;对于一个select表单,如果要求选择一条不能是第一条的记录,请用下列方式: ==请选择== 1 124.4、Email验证: 1234其中separator为可选项,表示输入多个email时的分隔符(无此选项只能是一个地址)4.5、加入其它javascript操作: function functionname(){ // code here}12345表单中加入`<input type="hidden" validatorType="javascript" functionName="functionname">`(此时emptyInfo等属性无效)时将调用function属性中指定的javascript方法(要求方法返回true或false,返回false将不再验证表单,也不提交表单)。5、在表单通过验证提交前disable一个按钮(也可将其它域disable,不能与其它验证同在一个域),不要求按钮是表单中的最后一个 126、不验证表单 123456当validator域值为0时不对表单进行验证,直接提交表单或执行指定function并返回true后提交表单functionName为可选代码如下: function getStringLength(str) { var endvalue = 0; var sourcestr = new String(str); var tempstr; for (var strposition = 0; strposition < sourcestr.length; strposition++) { tempstr = sourcestr.charAt(strposition); if (tempstr.charCodeAt(0) > 255 || tempstr.charCodeAt(0) < 0) { endvalue = endvalue + 2; } else { endvalue = endvalue + 1; } } return (endvalue);}function trim(str) { if (str == null) return “”; if (str.length == 0) return “”; var i = 0, j = str.length - 1, c; for (; i < str.length; i++) { c = str.charAt(i); if (c != ‘ ‘) break; } for (; j > -1; j–) { c = str.charAt(j); if (c != ‘ ‘) break; } if (i > j) return “”; return str.substring(i, j + 1);}function validateDate(date, format, alt) { var time = trim(date.value); if (time == “”) return; var reg = format; var reg = reg.replace(/yyyy/, “[0-9]{4}”); var reg = reg.replace(/yy/, “[0-9]{2}”); var reg = reg.replace(/MM/, “((0[1-9])|1[0-2])”); var reg = reg.replace(/M/, “(([1-9])|1[0-2])”); var reg = reg.replace(/dd/, “((0[1-9])|([1-2][0-9])|30|31)”); var reg = reg.replace(/d/, “([1-9]|[1-2][0-9]|30|31))”); var reg = reg.replace(/HH/, “(([0-1][0-9])|20|21|22|23)”); var reg = reg.replace(/H/, “([0-9]|1[0-9]|20|21|22|23)”); var reg = reg.replace(/mm/, “([0-5][0-9])”); var reg = reg.replace(/m/, “([0-9]|([1-5][0-9]))”); var reg = reg.replace(/ss/, “([0-5][0-9])”); var reg = reg.replace(/s/, “([0-9]|([1-5][0-9]))”); reg = new RegExp(“^” + reg + “$”); if (reg.test(time) == false) {// 验证格式是否合法 alert(alt); date.focus(); return false; } return true;}function validateDateGroup(year, month, day, alt) { var array = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); var y = parseInt(year.value); var m = parseInt(month.value); var d = parseInt(day.value); var maxday = array[m - 1]; if (m == 2) { if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) { maxday = 29; } } if (d > maxday) { alert(alt); return false; } return true;}function validateCheckbox(obj, alt) { var rs = false; if (obj != null) { if (obj.length == null) { return obj.checked; } for (i = 0; i < obj.length; i++) { if (obj[i].checked == true) { return true; } } } alert(alt); return rs;}function validateRadio(obj, alt) { var rs = false; if (obj != null) { if (obj.length == null) { return obj.checked; } for (i = 0; i < obj.length; i++) { if (obj[i].checked == true) { return true; } } } alert(alt); return rs;}function validateSelect(obj, alt) { var rs = false; if (obj != null) { for (i = 0; i < obj.options.length; i++) { if (obj.options[i].selected == true) { return true; } } } alert(alt); return rs;}function validateEmail(email, alt, separator) { var mail = trim(email.value); if (mail == “”) return; var em; var myReg = /^[_a-z0-9]+@([_a-z0-9]+.)+[a-z0-9]{2,3}$/; if (separator == null) { if (myReg.test(email.value) == false) { alert(alt); email.focus(); return false; } } else { em = email.value.split(separator); for (i = 0; i < em.length; i++) { em[i] = em[i].trim(); if (em[i].length > 0 && myReg.test(em[i]) == false) { alert(alt); email.focus(); return false; } } } return true;}function validateForm(theForm) {// 若验证通过则返回true var disableList = new Array(); var field = theForm.elements; // 将表单中的所有元素放入数组 for (var i = 0; i < field.length; i++) { var vali = theForm.validate; if (vali != null) { if (vali.value == “0”) { var fun = vali.functionName; if (fun != null) { return eval(fun + “()”); } else { return true; } } } var empty = false; var value = trim(field[i].value); if (value.length == 0) {// 是否空值 empty = true; } var emptyInfo = field[i].emptyInfo;// 空值验证 if (emptyInfo != null && empty == true) { alert(emptyInfo); field[i].focus(); return false; } var lengthInfo = field[i].lengthInfo;// 最大长度验证 if (lengthInfo != null && getStringLength(value) > field[i].maxLength) { alert(lengthInfo); field[i].focus(); return false; } var validatorType = field[i].validatorType; if (validatorType != null) {// 其它javascript var rs = true; if (validatorType == “javascript”) { eval(“rs=” + field[i].functionName + “()”); if (rs == false) { return false; } else { continue; } } else if (validatorType == “disable”) {// 提交表单前disable的按钮 disableList.length++; disableList[disableList.length - 1] = field[i]; continue; } else if (validatorType == “Date”) { rs = validateDate(theForm.elements(field[i].fieldName), field[i].format, field[i].errorInfo); } else if (validatorType == “DateGroup”) { rs = validateDateGroup(theForm.elements(field[i].year), theForm .elements(field[i].month), theForm .elements(field[i].day), field[i].errorInfo); } else if (validatorType == “Checkbox”) { rs = validateCheckbox(theForm.elements(field[i].fieldName), field[i].errorInfo); } else if (validatorType == “Radio”) { rs = validateRadio(theForm.elements(field[i].fieldName), field[i].errorInfo); } else if (validatorType == “Select”) { rs = validateSelect(theForm.elements(field[i].fieldName), field[i].errorInfo); } else if (validatorType == “Email”) { rs = validateEmail(theForm.elements(field[i].fieldName), field[i].errorInfo); } else { alert(“验证类型不被支持, fieldName: “ + field[i].name); return false; } if (rs == false) { return false; } } else {// 一般验证 if (empty == false) { var v = field[i].validator; // 获取其validator属性 if (!v) continue; // 如果该属性不存在,忽略当前元素 var reg = new RegExp(v); if (reg.test(field[i].value) == false) { alert(field[i].errorInfo); field[i].focus(); return false; } } } } for (i = 0; i < disableList.length; i++) { disableList[i].disabled = true; } return true;}```]]></content>
</entry>
<entry>
<title><![CDATA[常用工具整理之Windows]]></title>
<url>%2F2016%2F06%2F29%2F%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7%E6%95%B4%E7%90%86%E4%B9%8BWindows%2F</url>
<content type="text"><![CDATA[1.Divvy(WinDivvy)Divvy又是一个小巧的桌面窗口管理实用工具,它能简单的将桌面分割成几款不同的大小,方便操作。 当我们打开很多个窗口并需要在这多个窗口频繁切换或是同时显示多个窗口查看和编辑内容的时候,我们就会遇到麻烦了,而有了这个工具,我们就能非常方便地实现自己在有限桌面上排放多个串口,从而最大化地利用我们的电脑屏幕。 2.MacTypeMacType 是基于一个日本人的 GDI++的开源项目开发的,GDI++可以在 Windows 实现类似苹果 Mac 系统下的字体渲染效果。由于 GDI++ 已经停止了更新,所以国内网友 FlyingSnow 在GDI++ FreeType版本的基础上继续开发,并将它命名为 MacType。并且,MacType 相比 GDI++ 更加容易使用和配置,适合广大初级用户使用。并且使用之后,字体的显示效果优化非常明显,可谓是 Windows 系统字体显示优化的必备神器! 3.Uninstall ToolUninstall Tool是一个小巧、安全、快速、强大的软件卸载删除工具和自启动管理工具,它支持在使用软件本身的卸载程序卸载完毕后,再扫描软件残留的注册及其它残余文件,将其彻底在系统删除!安装监视器可以监视每个应用程序的安装,实时监视应用程序安装在系统中的任何文件及注册表项目,当您使用Uninstall Tool卸载软件时,它会更加彻底的将其删除干净,不留痕迹!软件本身还带有管理系统随机启动程序工具,加快系统启动速度!总体而言,Uninstall Tool 拥有着Total Uninstall 的功能和令人舒适的界面,却有着更小的体积! 4.Rapid Environment Editor一款免费的系统环境变量编辑工具,它包括易于使用的图形用户界面。环境变量是包含诸如驱动器、路径或文件名之类的字符串。环境变量控制着多种程序的行为。例如,TEMP 环境变量指定程序放置临时文件的位置。 5.EverythingEverything是速度最快的文件搜索软件。其速度之快令人震惊,百G硬盘几十万个文件,可以在几秒钟之内完成索引;文件名搜索瞬间呈现结果。它小巧免费,支持中文,支持正则表达式,可以通过HTTP或FTP分享搜索结果。如果不满意Windows自带的搜索工具、Total Commander的搜索、Google 桌面搜索或百度硬盘搜索,如果正在使用或放弃了Locate32,都值得推荐这款体积小巧、免安装、免费、速度极快(比Locate32更快)的文件搜索工具Everything! 6.Cmdercmder 是为 Windows 提供的一个便携式控制台仿真器。使用非常简单,只需下载解压后执行 cmder.bat 即可。 7.LICEcapLICEcap 是一款屏幕录制工具,支持导出 GIF 动画图片格式,轻量级、使用简单,录制过程中可以随意改变录屏范围。 8.Wox你可以将 Wox 看作一个高效的本地快速搜索框,通过快捷键呼出,然后输入关键字来搜索程序进行快速启动,或者搜索本地硬盘的文件,打开百度、Google 进行搜索,甚至是通过一些插件的功能实现单词翻译、关闭屏幕、查询剪贴板历史、查询编程文档、查询天气等更多功能。 7.WinEdtWinEdt这是一个很强大的通用文本编辑器,被广泛应用于诸如TeX、HTML或NSIS等编译器和排版系统。支持设置为不同的模式,其拼写检查功能支持多种语言设置。 8.FontCreatorFontCreator(字体编辑软件)可用来制作字体(TTF)的程序,除可自行制作外也能够直接编辑修改视窗操作系统上的任何TrueType字体,制作好的字体或修改好的字体能够让你储存和使用。FontCreator功能非常强大,是广大字体修改爱好者的必备工具。利用FontCreator,我们可以创建、修改ttf、otf、ttc格式的字体文件,并生成可在任意设备使用的标准字体文件,是设计制作字体的必备软件。 9.ChocolateyChocolatey 是 windows 下一款命令行包管理软件 ,简单说这就是 Windows 的 apt-get。习惯 Linux 操作方式并非常想用它操纵 Windows 的敬请折腾。Chocolatey 这套包管理系统目前已经包含了近 500 多款常用软件。 10.CloverClover 是 Windows Explorer 资源管理器的一个扩展,为其增加类似谷歌 Chrome 浏览器的多标签页功能。 11.ListaryListary 是一款 Windows 文件浏览增强工具,为 Windows 资源管理器增加智能命令、最近文档以及收藏功能。还可以与第三方程序集成,比如着名的 Total Commander 12.Babunbabun是windows上的一个第三方shell,在这个shell上面你可以使用几乎所有linux,unix上面的命令,他几乎可以取代windows的shell。 13.Filemenu ToolsFileMenu Tools 是用于自定义 Windows 右键菜单的小工具,支持编辑常见的几个窗口的右键菜单,以及添加多种实用的菜单选项。 14.LockHunterLockHunter 是一款极为简单的文件解锁工具(file unlocker),可以方便的删除被锁定的文件,LockHunter 将锁定文件删除到回收站,可以方便恢复。 15.VivaldiVivaldi 是 Opera 新作,基于 Chromium,可以直接试用 Chrome 扩展。对于 Opera 死忠用户来说,打开 Vivaldi 满满的情怀。]]></content>
</entry>
<entry>
<title><![CDATA[Linux命令之iptables]]></title>
<url>%2F2016%2F06%2F21%2FLinux%E5%91%BD%E4%BB%A4%E4%B9%8Biptables%2F</url>
<content type="text"><![CDATA[一、iptable介绍Netfilter包含有三种表,三种表下共包含有五种链,链下面包含各种规则。即表包含若干链,链包含若干规则。 (一) 三种表为:filter、nat、mangle filter:处理与本机有关的数据包,是默认表,包含有三种链:input、output、forward; nat表:与本机无关。主要处理源与目的地址IP和端口的转换。有三种链:prerouting、postrouting、output; mangle表:用于高级路由信息包,如包头内有更改(如tos改变包的服务类型,ttl包的生存时间,mark特殊标记)。有两种链:prerouting、output (kernel 2.4.18后又加了两种链:input forward)这种表很少使用; (二) 五种链 prerouting:进入netfilter后的数据包在进入路由判断前执行的规则。改变包。 Input:当经过路由判断后,要进入本机的数据包执行的规则。 output:由本机产生,需向外发的数据包执行的规则。 forward:经过路由判断后,目的地不是本机的数据包执行的规则。与nat 和 mangle表相关联很高,与本机没有关联。 postrouting:经过路由判断后,发送到网卡接口前。即数据包准备离开netfilter时执行的规则。 上图中,运行中的守护进程,是指本机。Input的包都会发到本机。本机处理后再经output 发出去。 (三)数据包进入netfilter后的经过图: 数据包进入linux服务器入接口,接口把数据包发往netfilter,数据包就此进入netfilter; 经prerouting处理,(如是否需要更改数据包的源IP地址等); 数据包到路由,路由通过路由表判断数据包的目的地。如果目的地是本机,就把数据包转给intput处理后进入本机。如果目的地不是本机,则把数据包转给forward处理; 数据包通过forward处理后,再转给postrouting处理,(是否有目标地址需要改变等),处理后数据包就出了netfilter,到linux服务器出接口,就出了linux服务器; 如果数据包进了本机后经过处理需要外发数据包,或本机自身有数据包需要外发,就把数据包发给output链进行处理后,转给postrouting处理后,出linux服务器。进入外面的花花世界; (四)规则的执行顺序 当数据包进入netfilter,就会和里面的规则进行对比。规则是有顺序的。 先和规则1对比,如果和规则1相匹配,被规则1接受(accept),则数据将不再和后面的规则进行对比。如果不匹配,则按顺序和后面的规则进行对比,直到被接受。如果所有的规则都不匹配,则进行默认策略操作,以决定数据包的去向。所以规则的顺序很重要。 二、iptable语法及参数1iptables [-t table] command [chain] [match][-j target] 注释:iptables [-t 表名] -命令 [链接] [匹配] [-j 动作/目标] (一) table(表) filter表:默认用filter表执行所有的命令。只操作与本机有关的数据包。 nat表:主要用于NAT地址转换。只有数据流的第一个数据包被这个链匹配,后面的包会自动做相同的处理。 分为:DNAT(目标地址转换)、SNAT(源地址转换)、MASQUERADE (1) DNAT操作主要用在这样一种情况,你有一个合法的IP地址,要把对防火墙的访问 重定向到其他的机子上(比如DMZ)。也就是说,我们改变的是目的地址,以使包能重路由到某台主机。 (2) SNAT 改变包的源地址,这在极大程度上可以隐藏你的本地网络或者DMZ等。内网到外网的映射。 (3) MASQUERADE 的作用和SNAT完全一样,只是计算机的负荷稍微多一点。因为对每个匹配的包,MASQUERADE都要查找可用的IP地址,而不象SNAT用的IP地址是配置好的。当然,这也有好处,就是我们可以使用通过PPP、 PPPOE、SLIP等拨号得到的地址,这些地址可是由ISP的DHCP随机分配的。 mangle表:用来改变数据包的高级特性,一般不用。 (二) command(命令)详解 -A或者–append //将一条或多条规则加到链尾 -D或者–delete //从链中删除该规则 -R或者–replace //从所选链中替换一条规则 -L或者–list //显示链的所有规则 -I或者–inset //根据给出的规则序号,在链中插入规则。按序号的顺序插入,如是 “1”就插入链首 -X或者–delete-chain //用来删除用户自定义链中规则。必须保证链中的规则都不在使用时才能删除链。如没有指定链,将删除所有自定义链中的规则。 -F或者–flush //清空所选链中的所有规则。如指定链名,则删除对应链的所有规则。如没有指定链名,则删除所有链的所有规则。 -N或者–new-chain //用命令中所指定的名字创建一个新链。 -P或者–policy //设置链的默认目标,即策略。 与链中任何规则都不匹配的信息包将强制使用此命令中指定的策略。 -Z或者–zero //将指定链中的所有规则的包字节计数器清零。 (三) match 匹配分为四大类:通用匹配、隐含匹配、显示匹配、针对非正常包的匹配 1. 通用匹配无论我们使用何种协议,装入何种扩展,通用匹配都可以使用。不需要前提条件 (1). -p(小写)或–protocol 用来检查某些特定协议。协议有TCP\UDP\ICMP三种。可用逗号分开这三种协议的任何组合。也可用“!”号进行取反,表示除该协议外的剩下的协议。也可用all表示全部协议。默认是all,但只代表tcp\udp\icmp三种协议。 12$ iptables -A INPUT -p TCP,UDP$ iptables -A INPUT -p ! ICMP //这两种表示的意思为一样的。 (2). -s 或 –source 以Ip源地址匹配包。根据源地址范围确定是否允许或拒绝数据包通过过滤器。可使用 “!”符号。 默认是匹配所有ip地址。 可是单个Ip地址,也可以指定一个网段。 如: 192.168.1.1/255.255.255.255 表示一个地址。 192.168.1.0/255.255.255.0 表示一个网段。 (3). -d 或 –destination 用目的Ip地址来与它们匹配。与 source 的格式用法一样 (4). -i 以包进入本地所使用的网络接口来匹配包。只能用INPUT \ FORWARD \PREROUTING 三个链中。用在其他任何链中都会出错。 可使用“+” “!”两种符号。 只用一个“+”号,表示匹配所有的包,不考虑使用哪个接口。如: iptables -A INPUT -i + //表匹配所有的包。 放在某类接口后面,表示所有此类接口相匹配。如: iptables -A INPUT -i eth+ //表示匹配所有ethernet 接口。 (5). -o 以数据包出本地所使用的网络接口来匹配包。与-i一样的使用方法。 只能用OUTPUT \ FORWARD \POSTROUTING 三个链中。用在其他任何链中都会出错。 可使用“+” “!”两种符号。 (6). -f (或 –fragment ) 用来匹配一个被分片的包的第二片或以后的部分。因一个数据包被分成多片以后,只有第一片带有源或目标地址。后面的都不带 ,所以只能用这个来匹配。可防止碎片攻击。 2. 隐含匹配这种匹配是隐含的,自动的载入内核的。如我们使用 –protocol tcp 就可以自动匹配TCP包相关的特点。 分三种不同协议的隐含匹配:tcp、udp、icmp 2.1 tcp match tcp match 只能隐含匹配TCP包或流的细节。但必须有 -p tcp 作为前提条件。 (2.1.1) TCP –sport 基于tcp包的源端口匹配包 ,不指定此项则表示所有端口。 12iptables -A INPUT -p TCP --sport 22:80 //TCP源端口号22到80之间的所有端口。iptables -A INPUT -p TCP --sport 22: //TCP源端口号22到65535之间的所有端口。 (2.1.2) TCP –dport 基于tcp包的目的端口来匹配包。 与–sport端口用法一样。 (2.1.3) TCP –flags 匹配指定的TCP标记。 1iptables -p TCP --tcp-flags SYN,FIN,ACK SYN 2.2 UDP match (2.1.1) UDP –sport 基于UDP包的源端口匹配包 ,不指定此项则表示所有端口。 (2.1.1) UDP –dport 基于UDP包的目的端口匹配包 ,不指定此项则表示所有端口。 2.3 icmp match icmp –icmp-type 根据ICMP类型包匹配。类型 的指定可以使用十进制数或相关的名字,不同的类型,有不同的ICMP数值表示。也可以用“!”取反。 例: iptables -A INPUT -p icmp-imcp-type 8 3、显示匹配显示匹配必须用 -m装 载。 (1)limit match 必须用 -m limit 明确指出。 可以对指定的规则的匹配次数加以限制。即,当某条规则匹配到一定次数后,就不再匹配。也就是限制可匹配包的数量。这样可以防止DOS攻击。 限制方法: 设定对某条规则 的匹配最大次数。设一个限定值 。 当到达限定值以后,就停止匹配。但有个规定,在超过限制次数后,仍会每隔一段时间再增加一次匹配次数。但增加的空闲匹配数最大数量不超过最大限制次数。 –limit rate 最大平均匹配速率:可赋的值有’/second’, ‘/minute’, ‘/hour’, or ‘/day’这样的单位,默认是3/hour。 –limit-burst number 待匹配包初始个数的最大值:若前面指定的极限还没达到这个数值,则概数字加1.默认值为5 iptables -A INPUT -m limit –limt 3/hour //设置最大平均匹配速率。也就是单位时间内,可匹配的数据包个数。 –limt 是指定隔多 长时间发一次通行证。 iptables -A INPUT -m limit –limit-burst 5 //设定刚开始发放5个通行证,也最多只可匹配5个数据包。 (2) mac match 只能匹配MAC源地址。基于包的MAC源地址匹配包 iptables -A INPUT -m mac –mac-source 00:00:eb:1c:24 //源地址匹配些MAC地址 (3) mark match 以数据包被 设置的MARK来匹配包。这个值由 MARK TARGET 来设置的。 (4) multiport match 这个模块匹配一组源端口或目标端口,最多可以指定15个端口。只能和-p tcp 或者 -p udp 连着使用。 多端口匹配扩展让我们能够在一条规则里指定不连续的多个端口。如果没有这个扩展,我们只能按端口来写规则了。这只是标准端口匹配的增强版。不能在一条规则里同时用标准端口匹配和多端口匹配。 三个选项:–source-port、–destination-port、–port 123iptables -A INPUT -p TCP -m multiport --source-port 22,28,115iptables -A INPUT -p TCP -m multiport --destination-port 22,28,115iptables -A INPUT -p TCP -m multiport --port 22,28,115 (5) state match 状态匹配扩展要有内核里的连接跟踪代码的协助。因为是从连接跟踪机制得到包的状态。这样不可以了解所处的状态。 (6) tos match 根据TOS字段匹配包,用来控制优先级。 (7) ttl match 根据IP头里的TTL字段来匹配包。 用来更改包的TTL,有些ISP根据TTL来判断是不是有多台机器共享连接上网。 12345iptables -t mangle -A PREROUTING -i eth0 -j TTL --ttl-set 64iptables -t mangle -A PREROUTING -i eth0 -j TTL --ttl-dec 1# 离开防火墙的时候实际上TTL已经-2了,因为防火墙本身要-1一次。iptables -t mangle -A PREROUTING -i eth0 -j TTL --ttl-inc 1# 离开防火墙的时候不增不减,tracert就不好用了,呵呵。 (8) owner match 基于包的生成者(即所有者或拥有者)的ID来匹配包。 owner 可以是启动进程的用户的ID,或用户所在的级的ID或进程的ID,或会话的ID。此只能用在OUTPUT 中。 此模块设为本地生成包匹配包创建者的不同特征。而且即使这样一些包(如ICMP ping应答)还可能没有所有者,因此永远不会匹配。 –uid-owner userid 如果给出有效的user id,那么匹配它的进程产生的包。 –gid-owner groupid 如果给出有效的group id,那么匹配它的进程产生的包。 –sid-owner seessionid 根据给出的会话组匹配该进程产生的包。 (四) targets/jump指由规则指定的操作,对与规则匹配的信息包执行什么动作。 1、accept 这个参数没有任何选项。指定 -j accept 即可。 一旦满足匹配不再去匹配表或链内定义的其他规则。但它还可能会匹配其他表和链内的规则。即在同一个表内匹配后就到上为止,不往下继续。 2、drop -j drop 当信息包与规则完全匹配时,将丢弃该 包。不对它做处理。并且不向发送者返回任何信息。也不向路由器返回信息。 3、reject 与drop相同的工作方式,不同的是,丢弃包后,会发送错误信息给发送方。 1iptables -A FORWARD -p TCP --dport 22 -j REJECT --reject-with icmp-net-unreachable 4、DNAT 用在prerouting链上。 做目的网络地址转换的。就是重写目的的IP地址。 如果一个包被匹配,那么和它属于同一个流的所有的包都会被自动转换。然后可以被路由到正确的主机和网络。 也就是如同防火墙的外部地址映射。把外部地址映射到内部地址上。 123iptables -t nat -A PREROUTING -d 218.104.235.238 -p TCP --dport 110,125 -j DNAT --to-destination 192.168.9.1//把所有访问218.104.235.238地址 110.125端口的包全部转发到 192.168.9.1上。--to-destination //目的地重写 5、SNAT 用在nat 表的postrouting链表。这个和DNAT相反。是做源地址转换。就是重写源地址IP。 常用在内部网到外部网的转换。 –to-source 1iptables -t nat POSTROUTING -o eth0 -p tcp -j SNAT --to-source 218.107.248.127 //从eth0接口往外发的数据包都把源地址重写为218.107.248.127 12iptables -t nat -A PREROUTING -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.9# 将所有的访问15.45.23.67:80端口的数据做DNAT发到192.168.1.9:80 如果和192.168.1.9在同一内网的机器要访问15.45.23.67,防火墙还需要做设置,改变源IP为防火墙内网IP 192.168.1.1。否则数据包直接发给内网机器,对方将丢弃。 12iptables -t nat -A POSTROUTING -p tcp --dst 15.45.23.67 --dport 80 -j SNAT --to-source 192.168.1.1# 将所有的访问15.45.23.67:80端口的数据包源IP改为192.168.1.1 如果防火墙也需要访问15.45.23.67:80,则需要在OUTPUT链中添加,因为防火墙自己发出的包不经过PREROUTING。 1iptables -t nat -A OUTPUT --dst 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.9 6、MASQUERADE masquerade 的作用和 SNAT的作用是一样的。 区别是,他不需要指定固定的转换后的IP地址。专门用来设计动态获取IP地址的连接的。 MASQUERADE的作用是,从服务器的网卡上,自动获取当前ip地址来做NAT 如家里的ADSL上网,外网的IP地址不是固定的,你无法固定的设定NAT转换后的IP地址。这时就需要用masquerade来动态获取了。 1iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j masquerade //即把192.168.1.0 这个网段的地址都重写为动态的外部IP地址。 7、REDIRECT 只能在NAT表中的PREROUTING OUTPUT 链中使用 在防火墙所在的机子内部转发包或流到另一个端口。比如,我们可以把所有去往端口HTTP的包REDIRECT到HTTP proxy(例如squid),当然这都发生在我们自己的主机内部。 –to-ports 1iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080 不使用这个选项,目的端口不会被改变。 指定一个端口,如–to-ports 8080 指定端口范围,如–to-ports 8080-8090 8、RETURN 顾名思义,它使包返回上一层,顺序是:子链——>父链——>缺省的策略。具体地说,就是若包在子链中遇到了RETURN,则返回父链的下一条规则继续进行条件的比较,若是在父链(或称主链,比如INPUT)中遇到了RETURN,就要被缺省的策略(一般是ACCEPT或DROP)操作了。(译者注:这很象C语言中函数返回值的情况) 9、MIRROR 颠倒IP头中的源地址与目的地址,再转发。 10、LOG 在内核空间记录日志,dmesg等才能看。 11、ULOG 在用户空间记录日志。 (五)IP转发功能打开转发IP功能(IP forwarding): 1echo "1" > /proc/sys/net/ipv4/ip_forward 如果使用PPP、DHCP等动态IP,需要打开: 1echo "1" > /proc/sys/net/ipv4/ip_dynaddr]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Linux命令之tar]]></title>
<url>%2F2016%2F06%2F21%2FLinux%E5%91%BD%E4%BB%A4%E4%B9%8Btar%2F</url>
<content type="text"><![CDATA[用途:>GNU `tar’ saves many files together into a single tape or disk archive, and can restore individual files from the archive. 语法:1tar [-cxtzjvfpPN] file[dir] .... 参数: -c :建立一个压缩文件的参数指令(create 的意思); -x :解开一个压缩文件的参数指令! -t :查看 tarfile 里面的文件! 特别注意,在参数的下达中, c/x/t 仅能存在一个!不可同时存在! 因为不可能同时压缩与解压缩。 -z :是否同时具有 gzip 的属性?亦即是否需要用 gzip 压缩? -j :是否同时具有 bzip2 的属性?亦即是否需要用 bzip2 压缩? -v :压缩的过程中显示文件!这个常用,但不建议用在背景执行过程! -f :使用档名,请留意,在 f 之后要立即接档名喔!不要再加参数! 例如使用 tar -zcvfP tfile sfile 就是错误的写法,要写成 tar -zcvPf tfile sfile -p :使用原文件的原来属性(属性不会依据使用者而变) -P :可以使用绝对路径来压缩! -N :比后面接的日期(yyyy/mm/dd)还要新的才会被打包进新建的文件中! –exclude FILE:在压缩的过程中,不要将 FILE 打包! 范例:1. 范例一:将整个 /etc 目录下的文件全部打包成为 /tmp/etc.tar12345678[txw1958@redhat ~]# tar -cvf /tmp/etc.tar /etc <==仅打包,不压缩![txw1958@redhat ~]# tar -zcvf /tmp/etc.tar.gz /etc <==打包后,以 gzip 压缩[txw1958@redhat ~]# tar -jcvf /tmp/etc.tar.bz2 /etc <==打包后,以 bzip2 压缩# 特别注意,在参数 f 之后的文件档名是自己取的,我们习惯上都用 .tar 来作为辨识。# 如果加 z 参数,则以 .tar.gz 或 .tgz 来代表 gzip 压缩过的 tar file ~# 如果加 j 参数,则以 .tar.bz2 来作为附档名啊~# 上述指令在执行的时候,会显示一个警告讯息:# 『tar: Removing leading `/" from member names』那是关於绝对路径的特殊设定。 2. 范例二:查阅上述 /tmp/etc.tar.gz 文件内有哪些文件?123[txw1958@redhat ~]# tar -ztvf /tmp/etc.tar.gz# 由於我们使用 gzip 压缩,所以要查阅该 tar file 内的文件时,# 就得要加上 z 这个参数了!这很重要的! 3. 范例三:将 /tmp/etc.tar.gz 文件解压缩在 /usr/local/src 底下123456[txw1958@redhat ~]# cd /usr/local/src[txw1958@redhat src]# tar -zxvf /tmp/etc.tar.gz# 在预设的情况下,我们可以将压缩档在任何地方解开的!以这个范例来说,# 我先将工作目录变换到 /usr/local/src 底下,并且解开 /tmp/etc.tar.gz ,# 则解开的目录会在 /usr/local/src/etc 呢!另外,如果您进入 /usr/local/src/etc# 则会发现,该目录下的文件属性与 /etc/ 可能会有所不同喔! 4. 范例四:在 /tmp 底下,我只想要将 /tmp/etc.tar.gz 内的 etc/passwd 解开而已1234[txw1958@redhat ~]# cd /tmp[txw1958@redhat tmp]# tar -zxvf /tmp/etc.tar.gz etc/passwd# 我可以透过 tar -ztvf 来查阅 tarfile 内的文件名称,如果单只要一个文件,# 就可以透过这个方式来下达!注意到! etc.tar.gz 内的根目录 / 是被拿掉了! 5. 范例五:将 /etc/ 内的所有文件备份下来,并且保存其权限!12[txw1958@redhat ~]# tar -zxvpf /tmp/etc.tar.gz /etc# 这个 -p 的属性是很重要的,尤其是当您要保留原本文件的属性时! 6. 范例六:在 /home 当中,比 2012/09/11 新的文件才备份1[txw1958@redhat ~]# tar -N "2012/09/11" -zcvf home.tar.gz /home 7. 范例七:我要备份 /home, /etc ,但不要 /home/dmtsai1[txw1958@redhat ~]# tar --exclude /home/dmtsai -zcvf myfile.tar.gz /home/* /etc 8. 范例八:将 /etc/ 打包后直接解开在 /tmp 底下,而不产生文件!12345[txw1958@redhat ~]# cd /tmp[txw1958@redhat tmp]# tar -cvf - /etc | tar -xvf -# 这个动作有点像是 cp -r /etc /tmp 啦~依旧是有其有用途的!# 要注意的地方在於输出档变成 - 而输入档也变成 - ,又有一个 | 存在~# 这分别代表 standard output, standard input 与管线命令啦!]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Linux命令之lsof]]></title>
<url>%2F2016%2F06%2F20%2FLinux%E5%91%BD%E4%BB%A4%E4%B9%8Blsof%2F</url>
<content type="text"><![CDATA[lsof, LiSt Opened Files, 列出打开的文件, 听起来很简单的样子. 但想*nix中很多其他工具一样, lsof把这件简单的事情做到了炉火纯青. 因为Unix认为”一切皆文件”, 那么”打开的文件”就不仅仅是传统意义上打开的文件了, 还可以是网络/Unix域套接字, 匿名/具名管道, 共享库文件, 目录文件, 设备文件等等. 很多场景下, 查看进程或系统打开的文件会给调试带来极大的帮助. 下面简单地介绍lsof常被使用的功能选项. lsof : 简单地执行lsof会列出当前系统中所有被打开的文件, 但为了看到完整的信息, 通常需要具有root权限; lsof -u dutor : 列出用户dutor打开的文件, 可指定多个用户, 默认是OR的关系; lsof -c tair : 列出名称以tair开头的进程打开的文件, c for command, 可指定多个; lsof -c /^t.*r$/ : 列出名称以t开头, r结尾的进程打开的文件; lsof -p 12315 : 列出进程号为12315的进程打开的文件, 可指定多个; lsof server.log : 列出打开server.log文件的进程, 可指明多个文件; lsof . : 列出打开当前目录的进程; lsof +D . : 递归地列出当前目录中被打开的文件, 当然也可以lsof | grep pwd; lsof -i : 列出打开的套接字; lsof -i tcp : 列出打开的tcp套接字; lsof -i :5198 : 列出打开5198端口的进程; lsof -i :ssh : 列出打开22端口的进程; lsof -i tcp:5198 : 列出打开5198号tcp端口的进程; lsof -U : 列出打开Unix域套接字的进程; lsof -d 0-2 : 列出在0到2文件描述符上打开文件的进程; lsof -d mem : 列出打开映射文件的进程; lsof -d txt : 列出打开的可执行文件. 还有其他一些非常有用的选项, 可以对lsof的行为进行控制. lsof -a: 上述功能性选项可以组合使用, 但默认采用OR逻辑列出, -a选项令lsof使用AND逻辑; lsof -t: 只列出进程号, 可以借此得到特定的进程列表, 以方便对这些进程的自动处理, 比如kill lsof -t -i :5198会杀死所有打开5198端口的进程; lsof -r [seconds]: -r选项可以让lsof以一定的时间间隔连续执行, 在监视文件/进程时会非常实用.这只是一个实用的不完全选项的罗列, 如果你知道其他非常实用的选项, 还望留言分享之.]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title><![CDATA[开放API接口验证]]></title>
<url>%2F2016%2F06%2F20%2F%E5%BC%80%E6%94%BEAPI%E6%8E%A5%E5%8F%A3%E9%AA%8C%E8%AF%81%2F</url>
<content type="text"><![CDATA[提出问题在写开放的API接口时如何保证数据的安全性?先来看看有哪些安全性问题在开放的api接口中,我们通过http POST或者GET方式请求服务器的时候,会面临着许多的安全性问题,例如: 请求来源(身份)是否合法? 请求参数被篡改? 请求的唯一性(不可复制)? 为了保证数据在通信时的安全性,我们可以采用参数签名的方式来进行相关验证。 案列分析我们通过给某【移动端(app)】写【后台接口(api)】的案例进行分析: 客户端: 以下简称app 后台接口:以下简称api 我们通过app查询产品列表这个操作来进行分析: 1app中点击查询按钮 --> 调用api进行查询 --> 返回查询结果 --> 显示在app中 一、不进行验证的方式api查询接口: app调用:http://api.test.com/getproducts?参数1=value1....... 如上,这种方式简单粗暴,通过调用getproducts方法即可获取产品列表信息了,但是 这样的方式会存在很严重的安全性问题,没有进行任何的验证,大家都可以通过这个方法获取到产品列表,导致产品信息泄露。那么,如何验证调用者身份呢?如何防止参数被篡改呢? 二、MD5参数签名的方式我们对api查询产品接口进行优化: 给app分配对应的key、secret Sign签名,调用API 时需要对请求参数进行签名验证,签名方式如下: 按照请求参数名称将所有请求参数按照字母先后顺序排序得到:keyvaluekeyvalue...keyvalue字符串如:将arong=1,mrong=2,crong=3排序为:arong=1, crong=3,mrong=2然后将参数名和参数值进行拼接得到参数字符串:arong1crong3mrong2 将secret加在参数字符串的头部后进行MD5加密 ,加密后的字符串需大写,即得到签名Sign(MD5简介详见博文MD5简介) 新api接口代码: app调用:http://api.test.com/getproducts?key=app_key&sign=BCC7C71CF93F9CDBDB88671B701D8A35&参数1=value1&参数2=value2....... 注:secret 仅作加密使用, 为了保证数据安全请不要在请求参数中使用。 如上,优化后的请求多了key和sign参数,这样请求的时候就需要合法的key和正确签名sign才可以获取产品数据。这样就解决了身份验证和防止参数篡改问题,如果请求参数被人拿走,没事,他们永远也拿不到secret,因为secret是不传递的。再也无法伪造合法的请求。 但是…这样就够了吗?细心的同学可能会发现,如果我获取了你完整的链接,一直使用你的key和sign和一样的参数不就可以正常获取数据了…-_-!是的,仅仅是如上的优化是不够的 三、请求的唯一性为了防止别人重复使用请求参数问题,我们需要保证请求的唯一性,就是对应请求只能使用一次,这样就算别人拿走了请求的完整链接也是无效的。唯一性的实现:在如上的请求参数中,我们加入时间戳 :timestamp(yyyyMMddHHmmss),同样,时间戳作为请求参数之一,也加入sign算法中进行加密。 新的api接口: app调用:http://api.test.com/getproducts?key=app_key&sign=BCC7C71CF93F9CDBDB88671B701D8A35×tamp=201603261407&参数1=value1&参数2=value2....... 如上,我们通过timestamp时间戳用来验证请求是否过期。这样就算被人拿走完整的请求链接也是无效的。 四、Sign签名安全性分析通过上面的案例,我们可以看出,安全的关键在于参与签名的secret,整个过程中secret是不参与通信的,所以只要保证secret不泄露,请求就不会被伪造。 上述的Sign签名的方式能够在一定程度上防止信息被篡改和伪造,保障通信的安全,这里使用的是MD5进行加密,当然实际使用中大家可以根据实际需求进行自定义签名算法,比如:RSA,SHA等。]]></content>
<categories>
<category>API</category>
</categories>
<tags>
<tag>API</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Context namespace element 'annotation-config' ... are only available on JDK 1.5 and higher]]></title>
<url>%2F2016%2F06%2F14%2FContext-namespace-element-annotation-config-are-only-available-on-JDK-1-5-and-higher%2F</url>
<content type="text"><![CDATA[环境 系统:Windows Server 2003 Java: 1.6.0_45(后来安装了jre1.8.0_91) Spring:2.5.5 Tomcat:7.0.27 问题Tomcat是绿色版,通过service.bat安装服务,启动后打开浏览器测试,发现页面一片空白,通过查看Tomcat日志,发现有一处异常only available on JDK 1.5 and higherSS,如下:1234567891011121314151617181920212223242526272829303132333435363738394041严重: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListenerorg.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class path resource [applicationContext.xml]; nested exception is java.lang.IllegalStateException: Context namespace element 'annotation-config' and its parser class [org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser] are only available on JDK 1.5 and higher at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:420) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:124) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:92) at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:123) at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:422) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:352) at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:255) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:199) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4791) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5285) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:618) at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1100) at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1618) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)Caused by: java.lang.IllegalStateException: Context namespace element 'annotation-config' and its parser class [org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser] are only available on JDK 1.5 and higher at org.springframework.context.config.ContextNamespaceHandler$1.parse(ContextNamespaceHandler.java:65) at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:69) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1297) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1287) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:135) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:92) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:507) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:398) ... 26 more六月 14, 2016 1:38:09 下午 org.apache.catalina.core.StandardContext startInternal严重: Error listenerStart 查看错误,找到关键点only available on JDK 1.5 and higher,验证这个百毒了一下,找到关键的原因点: JRE版本 Tomcat7启动时用到了JRE Spring框架中有一个jkdcheckversion方法,这个方法中,没有兼容到1.8 解决办法 降级JRE,即卸载JRE1.8,使用JRE1.6 修改Tomcat启动环境变量, 系统添加JRE_HOME环境变量,这个需要重启服务器(由于是客户的服务器,不能随便重启) 修改setclasspath.bat批处理文件,在最前面添加 12set JAVA_HOME=C:\Program Files\Java\jdk1.6.0_45set JRE_HOME=C:\Program Files\Java\jdk1.6.0_45\jre 修改完了批处理文件后,需要卸载Tomcat服务,重新安装服务]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Ubuntu上vim配置YoucompleteMe时./install.sh --clang-completer出现错误]]></title>
<url>%2F2016%2F06%2F13%2FUbuntu%E4%B8%8Avim%E9%85%8D%E7%BD%AEYoucompleteMe%E6%97%B6-install-sh-clang-completer%E5%87%BA%E7%8E%B0%E9%94%99%E8%AF%AF%2F</url>
<content type="text"><![CDATA[问题描述1234567891011121314151617181920212223242526272829303132333435363738394041424344➜ YouCompleteMe git:(master) sudo ./install.sh --clang-completer-- The C compiler identification is GNU 4.8.4-- The CXX compiler identification is GNU 4.8.4-- Check for working C compiler: /usr/bin/cc-- Check for working C compiler: /usr/bin/cc -- works-- Detecting C compiler ABI info-- Detecting C compiler ABI info - done-- Check for working CXX compiler: /usr/bin/c++-- Check for working CXX compiler: /usr/bin/c++ -- works-- Detecting CXX compiler ABI info-- Detecting CXX compiler ABI info - done-- Configuring incomplete, errors occurred!See also "/tmp/ycm_build.gX46II/CMakeFiles/CMakeOutput.log".Traceback (most recent call last): File "/home/vagrant/.vim/bundle/YouCompleteMe/third_party/ycmd/build.py", line 196, in <module> Main() File "/home/vagrant/.vim/bundle/YouCompleteMe/third_party/ycmd/build.py", line 189, in Main BuildYcmdLibs( GetCmakeArgs( args ) ) File "/home/vagrant/.vim/bundle/YouCompleteMe/third_party/ycmd/build.py", line 147, in BuildYcmdLibs sh.cmake( *full_cmake_args, _out = sys.stdout ) File "/home/vagrant/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/sh/sh.py", line 1021, in __call__ return RunningCommand(cmd, call_args, stdin, stdout, stderr) File "/home/vagrant/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/sh/sh.py", line 486, in __init__ self.wait() File "/home/vagrant/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/sh/sh.py", line 500, in wait self.handle_command_exit_code(exit_code) File "/home/vagrant/.vim/bundle/YouCompleteMe/third_party/ycmd/third_party/sh/sh.py", line 516, in handle_command_exit_code raise exc(self.ran, self.process.stdout, self.process.stderr)sh.ErrorReturnCode_1: RAN: '/usr/bin/cmake -G Unix Makefiles -DUSE_CLANG_COMPLETER=ON /home/vagrant/.vim/bundle/YouCompleteMe/third_party/ycmd/cpp' STDOUT: STDERR:Your C++ compiler supports C++11, compiling in that mode.CMake Error at /usr/share/cmake-2.8/Modules/FindPackageHandleStandardArgs.cmake:108 (message): Could NOT find PythonLibs (missing: PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS) (Required is at least version "2.6")Call Stack (most recent call first): /usr/share/cmake-2.8/Modules/FindPackageHandleStandardArgs.cmake:315 (_FPHSA_FAILURE_MESSAGE) /usr/share/cmake-2.8/Modules/FindPythonLibs.cmake:208 (FIND_PACKAGE_HANDLE_STANDARD_ARGS) BoostParts/CMakeLists.txt:30 (find_package) 解决办法1sudo apt-get install python-dev]]></content>
</entry>
<entry>
<title><![CDATA[node-sass模块安装失败]]></title>
<url>%2F2016%2F05%2F08%2Fnode-sass%E6%A8%A1%E5%9D%97%E5%AE%89%E8%A3%85%E5%A4%B1%E8%B4%A5%2F</url>
<content type="text"><![CDATA[一、下载对应平台二进制文件node-sass 3.4.2 版本二进制文件下载地址:https://github.com/sass/node-sass/releases/tag/v3.4.2或者:https://github.com/sass/node-sass-binaries 二、设置环境变量安装时执行: windows 1set SASS_BINARY_PATH=[FILE_PATH]\win32-x64-47_binding.node linux 1SASS_BINARY_PATH=/path/to/win32-x64-47_binding.node 或者添加到系统环境变量:设置变量 SASS_BINARY_PATH 为二进制文件地址, windows 环境变量SASS_BINARY_PATH, 值为文件路径, 如:E:\Programs\nodejs\win32-x64-47_binding.node linux 修改用户目录下的.bashrc文件,添加如下代码SASS_BINARY_PATH=/path/to/win32-x64-47_binding.node 三、检查 windows 1echo %SASS_BINARY_PATH% linux 1echo $SASS_BINARY_PATH 四、安装 windows 1npm install node-sass --save-dev linux 1sudo npm install node-sass --save-dev 参考地址:https://github.com/luqin/blog/issues/9]]></content>
<categories>
<category>Nodejs</category>
</categories>
<tags>
<tag>Nodejs</tag>
<tag>Sass</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Eclipse远程调试Tomcat配置]]></title>
<url>%2F2016%2F05%2F05%2FEclipse%E8%BF%9C%E7%A8%8B%E8%B0%83%E8%AF%95Tomcat%E9%85%8D%E7%BD%AE%2F</url>
<content type="text"><![CDATA[当项目在服务器上单独部署的时候没有,因为服务器上不可能给你装IDE的工具。但是项目在本地运行很好,就是部署到服务器上的时候就出现一堆的错误,想想又没有IDE,没办法在服务器的本地进行调试。这时候就用到了Tomcat远程调试 JVM的JPDA框架。而Tomcat默认是不启用JPDA的,需要我们手动开启。 Eclpse远程调试Tomcat的配置步骤: 第一步、配置tomcat一、在windows系统中:打开%CATALINE_HOME%/bin下的文件catalina.bat,加入下面这行: 1set CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 二、在非windows系统中:还需要把%CATALINE_HOME%/bin/startup.sh中的最后一行exec "$PRGDIR"/"$EXECUTABLE" start "$@"中的start改成jpda start。由于默认的端口是8000,所以如果8000端口已有他用的话,还需在catalina.sh文件中设 置:JPDA_ADDRESS=8000。 输入命令startup.sh或者catalina.sh jpda start就可启动tomcat。 在linux下出现错误时 1ERROR: Cannot load this JVM TI agent twice, check your java command line for duplicate jdwp options. 将-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n去掉。 三、启动后效果 第二步、配置Eclpse在Eclipse中选择Run Debug,在弹出对话框中右击Remote Java Application新建一个远程调试项,如下所示: 在 “Name”输入框中输入远程调试的名称,在“Project”中选择要调试的项目,在“Host”中输入需要远程调试项目的IP,也就是tomcat所在的IP,在“Port”中输入设置的端口号,比如上面设置的8000,然后钩选“Allow termination of remote VM”,点击“Apply”即可。 设置完后就可以开始调试了,大概分一下几步: 启动tomcat(远程),如在控制台输出Listening for transport dt_socket at address: 8000,即说明在tomcat中设置成功; 在本机设置断点; 进入上图界面,选择要调试的项,点击“Debug”即可进行远程调试; 访问你的测试页面即可看到久违的调试界面。5.但每次做上述操作非常烦,不如写个批处理,如取名为Tomcat debug.bat,在这个文件中加入下面几行: 12345cd %CATALINE_HOME%/binset JPDA_ADDRESS=8000set JPDA_TRANSPORT=dt_socketset CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000startup 将此脚本保存到tomcat/bin目录下,然后发个快捷方式在桌面 这样需要远程调试时,运行debug.bat即可;不需要远程调试时,还是运行startup.bat文件]]></content>
<categories>
<category>Eclipse</category>
<category>Java</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title><![CDATA[人为什么会拖延]]></title>
<url>%2F2016%2F05%2F01%2F%E4%BA%BA%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E6%8B%96%E5%BB%B6%2F</url>
<content type="text"><![CDATA[原文出处:waitbutwhy 拖延症普遍存在,但是如果你没清醒的理解并感受拖延症的危害,可能很多事情都没办法顺利做好,特别在这个信息纷繁的注意力经济环境当中。 拖延症 pro-cras-ti-na-tion |prəˌkrastəˈnāSHən, prō-|名词释义:指的是非必要、有害的推迟行为。例句:建议你不要患上拖延症。我说字典你是和我开玩笑对吧?人类和拖延症抗争这么多年,你给出的第一个例句就是:建议你不要患上拖延症。 不要患上拖延症,多么简洁明快,高贵冷艳。 要是这样子有用的话,我们可以直接告诉肥胖症患者克制住食欲,告诉抑郁症患者生活乐观,告诉搁浅在沙滩上的鲸鱼,它们不应该离开海洋的。 真是胡扯。“不要患上拖延症”只对于那些没有拖延症的人有效,或者说是那些假性拖延症患者。所谓假性拖延症患者,就是那些天天嘟囔:“我每天上班的时候水好几次微博,我真是一个超级拖延症患者!”他们也会煞有介事地对那些真正有拖延症的人说:“不要拖延你就没事了!”假性拖延症患者和字典作者有所不知,对于真正的拖延症患者,拖延与否不是一件有选择的事情,他们面对拖延,根本不知道如何反抗。 在我上大学的时候,突然给予我的自由让我猝不及防。我就像脱缰的野马一样不受控制,每天逛来逛去每天什么都完不成。唯一的例外就是,有时候我需要为某一门课程交一篇论文,于是我会Deadline之前的一天晚上开始写论文。但是事实上,我经常发现我Deadline那一天早上开始写也可以,所以我后来就索性Dealline那一天早晨疯狂地写论文。这种拖延症愈演愈烈。我毕业的时候需要写90页的毕业论文,我依然是Deadline之前的72小时才开始动笔。这样子的突击冲锋导致我手指痉挛不听使唤,最后我被送到校医院,医生的诊断是我因为疲劳过度血糖低才这样子的。(我最后还是完成了我的毕业论文,别问了,很糟糕。) 即使到了现在,这个问题依然很严重。比如你正在阅读的这个帖子,就花了我很长的时间才完成。我大部分时间都在网上看一些无聊的图片,比如这个大猩猩。心里一直想着,要是我和这个大猩猩打一架的话,它能够多么容易地把我揍扁,然后想着要是这个大猩猩和狮子打架的话谁会赢,然后就跳跃到了狮子和老虎打架谁会赢,然后就Google了到底谁会赢,最后发现是老虎。我真是病的不轻。 为了了解为什么拖延症患者拖延地这么厉害,首先让我们从“非拖延症人”的脑袋开始: 挺正常的对吧?好的现在让我们看看拖延症患者的脑袋: 有没有注意到什么不一样的地方? 好像是在拖延症患者脑子里面,除了理智之外,还有一个宠物————即时满足猴子。 其实“理智”先生如果知道如何饲养猴子的话,这个宠物还是挺可爱的。可惜的是“理智”没有经过饲养猴子的训练,所以有时候猴子会开始干扰他做自己应该做的事情: 事实上,即时奖励猴子是最不应该当家做主的。他永远只想着当下,完全忽视未来计划。他关心的事情就是如何让现在这个时刻更加快乐和容易。猴子和理智互相都不怎么了解对方。猴子心里想的总是:练钢琴要是不好玩,我们为什么要练钢琴?电脑可以上网,为什么我们要用电脑去工作?猴子觉得理智真是丧心病狂。 在猴子的世界里面,事情没这么复杂 —— 如果你饿了就吃,困了就睡,也不做什么困难的事情,你完全就是一只成功的猴子。但是可惜我们生活在人类世界,在这个世界里猴子完全没有资格做我们的领航员。而理智呢?他只知道如何如何做出理智的决定,而不是如何和无理取闹的猴子打交道,更不知道如何才能控制这只猴子。和猴子斗争的结果就是理智越来越有挫败感,他越是失败,我们就越拖延,我们越拖延,就越斥责自己的理智为什么没有做好他的工作。 这一团糟真是纠结。如果猴子掌权,那么拖延症患者会发现自己经常在一个地方浪费时间,这个地方叫做“黑暗游乐场”。 每个拖延症患者对于黑暗游乐场都心知肚明。在这个地方,不应该享受的娱乐活动一次又一次地发生。你在黑暗游乐场得到的快乐不是快乐,因为你知道自己没有完成任务,也没有开始玩的资格,所以玩的不尽兴。黑暗游乐场的气氛充满了负罪感,焦虑,自我憎恨,还有担惊受怕。有时候理智一气之下断绝了你所有的娱乐方式,但是“即时奖励猴子”表示抗议,最后把你放在了一个玩没法玩,工作没法工作的不伦不类之地。 你理智现在已经说不出话了,心里想的都是自己为什么这么失职,让你又沦落到了此番境地。 但是情况这么尴尬,拖延症患者又是如何完成任务的呢? 事实上:有一个东西可以把即时奖励猴子吓跑,这个就是慌乱怪——Deadline。 一般情况下慌乱怪都在休眠。但是当Deadline临近的时候它就被唤醒了。这时候,如果不完成任务,你就有可能被大家当作笑柄,或者被解雇,或者考试挂科,或者其他什么令人慌乱的东西。 平时固守岗位的即时奖励猴子,现在直接被慌乱怪吓得连滚带爬地逃走了。要不是这样子,同样平时拖延成性的人,是怎么在考试之前突然变得勇猛无比,战胜熬夜的疲倦,连续写成一篇八页的论文?要不是这样子,平时懒散不锻炼的人,怎么会突然在体育考试之前开始天天跑步? 但是,以上所述的都是幸运的拖延症患者。因为无论工作质量如何,他们至少还能够在Deadline之前把事情完成。有些晚期拖延症患者,对慌乱怪完全没有反应,在Deadline接近的最后那一刹那,选择和猴子一样逃回丛林,进入一种因为自我挫败导致的完全封锁中。 我们的人性啊! 当然了,这些都不是好的生活方式。就算是那些一般性拖延症患者,虽然能够在Deadline之前把事情完成,坚持在人类社会中存活下去,他们的生活也需要改观。以下是几个主要的原因: 这会让你非常不爽。拖延症患者把太多时间都浪费在黑暗游乐场了。要是你按时完成了任务,就完全可以用这些时间来享受那些毫无压力的闲适时光。难道这让你很开心么?拖延最终是出卖了自己。他们最后都不能发挥自己的潜能,这样子的感受煎熬着他的内心,让他变得自卑,充满悔恨。需要做的也许可以完成,但是想要做的却永远都做不到。也许拖延症患者的职业充满了Deadline,这能让他不被开除。但是生活中其他的事情呢?比如健身,做一顿美餐,学着弹吉他,读一本书,写书,甚至大胆的跳槽到更好的公司。这是事情都不会发生,因为没有deadline,没有慌乱怪,拖延症患者永远都做不到。这些事情拓展我们的经历,让我们的生活更加丰富,更重要的是给我们带来幸福感,这些事情对于大多数拖延症患者来说,最后都成了从未开始的压箱底的陈年旧事。现在你知道拖延症是怎么一回事了。战胜那个调皮的猴子,让理智重新掌舵吧。]]></content>
<categories>
<category>有道理</category>
</categories>
</entry>
<entry>
<title><![CDATA[据说如果你各种会聊天,能比别人少奋斗10年]]></title>
<url>%2F2016%2F04%2F30%2F%E6%8D%AE%E8%AF%B4%E5%A6%82%E6%9E%9C%E4%BD%A0%E5%90%84%E7%A7%8D%E4%BC%9A%E8%81%8A%E5%A4%A9%EF%BC%8C%E8%83%BD%E6%AF%94%E5%88%AB%E4%BA%BA%E5%B0%91%E5%A5%8B%E6%96%9710%E5%B9%B4%2F</url>
<content type="text"><![CDATA[原文地址:http://www.yixieshi.com/29182.html 知道吗?小到与同事、老板、客户的每一次日常沟通,大到升职加薪、拓展业务、签合同,处处皆谈判。 每一次谈判都有独特性,但一些战略、战术和原则可以让你的诸多难题迎刃而解。 取悦他人这一条听起来简单,但至关重要:人们只有喜欢你,才会为你争取利益。在谈判中,你做的不讨喜之事越多,越不容易为自己争取到更好的待遇。这不仅关乎礼貌,还涉及如何应对谈判中难免出现的紧张局面,比如争取自己应得的权益又不显得贪心;指出工作机会的缺陷又不被认为是在斤斤计较;坚持自己的意见又不让人感觉胡搅蛮缠。参加谈判的人可以通过评估别人可能的反应来避免上述状况发生。 解释清楚只让他们喜欢你还不够,你还要让他们相信你开出的价码物有所值。永远不要直接开价,记得要讲故事给他们听。不只是陈述愿望;要明确无误地向他们解释为什么要这样做。如果你说不出加薪的正当理由,那么提出加薪请求可能并不明智。同样要记住的是,既讨人喜欢又要求高薪,这两者之间存在天然的矛盾:如果你不知道如何以最佳方式与对方沟通,那么自称具有特殊价值听上去难免会有些傲慢。 表明忠心如果你打算争取更好的福利待遇,一定要让他们知道,你真的希望为这家雇主工作。有时你说多家公司都希望你加盟,会令用人单位很想雇你。但如果你过于强调这点,他们就可能认为,既然你不会接受他们开出的工作邀请,为什么还要费劲给你申请加薪? 了解对方公司不会和你谈判,你的谈判对象是人。要想影响坐在你对面的人,你要先了解她。他对什么感兴趣?关心什么?例如,与未来的老板谈判迥异于与人力资源代表谈判。你或许可以向后者详细询问工作细节,但不能用一些鸡毛蒜皮的要求来麻烦未来的上司。另一方面,人力资源人员可能要负责招聘10个人,因此不愿意打破常规,而你的老板可以从你加入公司这件事上直接受益,或许会愿意满足你的特殊要求。 理解局限他们可能喜欢你,可能认为你该得到所要的一切,但仍无法给你。为什么?可能是因为他们面临一些在谈判中无法网开一面的刚性限制。你的任务是要弄清楚在哪些问题上他们可以灵活处理,在哪些方面难以通过。你对这些限制了解得越透彻,越有可能提出建议,解决双方面临的难题,做到两全其美。 做好准备如果你没做准备,可能会狼狈不堪地蹦出搪塞之词,甚至更糟的是,说假话。我建议你在谈判中永远不要说谎,因为这么做经常适得其反,即使没有不良后果,那也是不道德的。 面临棘手问题时,另一个风险是你会过于讨好对方而难以讨价还价。重点在于你需要做好准备,以便应对那些让你下意识防御、感到不自在,或暴露缺点的问题和话题。你的目标是如实回答,别看上去像一个毫无吸引力的人,也不要放弃太多议价能力。如果你能提前准备好一些疑难问题的回答,可能就不会错失机会。 注意意图尽管你有所准备,还是有人会从意想不到的角度发问。如果发生这种情况,请记住这条简单法则:重要的不是问题本身,而是提问者的意图。 设法针对提问者的发问意图作答,要求你明确说出他心存的疑惑。如果你的回答正好是他想要的答案,或让他知道你愿意解答他的一切疑问,那么你们双方都会感觉更好。 全盘考虑可悲的是,许多人将“工作机会谈判”和“工资谈判”混为一谈。但是,你对工作的满意程度大多来自其他因素,相对于工资而言,它们更易于通过谈判实现。不要只盯着薪酬。你要专注于交易的整体价值,不要只想着你愿意得到的回报方式,还要考虑获得回报的时间。你或许会决定参加一门课程,虽然现在得到的回报有限,但将来会让你晋升至更好的职位。 多提问题如果有人提供给你一份工作,而且你对这份工作的某些部分很在意,通常情况下,一次性抛出所有问题的效果会比较好。如果你有一个以上的要求,不要只是简单地说出你想要的每一样东西,要表示出它们对你而言很重要。否则,对方可能会挑你在意度最小的两件事,轻松帮你解决,进而认为已经满足了你一半的要求。于是,你得到的工作机会并没有变得更诱人,而谈判对手却认为他们能做的都已经做了。 掌握分寸不要向别人证明你是一个谈判高手,要抑制这种冲动。那些上过谈判课的MBA学生常存在这种问题:在得到第一次面试机会时,就跟未来的雇主疯狂讨价还价。我的建议是:如果某样东西对你很重要,就一定要坚持谈判,但不要对每件小事都锱铢必较。为蝇头小利拼得你死我活会适得其反,也会在你今后的职业生涯中,限制你与公司协商的余地。 保持慎重如果你要考虑多个就业机会,最好能让所有工作机会短时间内同时到来。所以,为了让所有选择同时摆在你面前,不必害怕延长与某位潜在雇主的沟通时间,或者加快与另一位雇主的接触。这也是一种平衡手段:如果你拖延太久或催促太甚,公司都有可能对你失去兴趣,转而雇用别人。 不要耍酷人们不喜欢被告知“做这个,否则后果自负”,所以要避免下最后通牒。有时候我们会不经意这样做,目的只是为了展现实力,或者因为感到沮丧,用错了表达方式。你的谈判对手可能会做同样的事。 我个人的方法是,在收到最后通牒时干脆视而不见,因为在某些时候,发出最后通牒的人可能会认识到,这样做会把事情搞砸,想把它收回去。如果此事从未被讨论过,他更易于做到这一点,而且不丢面子。如果有人告诉你,“我们绝对做不到。”不要纠缠于此,或是让她不断重复这话。相反你可以说:“我知道,以目前的情况看,这可能有点困难。也许我们可以谈谈X、Y和Z。”假装最后通牒从未发出,不要让他纠结在这个问题上。如果他是认真的,过段时间,他会对此做出解释。 要有耐心艰难的工资谈判或长时间拖延,不告知是否录用你,可能会让你感觉招聘方在故意刁难。工资谈判在个别问题上陷入胶着,可能只是表明你对一些限制条款并不完全理解。迟迟得不到工作录用通知可能只是意味着,你不是招聘经理惟一关注的对象。 保持联系,但要有耐心。即使你无法耐心等待,也不要带着沮丧或愤怒的情绪,让一切朝期望的方向发展。 给予时间请记住:今天没谈拢的事或许明天可以商量。随着时间的推移,利益和限制都会发生改变。当有人说“不”的时候,他的意思是“今天我对此的看法是否定的。”一个月后,同样的人也许能做些此前他不能做的事,比如延长合同期限或给你加薪。 假设一位未来的老板拒绝你周五在家工作的请求,也许是因为他在这个问题上缺乏弹性。但也可能是因为你还没有得到他足够的信任,让他无法轻易应允。半年后,你可能会有更好的理由,说服他允许你在家办公。要乐意继续交谈,并鼓励他人重新思考未言明或未解决的问题。 有大局观这是最后也是最重要的一点。即使你可以像一位专业人士那样进行谈判,但如果选错了公司,你一样会铩羽而归。让你拥有满足感的是找到合适的工作,而不是如何在谈判中取胜。经验和研究表明,就满意度而言,相对于一份丰厚的工作待遇,你选择从事的行业和职位、你的职业生涯轨迹,以及日常工作氛围对你的影响要重要得多。 上述准则应该能帮你有效地进行谈判,但这些准则只有在深思熟虑、全盘考虑的过程中才会发挥作用,以确保你得偿所愿。]]></content>
<categories>
<category>有道理</category>
</categories>
</entry>
<entry>
<title><![CDATA[解决在Ubuntu14.04中 'Cannot Add PPA' 的错误]]></title>
<url>%2F2016%2F03%2F27%2FFix-Cannot-Add-PPA-Error-In-Ubuntu-14-04-Linux-Mint-17%2F</url>
<content type="text"><![CDATA[123➜ ~ > sudo add-apt-repository ppa:openjdk-r/ppaCannot add PPA: 'ppa:openjdk-r/ppa'.Please check that the PPA name or format is correct. 首先检查DNS设置,查看/etc/resolv.conf,如未配置DNS,则配置DNS,如果还是无效,则按以下思路来解决。 如果你在Ubuntu中添加PPA出现显示的错误时,不要着急。这是一个在添加PPA时出现的一个普遍的错误,也很容易解决。 解决在Ubuntu中无法添加PPA的错误 主要有两个原因会出现这种错误。要么是你系统中的CA证书损坏,或者是你的网络设置了代理。 我们首先重装CA证书: 1sudo apt-get install --reinstall ca-certificates 如果上面的命令无效的话,可能是设置了代理。可以通过E选项绕过系统代理,如下: 1sudo -E add-apt-repository ppa:openjdk-r/ppa]]></content>
<categories>
<category>Linux学习</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title><![CDATA[解决virtualbox复制ubuntu后改变mac地址不能识别网卡问题]]></title>
<url>%2F2016%2F03%2F26%2F%E8%A7%A3%E5%86%B3virtualbox%E5%A4%8D%E5%88%B6ubuntu%E5%90%8E%E6%94%B9%E5%8F%98mac%E5%9C%B0%E5%9D%80%E4%B8%8D%E8%83%BD%E8%AF%86%E5%88%AB%E7%BD%91%E5%8D%A1%E9%97%AE%E9%A2%98%2F</url>
<content type="text"><![CDATA[在vbox里面安装了一个ubuntu server 12.04,利用自带的复制功能,完成3台虚拟服务器的搭建。为了更好的模拟局域网环境,为了保证mac不一样,所以刷新mac地址,登陆时ifconfig发现eth0不翼而飞,自然也不能连通网络。 最后发现是/etc/udev/rules.d/70-persistent-net.rules文件保存了原始虚拟机网卡的mac地址,这时候利用vbox刷新mac地址,自然匹配不了,ubuntu就识别不出网卡。 解决 办法是删除这个文件,然后重启下虚拟机,就可以用了。]]></content>
<categories>
<category>Linux学习</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title><![CDATA[[转]Clickjacking简单介绍]]></title>
<url>%2F2016%2F03%2F24%2F%E8%BD%AC-Clickjacking%E7%AE%80%E5%8D%95%E4%BB%8B%E7%BB%8D%2F</url>
<content type="text"><![CDATA[原文地址:http://drops.wooyun.org/papers/104 0x00 相关背景介绍Clickjacking(点击劫持)是由互联网安全专家罗伯特·汉森和耶利米·格劳斯曼在2008年首创的。 是一种视觉欺骗手段,在web端就是iframe嵌套一个透明不可见的页面,让用户在不知情的情况下,点击攻击者想要欺骗用户点击的位置。 由于点击劫持的出现,便出现了反frame嵌套的方式,因为点击劫持需要iframe嵌套页面来攻击。 下面代码是最常见的防止frame嵌套的例子: 123if(top.location!=location) { top.location=self.location;} 事实上,这种代码很容易被绕过,在后文中讨论。 0x01 防御的几种方式防止frame嵌套的js使用代码由高到低比例: 12345678910if (top != self)if (top.location != self.location)if (top.location != location)if (parent.frames.length > 0)if (window != top)if (window.top !== window.self)if (window.self != window.top)if (parent && parent != window)if (parent && parent.frames && parent.frames.length>0)if((self.parent&&!(self.parent===self))&&(self.parent.frames.length!=0)) 检测到后的处理方案: 123456789101112131415161718192021222324top.location = self.locationtop.location.href = document.location.hreftop.location.href = self.location.hreftop.location.replace(self.location)top.location.href = window.location.hreftop.location.replace(document.location)top.location.href = window.location.hreftop.location.href = "URL"document.write('')top.location = locationtop.location.replace(document.location)top.location.replace('URL')top.location.href = document.locationtop.location.replace(window.location.href)top.location.href = location.hrefself.parent.location = document.locationparent.location.href = self.document.locationtop.location.href = self.locationtop.location = window.locationtop.location.replace(window.location.pathname)window.top.location = window.self.locationsetTimeout(function(){document.body.innerHTML='';},1);window.self.onload = function(evt){document.body.innerHTML='';}var url = window.location.href; top.location.replace(url) 0x02 绕过的几种方式对于使用parent.location来防御的可以使用多层嵌套的方式绕过。 一、例如防御代码为:123if(top.location!=self.location){ parent.location = self.location;} 建立两个页面: 1.html代码为: 1<iframe src="2.html"> 2.html代码为: 1<iframe src="http://www.victim.com"> 访问1.html之后可以看到页面并无跳转等动作。 二、onBeforeUnload函数的利用:onBeforeUnload的介绍以及各种浏览器的支持情况请见: http://w3help.org/zh-cn/causes/BX2047 如下的防御代码: 1if(top != self) top.location.replace(location); 新建立页面,代码如下: 123456789<script>var framekiller = true;window.onbeforeunload = function() { if(framekiller) { return"Write something here to keep people stay!"; }};</script><iframe src="http://www.victim.com/"> 打开页面显示如下: 欺骗用户点击留在此页后显示: 三、XSS filter的利用IE8以上以及Chrome浏览器都有XSS筛选器,这些可以用来对付防御frame嵌套的代码。 防御代码如下: 123if(top!=self){ top.location=self.location;} 新建立页面,代码如下: 1<iframe src="http://www.victim.com/?<script>"> 访问后页面显示: IE的xss筛选器自动拦截了跳转。 斯坦福的文章里写了Chrome也会出现这种情况,并给出了攻击代码: 1<iframe src=http://www.victim.com/?v=if(top+!%3D+self)+%7B+top.location%3Dself.location%3B+%7D"> 但是测试发现,新版的Chrome并不会拦截了,会直接跳转过去。 如果跟的参数中有变量在页面中显示的,会把变量过滤一遍再输出,但不会阻止跳转。 四、Referer检查的问题有一些站点允许自己的域名嵌套自己,禁止外站对自己的嵌套。 通常是用document.referer来检测来源是否为自己的域名。 123456if(top.location!=location){ if(document.referrer && document.referrer.indexOf("aaa.com")==1) { top.location.replace(document.location.href); }} 判断字符串中是否含有本域名是常见的错误用法,利用二级域名的方式便可绕过,如: http://aaa.com.bbb.com 注:从https域下post数据到http域的时候,浏览器不带Referer。 IE有个属性可以设置security为restricted可以禁止iframe里执行js脚本,但是要达到点击劫持的效果,必须要能够执行js所以很鸡肋。 代码如下: 1<iframe src="http://www.victim.com/iframe.html" security="restricted"></iframe> 重点是手机站点,很多主站做的很不错,但是手机站点没有做任何防护,很容易造成点击劫持。 五、location劫持在IE浏览器中,如果能够在防御代码的前面可以插入form表单的话,可以利用form表单对location进行劫持。 123456<form name=self location="javascript:alert(1)"></form><script>if(top!=self){ top.location=self.location}</script> 用iframe嵌套此代码,可以看到没有跳转,执行了alert(1)。 相关案例: WooYun: 腾讯微博clickhijacking(不要被你的双眼欺骗) WooYun: 新浪微博遭受clickhijacking攻击(已经有大量案例) 0x03 推荐防御的方法:一、X-FRAME-OPTIONSX-FRAME-OPTIONS是微软提出的一个http头,专门用来防御利用iframe嵌套的点击劫持攻击。 并且在IE8、Firefox3.6、Chrome4以上的版本均能很好的支持。 这个头有三个值: 123DENY // 拒绝任何域加载SAMEORIGIN // 允许同源域下加载ALLOW-FROM // 可以定义允许frame加载的页面地址 php中设置示例: 1header("X-FRAME-OPTIONS:DENY"); 二、目前最好的js的防御方案为:123456789101112<head><style> body { display : none;} </style></head><body><script>if (self == top) { var theBody = document.getElementsByTagName('body')[0]; theBody.style.display = "block";} else { top.location = self.location;}</script>]]></content>
<categories>
<category>Web安全</category>
</categories>
<tags>
<tag>JavaScript</tag>
</tags>
</entry>
<entry>
<title><![CDATA[SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed]]></title>
<url>%2F2016%2F03%2F23%2FSSL-connect-returned-1-errno-0-state-SSLv3-read-server-certificate-B-certificate-verify-failed%2F</url>
<content type="text"><![CDATA[执行gem install命令时,报错如下: 12OpenSSL::SSL::SSLError (SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed): app/controllers/users_controller.rb:37:in `update' 解决办法: 下载证书:http://curl.haxx.se/ca/cacert.pem 在windows添加环境变量:SSL_CERT_FILE, 值为{证书路径}/cert.pem 参考链接:http://stackoverflow.com/questions/4528101/ssl-connect-returned-1-errno-0-state-sslv3-read-server-certificate-b-certificat]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Ruby</tag>
</tags>
</entry>
<entry>
<title><![CDATA[ERROR: Could not find a valid gem 'sass']]></title>
<url>%2F2016%2F03%2F01%2FERROR-Could-not-find-a-valid-gem-sass%2F</url>
<content type="text"><![CDATA[使用gem安装sass时出错,提示找不到该sass,如下 123C:\>gem install sassERROR: Could not find a valid gem 'sass' (>= 0), here is why: Unable to download data from http://ruby.taobao.org/ - bad response Not Found 404 (http://ruby.taobao.org/specs.4.8.gz) 打开错误中的链接,确实找不到specs.4.8.gz文件 将http协议改成https后,提示下载,说明地址正确,于是修改HOME/.gemrc,将ruby镜像修改为https://ruby.taobao.org/]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Ruby</tag>
</tags>
</entry>
<entry>
<title><![CDATA[SonarQube安装Windows服务后,无法启动服务]]></title>
<url>%2F2016%2F02%2F19%2FSonarQube%E5%AE%89%E8%A3%85Windows%E6%9C%8D%E5%8A%A1%E5%90%8E%EF%BC%8C%E6%97%A0%E6%B3%95%E5%90%AF%E5%8A%A8%E6%9C%8D%E5%8A%A1%2F</url>
<content type="text"><![CDATA[手动安装SonarQube的windows服务后,启动报错,如下: 1234--> Wrapper Started as ServiceLaunching a JVM...Unable to execute Java command. 系统找不到指定的文件。 (0x2)... 解决办法:修改 SONAR_安装目录\conf\wrapper.conf文件,如下 123wrapper.java.command=java# 修改为wrapper.java.command=JAVA_安装目录\bin\java.exe 再次启动,仍然无法启动,错误如下: 12345678910111213141516171819202122232425--> Wrapper Started as ServiceLaunching a JVM...Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org Copyright 1999-2006 Tanuki Software, Inc. All Rights Reserved.WrapperSimpleApp: Encountered an error running main: java.lang.IllegalStateException: Temp directory is not writable: C:\Windows\system32\config\systemprofile\AppData\Local\Temp\java.lang.IllegalStateException: Temp directory is not writable: C:\Windows\system32\config\systemprofile\AppData\Local\Temp\ at org.sonar.process.MinimumViableSystem.checkWritableDir(MinimumViableSystem.java:60) at org.sonar.process.MinimumViableSystem.checkWritableTempDir(MinimumViableSystem.java:52) at org.sonar.process.MinimumViableSystem.check(MinimumViableSystem.java:45) at org.sonar.application.App.main(App.java:112) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.tanukisoftware.wrapper.WrapperSimpleApp.run(WrapperSimpleApp.java:240) at java.lang.Thread.run(Thread.java:745)Caused by: java.io.IOException: 系统找不到指定的路径。 at java.io.WinNTFileSystem.createFileExclusively(Native Method) at java.io.File.createNewFile(File.java:1006) at java.io.File.createTempFile(File.java:1989) at org.sonar.process.MinimumViableSystem.checkWritableDir(MinimumViableSystem.java:57) ... 9 more<-- Wrapper Stopped 解决办法:同样修改 wrapper.conf 文件,如下 123wrapper.java.additional.1=-Djava.awt.headless=true# 修改为wrapper.java.additional.1=-Djava.awt.headless=true -Djava.io.tmpdir=../../temp]]></content>
<categories>
<category>持续集成</category>
</categories>
<tags>
<tag>Sonar</tag>
</tags>
</entry>
<entry>
<title><![CDATA[npm_prompt.lua:11: attempt to concatenate local 'package_version' (a nil value)]]></title>
<url>%2F2016%2F02%2F04%2Fnpm-prompt-lua-11-attempt-to-concatenate-local-package-version-a-nil-value%2F</url>
<content type="text"><![CDATA[问题: 解决办法: 方法一、 package.json中添加version属性 方法二、修改CMDER_HOME\vendor\clink-completions\npm_prompt.lua文件]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Nodejs</tag>
</tags>
</entry>
<entry>
<title><![CDATA[karma start Cannot find module 'jasmine-core']]></title>
<url>%2F2016%2F02%2F03%2Fkarma-start-Cannot-find-module-jasmine-core%2F</url>
<content type="text"><![CDATA[执行 karma start my.conf.js 时出现错误,如下: 解决办法:全局安装 jasmine-core, 命令npm install -g jasmine-core]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Nodejs</tag>
<tag>Karma</tag>
<tag>测试</tag>
</tags>
</entry>
<entry>
<title><![CDATA[shim和polyfill有什么区别?]]></title>
<url>%2F2016%2F01%2F29%2Fshim%E5%92%8Cpolyfill%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB%2F</url>
<content type="text"><![CDATA[在JavaScript的世界里,有两个词经常被提到,shim和polyfill.它们指的都是什么,又有什么区别? 1.Shim 一个shim是一个库,它将一个新的API引入到一个旧的环境中,而且仅靠旧环境中已有的手段实现.  译者注:有时候也称为shiv,比如https://github.com/aFarkas/html5shiv 2.Polyfill 在2010年10月份的时候,Remy Sharp在博客上发表了一篇关于术语”polyfill”的文章,  一个polyfill是一段代码(或者插件),提供了那些开发者们希望浏览器原生提供支持的功能.  因此,一个polyfill就是一个用在浏览器API上的shim.我们通常的做法是先检查当前浏览器是否支持某个API,如果不支持的话就加载对应的polyfill.然后新旧浏览器就都可以使用这个API了.术语polyfill来自于一个家装产品Polyfilla:  Polyfilla是一个英国产品,在美国称之为Spackling Paste(译者注:刮墙的,在中国称为腻子).记住这一点就行:把旧的浏览器想象成为一面有了裂缝的墙.这些polyfill会帮助我们把这面墙的裂缝抹平,还我们一个更好的光滑的墙壁(浏览器) 3.例子 Paul Irish发布过一个Polyfill的总结页面“HTML5 Cross Browser Polyfills”. es5-shim是一个shim,而不是polyfill.因为它是在ECMAScript 3的引擎上实现了ECMAScript 5的新特性,而且在Node.js上和在浏览器上有完全相同的表现(译者注:作者的意思是因为它能在Node.js上使用,不光浏览器上,所以它不是polyfill).  译者注:按照作者的解释,”polyfill是专门兼容浏览器API的shim,shim的范围更大些”.照我看来,这个解释并不正确.但对这样两个连母语是英语的人们也很难理解的词,我也无能为力了.希望真正理解的朋友给讲下.  至于翻译,我觉的就不需要翻译了(类似bug这样的词).如果担心读者不懂,可以用脚注的方式说明一下.或者直接翻译成”兼容代码”,再或”模拟该API的代码”等短语也可以吧.  根据 Modernizr 网站的说法,polyfill 是“在旧版浏览器上复制标准 API 的 JavaScript 补充”。“标准API”指的是 HTML5 技术或功能,例如 Canvas。“JavaScript补充”指的是可以动态地加载 JavaScript 代码或库,在不支持这些标准 API 的浏览器中模拟它们。例如,geolocation(地理位置)polyfill 可以在 navigator 对象上添加全局的 geolocation 对象,还能添加 getCurrentPosition 函数以及“坐标”回调对象,所有这些都是 W3C 地理位置 API 定义的对象和函数。因为 polyfill 模拟标准 API,所以能够以一种面向所有浏览器未来的方式针对这些 API 进行开发,最终目标是:一旦对这些 API 的支持变成绝对大多数,则可以方便地去掉 polyfill,无需做任何额外工作。 参考链接: http://www.beautyoftheweb.cn/Content/zh-CN/Developers/ie10whitepaper/index.html#c6 http://www.ituring.com.cn/article/details/766 原文地址:http://www.cnblogs.com/ziyunfei/archive/2012/09/17/2688829.html]]></content>
<categories>
<category>涨姿势</category>
</categories>
<tags>
<tag>Shim</tag>
<tag>Polyfill</tag>
</tags>
</entry>
<entry>
<title><![CDATA[z-index在IE中失效的解决办法]]></title>
<url>%2F2016%2F01%2F25%2Fz-index%E5%9C%A8IE%E4%B8%AD%E5%A4%B1%E6%95%88%E7%9A%84%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95%2F</url>
<content type="text"><![CDATA[IE6、7都存在着z-index失效的bug,万恶的IE,对于每一个美工来说,IE都不怎么招人待见。但是又无法不照顾到它,毕竟它还占有强大的市场份额。我们不能期望它做出什么改变,我们就要学会找到方法去迎合它。 z-index是让元素漂浮起来的一个属性,在IE6、7中无论你把Z-INDEX的级别设置的有多高,它就是不漂浮起来。在CSS中,要让z-index起作用有个小小前提,就是元素的position属性要是relative,absolute或是fixed。 第一种情况(z-index无论设置多高都不起作用情况):这种情况发生的条件有三个: 父标签 position属性为relative; 问题标签无position属性(不包括static); 问题标签含有浮动(float)属性。 eg:z-index层级不起作用,浮动会让z-index失效 123<div style="position:relative; z-index:9999;"> <img style="float:left;" src="http://www.jacoobs.com/image/logo.jpg" /></div> 解决办法有三个(任一即可): 1、position:relative改为position:absolute; 2、浮动元素添加position属性(如relative,absolute等); 3、去除浮动。 第二种情况 IE6下,层级的表现有时候不是看子标签的z-index多高,而要看整个DOM tree(节点树)的第一个relative属性的父标签的层级。 eg:IE7与IE6有着同样的bug,原因很简单,虽然图片所在div当前的老爸层级很高(1000),但是由于老爸的老爸不顶用,可怜了9999如此强势的孩子没有出头之日啊! 1234567<div style="position:relative;"> <div style="position:relative; z-index:1000;"> <div style="position:absolute; z-index:9999;"> <img src="http://www.jacoobs.com/image/logo.jpg" /> </div> </div></div> 解决办法: 在第一个relative属性加上一个更高的层级(z-index:1) 1234567<div style="position:relative; z-index:1;"> <div style="position:relative; z-index:1000;"> <div style="position:absolute; z-index:9999;"> <img src="http://www.jacoobs.com/image/logo.jpg" /> </div> </div></div> z-index这玩意深不可测,里面所蕴含的知识不是 CSS手册上的那点东西,那只是冰山一角。这涉及到border及background的堆叠模型,涉及到同层级的显示问题,以及浏览器显示的些机制等, 这是很深的一潭水。]]></content>
<categories>
<category>Web开发</category>
</categories>
<tags>
<tag>CSS</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Eclipse中启动tomcat报错java.lang.OutOfMemoryError: PermGen space的解决方法]]></title>
<url>%2F2016%2F01%2F20%2FEclipse%E4%B8%AD%E5%90%AF%E5%8A%A8tomcat%E6%8A%A5%E9%94%99java-lang-OutOfMemoryError-PermGen-space%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95%2F</url>
<content type="text"><![CDATA[>原文地址:http://outofmemory.cn/java/OutOfMemoryError/outofmemoryerror-permgen-space-in-tomcat-with-eclipse 有的项目引用了太多的jar包,或者反射生成了太多的类,异或有太多的常量池,就有可能会报java.lang.OutOfMemoryError: PermGen space的错误, 我们知道可以通过jvm参数 -XX:MaxPermSize=256m来配置这部分堆内存的大小。 在eclipse中如何配置tomcat的内存大小呢? 首先需要双击tomcat server,如下图所示: 双击上图后会出现,tomcat配置的界面: 然后再点击上图的,红色矩形框的链接,会弹出tomcat参数配置的节面,要选择Arguments参数框: 如上图在VM arguments文本框内设置 -XX:MaxPermSize=256m的值即可, 当然此处还可以添加其他jvm参数,比如最大内存,最小内存等。]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Java</tag>
<tag>Eclipse</tag>
</tags>
</entry>
<entry>
<title><![CDATA[IE9中Script438: 对象不支持“createContextualFragment”属性或方法]]></title>
<url>%2F2016%2F01%2F19%2FIE9%E4%B8%ADScript438-%E5%AF%B9%E8%B1%A1%E4%B8%8D%E6%94%AF%E6%8C%81%E2%80%9CcreateContextualFragment%E2%80%9D%E5%B1%9E%E6%80%A7%E6%88%96%E6%96%B9%E6%B3%95%2F</url>
<content type="text"><![CDATA[这个问题在Extjs的官网有人讨论,详见 http://www.sencha.com/forum/showthread.php?125869-Menu-shadow-probolem-in-IE9&p=579336 至于解决办法也很简单,只要在网页什么地方加上 1234567891011if ((typeof Range !== "undefined") && !Range.prototype.createContextualFragment){ Range.prototype.createContextualFragment = function(html) { var frag = document.createDocumentFragment(), div = document.createElement("div"); frag.appendChild(div); div.outerHTML = html; return frag; };} 正对IE8提示 Range 未定义,可以在最前面添加如下 1var Range = window.Range || function(){}; 参考链接:http://www.cnblogs.com/m1234/p/3325705.html]]></content>
<categories>
<category>Web开发</category>
</categories>
<tags>
<tag>ExtJS</tag>
</tags>
</entry>
<entry>
<title><![CDATA[extjs菜单树在IE9下不能加载,报SCRIPT5007: 无法获取未定义或 null 引用的属性“ui”]]></title>
<url>%2F2016%2F01%2F19%2Fextjs%E8%8F%9C%E5%8D%95%E6%A0%91%E5%9C%A8IE9%E4%B8%8B%E4%B8%8D%E8%83%BD%E5%8A%A0%E8%BD%BD%EF%BC%8C%E6%8A%A5SCRIPT5007-%E6%97%A0%E6%B3%95%E8%8E%B7%E5%8F%96%E6%9C%AA%E5%AE%9A%E4%B9%89%E6%88%96-null-%E5%BC%95%E7%94%A8%E7%9A%84%E5%B1%9E%E6%80%A7%E2%80%9Cui%E2%80%9D%2F</url>
<content type="text"><![CDATA[extjs菜单树在IE10下不能加载,报SCRIPT5007: 无法获取未定义或 null 引用的属性“ui” 在ext-all.js下找这个getAttributeNS 方法,把判断ie的代码注释掉就好了; 1234567891011121314getAttributeNS : (Ext.isIE && !(/msie 9/.test(navigator.userAgent.toLowerCase()) && document.documentMode===9) && !(/msie 10/.test(navigator.userAgent.toLowerCase())&&document.documentMode===10))? function(ns, name){ var d=this.dom; var type = typeof d[ns+":"+name]; if( type != 'undefined' && type != 'unknown' ){ return d[ns+":"+name]; } return d[name]; } : function(ns, name){ var d = this.dom; return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name]; } 原文地址:http://www.lxway.com/910062484.htm]]></content>
<categories>
<category>Web开发</category>
</categories>
<tags>
<tag>ExtJS</tag>
</tags>
</entry>
<entry>
<title><![CDATA[JavaScript 事件——“事件流和事件处理程序”]]></title>
<url>%2F2016%2F01%2F11%2FJavaScript-%E4%BA%8B%E4%BB%B6%E2%80%94%E2%80%94%E2%80%9C%E4%BA%8B%E4%BB%B6%E6%B5%81%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%A4%84%E7%90%86%E7%A8%8B%E5%BA%8F%E2%80%9D%2F</url>
<content type="text"><![CDATA[事件流事件流描述的是从页面中接收事件的顺序。IE的事件流是事件冒泡流,而Netscape Communicator的事件流是事件捕获流。 事件冒泡即事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点。如: 123456789<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"></head><body> <div>Click</div></body></html> 当点击了页面中的div元素,那么这个click事件会按照如下顺序传播: div元素 body元素 html元素 document对象 事件捕获事件捕获的思想是最具体的节点应该最后接收到事件。事件捕获的用意在于事件到达目标之前捕获它。当点击了页面中的div元素,那么这个click事件则会按照如下顺序传播: document对象 html标签 body标签 div标签 虽然规范要求事件应该从document对象开始传播,但浏览器一般都是从window对象开始捕获事件的。因为老版本浏览器不支持,所以一般都使用事件冒泡。 DOM事件流“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。 在DOM事件流中,实际的目标在捕获阶段不会接收事件。就是说在 捕获阶段,事件从document到html再到body后就停止了。 下一个阶段是“处于目标”阶段,于是事件在div中发生,并在事件处理中被看成是冒泡阶段的一部分。然后,冒泡阶段发生。IE8及更早的版本不支持DOM事件流,浏览器在捕获阶段触发事件对象上的事件,结果就是有两个机会在目标对象上面操作事件。 事件处理程序事件就是用户或浏览器自身执行的某种动作;事件处理程序(或事件侦听器)就是响应某个事件的函数。事件处理程序的名字以“on”开头,如onload、onclick等。 HTML事件处理程序若要在按钮被单击时执行一些js代码,可以这样编写: 1<div onclick="alert('Clicked')">Click</div> 注意:不能在其中使用未经转义的HTML语法字符。 也可以调用在页面中其他地方定义的脚本: 123456<script>function showMessage() { document.write("fdas");}</script><input type="button" value="Click Me" onclick="showMessage()" /> 事件处理程序中的代码在执行时,有权访问全局作用域中的任何代码。 这样使用会创建一个封装着的元素属性值的函数。这个函数有一个局部变量 event ,也就是事件对象: 1<input type="button" value="Click Me" onclick="alert(event.type)" /> 其中, this 值等于事件的目标元素,如: 1<input type="button" value="Click Me" onclick="alert(this.value)" /> HTML事件处理程序存在众多问题,所以应该使用js指定的事件处理程序 DOM0级事件处理程序要使用js指定事件处理程序,首先必须取得一个要操作的对象的引用。 每个元素都有自己的事件处理程序属性,这些属性通常全部小写,如onclick。如: 123456<input type="button" value="Click Me" id="btn" /><script>document.querySelector("#btn").onclick = function() { console.log("hello");}</script> 使用DOM0级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行的;也就是this引用当前元素: 123456<input type="button" value="Click Me" id="btn" /><script>document.querySelector("#btn").onclick = function() { console.log(this.type);}</script> 以上述这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。 删除通过DOM0级方法指定的事件处理程序: btn.onclick = null; DOM2级事件处理程序 addEventListener()该方法接收三个参数:要处理的事件名、事件处理程序函数和布尔值;布尔值如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。如: 1234var btn = document.getElementById("btn");btn.addEventListener("click", function () { console.log(this.id);}) 还可以为该按钮添加多个事件处理程序,如: 1234567891011121314151617181920212223242526272829303132333435var btn = document.getElementById("btn");btn.addEventListener("click", function() { console.log(this.id);});btn.addEventListener("click", function() { console.log(this.value);});removeEventListener();var btn = document.getElementById("btn");function info () { console.log(this.value);}btn.addEventListener("click", info);btn.addEventListener("click", function () { console.log(this.id);});btn.addEventListener("click", function valueAndId () { console.log(this.value + " " + this.id);});btn.removeEventListener("click", info); // succbtn.removeEventListener("click", function () { console.log(this.id);}); // no effectbtn.removeEventListener("click", valueAndId); // error 大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样就可以最大限度地兼容各种浏览器。 原文地址:http://www.codesec.net/view/244340.html]]></content>
<categories>
<category>Web开发</category>
</categories>
<tags>
<tag>JavaScript</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android单元测试Invalid layout of java.lang.String at value]]></title>
<url>%2F2015%2F12%2F07%2FAndroid%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95Invalid-layout-of-java-lang-String-at-value%2F</url>
<content type="text"><![CDATA[遇到:Invalid layout of java.lang.String at value 这样的问题>原文地址: http://www.cnblogs.com/wangmars/p/3255044.html 1234567891011121314151617Invalid layout of java.lang.String at value## A fatal error has been detected by the Java Runtime Environment:## Internal Error (javaClasses.cpp:129), pid=7532, tid=11904# fatal error: Invalid layout of preloaded class## JRE version: 7.0_25-b17# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.25-b01 mixed mode windows-amd64 compressed oops)# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows## An error report file with more information is saved as:# E:\workspace\IflytekBus_06\hs_err_pid7532.log## If you would like to submit a bug report, please visit:# http://bugreport.sun.com/bugreport/crash.jsp# 看图就行了:]]></content>
<categories>
<category>移动开发</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title><![CDATA[自编译ngrok服务器实现内网穿透]]></title>
<url>%2F2015%2F11%2F25%2F%E8%87%AA%E7%BC%96%E8%AF%91ngrok%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%AE%9E%E7%8E%B0%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%2F</url>
<content type="text"><![CDATA[一. 首先安装GO环境 Linux 下安装 Centos下使用epel源安装: 1yum install golang Centos/Linux下源码安装golang: 1234567wget https://storage.googleapis.com/golang/go1.4.1.linux-amd64.tar.gztar -C /usr/local -xzf go1.4.1.linux-amd64.tar.gzmkdir $HOME/goecho 'export GOROOT=/usr/local/go' >> ~/.bashrcecho 'export GOPATH=$HOME/go' >> ~/.bashrcecho 'export PATH=$PATH:$GOROOT/bin:$GOPATH/bin' >> ~/.bashrcsource $HOME/.bashrc 安装go get工具: 1yum install mercurial git bzr subversion Windows 下安装: 下载https://storage.googleapis.com/golang/go1.4.1.windows-386.zip 设置环境变量: 12345setx GOOS windowssetx GOARCH 386setx GOROOT "D:\Program Files\go"setx GOBIN "%GOROOT%\bin"setx PATH %PATH%;D:\Program Files\go\bin" 二. 编译安装 NGROK 下载 NGROK源码 1234cd /usr/local/src/git clone https://github.com/inconshreveable/ngrok.gitexport GOPATH=/usr/local/src/ngrok/export NGROK_DOMAIN="haiyun.me" 生成自签名SSL证书,ngrok为ssl加密连接: 生成证书并编译 123456789101112cd ngrokopenssl genrsa -out rootCA.key 2048openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -out rootCA.pemopenssl genrsa -out device.key 2048openssl req -new -key device.key -subj "/CN=$NGROK_DOMAIN" -out device.csropenssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 5000cp rootCA.pem assets/client/tls/ngrokroot.crtcp device.crt assets/server/tls/snakeoil.crtcp device.key assets/server/tls/snakeoil.keyGOOS=linux GOARCH=386make cleanmake release-server release-client 如果在安装yaml的时候不能下载,无反应: 1go get gopkg.in/yaml.v1 原因git版本太低,需>= 1.7.9.5,通过RPMForge源安装最新版本git解决: 1yum --enablerepo=rpmforge-extras install git 三. 启动SERVER: 启动 Server 1bin/ngrokd -domain="$NGROK_DOMAIN" -httpAddr=":8000" 交叉编译windows客户端,最好安装最新版本Golang,使用yum安装的一直编译不通过。 1234cd /usr/local/go/src/GOOS=windows GOARCH=386 CGO_ENABLED=0 ./make.bashcd -GOOS=windows GOARCH=386 make release-server release-client 客户端配置: 123456789101112server_addr: "haiyun.me:4443"trust_host_root_certs: falsetunnels: http: subdomain: "example" auth: "user:12345" proto: http: "80" ssh: remote_port: 2222 proto: tcp: "22" 启动客户端: 1bin/ngrok -config ngrok.conf start http ssh 注意所有domain要一致,不然会出现证书错误: 1Failed to read message: remote error: bad certificate 原文地址:http://www.haiyun.me/archives/1012.html]]></content>
<tags>
<tag>Linux</tag>
<tag>Ngrok</tag>
</tags>
</entry>
<entry>
<title><![CDATA[gradle工程提示Unable to start the daemon process]]></title>
<url>%2F2015%2F11%2F19%2Fgradle%E5%B7%A5%E7%A8%8B%E6%8F%90%E7%A4%BAUnable-to-start-the-daemon-process%2F</url>
<content type="text"><![CDATA[Eclipse中使用Gradle 管理项目依赖时,提示错误,如下1234567891011Unable to start the daemon process.This problem might be caused by incorrect configuration of the daemon.For example, an unrecognized jvm option is used.Please refer to the user guide chapter on the daemon at http://gradle.org/docs/2.4/userguide/gradle_daemon.htmlPlease read the following process output to find out more:-----------------------Unrecognized VM option 'MaxPermSize=256m'Error: Could not create the Java Virtual Machine.Error: A fatal exception has occurred. Program will exit.Could not fetch model of type 'EclipseProject' using Gradle installation '/Users/bao/Desktop/BFL/programs/gradle/gradle-2.4'. 解决办法如下: 在操作系统当前用户的.gradle文件夹下:$HOME/.gradle 设置gradle.properties,若无就新增, 并在文件中添加如下配置信息:12org.gradle.daemon=trueorg.gradle.jvmargs=-Xmx512m]]></content>
<tags>
<tag>Gradle</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Ubuntu下通过nvm安装node,npm command not found]]></title>
<url>%2F2015%2F11%2F05%2FUbuntu%E4%B8%8B%E9%80%9A%E8%BF%87nvm%E5%AE%89%E8%A3%85node%EF%BC%8Cnpm-command-not-found%2F</url>
<content type="text"><![CDATA[在 Ubuntu 下使用 NVM 管理 node 版本,执行 npm 命令的时候,提示找不到命令,但是通过 where 查找 npm 命令的时候,是可以找到的,同时提示npm:aliased to sudo npm,如下图: 根据这个思路查找,找到了解决办法:为当前账户添加node_modules目录读写权限即可。1sudo chown -R $(whoami) ~/.npm]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Nodejs</tag>
<tag>Npm</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Android Studio配置Respository更新Android SDK]]></title>
<url>%2F2015%2F10%2F31%2FAndroid-Studio%E9%85%8D%E7%BD%AERespository%E6%9B%B4%E6%96%B0Android-SDK%2F</url>
<content type="text"><![CDATA[1. 首先关闭 Android Studio 启动SDK 版本检测Android Studio 安装后启动后一直停止在 Checking for updated SDK components,定位到 Android studio 安装目录的bin子目录,找到 idea.properties 文件。在 idea.properties 文件的最后增加一行代码: 1disable.android.first.run=true 这行的作用就是让Android studio 在启动过程不进行SDK的版本检测。再次启动 Android studio,就可以进入开发界面了。 2. 打开 Android Studio 配置界面 添加 东软信息学院开源镜像 Repository 1http://mirrors.neusoft.edu.cn/android/repository/addon.xml 3. 更新 SDK Tools 选中需要更新的项,点击右下角的 Apply]]></content>
<categories>
<category>移动开发</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title><![CDATA['tools.jar' seems to be not in Studio classpath]]></title>
<url>%2F2015%2F10%2F31%2Ftools-jar-seems-to-be-not-in-Studio-classpath%2F</url>
<content type="text"><![CDATA[Q: Mac 启动 Android Studio 时,无法启动,错误如下: A: 将 $JAVA_HOME/lib/tools 拷贝到 ANDROID_STUDIO_ROOT/lib/ 下, 可执行如下命令 1sudo cp $JAVA_HOME/lib/tools.jar /Applications/Android\ Studio.app/Contents/lib/]]></content>
<categories>
<category>移动开发</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title><![CDATA[CocoaPod 出现 Unable to satisfy the following requirements:required by 'Podfile']]></title>
<url>%2F2015%2F10%2F22%2FCocoaPod-%E5%87%BA%E7%8E%B0-Unable-to-satisfy-the-following-requirements-required-by-Podfile%2F</url>
<content type="text"><![CDATA[Q:通过 pod 更新iOS 第三方库时报错,错误如下: 12345678$ pod update --verbose --no-repo-update......Resolving dependencies of `Podfile`[!] Unable to satisfy the following requirements:- `AFNetworking (~> 2.6.0)` required by `Podfile` A:通过网络搜索,找到解决办法如下: 删除本地缓存sudo rm -fr ~/.cocoapods/repos/master 然后运行pod setup 注:如果出现下面错误 1git clone error: RPC failed; result=56, HTTP code = 200 错误解决 1git config --global http.postBuffer 524288000(尽量大)]]></content>
<categories>
<category>移动开发</category>
</categories>
<tags>
<tag>iOS</tag>
</tags>
</entry>
<entry>
<title><![CDATA[DOM 中 Property 和 Attribute 的区别]]></title>
<url>%2F2015%2F10%2F05%2FDOM-%E4%B8%AD-Property-%E5%92%8C-Attribute-%E7%9A%84%E5%8C%BA%E5%88%AB%2F</url>
<content type="text"><![CDATA[property 和 attribute非常容易混淆,两个单词的中文翻译也都非常相近(property:属性,attribute:特性),但实际上,二者是不同的东西,属于不同的范畴。 property是DOM中的属性,是JavaScript里的对象; attribute是HTML标签上的特性,它的值只能够是字符串; 基于JavaScript分析property 和 attributehtml中有这样一段代码: 1<input id="in_1" value="1" sth="whatever"> 简单的在html页面上创建一个input输入栏(注意在这个标签中添加了一个DOM中不存在的属性“sth”),此时在JS执行如下语句 1var in1 = document.getElementById('in_1'); 执行语句 1console.log(in1); 从console的打印结果,可以看到in1含有一个名为“attributes”的属性,它的类型是NamedNodeMap,同时还有“id”和“value”两个基本的属性,但没有“sth”这个自定义的属性。 123attributes: NamedNodeMapvalue: "1"id: "in_1" 有些console可能不会打印in1上的属性,那么可以执行以下命令打印要观察的属性: 123console.log(in1.id); // 'in_1'console.log(in1.value); // 1console.log(in1.sth); // undefined 可以发现,标签中的三个属性,只有“id”和“value”会在in1上创建,而“sth”不会被创建。这是由于,每一个DOM对象都会有它默认的基本属性,而在创建的时候,它只会创建这些基本属性,我们在TAG标签中自定义的属性是不会直接放到DOM中的。 我们做一个额外的测试,创建另一个input标签,并执行类似的操作: html: 1<input id="in_2"> JS: 12var in2 = document.getElementById('in_2');console.log(in2); 从打印信息中可以看到: 12id: "in_2"value: null 尽管我们没有在TAG中定义“value”,但由于它是DOM默认的基本属性,在DOM初始化的时候它照样会被创建。由此我们可以得出结论: DOM有其默认的基本属性,而这些属性就是所谓的“property”,无论如何,它们都会在初始化的时候再DOM对象上创建。 如果在TAG对这些属性进行赋值,那么这些值就会作为初始值赋给DOM的同名property。 现在回到第一个input(“#in_1”),我们就会问,“sth”去哪里了?别急,我们把attributes这个属性打印出来看看 1console.log(in2); 上面有几个属性: 123450: id1: value2: sthlength: 3__proto__: NamedNodeMap 原来“sth”被放到了attributes这个对象里面,这个对象按顺序记录了我们在TAG中定义的属性和属性的数量。此时,如果再将第二个input标签的attributes打印出来,就会发现只有一个“id”属性,“length”为1。 从这里就可以看出,attributes是属于property的一个子集,它保存了HTML标签上定义属性。如果再进一步探索attitudes中的每一个属性,会发现它们并不是简单的对象,它是一个Attr类型的对象,拥有NodeType、NodeName等属性。关于这一点,稍后再研究。注意,打印attribute属性不会直接得到对象的值,而是获取一个包含属性名和值的字符串,如: 1console.log(in1.attibutes.sth); // 'sth="whatever"' 由此可以得出: HTML标签中定义的属性和值会保存该DOM对象的attributes属性里面; 这些attribute属性的JavaScript中的类型是Attr,而不仅仅是保存属性名和值这么简单; 那么,如果我们更改property和attribute的值会出现什么效果呢?执行如下语句: 123in1.value = 'new value of prop';console.log(in1.value); // 'new value of prop'console.log(in1.attributes.value); // 'value="1"' 此时,页面中的输入栏的值变成了“new value of prop”,而propety中的value也变成了新的值,但attributes却仍然是“1”。从这里可以推断,property和attribute的同名属性的值并不是双向绑定的。 如果反过来,设置attitudes中的值,效果会怎样呢? 123in1.attributes.value.value = 'new value of attr';console.log(in1.value); // 'new value of attr'console.log(in1.attributes.value); // 'new value of attr' 此时,页面中的输入栏得到更新,property中的value也发生了变化。此外,执行下面语句也会得到一样的结果 1in1.attributes.value.nodeValue = 'new value of attr'; 由此,可得出结论: property能够从attribute中得到同步; attribute不会同步property上的值; attribute和property之间的数据绑定是单向的,attribute->property; 更改property和attribute上的任意值,都会将更新反映到HTML页面中; 基于jQuery分析attribute和property那么jQuery中的attr和prop方法是怎样的呢? 首先利用jQuery.prop来测试 1234$(in1).prop('value', 'new prop form $');console.log(in1.value); // 'new prop form $'console.log(in1.attributes.value); // '1' 输入栏的值更新了,但attribute并未更新。 然后用jQuery.attr来测试 1234$(in1).attr('value', 'new attr form $');console.log(in1.value); // 'new attr form $'console.log(in1.attributes.value); // 'new attr form $' 输入栏的值更新了,同时property和attribute都更新了。 从上述测试的现象可以推断,jQuery.attr和jQuery.prop基本和原生的操作方法效果一致,property会从attribute中获取同步,然而attribute不会从property中获取同步。那么jQuery到底是如何实现的呢? 下面,我们来看看jQuery.attr和jQuery.prop的源码。 jQuery源码$().prop源码123456jQuery.fn.extend({ prop: function( name, value ) { return access( this, jQuery.prop, name, value, arguments.length > 1 ); }, ... // removeProp方法}); $().attr源码123456jQuery.fn.extend({ attr: function( name, value ) { return access( this, jQuery.attr, name, value, arguments.length > 1 ); }, ... // removeAttr方法}); 无论是attr还是prop,都会调用access方法来对DOM对象的元素进行访问,因此要研究出更多内容,就必须去阅读access的实现源码。 jQuery.access12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364// 这是一个多功能的函数,能够用来获取或设置一个集合的值// 如果这个“值”是一个函数,那么这个函数会被执行// @param elems, 元素集合// @param fn, 对元素进行处理的方法// @param key, 元素名// @param value, 新的值// @param chainable, 是否进行链式调用// @param emptyGet,// @param raw, 元素是否一个非function对象var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, // 迭代计数 length = elems.length, // 元素长度 bulk = key == null; // 判断是否有特定的键(属性名) // 如果存在多个属性,递归调用来逐个访问这些值 if ( jQuery.type( key ) === "object" ) { chainable = true; for ( i in key ) { jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); } // 设置一个值 } else if ( value !== undefined ) { chainable = true; if ( !jQuery.isFunction( value ) ) { // 如果值不是一个function raw = true; } if ( bulk ) { // Bulk operations run against the entire set // 如果属性名为空且属性名不是一个function,则利用外部处理方法fn和value来执行操作 if ( raw ) { fn.call( elems, value ); fn = null; // ...except when executing function values // 如果value是一个function,那么就重新构造处理方法fn // 这个新的fn会将value function作为回调函数传递给到老的处理方法 } else { bulk = fn; fn = function( elem, key, value ) { return bulk.call( jQuery( elem ), value ); }; } } if ( fn ) { // 利用处理方法fn对元素集合中每个元素进行处理 for ( ; i < length; i++ ) { fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); // 如果value是一个funciton,那么首先利用这个函数返回一个值并传入fn } } } return chainable ? elems : // 如果是链式调用,就返回元素集合 // Gets bulk ? fn.call( elems ) : length ? fn( elems[0], key ) : emptyGet;}; access方法虽然不长,但是非常绕,要完全读懂并不简单,因此可以针对jQuery.fn.attr的调用来简化access。 jQuery.fn.attr/ jQuery.fn.prop 中的access调用$().attr的调用方式: $().attr( propertyName ) // 获取单个属性 $().attr( propertyName, value ) // 设置单个属性 $().attr( properties ) // 设置多个属性 $().attr( propertyName, function ) // 对属性调用回调函数 prop的调用方式与attr是一样的,在此就不重复列举。为了简单起见,在这里只对第一和第二种调用方式进行研究。 调用语句: 1access( this, jQuery.attr, name, value, arguments.length > 1 ); 简化的access: 123456789101112131415161718192021222324252627282930313233// elems 当前的jQuery对象,可能包含多个DOM对象// fn jQuery.attr方法// name 属性名// value 属性的值// chainable 如果value为空,则chainable为false,否则chainable为truevar access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, // 迭代计数 length = elems.length, // 属性数量 bulk = false; // key != null if ( value !== undefined ) { // 如果value不为空,则为设置新值,否则返回该属性的值 chainable = true; raw = true; // value不是function if ( fn ) { // fn为jQuery.attr for ( ; i < length; i++ ) { fn( elems[i], key, value); // jQuery.attr(elems, key, value); } } } if(chainable) { // value不为空,表示是get return elems; // 返回元素实现链式调用 } else { if(length) { // 如果元素集合长度不为零,则返回第一个元素的属性值 return fn(elems[0], key); // jQuery.attr(elems[0], key); } else { return emptyGet; // 返回一个默认值,在这里是undefined } }}; 通过简化代码,可以知道,access的作用就是遍历上一个$调用得到的元素集合,对其调用fn函数。在jQuery.attr和jQuery.prop里面,就是利用access来遍历元素集合并对其实现对attribute和property的控制。access的源码里面有多段条件转移代码,看起来眼花缭乱,其最终目的就是能够实现对元素集合的变量并完成不同的操作,复杂的代码让jQuery的接口变得更加简单,能极大提高代码重用性,意味着减少了代码量,提高代码的密度从而使JS文件大小得到减少。 这些都是题外话了,现在回到$().attr和$().prop的实现。总的说,这两个原型方法都利用access对元素集进行变量,并对每个元素调用jQuery.prop和jQuery.attr方法。要注意,这里的jQuery.prop和jQuery.attr并不是原型链上的方法,而是jQuery这个对象本身的方法,它是使用jQuery.extend进行方法扩展的(jQuery.fn.prop和jQuery.fn.attr是使用jQuery.fn.extend进行方法扩展的)。 下面看看这两个方法的源码。 jQury.attr1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556jQuery.extend({ attr: function( elem, name, value ) { var hooks, ret, nType = elem.nodeType; // 获取Node类型 // 如果 elem是空或者NodeType是以下类型 // 2: Attr, 属性, 子节点有Text, EntityReference // 3: Text, 元素或属性中的文本内容 // 8: Comment, 注释 // 不执行任何操作 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return; } // 如果支持attitude方法, 则调用property方法 if ( typeof elem.getAttribute === strundefined ) { return jQuery.prop( elem, name, value ); } // 如果elem的Node类型不是元素(1) if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { name = name.toLowerCase(); // 针对浏览器的兼容性,获取钩子函数,处理一些特殊的元素 hooks = jQuery.attrHooks[ name ] || ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook ); } if ( value !== undefined ) { // 如果value不为undefined,执行"SET" if ( value === null ) { // 如果value为null,则移除attribute jQuery.removeAttr( elem, name ); } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; // 使用钩子函数 } else { // 使用Dom的setAttribute方法 elem.setAttribute( name, value + "" ); // 注意,要将value转换为string,因为所有attribute的值都是string return value; } // 如果value为undefined,就执行"GET" } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { return ret; // 使用钩子函数 } else { ret = jQuery.find.attr( elem, name ); // 实际上调用了Sizzle.attr,这个方法中针对兼容性问题作出处理来获取attribute的值 // 返回获得的值 return ret == null ? undefined : ret; } }, ...}); 从代码可以发现,jQuery.attr调用的是getAttribute和setAttribute方法。 jQeury.prop123456789101112131415161718192021222324252627282930313233jQuery.extend({ ... prop: function( elem, name, value ) { var ret, hooks, notxml, nType = elem.nodeType; // 过滤注释、Attr、元素文本内容 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return; } notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); if ( notxml ) { // 如果不是元素 name = jQuery.propFix[ name ] || name; // 修正属性名 hooks = jQuery.propHooks[ name ]; // 获取钩子函数 } if ( value !== undefined ) { // 执行"SET" return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ? ret : // 调用钩子函数 ( elem[ name ] = value ); // 直接对elem[name]赋值 } else { // 执行"GET" return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ? ret : // 调用钩子函数 elem[ name ]; // 直接返回elem[name] } }, ...}); jQuery.prop则是直接对DOM对象上的property进行操作。 通过对比jQuery.prop和jQuery.attr可以发现,前者直接对DOM对象的property进行操作,而后者会调用setAttribute和getAttribute方法。setAttribute和getAttribute方法又是什么方法呢?有什么效果? setAttribute和getAttribute基于之前测试使用的输入框,执行如下代码: 12345in1.setAttribute('value', 'new attr from setAttribute');console.log(in1.getAttribute('value')); // 'new attr from setAttribute'console.log(in1.value); // 'new attr from setAttribute'console.log(in1.attributes.value); // 'value="new attr from setAttribute"',实际是一个Attr对象 执行完setAttribute以后,就如同直接更改attributes中的同名属性;而getAttribute的结果与访问property的结果一模一样,而不会像直接访问attritudes那样返回一个Attr对象。 特殊的例子href然而,是不是所有标签,所有属性都维持保持这样的特性呢?下面我们看看href这个属性/特性。 首先在html中创建一个标签: 1<a href='page_1.html' id='a_1'></a> 在JS脚本中执行如下代码: 12console.log(a1.href); // 'file:///D:/GitHub/JS/html/test_01/page_1.html'console.log(a1.getAttribute('href')); // 'page_1.html' 可以看到,property中保存的是绝对路径,而attribute中保存的是相对路径。那么,如果更改了这些值会发生什么情况呢? 更改attribute: 1234567a1.setAttribute('href', 'page_2.html'); // 相对路径console.log(a1.href); // 'file:///D:/GitHub/JS/html/test_01/page_2.html'console.log(a1.getAttribute('href')); // 'page_2.html'a1.setAttribute('href', '/page_3.html'); // 根目录路径console.log(a1.href); // 'file:///D:/page_3.html'console.log(a1.getAttribute('href')); // '/page_3.html' 更改property: 1234567a1.href = 'home.html'; // 相对路径console.log(a1.href); // 'file:///D:/GitHub/JS/html/test_01/home.html'console.log(a1.getAttribute('href')); // 'home.html'a1.href = '/home.html'; // 根目录路径console.log(a1.href); // 'file:///D:/home.html'console.log(a1.getAttribute('href')); // '/home.html' 从这里可以发现,href是特殊的属性/特性,二者是双向绑定的,更改任意一方,都会导致另一方的的值发生改变。而且,这并不是简单的双向绑定,property中的href永远保存绝对路径,而attribute中的href则是保存相对路径。 看到这里,attribute和property的区别又多了一点,然而,这又让人变得更加疑惑了。是否还有其他类似的特殊例子呢? ####id 尝试改变property中的id: 123a1.id = 'new_id';console.log(a1.id); // 'new_id'console.log(a1.getAttribute('id')); // 'new_id' 天呀,现在attribute中的id从property中的id发生了同步,数据方向变成了property <=> attribute; ####disabled 再来看看disabled这个属性,我们往第一个添加“disabled”特性: 1<input id="in_1" value="1" sth="whatever" disabled='disabled'> // 此时input已经被禁用了 然后执行下面的代码: 1234console.log(in1.disabled); // truein1.setAttribute('disabled', false); // 设置attribute中的disabled,无论是false还是null都不会取消禁用console.log(in1); // trueconsole.log(in1.getAttribute('disabled')); // 'false' 改变attributes中的disabled不会改变更改property,也不会取消输入栏的禁用效果。 如果改成下面的代码: 12345678910console.log(in1.disabled); // truein1.disabled = false; // 取消禁用console.log(in1.disabled); // falseconsole.log(in1.getAttribute('disabled')); // null,attribute中的disabled已经被移除了又或者:console.log(in1.disabled); // truein1.removeAttribute('disabled'); // 移除attribute上的disabled来取消禁用console.log(in1.disabled); // falseconsole.log(in1.getAttribute('disabled')); // null,attribute中的disabled已经被移除了 可以发现,将property中的disabled设置为false,会移除attributes中的disabled。这样数据绑定又变成了,property<=>attribute; 所以property和attritude之间的数据绑定问题并不能单纯地以“property<-attribute”来说明。 总结分析了这么多,对property和attribute的区别理解也更深了,在这里总结一下: 创建 DOM对象初始化时会在创建默认的基本property; 只有在HTML标签中定义的attribute才会被保存在property的attributes属性中; attribute会初始化property中的同名属性,但自定义的attribute不会出现在property中; attribute的值都是字符串; 数据绑定 attributes的数据会同步到property上,然而property的更改不会改变attribute; 对于value,class这样的属性/特性,数据绑定的方向是单向的,attribute->property; 对于id而言,数据绑定是双向的,attribute<=>property; 对于disabled而言,property上的disabled为false时,attribute上的disabled必定会并存在,此时数据绑定可以认为是双向的; 使用 可以使用DOM的setAttribute方法来同时更改attribute; 直接访问attributes上的值会得到一个Attr对象,而通过getAttribute方法访问则会直接得到attribute的值; 大多数情况(除非有浏览器兼容性问题),jQuery.attr是通过setAttribute实现,而jQuery.prop则会直接访问DOM对象的property; 到这里为止,得出,property是DOM对象自身就拥有的属性,而attribute是我们通过设置HTML标签而给之赋予的特性,attribute和property的同名属性/特性之间会产生一些特殊的数据联系,而这些联系会针对不同的属性/特性有不同的区别。 事实上,在这里,property和attribute之间的区别和联系难以用简单的技术特性来描述,我在StackFlow上找到如下的回答,或者会更加接近于真正的答案:>These words existed way before Computer Science came around.>Attribute is a quality or object that we attribute to someone or something. For example, the scepter is an attribute of power and statehood. >Property is a quality that exists without any attribution. For example, clay has adhesive qualities; or, one of the properties of metals is electrical conductivity. Properties demonstrate themselves though physical phenomena without the need attribute them to someone or something. By the same token, saying that someone has masculine attributes is self-evident. In effect, you could say that a property is owned by someone or something.>To be fair though, in Computer Science these two words, at least for the most part, can be used interchangeably - but then again programmers usually don’t hold degrees in English Literature and do not write or care much about grammar books :). 最关键的两句话: attribute(特性),是我们赋予某个事物的特质或对象。 property(属性),是早已存在的不需要外界赋予的特质。 参考 What is the difference between attribute and property? javascript中attribute和property的区别详解 原文地址:http://www.cnblogs.com/elcarim5efil/p/4698980.html]]></content>
<categories>
<category>Web开发</category>
</categories>
<tags>
<tag>JavaScript</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Vagrant up with warning of Authentication failure]]></title>
<url>%2F2015%2F10%2F01%2FVagrant-up-with-warning-of-Authentication-failure%2F</url>
<content type="text"><![CDATA[当vagrant up启动虚拟机的时候,到最后一直提示如下: 1234......default: Warning: Remote connection disconnect. Retrying...default: Warning: Authentication failure. Retrying...default: Warning: Authentication failure. Retrying... 最终找到解决办法,很简单,删除虚拟机的私有密钥即可,命令如下: 1rm .vagrant/machines/ubuntu-study/virtualbox/private_key 参考地址:http://dockone.io/article/339]]></content>
<categories>
<category>Linux学习</category>
</categories>
<tags>
<tag>Vagrant</tag>
</tags>
</entry>
<entry>
<title><![CDATA[如何下载各版本Chrome的离线安装包]]></title>
<url>%2F2015%2F09%2F26%2F%E5%A6%82%E4%BD%95%E4%B8%8B%E8%BD%BD%E5%90%84%E7%89%88%E6%9C%ACChrome%E7%9A%84%E7%A6%BB%E7%BA%BF%E5%AE%89%E8%A3%85%E5%8C%85%2F</url>
<content type="text"><![CDATA[打开Chrome官网(自行搜索),我们就会看到如下图的下载按钮,然而点击下载后,下载的却是联网安装包,这对部分上网不方便的用户造成了一定的麻烦。 在官网首页,我们可以找到该网页的链接,如下图所示: 我们在该网页链接的后面加上?standalone=1就可以下载到离线安装包,这是最新稳定版的离线安装包,如下图所示: 在此总结一下: 最新稳定版:https://www.google.com/intl/zh-CN/chrome/browser/?standalone=1 最新测试版:https://www.google.com/intl/zh-CN/chrome/browser/?standalone=1&extra=betachannel 最新开发版:https://www.google.com/intl/zh-CN/chrome/browser/?standalone=1&extra=devchannel 有时候我们想要下载历史版本的怎么办?这个也有通用的下载地址,但是前提是你需要知道想要下载的历史版本的版本号。通用的下载地址是:http://dl.google.com/chrome/install/[版本号后两位]/chrome_installer.exe 比如,我们想要下载4.0.266.0的版本,下载地址就是http://dl.google.com/chrome/install/266.0/chrome_installer.exe]]></content>
<tags>
<tag>Chrome</tag>
</tags>
</entry>
<entry>
<title><![CDATA[JavaScript基础之Array对象]]></title>
<url>%2F2015%2F09%2F18%2FJavaScript%E5%9F%BA%E7%A1%80%E4%B9%8BArray%E5%AF%B9%E8%B1%A1%2F</url>
<content type="text"><![CDATA[>原文链接:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array Summary>The JavaScript Array object is a global object that is used in the construction of arrays; which are high-level, list-like objects. Create an Array 1234var fruits = ["Apple", "Banana"];console.log(fruits.length);// 2 Access (index into) an Array item 12345var first = fruits[0];// Applevar last = fruits[fruits.length - 1];// Banana Loop over an Array 12345fruits.forEach(function (item, index, array) { console.log(item, index);});// Apple 0// Banana 1 Add to the end of an Array 12var newLength = fruits.push("Orange");// ["Apple", "Banana", "Orange"] Remove from the end of an Array 12var last = fruits.pop(); // remove Orange (from the end)// ["Apple", "Banana"]; Remove from the front of an Array 12var first = fruits.shift(); // remove Apple from the front// ["Banana"]; Add to the front of an Array 12var newLength = fruits.unshift("Strawberry") // add to the front// ["Strawberry", "Banana"]; Find the index of an item in the Array 12345fruits.push("Mango");// ["Strawberry", "Banana", "Mango"]var pos = fruits.indexOf("Banana");// 1 Remove an item by Index Position 12var removedItem = fruits.splice(pos, 1); // this is how to remove an item// ["Strawberry", "Mango"] Copy an Array 12var shallowCopy = fruits.slice(); // this is how to make a copy// ["Strawberry", "Mango"] Syntax>123[element0, element1, ..., elementN]new Array(element0, element1[, ...[, elementN]])new Array(arrayLength) elementN   A JavaScript array is initialized with the given elements, except in the case where a single argument is passed to the Array constructor and that argument is a number. (See below.) Note that this special case only applies to JavaScript arrays created with the Array constructor, not array literals created with the bracket syntax. arrayLength   If the only argument passed to the Array constructor is an integer between 0 and 232-1 (inclusive), this returns a new JavaScript array with length set to that number. If the argument is any other number, a RangeError exception is thrown. DescriptionArrays are list-like objects whose prototype has methods to perform traversal and mutation operations. Neither the length of a JavaScript array nor the types of its elements are fixed. Since an array’s size length grow or shrink at any time, JavaScript arrays are not guaranteed to be dense. In general, these are convenient characteristics; but if these features are not desirable for your particular use, you might consider using typed arrays. Some people think that you shouldn’t use an array as an associative array. In any case, you can use plain objects instead, although doing so comes with its own caveats. See the post Lightweight JavaScript dictionaries with arbitrary keys as an example. Accessing array elements JavaScript arrays are zero-indexed: the first element of an array is at index 0, and the last element is at the index equal to the value of the array’s length property minus 1. 1234var arr = ['this is the first element', 'this is the second element'];console.log(arr[0]); // logs 'this is the first element'console.log(arr[1]); // logs 'this is the second element'console.log(arr[arr.length - 1]); // logs 'this is the second element' Array elements are object properties in the same way that toString is a property, but trying to access an element of an array as follows throws a syntax error, because the property name is not valid: 1console.log(arr.0); // a syntax error There is nothing special about JavaScript arrays and the properties that cause this. JavaScript properties that begin with a digit cannot be referenced with dot notation; and must be accessed using bracket notation. For example, if you had an object with a property named ‘3d’, it can only be referenced using bracket notation. E.g.: 12345var years = [1950, 1960, 1970, 1980, 1990, 2000, 2010];console.log(years.0); // a syntax errorconsole.log(years[0]); // works properlyrenderer.3d.setTexture(model, 'character.png'); // a syntax errorrenderer['3d'].setTexture(model, 'character.png'); // works properly Note that in the 3d example, ‘3d’ had to be quoted. It’s possible to quote the JavaScript array indexes as well (e.g., years[‘2’] instead of years2), although it’s not necessary. The 2 in years2 is coerced into a string by the JavaScript engine through an implicit toString conversion. It is for this reason that ‘2’ and ‘02’ would refer to two different slots on the years object and the following example could be true: 1console.log(years['2'] != years['02']); Similarly, object properties which happen to be reserved words(!) can only be accessed as string literals in bracket notation(but it can be accessed by dot notation in firefox 40.0a2 at least): 12345var promise = { 'var' : 'text', 'array': [1, 2, 3, 4]};console.log(promise['array']); Relationship between length and numerical properties A JavaScript array’s length property and numerical properties are connected. Several of the built-in array methods (e.g., join, slice, indexOf, etc.) take into account the value of an array’s length property when they’re called. Other methods (e.g., push, splice, etc.) also result in updates to an array’s length property. 1234var fruits = [];fruits.push('banana', 'apple', 'peach');console.log(fruits.length); // 3 When setting a property on a JavaScript array when the property is a valid array index and that index is outside the current bounds of the array, the engine will update the array’s length property accordingly: 1234fruits[5] = 'mango';console.log(fruits[5]); // 'mango'console.log(Object.keys(fruits)); // ['0', '1', '2', '5']console.log(fruits.length); // 6 Increasing the length. 123fruits.length = 10;console.log(Object.keys(fruits)); // ['0', '1', '2', '5']console.log(fruits.length); // 10 Decreasing the length property does, however, delete elements. 123fruits.length = 2;console.log(Object.keys(fruits)); // ['0', '1']console.log(fruits.length); // 2 This is explained further on the Array.length page. Creating an array using the result of a match The result of a match between a regular expression and a string can create a JavaScript array. This array has properties and elements which provide information about the match. Such an array is returned by RegExp.exec, String.match, and String.replace. To help explain these properties and elements, look at the following example and then refer to the table below: 123456// Match one d followed by one or more b's followed by one d// Remember matched b's and the following d// Ignore casevar myRe = /d(b+)(d)/i;var myArray = myRe.exec('cdbBdbsbz'); The properties and elements returned from this match are as follows: Property/Element Description Example input A read-only property that reflects the original string against which the regular expression was matched. cdbBdbsbz index A read-only property that is the zero-based index of the match in the string. 1 [0] A read-only element that specifies the last matched characters. dbBd [1], …[n] Read-only elements that specify the parenthesized substring matches, if included in the regular expression. The number of possible parenthesized substrings is unlimited. [1]: bB[2]: d PropertiesFor properties available on Array instances, see Properties of Array instances. Array.length   The Array constructor’s length property whose value is 1. Array.prototype   Allows the addition of properties to all array objects. MethodsFor methods available on Array instances, see Methods of Array instances. Array.from()   Creates a new Array instance from an array-like or iterable object. Array.isArray()   Returns true if a variable is an array, if not false. Array.observe()   Asynchronously observes changes to Arrays, similar to Object.observe() for objects. It provides a stream of changes in order of occurrence. Array.of()   Creates a new Array instance with a variable number of arguments, regardless of number or type of the arguments. Array instancesAll Array instances inherit from Array.prototype. The prototype object of the Array constructor can be modified to affect all Array instances. PropertiesArray.prototype.constructor   Specifies the function that creates an object’s prototype. Array.prototype.length   Reflects the number of elements in an array. MethodsMutator methodsThese methods modify the array: Array.prototype.copyWithin()   Copies a sequence of array elements within the array. Array.prototype.fill()   Fills all the elements of an array from a start index to an end index with a static value. Array.prototype.pop()   Removes the last element from an array and returns that element. Array.prototype.push()   Adds one or more elements to the end of an array and returns the new length of the array. Array.prototype.reverse()   Reverses the order of the elements of an array in place — the first becomes the last, and the last becomes the first. Array.prototype.shift()   Removes the first element from an array and returns that element. Array.prototype.sort()   Sorts the elements of an array in place and returns the array. Array.prototype.splice()   Adds and/or removes elements from an array. Array.prototype.unshift()   Adds one or more elements to the front of an array and returns the new length of the array. Accessor methodsThese methods do not modify the array and return some representation of the array. Array.prototype.concat()   Returns a new array comprised of this array joined with other array(s) and/or value(s). Array.prototype.includes()   Determines whether an array contains a certain element, returning true or false as appropriate. Array.prototype.join()   Joins all elements of an array into a string. Array.prototype.slice()   Extracts a section of an array and returns a new array. Array.prototype.toSource()   Returns an array literal representing the specified array; you can use this value to create a new array. Overrides the Object.prototype.toSource() method. Array.prototype.toString()   Returns a string representing the array and its elements. Overrides the Object.prototype.toString() method. Array.prototype.toLocaleString()   Returns a localized string representing the array and its elements. Overrides the Object.prototype.toLocaleString() method. Array.prototype.indexOf()   Returns the first (least) index of an element within the array equal to the specified value, or -1 if none is found. Array.prototype.lastIndexOf()   Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. Iteration methodsSeveral methods take as arguments functions to be called back while processing the array. When these methods are called, the length of the array is sampled, and any element added beyond this length from within the callback is not visited. Other changes to the array (setting the value of or deleting an element) may affect the results of the operation if the method visits the changed element afterwards. While the specific behavior of these methods in such cases is well-defined, you should not rely upon it so as not to confuse others who might read your code. If you must mutate the array, copy into a new array instead. Array.prototype.forEach()   Calls a function for each element in the array. Array.prototype.entries()   Returns a new Array Iterator object that contains the key/value pairs for each index in the array. Array.prototype.every()   Returns true if every element in this array satisfies the provided testing function. Array.prototype.some()   Returns true if at least one element in this array satisfies the provided testing function. Array.prototype.filter()   Creates a new array with all of the elements of this array for which the provided filtering function returns true. Array.prototype.find()   Returns the found value in the array, if an element in the array satisfies the provided testing function or undefined if not found. Array.prototype.findIndex()   Returns the found index in the array, if an element in the array satisfies the provided testing function or -1 if not found. Array.prototype.keys()   Returns a new Array Iterator that contains the keys for each index in the array. Array.prototype.map()   Creates a new array with the results of calling a provided function on every element in this array. Array.prototype.reduce()   Apply a function against an accumulator and each value of the array (from left-to-right) as to reduce it to a single value. Array.prototype.reduceRight()   Apply a function against an accumulator and each value of the array (from right-to-left) as to reduce it to a single value. Array.prototype.values()   Returns a new Array Iterator object that contains the values for each index in the array. Array.prototype[@@iterator]()   Returns a new Array Iterator object that contains the values for each index in the array. Array generic methods>Array generics are non-standard, deprecated and might get removed in the future. Note that you can not rely on them cross-browser. However, there is a shim available on GitHub. Sometimes you would like to apply array methods to strings or other array-like objects (such as function arguments). By doing this, you treat a string as an array of characters (or otherwise treat a non-array as an array). For example, in order to check that every character in the variable str is a letter, you would write:1234567function isLetter(character) { return character >= 'a' && character <= 'z';}if (Array.prototype.every.call(str, isLetter)) { console.log("The string '" + str + "' contains only letters!");} This notation is rather wasteful and JavaScript 1.6 introduced a generic shorthand: 123if (Array.every(str, isLetter)) { console.log("The string '" + str + "' contains only letters!");} Generics are also available on String. These are currently not part of ECMAScript standards (though the ES6 Array.from() can be used to achieve this). The following is a shim to allow its use in all browsers: 123456789101112131415161718192021222324252627282930313233// Assumes Array extras already present (one may use polyfills for these as well)(function() { 'use strict'; var i, // We could also build the array of methods with the following, but the // getOwnPropertyNames() method is non-shimable: // Object.getOwnPropertyNames(Array).filter(function(methodName) { // return typeof Array[methodName] === 'function' // }); methods = [ 'join', 'reverse', 'sort', 'push', 'pop', 'shift', 'unshift', 'splice', 'concat', 'slice', 'indexOf', 'lastIndexOf', 'forEach', 'map', 'reduce', 'reduceRight', 'filter', 'some', 'every', 'find', 'findIndex', 'entries', 'keys', 'values', 'copyWithin', 'includes' ], methodCount = methods.length, assignArrayGeneric = function(methodName) { if (!Array[methodName]) { var method = Array.prototype[methodName]; if (typeof method === 'function') { Array[methodName] = function() { return method.call.apply(method, arguments); }; } } }; for (i = 0; i < methodCount; i++) { assignArrayGeneric(methods[i]); }}()); ExamplesCreating an arrayThe following example creates an array, msgArray, with a length of 0, then assigns values to msgArray[0] and msgArray[99], changing the length of the array to 100. 1234567var msgArray = [];msgArray[0] = 'Hello';msgArray[99] = 'world';if (msgArray.length === 100) { console.log('The length is 100.');} Creating a two-dimensional arrayThe following creates a chess board as a two dimensional array of strings. The first move is made by copying the ‘p’ in (6,4) to (4,4). The old position (6,4) is made blank.12345678910111213141516var board = [ ['R','N','B','Q','K','B','N','R'], ['P','P','P','P','P','P','P','P'], [' ',' ',' ',' ',' ',' ',' ',' '], [' ',' ',' ',' ',' ',' ',' ',' '], [' ',' ',' ',' ',' ',' ',' ',' '], [' ',' ',' ',' ',' ',' ',' ',' '], ['p','p','p','p','p','p','p','p'], ['r','n','b','q','k','b','n','r'] ];console.log(board.join('\n') + '\n\n');// Move King's Pawn forward 2board[4][4] = board[6][4];board[6][4] = ' ';console.log(board.join('\n')); Here is the output: 1234567891011121314151617R,N,B,Q,K,B,N,RP,P,P,P,P,P,P,P , , , , , , , , , , , , , , , , , , , , , , , , , , , ,p,p,p,p,p,p,p,pr,n,b,q,k,b,n,rR,N,B,Q,K,B,N,RP,P,P,P,P,P,P,P , , , , , , , , , , , , , , , , , ,p, , , , , , , , , ,p,p,p,p, ,p,p,pr,n,b,q,k,b,n,r Specifications Specification Status Comment ECMAScript 1st Edition (ECMA-262) Standard Initial definition. ECMAScript 5.1 (ECMA-262) The definition of ‘Array’ in that specification. Standard New methods added: Array.isArray, indexOf, lastIndexOf, every, some, forEach, map, filter, reduce, reduceRight ECMAScript 2015 (6th Edition, ECMA-262) The definition of ‘Array’ in that specification. Standard New methods added: Array.from, Array.of, find, findIndex, fill, copyWithin Browser compatibilityDesktop>|Feature | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari||:——-:|:——-:|:——-:|:——-:|:——-:|:——-:||Basic support | (Yes) | (Yes) | (Yes) | (Yes) | (Yes)| Mobile>|Feature | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile ||:——-:|:——-:|:——-:|:——-:|:——-:|:——-:|:——-:||Basic support | (Yes) | (Yes) | (Yes) | (Yes) | (Yes)| (Yes) | See also JavaScript Guide: “Indexing object properties JavaScript Guide: “Predefined Core Objects: Array Object” Array comprehensions Polyfill for JavaScript 1.8.5 Array Generics and ECMAScript 5 Array Extras Typed Arrays]]></content>
<categories>
<category>翻译</category>
<category>Web开发</category>
</categories>
<tags>
<tag>JavaScript</tag>
<tag>Array</tag>
</tags>
</entry>
<entry>
<title><![CDATA[git提示warning: LF will be replaced by CRLF]]></title>
<url>%2F2015%2F09%2F17%2Fgit%E6%8F%90%E7%A4%BAwarning-LF-will-be-replaced-by-CRLF%2F</url>
<content type="text"><![CDATA[问题描述: 执行git add .指令,命令行出现如下错误: 12warning: LF will be replaced by CRLF in nodejs-in-action/yeoman/mytodo/.editorconfig.The file will have its original line endings in your working directory. 原因分析: CRLF(Carriage-Return Line-Feed)回车换行就是回车(CR, ASCII 13, \r) 换行(LF, ASCII 10, \n)。 这两个ACSII字符不会在屏幕有任何输出,但在Windows中广泛使用来标识一行的结束。而在Linux/UNIX系统中只有换行符。也就是说在windows中的换行符为 CRLF, 而在linux下的换行符为:LF 使用git提交更改时,文件中的换行符为LF, 当执行git add .时,系统提示:LF 将被转换成 CRLF 解决方法: 1$ git config --global core.autocrlf false 这样系统就不会去进行换行符的转换了,最后重新执行 1$ git add . 系统即可正常运行!]]></content>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Windows7升级git到2.5版本后,hexo无法发布文章]]></title>
<url>%2F2015%2F09%2F17%2Fhexo%E5%8F%91%E5%B8%83%E5%86%85%E5%AE%B9%E6%97%B6%E6%8F%90%E7%A4%BANo-such-deive-or-address%E9%94%99%E8%AF%AF%2F</url>
<content type="text"><![CDATA[Windows7,系统升级git最新版后 12> git --version> git version 2.5.2.windows.2 hexo d -g无法发布文章,出现如下错误:123456789101112131415161718On branch masternothing to commit, working directory cleanbash: /dev/tty: No such device or addresserror: failed to execute prompt script (exit code 1)fatal: could not read Username for 'https://github.com': Invalid argumentFATAL Something's wrong. Maybe you can find the solution here: http://hexo.io/docs/troubleshooting.htmlError: bash: /dev/tty: No such device or addresserror: failed to execute prompt script (exit code 1)fatal: could not read Username for 'https://github.com': Invalid argument at ChildProcess.<anonymous> (E:\BFL\workspaces\blog\node_modules\hexo-deployer-git\node_modules\hexo-util\lib\spawn.js:42:17) at emitTwo (events.js:87:13) at ChildProcess.emit (events.js:172:7) at maybeClose (internal/child_process.js:817:16) at Socket.<anonymous> (internal/child_process.js:319:11) at emitOne (events.js:77:13) at Socket.emit (events.js:169:7) at Pipe._onclose (net.js:469:12) 后来重新安装git老版本后,问题才得以解决 12git --versiongit version 1.9.5.msysgit.0]]></content>
<tags>
<tag>Git</tag>
<tag>Hexo</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Error: fatal: Unable to find remote helper for 'https']]></title>
<url>%2F2015%2F09%2F17%2FError-fatal-Unable-to-find-remote-helper-for-https%2F</url>
<content type="text"><![CDATA[执行命令hexo d -g发布文章时,报错: 1234567891011On branch masternothing to commit, working directory cleanfatal: Unable to find remote helper for 'https'FATAL Something's wrong. Maybe you can find the solution here: http://hexo.io/docs/troubleshooting.htmlError: fatal: Unable to find remote helper for 'https' at ChildProcess.<anonymous> (E:\BFL\workspaces\blog\node_modules\hexo-deployer-git\node_modules\hexo-util\lib\spawn.js:42:17) at emitTwo (events.js:87:13) at ChildProcess.emit (events.js:172:7) at maybeClose (internal/child_process.js:817:16) at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5) 解决办法:将原来环境变量PATH中配置的git安装目录<GIT_INSTALL_DIR>或者:<GIT_INSTALL_DIR>\bin,修改为<GIT_INSTALL_DIR>\cmd]]></content>
<categories>
<category>博客</category>
</categories>
<tags>
<tag>Git</tag>
<tag>Hexo</tag>
</tags>
</entry>
<entry>
<title><![CDATA[win8中让cmd.exe始终以管理员身份运行]]></title>
<url>%2F2015%2F09%2F17%2Fwin8%E4%B8%AD%E8%AE%A9cmd-exe%E5%A7%8B%E7%BB%88%E4%BB%A5%E7%AE%A1%E7%90%86%E5%91%98%E8%BA%AB%E4%BB%BD%E8%BF%90%E8%A1%8C%2F</url>
<content type="text"><![CDATA[通过一下方法可以让cmd.exe(或者其他程序)以管理员身份来运行: 方法一: Win+R – regedit 找到以下位置HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers 新建一个字符串值,命名为C:\Windows\System32\cmd.exe 然后右键–修改 – 数值数据写入“RUNASADMIN”,确定 方法二:1234Windows Registry Editor Version 5.00[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers]"C:\\Windows\\System32\\cmd.exe"="RUNASADMIN" 打开记事本,复制粘贴入以上代码,另存为runas.reg,然后双击导入注册表即可。]]></content>
<categories>
<category>随笔</category>
</categories>
<tags>
<tag>随笔</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Updating Maven Project, Unsupported IClasspathEntry kind=4]]></title>
<url>%2F2015%2F09%2F16%2FUpdating-Maven-Project-Unsupported-IClasspathEntry-kind-4%2F</url>
<content type="text"><![CDATA[Eclipse项目上鼠标右键,选择Maven,禁用’Maven Nature’ 在项目目录中,cmd窗口运行mvn eclipse:clean命令 Eclipse项目,启用“Maven Nature”,右键选择’Configure’-> ‘Convert to Maven Project’]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Maven</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Maven常用命令]]></title>
<url>%2F2015%2F09%2F16%2FMaven%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%2F</url>
<content type="text"><![CDATA[Maven库:http://repo2.maven.org/maven2/ Maven依赖查询:http://mvnrepository.com/ Maven常用命令: 创建Maven的普通java项目: 1mvn archetype:create -DgroupId=packageName -DartifactId=projectName 创建Maven的Web项目: 1234mvn archetype:create-DgroupId=packageName-DartifactId=webappName-DarchetypeArtifactId=maven-archetype-webapp 编译源代码:mvn compile 编译测试代码:mvn test-compile 运行测试:mvn test 产生site:mvn site 打包:mvn package 在本地Repository中安装jar:mvn install 清除产生的项目:mvn clean 生成eclipse项目:mvn eclipse:eclipse 生成idea项目:mvn idea:idea 组合使用goal命令,如只打包不测试:mvn -Dtest package 编译测试的内容:mvn test-compile 只打jar包:mvn jar:jar 只测试而不编译,也不测试编译:mvn test -skipping compile -skipping test-compile( -skipping 的灵活运用,当然也可以用于其他组合命令) 清除eclipse的一些系统设置:mvn eclipse:clean 注意: 一般使用情况是这样,首先通过cvs或svn下载代码到本机,然后执行mvn eclipse:eclipse生成ecllipse项目文件,然后导入到eclipse就行了;修改代码后执行mvn compile或mvn test检验,也可以下载eclipse的maven插件。1234567891011121314151617181920212223242526272829303132333435363738394041mvn -version/-v 显示版本信息mvn archetype:generate 创建mvn项目mvn archetype:create -DgroupId=com.example -DartifactId=myApp 创建mvn项目mvn archetype:create -DgroupId=com.example -DartifactId=myApp -DpackageName=org.example 创建Maven的普通java项目,在命令行使用Maven Archetype 插件mvn package 生成target目录,编译、测试代码,生成测试报告,生成jar/war文件mvn jetty:run 运行项目于jetty上,mvn compile 编译mvn test 编译并测试mvn clean 清空生成的文件mvn clean install 删除再编译mvn site 生成项目相关信息的网站mvn -Dwtpversion=1.0 eclipse:eclipse 生成Wtp插件的Web项目mvn -Dwtpversion=1.0 eclipse:clean 清除Eclipse项目的配置信息(Web项目)mvn eclipse:eclipse 将项目转化为Eclipse项目mvn help:describe -Dplugin=help 使用 help 插件的 describe 目标来输出 Maven Help 插件的信息。mvn help:describe -Dplugin=help -Dfull 使用Help 插件输出完整的带有参数的目标列mvn help:describe -Dplugin=compiler -Dmojo=compile -Dfull 获取单个目标的信息,设置 mojo 参数和 plugin 参数。此命令列出了Compiler 插件的compile 目标的所有信息mvn help:describe -Dplugin=exec -Dfull 列出所有 Maven Exec 插件可用的目标mvn help:effective-pom 看这个“有效的 (effective)”POM,它暴露了 Maven的默认设置mvn exec:java -Dexec.mainClass=com.example.Main Exec 插件让我们能够在不往 classpath 载入适当的依赖的情况下,运行这个程序mvn dependency:resolve 打印出已解决依赖的列表mvn dependency:tree 打印整个依赖树mvn install -X 想要查看完整的依赖踪迹,包含那些因为冲突或者其它原因而被拒绝引入的构件,打开 Maven 的调试标记运行mvn install -Dmaven.test.skip=true 给任何目标添加maven.test.skip 属性就能跳过测试mvn install assembly:assembly 构建装配Maven Assembly 插件是一个用来创建你应用程序特有分发包的插件mvn jetty:run 调用 Jetty 插件的 Run 目标在 Jetty Servlet 容器中启动 web 应用mvn hibernate3:hbm2ddl 使用 Hibernate3 插件构造数据库mvn -e 显示详细错误 信息.mvn validate 验证工程是否正确,所有需要的资源是否可用。mvn test-compile 编译项目测试代码mvn integration-test 在集成测试可以运行的环境中处理和发布包。mvn verify 运行任何检查,验证包是否有效且达到质量标准。mvn generate-sources 产生应用需要的任何额外的源代码,如xdoclet。 在应用程序用使用多个存储库123456789101112<repositories> <repository> <id>Ibiblio</id> <name>Ibiblio</name> <url>http://www.ibiblio.org/maven/</url> </repository> <repository> <id>PlanetMirror</id> <name>Planet Mirror</name> <url>http://public.planetmirror.com/pub/maven/</url> </repository></repositories> 1mvn deploy:deploy-file -DgroupId=com.example -DartifactId=myApp -Dversion=0.1.0 -Dpackaging=jar -Dfile=d:\myApp-0.1.0.jar -DrepositoryId=maven-repository-inner -Durl=ftp://xxxxxxx/opt/maven/repository/ 发布第三方Jar到本地库中:1mvn install:install-file -DgroupId=com.example -DartifactId=myApp -Dversion=0.1.0 -Dpackaging=jar -Dfile=d:\myApp-0.1.0.jar -DdownloadSources=true -DdownloadJavadocs=true]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Java</tag>
<tag>Maven</tag>
</tags>
</entry>
<entry>
<title><![CDATA[40个Java集合面试问题和答案]]></title>
<url>%2F2015%2F09%2F16%2F40%E4%B8%AAJava%E9%9B%86%E5%90%88%E9%9D%A2%E8%AF%95%E9%97%AE%E9%A2%98%E5%92%8C%E7%AD%94%E6%A1%88%2F</url>
<content type="text"><![CDATA[译文出处: Sanesee 原文出处:javacodegeeks Java集合框架是什么?说出一些集合框架的优点? 每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector、Stack、HashTable和Array。随着集合的广泛使用,Java1.2提出了囊括所有集合接口、实现和算法的集合框架。在保证线程安全的情况下使用泛型和并发集合类,Java已经经历了很久。它还包括在Java并发包中,阻塞接口以及它们的实现。集合框架的部分优点如下: 使用核心集合类降低开发成本,而非实现我们自己的集合类。 随着使用经过严格测试的集合框架类,代码质量会得到提高。 通过使用JDK附带的集合类,可以降低代码维护成本。 复用性和可操作性。 集合框架中的泛型有什么优点? Java1.5引入了泛型,所有的集合接口和实现都大量地使用它。泛型允许我们为集合提供一个可以容纳的对象类型,因此,如果你添加其它类型的任何元素,它会在编译时报错。这避免了在运行时出现ClassCastException,因为你将会在编译时得到报错信息。泛型也使得代码整洁,我们不需要使用显式转换和instanceOf操作符。它也给运行时带来好处,因为不会产生类型检查的字节码指令。 Java集合框架的基础接口有哪些? Collection为集合层级的根接口。一个集合代表一组对象,这些对象即为它的元素。Java平台不提供这个接口任何直接的实现。 Set是一个不能包含重复元素的集合。这个接口对数学集合抽象进行建模,被用来代表集合,就如一副牌。 List是一个有序集合,可以包含重复元素。你可以通过它的索引来访问任何元素。List更像长度动态变换的数组。 Map是一个将key映射到value的对象.一个Map不能包含重复的key:每个key最多只能映射一个value。 一些其它的接口有Queue、Dequeue、SortedSet、SortedMap和ListIterator。 为何Collection不从Cloneable和Serializable接口继承? Collection接口指定一组对象,对象即为它的元素。如何维护这些元素由Collection的具体实现决定。例如,一些如List的Collection实现允许重复的元素,而其它的如Set就不允许。很多Collection实现有一个公有的clone方法。然而,把它放到集合的所有实现中也是没有意义的。这是因为Collection是一个抽象表现。重要的是实现。 当与具体实现打交道的时候,克隆或序列化的语义和含义才发挥作用。所以,具体实现应该决定如何对它进行克隆或序列化,或它是否可以被克隆或序列化。 在所有的实现中授权克隆和序列化,最终导致更少的灵活性和更多的限制。特定的实现应该决定它是否可以被克隆和序列化。 为何Map接口不继承Collection接口? 尽管Map接口和它的实现也是集合框架的一部分,但Map不是集合,集合也不是Map。因此,Map继承Collection毫无意义,反之亦然。 如果Map继承Collection接口,那么元素去哪儿?Map包含key-value对,它提供抽取key或value列表集合的方法,但是它不适合“一组对象”规范。 Iterator是什么? Iterator接口提供遍历任何Collection的接口。我们可以从一个Collection中使用迭代器方法来获取迭代器实例。迭代器取代了Java集合框架中的Enumeration。迭代器允许调用者在迭代过程中移除元素。 Enumeration和Iterator接口的区别? Enumeration的速度是Iterator的两倍,也使用更少的内存。Enumeration是非常基础的,也满足了基础的需要。但是,与Enumeration相比,Iterator更加安全,因为当一个集合正在被遍历的时候,它会阻止其它线程去修改集合。 迭代器取代了Java集合框架中的Enumeration。迭代器允许调用者从集合中移除元素,而Enumeration不能做到。为了使它的功能更加清晰,迭代器方法名已经经过改善。 为何没有像Iterator.add()这样的方法,向集合中添加元素? 语义不明,已知的是,Iterator的协议不能确保迭代的次序。然而要注意,ListIterator没有提供一个add操作,它要确保迭代的顺序。 为何迭代器没有一个方法可以直接获取下一个元素,而不需要移动游标? 它可以在当前Iterator的顶层实现,但是它用得很少,如果将它加到接口中,每个继承都要去实现它,这没有意义。 Iterater和ListIterator之间有什么区别? 我们可以使用Iterator来遍历Set和List集合,而ListIterator只能遍历List。 Iterator只可以向前遍历,而LIstIterator可以双向遍历。 ListIterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。 遍历一个List有哪些不同的方式? 1234567891011List<String> strList = new ArrayList<>();//使用for-each循环for(String obj : strList){ System.out.println(obj);}//using iteratorIterator<String> it = strList.iterator();while(it.hasNext()){ String obj = it.next(); System.out.println(obj);} 使用迭代器更加线程安全,因为它可以确保,在当前遍历的集合元素被更改的时候,它会抛出ConcurrentModificationException。 通过迭代器fail-fast属性,你明白了什么? 每次我们尝试获取下一个元素的时候,Iterator fail-fast属性检查当前集合结构里的任何改动。如果发现任何改动,它抛出ConcurrentModificationException。Collection中所有Iterator的实现都是按fail-fast来设计的(ConcurrentHashMap和CopyOnWriteArrayList这类并发集合类除外)。 fail-fast与fail-safe有什么区别? Iterator的fail-fast属性与当前的集合共同起作用,因此它不会受到集合中任何改动的影响。Java.util包中的所有集合类都被设计为fail-fast的,而java.util.concurrent中的集合类都为fail-safe的。Fail-fast迭代器抛出ConcurrentModificationException,而fail-safe迭代器从不抛出ConcurrentModificationException。 在迭代一个集合的时候,如何避免ConcurrentModificationException? 在遍历一个集合的时候,我们可以使用并发集合类来避免ConcurrentModificationException,比如使用CopyOnWriteArrayList,而不是ArrayList。 为何Iterator接口没有具体的实现? Iterator接口定义了遍历集合的方法,但它的实现则是集合实现类的责任。每个能够返回用于遍历的Iterator的集合类都有它自己的Iterator实现内部类。 这就允许集合类去选择迭代器是fail-fast还是fail-safe的。比如,ArrayList迭代器是fail-fast的,而CopyOnWriteArrayList迭代器是fail-safe的。 UnsupportedOperationException是什么? UnsupportedOperationException是用于表明操作不支持的异常。在JDK类中已被大量运用,在集合框架java.util.Collections.UnmodifiableCollection将会在所有add和remove操作中抛出这个异常。 在Java中,HashMap是如何工作的? HashMap在Map.Entry静态内部类实现中存储key-value对。HashMap使用哈希算法,在put和get方法中,它使用hashCode()和equals()方法。当我们通过传递key-value对调用put方法的时候,HashMap使用Key hashCode()和哈希算法来找出存储key-value对的索引。Entry存储在LinkedList中,所以如果存在entry,它使用equals()方法来检查传递的key是否已经存在,如果存在,它会覆盖value,如果不存在,它会创建一个新的entry然后保存。当我们通过传递key调用get方法时,它再次使用hashCode()来找到数组中的索引,然后使用equals()方法找出正确的Entry,然后返回它的值。下面的图片解释了详细内容。 其它关于HashMap比较重要的问题是容量、负荷系数和阀值调整。HashMap默认的初始容量是32,负荷系数是0.75。阀值是为负荷系数乘以容量,无论何时我们尝试添加一个entry,如果map的大小比阀值大的时候,HashMap会对map的内容进行重新哈希,且使用更大的容量。容量总是2的幂,所以如果你知道你需要存储大量的key-value对,比如缓存从数据库里面拉取的数据,使用正确的容量和负荷系数对HashMap进行初始化是个不错的做法。 hashCode()和equals()方法有何重要性? HashMap使用Key对象的hashCode()和equals()方法去决定key-value对的索引。当我们试着从HashMap中获取值的时候,这些方法也会被用到。如果这些方法没有被正确地实现,在这种情况下,两个不同Key也许会产生相同的hashCode()和equals()输出,HashMap将会认为它们是相同的,然后覆盖它们,而非把它们存储到不同的地方。同样的,所有不允许存储重复数据的集合类都使用hashCode()和equals()去查找重复,所以正确实现它们非常重要。equals()和hashCode()的实现应该遵循以下规则: 如果o1.equals(o2),那么o1.hashCode() == o2.hashCode()总是为true的。 如果o1.hashCode() == o2.hashCode(),并不意味着o1.equals(o2)会为true。 我们能否使用任何类作为Map的key? 我们可以使用任何类作为Map的key,然而在使用它们之前,需要考虑以下几点: 如果类重写了equals()方法,它也应该重写hashCode()方法。 类的所有实例需要遵循与equals()和hashCode()相关的规则。请参考之前提到的这些规则。 如果一个类没有使用equals(),你不应该在hashCode()中使用它。 用户自定义key类的最佳实践是使之为不可变的,这样,hashCode()值可以被缓存起来,拥有更好的性能。不可变的类也可以确保hashCode()和equals()在未来不会改变,这样就会解决与可变相关的问题了。 比如,我有一个类MyKey,在HashMap中使用它。 1234567//传递给MyKey的name参数被用于equals()和hashCode()中MyKey key = new MyKey('Pankaj'); //assume hashCode=1234myHashMap.put(key, 'Value');// 以下的代码会改变key的hashCode()和equals()值key.setName('Amit'); //assume new hashCode=7890//下面会返回null,因为HashMap会尝试查找存储同样索引的key,而key已被改变了,匹配失败,返回nullmyHashMap.get(new MyKey('Pankaj')); 那就是为何String和Integer被作为HashMap的key大量使用。 Map接口提供了哪些不同的集合视图? Map接口提供三个集合视图: Set keyset():返回map中包含的所有key的一个Set视图。集合是受map支持的,map的变化会在集合中反映出来,反之亦然。当一个迭代器正在遍历一个集合时,若map被修改了(除迭代器自身的移除操作以外),迭代器的结果会变为未定义。集合支持通过Iterator的Remove、Set.remove、removeAll、retainAll和clear操作进行元素移除,从map中移除对应的映射。它不支持add和addAll操作。 Collection values():返回一个map中包含的所有value的一个Collection视图。这个collection受map支持的,map的变化会在collection中反映出来,反之亦然。当一个迭代器正在遍历一个collection时,若map被修改了(除迭代器自身的移除操作以外),迭代器的结果会变为未定义。集合支持通过Iterator的Remove、Set.remove、removeAll、retainAll和clear操作进行元素移除,从map中移除对应的映射。它不支持add和addAll操作。 Set]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Java 8新特性之旅:使用Stream API处理集合]]></title>
<url>%2F2015%2F09%2F16%2FJava-8%E6%96%B0%E7%89%B9%E6%80%A7%E4%B9%8B%E6%97%85%EF%BC%9A%E4%BD%BF%E7%94%A8Stream-API%E5%A4%84%E7%90%86%E9%9B%86%E5%90%88%2F</url>
<content type="text"><![CDATA[在这篇“Java 8新特性教程”系列文章中,我们会深入解释,并通过代码来展示,如何通过流来遍历集合,如何从集合和数组来创建流,以及怎么聚合流的值。 在之前的文章“遍历、过滤、处理集合及使用Lambda表达式增强方法”中,我已经深入解释并演示了通过lambda表达式和方法引用来遍历集合,使用predicate接口来过滤集合,实现接口的默认方法,最后还演示了接口静态方法的实现。 源代码都在我的Github上:可以从这里克隆。 内容列表 使用流来遍历集合。 从集合或数组创建流。 聚合流中的值。 1. 使用流来遍历集合 简介: Java的集合框架,如List和Map接口及Arraylist和HashMap类,让我们很容易地管理有序和无序集合。集合框架自引入的第一天起就在 持续的改进。在Java SE 8中,我们可以通过流的API来管理、遍历和聚合集合。一个基于流的集合与输入输出流是不同的。 如何工作? 它采用一种全新的方式,将数据作为一个整体,而不是单独的个体来处理。当你使用流时,你不需要关心循环或遍历的细节。你可以直接从一个集合创建一个流。然 后你就能用这个流来许多事件了,如遍历、过滤及聚和。我将从项目 Java8Features 的 com.tm.java8.features.stream.traversing包下的例子开始。代码在一个SequentialStream类中,Java SE 8 中有两种集合流,即串行流和并行流。 123456789101112131415161718192021List<person> people = new ArrayList<>();people.add(new Person("Mohamed", 69));people.add(new Person("Doaa", 25));people.add(new Person("Malik", 6));Predicate<person> pred = (p) -> p.getAge() > 65;displayPeople(people, pred);...........private static void displayPeople(List<person> people, Predicate<person> pred) { System.out.println("Selected:"); people.forEach(p -> { if (pred.test(p)) { System.out.println(p.getName()); } });} 在这两种流中,串行流相对比较简单,它类似一个迭代器,每次处理集合中的一个元素。但是语法与以前不同。在这段代码中,我创建了 pepole 的数组列表,向上转型为List。它包含三个 Person 类的实例。然后我们使用 Predicate 声明一个条件,只有满足这个条件的 people 才会显示。在 displayPeople() 方法的48到52行循环遍历该集合,挨个测试其中的每一项。运行这段代码,你将获得如下的结果: 12Selected:Mohamed 我将会展示如何使用流来重构这段代码。首先,我注释了这段代码。然后,在这段注释的代码下,我开始使用集合对象 people。然后我调用一个 stream() 方法。一个stream对象,类似集合,也要声明泛型。如果你从一个集合获取流,则该流中每一项的类型与集合本身是一致的。我的集合是 Person 类的实例,所以流中也使用同样的泛型类型。 123456789System.out.println("Selected:"); //people.forEach(p -> { // if (pred.test(p)) { // System.out.println(p.getName()); // } //}); people.stream().forEach(p -> System.out.println(p.getName()));} 你可以调用一个stream()方法来获得了一个流对象,然后可以在该对象上进行一些操作。我简单地调用了forEach方法,该方法需要一个Lamda表达式。我在参数中传递了一个Lamda表达式。列表中的每一项就是通过迭代器处理的每一项。处理过程是通过Lambda 操作符和方法实现来完成的。我简单使用system output来输出每个人的名称。保存并运行这段代码,输出结果如下。因为没有过滤,所以输出了列表中所有元素。 1234Selected:MohamedDoaaMalik 现在,一旦有了一个流对象,就可以很容易使用predicate对象了。当使用for each方法处理每一项时,我不得不显示调用predicate的test方法,但是使用流时,你可以调用一个名为filter的方法。该方法接收一个predicate对象,所有的predicate对象都有一个test方法,所以它已经知道怎样去调用该方法。所以,我对该代码做一点改动。我将.forEach()方法下移了两行,然后在中间的空白行,我调用了filter方法。 123people.stream() .filter(pred) .forEach(p -> System.out.println(p.getName())); filter方法接收一个predicate接口的实例对象。我将predicate对象传进去。filtr方法返回一个过滤后的流对象,在这个对象上我就可以去调用forEach()方法了。我运行这段代码,这次我只显示集合中满足预定义条件的项了。你可以在 流对象上做更多的事情。去看看 Java SE 8 API 中流的doc文档吧。 12Selected:Mohamed 你将会看到除了过滤,你还可以做聚合、排序等其他的事情。在我总结这段演示之前,我想向你们展示一下串行流和并行流之前的重要区别。Java SE 8 的一个重要目标就是改善多 CPU 系统的处理能力。Java 可在运行期自动协调多个 CPU 的运行。你需要做的所有事情仅仅是将串行流转换为并行流。 从语法上讲,有两种方法来实现流的转换。我复制一份串行流类。在包视图窗口,我复制并粘贴该类,然后对它重命名,ParallelStream,打开这个 新的类。在这个版本中,删除了注释的代码。我不再需要这些注释了。现在就可以通过两种方式创建并行流。第一种方式是调用集合中的 parallelStream()方法。现在我就拥有一个可以自动分配处理器的流了。 123456private static void displayPeople(List<person> people, Predicate<person> pred) { System.out.println("Selected:"); people.parallelStream() .filter(pred) .forEach(p -> System.out.println(p.getName())); } 运行这段代码,就可以看到完全一致的结果,过滤然后返回数据。 12Selected:Mohamed 第二种创建并行流的方式。再次调用 stream() 方法,然后在 stream 方法的基础上调用 parallel() 方法,其本质上做的事情是一样的。开始是一个串行的流,然后再将其转换为并行流。但是它仍然是一个流。可以过滤,可以用之前的一样方式去处理。只是现在的 流可以分解到多个处理起来处理。 1234people.stream() .parallel() .filter(pred) .forEach(p -> System.out.println(p.getName())); 总结 现在还没有一个明确的规定来说明在什么情况下并行流优于串行流。这个依赖于数据的大小和复杂性以及硬件的处理能力。还有你运行的多 CPU 系统。我可以给你的唯一建议是测试你的应用和数据。建立一个基准的、计时的操作。然后分别使用串行流和并行流,看哪一个更适合于你。 2. 从集合或数组创建流简介 Java SE 8’s stream API 是为了帮助管理数据集合而设计的,这些对象是指集合框架中的对象,例如数组列表或哈希表。但是,你也可以直接从数组创建流。 如何工作? 在 Java8Features 项目中的eg.com.tm.java8.features.stream.creating包下,我创建了一个名为ArrayToStream的类。在这个类的main方法中,我创建了一个包含三个元素的数组。每个元素都是Person类的一个实例对象。 1234567891011public static void main(String args[]) { Person[] people = { new Person("Mohamed", 69), new Person("Doaa", 25), new Person("Malik", 6) }; for (int i = 0; i < people.length; i++) { System.out.println(people[i].getInfo()); }} 该类中为私有成员创建了setters和getters方法,以及getInfo()方法,该方法返回一个拼接的字符串。 123public String getInfo() { return name + " (" + age + ")";} 现在,如果想使用流来处理这个数组,你可能认为需要先将数组转为数组列表,然后从这个列表创建流。但是,实际上你可以有两种方式直接从数组创建流。第一方式,我不需要处理数据的那三行代码,所以先注释掉。然后,在这个下面,我声明一个流类型的对象。 Stream 是java.util.stream下的一个接口。当我按下Ctrl+Space并选取它的时候,会提示元素的泛型,这就是流管理的类型。在这里,元素的类型即为Person,与数组元素本身的类型是一致的。我将我新的流对象命名为 stream,所有的字母都是小写的。这就是第一种创建流的方法,使用流的接口,调用of()方法。注意,该方法存在两个不同版本。 第一个是需要单个对象,第二个是需要多个对象。我使用一个参数的方法,所以传递一个名为people的数组,这就是我需要做的所有事情。Stream.of()意思就是传入一个数组,然后将该数组包装在流中。现在,我就可以使用lambda表达式、过滤、方法引用等流对象的方法。我将调用流的for each方法,并传入一个lambda表达式,将当前的person对象和lambda操作符后传入后,就能获取到person对象的信息。该信息是通过对象的getInfo()方法获取到的。 1234567891011Person[] people = { new Person("Mohamed", 69), new Person("Doaa", 25), new Person("Malik", 6)};//for (int i = 0; i < people.length; i++) {// System.out.println(people[i].getInfo());//}Stream<Person> stream = Stream.of(people);stream.forEach(p -> System.out.println(p.getInfo())); 保存并运行这段代码,就可获取到结果。输出的元素的顺序与我放入的顺序是一致的。这就是第一种方式:使用Stream.of()方法。 123Mohamed (69)Doaa (25)Malik (6) 另一种方式与上面的方式实际上是相同的。复制上面的代码,并注释掉第一种方式。这次不使用Stream.of()方法,我们使用名为Arrays的类,该类位于java.util包下。在这个类上,可以调用名为stream的方法。注意,stream方法可以包装各种类型的数组,包括基本类型和复合类型。 123//Stream<person> stream = Stream.of(people);Stream<person> stream = Arrays.stream(people);stream.forEach(p -> System.out.println(p.getInfo())); 保存并运行上面的代码,流完成的事情与之前实质上是一致的。 123Mohamed (69)Doaa (25)Malik (6) 结论 所以,无论是Stream.of()还是Arrays.stream(),所做的事情实质上是一样的。都是从一个基本类型或者复合对象类型的数组转换为流对象,然后就可以使用 lambda 表达式、过滤、方法引用等功能了。 3. 聚合流的值简介 之前,我已经描述过怎么使用一个流来迭代一个集合。你也可以使用流来聚合集合中的每一项。如计算总和、平均值、总数等等。当你做这些操作的时候,弄明白并行流特性就非常重要。 如何工作? 我会在 Java8Features 项目的eg.com.tm.java8.features.stream.aggregating包下进行演示。首先我们使用ParallelStreams类。在这个类的main方法中,我创建了一个包含字符串元素的数组列表。我简单地使用循环在列表中添加了10000个元素。然后在35和36行,我创建了一个流对象,并通过for each方法挨个输出流中每一项。 12345678910public static void main(String args[]) { System.out.println("Creating list"); List<string> strings = new ArrayList<>(); for (int i = 0; i < 10000; i++) { strings.add("Item " + i); } strings.stream() .forEach(str -> System.out.println(str));} 运行这段代码后,就获得了一个我所预期的结果。在屏幕上输出的顺序与添加到列表中的顺序是一致的。 12345678910111213141516171819.........Item 9982Item 9983Item 9984Item 9985Item 9986Item 9987Item 9988Item 9989Item 9990Item 9991Item 9992Item 9993Item 9994Item 9995Item 9996Item 9997Item 9998Item 9999 现在,让我们看一下当转换成并行流后会发生什么。正如我之前所描述的,我即可以调用parallelStream方法,也可以在流上调用parallel方法。 我将采用第二种方法。现在,我就可以使用并行流了,该流可以根据负载分配到多个处理器来处理。 123strings.stream() .parallel() .forEach(str -> System.out.println(str)); 再次运行该段代码,然后观察会发生什么。注意,现在最后打印的元素不是列表中最后一个元素,最后一个元素应该是9999。如果我滚动输出结果,就能发现处理过程以某种方式在循环跳动。这是因为在运行时将数据划分成了多个块。 123456789101112131415161718192021.........Item 5292Item 5293Item 5294Item 5295Item 5296Item 5297Item 5298Item 5299Item 5300Item 5301Item 5302Item 5303Item 5304Item 5305Item 5306Item 5307Item 5308Item 5309Item 5310Item 5311 然后,将数据块分配给合适的处理器去处理。只有当所有块都处理完成了,才会执行之后的代码。本质上讲,这是在调用forEach()方法时,将整个过程是根据需要来进行划分了。现在,这么做可能会提高性能,也可能不会。这依赖于数据集的大小以及你硬件的性能。通过这个例子,也可以看 出,如果需要按照添加的顺序挨个处理每一项,那么并行流可能就不合适了。 串行流能保证每次运行的顺序是一致的。但并行流,从定义上讲,是一种更有效率的方式。所以并行流在聚合操作的时候非常有效。很适合将集合作为一个整体考虑,然后在该集合上进行一些聚合操作的情况。我将会通过一个例子来演示集合元素的计数、求平均值及求和操作。 我们在这个类的main方法中来计数,开始还是用相同的基础代码。创建10,000个字符串的列表。然后通过一个for each方法循环处理每一项。 12345678910public static void main(String args[]) { System.out.println("Creating list"); List<string> strings = new ArrayList<>(); for (int i = 0; i < 10000; i++) { strings.add("Item " + i); } strings.stream() .forEach(str -> System.out.println(str));} 在这个例子中,我想直接对集合元素进行计数,而不是挨个来处理。所以,我注释掉原来的代码,使用下面的代码。因为不能准确的知道该集合到底有多少个元素。所以我使用长整型变量来存储结果。 我将这个变量命名为count,通过调用集合strings的.stream(),.count()方法,返回一个长整型的值。然后将这个值与“count:”拼接起来,再通过system的output来打印。 1234//strings.stream()// .forEach(str -> System.out.println(str));long count = strings.stream().count();System.out.println("Count: " + count); 保存并运行该段代码,下面是输出结果。集合中元素数量的统计几乎是瞬间完成。 12Creating listCount: 10000 现在对上面的代码做一点小小的改动,增加两个0。现在,开始处理1000,000个字符串。我再次运行这段代码,也很快就返回结果了。 12Creating listCount: 1000000 现在,我使用并行流来处理,看会发生什么。我在下面增加 parallel 方法: 1234//strings.stream()// .forEach(str -> System.out.println(str));long count = strings.stream().parallel().count();System.out.println("Count: " + count); 然后我运行这段代码,发现花费的时间更长一点了。现在,我做一个基准测试,通过抓取操作前后的时间戳来观察发生了什么。然后做一点数学的事情。不同的系统 上,得到的结果可能不同。但是根据我的经验来说,这种包含简单类型的简单集合,使用并行流并没有太多的优势。不过,我还是鼓励你去自己做基准测试,虽然有 点麻烦。 不过这也要你是如何去做的。 再让我们看一下求和及求均值。我将使用SumAndAverage类。这次,我有一个包含三个person对象的列表,每个person对象的有不同的年龄值。我的目的是求三个年龄的和及年龄的平均值。我在所有的person对象都加入到列表之后加入了一行新的代码。然后,我创建了一个名为sum的整型变量。 首先,我通过pepole.stream()方法获取一个流。在这个流基础上,我可以调用mapToInt()方法。注意,还有两个类似的Map Method:mapToDouble()和mapToLong()。这些方法的目的就是,从复合类型中获取简单的基本类型数据,创建流对象。你可以用 lambda 表达式来完成这项工作。所以,我选择mapToInt()方法,因为每个人的年龄都是整数。 关于 Lambda 表达式,开始是一个代表当前person的变量。然后,通过 Lambda 操作符和 Lambda 表达式(p.getAge())返回一个整数。这种返回值,我们有时也叫做int字符串。也可以返回double字符串或其它类型。现在,由于已经知道它 是一个数字类型的值,所以我可以调用sum()方法。现在,我就已经将所有集合中person对象的年龄值全部加起来了。通过一条语句,我就可以用System Output来输出结果了。我将求和的结果与“Total of ages”连接在一起输出。 123456789List<person> people = new ArrayList<>();people.add(new Person("Mohamed", 69));people.add(new Person("Doaa", 25));people.add(new Person("Malik", 6));int sum = people.stream() .mapToInt(p -> p.getAge()) .sum();System.out.println("Total of ages " + sum); 保存并运行上面的代码。三个年龄的总和是100。 1Total of ages 100 求这些值的平均值非常类似。但是,求平均值需要做除法操作,所以需要考虑除数为0的问题,因此,当你求平均值的时候,可以返回一个Optional的变量。 你可以使用多种数据类型。在计算平均值的时候,我想获得一个double类型的值。所以,我创建了一个OptionalDouble类型的变量。注意,还存在Optional Int和Optional Long。我将平均值命名为avg,使用的代码与求和的代码也是一致的,开始用people.stream()。在这个基础上,再次使用mapToInt()。并且传递了相同的 lambda 表达式,最后,调用average方法。 现在,获得了一个OptionalDouble类型的变量。在处理这个变量前,你可以通过isPresent()来确保它确实是一个double值。所以,我使用了一段 if/else 的模板代码来处理。判定的条件是avg.isPresent()。如果条件为真,就使用System Output输出“Average”标签和平均值。在else子句中,我简单地打印“average wasn’t calculated”。 12345678OptionalDouble avg = people.stream() .mapToInt(p -> p.getAge()) .average();if (avg.isPresent()) { System.out.println("Average: " + avg);} else { System.out.println("average wasn't calculated");} 现在,在这个例子中,我知道能成功,因为我给三个人的年龄都赋值了。但是,情况不总是这样的。正如我前面说的,存在除0的情况,这时你就不能获取到一个double类型返回值。我保存并运行这段代码,请注意optional double类,它是一个复合对象。 12Total of ages 100Average: OptionalDouble[33.333333333333336] 所以,真实的值被包含在该类型中,回到这段代码,直接引用该对象,并调用getAsDouble()方法。 12345if (avg.isPresent()) { System.out.println("Average: " + avg.getAsDouble());} else { System.out.println("average wasn't calculated");} 现在,我就可以获得double类型的值。我再次运行这段代码,输出结果如下: 12Total of ages 100Average: 33.333333333333336 结论 通过流和 lambda 表达式,你可以用非常非常少的代码就可以完成集合的聚合计算。 原文链接: javacodegeeks 翻译: ImportNew.com - paddx译文链接: http://www.importnew.com/16545.html]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title><![CDATA[UnicodeEncodeError: 'ascii' codec can't encode character...的解决方法]]></title>
<url>%2F2015%2F09%2F15%2FUnicodeEncodeError-ascii-codec-can-t-encode-character-%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95%2F</url>
<content type="text"><![CDATA[在python2.7下,因为想从数据库中读出来分类名进行写入到文件,提示1234Traceback (most recent call last): File "test.py", line 28, in <module> fp.write("%d:%s\r\n"%(sClassid,sClassName))UnicodeEncodeError: 'ascii' codec can't encode character u'\uff08' in position 12: ordinal not in range(128 不用fp.write,用print打印却正常,这到底是怎么回来呢? 1234#! /usr/bin/python# -*- coding: utf-8 -*-import sysprint sys.getdefaultencoding(); 运行上面的程序提示 1ascii 原来如此,在程序的头部加上 1234import sysreload(sys)sys.setdefaultencoding('utf-8') 再次运行,错误消息。 总结一下,python2.7是基于ascii去处理字符流,当字符流不属于ascii范围内,就会抛出异常(ordinal not in range(128))]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[pip配置国内镜像]]></title>
<url>%2F2015%2F09%2F07%2Fpip%E9%85%8D%E7%BD%AE%E5%9B%BD%E5%86%85%E9%95%9C%E5%83%8F%2F</url>
<content type="text"><![CDATA[在安装python包的过程中,经常会出现如下错误: 12345678Downloading/unpacking ...Cleaning up...Exception:Traceback (most recent call last): ...SSLError: The read operation timed out 这个主要是墙的问题,但是又无法代理又无法翻~~一墙,被逼着想到了使用镜像的方法了,一些公共的网站在国内总有一些镜像,使用这些镜像地址来安装就可以了 有了目的性搜索很快就搜索到了两个有效的镜像:12https://pypi.tuna.tsinghua.edu.cn/simple/http://pypi.v2ex.com/simple/ 使用镜像的方法可以在每次执行pip的时候加上参数-i http://pypi.v2ex.com/simple即可,或者也可以在本地配置,这样就不用每次都加上参数了: 使用pip的用户可以如下配置: 在unix和macos,配置文件为:$HOME/.pip/pip.conf 在windows上,配置文件为:%HOME%\pip\pip.ini 需要在配置文件内加上: 12[global]index-url=http://mirrors.tuna.tsinghua.edu.cn/pypi/simple 还有一个小技巧,就是把所有要安装的包写在一个文件里面,比如requirement.txt(每个包写一行,顶行头写),然后pip安装的时候只需要加参数”-r requirement.txt”即可。]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Git学习笔记(2)-拉取指定文件或目录]]></title>
<url>%2F2015%2F09%2F02%2FGit%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-2-%E6%8B%89%E5%8F%96%E6%8C%87%E5%AE%9A%E6%96%87%E4%BB%B6%E6%88%96%E7%9B%AE%E5%BD%95%2F</url>
<content type="text"><![CDATA[拉取指定分支下的指定文件或目录 1234$ git init$ git remote add origin [email protected]:<用户名>/<项目名>.git$ git fetch$ git checkout <分支如origin/master> <目录或文件>]]></content>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title><![CDATA[魅族前端面试题]]></title>
<url>%2F2015%2F08%2F28%2F%E9%AD%85%E6%97%8F%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95%E9%A2%98%2F</url>
<content type="text"><![CDATA[列举3个HTML5标签,3个CSS3新特性,3个ECMAScript 5新API。 2种方式,实现某DIV元素以50px每秒的速度左移100px。 用css分别实现某个DIV元素上下居中和左右居中。 用DIV+CSS实现三栏布局(左右固定200px,中间自适应)。 按顺序写出alert弹出窗口的内容。 1234567891011121314var name = "The Window";var object = { name : "My Object", getNameFunc : function(){ alert('1.' + this.name); return function(){ return this.name; }; }};var func = object.getNameFunc();alert('2.' + func());alert('3.' + func.call(object));alert('4.' + func.apply(object)); 列出三个常见的不同浏览器JS的兼容性问题。 用JS写一个实现继承的方法。 用JS实现一个数组合并的方法(要求去重)。 使用正则表达式给所有string对象添加trim方法。 用js实现一个电话号码提取的方法。 例如:” 1852145998 020-888-999845 测试 021 - 85421987, 19865754”得到的结果应该是[1852145998,020-888-999845,021-85421987,19865754] 哪些方法可以提升网站前端性能? 列举你经常访问的前端技术网站,并简单描述一下自己的职业规划。]]></content>
<categories>
<category>Web开发</category>
</categories>
<tags>
<tag>前端</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Git学习笔记(1)-添加删除分支]]></title>
<url>%2F2015%2F08%2F26%2FGit%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-1-%E6%B7%BB%E5%8A%A0%E5%88%A0%E9%99%A4%E5%88%86%E6%94%AF%2F</url>
<content type="text"><![CDATA[使用git在本地创建/删除一个分支的过程 12345678910$ git init //初始化$ touch README$ git add README //更新README文件$ git commit -m 'first commit' //提交更新,并注释信息“first commit”$ git remote add origin [email protected]:<用户名>/<项目名>.git //连接远程github项目$ git branch <分支名称> //在本地新建一个分支$ git checkout <分支名称> //切换到你的新分支$ git push origin <分支名称> //将新分支发布在github上$ git branch -d <分支名称> //在本地删除一个分支$ git push origin :<分支名称> //在github远程端删除一个分支 (分支名前的冒号代表删除)]]></content>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title><![CDATA[运行java,提示找不到或无法加载主类]]></title>
<url>%2F2015%2F08%2F10%2F%E8%BF%90%E8%A1%8Cjava%EF%BC%8C%E6%8F%90%E7%A4%BA%E6%89%BE%E4%B8%8D%E5%88%B0%E6%88%96%E6%97%A0%E6%B3%95%E5%8A%A0%E8%BD%BD%E4%B8%BB%E7%B1%BB%2F</url>
<content type="text"><![CDATA[在javac编译java文件,成功编译,java运行class文件,一直提示找不到或无法加载主类,检查java文件,定义了标准的main方法,无赖一直无法运行,检查环境变量,发现添加了classpath环境变量,才想起是在测试时添加的,classpath的值为E:\java,解决办法,将classpath的值改为.;E:\java,或者删除classpath环境变量]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title><![CDATA[iOS开发技巧]]></title>
<url>%2F2015%2F08%2F10%2FiOS%E5%BC%80%E5%8F%91%E6%8A%80%E5%B7%A7%2F</url>
<content type="text"><![CDATA[多个版本xcode选择默认的 在 Xcode 6.4 安装后下载和安装 Xcode 7,使用以下命令,设置 Xcode 7 为默认选型: sudo xcode-select -s /Applications/Xcode-beta.app]]></content>
<categories>
<category>移动开发</category>
</categories>
<tags>
<tag>iOS</tag>
<tag>Xcode</tag>
</tags>
</entry>
<entry>
<title><![CDATA[docker容器中安装vim]]></title>
<url>%2F2015%2F08%2F06%2Fdocker%E5%AE%B9%E5%99%A8%E4%B8%AD%E5%AE%89%E8%A3%85vim%2F</url>
<content type="text"><![CDATA[在使用docker容器时,有时候里边没有安装vim,敲vim命令时提示说:vim: command not found,这个时候就需要安装vim,可是当你敲apt-get install vim命令时,提示: 1234Reading package lists... DoneBuilding dependency treeReading state information... DoneE: Unable to locate package vim 这时候需要敲:apt-get update,这个命令的作用是:同步/etc/apt/sources.list 和/etc/apt/sources.list.d中列出的源的索引,这样才能获取到最新的软件包。 等更新完毕以后再敲命令:apt-get install vim命令即可。]]></content>
<categories>
<category>Linux学习</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Docker</tag>
</tags>
</entry>
<entry>
<title><![CDATA[深度解析Objective-C笔试题]]></title>
<url>%2F2015%2F08%2F05%2F%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90Objective-C%E7%AC%94%E8%AF%95%E9%A2%98%2F</url>
<content type="text"><![CDATA[本文介绍的是Objective-C笔试题,先来问一个,为什么很多内置类如UITableViewController的delegate属性都是assign而不是retain的?看本文详细详细解答内容。   Objective-C笔试题是本文要介绍的内容,很详细的讲解写的答案。大约有18个Objective-C问题供你参考学习,不多说,我们一起来看详细解答! 1.Objective-C中,与alloc语义相反的方法是dealloc还是release?与retain语义相反的方法是dealloc还是release,为什么?需要与alloc配对使用的方法是dealloc还是release,为什么?答:alloc与dealloc语意相反,alloc是创建变量,dealloc是释放变量。 retain对应release,retain保留一个对象。调用之后,变量的计数加1。或许不是很明显,在这有例为证: 12345— (void) setName : (NSString*) name { [name retain]; [myname release]; myname = name;} 我们来解释一下:设想,用户在调用这个函数的时候,他注意了内存的管理,所以他小心的写了如下代码: 123NSString * newname = [[NSString alloc] initWithString: @"John"];[aClass setName: newname];[newname release]; 我们来看一看newname的计数是怎么变化的。首先,它被alloc,count = 1;然后,在setName中,它被retain, count = 2;最后,用户自己释放newname,count = 1,myname指向了newname。这也解释了为什么需要调用[myname release]。我们需要在给myname赋新值的时候,释放掉以前老的变量。retain之后直接dealloc对象计数器没有释放。alloc需要与release配对使用,因为alloc这个函数调用之后,变量的计数加1。所以在调用alloc之后,一定要调用对应的release。另外,在release一个变量之后,他的值仍然有效,所以最好是后面紧接着再var=nil。 2.在一个对象的方法里面:self.name = “object”; 和name =”object”有什么不同吗?答:self.name = "object"会调用对象的setName()方法,name = "object"会直接把object赋值给当前对象的name属性。 3.这段代码有什么问题吗:12345@implementation Person— (void)setAge:(int)newAge { self.age = newAge;}@end 答:会进入死循环。 4.什么是retain count?答:引用计数(ref count或者retain count)。对象的内部保存一个数字,表示被引用的次数。例如,某个对象被两个指针所指向(引用)那么它的retain count为2。需要销毁对 象的时候,不直接调用dealloc,而是调用release。release会 让retain count减1,只有retain count等于0,系统才会调用dealloc真正销毁这个对象。 5.以下每行代码执行后,person对象的retain count分别是多少1234Person *person = [[Person alloc] init]; //count 1[person retain]; //count 2[person release];//count 1[person release];//retain count = 1; 6.为什么很多内置类如UITableViewController的delegate属性都是assign而不是retain的?答:会引起循环引用。 7.定义属性时,什么情况使用copy,assign,和retain 。答:assign用于简单数据类型,如NSInteger,double,bool,retain 和copy用户对象,copy用于当 a指向一个对象,b也想指向同样的对象的时候,如果用assign,a如果释放,再调用b会crash,如果用copy 的方式,a和b各自有自己的内存,就可以解决这个问题。retain 会使计数器加一,也可以解决assign的问题。另外:atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。在多线程环境下,原子操作是必要的,否则有可能引起错误的结果。加了atomic,setter函数会变成下面这样: 1234if (property != newValue) { [property release]; property = [newValue retain];} 8.对象是在什么时候被release的?答:autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该Object放入了当前的Autorelease pool中,当该pool被释放时,该pool中的所有Object会被调用Release。对于每一个Runloop,系统会隐式创建一个Autorelease pool,这样所有的release pool会构成一个象CallStack一样的一个栈式结构,在每一个Runloop结束时,当前栈顶的Autorelease pool会被销毁,这样这个pool里的每个Object(就是autorelease的对象)会被release。那什么是一个Runloop呢?一个UI事件,Timer call, delegate call, 都会是一个新的Runloop。那什么是一个Runloop呢?一个UI事件,Timer call, delegate call,都会是一个新的Runloop。 9.这段代码有什么问题,如何修改1234567for (int i = 0; i < someLargeNumber; i++){ NSString *string = @”Abc”; string = [string lowercaseString]; string = [string stringByAppendingString:@"xyz"]; NSLog(@“%@”, string);} 答:会内存泄露,修改如下 12345678for(int i = 0; i<1000;i++){ NSAutoreleasePool * pool1 = [[NSAutoreleasePool alloc] init]; NSString *string = @"Abc"; string = [string lowercaseString]; string = [string stringByAppendingString:@"xyz"]; NSLog(@"%@",string); [pool1 drain];} 10.autorelease和垃圾回收机制(gc)有什么关系?答:完全不同的两种机制 11.iPhone OS有没有垃圾回收(gc)?答:早期没有,现在版本支持。 12.什么是Notification?答:观察者模式,controller向defaultNotificationCenter添加自己的notification,其他类注册这个notification就可以收到通知,这些类可以在收到通知时做自己的操作(多观察者默认随机顺序发通知给观察者们,而且每个观察者都要等当前的某个观察者的操作做完才能轮到他来操作,可以用NotificationQueue的方式安排观察者的反应顺序,也可以在添加观察者中设定反映时间,取消观察需要在viewDidUnload 跟dealloc中都要注销)。 13.什么时候用delegate,什么时候用Notification?答:delegate针对one-to-one关系,并且reciever可以返回值给sender,notification 可以针对one-to-one/many/none,reciever无法返回值给sender.所以,delegate用于sender希望接受到reciever的某个功能反馈值,notification用于通知多个object某个事件。 14.什么是KVC和KVO?答:KVC(Key-Value-Coding)内部的实现:一个对象在调用setValue的时候,(1)首先根据方法名找到运行方法的时候所需要的环境参数。(2)他会从自己isa指针结合环境参数,找到具体的方法实现的接口。(3)再直接查找得来的具体的方法实现。KVO(Key-Value-Observing):当观察者为一个对象的属性进行了注册,被观察对象的isa指针被修改的时候,isa指针就会指向一个中间类,而不是真实的类。所以isa指针其实不需要指向实例对象真实的类。所以我们的程序最好不要依赖于isa指针。在调用类的方法的时候,最好要明确对象实例的类名。 15.ViewController 的 loadView, viewDidLoad, viewDidUnload 分别是在什么时候调用的?在自定义ViewController的时候这几个函数里面应该做什么工作?答:viewDidLoad在view 从nib文件初始化时调用,loadView在controller的view为nil时调用。此方法在编程实现view时调用,view 控制器默认会注册memory warning notification,当view controller的任何view 没有用的时候,viewDidUnload会被调用,在这里实现将retain 的view release,如果是retain的IBOutlet view 属性则不要在这里release,IBOutlet会负责release 。 16.ViewController 的 didReceiveMemoryWarning 是在什么时候被调用的?默认的操作是什么?答:默认调用[super didReceiveMemoryWarning]]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Objective-C</tag>
</tags>
</entry>
<entry>
<title><![CDATA[JavaScript 获取客户端内网IP和外网IP(STUN)]]></title>
<url>%2F2015%2F08%2F04%2FJavaScript-%E8%8E%B7%E5%8F%96%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%86%85%E7%BD%91IP%E5%92%8C%E5%A4%96%E7%BD%91IP-STUN%2F</url>
<content type="text"><![CDATA[from:https://github.com/diafygi/webrtc-ips Firefox 跟 Chrome支持WebRTC可以向STUN服务器请求,返回内外网IP,不同于XMLHttpRequest请求,STUN请求开发者工具当中看不到网络请求的。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879//get the IP addresses associated with an accountfunction getIPs(callback){ var ip_dups = {}; //compatibility for firefox and chrome var RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection; var useWebKit = !!window.webkitRTCPeerConnection; //bypass naive webrtc blocking using an iframe if(!RTCPeerConnection){ //NOTE: you need to have an iframe in the page right above the script tag // //<iframe id="iframe" sandbox="allow-same-origin" style="display: none"></iframe> //<script>...getIPs called in here... // var win = iframe.contentWindow; RTCPeerConnection = win.RTCPeerConnection || win.mozRTCPeerConnection || win.webkitRTCPeerConnection; useWebKit = !!win.webkitRTCPeerConnection; } //minimal requirements for data connection var mediaConstraints = { optional: [{RtpDataChannels: true}] }; var servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]}; //construct a new RTCPeerConnection var pc = new RTCPeerConnection(servers, mediaConstraints); function handleCandidate(candidate){ //match just the IP address var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/ var ip_addr = ip_regex.exec(candidate)[1]; //remove duplicates if(ip_dups[ip_addr] === undefined) callback(ip_addr); ip_dups[ip_addr] = true; } //listen for candidate events pc.onicecandidate = function(ice){ //skip non-candidate events if(ice.candidate) handleCandidate(ice.candidate.candidate); }; //create a bogus data channel pc.createDataChannel(""); //create an offer sdp pc.createOffer(function(result){ //trigger the stun server request pc.setLocalDescription(result, function(){}, function(){}); }, function(){}); //wait for a while to let everything done setTimeout(function(){ //read candidate info from local description var lines = pc.localDescription.sdp.split('\n'); lines.forEach(function(line){ if(line.indexOf('a=candidate:') === 0) handleCandidate(line); }); }, 1000);}//Test: Print the IP addresses into the consolegetIPs(function(ip){console.log(ip);});]]></content>
<categories>
<category>Web开发</category>
</categories>
<tags>
<tag>Javascript</tag>
</tags>
</entry>
<entry>
<title><![CDATA[ruby安装时错误-mysql2]]></title>
<url>%2F2015%2F08%2F03%2Fruby%E5%AE%89%E8%A3%85%E6%97%B6%E9%94%99%E8%AF%AF-mysql2%2F</url>
<content type="text"><![CDATA[执行bundle install时,控制台报错: 解决:sudo gem install mysql2 -v '0.3.16',如果还不行,则 sudo apt-get install libmysqlclient-dev,安装后再运行上边的命令]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Ruby</tag>
</tags>
</entry>
<entry>
<title><![CDATA[brew安装appledoc时提示No available formula for appledoc]]></title>
<url>%2F2015%2F07%2F31%2Fbrew%E5%AE%89%E8%A3%85appledoc%E6%97%B6%E6%8F%90%E7%A4%BANo-available-formula-for-appledoc%2F</url>
<content type="text"><![CDATA[执行brew install appledoc 提示: 123Error: No available formula for appledocSearching formulae...Searching taps... 执行brew tap homebrew/dupes再执行:brew install appledoc]]></content>
<categories>
<category>Linux学习</category>
</categories>
<tags>
<tag>Mac</tag>
</tags>
</entry>
<entry>
<title><![CDATA[优雅地使用 OS X]]></title>
<url>%2F2015%2F07%2F30%2F%E4%BC%98%E9%9B%85%E5%9C%B0%E4%BD%BF%E7%94%A8-OS-X%2F</url>
<content type="text"><![CDATA[]]></content>
<tags>
<tag>Mac</tag>
</tags>
</entry>
<entry>
<title><![CDATA[我的全栈之路]]></title>
<url>%2F2015%2F07%2F30%2F%E6%88%91%E7%9A%84%E5%85%A8%E6%A0%88%E4%B9%8B%E8%B7%AF%2F</url>
<content type="text"><![CDATA[]]></content>
<tags>
<tag>Full Stack Developer</tag>
</tags>
</entry>
<entry>
<title><![CDATA[nginx运行PHP页面报502错误]]></title>
<url>%2F2015%2F07%2F30%2Fnginx%E8%BF%90%E8%A1%8CPHP%E9%A1%B5%E9%9D%A2%E6%8A%A5502%E9%94%99%E8%AF%AF%2F</url>
<content type="text"><![CDATA[在ubuntu上搭建lnmp环境的时候,运行php页面,代码如下 123<?phpphpinfo();?> 浏览器打开http://localhost/info.php,结果502了 解决办法: 修改为: 运行sudo service nginx reload就可以正常访问了]]></content>
<categories>
<category>Linux学习</category>
</categories>
<tags>
<tag>Nginx</tag>
<tag>PHP</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Mac安装Android SDK]]></title>
<url>%2F2015%2F07%2F29%2FMac%E5%AE%89%E8%A3%85Android-SDK%2F</url>
<content type="text"><![CDATA[启动Android SDK Manager,打开主界面,在菜单栏,依次选择「Android SDK Manager」、「Preference…」,弹出『Android SDK Manager - Settings』窗口; 在『Android SDK Manager - Settings』窗口中,在「HTTP Proxy Server」和「HTTP Proxy Port」输入框内填入mirrors.neusoft.edu.cn和80,并且选中「Force https://… sources to be fetched using http: //…」复选框。设置完成后单击「Close」按钮关闭『Android SDK Manager - Settings』窗口返回到主界面; 依次选择「Packages」、「Reload」]]></content>
<categories>
<category>移动开发</category>
</categories>
<tags>
<tag>Android</tag>
</tags>
</entry>
<entry>
<title><![CDATA[编译安装nginx报错[install_docs] Error 255]]></title>
<url>%2F2015%2F07%2F28%2F%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85nginx%E6%8A%A5%E9%94%99-install-docs-Error-255%2F</url>
<content type="text"><![CDATA[源码编译安装nginx报错: 解决办法: 1rm /usr/bin/pod2man]]></content>
<tags>
<tag>Nginx</tag>
</tags>
</entry>
<entry>
<title><![CDATA[使用hexo generate生成文章时报错JS-YAML: can not read a block mapping entry]]></title>
<url>%2F2015%2F07%2F28%2F%E4%BD%BF%E7%94%A8hexo-generate%E7%94%9F%E6%88%90%E6%96%87%E7%AB%A0%E6%97%B6%E6%8A%A5%E9%94%99JS-YAML-can-not-read-a-block-mapping-entry%2F</url>
<content type="text"><![CDATA[在使用hexo generate生成静态文章时报错了,错误内容如下 1234ERROR Process failed: _posts/vagrant-reload命令报错-UndefinedConversionError.mdJS-YAML: can not read a block mapping entry; a multiline key may not be an implicit key at line 4, column 1: ^ 错误原因是在tags:["vagrant", "ruby"]中tag:后面必须要有空格(半角)]]></content>
<tags>
<tag>Hexo</tag>
</tags>
</entry>
<entry>
<title><![CDATA[vagrant reload命令报错:UndefinedConversionError]]></title>
<url>%2F2015%2F07%2F28%2Fvagrant-reload%E5%91%BD%E4%BB%A4%E6%8A%A5%E9%94%99-UndefinedConversionError%2F</url>
<content type="text"><![CDATA[修改了Vagrantfile文件后,运行vagrant reload命令,控制台直接报错了,错误如下 12345678910111213/opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/subprocess.rb:28:in `encode': "\xE4" from ASCII-8BIT to UTF-8 (Encoding::UndefinedConversionError) from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/subprocess.rb:28:in `block in initialize' from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/subprocess.rb:28:in `each' from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/subprocess.rb:28:in `initialize' from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/subprocess.rb:22:in `new' from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/subprocess.rb:22:in `execute' from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/plugins/providers/virtualbox/driver/base.rb:404:in `block in raw' from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/busy.rb:19:in `busy' from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/plugins/providers/virtualbox/driver/base.rb:403:in `raw' from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/plugins/providers/virtualbox/driver/base.rb:342:in `block in execute' from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/retryable.rb:17:in `retryable' from /opt/vagrant/embedded/gems/gems/vagrant-1.7.2/plugins/providers/virtualbox/driver/base.rb:337:in `execute' ...... 回头仔细检查了一下Vagrantfile文件,只是修改了一下网络为public_network和IP,并没有什么问题,后来想了一下,该box是我重Windows上打包,然后在导入Mac系统中的,vagrant的源码使用Ruby实现的,Ruby 转码的方法:encode 有转码兼容,GBK转码为UTF-8不兼容,所以报错 解决方法:思路:将参数用 force_encoding方法 强制转换成GBK编码即可方法:找到报错的目录/opt/vagrant/embedded/gems/gems/vagrant-1.7.2/lib/vagrant/util/subprocess.rb文件找到line 26,将代码修改为:然后vagrant reload 没有报错,重启成功,代码同步成功。这是vagrant的一个bug。]]></content>
<categories>
<category>Linux学习</category>
</categories>
<tags>
<tag>Ruby</tag>
<tag>vagrant</tag>
</tags>
</entry>
<entry>
<title><![CDATA[no version information available]]></title>
<url>%2F2015%2F07%2F27%2Fno-version-information-available%2F</url>
<content type="text"><![CDATA[使用nvm安装nodejs的时候报错了,错误信息如下: 12345678910111213vagrant@ubuntu-14:~$ nvm install 0.12.4curl: /home/vagrant/.linuxbrew/lib/libssl.so.1.0.0: no version information available (required by /usr/lib/x86_64-linux-gnu/libcurl.so.4)curl: /home/vagrant/.linuxbrew/lib/libssl.so.1.0.0: no version information available (required by /usr/lib/x86_64-linux-gnu/libcurl.so.4)curl: /home/vagrant/.linuxbrew/lib/libcrypto.so.1.0.0: no version information available (required by /usr/lib/x86_64-linux-gnu/libcurl.so.4)curl: /home/vagrant/.linuxbrew/lib/libssl.so.1.0.0: no version information available (required by /usr/lib/x86_64-linux-gnu/libcurl.so.4)curl: /home/vagrant/.linuxbrew/lib/libssl.so.1.0.0: no version information available (required by /usr/lib/x86_64-linux-gnu/libcurl.so.4)curl: /home/vagrant/.linuxbrew/lib/libcrypto.so.1.0.0: no version information available (required by /usr/lib/x86_64-linux-gnu/libcurl.so.4)curl: /home/vagrant/.linuxbrew/lib/libssl.so.1.0.0: no version information available (required by /usr/lib/x86_64-linux-gnu/libcurl.so.4)curl: /home/vagrant/.linuxbrew/lib/libssl.so.1.0.0: no version information available (required by /usr/lib/x86_64-linux-gnu/libcurl.so.4)curl: /home/vagrant/.linuxbrew/lib/libcrypto.so.1.0.0: no version information available (required by /usr/lib/x86_64-linux-gnu/libcurl.so.4)curl: /home/vagrant/.linuxbrew/lib/libssl.so.1.0.0: no version information available (required by /usr/lib/x86_64-linux-gnu/libcurl.so.4)curl: /home/vagrant/.linuxbrew/lib/libssl.so.1.0.0: no version information available (required by /usr/lib/x86_64-linux-gnu/libcurl.so.4)curl: /home/vagrant/.linuxbrew/lib/libcrypto.so.1.0.0: no version information available (required by /usr/lib/x86_64-linux-gnu/libcurl.so.4) 处理办法:rm /home/vagrant/.linuxbrew/lib/libssl.so.1.0.0, 同理删除libcrypto]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Nodejs</tag>
</tags>
</entry>
<entry>
<title><![CDATA[C语言基础]]></title>
<url>%2F2015%2F07%2F24%2FC%E8%AF%AD%E8%A8%80%E5%9F%BA%E7%A1%80%2F</url>
<content type="text"><![CDATA[1.include include“a.txt”:即a.txt中的内容加载到程序中。 include用法:如果导入的是系统自带的则用<>; 如果导入的是自己写的文件则用“”; 2.头文件 比如stadio.h,用来声明一些常用的函数。如输入,输出函数。 3.程序入口 C语言的函数入口为main()函数,C不允许重复定义函数,否则报错。 4.参数 (1)形参:在方法后面的()中定义的变量称为形式参数; 如: void test(int b){printf("我被调用%d次了。"+b);} b既是形参。 (2)实参:在调用函数时传入的值称为实际参数 如: void main(){ printf("调用test函数:"+test(1));} 5.常用的基本类型 类型 名称 存储空间(16位编译器) 存储空间(32位编译器) 存储空间(64位编译器) short 短整型 2个字节 2个字节 2个字节 int 整型 2个字节 4个字节 4个字节 long 长整型 4个字节 4个字节 8个字节 float 单精度浮点型 4个字节 4个字节 4个字节 double 双精度浮点型 8个字节 8个字节 8个字节 char 字符型 1个字节 1个字节 1个字节 6.类型修饰符 类型 名称 取值范围 short 短型 -32768 ~ 32767 long 长型 -2147483648 ~ 2147483647 signed 有符号型(有正数和负数) -32768 ~ 32767 unsigned 无符号型(只有正数和零) 0 ~ 65535 7.关系运算符 符号 名称 < 小于运算符 ≤ 小于等于运算符 > 大于等于运算符 ≥ 大于等于运算符 == 等于运算符 != 不等于运算符 注意点:在Java中,关系运算结果如果为真就返回true;为假就返回false;如:boolean b = 1>2 //返回false而在C语言中,关系运算结果如果为真就返回1,为假就返回0;如:int b =1>2 //返回0 8.逗号表达式 用逗号运算符连接起来的表达式称为逗号表达式,它的一般形式:表达式1,表达式2,…,表达式n;运算过程是:从左往右的顺序。逗号表达式也有返回值,整个逗号表达式的值是最后一个表达式的值。如: 12345int a =1;int b=2;int c;c = (a+=2,b+=a);printf("c=%d",c); 9.二位数组 注意点:二维数组可以省略行数,但不可以省略列数。 10.字符串 ‘\0’:表示字符串结束标志。它是一个ASCII码值为0的字符,是一个空操作符,表示什么也不干。 如:存储一个字符串“book”,char a[] =”book”;它应该是占用5个字符,因为“\0”也算一个。 123char b[3] ={'a','b','\0'} //表示字符串char b[2] ={'a','b'} //表示字符数组char b[] ="ab"; //会在字符串尾部自动加上一个 \0 结束。 输出字符串函数有: printf:可以输出多个字符串。 如:printf(“%s %s %s %s.\n”,”my”,”name”,”is”,”Jack”); puts:只能输出一个字符串,而且会自动换行。直到读取到’\0’才结束。 如: 123char s1[] = {'a','b','\0'};char s2[] = {'e','f'};puts(s2);//输出结果为efab 输入字符串函数有: scanf();可以一次性输入多个字符串。不能用来读取空格,tab。从首地址开始存放用户输入的字符,存放完毕后,系统会自动在尾部 加上一个结束标志\0。 gets();一次只能读取一个字符串,可以读入包含空格、tab的字符串,直到遇到回车为止这个函数不支持使用,因为会造成内存溢出问题。如: 1234char s1[] ="ab";char s2[2];gets(s2);//键盘输入printf("%s",s1); 原因:因为s2在内存中占2个字符,内容为it,剩下的为cast,所以输出结果为cast 常用的函数有: strlen():用来测量字符串的字符个数。不包括\0。如:int size = strlen(“abcdef”); strcpy(字符串1,字符串2):复制字符串函数。 strcat(字符串1,字符串2):字符串连接函数。原理是把第二个字符放到掉第一个字符的结尾\0,如果有多个\0结束符,默认从第一个\0结束符开始连接。如: 1234char a[]={'b','o','\0','o','k','\0'};char b[] ="tick";strcpy(a,b);printf("%s",a); //输出结果为:botick strcmp(字符串1,字符串2):字符串比较函数。原理是两个字符串从左往右逐个字符比较,直到字符不相同或者遇见‘\0’为止。如果全部相同则返回0,大于则返回正,小于则返回负。 strlwr():将字符串中大写字母转换成小写字母。 strupr():将字符串中小写字母转换成大写字母。 11.字符 字符输出函数putchar:一次只能输出一个字符。如putchar(65);输出A 字符输入函数getchar:一次只能输入一个字符。可以读取空格、tab,直到遇到回车为止。 12.指针 概念 直接引用:直接通过变量名引用的叫直接引用。 间接引用:通过另一个变量来引用的叫间接引用。 指针变量:用来存放变量地址的变量就叫指针变量。 1234char a;char *b;//定义了一个指针变量bb=&amp;a; //表示把a的地址赋给b*b =10; //表示b中对应的存储空间的值为10。也相当于a= 10 一个指针变量所占的内存空间是固定的。它不会因为指向的类型不同而在内存中所占的空间大小也不同。但在不同的编译器下所占的内存空间是不一样的。 16位编译器 32位编译器 64位编译器指针变量 2字节 4字节 8字节 指针与字符串 12char a[] = "abc";//定义的是一个字符串变量,a[0] ='b'这样子也是可以改的。char *p = "abc"; //定义的是一个字符串常量!严格来说,应该写成const char *p ="abc"; 但是*p ='b';这样子是不能修改的,因为*p指向的是字符串常量,所以不能修改。 指针与函数 函数:函数在内存中也要占据部分存储空间,它也有一个起始地址,即函数的入口地址。例子:被调用函数为int sum(int a, int b){ int c = a+b;return c; } 12345void main(){ int (*p)(int,int);//定义了一个指向函数的指针变量p,返回值类型为int类型,接收两个int类型的参数 p = sum; //把函数sum的地址赋给指针p (*p)(3,4);//调用函数sum} 函数利用指针的好处:可以把函数当做参数进行传递。 13.预处理指令 概念:C语言在对源程序进行编译之前,会先对一些特殊的预处理指令作解释(比如#include文件包含的指令),产生一个新的源程序,这个过程称为编译预处理。 C语言提供的预处理指令主要有:宏定义、文件包含、条件编译。 宏定义:即字符替换。可以定义变量,也可以定义表达式。如: 12#define Num 6#define sum(a,b) a+b 条件编译:只希望程序的其中一部分代码在满足一定的条件时才进行编译,否则不参与编译,这就是条件编译。常用用法:用来判断宏的值。格式: 1234#if 条件{}#elif 条件{}#else {}#endif 其他用法 #if defined()和#if!defined()的用法:用来判断是否定义过某个宏。 #ifndef的使用和#if defined()的用法基本一致。 #ifndef的使用和#if !defined()的用法基本一致。 文件包含:即#include指令,它可以将一个文件的全部内容拷贝到另一个文件中。常见的形式有: #include<文件名>:这种形式一般指导入C语言的库函数。 #include”文件名”:这种形式一般指导入用户自定义的文件。程序一般会在源程序的当前目录下寻找,若找不到,再到操作系统的path路径中查找,最后才到C语言库函数头文件所在目录中查找。注意点:#include指令允许嵌套包含,但不允许递归包含。 14.变量 根据变量的作用域不同,可分为局部变量和全局变量。 局部变量:在函数内部定义的变量称为局部变量。 全局变量:在所有函数外部定义的变量称为全局变量。作用域是从定义变量的位置开始到源程序结束。 变量的存储类型指变量存储在什么地方,一般有3个地方可以存储变量:普通内存、运行时堆栈、硬件寄存器。变量的存储类型决定了变量何时创建、何时销毁以及它的值能保持多久。根据存储类型的不同,可分为: 自动变量:被关键字auto修饰的局部变量都是自动变量。一般auto都是省略的,所以所有的局部变量在默认情况下都是自动变量。自动变量是存储在运行时堆栈中的。生命周期:在程序执行到声明自动变量的代码块(函数)时,自动变量才被创建;当自动变量所在的代码块(函数)执行完毕后,这些自动变量就会自行销毁。如果一个函数被重复调用,这些自动变量每次都会重新创建。 静态变量:存储在静态内存中,也就是不属于堆栈的变量。如:全局变量和被static修饰的局部变量。生命周期:静态变量在重新运行之前创建,在程序的整个运行期间始终存在,直到程序结束。 寄存器变量:存储在硬件寄存器中的变量称为寄存器变量。(默认情况下,自动变量和静态变量都是放在内存中的。被关键字register修饰的自动变量都是寄存器变量。只有自动变量才可以是寄存器变量。只限于int、char和指针类型变量使用。生命周期:在调用该函数时占用寄存器中存放的值,当函数结束后释放寄存器,变量消失。 15.函数 外部函数: 在当前文件定义的函数允许被其他文件访问、调用的,就称为外部函数。完整地定义一个外部函数需要extern关键字。extern也可以省略。 内部函数:在当前文件定义的函数不允许被其他文件访问、调用,只能在内部使用的,就称为内部函数。常用static关键字修饰。扩展:同理也有用extern修饰的变量叫外部变量和用static修饰的变量叫内部变量。 16.结构体定义一个结构的一般形式为 1234struct 结构名{ 成员表列} 成员表由若干个成员组成,每个成员都是该结构的一个组成部分。结构体本身并不会被作为数据而开辟内存,真正作为数据而在内存中存储的是这种结构体所定义的变量。说明结构变量有以下三种方法。 先定义结构,再说明结构变量。 如: 1234567struct student{ int num; char *name; int age;};struct student stu1,stu2; 说明了两个变量stu1和stu2为student结构类型。 在定义结构类型的同时说明结构变量。例如: 123456struct student{ int num; char *name; int age;} stu1,stu2; 注意当你的结构体变量中有存放多个字符的成员,建议你将它定义为数组(比如前面的姓名成员,不知道数组该开辟多大时,也可以定义为指针)。原因是指针变量不能存放实际数据,仅仅是地址。 使用结构变量成员的一般形式是:结构变量名.成员名 如:stu1.age表示取得学生的年龄这个属性。 17.枚举:当一个变量有几个固定取值时,可以将这个变量定义为枚举类型。 一般形式:enum 枚举名{枚举元素1,枚举元素2,…};如:enum season {spring,summer,autumn,winter}; C语言编译器会将枚举元素作为整型常量处理,称为枚举常量。枚举元素的值取决于定义时各枚举元素排列的先后顺序。 18.typeof关键字 给各种数据类型定义一个新名字(别名)。可以是基本类型,也可以是结构体,枚举。如:typedef int Integer;, 使用的时候就可以这样写了: Integer b =9;]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>C</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Failed to build gem native extension - cannot load such file -- mkmf(LoadError)]]></title>
<url>%2F2015%2F07%2F23%2FFailed-to-build-gem-native-extension-cannot-load-such-file-mkmf-LoadError%2F</url>
<content type="text"><![CDATA[在Ubuntu Server上利用Gitlab搭建git服务器的时候,执行sudo bundle install --deployment --without development test postgres aws报一下错误 1234567891011121314151617181920Don't run Bundler as root. Bundler can ask for sudo if it is needed, and installing your bundle as root will breakthis application for all non-root users on this machine.Fetching gem metadata from http://ruby.taobao.org/........Fetching version metadata from http://ruby.taobao.org/..Using rake 10.4.2Using CFPropertyList 2.3.1Installing RedCloth 4.2.9 with native extensionsGem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension. /usr/bin/ruby1.9.1 extconf.rb/usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require': cannot load such file -- mkmf (LoadError) from /usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require' from extconf.rb:1:in `<main>'Gem files will remain installed in /home/git/gitlab/vendor/bundle/ruby/1.9.1/gems/RedCloth-4.2.9 for inspection.Results logged to /home/git/gitlab/vendor/bundle/ruby/1.9.1/gems/RedCloth-4.2.9/ext/redcloth_scan/gem_make.outAn error occurred while installing RedCloth (4.2.9), and Bundler cannot continue.Make sure that `gem install RedCloth -v '4.2.9'` succeeds before bundling. 最终baidu寻找到解决办法http://stackoverflow.com/questions/13767725/unable-to-install-gem-failed-to-build-gem-native-extension-cannot-load-such 123456789101112131415There is similar questions:`require': no such file to load -- mkmf (LoadError)Failed to build gem native extension (mkmf (LoadError)) - Ubuntu 12.04The solution is:sudo apt-get install ruby-devOr, if that doesn't work, depending on your ruby version, run something like:sudo apt-get install ruby1.9.1-devShould fix your problem.Still not working? Try the following after installing ruby-dev:sudo apt-get install make]]></content>
<categories>
<category>编程开发</category>
</categories>
<tags>
<tag>Ruby</tag>
<tag>Nodejs</tag>
<tag>Rails</tag>
</tags>
</entry>
<entry>
<title><![CDATA[我的MacMini上安装的Apps]]></title>
<url>%2F2015%2F07%2F23%2F%E6%88%91%E7%9A%84MacMini%E4%B8%8A%E5%AE%89%E8%A3%85%E7%9A%84Apps%2F</url>
<content type="text"><![CDATA[]]></content>
<tags>
<tag>Mac</tag>
</tags>
</entry>
<entry>
<title><![CDATA[iOS完整学习路线图]]></title>
<url>%2F2015%2F07%2F21%2FiOS%E5%AE%8C%E6%95%B4%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF%E5%9B%BE%2F</url>
<content type="text"><![CDATA[]]></content>
<categories>
<category>移动开发</category>
</categories>
<tags>
<tag>iOS</tag>
</tags>
</entry>
<entry>
<title><![CDATA[全栈工程师技能树]]></title>
<url>%2F2015%2F07%2F20%2F%E5%85%A8%E6%A0%88%E5%B7%A5%E7%A8%8B%E5%B8%88%E6%8A%80%E8%83%BD%E6%A0%91%2F</url>
<content type="text"><![CDATA[]]></content>
<tags>
<tag>FSD</tag>
<tag>Full Stack Developer</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Xcode快捷键]]></title>
<url>%2F2015%2F07%2F20%2FXcode%E5%BF%AB%E6%8D%B7%E9%94%AE%2F</url>
<content type="text"><![CDATA[完整内容请查看PDF文档]]></content>