BlogJava 联系 聚合 管理  

Blog Stats

随笔档案


bitmap

bitmap

2009年7月20日 #

     摘要: /**   * author:annegu  * date:2009-07-16   */ annegu做了一个简单的Http多线程的下载程序,来讨论一下多线程并发下载以及断点续传的问题。 这个程序的功能,就是可以分多个线程从目标地址上下载数据,每个线程负责下载一部分,并可以支持断点续传和超时重连。 下载的方法是do...  阅读全文
posted @ 2009-07-20 20:27 bitmap| 编辑 收藏

2009年7月19日 #

     摘要: ECC ECC-Elliptic Curves Cryptography,椭圆曲线密码编码学,是目前已知的公钥体制中,对每比特所提供加密强度最高的一种体制。在软件注册保护方面起到很大的作用,一般的序列号通常由该算法产生。     当我开始整理《Java加密技术(二)》的时候,我就已经在开始研究ECC了,但是关于Java实现ECC算法的资料实在是太少了,无论是国...  阅读全文
posted @ 2009-07-19 09:08 bitmap| 编辑 收藏

2009年7月17日 #

     摘要: DSA DSA-Digital Signature Algorithm 是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard)。简单的说,这是一种更高级的验证方式,用作数字签名。不单单只有公钥、私钥,还有数字签名。私钥加密生成数字签名,公钥验证数据及签名。如果数据和签名不匹配则认为验证失败!数字签名的作用就是校验数据在传输...  阅读全文
posted @ 2009-07-17 21:27 bitmap| 编辑 收藏

2009年7月14日 #

最近与一位创业公司的朋友私下交流了一些项目管理和软件开发的心得,是互联网创业型公司,通过几次的交流,加深了我对互联网创业的一些感悟,本来不太想拿到桌面上说,但实在忍不住,还是想拿出来和希望创业的朋友讨论下。

