|  | 
				
					
			  
	2015年1月20日
	
 
			
			1. java zip 多个文件时,如果先添加了一个excel文件,然后再想添加其他的文件时会出现 steam is closed的错误。这是因为work.write(outputSteam)后,出调用outputSteam.close(),关闭输出流。 解决方法: 将原来的程序:             ZipEntry entry = new ZipEntry( "file3.txt" );zos.putNextEntry( entry );
 workbook.write( zos );
 zos.closeEntry();
 改为:             ZipEntry entry = new ZipEntry( "file3.txt" );zos.putNextEntry( entry );
 workbook.write( new NonCloseableOutputStream( zos ) );
 zos.closeEntry();
 其中 NonCloseableOutputStream 定义如下: public class NonCloseableOutputStream extends java.io.FilterOutputStream {public NonCloseableOutputStream(OutputStream out) {
 super(out);
 }
 @Override public void close() throws IOException {
 flush();
 }
 }
 2. 使用binary使得mysql区分大小写 select * from table1 where binary field1 = 'abc'; 
			
			https://notepad-plus-plus.org/community/topic/13661/plugin-manager-x64-available-submit-your-plugins 
			
			move Git Server to a new IP/URL:
 you can just edit
 .git/configand change the URLs there
 也可以在git视图中,右键点击项目,选择属性,然后修改url中的地址
 
 
			
			autohotkeylistary
 cmder可以split screen,在一个窗口中同时运行数个cmd
 
			
			官网地址:autohotkey.com ; fill password ^Numpad2:: 	Send, root{tab}root{enter} Return ^Numpad3:: IfWinExist, ahk_exe OUTLOOK.EXE {     WinActivate ahk_exe OUTLOOK.EXE ; Automatically uses the window found above.     ; WinMaximize  ; same     ;Send, Some text.{Enter} 	msgbox Outlook is running. } Return 
			
			<html><head>
 <script src="https://unpkg.com/vue/dist/vue.js"></script>
 <script>
 window.onload = function () {
 var app = new Vue({
 el: '#app',
 data: {
 message: 'Hello Vue!'
 }
 });
 }
 </script>
 </head>
 
 <body>
 <div id="app">
 {{ message }}
 </div>
 </body>
 </html>
 
			
			String[] splits=someString.split("a,b,c,d", ","); logger.debug( "array: {}", (Object) splits ); 这里要注意的就是要把数组的数据类型强制转换为Object  
			
			在windows环境中,可以用如下方法重置root密码 1、先停止mysql数据库 2、保存密码重置sql文件      5.7.6(包括)以后的版本:ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';      5.7.5(包括)以前的版本:SET PASSWORD FOR 'root'@'localhost' = PASSWORD('MyNewPass'); 假设保存到文件: c:\reset.txt 3、以管理员身份打开命令行窗口,运行 C:\> cd "C:\Program Files\MySQL\MySQL Server 5.5\bin" C:\> mysqld --init-file=C:\reset.txt
 4、启动后,还不能马上用新密码连接数据库,需要重启mysql数据库
 
 
			
			This is a general step that happens when m2e/m2eclipse (Maven integration for Eclipse) is installed, whether projects are actively using it or not.这是因为m2eclipse(maven插件)要在启动时需要进行的一个步骤。
 This step can be disabled through the Eclipse preferences: Window / Preferences / Maven / "Download repository index updates on startup". This option is on the main "Maven" preference page (not a child page). Just uncheck the box to prevent this from happening.我们可以停止这个动作。方法:Windows -> Preferences -> Maven 取消勾选 Download repository index updates on startup
 
			
			有好几个java library都可以实现这个功能,但是从pdf提取文本的一个问题是,提取出来的文本没有固定的顺序,不容易比较好的还原其格式。
 我的做法是使用pdfclown来进行这项工作。官方网站是:https://pdfclown.org/ 先下载其最新版本。
 参考其示例代码:https://pdfclown.org/2010/01/02/upcoming-0-0-8-whats-going-to-be-new/#more-30
 
 使用这段代码,我们不仅可以得到文本的字符串,还能得到文本的页数和相对坐标。
 我的思路是先把所有文本的字符串和坐标提取出来。然后排序,排序的顺序是纵坐标,然后横坐标。
 这样排序完毕后,就能比较好的解决文本格式问题。
 
			
			1, 先定义一个input, 做为datepicker的容器。
 <input type='text' class="form-control" id="dateTo" name="dateTo" required/>
 
 2, 在后面加上glyphicon, 注意关键是label 中的for的id需要是前面定义的容器的id, 这样点击glyphicon的时候就会触发弹出日期选择框。
 <label for="dateTo" class="input-group-addon"><span class="glyphicon glyphicon-time"></span></label> 
			
			在日志文件中看到这个错误信息Cause: java.sql.SQLException: #HY000 
 
 后来才知道这是因为数据库中有个别字段要求不能为空, 但是insert语句中没有提供数据,造成了这个错误。 关键是错误信息不明确直观,不容易知道是这个原因
 
			
			    public void afterJFinalStart(){Configuration config = FreeMarkerRender.getConfiguration();
 config.setTemplateUpdateDelayMilliseconds( 2 );
 config.setAPIBuiltinEnabled( true );
 }
 
			
			中文版地址  https://angular.cn/ 
			
			1, call ##002# to cancel "call diversion"
 2, call 121600, choose option "2" to cancel "Active call catcher"
 
			
			1. 格式化XML的插件可以安装“XML Tools", 安装完毕后,选择 插件->XML Tools->Pretty Print(XML Only - with line breaks)
 
 2. 格式化JSON的插件
 可以安装”JSON Viewer", 安装完毕后,选择 插件->JSON Viewer->Format JSON
 
 3. 格式化SQL的插件
 可以安装“Poor man's T-Sql Formatter", 选择 插件->Poor man's T-Sql Formatter->Format T-Sql Code
 
			
			  使用的工具
 
 1. Apache HttpClient
 2. Firefox + FireBug
 3. Burp Suite ( https://portswigger.net/burp ) + Firefox FoxyProxy
 
 Firefox + FireBug 主要用于查看渲染出的页面中的信息(比如:表单项的名称,节点ID等等)
 Burp Suite 主要用于动态拦截页面的交互,查看Ajax的调用。
 HttpClient 用于最后程序的编制。搞清楚了网页交互的过程,就可以自主决定程序需要包含的内容。
 在实际网页中,可能需要点开数级菜单,才能最后看到需要的内容。
 但是在程序中,可以直接跳到最后一步。
 
			
			1. 表格文字右对齐  
 <table> 
<tr> 
    <td><p style="text-align:right;margin:0;padding:0">文字右对齐</p></td> 
    <td>文字左对齐</td> 
</tr> 
</table>
 
2. 表格边缘的margin
需要在表格外再套一个div
 <div style="margin:10px">      <table>
     ......     </table>
 </div> 3. btn-toolbar class can put a margin between 2 "pull-right" buttons         <div class="row"><div class="col-md-2"></div>
 <div class="col-md-8 btn-toolbar">
 <input type="submit" class="btn btn-warning pull-right" value="Submit">
 <input type="button" id="profilePassBackBtn" class="btn btn-info pull-right" value="Back">
 </div>
 <div class="col-md-2">
 </div>
 </div>
 
			
			 AngularJS 2.0 已经发布了Beta版本,相信正式版不久以后就会发布了。
 下面是官网上的新功能介绍:
 
 1. 更快更高效。AngularJS 2 将会比 AnuglarJS 1 快很多。因为它会支持:从远程胳快速加载、离线编译以便于更快启动、以及超快的变动检测和为使滚动更平滑的视图缓存等等。
 
 2. 更加简单清晰。语法将会显得更加自然,易于编写
 
 3. 跨越平台。无论是台式机、手机浏览器、安卓、IOS平台,AngularJS都能提供相应的支持。
 
 4. 无缝从 AngularJS 1 升级到 2
 
 5. 简便的开发。支持各种开发语言,ES5, TypeScript, Dart
 
 6. 全面完备的路由。 方便地映射URL到应用组件,并提供多种高级功能,比如:嵌套和邻接路由,支持卡片栈导航、动画过渡、手机用户延迟加载等等
 
 7. 依赖注入。
 
 8. 旧浏览器的良好支持
 
 9. 动画效果 (仍在开发中)
 
 10. 国际化支持(仍在开发中)
 
			
			Go to web project properties.Deployment Assembly (Left).Add > Select project > Select your lib project > Check "Assemble projects into the WEB-INF/lib folder of the web application" if not checked > Finish.
 
			
			 使用酷狗就可以转换。右键点击歌曲 ,工具,格式转换。
 唯一要注意的是要先登录。
 
			
			今天把commons dbcp 和 pool都升级到2.x, 结果发现不能正常的工作,卡在new BasicDataSource()上了. 后来才发现原因是因为没有加入commons-logging的jar文件 几个注意点:1. commons dbcp2.x 和 commons pool需要同时升到2.x
 2. dbcp 2.x要运行在java 7以上
 3. mysql connector要5.1.11以上
 4. 需要有commons-logging的包,我使用的是slf4j, 就需要加一个jcl-over-slf4j
 
			
			Errorcom.jcraft.jsch.JSchException: The cipher 'aes256-cbc' is required, but it is not available.
 or
 
 Caused by: java.security.InvalidKeyException: Illegal key size 
 
 
			
			我在网上搜索了一下如何使用Selenium下载文件,其中确实有几篇文件介绍了实现的方法。
 但是其主要思想都是使用httpClient或者URL获得InputStream, 然后保存到文件中。
 但是,其中的问题是用户登录的Session不能维持。
 
 我发现了一个简单的方法。
 直接使用WebDriver.get, 示例如下:
 
 webDriver.get("https://website.com/login");
 WebElement element = driver.findElement( By.id( "userID" ) );
 element.sendKeys( "user01" );
 
 element = driver.findElement( By.id( "passwd" ) );
 element.sendKeys( "password" );
 
 element = driver.findElement( By.name( "Login" ) );
 element.submit();
 
 webDriver.get("https://website.cm/download.do?start=xx&end=yy");
 String source = webDriver.getPageSource();
 
 这个source就是我们想保存的要下载的内容。
 只要把这个String写到一个文件中,就实现了文件下载的目的
 
			
			     摘要: 在我的上一篇文章中介绍了如何进行GPG加密解密。
 加密解密的基本操作流程是,用户使用公钥对明文进行加密,解密方使用私钥对密文进行解密。
 在实际应用中,除了加密保证文本内容不泄露外,同时还要考虑能够验证密文发送方的身份,比较普遍使用的方法就是签名。
 本文主要对具体的方法进行介绍并附上源代码。  阅读全文 
			
			Java程序中访问拥有全部读写权限的目录相对比较简单,和普通的目录没有什么差别。 但是要访问一个需要用户和密码验证的目录就需要一点点小技巧了。 这里介绍一个开源的库能够比较容易的实现这一需求。 1。 下载库文件:   https://jcifs.samba.org/ 下载的zip文件中, 不仅包含了jar文件,还有文档和示例。 2。拷贝jcif-1.3.18.jar到类路径中。 3。代码示例:  1     String user = "your_user_name";2     String pass ="your_pass_word";
 3
 4     String sharedFolder="shared";
 5     String path="smb://ip_address/"+sharedFolder+"/test.txt";
 6     NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("",user, pass);
 7     SmbFile smbFile = new SmbFile(path,auth);
 8     SmbFileOutputStream smbfos = new SmbFileOutputStream(smbFile);
 9     smbfos.write("testing
  .and writing to a file".getBytes()); 10     System.out.println("completed
  nice !"); 说明: 如果有一个共享目录,比如: \\192.168.1.2\testdir\ 那么smb的路径就是:smb://192.168.1.2/testdir/ NtlmPasswordAuthentication需要三个参数, 第一个是域名,没有的话,填null, 第二个是用户名,第三个是密码
 得到SmbFile之后,操作就和java.io.File基本一样了。
 另外还有一些功能比如:
 SmbFile.copyTo
 SmbFile.renameTo
 等等
 
 
			
			先将my.default.ini改名为my.ini放到bin目录
 命令行执行: mysqld --initialize --user=mysql --console
 先执行以上命令, 生成库. 注意有个临时密码, 要记下来. 安装服务:mysqld.exe --install MySql5.7 --defaults-file=c:\mysql\mysql5.7\my.ini
 然后启动服务.
 然后再命令行: mysql -uroot -p 输入密码, 再输入:  set password = password('root') 改密码成功, 然后就可以操作了. 
			
			如果只是在beforeSubmit()中 调用$('#fieldname').val(2)是不能成功修改表单的值的。 因为此时ajaxForm已经把表单中所有的内容存储在arr之中了。     $('#form1').ajaxForm({         beforeSubmit: function(arr){             for ( var i = 0; i < arr.length; i ++ ) {if ( arr[i].name == "fieldName1" ) {
 arr[i].value = '新的值';
 }
 }
 }
     });需要使用这种方式进行修改。 
			
			今天在运行myeclipse的时候,突然报nullPointerException. 具体的错误信息如下: Message: Errors running builder ‘DeploymentBuilder’ on project XXX’. Exception Stack Tracejava.lang.NullPointerException
 解决方法: 1. Shut down the workspace.  2. Delete the file com.genuitec.eclipse.ast.deploy.core.prefs which  is located at <workspace  dir>/.metadata/.plugins/org.eclipse.core.runtime/.settings/com.genuitec.eclipse.ast.deploy.core.prefs   3. Start the IDE.  
			
			  ipconfig /flushdns
 ipconfig /registerdns
 netsh winsock reset
 
 重新启动电脑。
 
			
			今天下载了Apache James 3.0 Beta 5, 文件名:james-server-app-3.0.0-beta5-20150627.102412-1076-app.zip 解压,运行run.bat 然后,注册domain james-cli --host localhost adddomain example.com 添加用户 james-cli.bat --host localhost adduser test@example.com password 然后测试发送邮件,客户端显示发送成功,但是james服务器报错,找不到MimeConfig的无参数构造函数。 解决方法: 使用旧的mime4j的jar包替换james 3.0 beta5中自带的最新包。 beta5中自带的是0.8.0版,apache网站中可以下载到0.7.2 下载apache-mime4j-0.7.2-bin.zip, 将其中的apache-mime4j-core-0.7.2.jar, apache-mime4j-dom-0.7.2.jar复制到james\lib目录, 并将其更名覆盖原有的 apache-mime4j-core-0.8.0-20150617.024907-738.jar apache-mime4j-dom-0.8.0-20150617.024927-735.jar重新启动james, 发送邮件, 成功。 
			
			     摘要: 解压/生成有密码保护的压缩文件, 研发过程中,作者研究了压缩文件格式文档: http://www.pkware.com/documents/casestudies/APPNOTE.TXT,并且参考了7-zip的实现。
阅读全文 
			
			     摘要: 花了两天时间终于把windows10安装好了,以下是我的一些个人的体会
阅读全文 
			
			在JfinalConfig的继承类中, configConstant() 需要设置me.setDevMode(true); 1. 只有在DevMode下,才能禁止freeMarker的缓存。 Configuration config = FreeMarkerRender.getConfiguration(); config.setTemplateUpdateDelayMilliseconds(0);才会生效
 
 
 2. 这时才会有JFinal Action Report日志输出
 
			
			本文将简单介绍如何使用PowerMock和Mockito来mock 
1. 构造函数 
2. 静态函数 
3. 枚举实现的单例 
4. 选择参数值做为函数的返回值 
5. 在调用mock出来的方法中,改变方法参数的值
 
一点简要说明:Mockito其实已经可以满足大部分的需求,但是它的实现机制是使用cglib来动态创建接口的类的实例。但是这种实现方式不能用于构造函数和静态函数,因为那需要使用类的字节码(比如使用javassist). 所以我们才需要结合使用PowerMock.
 
1. mock构造函数, 如果有代码没有使用DI注入依赖实例,在单元测试中可以使用PowerMock来模拟创建对象。 
注意的开始两行的2个注解 @RunWith 和 @PrepareForTest 
@RunWith比较简单,后面始终是PowerMockRunner.class 
@PrepareForText后面需要加的是调用构造函数的类名,而不是有构造函数的类本身。 
在下面的例子中,我们要测试的类是:Helper, 在Helper类中调用了Somthing类的构造函数来创建实例。
 @RunWith(PowerMockRunner.class)@PrepareForTest(Helper.class)
 public class HelperTest {
 @Mock
 private Something mockSomething;
 
 @InjectMocks
 private Helper helper;
 
 @Test
 public void doSomething() throws Exception {
 String argument = "arg";
 
 PowerMockito.whenNew(Something.class).withArguments(argument).thenReturn(mockSomething);
 
 // 调用需要测试方法
 helper.doSomething(argument);
 
 // 进行验证
 verify(mockSomething).doIt();
 }
 }
 
 
 
 public class Helper {public void doSomething(String arg) {
 Something something = new Something(arg);
 something.doit();
 }
 }
 
 
2,mock 静态函数, 单例模式就是一个典型的会调用静态函数的例子。 注意要点与mock构造函数相同。
 class ClassWithStatics {public static String getString() {
 return "String";
 }
 
 public static int getInt() {
 return 1;
 }
 }
 
 @RunWith(PowerMockRunner.class)
 @PrepareForTest(ClassWithStatics.class)
 public class StubJustOneStatic {
 @Test
 public void test() {
 PowerMockito.mockStatic(ClassWithStatics.class);
 
 when(ClassWithStatics.getString()).thenReturn("Hello!");
 
 System.out.println("String: " + ClassWithStatics.getString());
 System.out.println("Int: " + ClassWithStatics.getInt());
 }
 }
 
3。mock枚举实现的单例
 
SingletonObject.java  public class SingletonConsumer {public enum SingletonObject { INSTANCE;
 private int num;
 protected void setNum(int num) {
 this.num = num;
 }
 public int getNum() {
 return num;
 }
 }
 SingletonConsumer.java
     public String consumeSingletonObject() { return String.valueOf(SingletonObject.INSTANCE.getNum());
 }
 }
 
 SingletonConsumerTest.java
 @RunWith(PowerMockRunner.class) @PrepareForTest({SingletonObject.class})
 public class SingletonConsumerTest {
 @Test public void testConsumeSingletonObject() throws Exception {
 SingletonObject mockInstance = mock(SingletonObject.class);
 Whitebox.setInternalState(SingletonObject.class, "INSTANCE", mockInstance);
 when(mockInstance.getNum()).thenReturn(42);
 assertEquals("42", new SingletonConsumer().consumeSingletonObject());
 }
 }
4。返回参数值做为函数返回值。 
mockito 1.9.5之后,提供一个方便的方法来实现这个需要,在这之前可以使用一个匿名函数来返回一个answer来实现。
 
when(myMock.myFunction(anyString())).then(returnsFirstArg());
 
其中returnsFirstArg()是org.mockito.AdditionalAnswers中的一个静态方法。 
在这个类中还有其他的一些类似方法 
returnsSecondArg()
 returnsLastArg() ReturnsArgumentAt(int position) 5. 在调用mock出来的方法中,改变方法参数的值 when( myMock.someMethod( any( List.class ) ) ).thenAnswer( ( new Answer<Void>() {@Override
 public Void answer( InvocationOnMock invocation )
 throws Throwable {
 Object[] args = invocation.getArguments();
 List arg1 = (List)args[0];
 arg1.add("12345");
 return null;
 }
 } ) );
 
 
Verifying with generic parametersverify(someService).process(Matchers.<Collection<Person>>any()); 
 verify(adunoMasterBaseProcessor).processBinFiles( anyListOf(File.class) ); 
			
			Oracle提供的JDK其实已经自带一定程度的热加载功能,但是如果你修改了类名,方法名,或者添加了新类,新方法的话。 Tomcat都需要重新启动来使得刚才的更改生效。 而JRebel和springloaded都能有效地解决这个问题。其中springloaded是开源软件,可以免费使用,尤其难得。 其主页:https://github.com/spring-projects/spring-loaded 在官方页面的简单介绍中,作者只讲述了如何在java程序中应用springloaded,而没有说明如何在tomcat中进行配置。 本文将简要进行介绍。 1,下载springloaded到本地目录,比如:c:\temp\springloaded-1.2.3.RELEASE.jar 2. 修改tomcat的应用,禁止tomcat自己的热加载,方法是在META-INF目录下创建context.xml文件,里面包含如下语句,关键便是其中设置reloadable为false <?xml version="1.0" encoding="UTF-8"?><Context antiResourceLocking="false" privileged="true" useHttpOnly="true" reloadable="false" />
 3.在运行环境中添加springloaded的jar文件,在eclipse中右键点击项目,run as->run configuration 在弹出的窗口中,选择Arguments标签,在vm arguments的末尾添加: -javaagent:C:\temp\springloaded-1.2.3.RELEASE.jar -noverify 点击应用按钮。 以上便完成了所有的配置,步骤并不复杂。 
			
			java wrapper是一个可以用于将java应用程序包装成windows服务的工具。 并且可以通过简单的配置来允许使用visualVM进行监控。 配置方法: 在wrapper.conf中添加如下3行 wrapper.java.additional.1=-Dcom.sun.management.jmxremote.port=9898 #这里的端口号可以自行选择。wrapper.java.additional.2=-Dcom.sun.management.jmxremote.ssl=false
 wrapper.java.additional.3=-Dcom.sun.management.jmxremote.authenticate=false
 修改完毕保存后重新启动服务。 打开visualVM, 在菜单中选择 file->Add JMX Connection。 在弹出窗口中,connection一项中输入: localhost:9898 即可。 此配置对于jconsole也同样有效。 
			
			在一些历史遗留代码中,会用到java.util.logging. 如果在新的项目中引用了这些代码,而又不希望去一个一个的修改原来的代码。 可以使用slf4j提供的类来转接这部分的日志输出。 方法: 1、类路径中添加     slf4j-api-1.7.10.jar     jul-to-slf4j.1.7.10.jar ( 用于将java.util.logging的日志桥接到slf4j中)     logback-core.1.1.2.jar     logback-classic-1.1.2.jar 2、在代码中添加:          // Optionally remove existing handlers attached to j.u.l root loggerSLF4JBridgeHandler.removeHandlersForRootLogger();  // (since SLF4J 1.6.5)
 
 // add SLF4JBridgeHandler to j.u.l's root logger, should be done once during
 // the initialization phase of your application
 SLF4JBridgeHandler.install();
 注意事项: 1、这个桥接可以会造成性能问题。 和其他的桥接实现(比如:log4j, commons logging)不同,这个模块并不真正的完全替代java.util.logging类,因为这个java.util.logging是java自带的。 所以只是把原来的日志对象进行了转换,简单的说,这个转换过程是有开销的。 关键在于,不管日志语句有没有根据日志级别被关闭,这个转换无法避免。 2、不能在类路径中放入 slf4j-jkd14.jar jul-toslf4j.jar 
			
			 1. Text Editor: Notepad++/Syncplify.me Notepad!2. Browser: Chrome/Firefox
 3. 文件管理: XYplorer Lite/Explorer++/Q-Dir
 4. Mind map: XMind Free
 5. Video player: PotPlayer
 6. Music player: Kugou
 7. Mysql client: HeidiSql
 8. PDF reader: Foxit Reader
 9. File/Folder synchronize : FreeFileSync
 10. MP3 tools: Audacity/MP3 Gain
 11. Zip: 7-zip
 12. Partition Management: EaseUS Partition Master Free / MiniTool Free Partition Manager
 13. Data Recovery: EaseUS Data Recovery Wizard Free / MiniTool Free Data Recovery
 14. PDF Printer: PDF reDirect v2
 15. 个人信息管理: EssentialPIM Free Edition
 16. 远程登录: Terminals
 17. 文本比较合并: winmerge
 18. (s)FTP client: WinSCP
 19. 图像处理: GIMP
 
			
			Ember 是一个旨在创建大型web应用的JavaScript框架,它消除了样板(boilerplate)并提供了标准的应用程序架构。 
 Manning: Ember.js in action 第一章
 Manning: Ember.js in action 第五章
 
 
 
			
			先给一个例子:$http. get('/remote/item' ). then(function(response) {
 console.log('成功。');
 }, function(errResponse) {
 console. error('出错.' );
 });
 
 一。介绍Promise
 在这个例子中,$http.get()函数返回了一个Promise对象, 有了这个对象,我们才能很方便地直接在后面添加then函数的定义。
 Promise对象在AngularJS中是一个非常重要的存在。它提供了强大的功能和便利性。
 
 1。异步性
 从定义的语法上看,操作似乎是同步的,但是Promise的工作其实是异步的,只有在服务端返回数据后,后续的函数才会被调用。这是一个事件驱动,非阻塞式的框架。
 
 2。它避免了其它框架的嵌套回调函数的缺点。
 -所有异步任务都会返回一个Promise对象
 -每个Promise对象都有一个then函数,then函数有两个参数,分别是成功处理函数和失败处理函数
 -失败处理函数和成功处理函数都只会在异步处理完成后被调用一次
 -then函数也会返回Promise对象,这样,我们可以把多个函数串连起来成为一个函数链
 -成功处理函数和失败处理函数的返回值可以被传递到函数链下一个的函数中
 -如果在成功(或者失败)处理函数中,又开始了一个异步调用,那么函数链中的函数将会在这个异步调用结束后才开始
 
 二。异步链式调用的后续处理
 假如我们定义了如下的函数链:
 $http.get('/item').then(s1, e1).then(s2, e2).then(s3, e3);
 我们如何自主的根据函数链中每个函数的运行结果,决定触发后续函数的成功处理函数或者失败处理函数呢?
 比如说,在s1处理过程中,发生问题,于是我们触发了e2, 但是在e2处理完后,我们又想触发s3.
 AnguarJS提供了$q来满足这样的需求。
 如果我们想触发函数链中下一个函数的成功处理,我们只需要最后给出一个返回值,有了返回值,AngularJS会认为函数执行正确,自动调用下一个函数中的成功处理
 如果想触发失败处理,那么可以简单地返回$q.reject(data),这样就会触发下一个函数的失败处理
 
			
			在前文(http://www.blogjava.net/usherlight/archive/2015/02/01/422633.html)中我们曾经介绍过,定义controller时,需要2个参数,第一个参数是controller的名称,第二个参数是一个数组,数组的最后一个元素将是controller的函数,前面的参数是controller的依赖项。我们现在就来仔细分析一下其中的具体过程。 先给一个例子: angular. module('notesApp' , []). controller('MainCtrl' , ['$log' , function($log) {
 var self = this;
 self. logStuff = function() {
 $log. log('The button was pressed' );
 };
 }])
 在这个例子中可以看到,我们在第一个参数中用字符串(服务名称)添加了一个依赖项。当我们通过字符串声明了这一个服务之后,我们就可以把它当作一个变量注入到函数中。AngularJS会自动查找字符串名称对应的服务名,按照顺序将其注入到函数中。 myModule.controller("MainCtrl",  ["$log", "$window", function($l, $w) {}]);在这个例子中,$log, $windows是AngularJS自带的两个服务,在数组中通过名称声明后,会被注入到函数的两个参数中。
 比较常用的AngularJS自带的服务有:$window, $location, $http等
 
 从上面的例子中可以看出,AngularJS的设计思想就是不要在函数中自己去实例化或者通过其它途径来获取服务的实例,而是声明需要的对象,由AngularJS来注入具体的实例。
 
 创建自己的服务
 什么时候应该创建服务,而不是controller呢?
 1。 需要重用的时候
 2。需要保留应用级的状态。这是非常重要的一点,controller是会不断地被创建和销毁的,如果需要保存应用级的状态,就需要使用service
 3。和页面显示无关
 4。需要和第三方服务整合
 5。缓存
 
 服务是会被延迟加载的,也就是说只有在第一次被引用的时候,才会被创建。
 服务将会被定义一次,也只会被实例化一次。
 
 
			
			     摘要: 默认情况下,每隔一秒种,SpringLoaded就会扫描类路径,自动加载改变过的类, 而不需要重新启动应用  阅读全文 
			
			07. ng-repeart 	a. 在循环map的时候,会自动根据键值进行排序。 	b. 一些自带的变量,$first(是否是第一个), $last(是否是最后一个), $middle(是否是中间的), $index(下标,根据键值排序后的下标), $even, $odd 08. 自己定义新变量时不要使用$$开头。 09. 可以使用track-by表达式来优化对DOM的操作,对DOM对象使用从数据库取得的ID来进行标记,这样的话,当我们重复多次从数据库中取出相同的数据的时候,DOM对象就能够被重用。 10. 数据双向绑定的好处 	a. 如果我们想改变页面Form中的数值,我们不需要在Javascript中,根据ID或者名称来查找相应的Form控件,只需要改变Controller变量的值,不需要JQuery的Selector,也不需要findElementByID 	b. 如果我们想在javascript中获取Form控件的值,在控件的变量中就能直接获得。 11. 使用ng-submit比在button上使用ng-click要好一些。HTML的表单的提交有多种方式,比如在输入域中按回车键就会触发ng-submit,而不会触发button的ng-click事件。 12. 在ng-model中,可以直接引用一个对象,比如:<input type="text" ng-model="ctrl.user.name">,而不需要事先在model中以self.user={}定义。在AngularJS中,使用了ng-model的话,AngularJS在初始化数据绑定的时候,自动创建其中的对象和键值。在刚才的例子中,一旦用户开始在输入域中键入第一个字母,用户user就会被自动创建。 13. 推荐使用将相关数据集中到一个对象的方式来进行数据绑定,比如,用户名和密码,推荐使用: 	<input type="text" ng-model="ctrl.user.name"> 	<input type="text" ng-model="ctrl.user.password"> 而不是: 	<input type="text" ng-model="ctrl.name"> 	<input type="text" ng-model="ctrl.password"> 
			
			1. AngularJS的module函数有两种用法, 	a. 定义一个module, 需要传入2个参数,module('moduleName', []), 第一个参数是新的module名称,第二个参数是新module所依赖的module数组。 	b. 载入一个module, 只需要1个参数,module('moduleName'), 唯一的一个参数指定要载入的module名称。 2. 使用controller函数来定义一个控制器(controller), 用ng-controller将控制器绑定到具体的HTML组件上。定义控制器的controller函数也需要2个参数,第一个是控制器名称,第二个参数同样也是一个数组,数组的最后一个元素就是controller本身的函数,前面的元素用字符串的形式指定其需要的依赖项。如果没有依赖项,那就只需要定义函数。比如: 	angular.module('app1', [])  .controller('mainControl', [function() {  console.log('controller created.');  }]); 3. 在controller函数中用var定义的局部变量,在HTML中是不可见的。 4. 推荐在controller函数中尽量避免直接引用this, 比较好的做法是使用代理。原因是一个函数中的this关键词在被外部调用的时候,是会被覆盖掉的。这样的话,在函数内部和外部的this会是完全不同两个对象。 代理用法示例: 	angular.module('app1', [])  .controller('mainControl', [function() {  var self = this;  self.message = 'Hello world';  self.changeMessage = function() {  self.message = 'Goodbye.';  };  }]); 5. ng-bind与双大括号的区别, ng-bind和{{}}可以说基本上是可以互相替换的,但是也有区别。区别在于:AngularJS在启动的时候就会执行ng-bind, 而{{}}的替换时间会稍晚一些。有可能发现页面在加载的时候,双括号被一闪而过地替换掉(只在页面初次加载的时候发生)。但是ng-bind就没有这个问题。6. ng-cloak可以用于解决双括号闪现的问题。
 
			
			1. HTML页面的加载,这会触发加载页面包含的所有JS (包括 AngularJS) 2. AngularJS启动,搜寻所有的指令(directive) 3. 找到ng-app,搜寻其指定的模块(Module),并将其附加到ng-app所在的组件上。 4. AnguarJS遍历所有的子组件,查找指令和bind命令 5. 每次发现ng-controller或者ng-repeart的时候,它会创建一个作用域(scope),这个作用域就是组件的上下文。作用域指明了每个DOM组件对函数、变量的访问权。 6. AngularJS然后会添加对变量的监听器,并监控每个变量的当前值。一旦值发生变化,AngularJS会更新其在页面上的显示。 7. AngularJS优化了检查变量的算法,它只会在某些特殊的事件触发时,才会去检查数据的更新,而不是简单地在后台不停地轮询。 
			
			Java虚拟机规范规定JVM的内存分为了好几块,比如堆,栈,程序计数器,方法区等,而Hotspot jvm的实现中,将堆内存分为了三部分,新生代,老年代,持久带,其中持久带实现了规范中规定的方法区,而内存模型中不同的部分都会出现相应的OOM错误,接下来我们就分开来讨论一下。 栈溢出(StackOverflowError) 栈溢出抛出java.lang.StackOverflowError错误,出现此种情况是因为方法运行的时候栈的深度超过了虚拟机容许的最大深度所致。 出现这种情况,一般情况下是程序错误所致的,比如写了一个死递归,就有可能造成此种情况。 下面我们通过一段代码来模拟一下此种情况的内存溢出。 运行上面的代码,会抛出如下的异常:import java.util.*;  import java.lang.*;  public class OOMTest{       public void stackOverFlowMethod(){        stackOverFlowMethod();    }       public static void main(String... args){        OOMTest oom = new OOMTest();        oom.stackOverFlowMethod();    }     }  
