leisure

JAVA - exceed,helloworld
随笔 - 50, 文章 - 0, 评论 - 11, 引用 - 0
数据加载中……

2011年10月15日

flash调用javascript

flash.external.ExternalInterface.call("pop")

posted @ 2013-01-11 10:34 leisure 阅读(516) | 评论 (0)编辑 收藏

spring2 JNDI

      <bean id= "myjndi" class= "org.springframework.jndi.JndiObjectFactoryBean" >
             <property name ="jndiName" value= "java:comp/env/jdbc/myjndi" />
      </bean >

posted @ 2013-01-11 10:33 leisure 阅读(507) | 评论 (0)编辑 收藏

两个div在同一行

<style>
.b,.c{float:left; margin-right:10px;}
</style>
<div class="a">
  <div class="b">
      test
  </div>
  <div class="c">
       testc
  </div>
</div>

posted @ 2013-01-11 10:32 leisure 阅读(927) | 评论 (0)编辑 收藏

Javascriptz格式化数字

<script>
    
/*** 格式化数字显示方式
        * 用法
        * formatNumber(12345.999,'#,##0.00');
        * formatNumber(12345.999,'#,##0.##');
        * formatNumber(123,'000000');
        * @param num* @param pattern
    
*/
    
function formatNumber(num,pattern){
        num 
= Number(num);
        
var strarr = num?num.toString().split('.'):['0'];
        
var fmtarr = pattern?pattern.split('.'):[''];
        
var retstr='';    // 整数部分
        var str = strarr[0];
        
var fmt = fmtarr[0];
        
var i = str.length-1;
        
var comma = false;
        
for(var f=fmt.length-1;f>=0;f--){
            
switch(fmt.substr(f,1)) {
                
case '#':
                    
if(i>=0 ) retstr = str.substr(i--,1+ retstr;
                    
break;
                
case '0':
                    
if(i>=0) retstr = str.substr(i--,1+ retstr;else retstr = '0+ retstr;
                    
break;
                
case ',':
                    comma 
= true;
                    retstr
=','+retstr;
                    
break;
            }
        }
        
if(i>=0){
            
if(comma){
                
var l = str.length;
                
for(;i>=0;i--){
                    retstr 
= str.substr(i,1+ retstr;
                    
if(i>0 && ((l-i)%3)==0) retstr = ',' + retstr;
                }
            } 
else 
                retstr 
= str.substr(0,i+1+ retstr;
        }
            retstr 
= retstr+'.';// 处理小数部分
            str=strarr.length>1?strarr[1]:'';
            fmt
=fmtarr.length>1?fmtarr[1]:'';
            i
=0;
            
for(var f=0;f<fmt.length;f++){
                
switch(fmt.substr(f,1)){
                    
case '#':
                        
if(i<str.length) retstr+=str.substr(i++,1);
                        
break;
                    
case '0':
                        
if(i<str.length) retstr+= str.substr(i++,1);
                        
else retstr+='0';
                        
break;
                    }
            } 
            
return retstr.replace(/^,+/,'').replace(/\.$/,'');
    }
    
    document.write(
"formatNumber('','')=" + formatNumber('',''));
    document.write(
"<br/>");
    document.write(
"formatNumber(123456789012.129,null)=" + formatNumber(123456789012.129,null));
    document.write(
"<br/>");
    document.write(
"formatNumber(null,null)=" + formatNumber(null,null));
    document.write(
"<br/>");
    document.write(
"formatNumber(123456789012.129,'#,##0.00')=" + formatNumber(123456789012.129,'#,##0.00'));
    document.write(
"<br/>");
    document.write(
"formatNumber(123456789012.129,'#,##0.##')=" + formatNumber(123456789012.129,'#,##0.##'));
    document.write(
"<br/>");
    document.write(
"formatNumber(123456789012.129,'#0.00')=" + formatNumber(123456789012.129,'#,##0.00'));
    document.write(
"<br/>");
    document.write(
"formatNumber(123456789012.129,'#0.##')=" + formatNumber(123456789012.129,'#,##0.##'));
    document.write(
"<br/>");
    document.write(
"formatNumber(12.129,'0.00')=" + formatNumber(12.129,'0.00'));
    document.write(
"<br/>");
    document.write(
"formatNumber(12.129,'0.##')=" + formatNumber(12.129,'0.##'));
    document.write(
"<br/>");
    document.write(
"formatNumber(12,'00000')=" + formatNumber(12,'00000'));document.write("<br/>");
    document.write(
"formatNumber(12,'#.##')=" + formatNumber(12,'#.##'));
    document.write(
"<br/>");
    document.write(
"formatNumber(12,'#.00')=" + formatNumber(12,'#.00'));
    document.write(
"<br/>");
    document.write(
"formatNumber(1080.0,'#.##')=" + formatNumber(1100.0,'#,###.##'));
    document.write(
"<br/>");
</script>

posted @ 2013-01-11 10:30 leisure 阅读(279) | 评论 (0)编辑 收藏

去掉eclipse的validate

困扰了好几天,与大家共享

1,在project名称上右键选择properties,打开属性窗口,选择左边的validation

2,勾选enable project specific setting;

3,点击Disable all,点击OK关闭窗口

4,在project名称上右键validate

备注:suspend all validators勾选没有效果,另外第4步很重要

posted @ 2013-01-11 10:20 leisure 阅读(7081) | 评论 (0)编辑 收藏

spring method interceptor

spring method interceptor

-author: leisure.xu

首先dao里面有find和save方法,本实例以拦截find方法为主,并改变find的返回值。

package com.leisure;

public class Dao {

     public String find() {

          System. out.println( "dao: find()");

          return "student";

     }

     public void save() {

          System. out.println( "dao: save()");

     }

}

一、新增一个DaoInterceptor,如下

package com.leisure;

import org.aopalliance.intercept.MethodInterceptor;

import org.aopalliance.intercept.MethodInvocation;

/**

 * class description goes here

 * @author leisure.xu

 * @version 1.0.0, 2012 -6 -29

 */

public class DaoInterceptor implements MethodInterceptor {

     @Override

     public Object invoke(MethodInvocation invocation) throws Throwable {

          String methodName = invocation.getMethod().getName();

          if( "find".equals(methodName)) {

               System. out.println( "invocation modify the return result to 'teacher'");

               return "teacher";

          }

          return invocation.proceed();

     } 

}

     DaoInterceptor实现了MethodInterceptor的invoke方法,在这里,MethodInvocation参数可以获取到getArguments等数据,至于能做什么,你懂的。

二、Dao跟DaoInterceptor还是没扯上关系,这时需要修改applicationContext.xml

     原来:

     <bean id = "dao" class= "com.leisure.Dao"/>

修改为:

          <!--

      <bean id=" dao" class="com.leiusre.Dao"/>

     -->

     <bean id ="daoInterceptor" class="com.leisure.DaoInterceptor"/>

     <bean id ="dao" class= "org.springframework.aop.framework.ProxyFactoryBean" >

          <property name ="target">

               <bean class ="com.leisure.Dao" />

          </property >

          <property name ="interceptorNames">

               <list >

                    <value >daoInterceptor </value >

               </list >

          </property >

     </bean >

三、运行看效果!

     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" );

     Dao dao = context.getBean(Dao. class);

     System. out.println(dao.find());

     dao.save();

结果:

invocation modify the return result to 'teacher'

teacher

dao: save()

从结果可以看出invocation拦截了find方法,并且修改了其返回结果,而对象的find方法并没有执行到。

该实例引用到的jar包:




posted @ 2012-07-11 09:14 leisure 阅读(990) | 评论 (0)编辑 收藏

spring2.0的jndi配置

<!--
 <jee:jndi-lookup id="application" jndi-name="java:comp/env/app-name"/>
    -->
改成
<bean id="application" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/app-name" />
</bean>

posted @ 2012-06-27 16:30 leisure 阅读(304) | 评论 (0)编辑 收藏

Caused by: java.lang.IllegalArgumentException: null source 解决

1 Caused by: java.lang.IllegalArgumentException: null source
2     at java.util.EventObject.<init>(EventObject.java:38)
3     at javax.sql.StatementEvent.<init>(StatementEvent.java:39)
4     at com.mysql.jdbc.jdbc2.optional.JDBC4PreparedStatementWrapper.close(JDBC4PreparedStatementWrapper.java:70)
5     at com.caucho.sql.UserStatement.close(UserStatement.java:163)
6     at com.caucho.sql.UserPreparedStatement.close(UserPreparedStatement.java:727)

开始使用的是:mysql-connector-java-5.1.6-bin
更换新的mysql驱动包就没问题了(mysql-connector-java-5.1.11-bin)

posted @ 2012-06-15 12:10 leisure 阅读(3359) | 评论 (0)编辑 收藏

redis五天亲密旅程

FIRST DAY
redis介绍、安装使用(win、linux)
redis数据类型
redis-twitter实例分析
驱动选材-Jedis
初探spring data - redis

SECOND DAY
项目架构搭建 spring + spring data redis + jedis
redisTemplate、jedis常用的API熟悉
spring data - redis源码解剖

THIRD DAY
redis数据库设计理念及应用场景分析
深入探究数据类型

FOURTH Day
 项目实战

FIFTH DAY
内存优化,设计优化
 分布式集群方案

posted @ 2012-04-12 10:10 leisure 阅读(523) | 评论 (0)编辑 收藏

游戏数据库上线拉

新应用,游戏数据库,为你提供详尽的游戏资料。


posted @ 2012-04-11 08:54 leisure 阅读(323) | 评论 (0)编辑 收藏

应用启动时,attempting to get SockIO from uninitialized pool!

在spring配置文件中,没有将实例名称对应上,导致mc client无法从一个未初始化的池里获取数据。

    <bean id="sockIOPool" class="com.danga.MemCached.SockIOPool"
        factory-method
="getInstance" init-method="initialize" destroy-method="shutDown"
        p:initConn
="${memcached.initConn}"
        p:minConn
="${memcached.minConn}"
        p:maxConn
="${memcached.maxConn}"
        p:maintSleep
="${memcached.maintSleep}"
        p:nagle
="${memcached.nagle}"
        p:socketTO
="${memcached.socketTO}"
        p:servers
="${memcached.servers}">
        <constructor-arg value="myName"/>
    </bean>
    
    <bean id="memCachedClient" class="com.danga.MemCached.MemCachedClient">
        <constructor-arg value="myName"/> 
        <property name="sanitizeKeys" value="false"/>
        <property name="compressEnable"   value="true"/>
        <property name="compressThreshold" value="1024"/>
    </bean>

注意<constructor-arg value="myName"/> 中的myName要保持一致。

posted @ 2012-02-17 14:44 leisure 阅读(3437) | 评论 (1)编辑 收藏

eclipse安装svn客户端

下载相应的插件版本
把解压的内容放置eclipse\dropins\svn\目录下(svn目录不存在则创建)
完成后,重启eclipse,重启完后,提示安装svn connector,选择一个安装即可,安装完后,再一次重启。
window - show view - other - svn 下即可以看到svn控制视图

posted @ 2012-01-25 10:59 leisure 阅读(304) | 评论 (0)编辑 收藏

hello,spring3

spring很早就更新了3.0版本,可是由于项目要求稳定,却一直没有使用到,最近有个新项目,打算采用spring3了。

项目整个结构如下:


 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4      xmlns:p="http://www.springframework.org/schema/p"
 5      xsi:schemaLocation="http://www.springframework.org/schema/beans
 6      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 7      
 8     <bean id="dao" class="Dao"/>
 9     
10 </beans>

1 
2 public class Dao {
3     public void find() {
4         System.out.println("dao: find()");
5     }
6 }
7 

 1 import org.springframework.context.ApplicationContext;
 2 import org.springframework.context.support.ClassPathXmlApplicationContext;
 3 
 4 public class Client {
 5 
 6     public static void main(String[] args) {
 7         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
 8         Dao dao = context.getBean(Dao.class);
 9         dao.find();
10     }
11 }
12 

posted @ 2011-12-29 16:02 leisure 阅读(206) | 评论 (0)编辑 收藏

java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

获取泛型参数的类型
        
Class<TentityClass = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];

出现:
java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

使用以下工具类方法获取~
 1 package cn.pconline.prolib.util;
 2 import java.lang.reflect.ParameterizedType;  
 3 import java.lang.reflect.Type;  
 4   
 5 public class GenericsUtils {  
 6     /**   
 7      * 通过反射,获得定义Class时声明的父类的范型参数的类型.   
 8      * 如public BookManager extends GenricManager<Book>   
 9      *   
10      * @param clazz The class to introspect   
11      * @return the first generic declaration, or <code>Object.class</code> if cannot be determined   
12      */  
13     public static Class getSuperClassGenricType(Class clazz) {  
14         return getSuperClassGenricType(clazz, 0);  
15     }  
16   
17     /**   
18      * 通过反射,获得定义Class时声明的父类的范型参数的类型.   
19      * 如public BookManager extends GenricManager<Book>   
20      *   
21      * @param clazz clazz The class to introspect   
22      * @param index the Index of the generic ddeclaration,start from 0.   
23      */  
24     public static Class getSuperClassGenricType(Class clazz, int index) throws IndexOutOfBoundsException {  
25   
26         Type genType = clazz.getGenericSuperclass();  
27   
28         if (!(genType instanceof ParameterizedType)) {  
29             return Object.class;  
30         }  
31   
32         Type[] params = ((ParameterizedType) genType).getActualTypeArguments();  
33   
34         if (index >= params.length || index < 0) {  
35             return Object.class;  
36         }  
37         if (!(params[index] instanceof Class)) {  
38             return Object.class;  
39         }  
40         return (Class) params[index];  
41     }  
42 }  

        
Class<TentityClass = GenericsUtils.getSuperClassGenricType(BasicService.class0);

posted @ 2011-12-26 14:37 leisure 阅读(17879) | 评论 (4)编辑 收藏

浅淡Java代理模式之秘书MM

代理对象一般定义了一个与目标对象相似或相近的行为。代理对象负责对真实模块调用,这使得调用者与被调用者之间建立了一个隔离带。
场景示例说明:老总说话都是很精简,每次发布一个消息时,总是先将简要内容交给秘书MM,秘书MM经过一番美化后,把消息公布出来。

设老总=Boss,秘书MM=MMProxy

于是简单的代理就有
1 public class Boss {
2     public void anounce(String content) {
3         System.out.println(content);
4     }
5 }

1 public class MMProxy {
2     public void anounce(String content) {
3         System.out.print("boss: 大家请注意了!");
4         new Boss().anounce(content);
5     }
6 }

new MMProxy().anounce("我请大家吃饭。");

结果出来的是:
boss: 大家请注意了!我请大家吃饭。

通过上面发现,这种代理比较呆板,比如说,Boss口渴了,又得重新写一个代理方法,这个时候,可以使用动态代理来进行:

添加一个接口IBoss
1 public interface IBoss {
2     public void anounce(String content);
3     public void drink();
4 }

修改Boss
1 public class Boss implements IBoss {
2     public void anounce(String content) {
3         System.out.println(content);
4     }
5 
6     public void drink() {
7         System.out.println("boss: 拿起杯子,喝水");
8     }
9 }

这时秘书MM变为
 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Method;
 3 
 4 public class MMProxy implements InvocationHandler {
 5 
 6     private Object obj;
 7 
 8     public MMProxy(Object obj) {
 9         this.obj = obj;
10     }
11 
12     public static Object newInstance(Object obj) {
13         return java.lang.reflect.Proxy.newProxyInstance(
14             obj.getClass().getClassLoader(),
15             obj.getClass().getInterfaces(),
16             new MMProxy(obj));
17     }
18     
19     @Override
20     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
21         if("drink".equals(method.getName())) {
22             System.out.println("秘书MM: 看到boss想喝水了,于是 把水倒进boss的杯子里。");
23         } else if("anounce".equals(method.getName())) {
24             System.out.print("boss: 大家请注意!");
25         }
26         method.invoke(obj, args);
27         return null;
28     }
29 }

        IBoss boss = (IBoss) MMProxy.newInstance(new Boss());
        boss.anounce(
"我请大家吃饭。");
        boss.drink();

boss: 大家请注意!我请大家吃饭。
秘书MM: 看到boss想喝水了,于是 把水倒进boss的杯子里。
boss: 拿起杯子,喝水

现在发现了吧,秘书MM真是服务周到呀。

posted @ 2011-12-09 09:54 leisure 阅读(249) | 评论 (0)编辑 收藏

[nginx]post数据莫名奇妙丢失事件

昨天快下班的时候,有位同事遇到post数据接收不到的问题

首先网络架构是:
     nginx1
       |  rewrite
     nginx2
       |  pass
     resin1

nginx1是在192.168.1.1上
nginx2跟resin1是在192.168.1.2上

首先访问nginx1,由nginx1 rewrite到nginx2,nginx2直接pass到resin1,整个过程是POST形式。至于
为什么要用两层nginx,这当然是有原因的了:-)

于是乎,快速制定了几个测试案例:
1,两种访问方式:GET,POST
   GET URL带参数,没有问题。
   POST 有问题。
   让网络同事检查,处理这个location并没有做什么特殊的POST处理。——!
2,访问nginx1时,直接pass到resin1,跳过nginx2
   问题依旧。
3,去掉nginx1,访问nginx2,直接pass到resin1
   有数据的。
4,直接访问resin1
   是有数据的。

到这里,我感到很奇怪,为啥,为啥nginx1传递不了post数据呀,而nginx2可以,问题肯定出现在nginx1的配置上!~经过一番斗争后,终于找到问题关键
nginx1中,配置了一个全的post处理
if($request_method = POST) {
   rewrite .* /post.php last;
}
最后,只能大眼望细眼,汗一滴。

posted @ 2011-11-25 12:07 leisure 阅读(5919) | 评论 (0)编辑 收藏

反射判断成员变量是否静态,并获得其静态成员的值

        Field[] fields = cls.getDeclaredFields();
        Field field 
= fields[0];
        
boolean isStatic = Modifier.isStatic(field.getModifiers());
        if(isStatic) {
            System.out.println(
field.get(null).toString());
        }

posted @ 2011-11-23 17:06 leisure 阅读(7076) | 评论 (0)编辑 收藏

npm ERR! Error: socket hang up

when i use npm to install express, it goes this message:

npm info it worked if it ends with ok
npm info using npm@1.0.106
npm info using node@v0.6.2
npm info addNamed [ 'express', '' ]
npm ERR! Error: socket hang up
npm ERR! at createHangUpError (http.js:1092:15)
npm ERR! at CleartextStream. (http.js:1175:27)
npm ERR! at CleartextStream.emit (events.js:88:20)
npm ERR! at Array.0 (tls.js:731:22)
npm ERR! at EventEmitter._tickCallback (node.js:192:40)
npm ERR! Report this entire log at:
npm ERR! http://github.com/isaacs/npm/issues
npm ERR! or email it to:
npm ERR! npm-@googlegroups.com
npm ERR! 
npm ERR! System Linux 3.0.0-12-generic
npm ERR! command "node" "/usr/local/bin/npm" "install" 
"express" "-d"
npm ERR! cwd /home/leisure/software/node-v0.6.2
npm ERR! node -v v0.6.2
npm ERR! npm -v 1.0.106
npm ERR! code ECONNRESET
npm ERR! 
npm ERR! Additional logging details can be found in:
npm ERR! /home/leisure/software/node-v0.6.2/npm-
debug.log
npm 

it sounds the https_proxy is broken.
so try to use http registry to solve it:
npm config set registry http://registry.npmjs.org/

posted @ 2011-11-23 15:11 leisure 阅读(3313) | 评论 (1)编辑 收藏

MYSQL Error Code: 1093 You can't specify target table 'x' for update in FROM clause

当子查询作为条件,执行delete跟update操作时,会出现:
Error Code: 1093 You can't specify target table 'x' for update in FROM clause

作一个简单的示例:
CREATE TABLE tbl_a(
id 
INT,
NAME 
VARCHAR(50)
);

INSERT INTO tbl_a VALUES(1'leisure');
INSERT INTO tbl_a VALUES(2'leisure2');

SELECT * FROM tbl_a;

执行更新操作
UPDATE tbl_a 
    
SET id = (
        
SELECT id FROM tbl_a 
        
WHERE NAME = 'leisure2'
    ) 
WHERE NAME = 'leisure';

这时,如愿见到我们标题上的错误,解决方法如下(橙色字体系关键):
UPDATE tbl_a 
    
SET id = (
        
SELECT id FROM (
            
SELECT * FROM tbl_a WHERE NAME = 'leisure2'
        ) xx
    )
WHERE NAME = 'leisure';

posted @ 2011-11-22 09:58 leisure 阅读(3540) | 评论 (1)编辑 收藏

解决IE下location.href丢失refer信息

相信有很多朋友,用javascript做一些跳转时,往往发现refer信息丢失了。为了解决该问题,在IE下,模拟一下点击事件即可!

function jumpTo (url) {
    var isIE 
= !-[1,];
    if (isIE) {
        var link 
= document.createElement("a");
        link.href 
= url;
        link.style.display 
= 'none';
        document.body.appendChild(link);
        link.click();
    } 
else {
        window.location.href 
= url;
    }
}

posted @ 2011-11-17 16:54 leisure 阅读(1056) | 评论 (0)编辑 收藏

nginx gzip 代理服务器没效

昨天新上线了一个新应用。经测试发现,采用代理,没有开启到gzip压缩。
查了一下API,将gzip_proxied设为any即可。
gzip_proxied系根据某些请求和应答来决定是否在对代理请求的应答启用压缩。

posted @ 2011-11-16 14:53 leisure 阅读(442) | 评论 (0)编辑 收藏

utuntu登录qq(qq2010协议)

#add-apt-repository ppa:microcai/forchina
#apt-get install libqq-pidgin
如果安装过程中提示E: Unable to locate package libqq-pidgin,请先更新一下库:
#apt-get update

接着重新再安装一次。安装完后,在empathy中添加账号,在高级处,记得把qq2008改成qq2010这个协议了!

posted @ 2011-11-12 16:17 leisure 阅读(390) | 评论 (0)编辑 收藏

ubuntu开启ssh服务

ubuntu默认情况下只安装了openssh-client,没有安装openssh-server。
#sudo apt-fast install openssh-server
#/etc/init.d/ssh start
#netstat -tlp
显示tcp 0 0 *:ssh *:* LISTEN即说明SSH启动成功。

posted @ 2011-11-06 12:54 leisure 阅读(233) | 评论 (0)编辑 收藏

ubuntu安装五笔输入法(ibus-table-wubi)

IBus-Table是为基于码表的输入法即所谓的形码开发的输入法框架,常见的形码有郑码、五笔、仓颉、二笔等。

安装如下:
# apt-get install ibus-table-wubi

开启ibus输入法,按操作提示即可。
System - Preferences - Keyboard Input Methods

开启完后,回到刚才的配置选项
Input Method - 选择 Chinese - 五 Wubi86 - Add

在文本框里,ctrl + space即可切换输入法。

默认情况下,ibus-table不开启直接上屏模式(即敲完四个码,没有重码时,直接显示到屏幕上),在五笔输入法下 Ctrl + / 即可。

开机自动启动ibus
System - Preferences - Startup Applications - Add
Name: ibus daemon
Command: /usr/bin/ibus-daemon -d
Comment: start ibus daemon when gnome start

posted @ 2011-11-06 12:31 leisure 阅读(39794) | 评论 (2)编辑 收藏

android浏览本地html

android访问本地html,有几种方法。

1,可以采用自带的浏览器,地址栏键入content://com.android.htmlfileprovider/sdcard/index.html

2,可以通过opera浏览器,地址栏输入file://localhost/mnt/sdcard/index.html

3,通过ireader直接打开浏览

看html文档的话,第一,二两点完美,可以灵活缩放,浏览起来跟在线浏览没区别,至于第三点,不支持缩放,并且样式也有点小问题。另外,第一点可以直接打开apk,而第二点需要先下载,根据提示打开。呵呵,这种情况适合刷了官方room并且没有文件浏览器的情况下安装软件。

posted @ 2011-11-05 20:17 leisure 阅读(1133) | 评论 (0)编辑 收藏

resin下定义mime-mapping

mime-mapping系web服务器提供给web站点管理员能够将文件扩展名与媒体相关联的方法。
由于某种原因,有些请求到了/favicon.ico。chrome变了下载。
resin的conf/app-default.xml
<mime-mapping extension=".ico" mime-type="image/jpeg"/>

posted @ 2011-11-03 15:47 leisure 阅读(384) | 评论 (0)编辑 收藏

SimpleDateFormat多线程并发下的不安全隐患

最近偶然发现一些数据的日期有错乱,而且时间出错格式无规律,有些去了1970年了,有些月份错了,有些号数变了,而日志上看并没有异常信息!

根据用户反应,常出现在某个批量更新操作中,于是乎,也按照用户描述的,线下操作了数遍,也没有出现这种情况。

有趣的是,就算在线上操作,也并不是一定会出现这种问题,只是偶然!

我开始怀疑底层代码问题了,因为那个操作,并没有修改到日期相关的字段,为了证实这点,经过我一番的排查,
问题终于定位在DateUtil.parse等方法上,parse方法调用了一个静态的simpleDateFormat.parse方法,为什么?!为什么这个方法不稳定的?
仔细阅读了java.util.SimpleDateFormat的api,发现此信息:

Synchronization

Date formats are not synchronized. It is recommended to create separate format instances for each thread.
If multiple threads access a format concurrently, it must be synchronized externally.


很明显simpledateformat并不是线程同步的,以致并发的时候不安全!为了证实这点于是乎写了一个简单的测试程序。

package com.leisure;
import java.text.ParseException;
public class TestSimpleDateFormatThreadSafe extends Thread {
    @Override
    public void run() {
        while(true) {
            try {
                this.join(2000);
            } 
catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            try {
                System.out.println(DateUtil.parse(
"2011-10-11 06:02:20"));
            } 
catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        for(int i = 0; i < 20; i++)
            new TestSimpleDateFormatThreadSafe().start();
    }
}

package com.leisure;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateUtil {
    
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    
public static Date parse(String str) throws ParseException {
        
return sdf.parse(str);
    }
}

输出结果:

Tue Oct 11 18:02:20 CST 2011

Tue Oct 11 18:02:20 CST 2011

Sun Oct 11 18:02:20 CST 1970

Tue Oct 11 18:02:20 CST 2011

Thu Jan 01 18:02:20 CST 1970

Sat Dec 11 18:02:20 CST 2010

Tue Oct 11 18:02:20 CST 2011

Exception in thread "Thread-18" java.lang.NumberFormatException: multiple points

at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)

at java.lang.Double.parseDouble(Unknown Source)

at java.text.DigitList.getDouble(Unknown Source)

at java.text.DecimalFormat.parse(Unknown Source)

at java.text.SimpleDateFormat.subParse(Unknown Source)

at java.text.SimpleDateFormat.parse(Unknown Source)

at java.text.DateFormat.parse(Unknown Source)

at com.leisure.DateUtil.parse(DateUtil.java:12)

at com.leisure.TestSimpleDateFormatThreadSafe.run(TestSimpleDateFormatThreadSafe.java:16)

Fri Dec 23 19:02:20 CST 2011

Fri Dec 23 18:02:20 CST 2011

输出结果很明显了,跟线上数据出现的问题基本一致。不过按照这里看到的结果,有报错,再仔细阅读了应用的底层代码,
某个位置拦截了部份异常,没有记录也没有向上抛出处理,到这里,我只想问一句:底层代码谁写的?

posted @ 2011-10-15 00:22 leisure 阅读(2860) | 评论 (0)编辑 收藏