那么我对互联网公司的比较感兴趣的地方主要体现在软件质量和技术管理方面,以下2点可以作为讨论的提纲:

     1 软件质量,尽管质量是我们嘴边经常挂念的一个词,但不少创业型公司的投机心理太重,在与这些负责人的交流中发现,谈论的更多的是新想法、新概念,有非常重的商业气息,当然这没什么不好,但我看了他们的一些产品后发现,他们所做的产品用户体验非常糟糕,就拿界面来说,非常的粗糙,由于有家公司做的产品和易趣类似,我特意打开2个窗口对比一下,总觉得易趣的看起来比较舒服,他们整体布局倒模仿易趣倒挺像,但问题就体现在细节上,图片失真严重、字体风格不一致、细节处理的不到位。好了,那就凑合着看吧,发现该产品的功能非常的多,但让人郁闷的是,很多功能是有问题的,比如明明提示我系统给偶发了个邮件,但就是找不到,有时候提交表单是可以的,有时候见到一堆java异常错误。所以我觉得这就是典型的追求功能的庞大而导致质量的缩水。

    其实自从豆瓣开始流行后,大家都意识到功能做的简洁原来是有好处的,有不少创业者声称自己要向豆瓣看齐,鄙视csdn,坚决走简洁之路,但让我纳闷的是,很少有人真正的坚持下去,我有个同学06年底曾在一家创业公司玩过python,准备做一个很有趣的网站,叫做抱怨网,其实是蛮有创意的,不久前JE不是有个哥们在四处发帖说我爱我家黑中介的事,其实本来这个网站就是干这个事的,专门揭不良企业底的,但做着做着,成了巨无霸,开始是把大众点评网的功能加进去,接着又开始融进赶集网的分类信息功能,最后有把智联招聘的招聘功能加上了,结局就是1年不到,网站不出意料的死掉了,原因就是用户体验差,根本不感兴趣!最后我替他们老板做了下反思,其实说实话,我还是很理解创业人的心,看到好东西都想要,而且之前几年在互联网圈钱谁都眼红。另外,他们的功能尽管是抄袭别人的,但还是有一定的特色与盈利模式,并且各个功能分的也蛮清的。 所以我觉得失败的原因不能简单的归结为功能太多,而是质量,小公司也就那几号人,作为开发人员,面对这么多的需求,只有拼命的赶进度,丫还有时间考虑质量或者用户体验吗?所以没有一定的资本与一批强有力的管理和开发人员,切勿贪大求全,否则很可能就是在生产垃圾。其实质量这个东西从高的层面上说就是用户体验的好坏,bug少不见得质量高,但用户体验差的东西绝对就是垃圾。

    最近市面上有个说法有个说法是30w足以模仿个淘宝,我认为就是扯淡,误导了很多创业者,认为花点银子,雇几个人,就可以轻松抄袭淘宝了,咱先不说市场投资,只谈技术,表面上看淘宝,丫就是一个破网站,但背后的技术你看的见吗?稳定性、性能、维护、可扩展性,这些都和软件质量息息相关,直接影响着用户的满意度,你确定真的做到了吗?淘宝的架构师一年的薪水也30w了。所以我觉得创业者要领悟毛泽东思想,采用各个击破的战术,在有限的资源下约束的自己产品的功能,做到小而美。

     这里举个正面的例子,有家位于芝加哥、名为37 Signals的小公司,正是这种拥抱限制的方式之代表者。37 Signals最初是一家网页设计资讯公司,后来为了满足自身需求而将业务扩展到软件开发领域。他们编写了一些用于项目管理的内部工具。为了和客户沟通, 就向客户开放了部分系统。公司创始人和总裁杰森•弗瑞德(Jason Fried)解释说,在他们自己意识到之前,已经做出了一套基于网页的应用。又做了4个月,他们把软件转换为称作Basecamp的服务。 Basecamp发布于2004年2月,很快在类似Flickr和Google的Gmail等新Web富应用天堂中名列前茅。

     Basecamp只是这家公司花一年多时间投入少量程序员做出来的一系列值得注意的小而精的产品之一。Basecamp之后是Ta-da List,用于保存和共享待办事项(及类似事项)列表。几个月后推出了Backpack,它允许用户保存和共享便签及文件。每种产品都可靠并易于使用,而 且都是精心设计的。每种产品通常也都只包括少量新特性。例如,Basecamp就有一些精巧的电子邮件功能:和其他服务和程序一样,也可以设置邮件到达提醒——还可以从另外的计算机或手机等移动设备向Backpack网页发送邮件,邮件文本就会在页面上显示出来。

     2 技术管理,你会发现很多公司的负责人不是很懂技术,但却是负责技术的,丫今天听到SOA是个好东西,号令纷纷SOA,反正大家都不理解这个含糊不清的东西,做呗,看谁能忽悠的过谁,一般来讲,创业型公司为了节约成本,不会预留专门的QA,有专门的测试人员就不错了,所以缺乏一个质量保证的环节,遇到问题怎么办?谁做的谁改,改成什么样没人关心,只要负责人看到问题解决了就可以了,但,我想问的是,不良代码背后的隐患你知道吗?结果就是你咬牙给开发人员开工资,开发人员假装帮你实现梦想,或者说造就一批划水的人。其实很多东西不是钱的问题,也不要以为多开点薪水就可以留住人心。另外我觉得很多技术负责人喜欢把东西模糊化,比如把软件即服务的理念挂在嘴边,但做起来是另一码子事,我觉得作为一个技术负责人自己就要身先士卒,至少在创业公司是这样,这样才更有说服力,遇到问题自己应当第一个冲上去,拿出具体的解决方案,对代码应当做到精细管理,做到心中有数。说到底,创业公司得有一个技术核心,一个真正能实现你的想法的人,一个可以让大家凝聚起来的人,不至于让大家划水的人。

