目前分類:java (28)
- Jul 22 Thu 2010 11:04
Lambdas in Java Preview
- Apr 15 Thu 2010 10:24
Play framework
經歷ASP、PHP、JSP、Tapestry、Wicket、Rails,目前正在使用的是Play framework。開發時只需用內建的server,修改java程式或HTML網頁之後,只要refresh就能看到結果,Play會幫我們編譯java檔。部署時可以用內建的server,也能打包成war檔放進application server,若要部署至Google App Engine也有GAE module可用。Play也把Hibernate包裝好了,使用時不再需要繁瑣的設定。其它如MongoDB、Scala、Spring、GWT等也已經有支援模組。就像Rails,Play也有內建routes功能可以讓你輕鬆開發RESTFul application,或是讓URL看起來漂亮些。
A web app in 10 minutes using Play! from zenexity on Vimeo.
- Apr 15 Thu 2010 10:11
BoneCP參數
- maxConnectionsPerPartition最小值是2,給了小於2的值會被設成50
- minConnectionsPerPartition最小值是2,給了小於2的值會被設成10
- minConnectionsPerPartition大於maxConnectionsPerPartition時,會被設成maxConnectionsPerPartition
- acquireIncrement小於或等於0時,會被設成1
- partitionCount小於1時,會被設成3
- releaseHelperThreads小於0時,會被設成3
- statementsCacheSize小於0時,會被設成0
- acquireRetryDelay小於或等於0 時,會被設成1000
- Oct 21 Tue 2008 09:21
ant管理dependencies
有時候要把Maven調教成想要的樣子真的很麻煩,自己刻Ant build file比較快,但是這樣就要自己管理dependencies,引用很多library的時候會很痛苦,還好有Ant Tasks for Maven可以幫忙減輕痛苦。下載maven-ant-tasks-*.jar後扔進$APACHE_HOME/lib目錄就可以用了。
使用時可以像用Maven時一樣,把dependencies資訊存入pom.xml,再從build.xml引用。
pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project> <modelVersion>4.0.0</modelVersion> <groupId>net.zbwei</groupId> <artifactId>bento</artifactId> <packaging>war</packaging> <name>bento</name> <version>0.1</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.5.5</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> <version>3.3.0.ga</version> </dependency> </dependencies> </project>
build.xml:
- Mar 20 Thu 2008 09:11
用Hibernate建立Membership
@Entity @Table(name="memberships") @IdClass(MembershipPK.class) public class Membership { private Integer groupId; private Integer userId; @Id @Column(name="group_id") public Integer getGroupId() { return groupId; } public void setGroupId(Integer groupId) { this.groupId = groupId; } @Id @Column(name="user_id") public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } }
@Embeddable public class MembershipPK { private Integer groupId; private Integer userId; public Integer getGroupId() { return groupId; } public void setGroupId(Integer groupId) { this.groupId = groupId; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } }
- Feb 21 Thu 2008 09:08
Wicket和Spring
在Wicket程式用Spring,要在web.xml加入設定:
<context -param> <param -name>contextConfigLocation</param> <param -value>/WEB-INF/spring*.xml</param> </context> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
在WebApplication中要建立SpringComponentInjector:
public class BasicApplication extends WebApplication { @Override protected void init() { super.init(); addComponentInstantiationListener(new SpringComponentInjector(this)); } }
如果還想把bean注入WebSession,要用InjectorHolder:
public class BasicSession extends WebSession { public BasicSession(Request request) { super(request); InjectorHolder.getInjector().inject(this); } }
設定好之後,只要在需要注入bean的地方用@SpringBean即可,範例如下:
public class SignUpPage extends BasePage { @SpringBean private UserService userService; public SignUpPage() { add(new SignUpForm("signUpForm")); } class SignUpForm extends Form { private String name; private String email; private String password; @SuppressWarnings("unused") private String confirmPassword; public SignUpForm(String id) { super(id); PasswordTextField passwordField, confirmPasswordField; add(new TextField("name", new PropertyModel(this, "name")).setRequired(true).add(new StringValidator.LengthBetweenValidator(2, 32))); add(new TextField("email", new PropertyModel(this, "email")).setRequired(true).add(EmailAddressValidator.getInstance())); add(passwordField = new PasswordTextField("password", new PropertyModel(this, "password"))); add(confirmPasswordField = new PasswordTextField("confirmPassword", new PropertyModel(this, "confirmPassword"))); add(new EqualPasswordInputValidator(passwordField, confirmPasswordField)); } @Override protected void onSubmit() { User user = new User(name, email, password, User.ROLE_USER); try { userService.createUser(user); setResponsePage(HomePage.class); } catch (DuplicatedUserNameException e) { error(getLocalizer().getString(getId() + ".nameTaken", getWebPage(), "User's name is taken: " + name)); } catch (DuplicatedUserEmailException e) { error(getLocalizer().getString(getId() + ".emailTaken", getWebPage(), "User's email is taken: " + email)); } } } }
- Feb 11 Mon 2008 09:07
程式和內嵌Jetty共用spring context
應用程式內嵌Jetty運行webapp時,希望程式和webapp共用同一個spring context,在web.xml設定context loader listener時,要改用自定的MyContextLoaderListener。
JettyServer.java:
import org.mortbay.jetty.Server; import org.mortbay.jetty.nio.SelectChannelConnector; import org.mortbay.jetty.webapp.WebAppContext; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class JettyServer implements ApplicationContextAware { private ApplicationContext applicationContext; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public void start() throws Exception { int port = Integer.parseInt(System.getProperty("jetty.port", "8080")); SelectChannelConnector connector = new SelectChannelConnector(); connector.setPort(port); Server server = new Server(); server.addConnector(connector); WebAppContext context = new WebAppContext(); context.setClassLoader(applicationContext.getClassLoader()); context.setAttribute("applicationContext", applicationContext); context.setServer(server); context.setContextPath("/"); context.setWar("src/main/webapp"); server.addHandler(context); server.start(); } }
MyContextLoader.java:
import javax.servlet.ServletContext; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.web.context.ContextLoader; public class MyContextLoader extends ContextLoader { @Override protected ApplicationContext loadParentContext(ServletContext servletContext) throws BeansException { return (ApplicationContext)servletContext.getAttribute("applicationContext"); } }
MyContextLoaderListener.java:
import org.springframework.web.context.ContextLoader; import org.springframework.web.context.ContextLoaderListener; public class MyContextLoaderListener extends ContextLoaderListener { @Override protected ContextLoader createContextLoader() { return new MyContextLoader(); } }
- Feb 11 Mon 2008 09:05
Maven設定Terracotta
Maven repository沒有Terracotta和Terracotta Maven Plugin,所以要在pom.xml加入:
<repositories> <repository> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> <id>terracotta-repository</id> <url> http://www.terracotta.org/download/reflector/maven2 </url> </repository> </repositories> <pluginrepositories> <pluginrepository> <id>terracotta-snapshots</id> <url> http://www.terracotta.org/download/reflector/maven2 </url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </pluginrepository> </pluginrepositories> <build> <plugins> <plugin> <groupid>org.terracotta.maven.plugins</groupid> <artifactid>tc-maven-plugin</artifactid> <version>1.0.3</version> <configuration> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupid>org.terracotta</groupid> <artifactid>terracotta</artifactid> <version>2.5.1</version> </dependency> </dependencies>
不過,Terracotta DSO Eclipse Plug-in比Terracotta Maven Plugin好用多了。
- Feb 01 Fri 2008 08:59
Java調用Ruby物件
RubyHelp.java:
public class RubyHelper { static { System.setProperty("jruby.home", new File("").getAbsolutePath()); } private RubyHelper() { } public static Object create(String className, Class interfaceClazz, String scriptFileName) { InputStream scriptInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(scriptFileName); if (null == scriptInputStream) { throw new RuntimeException("Could not find " + scriptFileName); } StringBuilder sb = new StringBuilder(); byte[] buf = new byte[8192]; try { for (int n; (n = scriptInputStream.read(buf)) != -1;) { sb.append(new String(buf, 0, n, "UTF-8")); } scriptInputStream.close(); } catch (IOException e) { throw new RuntimeException("Error loading " + scriptFileName + ": " + e.getMessage()); } Ruby runtime = JavaEmbedUtils.initialize(new ArrayList()); runtime.eval(runtime.parse(sb.toString(), scriptFileName, runtime.getCurrentContext().getCurrentScope(), 0, false)); return JavaEmbedUtils.rubyToJava(runtime, runtime.evalScriptlet(className + ".new"), interfaceClazz); } }
HelloService.java:
public interface HelloService { void hello(); }
hello.rb:
class Hello def hello puts 'hello there' end end
Test.java:
public class Test { public static void main(String[] args) throws Exception { HelloService s = (HelloService)RubyHelper.create("Hello", HelloService.class, "hello.rb"); s.hello(); } }
- Feb 07 Wed 2007 20:30
工作用到的Java
- Apache MINA
- dom4j
- ehcache
- FreeMarker
- Hibernate
- Hibernate Annotations
- ini4j
- JavaMail
- Java Service Wrapper
- Jakarta Commons Logging
- JCIFS
- Jetty
- JGoodies Binding
- JGoodies Forms
- JGoodies Looks
- JGoodies Validation
- Jpcap
- jTDS
- log4j
- Proxool
- Quartz
- Spring Framework
- Wicket
- XStream
- YourKit Java Profiler
- Jan 23 Tue 2007 20:27
DbUnit提供的資料操作
下列是DatabaseOperation提供的功能,如果有用IDENTITY欄位,要改用InsertIdentityOperation提供的INSERT、CLEAN_INSERT、REFRESH。
UPDATE | 用dataset更新資料,如果資料庫中沒有資料,會被視為錯誤。 |
INSERT | 用dataset建立資料,如果資料庫中已有資料,會被視為錯誤。 |
DELETE | 用資料庫系統的DELETE命令刪除table中的資料,只有在dataset內的資料會被刪除。 |
DELETE_ALL | 用資料庫系統的DELETE命令刪除table中的所有資料,只有dataset列出的table會被影響。 |
TRUNCATE | 用資料庫系統的TRUNCATE命令清除table中的所有資料,只有dataset列出的table會被影響。 |
REFRESH | 用dataset更新和建立資料。已存在的資料會被標新,不存在的資料會被建立。 |
CLEAN_INSERT | 先執行DELETE_ALL,再執行INSERT。 |
- Jan 16 Tue 2007 20:25
Wicket開發指南
Wicket開發指南,作者是王磊,這本三百多頁的開發指南,應該是目前對Wicket解說最詳細的中文手冊。我用過的Java web framework只有兩個,Tapestry是第一個,第二個就是Wicket。Tapestry已經被我停用了,位子則由Wicket和Ruby on Rails一同接下。第一次知道Wicket這東西,是在Tapestry作者的blog中瞧見的。在IDE如Eclipse的 協助下,熟悉Java的程序員使用Wicket的開發速度可以非常快,雖然在persistence layer要用JDBC或Hibernate,不如Ruby on Rails的ActiveRecord省事,但在presentation layer的用法則是我所喜愛的,這也是早期採用Tapestry的原因,Rails中調用簡便的AJAX,在Wicket也有良好支援。至於 Struts和Spring MVC,雖然沒事偶爾會看看,但是,看看就好,完全不想用(真是任性啊!)。目前要我開發web app的話,不是Wicket,就是Ruby on Rails了。
- Oct 17 Tue 2006 20:05
Pro Wicket
- Oct 05 Thu 2006 20:01
我的Eclipse裝了哪些Plug-in
- Sep 12 Tue 2006 20:00
我的spring-beans.xml
<?xml version=”1.0″ encoding=”UTF-8″?> <!DOCTYPE beans PUBLIC “-//SPRING/DTD BEAN/EN” “http://www.springframework.org/dtd/spring-beans.dtd”> <beans> <bean id=”dataSource” class=”org.logicalcobwebs.proxool.ProxoolDataSource” destroy-method=”close”> <property name=”driver”><value>${jdbc.driver}</value></property> <property name=”driverUrl”><value>${jdbc.url}</value></property> <property name=”user”><value>${jdbc.username}</value></property> <property name=”password”><value>${jdbc.password}</value></property> <property name=”alias”><value>xfort</value></property> <property name=”houseKeepingTestSql”><value>SELECT 1</value></property> <property name=”testBeforeUse”><value>false</value></property> <property name=”maximumActiveTime”><value>86400000</value></property> <property name=”maximumConnectionCount”><value>${proxool.maximum-connection-count}</value></property> <property name=”delegateProperties”><value>user=${jdbc.username},password=${jdbc.password}</value></property> </bean> <bean id=”sessionFactory” class=”org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean”> <property name=”dataSource”><ref bean=”dataSource” /></property> <property name=”hibernateProperties”> <props> <prop key=”hibernate.dialect”>${hibernate.dialect}</prop> <prop key=”hibernate.format_sql”>true</prop> <prop key=”hibernate.show_sql”>false</prop> <prop key=”hibernate.cache.use_second_level_cache”>false</prop> <prop key=”hibernate.cache.provider_class”>org.hibernate.cache.EhCacheProvider</prop> <prop key=”hibernate.current_session_context_class”>thread</prop> <prop key=”hibernate.connection.release_mode”>after_transaction</prop> <prop key=”hibernate.transaction.factory_class”>org.hibernate.transaction.JDBCTransactionFactory</prop> <prop key=”hibernate.transaction.auto_close_session”>false</prop> </props> </property> <property name=”annotatedPackages”> <list> <value>forth.model</value> </list> </property> <property name=”annotatedClasses”> <list> <value>zbwei.model.ModelName</value> </list> </property> </bean> </beans>
- Sep 07 Thu 2006 20:00
我的build.xml
<?xml version=”1.0″ encoding=”UTF-8″?> <project name=”Forth” default=”compile” basedir=”.”> <property name=”build.dir” value=”build” /> <property name=”build.dist.dir” value=”${build.dir}/dist” /> <property name=”build.main.dir” value=”${build.dir}/main” /> <property name=”build.test.dir” value=”${build.dir}/test” /> <property name=”build.test.output.dir” value=”${build.dir}/test-output” /> <property name=”build.test.report.dir” value=”${build.dir}/test-report” /> <property name=”src.dir” value=”src” /> <property name=”test.dir” value=”test” /> <property name=”lib.dir” value=”lib” /> <property name=”ext.dir” value=”ext” /> <property name=”web.dir” value=”web” /> <path id=”classpath”> <pathelement location=”${build.main.dir}” /> <pathelement location=”${build.test.dir}” /> <fileset dir=”${lib.dir}” includes=”*.jar” /> <fileset dir=”${ext.dir}” includes=”*.jar” /> </path> <target name=”prepare”> <mkdir dir=”${build.dist.dir}” /> <mkdir dir=”${build.main.dir}” /> <mkdir dir=”${build.test.dir}” /> <mkdir dir=”${build.test.output.dir}” /> <mkdir dir=”${build.test.report.dir}” /> </target> <target name=”clean” depends=”prepare”> <delete dir=”${build.dir}” /> </target> <target name=”compile” depends=”prepare”> <javac srcdir=”${src.dir}” destdir=”${build.main.dir}” encoding=”UTF-8″> <classpath refid=”classpath” /> </javac> </target> <target name=”compile-test” depends=”compile”> <javac srcdir=”${test.dir}” destdir=”${build.test.dir}” encoding=”UTF-8″> <classpath refid=”classpath” /> </javac> </target> <target name=”test” depends=”compile-test”> <taskdef name=”testng” classname=”org.testng.TestNGAntTask” classpath=”${ext.dir}/testng-5.1.jar” /> <testng classpathref=”classpath” outputdir=”${build.test.output.dir}” haltOnfailure=”true”> <xmlfileset dir=”test” includes=”testng.xml” /> </testng> </target> <target name=”test-report” depends=”test”> <junitreport todir=”${build.test.report.dir}”> <fileset dir=”${build.test.output.dir}” includes=”**/*.xml” /> <report format=”noframes” todir=”${build.test.report.dir}” /> </junitreport> </target> <target name=”pack-main” depends=”compile”> <jar destfile=”${build.dist.dir}/setup.jar”> <manifest> <attribute name=”Main-Class” value=”Installer” /> <attribute name=”Class-Path” value=”. server.jar” /> </manifest> </jar> <jar destfile=”${build.dist.dir}/server.jar”> <fileset dir=”${build.main.dir}” /> </jar> <jar destfile=”${build.dist.dir}/web.war”> <fileset dir=”${web.dir}” /> </jar> </target> <target name=”pack-test” depends=”compile-test”> <jar destfile=”${build.dist.dir}/test.jar”> <fileset dir=”${build.test.dir}” /> </jar> </target> <target name=”dist” depends=”pack-main, pack-test”> <copy todir=”${build.dist.dir}”> <fileset dir=”.” includes=”resource/*” /> <fileset dir=”.” includes=”config/*” /> </copy> </target> </project>
- Sep 07 Thu 2006 19:59
我的Java工作目錄結構
build/dist/ - 封裝成佈署用的檔案 build/main/ - 主程式class檔 build/test/ - 測試程式class檔 build/test-output/ - TestNG輸出 build/test-report/ - JUnitReport config/ - 設定檔 classes/ - Eclipse產生的class檔 ext/ - 其它JAR檔,例如ProGuard、yGuard lib/ - 程式庫JAR檔 resource/ - 資源檔 src/ - 主程式原始碼 test/ - 測試程式原始碼 web/ - 網頁 web/WEB-INF/
- Jul 29 Sat 2006 19:56
Java和Delphi時間換算
在Java中的Date是以long記錄時間,單位是ms,0表示1970-01-01 00:00:00 GMT,而Delphi的TDateTime則是以double記錄時間,0.0表示1899-12-30 00:00:00,整數部分代表從前述時間到某個日期所經過的天數,小數部分乘以86400代表該日經過的秒數。
從1899年12月30日到1970年1月1日,共計25569日,每日計有86400000ms,因此要把Java的時間轉成Delphi的格式可用下列程式:
static final double DAYS_BETWEEN_18991230_AND_19700101 = 25569; static final double MILLISECONDS_PER_DAY = 86400000; public static double javaTimeToDelphiTime(final Date time) { return (time.getTime() + TIME_ZONE_OFFSET_MILLIS) / MILLISECONDS_PER_DAY + DAYS_BETWEEN_18991230_AND_19700101; }
經過計算得到的時間就可以直接給在Delphi使用。要將時間換算成Java格式可用:
public static Date delphiTimeToJavaTime(final double time) { return new Date((long)((time - DAYS_BETWEEN_18991230_AND_19700101) * MILLISECONDS_PER_DAY - TIME_ZONE_OFFSET_MILLIS)); }
以上就是Java的Date和Delphi的TDateTime的暴力法轉換方式。
- Jul 29 Sat 2006 19:54
讓SSL使用自定的keystore
在命令列指定使用的keystore, client端:
java -Djavax.net.ssl.trustStore=mykeystore -Djavax.net.ssl.trustStorePassword=123456 Client
server端:
java -Djavax.net.ssl.keyStore=mykeystore -Djavax.net.ssl.keyStorePassword=123456 Server
在程式中設定使用的keystore:
char[] passphrase = "123456".toCharArray(); KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream("mykeystore"), passphrase); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, passphrase); TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks); SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); // client端 Socket socket = ctx.getServerSocketFactory().createServerSocket(port); // server端 ServerSocket serverSocket = ctx.getSocketFactory().createSocket("hostname", port);
- Jul 29 Sat 2006 19:52
同一context執行2個Tapestry程式
原本要在同一個context執行2個以上的Tapestry程式時,必須在application specification補上不少page的資訊,不過,現在有方便的做法了。檔案架構:
/app1/Home.html /WEB-INF/app1/app1.application /app2/Home.html /WEB-INF/app2/app2.application
app1和app2是servlet名稱,所以在web.xml中要設定:
<servlet> <servlet-name>app1</servlet-name> <servlet-class>org.apache.tapestry.ApplicationServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet> <servlet-name>app2</servlet-name> <servlet-class>org.apache.tapestry.ApplicationServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>app1</servlet-name> <url-pattern>/app1/app</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>app2</servlet-name> <url-pattern>/app2/app</url-pattern> </servlet-mapping>
使用app1:http://hostname/app1/app
使用app2:http://hostname/app2/app