Java堂  


Apache和Resin组合时UrlRewriteFilter失效的解决方法

Filed under: Tools,Web&Server — Jet @ 5:36 下午
Tags: ,
原文出处: Apache和Resin组合时UrlRewriteFilter失效的解决方法
作者: Jet Mah from Java堂
声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

目前在Spring3.0的官方example中都使用UrlRewriteFilter来做伪静态,单独运行在Resin等JavaEE Web容器中的时候一切都OK,但是一旦与Apache一起组合的时候总是会出现404或403错误,当然UrlRewriteFilter所设定的规则也无效。

造成这种现象的原因是因为在默认情况下,静态的资源均由Apache进行处理,而jsp或者由web.xml所映射的servlet均交给resin进行处理。如果web项目没有使用UrlRewriteFilter则一切OK,但是使用了UrlRewriteFilter之后,由servlet所映射的地址并不是/*即所有资源了,而是类似/app/*这样的设置。也就是说,用户所请求的资源首先由Apache判断一下,然后再由选择的交给Resin,最后才执行UrlRewriteFilter的规则。

知道了原因,解决的方法也就出来了,只要告诉Apache将所有的资源都交由Resin来处理就可以了,可以使用Resin的servlet-mapping方法进行配置,配置如下:

  1. <servlet-mapping url-pattern='/*' servlet-name='plugin_match'/>

其中plugin_match是Resin内置的servlet,按照resin官方的解释就是Resin告诉Apache将所有的符合url-pattern规则要求的请求都发送给它进行处理。

因为servlet-mapping是resin特有的,所以建议将此也放在resin-web.xml中,然后放在项目中的WEB-INF目录下:

  1. <web-app xmlns="http://caucho.com/ns/resin"
  2.          xmlns:resin="http://caucho.com/ns/resin/core">
  3.     <servlet-mapping url-pattern='/*' servlet-name='plugin_match'/>
  4. </web-app>

参考资料:
Apache的UrlRewrite和Resin的配置问题
Resin官方对servlet-mapping的说明

解决Firefox及Firebug内存泄漏的问题

Filed under: Tools,Web&Server — Jet @ 10:09 上午
原文出处: 解决Firefox及Firebug内存泄漏的问题
作者: Jet Mah from Java堂
声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

Firebug现在基本是调试Javascript脚本必备的工具,但是由于Firefox运行机制的原因,通常在使用一段时间之后会发现Firefox变得非常慢,在任务管理器中也会发现firefox.exe进程占用了不小的内容。

这里综合自己使用的情况强烈推荐三种方式,可以根据自己的喜好进行选择:

1. 进行系统设置
在地址栏中使用about:config打开FF的配置页面,右键添加一个属性:名称为config.trim_on_minimize,值类型为boolean,值为true,然后将FF关闭之后再打开,这样该设置就生效了。该属性的作用是当Firefox最小化之后会自动释放内容,可以打开任务管理器进行验证。该方法操作和设置都最简单。

2. 使用RAMBack扩展
FF中有一个非常不错的自动释放内存的扩展:RAMBack,这个扩展的基本原理也是上述第一条中的方法,只不过使用插件的方式将这个动作进行自动操作了,安装好扩展并重启FF就可以了,操作更方便。

这里顺便在推荐一个不错的扩展:StatusbarEx,该扩展是用来监视FF内存使用情况的,另外还可以监视系统内存的使用情况、CPU的使用率、FF CPU的使用率等等。

3. 使用SweepRAM软件
确切地来说,SweepRAM并非专门用来释放FF内存的,而是释放系统中所有未被使用但驻留在内存中的数据,据我的使用来看,他对javaw的释放效果也很明显,如果使用Eclipse或NetBeans等做开发的朋友可以试一试。

这个软件是使用VB开发的,所以通常需要在上面的网站上下载vb6fr.dll,然后拷贝到 %SystemRoot%\system32 目录下,另外默认执行SweepRAM.exe完成后会出现一个done的对话框,可以在后面加上 /s 参数禁止显示该对话框。我是在快速启动栏里面创建了一个快捷方式,使用的时候直接点一下,非常方便。

参考资料:
SweepRAM – Firefox3 内存释放工具

SimpleJdbcInsert使用executeAndReturnKeyHolder方法返回主键时需要注意的一个地方

Filed under: JavaPlateform — Jet @ 1:32 下午
Tags:
原文出处: SimpleJdbcInsert使用executeAndReturnKeyHolder方法返回主键时需要注意的一个地方
作者: Jet Mah from Java堂
声明: 可以非商业性任意转载, 转载时请务必以超链接形式标明文章原始出处、作者信息及此声明!

Spring的SimpleJdbcInsert发挥了Simple风格,与SimpleJdbcTemplate同属于Simple体系。该类为向数据库中插入数据提供了一个非常快捷的方式,另外它还提供了一套用于返回插入数据的主键的方法:executeAndReturnKeyHolder、executeAndReturnKey。

查看API的时候可以看到executeAndReturnKey这个方法的返回类型是Number类型,当时我就再想如果主键的类型是String类型呢,比如UUID。后来看到还有一个executeAndReturnKeyHolder方法,返回的是一个KeyHolder对象,可以通过keyHolder#getKeys()获取主键的值,另外还有一个getKeyList()方法用于复合主键的情况,这里先撇开不说。

看完API之后那就可以动手了,代码如下:

  1. // jdbcInsert是SimpleJdbcInsert对象
  2. Map<String, Object> data = Maps.newHashMap();
  3. data.put("id", "t0001");
  4. data.put("name", "Tom");
  5. data.put("age", 24);
  6. KeyHolder keyHolder = jdbcInsert.withTableName("t_tablename")
  7.         .usingColumns("id", "name", "age")
  8.         .usingGeneratedKeyColumns("id")
  9.         .executeAndReturnKeyHolder(data);
  10. // 下面主要是对keyHoder进行分析
  11. if(keyHolder == null) {
  12.     return null;
  13. }
  14. Map<String, Object> keys = keyHolder.getKeys();
  15. if(keys == null || keys.size() == 0 || keys.values().size() == 0) {
  16.     return null;
  17. }
  18. Object key = keys.values().toArray()[0];
  19. if(key == null || !(key instanceof Serializable)) {
  20.     return null;
  21. }
  22. if(key instanceof Number) {
  23.     Long k = (Long)key;
  24.     return (idType == int.class || idType == Integer.class) ?
  25.             k.intValue() : k;
  26. } else if(key instanceof String) {
  27.     return (String)key;
  28. } else {
  29.     return (Serializable)key;
  30. } // end of if(key instanceof Number)

如果主键id的类型是int或long上面的代码没有任何问题,但是如果是自定义的UUID等String类型则问题出现了,提示下面的错误:

org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL []; SQL state [HY000]; error code [1364]; Field ‘id’ doesn’t have a default value; nested exception is java.sql.SQLException: Field ‘id’ doesn’t have a default value

有些奇怪了吧?明明id的值已经传入了,但是错误的提示应该是没有传入id的值。进入到Spring的源代码中,发现代码里面有一些debug信息,于是在log4j中将debug打开:

  1. log4j.logger.org.springframework.jdbc.core=debug

从打印出来的信息中看,Spring自动生成的Insert语句中竟然没有id字段!!!继续最终源代码,先在org.springframework.jdbc.core.simple.AbstractJdbcInsert类中找到protected void compileInternal()方法,在代码前加上一个debug信息:

  1. protected void compileInternal() {
  2.     logger.debug("getGeneratedKeyNames: " + getColumnNames());
  3.     tableMetaDataContext.processMetaData(getJdbcTemplate().getDataSource(), getColumnNames(), getGeneratedKeyNames());
  4.     ...
  5. }

这个时候打印的列表中有id字段,继续最终,最后终于在TableMetaDataContext#createInsertString(java.lang.String[])方法里面找到,关键的代码片段如下:

  1. for (String columnName : this.getTableColumns()) {
  2.             // 这里将SimpleJdbcInsert#usingGeneratedKeyColumns方法中所设置的字段去除了
  3.             if (!keys.contains(columnName.toUpperCase())) {
  4.                 columnCount++;
  5.                 if (columnCount > 1) {
  6.                     insertStatement.append(", ");
  7.                 }
  8.                 insertStatement.append(columnName);
  9.             }
  10.         }

看到这里,我也猛然恍然大悟了。既然在INSERT INTO语句中设置了UUID的值,那这里就不需要再使用KeyHolder进行返回了,直接获取就是了。这也是为什么KeyHolder中的getKey()方法的返回类型是Number的原因了,因为通常来说需要Spring返回的就是插入数据库中的自增类型的主键值。