好了,先说那么多,希望各位准备创业的同仁能真正的树立精品意识,打造精品,实现梦想

posted @ 2009-07-14 13:14 bitmap| 编辑 收藏

2009年7月12日 #

问题的产生原因
       页面提交给Action去进行业务处理,Action再跳转回前台页面,但这时URL依然是“页面提交给Action的链接”,这时前台刷新一下页面,就变成再次执行了一次提交操作。

 

解决思路
     1,在Action页面中跳转的时候用重定向,可以在struts-config.xml中配置<forward ... redirect=“true”>
不过这种方法会使得request中放置数据丢失;
     2,用Token令牌环来实现
          提交到Action的时候,进行一系列操作,然后保存一个标志,这时再跳转到前台页面。如果前台页面刷新的话,Action通过查看是否有标志,就能判断用户是刷新还是提交。

 

Action中操作令牌的方法
      一: saveToken(HttpServletRequest request)
            创建一个新令牌,并将其保存在当前用户的会话中,如果用户的会话不存在,将首先创建新会话对象
      二: isTokenValid(HttpServletRequest request)
            判断存储在当前会话中的令牌值和请求参数中的令牌值是否匹配,如果匹配,返回true,否则返回false 。
            以下情况返回false:
                  1,用户的HttpSession不存在
                  2,用户Session中没有保存令牌值
                  3,在用户请求参数中没有令牌值
                  4,存储在用户Session范围内的令牌值和请求参数中 的令牌值不匹配
       三:resetToken()
             删除保存在Session范围内的令牌值

 

示例代码

1,进入目标页,如 http://www.bt285.cn ,通过IndexAction转发,其中需要保存令牌:

public ActionForward execute(ActionMapping mapping, ActionForm form,   
        HttpServletRequest request, HttpServletResponse response)   
        
throws Exception {   
    saveToken(request);   
    
return mapping.findForward("index");// http://www.5a520.cn   
}
  
 2,目标页面(test.jsp)需要使用Struts标签库:
<body>  
    
<html:form action=" http://www.5a520.cn test.do" method="post">  
        
<input type="submit" value="提交" />  
    
</html:form>  
</body>  
当提交test.jsp时提交到TestAction处理:
<struts-config>  
    
<form-beans>  
        
<form-bean name="testForm" type="com.tanlan.struts.form.TestForm">  
        
</form-bean>  
    
</form-beans>  
    
<action-mappings>  
        
<action path="/index" type="com.tanlan.struts.action.IndexAction">  
            
<forward name="index" path="/index.jsp"></forward>  
        
</action>  
        
<action path="/test" type="com.tanlan.struts.action.TestAction"  
            name
="testForm" input="/index.jsp">  
            
<forward name="test" path="/test.jsp"></forward>  
            
<forward name="error" path="/error.jsp"></forward>  
        
</action>  
    
</action-mappings>  
</struts-config>  

至此,大功告成!

完整示例请参考附件。

 

posted @ 2009-07-12 12:55 bitmap| 编辑 收藏

2009年7月11日 #

     摘要: 接下来我们分析DH加密算法,一种适基于密钥一致协议的加密算法。 DH Diffie-Hellman算法(D-H算法),密钥一致协议。是由公开密钥密码体制的奠基人Diffie和Hellman所提出的一种思想。简单的说就是允许两名用户在公开媒体上交换信息以生成"一致"的、可以共享的密钥。换句话说,就是由甲方产出一对密钥(公钥、私钥),乙方依照甲方公钥产生乙方密钥对(公钥、私钥)。以此为基线,作...  阅读全文
posted @ 2009-07-11 20:01 bitmap| 编辑 收藏

2009年7月9日 #

     摘要: RSA     这种算法1978年就出现了,它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman。     这种加密算法的特点主要是密钥的变化,上文我们看到DES只有一个密钥。相当于只有一把钥匙,如果...  阅读全文