引用 堆溢出(OutOfMemoryError:java heap space) 堆内存溢出的时候,虚拟机会抛出java.lang.OutOfMemoryError:java heap space,出现此种情况的时候,我们需要根据内存溢出的时候产生的dump文件来具体分析(需要增加-XX:+HeapDumpOnOutOfMemoryErrorjvm启动参数)。出现此种问题的时候有可能是内存泄露,也有可能是内存溢出了。 如果内存泄露,我们要找出泄露的对象是怎么被GC ROOT引用起来,然后通过引用链来具体分析泄露的原因。 如果出现了内存溢出问题,这往往是程序本生需要的内存大于了我们给虚拟机配置的内存,这种情况下,我们可以采用调大-Xmx来解决这种问题。 下面我们通过如下的代码来演示一下此种情况的溢出:Exception in thread "main" java.lang.StackOverflowError
 at OOMTest.stackOverFlowMethod(OOMTest.java:6)
 我们通过如下的命令运行上面的代码:import java.util.*;  import java.lang.*;  public class OOMTest{             public static void main(String... args){                  List<byte[]> buffer = new ArrayList<byte[]>();                  buffer.add(new byte[10*1024*1024]);          }     }  
程序输入如下的信息:java -verbose:gc -Xmn10M -Xms20M -Xmx20M -XX:+PrintGC OOMTest  
引用 从运行结果可以看出,JVM进行了一次Minor gc和两次的Major gc,从Major gc的输出可以看出,gc以后old区使用率为134K,而字节数组为10M,加起来大于了old generation的空间,所以抛出了异常,如果调整-Xms21M,-Xmx21M,那么就不会触发gc操作也不会出现异常了。 通过上面的实验其实也从侧面验证了一个结论:当对象大于新生代剩余内存的时候,将直接放入老年代,当老年代剩余内存还是无法放下的时候,出发垃圾收集,收集后还是不能放下就会抛出内存溢出异常了 持久带溢出(OutOfMemoryError: PermGen space) 我们知道Hotspot jvm通过持久带实现了Java虚拟机规范中的方法区,而运行时的常量池就是保存在方法区中的,因此持久带溢出有可能是运行时常量池溢出,也有可能是方法区中保存的class对象没有被及时回收掉或者class信息占用的内存超过了我们配置。当持久带溢出的时候抛出java.lang.OutOfMemoryError: PermGen space。 我在工作可能在如下几种场景下出现此问题。 1.使用一些应用服务器的热部署的时候,我们就会遇到热部署几次以后发现内存溢出了,这种情况就是因为每次热部署的后,原来的class没有被卸载掉。 2.如果应用程序本身比较大,涉及的类库比较多,但是我们分配给持久带的内存(通过-XX:PermSize和-XX:MaxPermSize来设置)比较小的时候也可能出现此种问题。 3.一些第三方框架,比如spring,hibernate都通过字节码生成技术(比如CGLib)来实现一些增强的功能,这种情况可能需要更大的方法区来存储动态生成的Class文件。 我们知道Java中字符串常量是放在常量池中的,String.intern()这个方法运行的时候,会检查常量池中是否存和本字符串相等的对象,如果存在直接返回对常量池中对象的引用,不存在的话,先把此字符串加入常量池,然后再返回字符串的引用。那么我们就可以通过String.intern方法来模拟一下运行时常量区的溢出.下面我们通过如下的代码来模拟此种情况:[GC 1180K->366K(19456K), 0.0037311 secs]
 [Full GC 366K->330K(19456K), 0.0098740 secs]
 [Full GC 330K->292K(19456K), 0.0090244 secs]
 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
 at OOMTest.main(OOMTest.java:7)
 我们通过如下的命令运行上面代码: java -verbose:gc -Xmn5M -Xms10M -Xmx10M -XX:MaxPermSize=1M -XX:+PrintGC OOMTest 运行后的输入如下图所示:import java.util.*;  import java.lang.*;  public class OOMTest{             public static void main(String... args){                  List<String> list = new ArrayList<String>();                  while(true){                          list.add(UUID.randomUUID().toString().intern());                  }          }     }  
