|
2010年9月13日
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/config and change the URLs there
也可以在git视图中,右键点击项目,选择属性,然后修改url中的地址
autohotkey listary 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
Error com.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 Trace java.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 enum SingletonObject { INSTANCE; private int num; protected void setNum(int num) { this.num = num; } public int getNum() { return num; } }
SingletonConsumer.java
public class SingletonConsumer {
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 parameters
verify(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 logger SLF4JBridgeHandler.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();
- }
-
- }
运行上面的代码,会抛出如下的异常: 引用 Exception in thread "main" java.lang.StackOverflowError at OOMTest.stackOverFlowMethod(OOMTest.java:6) 堆溢出(OutOfMemoryError:java heap space) 堆内存溢出的时候,虚拟机会抛出java.lang.OutOfMemoryError:java heap space,出现此种情况的时候,我们需要根据内存溢出的时候产生的dump文件来具体分析(需要增加-XX:+HeapDumpOnOutOfMemoryErrorjvm启动参数)。出现此种问题的时候有可能是内存泄露,也有可能是内存溢出了。 如果内存泄露,我们要找出泄露的对象是怎么被GC ROOT引用起来,然后通过引用链来具体分析泄露的原因。 如果出现了内存溢出问题,这往往是程序本生需要的内存大于了我们给虚拟机配置的内存,这种情况下,我们可以采用调大-Xmx来解决这种问题。 下面我们通过如下的代码来演示一下此种情况的溢出: - 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
程序输入如下的信息: 引用 [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) 从运行结果可以看出,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方法来模拟一下运行时常量区的溢出.下面我们通过如下的代码来模拟此种情况: - 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());
- }
- }
-
- }
我们通过如下的命令运行上面代码: java -verbose:gc -Xmn5M -Xms10M -Xmx10M -XX:MaxPermSize=1M -XX:+PrintGC OOMTest 运行后的输入如下图所示: 引用 Exception in thread "main" java.lang.OutOfMemoryError: PermGen space at java.lang.String.intern(Native Method) at OOMTest.main(OOMTest.java:8) 通过上面的代码,我们成功模拟了运行时常量池溢出的情况,从输出中的PermGen space可以看出确实是持久带发生了溢出,这也验证了,我们前面说的Hotspot jvm通过持久带来实现方法区的说法。 OutOfMemoryError:unable to create native thread 最后我们在来看看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来达到创建更多线程的目的。
现在的显示屏都在飚像素,商家的宣传一个比一个噱头大,什么 Retina、4K、8K 这种名词一个接一个的出来, 这些到底都是啥意思? 首先,Retina 和 4K 以及 8K 并不是同一层面的定义。屏幕一般是以像素点做单位的,4K 和 8K 就是直接限定了像素点的多少,而 Retina 则是没有硬性的规范。Retina 屏幕的概念最早由苹果公司执行长史蒂夫·乔布斯(Steve Jobs)于 WWDC2010 发布 iPhone 4 时提出的。 定义是:要求在正常观看距离下,足以使人肉眼无法分辨其中的单独像素。因此它并没有限定像素值多少。
4K 就是水平方向每一行的像素值达到或是接近 1024 的 4 倍,8K 就是达到或接近 8 倍。 以此为标准,4K 一般图像就是指 4096*2160 的分辨率。当然,这也不是硬性要求,像市场上很多 4K 屏幕其实是 3840*2160 或是 3656*2664,这些都是 4K 图像分辨率的范畴。 8K 就是分辨率在 7680*4320 左右。
顺便说一下,720p 则是指竖直方向的像素点达到 720 个,1080p 则是 1080 个,“P”是逐行扫描的意思
问:那到底 Retina 和 4K 或是 Retina 和 8K 哪个更清楚呢? 答:不一定,二者不能平行比较。 因为 4K 和 8K 是限定了像素点的多少,而 Retina 是要求正常距离看不到像素点。 举个例子:如果放到正常的 42 寸屏幕上,4K 和 8K 在正常距离观看下都看不到像素点,那么两者都可以被称作“Retina 屏幕”。
可是如果给你一台 500 寸的巨大屏幕,那么即便是 8K 也会到处是马赛克,这时 Retina 观感依然是高清无像素点,必然比 8K 和 4K 清楚的多。
Last_SQL_Error: Error 'Lock wait timeout exceeded; try restarting transaction' on query. Default database: 'test'. Query: 'DELETE FROM table1 WHERE id = 361' 1 row in set (0.00 sec)
solution: restart slave;
stop slave; start slave;
1. server.xml 在<engine>中添加 <Realm className="org.apache.catalina.realm.MemoryRealm" /> 2. tomcat-user.xml <role rolename="manager"/> <role rolename="manager-gui"/>
<user username="admin" password="tomcat" roles="manager"/>
1. 自动扫描配置文件改动
<configuration scan="true" scanPeriod="30 seconds">
....
</configuration
2. 日志每天归档,同时目录名包含相应的年份和月份
<fileNamePattern>F:\Programs\GlobalPos\GatewayCiti\logs\%d{yyyy/MM,aux}\G%d{dd}-%i.log</fileNamePattern>
注意其中aux的使用,在fileNamePatter中如果出现多个%d的情况下,只能有一个为主配置,其他都需要使用aux标记为附属配置
其中的%i请参看下节的介绍
3. 文件同时根据日期和大小滚动创建
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily -->
<!--
<fileNamePattern>F:\Programs\GlobalPos\NetReport\logs\Portal-%d{yyyyMMdd}.log</fileNamePattern>
-->
<!-- Size and time based archiving -->
<fileNamePattern>D:\logs\%d{yyyy/MM,aux}\L%d{dd}-%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
fileNamePattern在上一节已经介绍,这里主要介绍timeBasedFileNamingAndTriggeringPolicy,此处配置对文件大小的限定,由fileNamePattern的%i在确定下标在文件名中的位置
此示例产生的日志文件将会是:
D:\logs\2015\01\L05-0.log 如果该文件大于100M,就会生成D:\logs\2015\01\L05-1.log
OpenPGP 号称是世界上使用最广泛的邮件加密标准. OpenPGP is the most widely used email encryption standard in the world. ( http://www.openpgp.org/ ) 这篇例子介绍如何使用这个标准进行文件的加密解密 (https://www.bouncycastle.org/latest_releases.html, 需要下载: bcprov-jdk15on-151.jar, bcpg-jdk15on-151.jar). 主要是使用bouncycastle提供的OpenPGP的库来完成这个功能,参照了其提供的示例程序,进行了部分改动 ( Bouncy Castle 是一种用于 Java 平台的开放源码的轻量级密码术包。它支持大量的密码术算法,并提供 JCE 1.2.1 的实现。因为 Bouncy Castle 被设计成轻量级的,所以从 J2SE 1.4 到 J2ME(包括 MIDP)平台,它都可以运行。它是在 MIDP 上运行的唯一完整的密码术包。)1. 添加循环遍历来查找第一个可用的message 2. 需要注意的是在main函数中的, 如果不添加这一句的话 Security.addProvider(new BouncyCastleProvider()); 程序运行中会报错:No such Provider "BC" 3. 错误Exception in thread "main" java.security.InvalidKeyException: Illegal key size or default parameters , 这是因为java缺省的库支持的key长度比较短,需要到oracle的网站上去下载一个支持更长key的库覆盖原有的库文件 <JAVA_HOME>/lib/securty/ 目录下的两个jar文件 local_policy.jar and US_export_policy.jar 搜索这个文件: Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files
package org.bouncycastle.openpgp.examples;
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.Security; import java.util.Iterator;
import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.bcpg.CompressionAlgorithmTags; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.PGPCompressedData; import org.bouncycastle.openpgp.PGPEncryptedData; import org.bouncycastle.openpgp.PGPEncryptedDataGenerator; import org.bouncycastle.openpgp.PGPEncryptedDataList; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPLiteralData; import org.bouncycastle.openpgp.PGPOnePassSignatureList; import org.bouncycastle.openpgp.PGPPrivateKey; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.bouncycastle.openpgp.PGPSignatureList; import org.bouncycastle.openpgp.PGPUtil; import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory; import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; import org.bouncycastle.util.io.Streams;
/** * A simple utility class that encrypts/decrypts public key based * encryption files. * <p> * To encrypt a file: KeyBasedFileProcessor -e [-a|-ai] fileName publicKeyFile.<br> * If -a is specified the output file will be "ascii-armored". * If -i is specified the output file will be have integrity checking added. * <p> * To decrypt: KeyBasedFileProcessor -d fileName secretKeyFile passPhrase. * <p> * Note 1: this example will silently overwrite files, nor does it pay any attention to * the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase * will have been used. * <p> * Note 2: if an empty file name has been specified in the literal data object contained in the * encrypted packet a file with the name filename.out will be generated in the current working directory. */ public class KeyBasedFileProcessor { private static void decryptFile( String inputFileName, String keyFileName, char[] passwd, String defaultFileName) throws IOException, NoSuchProviderException { InputStream in = new BufferedInputStream(new FileInputStream(inputFileName)); InputStream keyIn = new BufferedInputStream(new FileInputStream(keyFileName)); decryptFile(in, keyIn, passwd, defaultFileName); keyIn.close(); in.close(); }
/** * decrypt the passed in message stream */ private static void decryptFile( InputStream in, InputStream keyIn, char[] passwd, String defaultFileName) throws IOException, NoSuchProviderException { in = PGPUtil.getDecoderStream(in); try { JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in); PGPEncryptedDataList enc;
Object o = pgpF.nextObject(); // // the first object might be a PGP marker packet. // if (o instanceof PGPEncryptedDataList) { enc = (PGPEncryptedDataList)o; } else { enc = (PGPEncryptedDataList)pgpF.nextObject(); } // // find the secret key // Iterator it = enc.getEncryptedDataObjects(); PGPPrivateKey sKey = null; PGPPublicKeyEncryptedData pbe = null; PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection( PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator());
while (sKey == null && it.hasNext()) { pbe = (PGPPublicKeyEncryptedData)it.next(); sKey = PGPExampleUtil.findSecretKey(pgpSec, pbe.getKeyID(), passwd); } if (sKey == null) { throw new IllegalArgumentException("secret key for message not found."); } InputStream clear = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey)); JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear); Object message = plainFact.nextObject(); while ( true ) { if (message instanceof PGPCompressedData) { PGPCompressedData cData = (PGPCompressedData)message; JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(cData.getDataStream()); message = pgpFact.nextObject(); } if (message instanceof PGPLiteralData) { PGPLiteralData ld = (PGPLiteralData)message;
String outFileName = ld.getFileName(); if (outFileName.length() == 0) { outFileName = defaultFileName; }
InputStream unc = ld.getInputStream(); OutputStream fOut = new BufferedOutputStream(new FileOutputStream(outFileName));
Streams.pipeAll(unc, fOut);
fOut.close(); break; } else if (message instanceof PGPOnePassSignatureList) { System.out.println("encrypted message contains a signed message - not literal data."); } else if (message instanceof PGPSignatureList) { System.out.println("encrypted message contains a signed message - not literal data."); } else { throw new PGPException("message is not a simple encrypted file - type unknown."); } message = plainFact.nextObject(); } if (pbe.isIntegrityProtected()) { if (!pbe.verify()) { System.err.println("message failed integrity check"); } else { System.err.println("message integrity check passed"); } } else { System.err.println("no message integrity check"); } } catch (PGPException e) { System.err.println(e); if (e.getUnderlyingException() != null) { e.getUnderlyingException().printStackTrace(); } } }
private static void encryptFile( String outputFileName, String inputFileName, String encKeyFileName, boolean armor, boolean withIntegrityCheck) throws IOException, NoSuchProviderException, PGPException { OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFileName)); PGPPublicKey encKey = PGPExampleUtil.readPublicKey(encKeyFileName); encryptFile(out, inputFileName, encKey, armor, withIntegrityCheck); out.close(); }
private static void encryptFile( OutputStream out, String fileName, PGPPublicKey encKey, boolean armor, boolean withIntegrityCheck) throws IOException, NoSuchProviderException { if (armor) { out = new ArmoredOutputStream(out); }
try { byte[] bytes = PGPExampleUtil.compressFile(fileName, CompressionAlgorithmTags.ZIP);
PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator( new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck).setSecureRandom(new SecureRandom()).setProvider("BC"));
encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("BC"));
OutputStream cOut = encGen.open(out, bytes.length);
cOut.write(bytes); cOut.close();
if (armor) { out.close(); } } catch (PGPException e) { System.err.println(e); if (e.getUnderlyingException() != null) { e.getUnderlyingException().printStackTrace(); } } }
public static void main( String[] args) throws Exception { Security.addProvider(new BouncyCastleProvider());
if (args.length == 0) { System.err.println("usage: KeyBasedFileProcessor -e|-d [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]"); return; }
if (args[0].equals("-e")) { if (args[1].equals("-a") || args[1].equals("-ai") || args[1].equals("-ia")) { encryptFile(args[2] + ".asc", args[2], args[3], true, (args[1].indexOf('i') > 0)); } else if (args[1].equals("-i")) { encryptFile(args[2] + ".bpg", args[2], args[3], false, true); } else { encryptFile(args[1] + ".bpg", args[1], args[2], false, false); } } else if (args[0].equals("-d")) { decryptFile(args[1], args[2], args[3].toCharArray(), new File(args[1]).getName() + ".out"); } else { System.err.println("usage: KeyBasedFileProcessor -d|-e [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]"); } } } asdf
Netty作为一个异步非阻塞式的框架,是不允许在ChannelHandler中长时间处理事务(比如数据库的操作),阻塞I/O的读写处理的。 在Netty in Action中是这样描述的:
While the I/O thread must not be blocked at all, thus prohibiting any direct blocking operations within your ChannelHandler, there is a way to implement this requirement. You can specify an EventExecutorGroup when adding ChannelHandlers to the ChannelPipeline. This EventExecutorGroup will then be used to obtain an EventExecutor, which will execute all the methods of the ChannelHandler. This EventExecutor will use a different thread from the I/O thread, thus freeing up the EventLoop. I/O线程是不允许被阻塞的,也就是不能在ChannelHandler中进行任何阻塞式的处理,但是对此我们也有相应的解决方法. 就是在把ChannelHanders添加到ChannelPipeline的时候,指定一个EventExecutorGroup,ChannelHandler中所有的方法都将会在这个指定的EventExecutorGroup中运行。 而这个EVentExecutorGroup运行的线程与I/O线程不同,达到不阻塞I/O的目的。 程序示例如下: Channel ch = ...; ChannelPipeline p = ch.pipeline(); EventExecutor e1 = new DefaultEventExecutorGroup(16); EventExecutor e2 = new DefaultEventExecutorGroup(8); p.addLast(new MyProtocolCodec()); p.addLast(e1, new MyDatabaseAccessingHandler()); p.addLast(e2, new MyHardDiskAccessingHandler()); 需要补充说明一下,上面的示例程序似乎有点问题。使用上述方法添加ChannelHandler到pipeline中以后,channelHandler的所有方法确实什么在一个单独的线程中被处理。 但是,每次DefaultEventExcutorGroup线程池中的线程不能被重用,每次都会生成一个新的线程,然后在新的线程中调用ChannelHandler, 在visualvm可以看到线程数量直线增长。 解决的方法是:不能使用局部变量形式的DefaultEventExecutorGroup。而使用类静态成员变量: static final EventExecutor e1 = new DefaultEventExecutorGroup(16); 我分析原因可能是:在新的连接到来,创建ChannelPipeline给新Channel的时候,如果不使用静态的共享变量,而使用局部变量的话,就造成DefaultEventExecutorGroup被多次重复创建。因此,虽然一个DefaultEventExecutorGroup中的Thread数量是固定的,但是却产生了多余的DefaultEventExecutorGroup。从VisualVM中也可以看到,DefaultEventExecutorGroup线程的名字会是: xxx-2-1 xxx-3-1 xxx-4-1 xxx-n-1 说明是Group的数量(第一个数字)在增多,而不是Group中的线程数量(第二个数字)在增多 改成静态变量后,线程名会是: xxx-2-1 xxx-2-2 xxx-2-3 xxx-2-n 最后一个n就是在创建DefaultEventExecutorGroup时候,传入的线程个数参数的大小。
Netty 1. there're 2 EventLoopGroup in netty, bossGroup and workerGroup, (1 implementation NioEventLoopGroup is a kind of thread pool) 2. bossGroup is Acceptor,is responsible for creating Channels for incoming connection requests 3. workerGroup is the Reactor/Selector?, handling I/O requests. 4. a thread in bossGroup will be listening in the port, Once a connection has been accepted workerGroup assigns an EventLoop to its Channel 5. multiple channels can be registered into 1 EventLoop, multiple EventLoops will exist in workerGroup 6. workerGroup will iterate all the EventLoop, and iterate all the channels in EventLoop, if any of the channel is ready to execute/process 7. it will invoke all the channelHandlers in the channelPipeline 8. ChannelPipelines are containers for chains of ChannelHandlers which executed in order 9. There are, in fact, two ways of sending messages in Netty. You can write directly to the Channel or write to the ChannelHandlerContext object. The main difference is that the former approach causes the message to start from the tail of the ChannelPipeline, while the latter causes the message to start from the next handler in the ChannelPipeline. 10. While the I/O thread must not be blocked at all, thus prohibiting any direct blocking operations within your ChannelHandler, there is a way to implement this requirement. You can specify an EventExecutorGroup when adding ChannelHandlers to the ChannelPipeline. This EventExecutorGroup will then be used to obtain an EventExecutor, which will execute all the methods of the ChannelHandler. This EventExecutor will use a different thread from the I/O thread, thus freeing up the EventLoop. Channel ch = ...; ChannelPipeline p = ch.pipeline(); EventExecutor e1 = new DefaultEventExecutor(16); EventExecutor e2 = new DefaultEventExecutor(8); p.addLast(new MyProtocolCodec()); p.addLast(e1, new MyDatabaseAccessingHandler()); p.addLast(e2, new MyHardDiskAccessingHandler()); http://stackoverflow.com/questions/12928723/netty-4-eventloopgroup-eventloop-eventexecutor-thread-affinity
http://denis.doublebuffer.net/lablog/2012/11/19/fixing-the-screen-flickering-on-a-dell-inspiron-n5720-and-maybe-many-others/ A Dell Inspiron N5720 has a nVidia GT 630M and an Intel HD Graphics 4000. Let’s see what the Intel Graphics Control panel looks like. To open it, follow these instructions. Select Advanced mode. Go to the Power menu and change the power source to “On battery”. Now uncheck the little check box that says “Display Refresh Rate Switch”. Apply. OK. And you’re done.
Where are the Database Files Stored?When using database URLs like jdbc:h2:~/test , the database is stored in the user directory. For Windows, this is usually C:\Documents and Settings\<userName> or C:\Users\<userName> . If the base directory is not set (as in jdbc:h2:test ), the database files are stored in the directory where the application is started (the current working directory). When using the H2 Console application from the start menu, this is<Installation Directory>/bin . The base directory can be set in the database URL. A fixed or relative path can be used. When using the URL jdbc:h2:file:data/sample , the database is stored in the directory data (relative to the current working directory). The directory is created automatically if it does not yet exist. It is also possible to use the fully qualified directory name (and for Windows, drive name). Example:jdbc:h2:file:C:/data/tes
在主动模式下,FTP客户端随机开启一个大于1024的端口N向服务器的21号端口发起连接,然后开放N+1号端口进行监听,并向服务器发出PORT N+1命令。服务器接收到命令后,会用其本地的FTP数据端口(通常是20)来连接客户端指定的端口N+1,进行数据传输。 在被动模式下,FTP库户端随机开启一个大于1024的端口N向服务器的21号端口发起连接,同时会开启N+1号端口。然后向服务器发送PASV命令,通知服务器自己处于被动模式。服务器收到命令后,会开放一个大于1024的端口P进行监听,然后用PORT P命令通知客户端,自己的数据端口是P。客户端收到命令后,会通过N+1号端口连接服务器的端口P,然后在两个端口之间进行数据传输。 总的来说,主动模式的FTP是指服务器主动连接客户端的数据端口,被动模式的FTP是指服务器被动地等待客户端连接自己的数据端口。
被动模式的FTP通常用在处于防火墙之后的FTP客户访问外界FTp服务器的情况,因为在这种情况下,防火墙通常配置为不允许外界访问防火墙之后主机,而只允许由防火墙之后的主机发起的连接请求通过。 因此,在这种情况下不能使用主动模式的FTP传输,而被动模式的FTP可以良好的工作。
Standard模式FTP 客户端首先和FTP Server的TCP 21端口建立连接,通过这个通道发送命令,客户端需要接收数据的时候在这个通道上发送PORT命令。 PORT命令包含了客户端用什么端口接收数据。 在传送数据的时候,服务器端通过自己的TCP 20端口发送数据。 FTP server必须和客户端建立一个新的连接用来传送数据。 Passive模式在建立控制通道的时候和Standard模式类似,当客户端通过这个通道发送PASV 命令的时候,FTP server打开一个位于1024和5000之间的随机端口并且通知客户端在这个端口上传送数据的请求, 然后FTP server 将通过这个端口进行数据的传送,这个时候FTP server不再需要建立一个新的和客户端之间的连接。
java.awt.Desktop is the class you're looking for.
import java.awt.Desktop; import java.net.URI; // ... if(Desktop.isDesktopSupported()) { Desktop.getDesktop().browse(new URI("http://www.example.com")); }
If you're using Java 6 or above, see the Desktop API, in particular browse. Use it like this (not tested):
// using this in real life, you'd probably want to check that the desktop
// methods are supported using isDesktopSupported()...
String htmlFilePath = "path/to/html/file.html"; // path to your new file
File htmlFile = new File(htmlFilePath);
// open the default web browser for the HTML page
Desktop.getDesktop().browse(htmlFile.toURI());
// if a web browser is the default HTML handler, this might work too
Desktop.getDesktop().open(htmlFile);
例子: java -cp bin;lib/* org.kevin.task.RunJobA f:\temp\jobs 1.路径中需要使用/,而不是\\, 2.只能用一个*,不需要添加后缀,
P66 1. components: a. Message a.1 Header a.1.1 Destination a.1.2 DeliveryMode: persistent, non-persistent a.2 Body b. Queue c. Client c.1 Producer c.2 Consumer - Message Selector d. Domain, 2 styles of messaging d.1 point-to-point d.1.1 destination known as QUEUE d.1.2 similar to person to person email sent through a mail server d.1.3 multiple consumers can be registered on a single queue but only one consumer will receive a a given messge and it's upt to that consumer to acknowledge the message d.2 publish-subscribe d.2.1 destination known as TOPICS d.2.2 publishers send messages to the topic and subscribers register to receive messages from the topic d.2.3 durable subscriptions allow for subscriber disconnection without missing any messages
最近在开发中遇到一个问题,就是如何判断远端服务器是否已经断开连接,如果断开那么需要重新连接。 首先想到socket类的方法isClosed()、isConnected()、isInputStreamShutdown()、isOutputStreamShutdown()等,但经过试验并查看相关文档,这些方法都是本地端的状态,无法判断远端是否已经断开连接。 然后想到是否可以通过OutputStream发送一段测试数据,如果发送失败就表示远端已经断开连接,类似ping,但是这样会影响到正常的输出数据,远端无法把正常数据和测试数据分开。 最后又回到socket类,发现有一个方法sendUrgentData,查看文档后得知它会往输出流发送一个字节的数据,只要对方Socket的SO_OOBINLINE属性没有打开,就会自动舍弃这个字节,而SO_OOBINLINE属性默认情况下就是关闭的,太好了,正是我需要的! 于是,下面一段代码就可以判断远端是否断开了连接: Java代码 - try{
- socket.sendUrgentData(0xFF);
- }catch(Exception ex){
- reconnect();
- }
有一个WEB应用,使用了AJAX框架,所有页面的展示都是从AJAX的函数中进行的。 在这种情况,有一个很简单的方法来下载一个文件: window.location="download.action?para1=value1...."
run in the mysql command line client next sequence of queries:
USE mysq; SHOW TABLE STATUS; SHOW INDEX FROM `columns_priv`; DESCRIBE `columns_priv`; SHOW INDEX FROM `db`; DESCRIBE `db`;
describe `column_priv`; ERROR `(HY000): Can't create/write to file 'c:\windows\Temp\#sql_7a4_0.MYD (Errcode: 2)
Delete the file #sql_7a4_0.MYD if exists
在apache dbutil中,给数据列起别名有时候不起作用。这时候,需要在连接字符串中添加一个参数:
useOldAliasMetadataBehavior=true";
Mysql replication error 1201 On a fine happy morning I am greeted with an alert that slave is not running. Running start slave yields this: ERROR 1201 (HY000): Could not initialize master info structure; more error messages can be found in the MySQL error log Enabling the log yielded nothing. Googling yielded This Page that helped me a lot, but I didn't have to do quite as much work all over again. Here is what I did. First, I saved my "SHOW SLAVE STATUS\G" output: ************************** 1. row ************************** Slave_IO_State: Master_Host: 127.0.0.1 Master_User: replication Master_Port: 3307 Connect_Retry: 60 Master_Log_File: mysqld-bin.000401 Read_Master_Log_Pos: 98 Relay_Log_File: mysqld-relay-bin.006135 Relay_Log_Pos: 242 Relay_Master_Log_File: mysqld-bin.000401 Slave_IO_Running: No Slave_SQL_Running: No Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 98 Relay_Log_Space: 0 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: NULL 1 row in set (0.00 sec) STOP SLAVE; RESET SLAVE; mysql> CHANGE MASTER TO MASTER_LOG_POS=98 , MASTER_LOG_FILE = 'mysqld-bin.000401'; Query OK, 0 rows affected (0.04 sec) mysql> start slave; Query OK, 0 rows affected (0.00 sec) The position comes from the output I saved before It's working fine again. Still don't know what caused this - possibly random remote server power cycling...
picky挑剔的; quick-tempered容易发脾气的; rude粗鲁无礼的; scatter-brained 记性不好的; slapdash粗心大意的; sly狡猾的; spiteful怀恨在心的; thoughtless草率的; fussy挑剔的; manic狂躁的; manipulative喜欢指使别人的; moody情绪化的
package org.springside.examples.miniweb.dao.account; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.springframework.stereotype.Component; import org.springside.examples.miniweb.entity.account.Group; import org.springside.examples.miniweb.entity.account.User; /** * GroupDao的扩展行为实现类. */ @Component public class GroupDaoImpl implements GroupDaoCustom { private static final String QUERY_USER_BY_GROUPID = "select u from User u left join u.groupList g where g.id=?"; @PersistenceContext private EntityManager em; @Override public void deleteWithReference(Long id) { //因為Group中沒有与User的关联,只能用笨办法,查询出拥有该权限组的用户, 并删除该用户的权限组. Group group = em.find(Group.class, id); List<User> users = em.createQuery(QUERY_USER_BY_GROUPID).setParameter(1, id).getResultList(); for (User u : users) { u.getGroupList().remove(group); } em.remove(group); } }
造成这个错误的原因主要是一些系统文件夹system权限丢失。 所以只要把权限加回去就行了。 我主要查看了 c:\windows\installer C:\Documents and Settings\<user name>\Local Settings\Temp 右键点击目录,点安全选项页,在“组和用户名称”列表中把system用户添加进去,并在下面的权限列表中勾选“完全控制” 即可
Spring Security中指定session超时后跳转的页面
在xml配置文件中加入:<session-management invalid-session-url="/session-timeout.htm" />
在applicationContext.xml中定义了一个DataSource:<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" /> 但是在代码中,使用anotation进行注入的时候,却总是找不到这个dataSource. @Autowired public void setDataSource(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); jdbcInsert = new SimpleJdbcInsert(dataSource); } 最后终于想明白了,原因大概是这样的,使用autowired的时候,默认是根据类型来匹配的,在xml中定义的类型是:BasicDataSource,而不是接口DataSource,所以默认情况下这样是无法自动装配的。解决办法是指令使用名字来进行bean的匹配,也就是用Qualifier指定bean的id. @Autowired public void setDataSource(@Qualifier("dataSource") DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource); jdbcInsert = new SimpleJdbcInsert(dataSource); } 另外一点,在网上搜索的过程中发现有不少人都有类似的问题,但是他们的原因是没有正确使用spring的注入,而是自己在代码中new了一个Dao的实例,这样的话,spring是无法将dataSource注入到dao的实例中的
HeidiSql是一家德国公司研发的轻量级的,开源mysql客户端工具。体积十分小巧,可是十分实用。
我之所以喜欢的原因: 1,有导入/导出的功能,可以将数据直接从文本文件中导入到数据库的数据表中。 2,可以将选中的数据导出成为sql语句 3,界面布置十分合理,操作简便
在FreeMarker中使用:${rc.getMessage("key.in.properties")}
mysql数据复制的一个非常有用的选项。
大部分情况下,我使用两个mysql数据库双向复制。 结构大致如下: A <==> B 但是,现在有了新需要,要求在另一个机器上复制出生产环境的所有数据,但是这些数据的复制是单向,也就是说数据只会从生产环境复制到新的服务器上,而所有新数据库的数据变化不会复制到生产环境中。
新的结构大致如下: A <==> B --> C (新的服务器) 设置数据单向复制的步骤其实非常简单,只要在新的服务器(也就是slave端)指定master的 1,在服务器端B,先stop slave; 2, show master status, 记录文件名和position 3,backup the whole database 4,start slave 5, 在slave端,restore database 6, change master .... 到目前为止,看上去一切都进展顺利,但是马上我就发现slave端只有服务器B的数据。因为服务器B没有把从服务器A中复制过来的数据记录到日志中。 所以,slave C就无法得到此部分数据。 后来,经过网上搜索发现有一个选项 -log_slave_update,可以让服务器B记录此部分数据。 实践中,在服务器B中加入此选项后,机器C中就能够获得所有的数据。
主要是使用: Biff8EncryptionKey.setCurrentUserPassword(password); 在打开workbook之前 HSSFWorkbook workbook = new HSSFWorkbook(inp); 注意事项:这个应该是只适用于xls,而不是xlsx
Tapestry5 in action现在还只是提供MEAP形式的订购,MEAP-Manning Early Access Program, 也就是提前试阅的意思,如果读者订购了此版本,那么manning会在作者每完成一章后,将该章节发给订购者,订购者可以提交自己的反馈,manning会根据情况发布相应的错误修改信息。
目前此书的第一章可以免费下载:
http://www.blogjava.net/Files/usherlight/Tapestry5%20in%20action%20MEAP%20ch01.zip
我使用的是sun提供的javax.comm包,不确定其他的comm支持包(比如:rxtx)行为与之相同
1、事件驱动的数据读取
需要注意的是:一个SerialPort只能注册一个事件监听程序,因此,有时候有会发现,你的事件监听处理程序会变得非常庞大
另外,要注意的就是事件处理如果比较耗时的话,最好是在单独的线程中运行,否则会阻塞数据的接收。
串口接收到数据后,默认在线程: Win32SerialPort Notification thread中运行。如果不及时释放的话,会造成数据无法读取。
我的做法是,接收到数据后,先判断数据的合法和完整性,如果没有接收到完整的数据,则在缓存数据后,马上返回
如果数据完整而且合法,则另开一个线程,进行数据处理
2、数据的发送
建议单独使用一个线程来发送数据,目的还是为了防止阻塞,有一个技巧就是使用OUTPUT_BUFFER_EMPTY事件来发送。
uTorrent
7-zip
CDBurnerXP
Notepad++
OpenOffice(LibreOffice)
FireFox
VirtualBox(vmware player)
WinCDEmu
搜狗五笔
打开Sun virtualBox界面,点击设置,点“数据空间”,再点右边带有加号的图标,这时选择你想共享的文件夹,有只读模式与固定模式,选择一种,只读模式是指在虚拟系统中你不能操作这个文件夹,只能读文件,固定模式是指完全操作。
然后打开你的虚拟系统,点开界面上的菜单“设备”选择最后一项“安装增强功能”虚拟系统开始安装,结束后重启虚拟系统。在虚拟系统中打开资源管理器,右击最下面的“网络”,点开“映射网络驱动器”浏览,打击“virtualbox..."(要等会)找到前面共享的了文件夹,确定,
然后你应该在你的资源管理器中就可以看到你刚刚映射的驱动器,你可以设置多个共享文件夹,步骤如前。你想用主机上哪个文件,你就把它复制到共享的文件夹就可以了。
1、用@RequestParam获取HttpServletRequest里的参数值相当方便,spring可以进行自动的类型转换
2、对于Restful的支持,结合@RequestMapping的UriTemplate和method以及@PathVariable,非常方便地实现了restful的url
3、对于Ajax的支持,@RespsonseBody提供了方便的机制
4、灵活丰富的@Controller的函数返回类型
5、可以方便地给@Controller函数注入各种资源
其他的一些别的框架都有特性,诸如国际化,文件上传什么的就不说了
1、Tapestry5.2.4的发布,Tapestry5.2.3版本在内部投票中被否决(主要是因为使用maven快速创建的原型有问题),所以在被否决的3天后便发布了5.2.4,相对5.2.2来说,变动并不大,只有8个错误修复和5个功能改进。但是至少说明Tapestry的项目还在顺利的进行中。
2、Tapestry主页的全新改版。主要是完善了文档。这一点是非常重要的,Tapestry项目组的成员也承认Tapestry在推销自己或者是在市场推广方面做得非常失败(very bad in marketing),所以最近也采取了一些措施来进行改变,比如,预计明年会发行Tapestry5 in action一书等等。
3、还有一件事需要提及的是:appfuse的作者最近对web框架进行了一番对比http://raibledesigns.com/rd/entry/my_comparing_jvm_web_frameworks,Tapestry在13个框架中名列第7,刚好是中间的位置。Tapestry项目的成员颇有不满,认为作者Matt Raible对Tapestry不够了解,有误导观众之嫌。Tapestry项目成员Igor E. Poteryaev认为Matt在 认识度,开发效率,项目健康度,测试友好性,scalability等方面严重低估了Tapestry的能力。
1、发布了MyBatis3.0.3, 具体内容不详,没有能够发现release notes.
2、发布了mybatis-generator 1.3.0, 这是一个能够根据数据库的表自动生成mybatis的
sqlmap xml文件
与数据表对应的java class
使用上两个文件的java类
我下载后,尝试着使用了一下,发现需要有一个配置文件,我觉得应该是用于提供数据库连接的信息。但是配置文件的格式不详。
现在发现mybatis的文档比较成问题,很多东西都没有说明,使用起来很困难啊。
3、新增了两个中方翻译文档
# MyBatis 3 User Guide Simplified Chinese.pdf
# MyBatis-Spring Reference Simplied Chinese.pdf
4、发布了mybatis-spring-1.0.0-RC2
5、发布了mybatis-guice-1.0.0-RC3
主要是一些bug修复和改进,最重要的一点是能够从link对象生成绝对路径了。
这主要是便于ajax的使用。
Bug
* Element.forceAttribute uses the element's namespace to match the attribute.
* Element.attribute(String name, String value) adds elements that already exist
* Element#addClassName can create an additional new 'class' attribute
* Properties defined in an Interface are not exposed by PropertyAccess for abstract classes that do not directly implement the methods
* Some services require a notification that they have been reloaded, so they can clean up external dependencies
* Whitespaces in SymbolConstants.SUPPORTED_LOCALES cause that locales are not persised
* Validation macros do not work when used in @Validate annotation
* Client-side validation of @Pattern is broken
* Linking a Form to a Zone will no longer work unless the Form contains validated fields
* When using PropertyShadowBuilder to build a service, if the property is null, an immediate exception is needed (rather than a NullPointerException)
* When using a MultiZoneUpdate, Tapestry will clear the referenced zone
Improvement
* Add the facility to optionally disable on-focus-change triggered validation while retaining the on-form-submit validation
* Form component should be able to render a secure URL even on an insecure page
* New annotations @Decorate and @Advise to identify methods that decorate or annotate services
* Extend Link with new methods for producing absolute URLs (that include scheme, hostname, etc.)
* Simplify connecting a link or form to an (enclosing) Zone
* BeanBlockContribution should be split into two sub-classes: EditBlockContribution and DisplayBlockContribution
* Define a special CSS class to prevent a client-side form from submitting normally (for Ajax use cases)
* Additional method for Link: addParameterValue(String,Object) that uses ContextPathEncoder to encode object value to a string
* SeleniumTestCase should expose the underlying CommandProcessor, to allow execution of commands not defined by the Selenium interface
* Allow individual SeleniumTestCases to run w/o configuring SeleniumLauncher
今天在网上转了转,发现Tapestry又有了新动作。
1、从5.2.0alpha版8月11日发布到现在,终于发布5.2.1Beta版了。这个版本主要是修改alpha版本中的bug.
5.2相对于5.1进行了许多重大的改进,详细内容可见:Tapestry5.2的新变化
2、据称在5.3版中将引入大量的新功能,具体内容不详。
3、以往最令人诟病的文档问题,目前开发小组也在努力解决。
首先,建立了新的文档网页:http://people.apache.org/~uli/tapestry-site/,不过目前这个网站还没有完全完成,只能算是预览版,但是这毕竟是在正确的道路上前进。
其次,Tapestry 5 in action一书正在写作中,已经完成20%,预计明年一季度能够出版。
我相信,随着功能的不断完善和补充,再加上文档的逐渐充实,Tapestry完全有理由能吸引更多的开发者来关注和使用。
这是mybatis从ibatis更名过来后,发布的第2个版本(第1个版本是3.0.1)。
在这个版本中只修复了4个bug(感觉数目有点少,难道是因为上一个版本的bug真的如此之少?),增加了一个小功能.
作者的话:尽管只有5个修改,但我还是觉得值得为此发布一个新版本。
这5个修改是:
1、在org.apache.ibatis.Session中增加了一个新方法:void select(String statement, ResultHandler handler);
原来只有:
void select(String statement, Object parameter, ResultHandler handler);
void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
2、修复了ManagedConnection中关闭连接的问题
3、修复了schema migration中,语句提交(statement commit)不正确的问题
4、修复了延迟加载已经预读取属性时的问题
5、修复了schema migration中,FileInputStream没有正确关闭的问题
|