posted @ 2009-07-09 21:08 bitmap| 编辑 收藏

2009年7月8日 #

除了DES,我们还知道有DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)等多种对称加密方式,其实现方式大同小异,这里介绍对称加密的另一个算法——PBE

PBE
    PBE——Password-based encryption(基于密码加密)。其特点在于口令由用户自己掌管,不借助任何物理媒体;采用随机数(这里我们叫做盐)杂凑多重加密等方法保证数据的安全性。是一种简便的加密方式。



通过java代码实现如下:

 

import java.security.Key;   
import java.util.Random;   
  
import javax.crypto.Cipher;   
import javax.crypto.SecretKey;   
import javax.crypto.SecretKeyFactory;   
import javax.crypto.spec.PBEKeySpec;   
import javax.crypto.spec.PBEParameterSpec;   
  
/**  
 * PBE安全编码组件 
http://www.bt285.cn   http://www.5a520.cn 
 *   
 * 
@author 梁栋  
 * 
@version 1.0  
 * 
@since 1.0  
 
*/
  
public abstract class PBECoder extends Coder {   
    
/**  
     * 支持以下任意一种算法  
     *   
     * <pre>  
     * PBEWithMD5AndDES   
     * PBEWithMD5AndTripleDES   
     * PBEWithSHA1AndDESede  
     * PBEWithSHA1AndRC2_40  
     * </pre>  
     
*/
  
    
public static final String ALGORITHM = "PBEWITHMD5andDES";   
  
    
/**  
     * 盐初始化  
     *   
     * 
@return  
     * 
@throws Exception  
     
*/
  
    
public static byte[] initSalt() throws Exception {   
        
byte[] salt = new byte[8];   
        Random random 
= new Random();   
        random.nextBytes(salt);   
        
return salt;   
    }
   
  
    
/**  
     * 转换密钥<br>  
     *   
     * 
@param password  
     * 
@return  
     * 
@throws Exception  
     
*/
  
    
private static Key toKey(String password) throws Exception {   
        PBEKeySpec keySpec 
= new PBEKeySpec(password.toCharArray());   
        SecretKeyFactory keyFactory 
= SecretKeyFactory.getInstance(ALGORITHM);   
        SecretKey secretKey 
= keyFactory.generateSecret(keySpec);   
  
        
return secretKey;   
    }
   
  
    
/**  
     * 加密  
     *   
     * 
@param data  
     *            数据  
     * 
@param password  
     *            密码  
     * 
@param salt  
     *            盐  
     * 
@return  
     * 
@throws Exception  
     
*/
  
    
public static byte[] encrypt(byte[] data, String password, byte[] salt)   
            
throws Exception {   
  
        Key key 
= toKey(password);   
  
        PBEParameterSpec paramSpec 
= new PBEParameterSpec(salt, 100);   
        Cipher cipher 
= Cipher.getInstance(ALGORITHM);   
        cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);   
  
        
return cipher.doFinal(data);   
  
    }
   
  
    
/**  
     * 解密  
     *   
     * 
@param data  
     *            数据  
     * 
@param password  
     *            密码  
     * 
@param salt  
     *            盐  
     * 
@return  
     * 
@throws Exception  
     
*/
  
    
public static byte[] decrypt(byte[] data, String password, byte[] salt)   
            
throws Exception {   
  
        Key key 
= toKey(password);   
  
        PBEParameterSpec paramSpec 
= new PBEParameterSpec(salt, 100);   
        Cipher cipher 
= Cipher.getInstance(ALGORITHM);   
        cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);   
  
        
return cipher.doFinal(data);   
  
    }
   
}
  

再给出一个测试类:
import static org.junit.Assert.*;   
  
import org.junit.Test;   
  
/**  
 *   
 * 
@author 梁栋  http://www.5a520.cn http://www.feng123.com
 * 
@version 1.0  
 * 
@since 1.0  
 
*/
  