引用 通过上面的代码,我们成功模拟了运行时常量池溢出的情况,从输出中的PermGen space可以看出确实是持久带发生了溢出,这也验证了,我们前面说的Hotspot jvm通过持久带来实现方法区的说法。 OutOfMemoryError:unable to create native threadException in thread "main" java.lang.OutOfMemoryError: PermGen space
 at java.lang.String.intern(Native Method)
 at OOMTest.main(OOMTest.java:8)
 最后我们在来看看java.lang.OutOfMemoryError:unable to create natvie thread这种错误。 出现这种情况的时候,一般是下面两种情况导致的: 1.程序创建的线程数超过了操作系统的限制。对于Linux系统,我们可以通过ulimit -u来查看此限制。 给虚拟机分配的内存过大,导致创建线程的时候需要的native内存太少。我们都知道操作系统对每个进程的内存是有限制的,我们启动Jvm,相当于启动了一个进程,假如我们一个进程占用了4G的内存,那么通过下面的公式计算出来的剩余内存就是建立线程栈的时候可以用的内存。 线程栈总可用内存=4G-(-Xmx的值)- (-XX:MaxPermSize的值)- 程序计数器占用的内存 通过上面的公式我们可以看出,-Xmx 和 MaxPermSize的值越大,那么留给线程栈可用的空间就越小,在-Xss参数配置的栈容量不变的情况下,可以创建的线程数也就越小。因此如果是因为这种情况导致的unable to create native thread,那么要么我们增大进程所占用的总内存,或者减少-Xmx或者-Xss来达到创建更多线程的目的。
 |