`
dyccsxg
  • 浏览: 201710 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
社区版块
存档分类
收藏列表
标题 标签 来源
HTTPS详解
简介 
  它是由Netscape开发并内置于其浏览器中,用于对数据进行压缩和解压操作,并返回网络上传送回的结果。HTTPS实际上应用了Netscape的安全套接字层(SSL)作为HTTP应用层的子层。(HTTPS使用端口443,而不是象HTTP那样使用端口80来和TCP/IP进行通信。)SSL使用40 位关键字作为RC4流加密算法,这对于商业信息的加密是合适的。HTTPS和SSL支持使用X.509数字认证,如果需要的话用户可以确认发送者是谁。 
  也就是说它的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。 
HTTPS和HTTP的区别 
  一、https协议需要到ca申请证书,一般免费证书很少,需要交费。 
  二、http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。 
  三、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。 
  四、http的连接很简单,是无状态的,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议要比http协议安全。 
HTTPS解决的问题
一、信任主机的问题.
  采用https 的server(服务器) 必须从CA (Certificate Authority)申请一个用于证明服务器用途类型的证书. 该证书只有用于对应的server 的时候,客户端才信任此主机. 所以目前所有的银行系统网站,关键部分应用都是https 的. 客户通过信任该证书,从而信任了该主机. 其实这样做效率很低,但是银行更侧重安全. 这一点对我们没有任何意义,我们的server ,采用的证书不管自己issue(发布) 还是从公众的地方issue, 客户端都是自己人,所以我们也就肯定信任该server. 
二、通讯过程中的数据的泄密和被篡改
  1. 一般意义上的https, 就是 server 有一个证书. 
  a) 主要目的是保证server 就是他声称的server. 这个跟第一点一样. 
  b) 服务端和客户端之间的所有通讯,都是加密的. 
  i. 具体讲,是客户端产生一个对称的密钥,通过server 的证书来交换密钥. 一般意义上的握手过程. 
  ii. 加下来所有的信息往来就都是加密的. 第三方即使截获,也没有任何意义.因为他没有密钥. 当然篡改也就没有什么意义了. 
  2. 少许对客户端有要求的情况下,会要求客户端也必须有一个证书. 
  a) 这里客户端证书,其实就类似表示个人信息的时候,除了用户名/密码, 还有一个CA 认证过的身份. 应为个人证书一般来说上别人无法模拟的,所有这样能够更深的确认自己的身份. 
  b) 目前少数个人银行的专业版是这种做法,具体证书可能是拿U盘(即U盾)作为一个备份的载体. 
限制
概述
  它的安全保护依赖浏览器的正确实现以及服务器软件、实际加密算法的支持. 
  一种常见的误解是“银行用户在线使用https:就能充分彻底保障他们的银行卡号不被偷窃。”实际上,与服务器的加密连接中能保护银行卡号的部分,只有用户到服务器之间的连接及服务器自身。并不能绝对确保服务器自己是安全的,这点甚至已被攻击者利用,常见例子是模仿银行域名的钓鱼攻击。少数罕见攻击在网站传输客户数据时发生,攻击者尝试窃听数据于传输中。 
  商业网站被人们期望迅速尽早引入新的特殊处理程序到金融网关,仅保留传输码(transaction number)。不过他们常常存储银行卡号在同一个数据库里。那些数据库和服务器少数情况有可能被未授权用户攻击和损害。 
TLS 1.1之前
  这段仅针对TLS 1.1之前的状况。因为SSL位于http的下一层,并不能理解更高层协议,通常SSL服务器仅能颁证给特定的IP/端口组合。这是指它经常不能在虚拟主机(基于域名)上与HTTP正常组合成HTTPS。 
  这一点已被更新在即将来临的TLS 1.1中—会完全支持基于域名的虚拟主机。 
  SSL介绍 
  SSL (Secure Socket Layer) 
  为Netscape所研发,用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,可确保数据在网络 
  上之传输过程中不会被截取及窃听。目前一般通用之规格为40 bit之安全标准,美国则已推出128 bit之更高安全 
  标准,但限制出境。只要3.0版本以上之I.E.或Netscape浏览器即可支持SSL。 
  当前版本为3.0。它已被广泛地用于Web浏览器与服务器之间的身份认证和加密数据传输。 
  SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。 SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。 
SSL协议提供的服务主要有哪些?
  1)认证用户和服务器,确保数据发送到正确的客户机和服务器; 
  2)加密数据以防止数据中途被窃取; 
  3)维护数据的完整性,确保数据在传输过程中不被改变。 
SSL协议的工作流程:
  服务器认证阶段:1)客户端向服务器发送一个开始信息“Hello”以便开始一个新的会话连接;2)服务器根据客户的信息确定是否需要生成新的主密钥,如需要则服务器在响应客户的“Hello”信息时将包含生成主密钥所需的信息;3)客户根据收到的服务器响应信息,产生一个主密钥,并用服务器的公开密钥加密后传给服务器;4)服务器恢复该主密钥,并返回给客户一个用主密钥认证的信息,以此让客户认证服务器。 
用户认证阶段:
  在此之前,服务器已经通过了客户认证,这一阶段主要完成对客户的认证。经认证的服务器发送一个提问给客户,客户则返回(数字)签名后的提问和其公开密钥,从而向服务器提供认证。 
  从SSL 协议所提供的服务及其工作流程可以看出,SSL协议运行的基础是商家对消费者信息保密的承诺,这就有利于商家而不利于消费者。在电子商务初级阶段,由于运作电子商务的企业大多是信誉较高的大公司,因此这问题还没有充分暴露出来。但随着电子商务的发展,各中小型公司也参与进来,这样在电子支付过程中的单一认证问题就越来越突出。虽然在SSL3.0中通过数字签名和数字证书可实现浏览器和Web服务器双方的身份验证,但是SSL协议仍存在一些问题,比如,只能提供交易中客户与服务器间的双方认证,在涉及多方的电子交易中,SSL协议并不能协调各方间的安全传输和信任关系。在这种情况下,Visa和 MasterCard两大信用卡公组织制定了SET协议,为网上信用卡支付提供了全球性的标准。 
SSL协议的握手过程
  为了便于更好的认识和理解 SSL 协议,这里着重介绍 SSL 协议的握手协议。SSL 协议既用到了公钥加密技术又用到了对称加密技术,对称加密技术虽然比公钥加密技术的速度快,可是公钥加密技术提供了更好的身份认证技术。SSL 的握手协议非常有效的让客户和服务器之间完成相互之间的身份认证,其主要过程如下: 
  ①客户端的浏览器向服务器传送客户端 SSL 协议的版本号,加密算法的种类,产生的随机数,以及其他服务器和客户端之间通讯所需要的各种信息。 
  ②服务器向客户端传送 SSL 协议的版本号,加密算法的种类,随机数以及其他相关信息,同时服务器还将向客户端传送自己的证书。 
  ③客户利用服务器传过来的信息验证服务器的合法性,服务器的合法性包括:证书是否过期,发行服务器证书的 CA 是否可靠,发行者证书的公钥能否正确解开服务器证书的“发行者的数字签名”,服务器证书上的域名是否和服务器的实际域名相匹配。如果合法性验证没有通过,通讯将断开;如果合法性验证通过,将继续进行第四步。 
  ④用户端随机产生一个用于后面通讯的“对称密码”,然后用服务器的公钥(服务器的公钥从步骤②中的服务器的证书中获得)对其加密,然后将加密后的“预主密码”传给服务器。 
  ⑤如果服务器要求客户的身份认证(在握手过程中为可选),用户可以建立一个随机数然后对其进行数据签名,将这个含有签名的随机数和客户自己的证书以及加密过的“预主密码”一起传给服务器。 
  ⑥如果服务器要求客户的身份认证,服务器必须检验客户证书和签名随机数的合法性,具体的合法性验证过程包括:客户的证书使用日期是否有效,为客户提供证书的CA 是否可靠,发行CA 的公钥能否正确解开客户证书的发行 CA 的数字签名,检查客户的证书是否在证书废止列表(CRL)中。检验如果没有通过,通讯立刻中断;如果验证通过,服务器将用自己的私钥解开加密的“预主密码”,然后执行一系列步骤来产生主通讯密码(客户端也将通过同样的方法产生相同的主通讯密码)。 
  ⑦服务器和客户端用相同的主密码即“通话密码”,一个对称密钥用于 SSL 协议的安全数据通讯的加解密通讯。同时在 SSL 通讯过程中还要完成数据通讯的完整性,防止数据通讯中的任何变化。 
  ⑧客户端向服务器端发出信息,指明后面的数据通讯将使用的步骤⑦中的主密码为对称密钥,同时通知服务器客户端的握手过程结束。 
  ⑨服务器向客户端发出信息,指明后面的数据通讯将使用的步骤⑦中的主密码为对称密钥,同时通知客户端服务器端的握手过程结束。 
  ⑩SSL 的握手部分结束,SSL 安全通道的数据通讯开始,客户和服务器开始使用相同的对称密钥进行数据通讯,同时进行通讯完整性的检验。 
证书各部分的含义
  证书版本号,不同版本的证书格式不同 
  Serial Number 序列号,同一身份验证机构签发的证书序列号唯一 
  Algorithm Identifier 签名算法,包括必要的参数 Issuer 身份验证机构的标识信息 
  Period of Validity 有效期 
  Subject 证书持有人的标识信息 
  Subject’s Public Key 证书持有人的公钥 
  Signature 身份验证机构对证书的签名 
  证书的格式 认证中心所发放的证书均遵循 X.509 V3 标准,其基本格式如下: 
  证书版本号(Certificate Format Version) 
  含义:用来指定证书格式采用的 X.509 版本号。 
  证书序列号(Certificate Serial Number) 
  含义:用来指定证书的唯一序列号,以标识 CA 发出的所有公钥证书。 
  签名(Signature) 算法标识(Algorithm Identifier) 
  含义:用来指定 CA 签发证书所用的签名算法。 
  签发此证书的 CA 名称(Issuer ) 
  含义:用来指定签发证书的 CA 的 X.500 唯一名称(DN, Distinguished Name)。 
  证书有效期(Validity Period) 起始日期(notBefore)终止日期(notAfter) 
  含义:用来指定证书起始日期和终止日期。 
  用户名称(Subject) 
  含义:用来指定证书用户的 X.500 唯一名称(DN,Distinguished Name)。 
  用户公钥信息(Subject Public Key Information) 算法(algorithm) 算法标识(Algorithm Identifier) 用户公钥(subject Public Key) 
  含义:用来标识公钥使用的算法,并包含公钥本身。 
  证书扩充部分(扩展域)(Extensions) 
  含义:用来指定额外信息。  
  X.509 V3 证书的扩充部分(扩展域)及实现方法如下: 
  CA 的公钥标识(Authority Key Identifier) 
  公钥标识(SET 未使用)(Key Identifier) 
  签发证书者证书的签发者的甄别名(Certificate Issuer) 
  签发证书者证书的序列号(Certificate Serial Number) 
  X.509 V3 证书的扩充部分(扩展域)及实现CA 的公钥标识(Authority Key Identifier) 
  公钥标识(SET 未使用)(Key Identifier) 
  签发证书者证书的签发者的甄别名(Certificat签发证书者证书的序列号(Certificate Serial Number) 
  含义:CA 签名证书所用的密钥对的唯一标识用户的公钥标识(Subject Key Identifier)  
  含义:用来标识与证书中公钥相关的特定密钥进行解密。 
  证书中的公钥用途(Key Usage) 
  含义:用来指定公钥用途。 
  用户的私钥有效期(Private Key Usage Period) 起始日期(Note Before) 终止日期(Note After) 
  含义:用来指定用户签名私钥的起始日期和终止日期。 
  CA 承认的证书政策列表(Certificate Policies) 
  含义:用来指定用户证书所适用的政策,证书政策可由对象标识符表示。 
  用户的代用名(Substitutional Name) 
  含义:用来指定用户的代用名。 
  CA 的代用名(Issuer Alt Name) 
  含义:用来指定 CA 的代用名。 
  基本制约(Basic Constraints) 
  含义:用来表明证书用户是最终用户还是 CA。 在 SET 系统中有一些私有扩充部分(扩展域)Hashed Root Key 含义:只在根证书中使用,用于证书更新时进行回溯。 
  证书类型(Certificate Type) 
  含义:用来区别不同的实体。该项是必选的。 
  商户数据(Merchant Data) 
  含义:包含支付网关需要的所有商户信息。 
  持卡人证书需求(Card Cert Required) 
  含义:显示支付网关是否支持与没有证书的持卡人进行交易。 
  SET 扩展(SETExtensions) 
  含义:列出支付网关支持的支付命令的 SET 信息扩展。 
  CRL 数据定义版本(Version) 
  含义:显示 CRL 的版本号。 
  CRL 的签发者(Issuer) 
  含义:指明签发 CRL 的 CA 的甄别名。 
  CRL 发布时间(this Update) 预计下一个 CRL 更新时间(Next Update) 撤销证书信息目录(Revoked Certificates) CRL 扩展(CRL Extension) CA 的公钥标识(Authority Key Identifier) CRL 号(CRL Number)
开发工具整理
1. Notepad ++
   http://notepad-plus-plus.org/ 
   Notepad++ 是一款 Windows 下的开源代码编辑器,支持多种编程语言。

2. Fiddler 
   http://www.fiddler2.com/fiddler2/ 
   Fiddler 是一款 Web 调试代理软件,它能够记录所有客户端和服务器间的 HTTP 请求,允许你监视、设置断点。
javascript 基础知识 javascript
# javascript if (condition) { ... }
  转换规则: 
    Any value that is not [undefined, null, 0, NaN, '']、and any object(including Boolean(false)) -> true
Java 内存泄露分析
1. 安装 eclipse MAT 插件
   # 1. 登录 MAT 官网
   http://www.eclipse.org/mat/downloads.php
   # 2. 找到在线更新地址
   http://download.eclipse.org/mat/1.1/update-site/
   # 3. 在 eclipse 中安装 MAT 插件
   Help -> Install New Software...
   # 4. 安装完成后重启 eclipse
   # 5. 切换到 Memory Analysis Perspective
2. 获取 JVM 内存快照
   # 1. 获取 java 进程 id
   > jps
   # 2. 根据进程 id 获取内存快照
   > jmap -dump:format=b,file=d:\temp\current_jvm.bin 3912
3. 分析 JVM 内存快照
   # 打开快照文件
   File -> Open Heap Dump...

# link
http://2528.iteye.com/blog/1246371 
释放 mysql 日志文件占用的磁盘空间
1. mysql 日志文件存放目录及名称
  %MYSQL_HOME%\data\mysql-bin.***

2. 先禁用日志功能
   # 注释掉 %MYSQL_HOME%\mysql.ini 中的以下几行
   # log-bin=mysql-bin
   # binlog_format=mixed
   # server-id	= 8
   
3. 以 root 用户登录 mysql 重置 master
   > mysql -hlocalhost -uroot -pPassword
   > reset master
   
4. 将第 2 步注释掉的三行还原
   log-bin=mysql-bin
   binlog_format=mixed
   server-id	= 8
   
5. 重启 mysql 服务
   > net stop mysql
   > net start mysql
   
JDK 原生 Web Service [ JAX-WS ]
package org.demo.ws;

import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.xml.ws.Endpoint;
import org.demo.ws.client.HelloWorldService;

/**
 * JAX-WS 发布与调用 Web Service
 * <pre>
 * 生成客户端代码
 * wsimport -s src -d bin http://localhost:9200/hello?wsdl
 * </pre>
 */
@WebService(targetNamespace="http://ws.demo.org/client")
@SOAPBinding(style=Style.RPC)
public class HelloWorld
{

    /**
     * 测试
     * 
     * @param args
     */
    public static void main(String[] args)
    {
        String host = "http://localhost:9200/";
        String name = "hello";
        Endpoint.publish(host + name, new HelloWorld());
        
        HelloWorldService ws = new HelloWorldService();
        int value = ws.getHelloWorldPort().add(1, 2);
        System.out.println("result = " + value);
    }
    
    public int add(int a, int b){
        System.out.println( a + " + " + b + " = " + (a+b));
        return a + b;
    }

}
// 参考:http://liuyf8688.iteye.com/blog/451331
eclipse 编码设置
# Window -> Preferences -> General -> Workspace -> Text file encoding
# Window -> Preferences -> General -> Content Types -> Text -> JSP -> Default encoding
# Window -> Preferences -> Web -> JSP Files -> Encoding
# 选中 project -> 右键 -> Properties -> Resource -> Text file encoding
java 加密解密 2
    /**
     * 
     * 可逆 - DES 加密
     * 
     * @param key
     * @param text
     * @return
     * @throws Exception
     */
    public static String encryptDES(String key, String text) throws Exception{
        return encryptString("DES", Cipher.ENCRYPT_MODE, key, text);
    }
    
    /**
     * 
     * 可逆 - DES 解密
     * 
     * @param key
     * @param text
     * @return
     * @throws Exception
     */
    public static String decryptDES(String key, String text) throws Exception{
        return encryptString("DES", Cipher.DECRYPT_MODE, key, text);
    }
	
	/**
	 * 
	 * 不可逆 - MD5 加密
	 * 
	 * @param text
	 * @return
	 * @throws Exception
	 */
	public static String encryptMD5(String text) throws Exception{
	    MessageDigest md5 = MessageDigest.getInstance("MD5");
	    md5.update(text.getBytes());
	    byte[] data = md5.digest();
	    return new BASE64Encoder().encode(data);
	}
	
	/**
	 * 
	 * 不可逆 - SHA 加密
	 * 
	 * @param text
	 * @return
	 * @throws Exception
	 */
	public static String encryptSHA(String text) throws Exception{
	    MessageDigest sha = MessageDigest.getInstance("SHA");
	    sha.update(text.getBytes());
        byte[] data = sha.digest();
        return new BASE64Encoder().encode(data);
	}
	
	/**
	 * 
	 * 不可逆 - HMAC 加密
	 * 
	 * @param key
	 * @param text
	 * @return
	 * @throws Exception
	 */
	public static String encryptHMAC(String key, String text) throws Exception{
	    SecretKeySpec sk = new SecretKeySpec(key.getBytes(), "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(sk);
        byte[] data = mac.doFinal(text.getBytes());
        return new BASE64Encoder().encode(data);
	}
	
	/**
	 * 
	 * 加密/解密
	 * 
	 * @param algorithm   加密/解密算法
	 * @param type        Cipher.ENCRYPT_MODE | Cipher.DECRYPT_MODE
	 * @param key         key 值
	 * @param text        明文
	 * @return            密文
	 * @throws Exception
	 */
	private static String encryptString(
	        String algorithm, int type, String key, String text) throws Exception{
	    SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(key.getBytes());
        
        KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
        keyGenerator.init(secureRandom);
        
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(type, keyGenerator.generateKey());
        
        if (type == Cipher.ENCRYPT_MODE){
            byte[] data = cipher.doFinal(text.getBytes());
            return new BASE64Encoder().encode(data);
        } else if (type == Cipher.DECRYPT_MODE){
            byte[] decode = new BASE64Decoder().decodeBuffer(text);
            byte[] data = cipher.doFinal(decode);
            return new String(data);
        }
        
        return null;
	}
}
java 加密解密 1
import java.io.IOException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * 加密解密
 *
 */
public class EncryptUtil {

	public static void main(String[] args) throws Exception {
	    
	    String key = "admin";
	    String text = "password";
	    String pass = "";
	    
	    // BASE64
	    pass = encryptBASE64(text);
	    System.out.println(pass);
	    System.out.println(decryptBASE64(pass));

        // AES
	    pass = encryptAES(key, text);
        System.out.println(pass);
        System.out.println(decryptAES(key, pass));
        
        // DES 
        pass = encryptDES(key, text);
        System.out.println(pass);
        System.out.println(decryptDES(key, pass));
        
	    // MD5 
	    System.out.println(encryptMD5(text));
	    
	    // SHA
	    System.out.println(encryptSHA(text));
	    
	    // HMAC
	    System.out.println(encryptHMAC(key, text));
	    
	}
	
	/**
	 * 
	 * 可逆 - BASE64 加密
	 * 
	 * @param text
	 * @return
	 */
	public static String encryptBASE64(String text){
	    return new BASE64Encoder().encode(text.getBytes());
	}
	
	/**
	 * 
	 * 可逆 - BASE64 解密
	 * 
	 * @param pass
	 * @return
	 * @throws IOException 
	 */
	public static String decryptBASE64(String pass) throws IOException{
	    byte[] data = new BASE64Decoder().decodeBuffer(pass);
	    return new String(data);
	}
	
	/**
	 * 
	 * 可逆 - AES 加密
	 * 
	 * @param key
	 * @param text
	 * @return
	 * @throws Exception
	 */
	public static String encryptAES(String key, String text) throws Exception{
        return encryptString("AES", Cipher.ENCRYPT_MODE, key, text);
	}
	
    /**
     * 
     * 可逆 - AES 解密
     * 
     * @param key
     * @param text
     * @return
     * @throws Exception
     */
    public static String decryptAES(String key, String text) throws Exception{
        return encryptString("AES", Cipher.DECRYPT_MODE, key, text);
    }
    
扫描 classpath 中的 class 文件
    /**
     * 
     * 获取 classpath 下指定包中的所有类
     * 
     * @param pkgName   包名
     * @param recursive 是否扫描子目录
     * @return
     */
    public static List<Class<?>> getClsInClassPath(String pkgName, boolean recursive){
        List<Class<?>> list = new ArrayList<Class<?>>();
        
        String classpath = System.getProperty("java.class.path");
        String[] cp_array = classpath.split(File.pathSeparator);
        
        File file;
        for (String cp : cp_array){
            file = new File(cp);
            if (file.isDirectory()){
                scanClsInDir(list, file.getAbsolutePath(), pkgName, recursive);
            } else if (file.getName().endsWith(".jar")){
                scanClsInJar(list, file, pkgName, recursive);
            }
        }
        
        return list;
    }
    
    /**
     * 
     * 获取目录 dir 下的所有类
     * 
     * @param list      存放符合条件的类
     * @param path      classpath
     * @param pkg       包名
     * @param recursive 是否扫描子目录
     */
    public static void scanClsInDir(
            List<Class<?>> list, 
            String path, String pkg, boolean recursive){
        
        File file = new File(path + "/" + pkg.replaceAll("\\.", "/"));
        if (!file.exists()){
            return;
        }
        
        String clsName, prefix = "";
        if (pkg.length() > 0){
            prefix = pkg + ".";
        }
        
        File[] files = file.listFiles();
        for (File f : files){
            if (f.isDirectory() && recursive){
                // 扫描子目录
                scanClsInDir(list, path, prefix + f.getName(), recursive);
            } else if (f.isFile() && f.getName().endsWith(".class")){
                // 加载当前 class 文件
                clsName = prefix + f.getName();
                clsName = clsName.substring(0, clsName.lastIndexOf(".class"));
                try {
                    list.add(Class.forName(clsName, false, 
                                           Thread.currentThread().getContextClassLoader()));
                } catch (Throwable t){
                    // Ignore.
                }
            }
        }
    }
    
    /**
     * 
     * 获取 jar 中指定包名下的所有类
     * 
     * @param list      存放符合条件的类
     * @param jar       jar 文件
     * @param pkg       包名
     * @param recursive 是否扫描子目录
     */
    public static void scanClsInJar(
            List<Class<?>> list,
            File jar, String pkg, boolean recursive){
        try {
            JarFile jar_file = new JarFile(jar);
            Enumeration<JarEntry> entrys = jar_file.entries();
            
            String prefix = pkg.replaceAll("\\.", "/");
            String name;
            while(entrys.hasMoreElements()){
                name = entrys.nextElement().getName();
                
                if (!name.startsWith(prefix) || !name.endsWith(".class")){
                    continue;
                }
                if (!recursive && name.lastIndexOf('/') > prefix.length()){
                    continue;
                }
                
                name = name.substring(0, name.lastIndexOf(".class"));
                name = name.replaceAll("/", ".");
                try {
                    list.add(Class.forName(name, false, 
                                           Thread.currentThread().getContextClassLoader()));
                } catch(Throwable t){
                    // Ignore.
                }
            }
        } catch (IOException e) {
            // Ignore.
        }
    }
zip 中文件名乱码问题
1. 创建
fileName = new String(fileName.getBytes(), "iso-8859-1");
ZipEntry entry = new ZipEntry(fileName);

2. 解压
String dir = entry.getName();
dir = new String(dir.getBytes("iso-8859-1"), "gbk");
Java 中的注解 注解, java
# org.demo.annotation.Table.java
package org.demo.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 注解 - table
 * @author  
 * @date    2012-2-24
 * @file    org.demo.annotation.Table.java
 */
@Target(ElementType.TYPE)          // 域声明 : 表示注解用在什么地方
@Retention(RetentionPolicy.RUNTIME)// 在 JVM 运行期也保留注解 : 表示注解的级别
@Documented                        // 将此注解包含在 javadoc 中
@Inherited                         // 允许子类继承父类中的注解 
public @interface Table {
	String[] keys();
}

# org.demo.annotation.Id.java
package org.demo.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * 注解 - id
 * @author  
 * @date    2012-2-24
 * @file    org.demo.annotation.Id.java
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface Id {
	String value();
}

# org.demo.annotation.Column.java
package org.demo.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * 注解 - column
 * @author  
 * @date    2012-2-24
 * @file    org.demo.annotation.Column.java
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
	String name();
	String desc() default "";
}

# org.demo.annotation.User.java
package org.demo.annotation;

import java.lang.reflect.Field;

/**
 * 
 * @author  
 * @date    2012-2-24
 * @file    org.demo.annotation.User.java
 */
// 属性 keys 是一个数组,这时有两种写法
// @Table(keys="stuId")                // 1. 只有一个值
// @Table(keys={"stuId", "courseId"})  // 2. 两个或更多的值
@Table(keys={"stuId", "courseId"})
public class StudentScore {
	
	// 只有一个属性且名称为 value 时有两种写法
	// @Id("stu_id")                   // 1. 简写形式
	// @Id(value="stu_id")             // 2. 带名称的形式
	@Id("stu_id")
	private String stuId;
	
	@Id(value="course_id") 
	private String courseId;
	
	// 属性有默认值时有两种写法
	// @Column(name="score")           // 1. 有默认值的属性可以不写
	// @Column(name="note", desc="备注") // 2. 也可以把所有属性都写出来
	@Column(name="score")
	private String score;
	
	@Column(name="note", desc="备注")
	private String note;
	
	/**
	 * 通过反射读取注解内容
	 * @param args
	 */
	public static void main(String[] args) {
		Field[] fields = StudentScore.class.getDeclaredFields();
		for (Field f : fields){
			System.out.printf("%-10s", f.getName());
			
			Id id = f.getAnnotation(Id.class);
			if (id != null){
				System.out.printf("%10s %s", "id:", id.value());
			}
			
			Column column = f.getAnnotation(Column.class);
			if (column != null){
				System.out.printf("%10s %s", "column:", 
						"{" 
						+ "name: " + column.name() + ", " 
						+ "desc: " + column.desc() 
						+ "}");
			}
			System.out.println();
		}
	}
}
Java 远程 Debug
1. 在当前机器的 8000 端口监听 debug 连接
java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000 className
# 查看当前机器的调试端口
jps -v

2. 在 eclipse 中连接服务端程序进行 debug
2.1 Run -> Debug Configurations... -> Remote Java Application 
2.2 新建一个 Remote Java Application 
    Project : 选择源代码所在的 project
    Connect Type : Standard (Socket Attach)
    Host : 服务端 ip
    Port : 服务端 debug 监听端口 (例如 8000)

3. 打开 debug Perspective
   Window -> Open Perspective -> Debug

excel to html jacob, excel to html
import java.io.File;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;

/**
 * Excel to html
 * 使用 jacob 将 excel 转为 html
 * jacob url: http://sourceforge.net/projects/jacob-project/
 */
public class ExcelUtil
{
    // 
    public static final int EXCEL_HTML = 44;
    
    static {
        String jar = ActiveXComponent.class.getProtectionDomain()
                                     .getCodeSource().getLocation().getFile();
        File lib = new File(jar).getParentFile();
        System.setProperty("jacob.dll.path", lib.getAbsolutePath() + "/jacob-1.16-M2-x86.dll");
    }
    
    /**
     * excel to html
     * 
     * @param excelfile  excel file path
     * @param htmlfile   html file path
     */
    public static void excel_to_html(String excelfile, String htmlfile)
    {
        ActiveXComponent app = new ActiveXComponent("Excel.Application");
        try
        {
            File old_file = new File(htmlfile);
            if (old_file.exists()){
                old_file.delete();
            } else {
                old_file.getParentFile().mkdirs();
            }
            
            Variant VAR_FALSE = new Variant(false);
            Variant VAR_TRUE = new Variant(true);
            
            app.setProperty("Visible", VAR_FALSE);
            Dispatch excels = app.getProperty("Workbooks").toDispatch();
            Dispatch excel = Dispatch.invoke(
                                excels,
                                "Open",
                                Dispatch.Method,
                                new Object[]{
                                        excelfile, VAR_FALSE, VAR_TRUE
                                }, 
                                new int[1]
                             ).toDispatch();
            Dispatch.invoke(
                    excel, 
                    "SaveAs", 
                    Dispatch.Method, 
                    new Object[]{ htmlfile, new Variant(EXCEL_HTML)}, 
                    new int[1]);
            Dispatch.call(excel, "Close", VAR_FALSE);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            app.invoke("Quit", new Variant[]{});
        }
    }
}
nodejs upload picture demo nodejs
// index.js
var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");

var handle = {};
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;
handle["/show"] = requestHandlers.show;

server.start(router.route, handle);

// server.js
var http = require("http");
var url = require("url");
var HTTP_PORT = 8888;

function start(route, handle){

	function onRequest(req, resp){
		var pathname = url.parse(req.url).pathname;
		
		console.log("Request for " + pathname + " received.");
		route(handle, pathname, req, resp);
	}
	
	http.createServer(onRequest).listen(HTTP_PORT);
	console.log("Server has started.");
}

exports.start = start;

// router.js
function route(handle, pathname, req, resp){
	console.log("    route a request for " + pathname);
	
	if (typeof handle[pathname] === 'function'){
		handle[pathname](req, resp);
	} else {
		console.log("    No request handler found for " + pathname);
		resp.writeHead(404, {"Content-Type": "text/plain"});
		resp.write("404 Not found.");
		resp.end();
	}
}

exports.route = route;

// requestHandlers.js
var querystring = require("querystring"),
	fs = require("fs"),
	formidable = require("formidable");
var TMP_FILE = "./tmp/test.png";

function start(req, resp){
	console.log("        Request handler 'start' was called.");
	
	var body = '<html>'
			 + '<head>'
			 + '<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>'
			 + '</head>'
			 + '<body>'
			 + '<form action="/upload" enctype="multipart/form-data" method="post">'
			 + '    <input type="file" name="upload" multiple="multiple"/>'
			 + '    <input type="submit" value="Upload file">'
			 + '</form>'
			 + '</body>'
			 + '</html>';

	resp.writeHead(200, {"Content-Type": "text/html"});
	resp.write(body);
	resp.end();
}

function upload(req, resp){
	console.log("        Request handler 'upload' was called.");

	var form = new formidable.IncomingForm();
	form.parse(req, function(error, fields, files){
		console.log("            parsing done.");

		fs.renameSync(files.upload.path, TMP_FILE);
		resp.writeHead(200, {"Content-Type": "text/html"});
		resp.write("received image: <br/>");
		resp.write("<img src='/show' />");
		resp.end();
	});
}

function show(req, resp){
	console.log("        Request handler 'show' was called.");

	fs.readFile(TMP_FILE, "binary", function(error, file){
		if (error){
			resp.writeHead(500, {"Content-Type": "text/plain"});
			resp.write(error + "\r\n");
			resp.end();
		} else {
			resp.writeHead(200, {"Content-Type": "image/png"});
			resp.write(file, "binary");
			resp.end();
		}
	});
}

exports.start = start;
exports.upload = upload;
exports.show = show;
node.js npm install offline module nodejs
# 通过安装 formidable 为例进行说明

1. 在命令行中执行 npm install formidable, 会提示从下面的地址进行下载
npm http GET https://registry.npmjs.org/formidable

2. 在一台可以联网的电脑上访问上面的 url, 会得到一个 json 文件 formidable

3. 在这个 json 文件 formidable 中查找 tarball,找到最新的一个,例如
"tarball":"http://registry.npmjs.org/formidable/-/formidable-1.0.8.tgz"

4. 下载 http://registry.npmjs.org/formidable/-/formidable-1.0.8.tgz

5. 在工程根目录中安装 formidable
npm install formidable-1.0.8.tgz

6. 查看已安装的 modules
npm list
获取 table 数据
/**
 * 获取 table 数据
 */
function get_table_data(){
    var need_save_data = '';
    
    var grid = document.getElementById('table_id');
    var rows = grid.rows;
    var row_data, cols, input, tmp_value;
    
    // 跳过第一行和最后一行
    for (var i=1; i<rows.length-1; i++){
        cols = rows[i].cells;
        row_data = get_prefix(row_data, cols.length); 

        for (var j=0; j<cols.length; j++){
            input = cols[j].getElementsByTagName('input')[0];
            // append value
            if (input != null){
                tmp_value = input.value;
                if (tmp_value.indexOf('|') != -1 || tmp_value.indexOf('#') != -1 
                        || tmp_value.indexOf('&') != -1 ){
                    alert('不能输入以下字符:\r\n \'|\', \'#\', \'&\'');
                    return ''; 
                }
                row_data += input.value;
            } else {
                row_data += cols[j].innerHTML;
            }
            // append '|'
            if (j < cols.length - 1){
                row_data += '|';
            }
        }
        // append '#'
        if (i < rows.length - 2){
            row_data += '#';
        }
        need_save_data += row_data;
    }
    // 
    return need_save_data;
}
/**
 * 有单元格合并时,获取合并后的内容
 */
function get_prefix(pre_row_data, cur_size){
    var value = '';
    if (pre_row_data == null){
        return value;
    }
    // 这里表格只有 5 列
    var max_col_size = 5, curIdx = -1;
    for (var i = max_col_size - cur_size; i>0; i--){
        curIdx = pre_row_data.indexOf('|', curIdx + 1 );
    }
    if (curIdx > 0){
        value = pre_row_data.substring(0, curIdx + 1);
    }
    
    return value;
}
table css
table {
    position: relative;
    top: 20px;
    border-collapse:collapse;
}
table caption {
    font-size:22px;
    font-weight:900;
    color:#1E4E7B;
    font-family:Courier New 宋体;
}
th{
    background-color: #6293BB;
    color: #FFFFFF;
}
td {
    border : 1px solid #1E90FF;
}
.none_border {
    width: 98%;
    border: 0px;
    background-color: #E8F2FE;
    margin-bottom: -1px;
}
.focus_border {
    width: 98%;
    border: 0px;
    border-bottom: 2px solid #5CA32D;
    margin-bottom: -2px;
}
format ip java
    /**
     * 
     * 格式化 ip
     * 192.168.1.1 -> 192.168.001.001
     * @param ip
     * @return
     */
    public static String formatIP(String ip) 
    {
        StringBuilder sb = new StringBuilder();
        int start = 0, end = ip.indexOf('.');
        String tmp;
        
        // 1. 处理前3组数据
        while ((end != -1 && end > start)) 
        {
            tmp = ip.substring(start, end);
            for (int i=(end - start); i<3; i++)
            {
                sb.append('0');
            }
            sb.append(tmp).append('.');
            
            start = end + 1;
            end = ip.indexOf('.', start);
        }
        // 2. 处理第4组数据
        tmp = ip.substring(start);
        for (int i=(ip.length() - start); i<3; i++)
        {
            sb.append('0');
        }
        sb.append(tmp);
        
        // 
        return sb.toString();
    } 
Apache Commons Configuration http://commons.apache.org/configuration/index.html
public class ConfigUtil
{
    // 配置文件名称 [ classpath: config.xml ]
    private static String fileName = "config.xml";
    
    // 实例
    private static ConfigUtil INSTANCE = new ConfigUtil();
    
    // 系统配置
    private Configuration config;
    
    /**
     * 
     * 构造函数
     *
     */
    private ConfigUtil(){
        
        try {
            ConfigurationBuilder builder = new DefaultConfigurationBuilder(fileName);
            config = builder.getConfiguration();
            
            // 设置为自动刷新
            if (config instanceof CombinedConfiguration){
                CombinedConfiguration cmbCfg = (CombinedConfiguration)config;
                // 强制进行自动刷新检查
                cmbCfg.setForceReloadCheck(true);
                // 禁用分隔符 ','
                // cmbCfg.setDelimiterParsingDisabled(true);
                
                int size = cmbCfg.getNumberOfConfigurations();
                Configuration tmp;
                for (int i=0; i<size; i++){
                    tmp = cmbCfg.getConfiguration(i);
                    if (tmp instanceof FileConfiguration){
                        // 当文件发生变化时重新加载
                        // (对 include 进来的文件有没有发生变化不进行检测)
                        ((FileConfiguration)tmp).setReloadingStrategy(
                                new FileChangedReloadingStrategy());
                    }
                }
            }
        }
        catch (ConfigurationException e) {
            e.printStackTrace();
        }
        
    }
    
    /**
     * 
     * get 系统配置
     * 
     * @return
     */
    public static Configuration getConfig(){
        return INSTANCE.config;
    }
    
    /**
     * 
     * 测试
     * 
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(ConfigUtil.getConfig().getString("window.width"));
        System.out.println(ConfigUtil.getConfig().getString("user.userName"));
    }
}
// ############################################################################
// config.xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system />
    <properties fileName="app.properties" />
    <xml fileName="app-users.xml" />
</configuration>

// app.properties
# import ui.properties 
include = ui.properties

// ui.properties
# window properties
window.width = 1024
window.height = 768

// app-users.xml
<?xml version="1.0" encoding="utf-8"?>
<root>
    <user>
        <userName>ZhangShan</userName>
    </user>
</root>
Question2 http://www.iteye.com/topic/1118928
import java.util.ArrayList;
import java.util.List;

public class Question2 {

    public static void main(String[] args) {
        int result = 0;
        // 2阶,每次1,2 阶
        result = find(2, 1, 2);
        System.out.println(">>>>>>> " + result + " <<<<<<<");
        
        // 3阶,每次1,2 阶
        result = find(3, 1, 2);
        System.out.println(">>>>>>> " + result + " <<<<<<<");
        
        // 4阶,每次1,2,3,4 阶
        result = find(4, 1, 4);
        System.out.println(">>>>>>> " + result + " <<<<<<<");
    }
    
    /**
     * 
     * 青蛙跳台阶
     * 
     * @param length  台阶长度
     * @param minStep 最小步
     * @param maxStep 最大步
     * @return
     */
    public static int find(int length, int minStep, int maxStep){
        int count = 0;
        
        // 1. 用列表来存放跳跃路径,其中第一个存放临时路径
        List<String> list = new ArrayList<String>();
        list.add("");
        
        // 2. 搜索跳跃路径
        find(length, 0, minStep, maxStep, list);
        
        // 3. 记录结果
        if (list.size() > 1){
            count = list.size() - 1;
            // print result
            list.remove(0);
            System.out.println(list);
        }
        
        return count;
    }
    
    /**
     * 
     * 青蛙跳台阶
     * 
     * @param length      台阶长度
     * @param curIdx      当前台阶
     * @param min_step    最小步
     * @param max_step    最大步
     * @param list        记录跳跃路径
     */
    private static void find(
            int length, int curIdx, 
            int min_step, int max_step,
            List<String> list){
        
        String value = list.get(0);
        
        int tmpIdx = 0;
        for (int step=min_step; step<=max_step; step++){
            tmpIdx = curIdx + step;
            
            if (tmpIdx > length){
                // 越界
                break;
            } else if (tmpIdx == length){
                // 到达终点
                list.add(value + step + " ");
                break;
            } else {
                // 中途 (用列表中的第一个存放临时路径)
                list.set(0, value + step + " ");
                find(length, tmpIdx, min_step, max_step, list);
            }
        }
    }
}
Question1 http://www.iteye.com/topic/1118928
public class Question1 {
    
    public static void main(String[] args) {
        
        // 1. 初始化测试数组
        int[][] data = new int[][]{
                {1,2,8 ,9 ,20},
                {2,4,9 ,12,22},
                {4,7,10,13,23},
                {6,8,11,15,28},
                {7,9,12,16,32}
        };
        
        // 2. 测试 contains method
        int value = 0;
        boolean exist = false;
        for (int i=0; i<data.length; i++) {
            for (int j=0; j<data[i].length; j++){
                value = data[i][j];
                exist = contains(data, value);
                System.out.print(exist + " ");
            }
            System.out.println();
        }
        System.out.println(contains(data, 0));
        System.out.println(contains(data, 5));
        System.out.println(contains(data, 33));
    }
    
    /**
     * 
     * 判断二维数组 data 中是否包含 value
     * 
     * @param data
     * @param value
     * @return
     */
    public static boolean contains(int[][] data, int value){
        int row_end = data.length - 1;     // 最后一行下标
        int col_end = data[0].length - 1;  // 第一行最后一列下标
        return contains(data, value, 0, row_end, 0, col_end);
    } 
    
    /**
     * 
     * 判断二维数组 data 中是否包含 value
     * 
     * @param data
     * @param value
     * @param row_start
     * @param row_end
     * @param col_start
     * @param col_end
     */
    private static boolean contains(int[][] data, int value, 
            int row_start, int row_end,
            int col_start, int col_end
            ){
        
        // 1. 判断是否越界
        if (row_start > row_end || col_start > col_end){
            return false;
        }
        
        // 2. 只有一个元素
        if (row_start == row_end && col_start == col_end){
            return data[row_start][col_start] == value;
        }
        
        // 3. 判断左上角和右下角元素
        if (value < data[row_start][col_start] || value > data[row_end][col_end]){
            return false;
        }
        if (value == data[row_start][col_start] || value == data[row_end][col_end]){
            return true;
        }
        
        // 4. 计算中心点
        int row_middle = row_start + (row_end - row_start)/2;
        int col_middle = col_start + (col_end - col_start)/2;
        
        // 5. 分为上左、上右、下左、下右四个区进行搜索
        // 上左
        boolean result = contains(data, value, row_start, row_middle, col_start, col_middle);
        // 上右
        result = result || contains(data, value, row_start, row_middle, col_middle + 1, col_end);
        // 下左
        result = result || contains(data, value, row_middle + 1, row_end, col_start, col_middle);
        // 下右
        result = result || contains(data, value, row_middle + 1, row_end, col_middle + 1, col_end);
        
        return result;
    }
}
java read zip file
// read zip file
ZipFile zipFile = new ZipFile(file);
ZipEntry entry = zipFile.entries().nextElement();
InputStream in = zipFile.getInputStream(entry);
// ...
生产者消费者3
package org.demo;

import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 生产者消费者
 * 
 * @author     dyccsxg
 * @date       2011-12-9
 * @file       org.demo.ProducerConsumer.java
 */
public class ProducerConsumer
{
    /**
     * 生产者消费者
     * 
     * @param args
     */
    public static void main(String[] args)
    {
        // 线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        
        // 容量为 3 的仓库
        final int maxSize = 3;
        Queue<String> wareHouse = new PriorityQueue<String>(maxSize);

        pool.execute(new Producer("producer_1", wareHouse, maxSize));  // 生产者
        pool.execute(new Consumer("consumer_1", wareHouse));           // 消费者
        
    }

}
/**
 * 生产者
 * @author dyccsxg
 *
 */
class Producer implements Runnable {
    
    // name
    private String name;
    
    // 队列
    private Queue<String> queue;
    
    private int maxSize;
    
    public Producer(String name, Queue<String> queue, int maxSize){
        this.name = name;
        this.queue = queue;
        this.maxSize = maxSize;
    }
    
    @Override
    public void run()
    {
        for (int i=0; i<10; i++){
            synchronized (queue) {
                if (queue.size() == maxSize){
                    try {
                        queue.wait();
                    }
                    catch (InterruptedException e) {
                    }
                }
                
                queue.add(String.valueOf(i));
                System.out.println(name + " produce " + i);
                
                queue.notifyAll();
            }
        }
    }
}
/**
 * 消费者
 * @author dyccsxg
 *
 */
class Consumer implements Runnable {
    
    // name
    private String name;
    
    // 队列
    private Queue<String> queue;
    
    public Consumer(String name, Queue<String> queue){
        this.name = name;
        this.queue = queue;
    }
    
    @Override
    public void run()
    {
        while (true){
            synchronized (queue) {
                if (queue.size() == 0){
                    try {
                        queue.wait();
                    }
                    catch (InterruptedException e) {
                    }
                }
                
                String value = queue.poll();
                System.out.println(name + " consume " + value);
                
                queue.notifyAll();
            }
        }
    }
}
生产者消费者2
/**
 * 生产者
 * @author dyccsxg
 *
 */
class Producer implements Runnable {
    
    // name
    private String name;
    
    // 队列
    private Queue<String> queue;
    
    // 同步条件
    private MyCondition condition;
    
    public Producer(String name, Queue<String> queue, MyCondition condition){
        this.name = name;
        this.queue = queue;
        this.condition = condition;
    }
    
    @Override
    public void run()
    {
        for (int i=0; i<10; i++){
            // 已满时等待
            // 未满时获取互斥锁,保证下面的操作为一个原子操作
            condition.notFull();
            
            queue.add(String.valueOf(i));
            System.out.println(name + " produce " + i);
            
            // 非空通知
            // 同时释放互斥锁
            condition.notEmptyNotify();
        }
    }
}
/**
 * 消费者
 * @author dyccsxg
 *
 */
class Consumer implements Runnable {
    
    // name
    private String name;
    
    // 队列
    private Queue<String> queue;
    
    // 同步条件
    private MyCondition condition;
    
    public Consumer(String name, Queue<String> queue, MyCondition condition){
        this.name = name;
        this.queue = queue;
        this.condition = condition;
    }
    
    @Override
    public void run()
    {
        while (true){
            // 已空时等待
            // 非空时获取互斥锁,保证下面的操作为一个原子操作
            condition.notEmpty();
            
            String value = queue.poll();
            System.out.println(name + " consume " + value);
            
            // 未满通知
            // 同时释放互斥锁
            condition.notFullNotify();
        }
    }
}
生产者消费者1
package org.demo;

import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * 生产者消费者
 * 
 * @author     dyccsxg
 * @date       2011-12-9
 * @file       org.demo.ProducerConsumer.java
 */
public class ProducerConsumer
{
    /**
     * 生产者消费者
     * 
     * @param args
     */
    public static void main(String[] args)
    {
        // 线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        
        // 容量为 3 的仓库
        final int maxSize = 3;
        Queue<String> wareHouse = new PriorityQueue<String>(maxSize);

        // 线程同步条件
        MyCondition condition = new MyCondition(maxSize);
        
        pool.execute(new Producer("producer_1", wareHouse, condition));  // 生产者
        pool.execute(new Consumer("consumer_1", wareHouse, condition));  // 消费者
        
    }

}
/**
 * 同步条件
 * @author dyccsxg
 *
 */
class MyCondition {
    private Semaphore notFull;                        // 未满
    private Semaphore notEmpty = new Semaphore(0);    // 非空
    private Semaphore mutex = new Semaphore(1);       // 互斥
    
    public MyCondition(int size){
        notFull = new Semaphore(size);
    }
    
    /**
     * 
     * 如果已满则等待,未满时获取互斥锁
     *
     */
    public void notFull(){
        acquireSilent(notFull);
        lock();
    }
    
    /**
     * 
     * 如果已空则等待,非空时获取互斥锁
     *
     */
    public void notEmpty(){
        acquireSilent(notEmpty);
        lock();
    }
    
    /**
     * 
     * 未满通知
     *
     */
    public void notFullNotify(){
        notFull.release();
        unlock();
    }
    
    /**
     * 
     * 非空通知
     *
     */
    public void notEmptyNotify(){
        notEmpty.release();
        unlock();
    }
    
    /**
     * 
     * 获取互斥锁
     *
     */
    private void lock(){
        acquireSilent(mutex);
    }
    
    /**
     * 
     * 释放互斥锁
     *
     */
    private void unlock(){
        mutex.release();
    }
    
    /**
     * 
     * 获取一个信号量许可
     * 
     * @param semaphore
     */
    private void acquireSilent(Semaphore semaphore){
        try {
            semaphore.acquire();
        } catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
jstl 学习笔记
1. tablib
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

2. 赋值,获取
<c:set var="cur_time" value="<%=new java.util.Date()%>"/>
${cur_time}

3. 格式化
<c:set var="dateTime" value="<%=new java.util.Date()%>"/>
<fmt:formatDate value="${dateTime}" pattern="yyyy-MM-dd HH:mm:ss"/>

4. 分支
<c:set var="display" value="false"/>
<c:if test="${display != null}">
    display is not null
</c:if>

<c:choose>
    <c:when test="${display}">
        <div style="color:green">display is true</div>
    </c:when>
    <c:when test="${!display}">
        <div style="color:red">display is false</div>
    </c:when>
    <c:otherwise>otherwise</c:otherwise>
</c:choose>

5. 迭代
<%
    java.util.List<String> list = new java.util.ArrayList<String>();
    list.add("a");
    list.add("b");
    list.add("c");
    request.setAttribute("list", list);
%>
<%-- varStatus: count|index|first|last --%>
<c:forEach items="${list}" var="item" varStatus="status"> 
    <c:choose>
        <c:when test="${status.index % 2 == 0}">
            <div style="background-color:#CCFFFF">
                first: ${status.first}, value: ${item}
            </div>
        </c:when>
        <c:otherwise>
            <div style="background-color:#CCCCFF">
                first: ${status.first}, value: ${item}
            </div>
        </c:otherwise>
    </c:choose>    
</c:forEach>

6. function
<c:set var="a2n" value="abcdefghijklmn"/>
${fn:length(a2n)}
${fn:startsWith(a2n, "abc")}
${fn:endsWith(a2n, "xyz")}
${fn:contains(a2n, "jk")}
${fn:toUpperCase(a2n)}
EL 表达式
1. 隐含对象
pageContext   
pageScope     requestScope  sessionScope  applicationScope
param         paramValues
header        headerValues
cookie        initParam

2. 获取 url 中的参数
http://localhost:8081/examples/el.jsp?time=2011&name=one&name=two
${param.time}
${paramValues.name[0]}

3. 获取 header 中的值
${header.connection}
${header["accept-language"]}   # 当属性名称中含有 . - 等字符时需使用 ["propertyName"]

4. 获取 cookie 中的值
<%     
    response.addCookie(new Cookie("timeout", "10"));
%>
${cookie.timeout.value}

5. 获取页面相关信息
${pageContext.request.requestURL}
${pageContext.request.queryString}
${pageContext.request.contextPath}
${pageContext.session.id}

6. 获取 pageContext, request, session, application 中的属性
<%    
    pageContext.setAttribute("page_attr", "page_attr_val");
    request.setAttribute("req_attr", "req_attr_val");
    session.setAttribute("session_attr", "session_attr_val");
    application.setAttribute("app_attr", "app_attr_val");    
%>
${page_attr}
${req_attr}
${session_attr}
${app_attr}

7. 获取 Map, List 中的值
<%
    java.util.Map<String,String> map = new java.util.HashMap<String,String>();
    java.util.List<String> list = new java.util.ArrayList<String>();
    
    map.put("key_1", "value_1");
    list.add("list_idx0_value");
    
    request.setAttribute("map", map);
    request.setAttribute("list", list);
%>
${map.key_1}
${list[0]}

8. 获取 JavaBean 中的属性
<%!
    public class User {
        private String id;
        private String name;
        public User (String id, String name){
            this.id = id;
            this.name = name;
        }
        
        public String getId(){return id;}
        public void setId(String val) {id = val;}
        
        public String getName(){return name;}
        public void setName(String val) {name = val;}
    }
%>
<%
    request.setAttribute("user", new User("001", "zhangshan"));
%>
${user.id}
${user.name}  

9. EL 运算符
算术运算符:	+、-、*、/(或 div)和 %(或 mod)
关系运算符:	==(或 eq)、!=(或 ne)、<(或 lt)、>(或 gt)、<=(或 le)和 >=(或 ge)
逻辑运算符:	&&(或 and)、||(或 or)和 !(或 not)
验证运算符:	empty

10. 相关链接
http://www.ibm.com/developerworks/cn/java/j-jstl0211/index.html
http://download.oracle.com/otndocs/jcp/jstl-1.2-mrel2-eval-oth-JSpec/
linux 下卸载 Oracle oracle
    # oracle 用户登录 linux
    # 停止监听
    lsnrctl stop 
    # 关闭数据库
    sqlplus / as sysdba
    shutdown immediate;
    
    # root 身份登录 linux
    # 删除文件
    rm -rf /opt/oracle
    rm -rf /etc/ora*
    rm -rf /usr/local/bin/*oraenv
    rm -rf /usr/local/bin/dbhome
    rm -rf /var/tmp/.oracle
    rm -rf /tmp/.oracle
    rm -rf /tmp/*oracle*
    rm -rf /tmp/Oracle*
    rm -rf /tmp/*OraInstall*
    # 删除 oracle 用户及组
    userdel oracle
    rm -rf /home/oracle
    groupdel dba
    groupdel oinstall
    
    # 重启系统
    reboot
linux 下 shell 脚本登录 sqlplus 并查询数据库信息 oracle
# Main.sh
$ORACLE_HOME/bin/sqlplus / as sysdba <<\END
spool /home/oracle/test_dir/out.log
select instance_name,status from v$instance;
select name,log_mode,flashback_on from v$database;
select name from v$controlfile;
select name from v$datafile;
select member from v$logfile;
spool off
quit
END
Global site tag (gtag.js) - Google Analytics