public class PBECoderTest {   
  
    @Test  
    
public void test() throws Exception {   
        String inputStr 
= "abc";   
        System.err.println(
"原文: " + inputStr);   
        
byte[] input = inputStr.getBytes();   
  
        String pwd 
= "efg";   
        System.err.println(
"密码: " + pwd);   
  
        
byte[] salt = PBECoder.initSalt();   
  
        
byte[] data = PBECoder.encrypt(input, pwd, salt);   
  
        System.err.println(
"加密后: " + PBECoder.encryptBASE64(data));   
  
        
byte[] output = PBECoder.decrypt(data, pwd, salt);   
        String outputStr 
= new String(output);   
  
        System.err.println(
"解密后: " + outputStr);   
        assertEquals(inputStr, outputStr);   
    }
   
  
}
  

控制台输出:

  • 原文: abc   
  • 密码: efg   
  • 加密后: iCZ0uRtaAhE=   
  •   
  • 解密后: abc  

  •  

     

    posted @ 2009-07-08 22:22 bitmap| 编辑 收藏

    2009年7月6日 #

    一、利用random方法来生成随机数。

      在Java语言中生成随机数相对来说比较简单,因为有一个现成的方法可以使用。在Math类中,Java语言提供了一个叫做random的方法。通过这个方法可以让系统产生随机数。不过默认情况下,其产生的随机数范围比较小,为大于等于0到小于1的double型随机数。虽然其随机数产生的范围比较小,不能够满足日常的需求。如日常工作中可能需要产生整数的随机数。其实,只要对这个方法进行一些灵活的处理,就可以获取任意范围的随机数。http://www.bt285.cn  http://www.5a520.cn  

      如我们可以先通过random方法生成一个随机数,然后将结果乘以10。此时产生的随机数字即为大于等于0小于10的数字。然后再利用Int方法进行转换(它会去掉小数掉后面的数字,即只获取整数部分,不是四舍五入)。最后即可获取一个0到9的整数型随机数字。其实现方法很简单,就是对原有的random方法按照如下的格式进行变型:(int)(Math.Random()*10)即可。其实我们还可以对这个方法进行扩展,让其产生任意范围内的随机数。至需要将这个10换成n即可,如改为(int)(Math.Random()*n)。此时应用程序就会产生一个大于等于0小与n之间的随机数。如将n设置为5,那么其就会产生一个0到5之间的整数型的随机数。如果将这个写成一个带参数的方法,那么只要用户输入需要生成随机数的最大值,就可以让这个方法来生成制定范围的随机数。在Java中定义自己的工具库

      有时候程序员可能需要生成一个指定范围内的随机偶数或者奇数。此时是否可以通过这个方法来实现呢?答案是肯定的。如现在程序要需要生成一个1-100范围内的偶数。此时该如何实现?首先,需要生成一个0到99之内的随机数(至于这里为什么是99,大家耐心看下去就知道原因了)。要实现这个需求,很简单吧,只要通过如下语句就可以实现: i=1+(int)(Math.Random()*100)。其中(int)(Math.Random()*99)产生0到99的整数型随机数。然后再加上1就是产生1到100之间的随机整数。然后将产生的随机数赋值给变量i。但是此时其产生的随机数即有偶数,又有奇数。而现在程序员需要的是一个随机的偶数。那么我们可以在后面加上一个if判断语句。将这个随机数除以2,如果没有余数的话(或者余数为0)则表明这个随机数是偶数,直接返回即可。如果其返回的余数不为零,那么就表明其是奇数,我们只要加上1就变为了偶数,返回即可。注意,在上面的随机数生成中,笔者采用的范围是0到99,然后再加上1让其变为1到100的随机数。最后的结果就是生成1到100之间的随机偶数。其实,如果要范围随机奇数的话,至需要对上面的语句进行稍微的修改即可。Java:改变你我的世界

      假设现在用户想生成一个任意范围内的奇数或者偶数,能够实现吗?假设现在用户想实现一个m到n之间的任意偶数(其中m

      可见虽然random方法其自身产生的随机数有比较严格的范围限制。但是只要对其进行合理的转换,程序员仍然可以采用这个方法产生用户所需要的随机数据。

      二、通过Random类来生成随机数。

      在Java语言中,除了可以通过random 方法来产生随机数之外,还可以通过一个random类来产生随机数。程序开发人员可以通过实例化一个Random对象来创建一个随机数的生成器。如Random i=new Random()。通过这条语句就利用了Random类创建了一个随机数的生成器。不过以这种方法创建随机数时,与采用Random方法产生随机数的机制不同。利用现在这种方式实例化对象时,Java编译器会以系统当前的时间作为随机数生成器的种子。由于时间时时刻刻在变化的。若以这个时间作为生成器的种子,就可以保证生成的随机数真的是随机的,其生成的随机数重复率会大大的降低。

      利用这种方法其比较方便。如可以利用提供的关键字,让程序返回一个随机的整数(采用int nextInt(10))等等。不过其返回控制要比Random方法困难一点。如现在需要系统提供一个10到50之间的随机奇数, 利用这个Random类就无法完成。也就是说,利用这个Random类来生成随机数,其只能够控制上限,而不能够控制下限。换一句话说,其可以指定最大的随机数范围,而不能够指定最小的随机数范围。所以,在灵活性上,其比Random方法要稍微差一点。

      另外利用这个方法来实现的话,必须先创建一个对象。也就是说利用Randow类来创建对象。这跟Randow方法不同。像上面举的例子中,Randow方法本身就是一个math类中方法,可以直接调用,省去对象创建的方法。为此笔者建议各位读者与程序开发人员,最好还是使用Random方法来创建随机数。只有在生成一些比较特殊的随机数时采用Random类。如现在需要生成一个概率密度为高斯分布的双精度值随机数时,则通过采用Random类的方法来创建随机数相对来说比较简单一点。

    三、产生随机的字符。

      上面介绍的两种方法,产生的都是随机的数值型数据。但是有时候用户可能还需要产生随机的字符。其实也可以利用random方法来产生随机字符。如可以利用代码生成一个随机的小写字符:(char)(‘a’+Math.random()*(‘z’-‘a’+1))。其实这跟生成任意两个数之间的随机数类似。通过以上的代码就可以生成一个范围之内的任意随机字符。通过对这个代码进行适当的修整,还可以生成任意两个字符之间的随机字符与任意大写字符的随机字符。其转换的方式跟上面提到的任意范围之内的随机数类似。各位读者若感兴趣的话,可以自己进行测试一下。师傅领进门,修行在自身。如果笔者在这里一股脑儿将所有的答案告诉大家,大家的印象不会很深。大家若回去自己动手试试看,反而更容易记住。

      笔者在这里给大家一个提示,只需要根据m+(int)(Math.Random()*(n-m))这条语句来调整(char)(‘a’+Math.random()*(‘z’-‘a’+1))这个代码即可。

      最后笔者需要强调的一点就是在用户传入参数的时候,最好要对用户传入的参数进行合法性检查。以免用户传入的参数不符合既定的要求,如参数需要的是数值型的数据而传入的却是字符型的数据,而导致程序运行出错。
    posted @ 2009-07-06 22:22 bitmap| 编辑 收藏

    2009年7月5日 #

         摘要: 接下来我们介绍对称加密算法,最常用的莫过于DES数据加密算法。 DES DES-Data Encryption Standard,即数据加密算法。是IBM公司于1975年研究成功并公开发表的。DES算法的入口参数有三个:Key、Data、Mode。其中Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:...  阅读全文
    posted @ 2009-07-05 21:18 bitmap| 编辑 收藏

    仅列出标题  下一页