blogjava-凯发k8网页登录http://www.blogjava.net/xzclog/category/23459.htmlzh-cntue, 25 apr 2017 16:23:28 gmttue, 25 apr 2017 16:23:28 gmt60kerberos简介http://www.blogjava.net/xzclog/archive/2017/04/25/432480.htmlxzcxzctue, 25 apr 2017 07:56:00 gmthttp://www.blogjava.net/xzclog/archive/2017/04/25/432480.htmlhttp://www.blogjava.net/xzclog/comments/432480.htmlhttp://www.blogjava.net/xzclog/archive/2017/04/25/432480.html#feedback2http://www.blogjava.net/xzclog/comments/commentrss/432480.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/432480.html

blogjava-凯发k8网页登录

1.1. 功能

  1. 一个安全认证协议

  2. 用tickets验证

  3. 避免本地保存密码和在互联网上传输密码

  4. 包含一个可信任的第三方

  5. 使用对称加密

  6. 客户端与服务器(非kdc)之间能够相互验证

kerberos只提供一种功能——在网络上安全的完成用户的身份验证。它并不提供授权功能或者审计功能。

1.2. 概念

首次请求,三次通信方

  • the authentication server
  • the ticket granting server
  • the service or host machine that you’re wanting access to.

 

图 1‑1 角色

其他知识点

  • 每次通信,消息包含两部分,一部分可解码,一部分不可解码
  • 服务端不会直接有kdc通信
  • kdc保存所有机器的账户名和密码
  • kdc本身具有一个密码

 

  我们这里已获取服务器中的一张表(数据)的服务以为,为一个http服务。

2.1. 你和验证服务

  如果想要获取http服务,你首先要向kdc表名你自己的身份。这个过程可以在你的程序启动时进行。kerberos可以通过kinit获取。介绍自己通过未加密的信息发送至kdc获取ticket granting ticket (tgt)。

(1)信息包含

  • 你的用户名/id
  • 你的ip地址
  • tgt的有效时间

  authentication server收到你的请求后,会去数据库中验证,你是否存在。注意,仅仅是验证是否存在,不会验证对错。

  如果存在,authentication server会产生一个随机的session key(可以是一个64位的字符串)。这个key用于你和ticket granting server (tgs)之间通信。

(2)回送信息

  authentication server同样会发送两部分信息给你,一部分信息为tgt,通过kdc自己的密码进行加密,包含:

  • 你的name/id
  • tgs的name/id
  • 时间戳
  • 你的ip地址
  • tgt的生命周期
  • tgs session key

另外一部分通过你的密码进行加密,包含的信息有

  • tgs的name/id
  • 时间戳
  • 生命周期
  • tgs session key

 

图 2‑1 第一次通信

  如果你的密码是正确的,你就能解密第二部分信息,获取到tgs session key。如果,密码不正确,无法解密,则认证失败。第一部分信息tgt,你是无法解密的,但需要展示缓存起来。

2.2. 你和tgs

如果第一部分你已经成功,你已经拥有无法解密的tgt和一个tgs session key。

(1)    请求信息

 a)  通过tgs session key加密的认证器部分:

  • 你的name/id
  • 时间戳

b)       明文传输部分:

  • 请求的http服务名(就是请求信息)
  • http service的ticket生命周期

c)        tgt部分

  ticket granting server收到信息后,首先检查数据库中是否包含有你请求的http服务名。如果无,直接返回错误信息。

  如果存在,则通过kdc的密码解密tgt,这个时候。我们就能获取到tgs session key。然后,通过tgs session key去解密你传输的第一部分认证器,获取到你的用户名和时间戳。

tgs再进行验证:

  1. 对比tgt中的用户名与认证器中的用户名
  2. 比较时间戳(网上有说认证器中的时间错和tgt中的时间错,个人觉得应该是认证器中的时间戳和系统的时间戳),不能超过一定范围
  3. 检查是否过期
  4. 检查ip地址是否一致
  5. 检查认证器是否已在tgs缓存中(避免应答攻击)
  6. 可以在这部分添加权限认证服务

  tgs随机产生一个http service session key, 同时准备http service ticket(st)。

(2)    回答信息

  a)        通过http服务的密码进行加密的信息(st):

  • 你的name/id
  • http服务name/id
  • 你的ip地址
  • 时间戳
  • st的生命周期
  • http service session key

  b)       通过tgs session key加密的信息

  • http服务name/id
  • 时间戳
  • st的生命周期
  • http service session key

  你收到信息后,通过tgs session key解密,获取到了http service session key,但是你无法解密st。

 

图 2‑2 第二次通信

2.3. 你和http服务

  在前面两步成功后,以后每次获取http服务,在ticket没有过期,或者无更新的情况下,都可直接进行这一步。省略前面两个步骤。

(1)    请求信息

  a)        通过http service session key加密部分

  • 你的name/id
  • 时间戳

  b)       st

   http服务端通过自己的密码解压st(kdc是用http服务的密码加密的),这样就能够获取到http service session key,解密第一部分。

服务端解密好st后,进行检查

  1. 对比st中的用户名(kdc给的)与认证器中的用户名
  2. 比较时间戳(网上有说认证器中的时间错和tgt中的时间错,个人觉得应该是认证器中的时间戳和系统的时间戳),不能超过一定范围
  3. 检查是否过期
  4. 检查ip地址是否一致
  5. 检查认证器是否已在http服务端的缓存中(避免应答攻击)

(2)    应答信息

a)        通过http service session key加密的信息

  • http服务name/id
  • 时间戳

 

图 2‑3 第三次通信

  你在通过缓存的http service session key解密这部分信息,然后验证是否是你想要的服务器发送给你的信息。完成你的服务器的验证。

至此,整个过程全部完成。



xzc 2017-04-25 15:56
]]>
快使用阿里云的maven仓库 http://www.blogjava.net/xzclog/archive/2017/04/11/432442.htmlxzcxzctue, 11 apr 2017 02:08:00 gmthttp://www.blogjava.net/xzclog/archive/2017/04/11/432442.htmlhttp://www.blogjava.net/xzclog/comments/432442.htmlhttp://www.blogjava.net/xzclog/archive/2017/04/11/432442.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/432442.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/432442.html

自从开源中国的maven仓库挂了之后就一直在用国外的仓库,慢得想要砸电脑的心都有了。如果你和我一样受够了国外maven仓库的龟速下载?快试试阿里云提供的maven仓库,从此不在浪费生命……

仓库地址:

 

仓库配置

在maven的settings.xml文件里的mirrors节点,添加如下子节点:

<mirror>       <id>nexus-aliyunid>       <mirrorof>centralmirrorof>         <name>nexus aliyunname>       <url>http://maven.aliyun.com/nexus/content/groups/publicurl>   mirror> 

或者直接在profiles->profile->repositories节点,添加如下子节点:

<repository>     <id>nexus-aliyunid>     <name>nexus aliyunname>     <layout>defaultlayout>     <url>http://maven.aliyun.com/nexus/content/groups/publicurl>     <snapshots>         <enabled>falseenabled>     snapshots>     <releases>         <enabled>trueenabled>     releases> repository>

 

settings文件的路径

settings.xml的默认路径就:个人目录/.m2/settings.xml

如:

windowns: c:\users\你的用户名\.m2\settings.xml

linux: /home/你的用户名/.m2/settings.xml

keep it simple!
作者:
出处:
知识共享,欢迎转载。


xzc 2017-04-11 10:08
]]>
java对于数字证书的常用操作方法http://www.blogjava.net/xzclog/archive/2015/12/11/428610.htmlxzcxzcfri, 11 dec 2015 03:40:00 gmthttp://www.blogjava.net/xzclog/archive/2015/12/11/428610.htmlhttp://www.blogjava.net/xzclog/comments/428610.htmlhttp://www.blogjava.net/xzclog/archive/2015/12/11/428610.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/428610.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/428610.html

本文介绍java对于数字证书的常用操作方法

ad:

一:需要包含的包
import java.security.*;
import java.io.*;
import java.util.*;
import java.security.*;
import java.security.cert.*;
import sun.security.x509.*
import java.security.cert.certificate;
import java.security.cert.certificatefactory;
二:从文件中读取证书
用keytool将.keystore中的证书写入文件中,然后从该文件中读取证书信息
certificatefactory cf=certificatefactory.getinstance("x.509");
fileinputstream in=new fileinputstream("out.csr");
certificate c=cf.generatecertificate(in);
string s=c.tostring();
三:从密钥库中直接读取证书
string pass="123456";
fileinputstream in=new fileinputstream(".keystore");
keystore ks=keystore.getinstance("jks");
ks.load(in,pass.tochararray());
java.security.cert.certificate c=ks.getcertificate(alias);//alias为条目的别名
四:java程序中显示证书指定信息
system.out.println("输出证书信息:\n" c.tostring());
system.out.println("版本号:" t.getversion());
system.out.println("序列号:" t.getserialnumber().tostring(16));
system.out.println("主体名:" t.getsubjectdn());
system.out.println("签发者:" t.getissuerdn());
system.out.println("有效期:" t.getnotbefore());
system.out.println("签名算法:" t.getsigalgname());
byte [] sig=t.getsignature();//签名值
publickey pk=t.getpublickey();
byte [] pkenc=pk.getencoded();
system.out.println("公钥");
for(int i=0;i五:java程序列出密钥库所有条目
string pass="123456";
fileinputstream in=new fileinputstream(".keystore");
keystore ks=keystore.getinstance("jks");
ks.load(in,pass.tochararray());
enumeration e=ks.aliases();
while(e.hasmoreelements())
java.security.cert.certificate c=ks.getcertificate((string)e.nextelement());
六:java程序修改密钥库口令
string oldpass="123456";
string newpass="654321";
fileinputstream in=new fileinputstream(".keystore");
keystore ks=keystore.getinstance("jks");
ks.load(in,oldpass.tochararray());
in.close();
fileoutputstream output=new fileoutputstream(".keystore");
ks.store(output,newpass.tochararray());
output.close();
七:java程序修改密钥库条目的口令及添加条目
fileinputstream in=new fileinputstream(".keystore");
keystore ks=keystore.getinstance("jks");
ks.load(in,storepass.tochararray());
certificate [] cchain=ks.getcertificate(alias);获取别名对应条目的证书链
privatekey pk=(privatekey)ks.getkey(alias,oldkeypass.tochararray());获取别名对应条目的私钥
ks.setkeyentry(alias,pk,newkeypass.tochararray(),cchain);向密钥库中添加条目
第一个参数指定所添加条目的别名,假如使用已存在别名将覆盖已存在条目,使用新别名将增加一个新条目,第二个参数为条目的私钥,第三个为设置的新口令,第四个为该私钥的公钥的证书链
fileoutputstream output=new fileoutputstream("another");
ks.store(output,storepass.tochararray())将keystore对象内容写入新文件
八:java程序检验别名和删除条目
fileinputstream in=new fileinputstream(".keystore");
keystore ks=keystore.getinstance("jks");
ks.load(in,storepass.tochararray());
ks.containsalias("sage");检验条目是否在密钥库中,存在返回true
ks.deleteentry("sage");删除别名对应的条目
fileoutputstream output=new fileoutputstream(".keystore");
ks.store(output,storepass.tochararray())将keystore对象内容写入文件,条目删除成功
九:java程序签发数字证书
(1)从密钥库中读取ca的证书
fileinputstream in=new fileinputstream(".keystore");
keystore ks=keystore.getinstance("jks");
ks.load(in,storepass.tochararray());
java.security.cert.certificate c1=ks.getcertificate("caroot");
(2)从密钥库中读取ca的私钥
privatekey caprk=(privatekey)ks.getkey(alias,cakeypass.tochararray());
(3)从ca的证书中提取签发者的信息
byte[] encod1=c1.getencoded();提取ca证书的编码
x509certimpl cimp1=new x509certimpl(encod1); 用该编码创建x509certimpl类型对象
x509certinfo cinfo1=(x509certinfo)cimp1.get(x509certimpl.name "." x509certimpl.info); 获取x509certinfo对象
x500name issuer=(x500name)cinfo1.get(x509certinfo.subject "." certificateissuername.dn_name); 获取x509name类型的签发者信息
(4)获取待签发的证书
certificatefactory cf=certificatefactory.getinstance("x.509");
fileinputstream in2=new fileinputstream("user.csr");
java.security.cert.certificate c2=cf.generatecertificate(in);
(5)从待签发的证书中提取证书信息
byte [] encod2=c2.getencoded();
x509certimpl cimp2=new x509certimpl(encod2); 用该编码创建x509certimpl类型对象
x509certinfo cinfo2=(x509certinfo)cimp2.get(x509certimpl.name "." x509certimpl.info); 获取x509certinfo对象
(6)设置新证书有效期
date begindate=new date(); 获取当前时间
date enddate=new date(begindate.gettime() 3000*24*60*60*1000l); 有效期为3000天
certificatevalidity cv=new certificatevalidity(begindate,enddate); 创建对象
cinfo2.set(x509certinfo.validity,cv); 设置有效期
(7)设置新证书序列号
int sn=(int)(begindate.gettime()/1000);以当前时间为序列号
certificateserialnumber csn=new certificateserialnumber(sn);
cinfo2.set(x509certinfo.serial_number,csn);
(8)设置新证书签发者
cinfo2.set(x509certinfo.issuer "." certificateissuername.dn_name,issuer);应用第三步的结果
(9)设置新证书签名算法信息
algorithmid algorithm=new algorithmid(algorithmid.md5withrsaencryption_oid);
cinfo2.set(certificatealgorithmid.name "." certificatealgorithmid.algorithm,algorithm);
(10)创建证书并使用ca的私钥对其签名
x509certimpl newcert=new x509certimpl(cinfo2);
newcert.sign(caprk,"md5withrsa"); 使用ca私钥对其签名
(11)将新证书写入密钥库
ks.setcertificateentry("lf_signed",newcert);
fileoutputstream out=new fileoutputstream("newstore");
ks.store(out,"newpass".tochararray()); 这里是写入了新的密钥库,也可以使用第七条来增加条目
十:数字证书的检验
(1)验证证书的有效期
(a)获取x509certificate类型对象
certificatefactory cf=certificatefactory.getinstance("x.509");
fileinputstream in1=new fileinputstream("aa.crt");
java.security.cert.certificate c1=cf.generatecertificate(in1);
x509certificate t=(x509certificate)c1;
in2.close();
(b)获取日期
date timenow=new date();
(c)检验有效性
try{
t.checkvalidity(timenow);
system.out.println("ok");
}catch(certificateexpiredexception e){ //过期
system.out.println("expired");
system.out.println(e.getmessage());
}catch((certificatenotyetvalidexception e){ //尚未生效
system.out.println("too early");
system.out.println(e.getmessage());}
(2)验证证书签名的有效性
(a)获取ca证书
certificatefactory cf=certificatefactory.getinstance("x.509");
fileinputstream in2=new fileinputstream("caroot.crt");
java.security.cert.certificate cac=cf.generatecertificate(in2);
in2.close();
(c)获取ca的公钥
publickey pbk=cac.getpublickey();
(b)获取待检验的证书(上步已经获取了,就是c1)
(c)检验证书
boolean pass=false;
try{
c1.verify(pbk);
pass=true;
}catch(exception e){
pass=false;
system.out.println(e);


xzc 2015-12-11 11:40
]]>
der 和 pem 格式http://www.blogjava.net/xzclog/archive/2015/10/01/427579.htmlxzcxzcthu, 01 oct 2015 02:12:00 gmthttp://www.blogjava.net/xzclog/archive/2015/10/01/427579.htmlhttp://www.blogjava.net/xzclog/comments/427579.htmlhttp://www.blogjava.net/xzclog/archive/2015/10/01/427579.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/427579.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/427579.html

x509 文件扩展名

首先我们要理解文件的扩展名代表什么。der、pem、crt和cer这些扩展名经常令人困惑。很多人错误地认为这些扩展名可以互相代替。尽管的确有时候有些扩展名是可以互换的,但是最好你能确定证书是如何编码的,进而正确地标识它们。正确地标识证书有助于证书的管理。


编码 (也用于扩展名)

  • .der 扩展名der用于二进制der编码的证书。这些证书也可以用cer或者crt作为扩展名。比较合适的说法是“我有一个der编码的证书”,而不是“我有一个der证书”。
  • .pem = 扩展名pem用于ascii(base64)编码的各种x.509 v3 证书文件开始由一行"—– begin …“开始。

常用的扩展名

  • .crt = 扩展名crt用于证书。证书可以是der编码,也可以是pem编码。扩展名cer和crt几乎是同义词。这种情况在各种unix/linux系统中很常见。
  • cer = crt证书的微软型式。可以用微软的工具把crt文件转换为cer文件(crt和cer必须是相同编码的,der或者pem)。扩展名为cer的文件可以被ie识别并作为命令调用微软的cryptoapi(具体点就是rudll32.exe cryptext.dll, cyrptextopencer),进而弹出一个对话框来导入并/或查看证书内容。
  • .key = 扩展名key用于pcsk#8的公钥和私钥。这些公钥和私钥可以是der编码或者pem编码。

crt文件和cer文件只有在使用相同编码的时候才可以安全地相互替代。



xzc 2015-10-01 10:12
]]>
深入理解 java中的 流 (stream)http://www.blogjava.net/xzclog/archive/2015/07/16/426249.htmlxzcxzcthu, 16 jul 2015 03:36:00 gmthttp://www.blogjava.net/xzclog/archive/2015/07/16/426249.htmlhttp://www.blogjava.net/xzclog/comments/426249.htmlhttp://www.blogjava.net/xzclog/archive/2015/07/16/426249.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/426249.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/426249.html

最近在看《hadoop:the definitive guide》,对其分布式文件系统hdfs的streaming data access不能理解。基于流的数据读写,太抽象了,什么叫基于流,什么是流?hadoop是java语言写的,所以想理解好hadoop的streaming data access,还得从java流机制入手。流机制也是java及c 中的一个重要的机制,通过流使我们能够自由地操作包括文件,内存,io设备等等中的数据。

首先,流是什么?

流是个抽象的概念,是对输入输出设备的抽象,java程序中,对于数据的输入/输出操作都是以“流”的方式进行。设备可以是文件,网络,内存等。

流具有方向性,至于是输入流还是输出流则是一个相对的概念,一般以程序为参考,如果数据的流向是程序至设备,我们成为输出流,反之我们称为输入流。

可以将流想象成一个“水流管道”,水流就在这管道中形成了,自然就出现了方向的概念。

当程序需要从某个数据源读入数据的时候,就会开启一个输入流,数据源可以是文件、内存或网络等等。相反地,需要写出数据到某个数据源目的地的时候,也会开启一个输出流,这个数据源目的地也可以是文件、内存或网络等等。

流有哪些分类?

可以从不同的角度对流进行分类:

1. 处理的数据单位不同,可分为:字符流,字节流

2.数据流方向不同,可分为:输入流,输出流

3.功能不同,可分为:节点流,处理流

1. 和 2. 都比较好理解,对于根据功能分类的,可以这么理解:

节点流:节点流从一个特定的数据源读写数据。即节点流是直接操作文件,网络等的流,例如fileinputstream和fileoutputstream,他们直接从文件中读取或往文件中写入字节流。

处理流:“连接”在已存在的流(节点流或处理流)之上通过对数据的处理为程序提供更为强大的读写功能。过滤流是使用一个已经存在的输入流或输出流连接创建的,过滤流就是对节点流进行一系列的包装。例如bufferedinputstream和bufferedoutputstream,使用已经存在的节点流来构造,提供带缓冲的读写,提高了读写的效率,以及datainputstream和dataoutputstream,使用已经存在的节点流来构造,提供了读写java中的基本数据类型的功能。他们都属于过滤流。

举个简单的例子:

public static void main(string[] args) throws ioexception {
        // 节点流fileoutputstream直接以a.txt作为数据源操作
        fileoutputstream fileoutputstream = new fileoutputstream("a.txt");
        // 过滤流bufferedoutputstream进一步装饰节点流,提供缓冲写
        bufferedoutputstream bufferedoutputstream = new bufferedoutputstream(
                fileoutputstream);
        // 过滤流dataoutputstream进一步装饰过滤流,使其提供基本数据类型的写
        dataoutputstream out = new dataoutputstream(bufferedoutputstream);
        out.writeint(3);
        out.writeboolean(true);
        out.flush();
        out.close();
        // 此处输入节点流,过滤流正好跟上边输出对应,读者可举一反三
        datainputstream in = new datainputstream(new bufferedinputstream(
                new fileinputstream("a.txt")));
        system.out.println(in.readint());
        system.out.println(in.readboolean());
        in.close();
}

流结构介绍

java所有的流类位于java.io包中,都分别继承字以下四种抽象流类型。

 字节流字符流
输入流inputstreamreader
输出流outputstreamwriter

1.继承自inputstream/outputstream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit),如图,深色的为节点流,浅色的为处理流。

 

2.继承自reader/writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit),如图,深色的为节点流,浅色的为处理流。

常见流类介绍:

节点流类型常见的有:

对文件操作的字符流有filereader/filewriter,字节流有fileinputstream/fileoutputstream。

处理流类型常见的有:

缓冲流:缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写效率,同事增加了一些新的方法。

  字节缓冲流有bufferedinputstream/bufferedoutputstream,字符缓冲流有bufferedreader/bufferedwriter,字符缓冲流分别提供了读取和写入一行的方法readline和newline方法。

  对于输出地缓冲流,写出的数据,会先写入到内存中,再使用flush方法将内存中的数据刷到硬盘。所以,在使用字符缓冲流的时候,一定要先flush,然后再close,避免数据丢失。

转换流:用于字节数据到字符数据之间的转换。

  仅有字符流inputstreamreader/outputstreamwriter。其中,inputstreamreader需要与inputstream“套接”,outputstreamwriter需要与outputstream“套接”。

数据流:提供了读写java中的基本数据类型的功能。

  datainputstream和dataoutputstream分别继承自inputstream和outputstream,需要“套接”在inputstream和outputstream类型的节点流之上。

对象流:用于直接将对象写入写出。

  流类有objectinputstream和objectoutputstream,本身这两个方法没什么,但是其要写出的对象有要求,该对象必须实现serializable接口,来声明其是可以序列化的。否则,不能用对象流读写。

  还有一个关键字比较重要,transient,由于修饰实现了serializable接口的类内的属性,被该修饰符修饰的属性,在以对象流的方式输出的时候,该字段会被忽略。

 



xzc 2015-07-16 11:36
]]>
java 命令参数详解:-dhttp://www.blogjava.net/xzclog/archive/2015/01/21/422309.htmlxzcxzcwed, 21 jan 2015 02:09:00 gmthttp://www.blogjava.net/xzclog/archive/2015/01/21/422309.htmlhttp://www.blogjava.net/xzclog/comments/422309.htmlhttp://www.blogjava.net/xzclog/archive/2015/01/21/422309.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/422309.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/422309.html

java 命令参数详解:

1、-d= set a system property  设置系统属性。

      java命令引入jar时可以-cp参数,但时-cp不能用通配符(多个jar时什么烦要一个个写,不能*.jar),面通常的jar都在同一目录,且多于1个。前些日子找到(发现)-djava.ext.dirs太好。

如:

java -djava.ext.dirs=lib myclass  

 

可以在运行前配置一些属性,比如路径什么的。

java -dconfig="d:/config/config.xml" abc

这样在abc中就可以通过system.getproperty("config");获得这个值了。

 

 

在虚拟机的系统属性中设置属性名/值对,运行在此虚拟机之上的应用程序可用
当虚拟机报告类找不到或类冲突时可用此参数来诊断来查看虚拟机从装入类的情况。

另外,javac -d <目录> 指定存放生成的类文件的位置

standard system properties

 

key meaning
"file.separator" character that separates components of a file path. this is "/" on unix and "\" on windows.
"java.class.path" path used to find directories and jar archives containing class files. elements of the class path are separated by a platform-specific character specified in the path.separator property.
"java.home" installation directory for java runtime environment (jre)
"java.vendor" jre vendor name
"java.vendor.url" jre vender url
"java.version" jre version number
"line.separator" sequence used by operating system to separate lines in text files
"os.arch" operating system architecture
"os.name" operating system name
"os.version" operating system version
"path.separator" path separator character used in java.class.path
"user.dir" user working directory
"user.home" user home directory
"user.name" user account name

 

 

 

所谓的 system porperty,system 指的是 jre (runtime)system,不是指 os。

system.setproperty("net.jxta.tls.principal", "client");
system.setproperty("net.jxta.tls.password", "password");
system.setproperty("jxta_home",system.getproperty("jxta_home","client"));
可以利用系统属性来加载多个驱动



xzc 2015-01-21 10:09
]]>
静态html文件js读取url参数 http://www.blogjava.net/xzclog/archive/2011/12/12/366165.htmlxzcxzcmon, 12 dec 2011 09:15:00 gmthttp://www.blogjava.net/xzclog/archive/2011/12/12/366165.htmlhttp://www.blogjava.net/xzclog/comments/366165.htmlhttp://www.blogjava.net/xzclog/archive/2011/12/12/366165.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/366165.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/366165.html在ajax应用流行时,有时我们可能为了降低服务器的负担,把动态内容生成静态html页面或者是xml文件,供客户端访问!但是在我们的网站或系统中往住页面中某些部分是在后台没有进行修改时,其内容不会发生变化的。但是页面中也往往有部分内容是动态的更新的,比如一个新闻页面,新闻内容往往生成了之后就是静态的,但是新闻的最新评论往往是变化的,在这个时候有几种凯发天生赢家一触即发官网的解决方案:

1、重新生成该静态页面,优点是用户访问时页面上的肉容可以实现全静态,不与服务器程序及数据库后端打交道!缺点是每次用户对页面任何部分更新都必须重新生成。

2、js调用请求动态内容,优点是静态页面只生成一次,动态部分才动态加载,却点是服务器端要用输出一段js代码并用js代码输出网页内容,也不利于搜索引擎收录。

3、ajax调用动态内容,和js基本相似,只是与服务器交互的方式不同!并且页面显示不会受到因动态调用速度慢而影响整个页面的加载速度!至于ajax不利于搜索收录,当然在《ajax in acation》等相关书籍中也介绍有变向的凯发天生赢家一触即发官网的解决方案!

4、在服务器端ssl动态内容,用服务器端优化及缓存解决是时下最流行的方法!

对于第二种和第三种方法都是我最青睐的静态解决方法,适合以内容为主的中小型网站。那么在有时候可能会有js读取url参数的需求,事实证明的确也有很多时候有这种需求,特别是在胖客户端的情况下!以前也写过这样的代码,其实原理很简单就是利用javascript接口提供location对像得到url地址,然后通过分析url以取得参数,以下是我收录的一些优秀的url参数读取代码:

一、字符串分割分析法。
这里是一个获取url ?带questring参数的javascript客户端凯发天生赢家一触即发官网的解决方案,相当于asp的request.querystring,php的$_get
函数:



然后我们通过调用此函数获取对应参数值:




以此获取url串中所带的同名参数

二、正则分析法。

function     getquerystring(name)   
{   
     var     reg     =   new   regexp("(^|&)"      name     "=([^&]*)(&|$)");   
     var     r     =     window.location.search.substr(1).match(reg);   
     if     (r!=null)   return     unescape(r[2]);   return   null;   
}   
alert(getquerystring("参数名1"));   
alert(getquerystring("参数名2"));   
alert(getquerystring("参数名3"));

xzc 2011-12-12 17:15
]]>
java cookie 中文乱码解决方法 http://www.blogjava.net/xzclog/archive/2011/10/03/359956.htmlxzcxzcmon, 03 oct 2011 03:29:00 gmthttp://www.blogjava.net/xzclog/archive/2011/10/03/359956.htmlhttp://www.blogjava.net/xzclog/comments/359956.htmlhttp://www.blogjava.net/xzclog/archive/2011/10/03/359956.html#feedback3http://www.blogjava.net/xzclog/comments/commentrss/359956.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/359956.html
  • import java.net.*;    
  • string   key=urlencoder.encode("中文key","gbk");   
  • string   value=urlencoder.encode("中文value","gbk");   
  • cookie   cook=new cookie(key,value);        
  • string   key=cook.getname(),value=cook.getvalue();      
  • key=urldecoder.decode(key,"gbk");      
  • value=urldecoder.decode(value,"gbk");   


  •  

    string value = java.net.urlencoder.encode("中文","utf-8");

    cookie cookie = new cookie("chinese_code",value);

    cookie.setmaxage(60*60*24*6);

    response.addcookie(cookie);

     

     

     

    encode() 只有一个参数的已经过时了,现在可以设置编码格式, 取cookie值的时候 也不用解码了。

     



    xzc 2011-10-03 11:29
    ]]>
    web.xml中load-on-startup的作用http://www.blogjava.net/xzclog/archive/2011/09/29/359789.htmlxzcxzcthu, 29 sep 2011 07:22:00 gmthttp://www.blogjava.net/xzclog/archive/2011/09/29/359789.htmlhttp://www.blogjava.net/xzclog/comments/359789.htmlhttp://www.blogjava.net/xzclog/archive/2011/09/29/359789.html#feedback22http://www.blogjava.net/xzclog/comments/commentrss/359789.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/359789.html如下一段配置,熟悉dwr的再熟悉不过了:

       dwr-invoker
       org.directwebremoting.servlet.dwrservlet
      
        debug
        true
      
       1


       dwr-invoker
       /dwr/*

    我们注意到它里面包含了这段配置:1,那么这个配置有什么作用呢?

    贴一段英文原汁原味的解释如下:
    servlet specification:
    the load-on-startup element indicates that this servlet should be loaded (instantiated and have its init() called) on the startup of the web application. the optional contents of these element must be an integer indicating the order in which the servlet should be loaded. if the value is a negative integer, or the element is not present, the container is free to load the servlet whenever it chooses.   if the value is a positive integer or 0, the container must load and initialize the servlet as the application is deployed. the container must guarantee that servlets marked with lower integers are loaded before servlets marked with higher integers. the container may choose the order of loading of servlets with the same load-on-start-up value.

    翻译过来的意思大致如下:
    1)load-on-startup元素标记容器是否在启动的时候就加载这个servlet(实例化并调用其init()方法)。

    2)它的值必须是一个整数,表示servlet应该被载入的顺序

    2)当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个servlet;

    3)当值小于0或者没有指定时,则表示容器在该servlet被选择时才会去加载。

    4)正数的值越小,该servlet的优先级越高,应用启动时就越先加载。

    5)当值相同时,容器就会自己选择顺序来加载。

    所以,x,中x的取值1,2,3,4,5代表的是优先级,而非启动延迟时间。

    如下题目:

    2.web.xml中不包括哪些定义(多选)

    a.默认起始页

    b.servlet启动延迟时间定义

    c.error处理页面

    d.jsp文件改动后重新载入时间

    答案:b,d

    通常大多数servlet是在用户第一次请求的时候由应用服务器创建并初始化,但n   可以用来改变这种状况,根据自己需要改变加载的优先级!



    xzc 2011-09-29 15:22 发表评论
    ]]>
    java keytool 使用总结(转)http://www.blogjava.net/xzclog/archive/2011/09/15/358662.htmlxzcxzcthu, 15 sep 2011 00:30:00 gmthttp://www.blogjava.net/xzclog/archive/2011/09/15/358662.htmlhttp://www.blogjava.net/xzclog/comments/358662.htmlhttp://www.blogjava.net/xzclog/archive/2011/09/15/358662.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/358662.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/358662.htmlkeytool是一个java数据证书的管理工具 ,keytool将密钥(key)和证书(certificates)存在一个称为keystore的文件中在keystore里,包含两种数据:
    密钥实体(key entity)——密钥(secret key)又或者是私钥和配对公钥(采用非对称加密)
    可信任的证书实体(trusted certificate entries)——只包含公钥


    ailas(别名)每个keystore都关联这一个独一无二的alias,这个alias通常不区分大小写

     

    jdk中keytool常用命令:

    -genkey 在用户主目录中创建一个默认文件".keystore",还会产生一个mykey的别名,mykey中包含用户的公钥、私钥和证书
    (在没有指定生成位置的情况下,keystore会存在用户系统默认目录,如:对于window xp系统,会生成在系统的c:\documents and settings\username\文件名为“.keystore”)
    -alias 产生别名
    -keystore 指定密钥库的名称(产生的各类信息将不在.keystore文件中)
    -keyalg 指定密钥的算法 (如 rsa dsa(如果不指定默认采用dsa))
    -validity 指定创建的证书有效期多少天
    -keysize 指定密钥长度
    -storepass 指定密钥库的密码(获取keystore信息所需的密码)
    -keypass 指定别名条目的密码(私钥的密码)
    -dname 指定证书拥有者信息 例如: "cn=名字与姓氏,ou=组织单位名称,o=组织名称,l=城市或区域名称,st=州或省份名称,c=单位的两字母国家代码"
    -list 显示密钥库中的证书信息 keytool -list -v -keystore 指定keystore -storepass 密码
    -v 显示密钥库中的证书详细信息
    -export 将别名指定的证书导出到文件 keytool -export -alias 需要导出的别名 -keystore 指定keystore -file 指定导出的证书位置及证书名称 -storepass 密码
    -file 参数指定导出到文件的文件名
    -delete 删除密钥库中某条目 keytool -delete -alias 指定需删除的别 -keystore 指定keystore -storepass 密码
    -printcert 查看导出的证书信息 keytool -printcert -file yushan.crt
    -keypasswd 修改密钥库中指定条目口令 keytool -keypasswd -alias 需修改的别名 -keypass 旧密码 -new 新密码 -storepass keystore密码 -keystore sage
    -storepasswd 修改keystore口令 keytool -storepasswd -keystore e:\yushan.keystore(需修改口令的keystore) -storepass 123456(原始密码) -new yushan(新密码)
    -import 将已签名数字证书导入密钥库 keytool -import -alias 指定导入条目的别名 -keystore 指定keystore -file 需导入的证书

     

    下面是各选项的缺省值。
    -alias "mykey"

    -keyalg "dsa"

    -keysize 1024

    -validity 90

    -keystore 用户宿主目录中名为 .keystore 的文件

    -file 读时为标准输入,写时为标准输出




    1、keystore的生成:

    分阶段生成:
    keytool -genkey -alias yushan(别名) -keypass yushan(别名密码) -keyalg rsa(算法) -keysize 1024(密钥长度) -validity 365(有效期,天单位) -keystore

    e:\yushan.keystore(指定生成证书的位置和证书名称) -storepass 123456(获取keystore信息的密码);回车输入相关信息即可;

    一次性生成:
    keytool -genkey -alias yushan -keypass yushan -keyalg rsa -keysize 1024 -validity 365 -keystore e:\yushan.keystore -storepass 123456 -dname "cn=(名字与

    姓氏), ou=(组织单位名称), o=(组织名称), l=(城市或区域名称), st=(州或省份名称), c=(单位的两字母国家代码)";(中英文即可)

    2、keystore信息的查看:
    keytool -list -v -keystore e:\keytool\yushan.keystore -storepass 123456
    显示内容:
    ---------------------------------------------------------------------
    keystore 类型: jks
    keystore 提供者: sun

    您的 keystore 包含 1 输入

    别名名称: yushan
    创建日期: 2009-7-29
    项类型: privatekeyentry
    认证链长度: 1
    认证 [1]:
    所有者:cn=yushan, ou=xx公司, o=xx协会, l=湘潭, st=湖南, c=中国
    签发人:cn=yushan, ou=xx公司, o=xx协会, l=湘潭, st=湖南, c=中国
    序列号:4a6f29ed
    有效期: wed jul 29 00:40:13 cst 2009 至thu jul 29 00:40:13 cst 2010
    证书指纹:
    md5:a3:d7:d9:74:c3:50:7d:10:c9:c2:47:b0:33:90:45:c3
    sha1:2b:fc:9e:3a:df:c6:c4:fb:87:b8:a0:c6:99:43:e9:4c:4a:e1:18:e8
    签名算法名称:sha1withrsa
    版本: 3
    --------------------------------------------------------------------

     

    缺省情况下,-list 命令打印证书的 md5 指纹。而如果指定了 -v 选项,将以可读格式打印证书,如果指定了 -rfc 选项,将以可打印的编码格式输出证书。


    keytool -list -rfc -keystore e:\yushan.keystore -storepass 123456

    显示:

    -------------------------------------------------------------------------------------------------------

    keystore 类型: jks
    keystore 提供者: sun

    您的 keystore 包含 1 输入

    别名名称: yushan
    创建日期: 2009-7-29
    项类型: privatekeyentry
    认证链长度: 1
    认证 [1]:
    -----begin certificate-----
    miicszccabsgawibagiesm8p7tanbgkqhkig9w0baqufadbqmq8wdqydvqqgdabkuk3lm70xdzan
    bgnvbagmbua5luwnlzepma0ga1uebwwg5rmy5r2tmrewdwydvqqkdah4eownj s8mjerma8ga1ue
    cwwiehjlhazlj7gxdzanbgnvbamtbnl1c2hhbjaefw0wota3mjgxnjqwmtnafw0xmda3mjgxnjqw
    mtnamgoxdzanbgnvbaymbus4rewbvtepma0ga1uecawg5rmw5y2xmq8wdqydvqqhdabmuzjmva0x
    etapbgnvbaomchh45y2p5lyamrewdwydvqqldah4eowfrowpudepma0ga1ueaxmgexvzagfumigf
    ma0gcsqgsib3dqebaquaa4gnadcbiqkbgqcjoru1rqczrztnbwxefvnspqbyks220rs8y/ox3mza
    hjl4wlfourzuuxxuvqr2jx7qi xkme dhqj9r6aaclbci/t1jwf8mvyxtprutze/6kezdhowee70
    liwlve hytlbhz03zhwcd6q5humu27du3mpqvqiwzty7mrwivqq8iqidaqabma0gcsqgsib3dqeb
    bquaa4gbagoqq1/fntfkpqh ni6h3fzdn3sr8zzdmboaiyvlahbb85xdj8qztarhbzmjcidhxal1
    i08ct3e8u87v9t8gzfwvc4bfg/ zefev76sfpve56ix7p1jpsu78z0m69hhlds77vjtdyfmsvtxv
    syhp3fxfzx9wyhipbwd8vpk/ngep
    -----end certificate-----

    -------------------------------------------------------------------------------------------------------

    3、证书的导出:

    keytool -export -alias yushan -keystore e:\yushan.keystore -file e:\yushan.crt(指定导出的证书位置及证书名称) -storepass 123456

    4、查看导出的证书信息
    keytool -printcert -file yushan.crt
    显示:(在windows下可以双击yushan.crt查看)
    -----------------------------------------------------------------------
    所有者:cn=yushan, ou=xx公司, o=xx协会, l=湘潭, st=湖南, c=中国
    签发人:cn=yushan, ou=xx公司, o=xx协会, l=湘潭, st=湖南, c=中国
    序列号:4a6f29ed
    有效期: wed jul 29 00:40:13 cst 2009 至thu jul 29 00:40:13 cst 2010
    证书指纹:
    md5:a3:d7:d9:74:c3:50:7d:10:c9:c2:47:b0:33:90:45:c3
    sha1:2b:fc:9e:3a:df:c6:c4:fb:87:b8:a0:c6:99:43:e9:4c:4a:e1:18:e8
    签名算法名称:sha1withrsa
    版本: 3
    -----------------------------------------------------------------------

    5、证书的导入:
    准备一个导入的证书:
    keytool -genkey -alias shuany -keypass shuany -keyalg rsa -keysize 1024 -validity 365 -keystore e:\shuany.keystore -storepass 123456 -dname "cn=shuany,

    ou=xx, o=xx, l=xx, st=xx, c=xx";
    keytool -export -alias shuany -keystore e:\shuany.keystore -file e:\shuany.crt -storepass 123456

    现在将shuany.crt 加入到yushan.keystore中:
    keytool -import -alias shuany(指定导入证书的别名,如果不指定默认为mykey,别名唯一,否则导入出错) -file e:\shuany.crt -keystore e:\yushan.keystore -storepass

    123456

    keytool -list -v -keystore e:\keytool\yushan.keystore -storepass 123456
    显示:
    ------------------------------------------------------------------------------
    keystore 类型: jks
    keystore 提供者: sun

    您的 keystore 包含 2 输入

    别名名称: yushan
    创建日期: 2009-7-29
    项类型: privatekeyentry
    认证链长度: 1
    认证 [1]:
    所有者:cn=yushan, ou=xx公司, o=xx协会, l=湘潭, st=湖南, c=中国
    签发人:cn=yushan, ou=xx公司, o=xx协会, l=湘潭, st=湖南, c=中国
    序列号:4a6f29ed
    有效期: wed jul 29 00:40:13 cst 2009 至thu jul 29 00:40:13 cst 2010
    证书指纹:
    md5:a3:d7:d9:74:c3:50:7d:10:c9:c2:47:b0:33:90:45:c3
    sha1:2b:fc:9e:3a:df:c6:c4:fb:87:b8:a0:c6:99:43:e9:4c:4a:e1:18:e8
    签名算法名称:sha1withrsa
    版本: 3


    *******************************************
    *******************************************


    别名名称: shuany
    创建日期: 2009-7-29
    输入类型: trustedcertentry

    所有者:cn=shuany, ou=xx, o=xx, l=xx, st=xx, c=xx
    签发人:cn=shuany, ou=xx, o=xx, l=xx, st=xx, c=xx
    序列号:4a6f2cd9
    有效期: wed jul 29 00:52:41 cst 2009 至thu jul 29 00:52:41 cst 2010
    证书指纹:
    md5:15:03:57:9b:14:bd:c5:50:21:15:47:1e:29:87:a4:e6
    sha1:c1:4f:8b:cd:5e:c2:94:77:b7:42:29:35:5c:bb:bb:2e:9e:f0:89:f5
    签名算法名称:sha1withrsa
    版本: 3


    *******************************************
    *******************************************
    ------------------------------------------------------------------------------

    6、证书条目的删除:
    keytool -delete -alias shuany(指定需删除的别名) -keystore yushan.keystore -storepass 123456

    7、证书条目口令的修改:
    keytool -keypasswd -alias yushan(需要修改密码的别名) -keypass yushan(原始密码) -new 123456(别名的新密码) -keystore e:\yushan.keystore -storepass 123456

    8、keystore口令的修改:
    keytool -storepasswd -keystore e:\yushan.keystore(需修改口令的keystore) -storepass 123456(原始密码) -new yushan(新密码)

     

    9、修改keystore中别名为yushan的信息

     

    keytool -selfcert -alias yushan -keypass yushan -keystore e:\yushan.keystore -storepass 123456 -dname "cn=yushan,ou=yushan,o=yushan,c=us



    xzc 2011-09-15 08:30
    ]]>
    buffalo ajax框架使用 http://www.blogjava.net/xzclog/archive/2011/06/16/352439.htmlxzcxzcthu, 16 jun 2011 08:44:00 gmthttp://www.blogjava.net/xzclog/archive/2011/06/16/352439.htmlhttp://www.blogjava.net/xzclog/comments/352439.htmlhttp://www.blogjava.net/xzclog/archive/2011/06/16/352439.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/352439.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/352439.html下载地址:

    1.buffalo-2.0.jar
    在buffalo-2.0-bin里,把它加到web应用程序里的lib

    2.buffalo.js和prototype.js
    我把这两个文件放到web应用程序的scripts/目录下,buffalo.js在buffalo-2.0-bin里,prototype.js在buffalo-demo.war里找

    4.web.xml内容
    xml version="1.0" encoding="utf-8"?>
    <web-app version="2.4" 
        xmlns
    ="http://java.sun.com/xml/ns/j2ee" 
        xmlns:xsi
    ="http://www.w3.org/2001/xmlschema-instance" 
        xsi:schemalocation
    ="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    >
        
        
        
    <servlet>
            
    <servlet-name>bfappservlet-name>
            
    <servlet-class>net.buffalo.web.servlet.applicationservletservlet-class>
        
    servlet>
        
    <servlet-mapping>
            
    <servlet-name>bfappservlet-name>
            
    <url-pattern>/bfapp/*url-pattern>
        
    servlet-mapping>
        
    web-app>


    5.index.jsp文件
    <%@ page language="java" pageencoding="utf-8"%>


    doctype html public "-//w3c//dtd html 4.01 transitional//en">
    <html>
      
    <head>
        
    <title>第一个 buffalo 示例程序title>
        
    <script language="javascript" src="scripts/prototype.js">script>
        
    <script language="javascript" src="scripts/buffalo.js">script>
        
    <script type="text/javascript">
        
    var endpoint="<%=request.getcontextpath()%>/bfapp";
        
        
    var buffalo = new buffalo(endpoint);
        
    function hello(me) {
            buffalo.remotecall(
    "demoservice.gethello", [me.value], function(reply) {
                alert(reply.getresult());
            })
        }
        
    script>
      
    head>
      
      
    <body>
        输入你的名字:
    <input type="text" name="myname">
        
    <input type="button" value="buffao远程调用" onclick="hello($('myname'));"><br>
      
    body>
    html>

    说明:remotecall是远程调用方法,demoservice是buffalo-service.properties文件的键,gethello是被调用java类方法名,me.value是传给gethello方法的参数,reply.getresult()是gethello返回的值。

    6.demoservice.java文件
    package demo.buffalo;

    /**
     * 
     * @文件名 demo.buffalo.demoservice.java
     * @作者 chenlb
     * @创建时间 2007-7-14 下午12:42:17 
     
    */
    public class demoservice {

        
    public string gethello(string name) {
            
    return "hello , "name " 这是第一个buffalo示例程序";
        }
    }

    7.buffalo-service.properties文件放到web-inf/classes/目录下
    demoservice=demo.buffalo.demoservice
    说明:框架是通过此文件来查找远程调用的类的。

    8.现在可以运行了。

    注意:eclipse项目,文件编码是utf-8

    官方地址:
    buffalo中文论坛:

    javascript api :



    xzc 2011-06-16 16:44
    ]]>
    java通过telnet连接执行shell脚本http://www.blogjava.net/xzclog/archive/2010/09/29/333403.htmlxzcxzcwed, 29 sep 2010 07:56:00 gmthttp://www.blogjava.net/xzclog/archive/2010/09/29/333403.htmlhttp://www.blogjava.net/xzclog/comments/333403.htmlhttp://www.blogjava.net/xzclog/archive/2010/09/29/333403.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/333403.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/333403.html/**  
  •  * commons-net-2.0.jar是工程依赖包   
  •  */  
  • package telnet2;   
  •   
  • import java.io.inputstream;   
  • import java.io.printstream;   
  •   
  • import org.apache.commons.net.telnet.telnetclient;   
  •   
  • /**  
  •  * @descript nettelenet.java  
  •  * @author sinclair  
  •  * @date jun 10, 2010  
  •  */  
  • public class nettelnet {   
  •     private telnetclient telnet = new telnetclient();   
  •     private inputstream in;   
  •     private printstream out;   
  •     private char prompt = '$';// 普通用户结束   
  •   
  •     public nettelnet( string ip, int port, string user, string password ) {   
  •     try {   
  •         telnet.connect( ip, port );   
  •         in = telnet.getinputstream();   
  •         out = new printstream( telnet.getoutputstream() );   
  •         // 根据root用户设置结束符   
  •         this.prompt = user.equals( "root" ) ? '#' : '$';   
  •         login( user, password );   
  •     } catch ( exception e ) {   
  •         e.printstacktrace();   
  •     }   
  •     }   
  •   
  •     /**  
  •      * 登录  
  •      *   
  •      * @param user  
  •      * @param password  
  •      */  
  •     public void login( string user, string password ) {   
  •     readuntil( "login:" );   
  •     write( user );   
  •     readuntil( "password:" );   
  •     write( password );   
  •     readuntil( prompt   " " );   
  •     }   
  •   
  •     /**  
  •      * 读取分析结果  
  •      *   
  •      * @param pattern  
  •      * @return  
  •      */  
  •     public string readuntil( string pattern ) {   
  •     try {   
  •         char lastchar = pattern.charat( pattern.length() - 1 );   
  •         stringbuffer sb = new stringbuffer();   
  •         char ch = ( char ) in.read();   
  •         while ( true ) {   
  •         sb.append( ch );   
  •         if (ch == lastchar) {   
  •             if (sb.tostring().endswith( pattern )) {   
  •             return sb.tostring();   
  •             }   
  •         }   
  •         ch = ( char ) in.read();   
  •         }   
  •     } catch ( exception e ) {   
  •         e.printstacktrace();   
  •     }   
  •     return null;   
  •     }   
  •   
  •     /**  
  •      * 写操作  
  •      *   
  •      * @param value  
  •      */  
  •     public void write( string value ) {   
  •     try {   
  •         out.println( value );   
  •         out.flush();   
  •     } catch ( exception e ) {   
  •         e.printstacktrace();   
  •     }   
  •     }   
  •   
  •     /**  
  •      * 向目标发送命令字符串  
  •      *   
  •      * @param command  
  •      * @return  
  •      */  
  •     public string sendcommand( string command ) {   
  •     try {   
  •         write( command );   
  •         return readuntil( prompt   " " );   
  •     } catch ( exception e ) {   
  •         e.printstacktrace();   
  •     }   
  •     return null;   
  •     }   
  •   
  •     /**  
  •      * 关闭连接  
  •      */  
  •     public void disconnect() {   
  •     try {   
  •         telnet.disconnect();   
  •     } catch ( exception e ) {   
  •         e.printstacktrace();   
  •     }   
  •     }   
  •   
  •     public static void main( string[] args ) {   
  •     try {   
  •         system.out.println( "启动telnet..." );   
  •         string ip = "192.168.0.11";   
  •         int port = 23;   
  •         string user = "user";   
  •         string password = "111111";   
  •         nettelnet telnet = new nettelnet( ip, port, user, password );   
  •         telnet.sendcommand( "export lang=en" );   
  •         string r1 = telnet.sendcommand( "cd /home/project/" );   
  •         string r2 = telnet.sendcommand( "pwd" );   
  •         string r3 = telnet.sendcommand( "sh a.sh" );   
  •   
  •         system.out.println( "显示结果" );   
  •         system.out.println( r1 );   
  •         system.out.println( r2 );   
  •         system.out.println( r3 );   
  •   
  •         telnet.disconnect();   
  •     } catch ( exception e ) {   
  •         e.printstacktrace();   
  •     }   
  •     }   
  • }  


  • xzc 2010-09-29 15:56
    ]]>
    j2ee异常处理机制http://www.blogjava.net/xzclog/archive/2010/03/13/315329.htmlxzcxzcsat, 13 mar 2010 03:59:00 gmthttp://www.blogjava.net/xzclog/archive/2010/03/13/315329.htmlhttp://www.blogjava.net/xzclog/comments/315329.htmlhttp://www.blogjava.net/xzclog/archive/2010/03/13/315329.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/315329.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/315329.htmlhttp://mofeichen.javaeye.com/blog/557426

    异常的处理是每个java程序员时常面对的问题,但是很多人没有原则,遇到异常也不知道如何去处理,于是遇到检查异常就胡乱try...catch...一把,然后e.printstacktrace()一下了事,这种做法通常除了调试排错有点作用外,没任何价值。对于运行时异常,则干脆置之不理。

      原因是很多开发者缺乏对异常的认识和分析,首先应该明白java异常体系结构,一种分层继承的关系,你必须对层次结构熟烂于心:

      throwable(必须检查)

      error(非必须检查)

      exception(必须检查)

      runtimeexception(非必须检查)

      一般把exception异常及其直接子类(除了runtimeexception之外)的异常称之为检查异常。把runtimeexception以及其子类的异常称之为非检查异常,也叫运行时异常。

      对于throwable和error,则用的很少,一般会用在一些基础框架中,这里不做讨论。

      下面针对j2ee的分层架构:dao层、业务层、控制层、展示层的异常处理做个分析,并给出一般处理准则。

      一、dao层异常处理

      如果你用了spring的dao模板来实现,则dao层没有检查异常抛出,代码非常的优雅。但是,如果你的dao采用了原始的jdbc来写,这时候,你不能不对异常做处理了,因为难以避免的sqlexception会如影随形的跟着你。对已这种dao级别的异常,异常了你又能如何呢?与其这样胡乱try...catch...,囫囵吞枣消灭了异常不如让异常以另外一种非检查的方式向外传递。这样做好处有二:

      1)、dao的接口不被异常所污染,假设你抛出了sqlexception,以后要是换了spring dao模板,那dao接口就不再抛出了sqlexception,这样,你的接口抛出异常就是对接口的污染。

      2)、dao异常向外传播给更高层处理,以便异常的错误原因不丢失,便于排查错误或进行捕获处理。

      这里还有一个设计上常常令人困扰的问题:很多人会问,那定义一个什么样的异常抛出呢,或者是直接抛出一个throw runtimeexception(e)? 对于这个问题,需要分场合,如果系统小,你可以直接抛出一个throw runtimeexception(e),但对于一个庞大的多模块系统来说,不要抛这种原生的非检查异常,而要抛出自定义的非检查异常,这样不但利于排错,而且有利于系统异常的处理,通常针对每一个模块,粗粒度的定义一个运行时dao异常。比如:throw new modelxxxdaoruntimeexception(".....",e),对于msg信息,你可写也可不写,根据需要灵活抛出。

      这里常见一个很愚昧的处理方式,为每个dao定义一个异常,呵呵,这样累不累啊,有多大意义,在service层中调用时候,如果要捕获,还要捕获出一堆异常。这样致命的问题是代码混乱,维护困难,阅读也困难,dao的异常应该是粗粒度的。

      二、业务层异常处理

      习惯上把业务层称之为service层或者服务层,service层的代表的是业务逻辑,不要迷信分太多太多层有多大好处,除非需要,否则别盲目划分不必要的层,层越多,效率越差,根据需要够用就行了。

      service接口中的每个方法代表一个特定的业务,而这个业务一定是一个完整的业务,通常会看到一些傻x的做法,数据库事务配置在service层,而service的实现就是dao的直接调用,然后在控制层(action)中,调用了好多service去完成一个业务,你气得已经无语了,低头找砖头去!!!

      搞明白以上两个问题后再回过头看异常怎么处理,service层通常依赖dao,而service层的通常也会因为调用别的非检查异常方法而必须面对异常处理的问题,这里和dao层又有所不同,彼一时,此一时嘛!

      一般来说一个小模块对应一个service,当然也许有两个或多个,针对这个模块的service定义一个非检查异常,以应付那些不可避免的异常检查,这个自定义异常可以简单的命名为xxxserviceruntimeexception,将捕获到的异常顺势转译为非检查异常后抛出。我喜欢这么做,因为前台是j2ee应用,前台是web页面,它们的struts2等框架会自动捕获所有service层的异常,并把异常交给开发者去自由处理。

      但是还有一种情况,由于一些特殊的限制,如果某个异常一旦发生,必须做什么什么处理,而这种处理时硬性要求,或者调用某个service方法,必须检查处理什么异常,也可以抛出非检查的自定义异常,往往出现这种情况的是政治原因。不推崇这种做法,但也不排斥。

      总之,对于接口,尽可能不去用异常污染她!

      三、控制层异常

      控制层说的简单些就是常见的action层,主要是控制页面请求的处理。控制层通常都依赖于service层,现在比较流行的框架对控制层做得都相当的到位,比如struts2、springmvc等等,他们的控制层框架会捕获业务层的所有异常,并在控制层中声明可能抛出exception,因此控制层一般不处理什么异常。

      如果是控制层中因为调用了一些非检查异常的方法,比如io操作等,可以简单处理下异常,保证流的安全,这才是目的。

      四、显示层异常处理

      对于页面异常,处理的方式多种多样,一是不处理异常,一旦异常了,页面就报错。二是定义出错页面,根据异常的类型以及所在的模块,导航到出错页面。

      一般来说,出错页面是更友好的做法。

      另外还有特殊的处理方式,展示页面的模板可以捕获异常,并根据情况将异常信息铺到相应的位置,这样就更友好了,不过复杂度较高。

      怎么处理,就看需要了。

      五、总结

      1)、对于异常处理,应该从设计、需要、维护等多个角度综合考虑,有一个通用准则:千万别捕获了异常什么事情都不干,这样一旦出现异常了,你没法依据异常信息来排错。

      2)、对于j2ee多层架构系统来说,尽可能避免(因抛出异常带来的)接口污染。



    xzc 2010-03-13 11:59
    ]]>
    proxool连接池配置详细说明http://www.blogjava.net/xzclog/archive/2010/01/30/311320.htmlxzcxzcsat, 30 jan 2010 04:02:00 gmthttp://www.blogjava.net/xzclog/archive/2010/01/30/311320.htmlhttp://www.blogjava.net/xzclog/comments/311320.htmlhttp://www.blogjava.net/xzclog/archive/2010/01/30/311320.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/311320.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/311320.htmlc3p0>dbcp,proxool还提供了可视化的连接池实时监控工具,所以既稳定又方便,配置也是非常容易的事情。下面我来讲讲我如何配置proxool连接池的。       1、下载相关资源。       从http://pr...  

    xzc 2010-01-30 12:02
    ]]>
    hibernate的三种连接池设置c3p0、proxool和dbcp http://www.blogjava.net/xzclog/archive/2010/01/30/311319.htmlxzcxzcsat, 30 jan 2010 04:00:00 gmthttp://www.blogjava.net/xzclog/archive/2010/01/30/311319.htmlhttp://www.blogjava.net/xzclog/comments/311319.htmlhttp://www.blogjava.net/xzclog/archive/2010/01/30/311319.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/311319.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/311319.html
    xml代码
    1.   
    2. <property name="connection.driver_class">com.mysql.jdbc.driverproperty> <property name="connection.url">jdbc:mysql://localhost:3306/struts?useunicode=true&characterencoding=gbkproperty>   
    3. <property name="connection.username">rootproperty>   
    4. <property name="connection.password">8888property>   


    上面的一段配置,在c3p0dbcp中,都是必需的,因为hibernate会根据上述的配置来生成connections,再交给c3p0dbcp管理.

    1 c3p0

    只需在hibernate.cfg.xml中加入
    xml代码
    1. <property name="c3p0.min_size">5property>  
    2. <property name="c3p0.max_size">30property>  
    3. <property name="c3p0.time_out">1800property>  
    4. <property name="c3p0.max_statement">50property>   


    还有在classespath中加入c3p0-0.8.4.5.jar


    2 dbcp

    在hibernate.cfg.xml中加入

    xml代码
    1. <property name="dbcp.maxactive">100property>  
    2. <property name="dbcp.whenexhaustedaction">1property>  
    3. <property name="dbcp.maxwait">60000property>  
    4. <property name="dbcp.maxidle">10property>  
    5.   
    6. <property name="dbcp.ps.maxactive">100property>  
    7. <property name="dbcp.ps.whenexhaustedaction">1property>  
    8. <property name="dbcp.ps.maxwait">60000property>  
    9. <property name="dbcp.ps.maxidle">10property>  

    还有在classespath中加入commons-pool-1.2.jar 和commons-dbcp-1.2.1.jar.


    3 proxool

    由于数据库connection在较长时间没有访问下会自动断开连接,导致浏览出错,增加proxool作为数据库pool。它有自动连接功能。
    1)、从
    下载proxool,释放proxool.jar到web-inf/lib

    2)、在hibernate.cfg.xml中增加:
    xml代码
    1. <property name="hibernate.proxool.pool_alias">dbpoolproperty>  
    2. <property name="hibernate.proxool.xml">proxool.xmlproperty>  
    3. <property name="connection.provider_class">org.hibernate.connection.proxoolconnectionproviderproperty>  


    3)、在与hibernate.cfg.xml同级目录(src根目录下)增加proxool.xml文件:
    xml代码
    1. xml version="1.0" encoding="utf-8"?>  
    2. 为缩短或简化 javac 命令,可以指定一个或多个每行含有一个文件名的文件。在命令行中,采用 '@' 字符加上文件名的方法将它指定为文件列表。当 javac 遇到以 `@' 字符开头的参数时,它对那个文件中所含文件名的操作跟对命令行中文件名的操作是一样的。这使得 windows 命令行长度不再受限制。

      例如,可以在名为 sourcefiles 的文件中列出所有源文件的名称。该文件可能形如:

           myclass1.java
      myclass2.java
      myclass3.java
      

      然后可用下列命令运行编译器:

           c:> javac @sourcefiles
      


      xzc 2009-12-04 17:13
      ]]>java命令行命令详解http://www.blogjava.net/xzclog/archive/2009/12/04/304795.htmlxzcxzcfri, 04 dec 2009 09:12:00 gmthttp://www.blogjava.net/xzclog/archive/2009/12/04/304795.htmlhttp://www.blogjava.net/xzclog/comments/304795.htmlhttp://www.blogjava.net/xzclog/archive/2009/12/04/304795.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/304795.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/304795.htmljava命令行命令详解

      rmic

      功能说明:
        rmic 为远程对象生成 stub 和 skeleton。

      语法:
        rmic [ options ] package-qualified-class-name(s)

      补充说明:
        rmic 编译器根据编译后的 java 类(含有远程对象实现)名,为远程对象生成 stub 和 skeleton(远程对象是指实现 java.rmi.remote 接口的对象)。在 rmic 命令中所给的类必须是经 javac 命令成功编译且是完全包限定的类。

      命令选项
        -classpath[路径] 指定 rmic 用于查询类的路径。如果设置了该选项,它将覆盖缺省值或 classpath 环境变量。目录用冒号分隔。


        -d[目录] 指定类层次的根目录。此选项可用来指定 stub 和 skeleton 文件的目标目录。


        -depend 使编译器考虑重新编译从其它类引用的类。 一般来说,它只重新编译从源代码引用的遗漏或过期的类。

        -g 允许生成调试表格。调试表格含有行号和局部变量的有关信息,即 java 调试工具所使用的信息。缺省情况下,只生成行号。

        -j 与 -d 选项联用,它将紧跟其后的选项( -j 与 -d 之间无空格)传给 java 解释器。

        -keepgenerated 为 stub 和 skeleton 文件保留所生成的 .java 源文件,并将这些源文件写到与 .class 文件相同的目录中,如果要指定目录,则使用 -d 选项。

        -nowarn 关闭警告。如果使用该选项,则编译器不输出任何警告信息。

        -show 显示 rmic 编译器的 gui(图形用户界面)。输入一个或多个包限定类名(以空格分隔),并按回车键或“显示”按钮,创建 stub 和 skeleton。

        -vcompat (缺省值)创建与 jdk 1.1 和 1.2 stub 协议版本都兼容的 stub 和 skeleton。

        -verbose 使编译器和链接器输出关于正在编译哪些类和正在加载哪些类文件的信息。

        -v1.1 创建 jdk 1.1 stub 协议版本的 stub 和 skeleton。

        -v1.2 只创建 jdk 1.2 stub 协议版本的 stub。


      rmid

      功能说明:
        rmid 启动激活系统守护进程,以便能够在 java 虚拟机上注册和激活对象。

      语法:
        rmid [-port port] [-log dir]

      补充说明:
        rmid 工具启动激活系统守护进程。必须先启动激活系统守护进程,才能向激活系统注册可被激活的对象或在 java 虚拟机上激活可被激活的对象。

      命令选项
        -c<某些命令行选项> 指定一个选项,在创建每个 rmid 的子守护进程(激活组)时,该选项以命令行参数的形式传给该子守护进程。

        -log[目录] 指定目录的名称,激活系统守护进程在该目录中写入其数据库及相关信息。缺省状态下,将在执行 rmid 命令的目录中创建一个 log 目录。

        -port[端口] 指定 rmid 的注册服务程序所使用的端口。激活系统守护进程将 activationsystem 与该注册服务程序中的名称java.rmi.activation.activationsystem 捆绑在一起。

        -stop 停止 -port 选项所指定端口上的当前 rmid 调用。若未指定端口,则将停止在端口 1098 上运行的 rmid。

      rmiregistry

      功能说明:
        rmiregistry 命令可在当前主机的指定端口上启动远程对象注册服务程序。

      语法:
        rmiregistry [port]

      补充说明:
         rmiregistry 命令在当前主机的指定 port 上创建并启动远程对象注册服务程序。如果省略 port,则注册服务程序将在 1099 端口上启动。rmiregistry 命令不产生任何输出而且一般在后台运行。远程对象注册服务程序是自举命名服务。主机上的 rmi 服务器将利用它将远程对象绑定到名字上。客户机即可查询远程对象并进行远程方法调用。注册服务程序一般用于定位应用程序需调用其方法的第一个远程对象。该 对象反过来对各应用程序提供相应的支持,用于查找其它对象。

        java.rmi.registry.locateregistry 类的方法可用于在某台主机或主机和端口上获取注册服务程序操作。java.rmi.naming 类的基于 url 的方法将对注册服务程序进行操作,并可用于查询远程对象、将简单(字符串)名称绑定到远程对象、将新名称重新绑定到远程对象(覆盖旧绑定)、取消远程对象 的绑定以及列出绑定在注册服务程序上的 url。

      serialver

      功能说明:
        serialver 命令返回 serialversionuid。

      语法:
        serialver [ 命令选项 ]

      补充说明:
        serialver 以适于复制到演变类的形式返回一个或多个类的 serialversionuid。不带参数调用时,它输出用法行。

      命令选项
        -show 显示一个简单的用户界面。输入完整的类名并按回车键或“显示”按钮可显示 serialversionuid。

      jarsigner

      功能说明:
        为 java 归档 (jar) 文件产生签名,并校验已签名的 jar 文件的签名。

      语法:
        jarsigner [ 命令选项 ] jar-file alias
        jarsigner -verify [ 命令选项 ] jar-file

      补充说明:
        jarsigner 工具用于两个目的:
        1:为 java 归档 (jar) 文件签名
        2:校验已签名的 jar 文件的签名和完整性

      命令选项
        -keystore[url] 指定密钥仓库的 url。缺省值是用户的宿主目录中的 .keystore 文件,它由系统属性“user.home”决定。

        -storetype[storetype] 指定要被实例化的密钥仓库类型。默认的密钥仓库类型是安全属性文件中 "keystore.type" 属性值所指定的那个类型,由 java.security.keystore 中的静态方法 getdefaulttype 返回。

        -storepass[password] 指定访问密钥仓库所需的口令。这仅在签名(不是校验)jar 文件时需要。在这种情况下,如果命令行中没有提供 -storepass 选项,用户将被提示输入口令。

        -keypass[password] 指定用于保护密钥仓库项(由命令行中指定的别名标出)的私钥的口令。使用 jarsigner 为 jar 文件签名时需要该口令。如果命令行中没有提供口令,且所需的口令与密钥仓库的口令不同,则将提示用户输入它。

        -sigfile[file] 指定用于生成 .sf 和 .dsa 文件的基本文件名。

        -signedjar[file] 指定用于已签名的 jar 文件的名称。

         -verify 如果它出现在命令行中,则指定的 jar 文件将被校验,而不是签名。如果校验成功,将显示“jar verified”。如果试图校验未签名的 jar 文件,或校验被不支持的算法(例如未安装 rsa 提供者时使用的 rsa)签名的 jar 文件,则将有如下显示: "jar is unsigned. (signatures missing or not parsable)" 。

        -certs 如果它与 -verify 和 -verbose 选项一起出现在命令行中,则输出将包括 jar 文件的每个签名人的证书信息。

        -verbose 如果它出现在命令行中,则代表“verbose”模式,它使 jarsigner 在 jar 签名或校验过程中输出额外信息。

         -internalsf 过去,jar 文件被签名时产生的 .dsa(签名块)文件包含一个同时产生的 .sf 文件(签名文件)的完整编码副本。这种做法已被更改。为了减小输出 jar 文件的整个大小,缺省情况下 .dsa 文件不再包含 .sf 文件的副本。但是如果 -internalsf 出现在命令行中,将采用旧的做法。该选项主要在测试时有用;实际上不应使用它,因为这样将消除有用的优化。

        -sectionsonly 如果它出现在命令行中,则 jar 文件被签名时生成的 .sf 文件(签名文件)将不包括含有整个清单文件的散列的头。它仅包含 与 jar 中每个单独的源文件相关的信息和散列。该选项主要在测试时有用;实际上不应使用它,因为这样将消除有用的优化。

        -j [javaoption] 将指定的 javaoption 串直接传递到 java 解释器。((jarsigner 实际上是解释器的一个 “wrapper”)。该选项不应含有任何空格。它有助于调整执行环境或内存使用。要获得可用的解释器选项的清单,可在命令行键入 java -h 或 java -x。

      keytool

      功能说明:
        管理由私钥和认证相关公钥的 x.509 证书链组成的密钥仓库(数据库)。还管理来自可信任实体的证书。

      语法:
        keytool [ 命令 ]

      补充说明:
        keytool 是个密钥和证书管理工具。它使用户能够管理自己的公钥/私钥对及相关证书,用于(通过数字签名)自我认证(用户向别的用户/服务认证自己)或数据完整性以及认证服务。它还允许用户储存他们的通信对等者的公钥(以证书形式)。

      native2ascii

      功能说明:
        将含有本地编码字符(既非 latin1 又非 unicode 字符)的文件转换为 unicode 编码字符的文件。

      语法:
        native2ascii [options] [inputfile [outputfile]]

      补充说明:
        java 编译器和其它 java 工具只能处理含有 latin-1 和/或 unicode 编码(udddd 记号)字符的文件。native2ascii 将含有其它字符编码的文件转换成含 latin-1 和/或 unicode 编码字符的文件。若省略 outputfile,则使用标准输出设备输出。此外,如果也省略 inputfile,则使用标准输入设备输入。

      命令选项
        -reverse 执行相反的操作:将含 latin-1 和/或 unicode 编码字符的文件转换成含本地编码字符的文件。

        -encoding[encoding_name] 指定转换过程使用的编码名称。缺省的编码从系统属性 file.encoding 中得到。

      appletviewer

      功能说明:
        java applet 浏览器。appletviewer 命令可在脱离万维网浏览器环境的情况下运行 applet。

      语法:
        appletviewer [ threads flag ] [ 命令选项 ] urls ...

      补充说明:
         appletviewer 命令连接到 url 所指向的文档或资源上,并在其自身的窗口中显示文档引用的每个 applet。注意:如果 url 所指向的文档不引用任何带有 object、embed 或 applet 标记的 applet,那么 appletviewer 就不做任何事情。

      命令选项
        -debug 在 java 调试器 jdb 中启动 appletviewer,使您可以调试文档中的 applet。

        -encoding[编码名称] 指定输入 html 文件的编码名称。

         -j[javaoption] 将 javaoption 字符串作为单个参数传给运行 appletviewer 的 java 解释器。参数不能含有空格。由多重参数组成的字符串,其中的每个参数都必须以前缀 -j 开头,该前缀以后将被除去。这在调整编译器的执行环境或内存使用时将很有用。

      extcheck

      功能说明:
        extcheck 检测目标 jar 文件与当前安装方式扩展 jar 文件间的版本冲突。

      语法:
        extcheck [ -verbose ] targetfile.jar

      补充说明:
        extcheck 实用程序检查指定 jar 文件的标题和版本与 jdk tm 软件中所安装的扩展是否有冲突。在安装某个扩展前,可以用该实用程序查看是否已安装了该扩展的相同版本或更高的版本。

         extcheck 实用程序将 targetfile.jar 文件清单的 specification-title 和 specification-version 头与当前安装在扩展目录下所有 jar 文件的相对应的头进行比较(缺省扩展目录为 jre/lib/ext)。extcheck 实用程序比较版本号的方式与 java.lang.package.iscompatiblewith 方法相同。若未检测到冲突,则返回代码为 0。如果扩展目录中任何一个 jar 文件的清单有相同的 specification-title 和相同的或更新的 specification-version 号,则返回非零错误代码。如果 targetfile.jar 的清单中没有 specification-title 或 specification-version 属性,则同样返回非零错误代码。

      命令选项
        -verbose 对扩展目录中的 jar 文件进行检查时,列出文件。此外,还报告目标 jar 文件的清单属性及所有冲突的 jar 文件。

      jar

      功能说明:
        java归档工具

      语法:
        jar [ 命令选项 ] [manifest] destination input-file [input-files]

      补充说明:
         jar工具是个java应用程序,可将多个文件合并为单个jar归档文件。jar是个多用途的存档及压缩工具,它基于zip和zlib压缩格式。然而, 设计jar的主要目的是便于将java applet或应用程序打包成单个归档文件。将applet或应用程序的组件(.class 文件、图像和声音)合并成单个归档文件时,可以用java代理(如浏览器)在一次http事务处理过程中对它们进行下载,而不是对每个组件都要求一个新连 接。这大大缩短了下载时间。jar还能压缩文件,从而进一步提高了下载速度。此外,它允许applet的作者对文件中的各个项进行签名,因而可认证其来 源。jar工具的语法基本上与tar命令的语法相同。

      命令选项
        -c 在标准输出上创建新归档或空归档。

        -t 在标准输出上列出内容表。

        -x[file] 从标准输入提取所有文件,或只提取指定的文件。如果省略了file,则提取所有文件;否则只提取指定文件。

        -f 第二个参数指定要处理的jar文件。在-c(创建)情形中,第二个参数指的是要创建的jar文件的名称(不是在标准输出上)。在-t(表(或-x(抽取)这两种情形中,第二个参数指定要列出或抽取的jar文件。

        -v 在标准错误输出设备上生成长格式的输出结果。

        -m 包括指定的现有清单文件中的清单信息。用法举例:“jar cmf mymanifestfile myjarfile *.class”

        -0 只储存,不进行 zip 压缩。

        -m 不创建项目的清单文件。

         -u 通过添加文件或更改清单来更新现有的 jar 文件。例如:“jar -uf foo.jar foo.class”将文件 foo.class 添加到现有的jar文件foo.jar中,而“jar umf manifest foo.jar”则用manifest中的信息更新foo.jar的清单。

        -c 在执行 jar 命令期间更改目录。例如:“jar -uf foo.jar -c classes *”将classes目录内的所有文件加到foo.jar中,但不添加类目录本身。

      程序示例
        1:将当前目录下所有class文件打包成新的jar文件:
        jar cf file.jar *.class

        2:显示一个jar文件中的文件列表
        jar tf file.jar

        3:将当前目录下的所有文件增加到一个已经存在的jar文件中
        jar cvf file.jar *

      javadoc

      功能说明
        java api文档生成器从java源文件生成api文档html页。

      语法:
        javadoc [ 命令选项 ] [ 包名 ] [ 源文件名 ] [ @files ]
        其中[ 包名 ]为用空格分隔的一系列包的名字,包名不允许使用通配符,如(*)。[ 源文件名 ]为用空格分隔的一系列的源文件名,源文件名可包括路径和通配符,如(*)。[ @files ]是以任何次序包含包名和源文件的一个或多个文件。

      补充说明
        javadoc解析java源文件中的声明和文档注释,并产生相应的html页缺省),描述公有类、保护类、内部类、接口、构造函数、方法和域。

         在实现时,javadoc要求且依赖于java编译器完成其工作。javadoc调用部分javac编译声明部分,忽略成员实现。它建立类的内容丰富的 内部表示,包括类层次和“使用”关系,然后从中生成html。javadoc还从源代码的文档注释中获得用户提供的文档。

        当javadoc建立其内部文档结构时,它将加载所有引用的类。由于这一点,javadoc必须能查找到所有引用的类,包括引导类、扩展类和用户类。

      命令选项
        -overview i>path/filename 指定javadoc应该从path/filename所指定的“源”文件中获取概述文档,并将它放到概述页中(overview- summary.html)。其中path/filename 是相对于-sourcepath的相对路径名。

        -public 只显示公有类及成员。

        -protected 只显示受保护的和公有的类及成员。这是缺省状态。

        -package 只显示包、受保护的和公有的类及成员。

        -private 显示所有类和成员。

        -help 显示联机帮助,它将列出这些javadoc和doclet命令行选项。

         -doclet class 指定启动用于生成文档的docle 的类文件。该doclet定义了输出的内容和格式。如果未使用-doclet选项,则javadoc使用标准doclet生成缺省html格式。该类必须 包含start(root)法。该启动类的路径由 -docletpath选项定义。

        -docletpath classpathlist 指定doclet类文件的路径,该类文件用-doclet选项指定。如果doclet已位于搜索路径中,则没有必要使用该选项。

         -1.1 生成具有用javadoc 1.1生成的文档的外观和功能的文档。也就是说,页的背景为灰色,用图像做页眉,使用bullet列表而不是表格,具有单层目的目录结构,不包含继承 api,不使?*** tml框架,并且不支持内部类。该选项还自动将索引分割成每个字母一个文件。如果想要这种外观,则该选项比javadoc 1.1优越之处等于修正了一些错误。

        -sourcepath sourcepathlist
        当将包名传递到 javadoc命令中时,指定定位源文件(.java)的搜索路径。注意只有当用 javadoc命令指定包名时才能使用sourcepath选项 -- 它将不会查找传递到javadoc命令中的.java文件。如果省略-sourcepath,则javadoc使用类路径查找源文件。

        -classpath classpathlist 指定javadoc将在其中查找引用类的路径 -- 引用类是指带文档的类加上它们引用的任何类。javadoc将搜索指定路径的所有子目录。classpathlist可以包括多个路径,彼此用逗号分隔。

        -bootclasspath classpathlist 指定自举类所在路径。它们名义上是java平台类。这个bootclasspath是javadoc将用来查找源文件和类文件的搜索路径的一部分。在 classpathlist中用冒号(:)分隔目录。

        -extdirs dirlist 指定扩展类所在的目录。它们是任何使用java扩展机制的类。这个 extdirs是javadoc将用来查找源文件和在文件的搜索路径的一部分。在dirlist中用冒号(:)分隔目录。

        -verbose 在javadoc运行时提供更详细的信息。不使用verbose选项时,将显示加载源文件、生成文档(每个源文件一条信息)和排序的信息。verbose选项导致打印额外的信息,指定解析每个java源文件的毫秒数。

        -locale language_country_variant 指定javadoc在生成文档时使用的环境。

        -encoding name 指定源文件编码名,例如eucjis/sjis。如果未指定该选项,则使用平台缺省转换器。

        -j[flag] 将flag直接传递给运行javadoc的运行时系统java。注意在j和flag之间不能有空格。
      标准 doclet 提供的选项

        -d directory 指定javadoc保存生成的html件的目的目录。省略该选项将导致把文件保存到当前目录中。其中directory可以是绝对路径或相对当前工作目录的相对路径。

        -use 对每个带文档类和包包括一个“用法”页。该页描述使用给定类或包的任何 api 的包、类、方法、构造函数和域。对于给定类 c,使用类 c 的任何东西将包括 c 的子类、声明为 c 的域、返回 c 的方法以及具有 c 类型参数的方法和构造函数。

        -version 在生成文档中包括 @version 文本。缺省地将省略该文本。

        -author 在生成文档中包括 @author 文本。

        -splitindex 将索引文件按字母分割成多个文件,每个字母一个文件,再加上一个包含所有以非字母字符开头的索引项的文件。

        -windowtitle[title] 指定放入 html
       


      本文来自csdn博客,转载请标明出处:http://blog.csdn.net/smile_dyf/archive/2008/09/04/2882247.aspx



      xzc 2009-12-04 17:12
      ]]>
      ssh2的两种java实现[转]http://www.blogjava.net/xzclog/archive/2009/08/17/291531.htmlxzcxzcmon, 17 aug 2009 10:01:00 gmthttp://www.blogjava.net/xzclog/archive/2009/08/17/291531.htmlhttp://www.blogjava.net/xzclog/comments/291531.htmlhttp://www.blogjava.net/xzclog/archive/2009/08/17/291531.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/291531.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/291531.html

      转自:



    xzc 2009-08-17 18:01
    ]]>
    解决html导出excel时数字被改成科学计数法的问题[转]http://www.blogjava.net/xzclog/archive/2009/08/07/290246.htmlxzcxzcfri, 07 aug 2009 08:26:00 gmthttp://www.blogjava.net/xzclog/archive/2009/08/07/290246.htmlhttp://www.blogjava.net/xzclog/comments/290246.htmlhttp://www.blogjava.net/xzclog/archive/2009/08/07/290246.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/290246.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/290246.html【适用范围】ie,jsp

    【问题描述和定位】业务需要把一个html页面中的内容导出到excle文件里面,一个常用的方法是在需要导出的jsp页面中增加:

        response.setcontenttype("application/vnd.ms-excel; charset=gb2312");

        response.setheader("content-disposition","attachment;filename=excel文件名.xls");

        但是经常遇到会把身份证等数字比较长的数据改成科学计数法来显示。

    【凯发天生赢家一触即发官网的解决方案和步骤】

    在html页面里面加上如下css,然后在出现问题的字段应用这种style就可以了。



     
    示例:





    xzc 2009-08-07 16:26
    ]]>
    大数据量导出excel的方案[转]http://www.blogjava.net/xzclog/archive/2009/08/07/290240.htmlxzcxzcfri, 07 aug 2009 07:57:00 gmthttp://www.blogjava.net/xzclog/archive/2009/08/07/290240.htmlhttp://www.blogjava.net/xzclog/comments/290240.htmlhttp://www.blogjava.net/xzclog/archive/2009/08/07/290240.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/290240.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/290240.html
    试共同条件:
    数据总数为110011条,每条数据条数为19个字段。
    电脑配置为:p4 2.67ghz,1g内存。

    一、poi、jxl、fastexcel比较
    poi、jxl、fastexcel均为java第三方开源导出excel的开源项目。

    导出方案一:一次性全部导出到一个excel文件中。
    实际情况均报outofmemery错误,以下数据为报outofmemery数据时,数据到的最大数据数目,如表1所示:
    表1:报outofmemery错误时所能处理的数据量
    fastexecl poi jxl
    10000数据/sheet 37465 28996 42270
    5000数据/sheet 39096 31487 46270
    3000数据/sheet 39000 32493 47860
    小结:
    多分sheet能一定程度上减少内存的使用,但是均因为程序中创建的cell(即为excel中的一个单元格)无法释放,消耗大量内存,导致outofmemery错误;jxl表现最好,创建cell内存使用较少。

    导出方案二:先分多个excel文件将数据全部导出,然后对多个excel文件进行合并。
    首先,测试将全部数据导出所用的时间,如表2所示,数据均测试三次取平均。
    表2:导出全部数据所用时间

    fastexecl poi jxl
    10000数据/文件 68s 33s 30s
    5000数据/文件 68s 32s 33s
    3000数据/文件 59s 33s 39s
    小结:
    均成功导出excel文件,原因是导出一个excel文件,释放所占用的创建cell的内存。
    fastexecl表现最差,poi表现稳定,jxl随着数据的增大,速度一定程度上增快。

    然后,进行整合,由于将多excel合并成一个excel文件的功能只有poi所有,故使用poi测试,结果如表3所示。
    注:数据量大合并还会报outofmemery错误,故合并总数据量以5万为准。
    表3:合并5万数据所用时间
    时间
    10000数据/文件 11s
    5000数据/文件 11s
    3000数据/文件 11s
    小结:
    使用poi对文件进行合并速度较快,但有数据量的限制。


    总结:方案二比较可行,但是数据量有限制,为5万条。


    二、导出xml 的电子表格
    导出的格式类似为纯文本,能实现大数据量的存储,并能实现分sheet查看,且能添加简单的样式,符合项目要求。经实际测试excel2003和excel2007均能识别并正常打开查看。使用时间测试如表4所示,数据均测试3次取平均。
    表4:生成全部数据所用时间
    时间
    10000数据/sheet 28.0秒
    20000数据/sheet 30.1秒
    30000数据/sheet 28.1秒
    40000数据/sheet 26.5秒
    50000数据/shee 28.2秒
    55000数据/sheet 26.8秒
    59000数据/sheet 30.1秒
    59500数据/sheet 发生假死机现象
    60000数据/sheet 发生假死机现象

    但是导出的数据为xml不是纯正的excel文件,如使用excel文件的xls后缀保存,打开文件会弹出警告,但不影响阅读。
    且经实际测试,在access2007和access2003中可通过导入外部数据的方式,将导出的xml导入进access数据库。

    三、总结
    项目要求是大数据量导出excel文件,poi、jxl、fastexcel不能完全满足要求;使用xml 的电子表格导出实现了大数据量导出,但是格式为xml不是纯正的excel文件,为曲线救国。两种导出形式的比较,如表5所示。
    表5:合并5万数据所用时间
    poi、jxl、fastexcel xml 的电子表格
    导出数据格式 为纯execl文件 为xml文件
    导出数据量 较大
    能否分sheet
    能否添加样式
    能否添加图片 poi 能 不能
    导出数据能否导入access


    xzc 2009-08-07 15:57
    ]]>
    tomcat中文乱码问题的原理和解决方法http://www.blogjava.net/xzclog/archive/2008/11/22/242017.htmlxzcxzcsat, 22 nov 2008 12:39:00 gmthttp://www.blogjava.net/xzclog/archive/2008/11/22/242017.htmlhttp://www.blogjava.net/xzclog/comments/242017.htmlhttp://www.blogjava.net/xzclog/archive/2008/11/22/242017.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/242017.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/242017.html  一、java中文问题的由来

      java的内核和class文件是基于unicode的,这使java程序具有良好的跨平台性,但也带来了一些中文乱码问题的麻烦。原因主要有两方面,java和jsp文件本身编译时产生的乱码问题和java程序于其他媒介交互产生的乱码问题。

      首先java(包括jsp)源文件中很可能包含有中文,而java和jsp源文件的保存方式是基于字节流的,如果java和jsp编译成class文件过程中,使用的编码方式与源文件的编码不一致,就会出现乱码。基于这种乱码,建议在java文件中尽量不要写中文(注释部分不参与编译,写中文没关系),如果必须写的话,尽量手动带参数-ecoding gbk或-ecoding gb2312编译对于jsp,在文件头加上<%@ page contenttype="text/html;charset=gbk"%>或<%@ page contenttype="text/html;charset=gb2312"%>基本上就能解决这类乱码问题。

      本文要重点讨论的是第二类乱码,即java程序与其他存储媒介交互时产生的乱码。很多存储媒介,如数据库,文件,流等的存储方式都是基于字节流的,java程序与这些媒介交互时就会发生字符(char)与字节(byte)之间的转换,例如从页面提交表单中提交的数据在java程序里显示乱码等情况。

      如果在以上转换过程中使用的编码方式与字节原有的编码不一致,很可能就会出现乱码。

      二、解决方法

      对于流行的tomcat来说,有以下两种解决方法:

      1) 更改 d:\tomcat\conf\server.xml,指定浏览器的编码格式为“简体中文”:

      方法是找到 server.xml 中的

            enablelookups="false" redirectport="8443" acceptcount="100"
        connectiontimeout="20000" disableuploadtimeout="true" uriencoding='gbk' />

      标记,粗体字是我添加的。

      可以这样验证你的更改是否成功:在更改前,在你出现乱码的页面的ie浏览器,点击菜单“查看|编码”,会发现“西欧(iso)”处于选中状态。而更改后,点击菜单“查看|编码”,会发现“简体中文(gb2312)”处于选中状态。

      b)更该 java 程序,我的程序是这样的:

    public class threeparams extends httpservlet {
      public void doget(httpservletrequest request, httpservletresponse response)
       throws servletexception, ioexception {
          response.setcontenttype("text/html; charset=gbk");
          ...
      } 
    }

      粗体字是必需要有的,它的作用是让浏览器把unicode字符转换为gbk字符。这样页面的内容和浏览器的显示模式都设成了gbk,就不会乱码了。



    原创文章如转载,请注明:转载自 [ ]


    xzc 2008-11-22 20:39
    ]]>
    利用messagesource实现国际化[i18n]http://www.blogjava.net/xzclog/archive/2008/11/22/241974.htmlxzcxzcsat, 22 nov 2008 08:51:00 gmthttp://www.blogjava.net/xzclog/archive/2008/11/22/241974.htmlhttp://www.blogjava.net/xzclog/comments/241974.htmlhttp://www.blogjava.net/xzclog/archive/2008/11/22/241974.html#feedback3http://www.blogjava.net/xzclog/comments/commentrss/241974.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/241974.html

    3.8.1. 利用messagesource实现国际化

    applicationcontext接口扩展了messagesource接口,因而提供了消息处理的功能(i18n或者国际化)。与hierarchicalmessagesource一起使用,它还能够处理嵌套的消息,这些是spring提供的处理消息的基本接口。让我们快速浏览一下它所定义的方法:

    • string getmessage(string code, object[] args, string default, locale loc):用来从messagesource获取消息的基本方法。如果在指定的locale中没有找到消息,则使用默认的消息。args中的参数将使用标准类库中的messageformat来作消息中替换值。

    • string getmessage(string code, object[] args, locale loc):本质上和上一个方法相同,其区别在:没有指定默认值,如果没找到消息,会抛出一个nosuchmessageexception异常。

    • string getmessage(messagesourceresolvable resolvable, locale locale):上面方法中所使用的属性都封装到一个messagesourceresolvable实现中,而本方法可以指定messagesourceresolvable实现。

    当一个applicationcontext被加载时,它会自动在context中查找已定义为messagesource类型的bean。此bean的名称须为messagesource。如果找到,那么所有对上述方法的调用将被委托给该bean。否则applicationcontext会在其父类中查找是否含有同名的bean。如果有,就把它作为messagesource。如果它最终没有找到任何的消息源,一个空的staticmessagesource将会被实例化,使它能够接受上述方法的调用。

    spring目前提供了两个messagesource的实现:resourcebundlemessagesourcestaticmessagesource。它们都继承nestingmessagesource以便能够处理嵌套的消息。staticmessagesource很少被使用,但能以编程的方式向消息源添加消息。resourcebundlemessagesource会用得更多一些,为此提供了一下示例:

    
    messagesource"
    class="org.springframework.context.support.resourcebundlemessagesource">
    
    
    format
    exceptions
    windows
    
    
    
    

    这段配置假定在你的classpath中有三个资源文件(resource bundle),它们是formatexceptionswindows。通过resourcebundle,使用jdk中解析消息的标准方式,来处理任何解析消息的请求。出于示例的目的,假定上面的两个资源文件的内容为…

    # in 'format.properties'
    message=alligators rock!
    # in 'exceptions.properties'
    argument.required=the '{0}' argument is required.

    下面是测试代码。因为applicationcontext实现也都实现了messagesource接口,所以能被转型为messagesource接口

    public static void main(string[] args) {
    messagesource resources = new classpathxmlapplicationcontext("beans.xml");
    string message = resources.getmessage("message", null, "default", null);
    system.out.println(message);
    }

    上述程序的输出结果将会是...

    alligators rock!

    总而言之,我们在'beans.xml'的文件中(在classpath根目录下)定义了一个messagesource bean,通过它的basenames属性引用多个资源文件;而basenames属性值由list元素所指定的三个值传入,它们以文件的形式存在并被放置在classpath的根目录下(分别为format.propertiesexceptions.propertieswindows.properties)。

    再分析个例子,这次我们将着眼于传递参数给查找的消息,这些参数将被转换为字符串并插入到已查找到的消息中的占位符(译注:资源文件中花括号里的数字即为占位符)。

    
    
    messagesource" class="org.springframework.context.support.resourcebundlemessagesource">
    
    
    
    
    messagesource"/>
    
    
    public class example {
    private messagesource messages;
    public void setmessages(messagesource messages) {
    this.messages = messages;
    }
    public void execute() {
    string message = this.messages.getmessage("argument.required",
    new object [] {"userdao"}, "required", null);
    system.out.println(message);
    }
    }

    调用execute()方法的输出结果是...

    the 'userdao' argument is required.

    对于国际化(i18n),spring中不同的messageresource实现与jdk标准resourcebundle中的locale解析规则一样。比如在上面例子中定义的messagesource bean,如果你想解析british (en-gb) locale的消息,那么需要创建format_en_gb.propertiesexceptions_en_gb.propertieswindows_en_gb.properties三个资源文件。

    locale解析通常由应用程序根据运行环境来指定。出于示例的目的,我们对将要处理的(british)消息手工指定locale参数值。

    # in 'exceptions_en_gb.properties'
    argument.required=ebagum lad, the '{0}' argument is required, i say, required.
    public static void main(final string[] args) {
    messagesource resources = new classpathxmlapplicationcontext("beans.xml");
    string message = resources.getmessage("argument.required",
    new object [] {"userdao"}, "required", locale.uk);
    system.out.println(message);
    }

    上述程序运行时的输出结果是...

    ebagum lad, the 'userdao' argument is required, i say, required.

    messagesourceaware接口还能用于获取任何已定义的messagesource引用。任何实现了messagesourceaware接口的bean将在创建和配置的时候与messagesource一同被注入。



    xzc 2008-11-22 16:51
    ]]>
    spring i18n的better practice(相对于appfuse)http://www.blogjava.net/xzclog/archive/2008/11/22/241969.htmlxzcxzcsat, 22 nov 2008 08:40:00 gmthttp://www.blogjava.net/xzclog/archive/2008/11/22/241969.htmlhttp://www.blogjava.net/xzclog/comments/241969.htmlhttp://www.blogjava.net/xzclog/archive/2008/11/22/241969.html#feedback3http://www.blogjava.net/xzclog/comments/commentrss/241969.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/241969.html 照抄appfuse,折腾了很久后才发现appfuse式的sample总是只顾着演示自己的一亩三分地而忽略了很多其他东西。

       1.从基础开始,没有spring时,java的i18n是这样的:
       1.1 jsp环境
        首先写一个messages.zh_cn.properties文件,放在class-path也就是/web-inf/classes里     welcome=欢迎    然后用native2ascii.exe把它转为 welcome=\u6b22\u8fce
        在web.xml中定义messages文件     
          
                javax.servlet.jsp.jstl.fmt.localizationcontext
                messages
            

        最后在jsp里使用
    <%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
    <fmt:message key="welcome"/>
    如果有多个resource bundle文件, 就要在jsp里用定义了.

    1.2 pure java环境
        resourcebundle rb = resourcebundle.getbundle("messages");
        string welcome = rb.getstring("welcome");

    2.spring的增强及appfuse的做法
       spring增加了messagesource的概念,一是applicationcontext将充当一个单例的角色,不再需要每次使用i18时都初始化一次resourcebundle,二是可以代表多个resource bundle.

       在applicationcontext的定义文件中,增加如下节点: 
       
            
        
       则在pure java环境中。  context.getmessage("welcome", null, locale.china)

      而在jsp环境中,controller调用jstl viewresolver再调用jsp时,将继续发挥它的功效。

      因此,appfuse等sample都是在appfuse-servlet.xml 中定义一个

    3.better practice
    3.1 要不要定义javax.servlet.jsp.jstl.fmt.localizationcontext[定义]
          appfuse等sample,都是假定大家完全使用controller作访问入口,jsp甚至藏在了/web-inf/中。而很不幸,大家的项目可能还是有很多直接访问jsp的地方,而直接访问jsp时,节点是没有作用的。
         但如果定义了javax...localizationcontext, 又会让messagesource失效......


    3.2 messagesource定义在applicationcontext.xml还是appfuse-servlet.xml
         applicationcontext*.xml由contextloaderlistener载入而appfuse-servlet.xml靠dispatchservlet载入并拥有一个指向applcationcontex*.xml指针。所以,appfuse-servlet.xml能看到定义在applcationcontext里的东西,而反之做不到。
         明显, 把定义在applicationcontext.xml 能获得更好的可见性。
         但是appfuse没有在pure java代码中使用i18n,也就没有考虑这个问题。

    3.3 坚决不用鸡肋级 tag
          连appfuse也不用它,可见多么鸡肋。因为fmt在找不到资源时,最多显示???welcome???,而则会抛出异常,谁会喜欢这种定时炸弹阿。

    3.4 有趣的theme 解决"做成图片的文字"的国际化
           theme也就是把message的原理发挥了一下,让不同语言的美术字图片的路径也可以定义在theme_zh_cn.properties和theme_en_us.properties中。终于有一个不那么鸡肋的spring tag了。

    4.简单归纳

    1. jstl中仍然使用标准的及其定义?

    2.java中使用spring的实现单例

    3.用解决那些做成图片的文字的国际化问题

    4.spring 还有session,cookie locale resolver, 到时可以看一下.



    xzc 2008-11-22 16:40
    ]]>
    java语法总结 - 线程 http://www.blogjava.net/xzclog/archive/2008/11/21/241880.htmlxzcxzcfri, 21 nov 2008 10:01:00 gmthttp://www.blogjava.net/xzclog/archive/2008/11/21/241880.htmlhttp://www.blogjava.net/xzclog/comments/241880.htmlhttp://www.blogjava.net/xzclog/archive/2008/11/21/241880.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/241880.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/241880.html posted on 2007-10-25 23:53 阅读(3747)     所属分类:
    java语法总结 - 线程

    一提到线程好像是件很麻烦很复杂的事,事实上确实如此,涉及到线程的编程是很讲究技巧的。这就需要我们变换思维方式,了解线程机制的比较通用的技巧,写出高效的、不依赖于某个jvm实现的程序来。毕竟仅仅就java而言,各个虚拟机的实现是不同的。学习线程时,最令我印象深刻的就是那种不确定性、没有保障性,各个线程的运行完全是以不可预料的方式和速度推进,有的一个程序运行了n次,其结果差异性很大。


    1、什么是线程?线程是彼此互相独立的、能独立运行的子任务,并且每个线程都有自己的调用栈。所谓的多任务是通过周期性地将cpu时间片切换到不同的子任务,虽然从微观上看来,单核的cpu上同时只运行一个子任务,但是从宏观来看,每个子任务似乎是同时连续运行的。(但是java的线程不是按时间片分配的,在本文的最后引用了一段网友翻译的java原著中对线程的理解。)

    2、在java中,线程指两个不同的内容:一是java.lang.thread类的一个对象;另外也可以指线程的执行。线程对象和其他的对象一样,在堆上创建、运行、死亡。但不同之处是线程的执行是一个轻量级的进程,有它自己的调用栈。
    可以这样想,每个调用栈都对应一个线程,每个线程又对应一个调用栈。
    我们运行java程序时有一个入口函数main()函数,它对应的线程被称为主线程。一个新线程一旦被创建,就产生一个新调用栈,从原主线程中脱离,也就是与主线程并发执行。


    4、当提到线程时,很少是有保障的。我们必须了解到什么是有保障的操作,什么是无保障的操作,以便设计的程序在各种jvm上都能很好地工作。比如,在某些jvm实现中,把java线程映射为本地操作系统的线程。这是java核心的一部分。

    5、线程的创建。
    创建线程有两种方式:
    a、继承java.lang.thread类。
        class threadtest extends thread{
            public void run() {
                system.out.println ("someting run here!");
            }
            public void run(string s){
                system.out.println ("string in run is " s);
            }
            public static void main (string[] args) {
                threadtest tt = new threadtest();
                tt.start();
                tt.run("it won't auto run!");
            }
        }

    输出的结果比较有趣:
    string in run is it won't auto run!
    someting run here!
    注意输出的顺序:好像与我们想象的顺序相反了!为什么呢?
    一旦调用start()方法,必须给jvm点时间,让它配置进程。而在它配置完成之前,重载的run(string s)方法被调用了,结果反而先输出了“string in run is it won't auto run!”,这时tt线程完成了配置,输出了“someting run here!”。
    这个结论是比较容易验证的:
    修改上面的程序,在tt.start();后面加上语句for (int i = 0; i<10000; i ); 这样主线程开始执行运算量比较大的for循环了,只有执行完for循环才能运行后面的tt.run("it won't auto run!");语句。此时,tt线程和主线程并行执行了,已经有足够的时间完成线程的配置!因此先到一步!修改后的程序运行结果如下:
    someting run here!
    string in run is it won't auto run!
    注意:这种输出结果的顺序是没有保障的!不要依赖这种结论!

    没有参数的run()方法是自动被调用的,而带参数的run()是被重载的,必须显式调用。
    这种方式的限制是:这种方式很简单,但不是个好的方案。如果继承了thread类,那么就不能继承其他的类了,java是单继承结构的,应该把继承的机会留给别的类。除非因为你有线程特有的更多的操作。
    thread类中有许多管理线程的方法,包括创建、启动和暂停它们。所有的操作都是从run()方法开始,并且在run()方法内编写需要在独立线程内执行的代码。run()方法可以调用其他方法,但是执行的线程总是通过调用run()。

    b、实现java.lang.runnable接口。
        class threadtest implements runnable {
            public void run() {
                system.out.println ("someting run here");
            }
            public static void main (string[] args) {
                threadtest tt = new threadtest();
            thread t1 = new thread(tt);
            thread t2 = new thread(tt);
            t1.start();
            t2.start();
                //new thread(tt).start();
            }
        }

    比第一种方法复杂一点,为了使代码被独立的线程运行,还需要一个thread对象。这样就把线程相关的代码和线程要执行的代码分离开来。

    另一种方式是:参数形式的匿名内部类创建方式,也是比较常见的。
        class threadtest{
            public static void main (string[] args) {
                thread t = new thread(new runnable(){
                    public void run(){
                        system.out.println ("anonymous thread");
                    }
                });    
                
                t.start();
            }
        }
    如果你对此方式的声明不感冒,请参看本人总结的内部类。

    第一种方式使用无参构造函数创建线程,则当线程开始工作时,它将调用自己的run()方法。
    第二种方式使用带参数的构造函数创建线程,因为你要告诉这个新线程使用你的run()方法,而不是它自己的。
    如上例,可以把一个目标赋给多个线程,这意味着几个执行线程将运行完全相同的作业。

    6、什么时候线程是活的?
    在调用start()方法开始执行线程之前,线程的状态还不是活的。测试程序如下:
        class threadtest implements runnable {
            public void run() {
                system.out.println ("someting run here");
            }
            public static void main (string[] args) {
                threadtest tt = new threadtest();
                thread t1 = new thread(tt);
                system.out.println (t1.isalive());
                t1.start();
                system.out.println (t1.isalive());
            }
        }

    结果输出:
    false
    true
    isalive方法是确定一个线程是否已经启动,而且还没完成run()方法内代码的最好方法。

    7、启动新线程。
    线程的启动要调用start()方法,只有这样才能创建新的调用栈。而直接调用run()方法的话,就不会创建新的调用栈,也就不会创建新的线程,run()方法就与普通的方法没什么两样了!

    8、给线程起个有意义的名字。
    没有该线程命名的话,线程会有一个默认的名字,格式是:“thread-”加上线程的序号,如:thread-0
    这看起来可读性不好,不能从名字分辨出该线程具有什么功能。下面是给线程命名的方式。
    第一种:用setname()函数
    第二种:选用带线程命名的构造器
        class threadtest implements runnable{
            public void run(){
                system.out.println (thread.currentthread().getname());
            }
            public static void main (string[] args) {
            threadtest tt = new threadtest();     
            //thread t = new thread (tt,"eat apple");
            thread t = new thread (tt);
            t.setname("eat apple");
            t.start();
            }
        }

    9、“没有保障”的多线程的运行。下面的代码可能令人印象深刻。
        class threadtest implements runnable{
            public void run(){
                system.out.println (thread.currentthread().getname());
            }
            public static void main (string[] args) {
                threadtest tt = new threadtest();
                thread[] ts =new thread[10];
            
                for (int i =0; i < ts.length; i )
                    ts[i] = new thread(tt);
                    
                for (thread t : ts)
                    t.start();
            }
        }
    在我的电脑上运行的结果是:
    thread-0
    thread-1
    thread-3
    thread-5
    thread-2
    thread-7
    thread-4
    thread-9
    thread-6
    thread-8
    而且每次运行的结果都是不同的!继续引用前面的话,一旦涉及到线程,其运行多半是没有保障。这个保障是指线程的运行完全是由调度程序控制的,我们没法控制它的执行顺序,持续时间也没有保障,有着不可预料的结果。


    10、线程的状态。
    a、新状态。
    实例化thread对象,但没有调用start()方法时的状态。
    threadtest tt = new threadtest();     
    或者thread t = new thread (tt);
    此时虽然创建了thread对象,如前所述,但是它们不是活的,不能通过isalive()测试。

    b、就绪状态。
    线程有资格运行,但调度程序还没有把它选为运行线程所处的状态。也就是具备了运行的条件,一旦被选中马上就能运行。
    也是调用start()方法后但没运行的状态。此时虽然没在运行,但是被认为是活的,能通过isalive()测试。而且在线程运行之后、或者被阻塞、等待或者睡眠状态回来之后,线程首先进入就绪状态。

    c、运行状态。
    从就绪状态池(注意不是队列,是池)中选择一个为当前执行进程时,该线程所处的状态。

    d、等待、阻塞、睡眠状态。
    这三种状态有一个共同点:线程依然是活的,但是缺少运行的条件,一旦具备了条就就可以转为就绪状态(不能直接转为运行状态)。另外,suspend()和stop()方法已经被废弃了,比较危险,不要再用了。

    e、死亡状态。
    一个线程的run()方法运行结束,那么该线程完成其历史使命,它的栈结构将解散,也就是死亡了。但是它仍然是一个thread对象,我们仍可以引用它,就像其他对象一样!它也不会被垃圾回收器回收了,因为对该对象的引用仍然存在。
    如此说来,即使run()方法运行结束线程也没有死啊!事实是,一旦线程死去,它就永远不能重新启动了,也就是说,不能再用start()方法让它运行起来!如果强来的话会抛出illegalthreadstateexception异常。如:
    t.start();
    t.start();
    放弃吧,人工呼吸或者心脏起搏器都无济于事……线程也属于一次性用品。

    11、阻止线程运行。
    a、睡眠。sleep()方法
    让线程睡眠的理由很多,比如:认为该线程运行得太快,需要减缓一下,以便和其他线程协调;查询当时的股票价格,每睡5分钟查询一次,可以节省带宽,而且即时性要求也不那么高。
    用thread的静态方法可以实现thread.sleep(5*60*1000); 睡上5分钟吧。sleep的参数是毫秒。但是要注意sleep()方法会抛出检查异常interruptedexception,对于检查异常,我们要么声明,要么使用处理程序。
        try {
            thread.sleep(20000);
        }
        catch (interruptedexception ie) {
            ie.printstacktrace();
        }
    既然有了sleep()方法,我们是不是可以控制线程的执行顺序了!每个线程执行完毕都睡上一觉?这样就能控制线程的运行顺序了,下面是书上的一个例子:
        class threadtest implements runnable{
            public void run(){
                for (int i = 1; i<4; i ){
                    system.out.println (thread.currentthread().getname());
                    try {
                        thread.sleep(1000);
                    } catch (interruptedexception ie) { }
                }
            }
            public static void main (string[] args) {
                threadtest tt = new threadtest();
                thread t0 = new thread(tt,"thread 0");
                thread t1 = new thread(tt,"thread 1");
                thread t2 = new thread(tt,"thread 2");
                t0.start();
                t1.start();
                t2.start();            
            }
        }

    并且给出了结果:
    thread 0
    thread 1
    thread 2
    thread 0
    thread 1
    thread 2
    thread 0
    thread 1
    thread 2
    也就是thread 0  thread 1 thread 2 按照这个顺序交替出现,作者指出虽然结果和我们预料的似乎相同,但是这个结果是不可靠的。果然被我的双核电脑验证了:
    thread 0
    thread 1
    thread 2
    thread 2
    thread 0
    thread 1
    thread 1
    thread 0
    thread 2
    看来线程真的很不可靠啊。但是尽管如此,sleep()方法仍然是保证所有线程都有运行机会的最好方法。至少它保证了一个线程进入运行之后不会一直到运行完位置。

    时间的精确性。再强调一下,线程醒来之后不会进入运行状态,而是进入就绪状态。因此sleep()中指定的时间不是线程不运行的精确时间!不能依赖sleep()方法提供十分精确的定时。我们可以看到很多应用程序用sleep()作为定时器,而且没什么不好的,确实如此,但是我们一定要知道sleep()不能保证线程醒来就能马上进入运行状态,是不精确的。

    sleep()方法是一个静态的方法,它所指的是当前正在执行的线程休眠一个毫秒数。看到某些书上的thread.currentthread().sleep(1000); ,其实是不必要的。thread.sleep(1000);就可以了。类似于getname()方法不是静态方法,它必须针对具体某个线程对象,这时用取得当前线程的方法thread.currentthread().getname();

    b、线程优先级和让步。
    线程的优先级。在大多数jvm实现中调度程序使用基于线程优先级的抢先调度机制。如果一个线程进入可运行状态,并且它比池中的任何其他线程和当前运行的进程的具有更高的优先级,则优先级较低的线程进入可运行状态,最高优先级的线程被选择去执行。

    于是就有了这样的结论:当前运行线程的优先级通常不会比池中任何线程的优先级低。但是并不是所有的jvm的调度都这样,因此一定不能依赖于线程优先级来保证程序的正确操作,这仍然是没有保障的,要把线程优先级用作一种提高程序效率的方法,并且这种方法也不能依赖优先级的操作。

    另外一个没有保障的操作是:当前运行的线程与池中的线程,或者池中的线程具有相同的优先级时,jvm的调度实现会选择它喜欢的线程。也许是选择一个去运行,直至其完成;或者用分配时间片的方式,为每个线程提供均等的机会。

    优先级用正整数设置,通常为1-10,jvm从不会改变一个线程的优先级。默认情况下,优先级是5。thread类具有三个定义线程优先级范围的静态最终常量:thread.min_priority (为1) thread.norm_priority (为5) thread.max_priority (为10)

    静态thread.yield()方法。
    它的作用是让当前运行的线程回到可运行状态,以便让具有同等优先级的其他线程运行。用yield()方法的目的是让同等优先级的线程能适当地轮转。但是,并不能保证达到此效果!因为,即使当前变成可运行状态,可是还有可能再次被jvm选中!也就是连任。

    非静态join()方法。
    让一个线程加入到另一个线程的尾部。让b线程加入a线程,意味着在a线程运行完成之前,b线程不会进入可运行状态。
        thread t = new thread();
        t.start();
        t.join;
    这段代码的意思是取得当前的线程,把它加入到t线程的尾部,等t线程运行完毕之后,原线程继续运行。书中的例子在我的电脑里效果很糟糕,看不出什么效果来。也许是cpu太快了,而且是双核的;也许是jdk1.6的原因?

    12、没总结完。线程这部分很重要,内容也很多,看太快容易消化不良,偶要慢慢地消化掉……



    附: java原著中对线程的解释。

    e文原文:

    thread scheduling

    in java technology,threads are usually preemptive,but not necessarily time-sliced(the process of giving each thread an equal amount of cpu time).it is common mistake to believe that "preemptive" is a fancy word for "does time-slicing".

    for the runtime on a solaris operating environment platform,java technology does not preempt threads of the same priority.however,the runtime on microsoft windows platforms uses time-slicing,so it preempts threads of the same priority and even threads of higher priority.preemption is not guaranteed;however,most jvm implementations result in behavior that appears to be strictly preemptive.across jvm implementations,there is no absolute guarantee of preemption or time-slicing.the only guarantees lie in the coder’s use of wait and sleep.

    the model of a preemptive scheduler is that many threads might be runnable,but only one thread is actually running.this thread continues to run until it ceases to be runnable or another thread of higher priority becomes runnable.in the latter case,the lower priority thread is preempted by the thread of higher priority,which gets a chance to run instead.

    a thread might cease to runnable (that is,because blocked) for a variety of reasons.the thread’s code can execute a thread.sleep() call,deliberately asking the thread to pause for a fixed period of time.the thread might have to wait to access a resource and cannot continue until that resource become available.

    all thread that are runnable are kept in pools according to priority.when a blocked thread becomes runnable,it is placed back into the appropriate runnable pool.threads from the highest priority nonempty pool are given cpu time.

    the last sentence is worded loosed because:
    (1) in most jvm implementations,priorities seem to work in a preemptive manner,although there is no guarantee that priorities have any meaning at all;
    (2) microsoft window’s values affect thread behavior so that it is possible that a java priority 4 thread might be running,in spite of the fact that a runnable java priority 5 thread is waiting for the cpu.
    in reality,many jvms implement pool as queues,but this is not guaranteed hehavior.


    热心网友翻译的版本:

    在java技术中,线程通常是抢占式的而不需要时间片分配进程(分配给每个线程相等的cpu时间的进程)。一个经常犯的错误是认为“抢占”就是“分配时间片”。
    在solaris平台上的运行环境中,相同优先级的线程不能相互抢占对方的cpu时间。但是,在使用时间片的windows平台运行环境中,可以抢占相同甚至更高优先级的线程的cpu时间。抢占并不是绝对的,可是大多数的jvm的实现结果在行为上表现出了严格的抢占。纵观jvm的实现,并没有绝对的抢占或是时间片,而是依赖于编码者对wait和sleep这两个方法的使用。
    抢占式调度模型就是许多线程属于可以运行状态(等待状态),但实际上只有一个线程在运行。该线程一直运行到它终止进入可运行状态(等待状态)或是另一个具有更高优先级的线程变成可运行状态。在后一种情况下,底优先级的线程被高优先级的线程抢占,高优先级的线程获得运行的机会。
    线程可以因为各种各样的原因终止并进入可运行状态(因为堵塞)。例如,线程的代码可以在适当时候执行thread.sleep()方法,故意让线程中止;线程可能为了访问资源而不得不等待直到该资源可用为止。
    所有可运行的线程根据优先级保持在不同的池中。一旦被堵塞的线程进入可运行状态,它将会被放回适当的可运行池中。非空最高优先级的池中的线程将获得cpu时间。
    最后一个句子是不精确的,因为:
    (1)在大多数的jvm实现中,虽然不能保证说优先级有任何意义,但优先级看起来象是用抢占方式工作。
    (2)微软windows的评价影响线程的行为,以至尽管一个处于可运行状态的优先级为5的java线程正在等待cpu时间,但是一个优先级为4的java线程却可能正在运行。
    实际上,许多jvm用队列来实现池,但没有保证行为。


    xzc 2008-11-21 18:01
    ]]>
    java的多进程运行模式分析http://www.blogjava.net/xzclog/archive/2008/11/17/241023.htmlxzcxzcmon, 17 nov 2008 11:56:00 gmthttp://www.blogjava.net/xzclog/archive/2008/11/17/241023.htmlhttp://www.blogjava.net/xzclog/comments/241023.htmlhttp://www.blogjava.net/xzclog/archive/2008/11/17/241023.html#feedback3http://www.blogjava.net/xzclog/comments/commentrss/241023.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/241023.html
    • 摘要:本文通过java代码启动多个java子进程。必如在java中通过runtime中的exec方法执行java classname。如果执行成功,这个方法返回一个process对象,如果执行失败,将抛出一个ioexception错误。
    • 标签:      

    一般我们在java中运行其它类中的方法时,无论是静态调用,还是动态调用,都是在当前的进程中执行的,也就是说,只有一个java虚拟机实例在运行。而有的时候,我们需要通过java代码启动多个java子进程。这样做虽然占用了一些系统资源,但会使程序更加稳定,因为新启动的程序是在不同的虚拟机进程中运行的,如果有一个进程发生异常,并不影响其它的子进程。

    在java中我们可以使用两种方法来实现这种要求。最简单的方法就是通过runtime中的exec方法执行java classname。如果执行成功,这个方法返回一个process对象,如果执行失败,将抛出一个ioexception错误。下面让我们来看一个简单的例子。

                

    // test1.java文件
    import java.io.*;
    public class test
    {
     public static void main(string[] args)
     {
    fileoutputstream fout = new fileoutputstream("c:\\test1.txt");
    fout.close();
    system.out.println("被调用成功!");
     }
    }

    // test_exec.java
    public class test_exec
    {
     public static void main(string[] args)
     {
    runtime run = runtime.getruntime();
    process p = run.exec("java test1");
     }
    }

    通过java test_exec运行程序后,发现在c盘多了个test1.txt文件,但在控制台中并未出现“被调用成功!”的输出信息。因此可以断定,test已经被执行成功,但因为某种原因,test的输出信息未在test_exec的控制台中输出。这个原因也很简单,因为使用exec建立的是test_exec的子进程,这个子进程并没有自己的控制台,因此,它并不会输出任何信息。

    如果要输出子进程的输出信息,可以通过process中的getinputstream得到子进程的输出流(在子进程中输出,在父进程中就是输入),然后将子进程中的输出流从父进程的控制台输出。具体的实现代码如下如示:

                

    // test_exec_out.java
    import java.io.*;
    public class test_exec_out
    {
     public static void main(string[] args)
     {
    runtime run = runtime.getruntime();
    process p = run.exec("java test1");
    bufferedinputstream in = new bufferedinputstream(p.getinputstream());
    bufferedreader br = new bufferedreader(new inputstreamreader(in));
    string s;
    while ((s = br.readline()) != null)
     system.out.println(s);
     }
    }

    从上面的代码可以看出,在test_exec_out.java中通过按行读取子进程的输出信息,然后在test_exec_out中按每行进行输出。上面讨论的是如何得到子进程的输出信息。那么,除了输出信息,还有输入信息。既然子进程没有自己的控制台,那么输入信息也得由父进程提供。我们可以通过process的getoutputstream方法来为子进程提供输入信息(即由父进程向子进程输入信息,而不是由控制台输入信息)。我们可以看看如下的代码:

                

    // test2.java文件
    import java.io.*;
    public class test
    {
     public static void main(string[] args)
     {
    bufferedreader br = new bufferedreader(new inputstreamreader(system.in));
    system.out.println("由父进程输入的信息:" br.readline());
     }
    }

    // test_exec_in.java
    import java.io.*;
    public class test_exec_in
    {
     public static void main(string[] args)
     {
    runtime run = runtime.getruntime();
    process p = run.exec("java test2");
    bufferedwriter bw = new bufferedwriter(new outputstreamwriter(p.getoutputstream()));
    bw.write("向子进程输出信息");
    bw.flush();
    bw.close(); // 必须得关闭流,否则无法向子进程中输入信息
    // system.in.read();
     }
    }

    从以上代码可以看出,test1得到由test_exec_in发过来的信息,并将其输出。当你不加bw.flash()和bw.close()时,信息将无法到达子进程,也就是说子进程进入阻塞状态,但由于父进程已经退出了,因此,子进程也跟着退出了。如果要证明这一点,可以在最后加上system.in.read(),然后通过任务管理器(在windows下)查看java进程,你会发现如果加上bw.flush()和bw.close(),只有一个java进程存在,如果去掉它们,就有两个java进程存在。这是因为,如果将信息传给test2,在得到信息后,test2就退出了。

    在这里有一点需要说明一下,exec的执行是异步的,并不会因为执行的某个程序阻塞而停止执行下面的代码。因此,可以在运行test2后,仍可以执行下面的代码。

    exec方法经过了多次的重载。上面使用的只是它的一种重载。它还可以将命令和参数分开,如exec(“java.test2”)可以写成exec(“java”, “test2”)。exec还可以通过指定的环境变量运行不同配置的java虚拟机。

    除了使用runtime的exec方法建立子进程外,还可以通过processbuilder建立子进程。processbuilder的使用方法如下:

                

    // test_exec_out.java
    import java.io.*;
    public class test_exec_out
    {
     public static void main(string[] args)
     {
    processbuilder pb = new processbuilder("java", "test1");
    process p = pb.start();
    … …
     }
    }

    在建立子进程上,processbuilder和runtime类似,不同的processbuilder使用start()方法启动子进程,而runtime使用exec方法启动子进程。得到process后,它们的操作就完全一样的。

    processbuilder和runtime一样,也可设置可执行文件的环境信息、工作目录等。下面的例子描述了如何使用processbuilder设置这些信息。

                

    processbuilder pb = new processbuilder("command", "arg2", "arg2", ''');
    // 设置环境变量
    map env = pb.environment();
    env.put("key1", "value1");
    env.remove("key2");
    env.put("key2", env.get("key1") "_test");
    pb.directory("..\abcd"); // 设置工作目录
    process p = pb.start(); // 建立子进程



    xzc 2008-11-17 19:56
    ]]>
    java相对路径/绝对路径总结(转)http://www.blogjava.net/xzclog/archive/2008/11/11/239844.htmlxzcxzctue, 11 nov 2008 03:54:00 gmthttp://www.blogjava.net/xzclog/archive/2008/11/11/239844.htmlhttp://www.blogjava.net/xzclog/comments/239844.htmlhttp://www.blogjava.net/xzclog/archive/2008/11/11/239844.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/239844.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/239844.html关键字: 相对路径 绝对路径
    1.基本概念的理解

    绝对路径:绝对路径就是你的凯发k8网页登录主页上的文件或目录在硬盘上真正的路径,(url和物理路径)例如:
    c:xyz est.txt 代表了test.txt文件的绝对路径。http://www.sun.com/index.htm也代表了一个url绝对路径。

    相对路径:相对与某个基准目录的路径。包含web的相对路径(html中的相对目录),例如:在
    servlet中,"/"代表web应用的跟目录。和物理路径的相对表示。例如:"./" 代表当前目录,"../"代表上级目录。这种类似的表示,也是属于相对路径。
    另外关于uri,url,urn等内容,请参考rfc相关文档标准。

    rfc 2396: uniform resource identifiers (uri): generic syntax,
    (http://www.ietf.org/rfc/rfc2396.txt)


    2.关于jsp/servlet中的相对路径和绝对路径。

    2.1服务器端的地址

    服务器端的相对地址指的是相对于你的web应用的地址,这个地址是在服务器端解析的(不同于html和javascript中的相对地址,他们是由客户端浏览器解析的)也就是说这时候在jsp和servlet中的相对地址应该是相对于你的web应用,即相对于http: //192.168.0.1/webapp/的。

    其用到的地方有:
    forward:servlet中的request.getrequestdispatcher(address);这个address是在服务器端解析的,所以,你要forward到a.jsp应该这么写:request.getrequestdispatcher(“/user/a.jsp”)这个/ 相对于当前的web应用webapp,其绝对地址就是:http://192.168.0.1/webapp/user/a.jsp。 sendredirect:在jsp中<%response.sendredirect("/rtccp/user/a.jsp");%>

    2.22、客户端的地址

    所有的html页面中的相对地址都是相对于服务器根目录(http://192.168.0.1/)的,而不是(跟目录下的该web应用的目录) http://192.168.0.1/webapp/的。 html中的form表单的action属性的地址应该是相对于服务器根目录(http://192.168.0.1/)的,所以,如果提交到a.jsp 为:action="/webapp/user/a.jsp"或action="<%=request.getcontextpath()% >"/user/a.jsp;
    提交到servlet为actiom="/webapp/handleservlet" javascript也是在客户端解析的,所以其相对路径和form表单一样。


    因此,一般情况下,在jsp/html页面等引用的css,javascript.action等属性前面最好都加上
    <%=request.getcontextpath()%>,以确保所引用的文件都属于web应用中的目录。另外,应该尽量避免使用类似".","./","../../"等类似的相对该文件位置的相对路径,这样当文件移动时,很容易出问题。


    3. jsp/servlet中获得当前应用的相对路径和绝对路径

    3.1 jsp中获得当前应用的相对路径和绝对路径
    根目录所对应的绝对路径:request.getrequesturi()
    文件的绝对路径  :application.getrealpath(request.getrequesturi());
    当前web应用的绝对路径 :application.getrealpath("/");
    取得请求文件的上层目录:new file(application.getrealpath(request.getrequesturi())).getparent()

    3.2 servlet中获得当前应用的相对路径和绝对路径
    根目录所对应的绝对路径:request.getservletpath();
    文件的绝对路径 :request.getsession().getservletcontext().getrealpath
    (request.getrequesturi())
    当前web应用的绝对路径 :servletconfig.getservletcontext().getrealpath("/");
    (servletcontext对象获得几种方式:
    javax.servlet.http.httpsession.getservletcontext()
    javax.servlet.jsp.pagecontext.getservletcontext()
    javax.servlet.servletconfig.getservletcontext()
    )

    4.java 的class中获得相对路径,绝对路径的方法

    4.1单独的java类中获得绝对路径
    根据java.io.file的doc文挡,可知:
    默认情况下new file("/")代表的目录为:system.getproperty("user.dir")。
    一下程序获得执行类的当前路径

     
    1. package org.cheng.file;  
    2.   
    3. import java.io.file;  
    4.   
    5. public class filetest {  
    6.     public static void main(string[] args) throws exception {  
    7.         system.out.println(thread.currentthread().getcontextclassloader().getresource(""));  
    8.   
    9.         system.out.println(filetest.class.getclassloader().getresource(""));  
    10.   
    11.         system.out.println(classloader.getsystemresource(""));  
    12.         system.out.println(filetest.class.getresource(""));  
    13.         system.out.println(filetest.class.getresource("/"));
    14.         //class文件所在路径
    15.         system.out.println(new file("/").getabsolutepath());  
    16.         system.out.println(system.getproperty("user.dir"));  
    17.     }  


    4.2服务器中的java类获得当前路径(来自网络)

    (1).weblogic

    webapplication的系统文件根目录是你的weblogic安装所在根目录。
    例如:如果你的weblogic安装在c:eaweblogic700.....
    那么,你的文件根路径就是c:.
    所以,有两种方式能够让你访问你的服务器端的文件:
    a.使用绝对路径:
    比如将你的参数文件放在c:yourconfigyourconf.properties,
    直接使用 new fileinputstream("yourconfig/yourconf.properties");
    b.使用相对路径:
    相对路径的根目录就是你的webapplication的根路径,即web-inf的上一级目录,将你的参数文件放

    在yourwebappyourconfigyourconf.properties,
    这样使用:
    new fileinputstream("./yourconfig/yourconf.properties");
    这两种方式均可,自己选择。

    (2).tomcat

    在类中输出system.getproperty("user.dir");显示的是%tomcat_home%/bin

    (3).resin

    不是你的jsp放的相对路径,是jsp引擎执行这个jsp编译成servlet
    的路径为根.比如用新建文件法测试file f = new file("a.htm");
    这个a.htm在resin的安装目录下

    (4).如何读相对路径哪?

    在java文件中getresource或getresourceasstream均可

    例:getclass().getresourceasstream(filepath);//filepath可以是"/filename",这里的/代表web

    发布根路径下web-inf/classes

    默认使用该方法的路径是:web-inf/classes。已经在tomcat中测试。

    5.读取文件时的相对路径,避免硬编码和绝对路径的使用。(来自网络)
    5.1 采用spring的di机制获得文件,避免硬编码。
    参考下面的连接内容:

    5.2 配置文件的读取
    参考下面的连接内容:


    5.3 通过虚拟路径或相对路径读取一个xml文件,避免硬编码

    参考下面的连接内容:


    6.java中文件的常用操作(复制,移动,删除,创建等)(来自网络)
    常用 java file 操作类


    java文件操作大全(jsp中)


    java文件操作详解(java中文网)


    java 如何创建删除修改复制目录及文件


    总结:
    通过上面内容的使用,可以解决在web应用服务器端,移动文件,查找文件,复制
    删除文件等操作,同时对服务器的相对地址,绝对地址概念更加清晰。
    建议参考uri,的rfc标准文挡。同时对java.io.file. java.net.uri.等内容了解透彻
    对其他方面的理解可以更加深入和透彻。


    xzc 2008-11-11 11:54
    ]]>
    jspsmartupload下载用法http://www.blogjava.net/xzclog/archive/2008/11/03/238399.htmlxzcxzcmon, 03 nov 2008 09:58:00 gmthttp://www.blogjava.net/xzclog/archive/2008/11/03/238399.htmlhttp://www.blogjava.net/xzclog/comments/238399.htmlhttp://www.blogjava.net/xzclog/archive/2008/11/03/238399.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/238399.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/238399.html
    <%@ page import="java.io.*" %>
    <%
    // 得到文件名字和路径
    string filename = request.getparameter("filename");
    string filepath = request.getsession().getservletcontext().getgetrealpath("/download/excel/");
    //string filepath = request.getrealpath("/download/excel/");
    //读到流中
    inputstream inputstream = new fileinputstream(filepath "/" filename);
    //设置输出的格式
    response.reset();
    response.setcontenttype("bin");
    response.addheader("content-disposition","attachment;filename=\"" filename "\"");
    //循环取出流中的数据
    byte[] bytes = new byte[1000];
    int len = inputstream.read(bytes);
    while (len > 0){
     response.getoutputstream().write(bytes,0,len);
     len = inputstream.read(bytes);
    }
    inputstream.close();
    %>

    xzc 2008-11-03 17:58
    ]]>
    content-disposition的使用和注意事项http://www.blogjava.net/xzclog/archive/2008/10/30/237627.htmlxzcxzcthu, 30 oct 2008 08:07:00 gmthttp://www.blogjava.net/xzclog/archive/2008/10/30/237627.htmlhttp://www.blogjava.net/xzclog/comments/237627.htmlhttp://www.blogjava.net/xzclog/archive/2008/10/30/237627.html#feedback0http://www.blogjava.net/xzclog/comments/commentrss/237627.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/237627.html [转自:]

        最近不少web技术圈内的朋友在讨论协议方面的事情,有的说web开发者应该熟悉web相关的协议,有的则说不用很了解。个人认为这要分层次来看待这个问题,对于一个新手或者刚入门的web开发人员而言,研究协议方面的东西可能会使得web开发失去趣味性、抹煞学习积极性,这类人应该更多的了解基本的web技术使用。而对于在该行业工作多年的老鸟来说,协议相关的内容、标准相关内容应该尽量多些的了解,因为只有这样才能使得经手的web系统更加优秀(安全、漂亮、快速、兼容性好、体验好……)。本文我们来说一下mime 协议的一个扩展content-disposition

        我们在开发web系统时有时会有以下需求:

    • 希望某类或者某已知mime 类型的文件(比如:*.gif;*.txt;*.htm)能够在访问时弹出“文件下载”对话框
    • 希望以原始文件名(上传时的文件名,例如:山东省政府1024号文件.doc)提供下载,但服务器上保存的地址却是其他文件名(如:12519810948091234_asdf.doc)
    • 希望某文件直接在浏览器上显示而不是弹出文件下载对话框
    • ……………………

        要解决上述需求就可以使用content-disposition来解决。第一个需求的解决办法是

    response.addheader "content-disposition","attachment; filename=fname.ext"
     
    将上述需求进行归我给出如下例子代码:
    public static void todownload(string serverfilpath,string filename)
    {
    filestream filestream = new filestream(serverfilpath, filemode.open);
    long filesize = filestream.length;
    httpcontext.current.response.contenttype = "application/octet-stream";
    httpcontext.current.response.addheader("content-disposition", "attachment; filename=\""  utf_filename(filename)  "\";");
    ////attachment --- 作为附件下载
    ////inline --- 在线打开
    httpcontext.current.response.addheader("content-length", filesize.tostring());
    byte[] filebuffer = new byte[filesize];
    filestream.read(filebuffer, 0, (int)filesize);
    httpcontext.current.response.binarywrite(filebuffer);
    filestream.close();
    httpcontext.current.response.end();
    }
    public static void toopen(string serverfilpath, string filename)
    {
    filestream filestream = new filestream(serverfilpath, filemode.open);
    long filesize = filestream.length;
    httpcontext.current.response.contenttype = "application/octet-stream";
    httpcontext.current.response.addheader("content-disposition", "inline; filename=\""  utf_filename(filename)  "\";");
    httpcontext.current.response.addheader("content-length", filesize.tostring());
    byte[] filebuffer = new byte[filesize];
    filestream.read(filebuffer, 0, (int)filesize);
    httpcontext.current.response.binarywrite(filebuffer);
    filestream.close();
    httpcontext.current.response.end();
    }
    private static string utf_filename(string filename)
    {
    return httputility.urlencode(filename, system.text.encoding.utf8);
    }

     

    简单的对上述代码做一下解析,todownload方法为将一个服务器上的文件(serverfilpath为服务器上的物理地址),以某文件名(filename)在浏览器上弹出“文件下载”对话框,而toopen是将服务器上的某文件以某文件名在浏览器中显示/打开的。注意其中我使用了utf_filename方法,该方法很简单,主要为了解决包含非英文/数字名称的问题,比如说文件名为“衣明志.doc”,使用该方法客户端就不会出现乱码了。

     需要注意以下几个问题:

    1. content-disposition是mime协议的扩展,由于多方面的安全性考虑没有被标准化,所以可能某些浏览器不支持,比如说ie4.01
    2. 我们可以使用程序来使用它,也可以在web服务器(比如iis)上使用它,只需要在http header上做相应的设置即可

    可参看以下几篇文档:



    xzc 2008-10-30 16:07
    ]]>
    判定文件编码或文本流编码的方法http://www.blogjava.net/xzclog/archive/2008/06/16/208328.htmlxzcxzcmon, 16 jun 2008 06:44:00 gmthttp://www.blogjava.net/xzclog/archive/2008/06/16/208328.htmlhttp://www.blogjava.net/xzclog/comments/208328.htmlhttp://www.blogjava.net/xzclog/archive/2008/06/16/208328.html#feedback1http://www.blogjava.net/xzclog/comments/commentrss/208328.htmlhttp://www.blogjava.net/xzclog/services/trackbacks/208328.html 
    在程序中,文本文件经常用来存储标准的ascii码文本,比如英文、加减乘除等号这些运算符号。文本文件也可能用于存储一些其他非ascii字符,如基于gbk的简体中文,基于gig5的繁体中文等等。在存储这些字符时需要正确指定文件的编码格式;而在读取这些文本文件时,有时候就需要自动判定文件的编码格式。

    按照给定的字符集存储文本文件时,在文件的最开头的三个字节中就有可能存储着编码信息,所以,基本的原理就是只要读出文件前三个字节,判定这些字节的值,就可以得知其编码的格式。其实,如果项目运行的平台就是中文操作系统,如果这些文本文件在项目内产生,即开发人员可以控制文本的编码格式,只要判定两种常见的编码就可以了:gbk和utf-8。由于中文windows默认的编码是gbk,所以一般只要判定utf-8编码格式。

    对于utf-8编码格式的文本文件,其前3个字节的值就是-17、-69、-65,所以,判定是否是utf-8编码格式的代码片段如下:
    java代码
    1. java.io.file f=new java.io.file("待判定的文本文件名");   
    2. try{   
    3.   java.io.inputstream ios=new java.io.fileinputstream(f);   
    4.   byte[] b=new byte[3];   
    5.   ios.read(b);   
    6.   ios.close();   
    7.   if(b[0]==-17&&b[1]==-69&&b[2]==-65)   
    8.      system.out.println(f.getname() "编码为utf-8");   
    9.   else system.out.println(f.getname() "可能是gbk");   
    10. }catch(exception e){   
    11.    e.printstacktrace();   
    12. }   

    上述代码只是简单判定了是否是utf-8格式编码的文本文件,如果项目对要判定的文本文件编码不可控(比如用户上传的一些html、xml等文本),可以采用一个现成的开源项目:cpdetector,它所在的网址是:。它的类库很小,只有500k左右,利用该类库判定文本文件的代码如下:
    java代码
    1. /*------------------------------------------------------------------------  
    2.   detector是探测器,它把探测任务交给具体的探测实现类的实例完成。  
    3.   cpdetector内置了一些常用的探测实现类,这些探测实现类的实例可以通过add方法  
    4.   加进来,如parsingdetector、 jchardetfacade、asciidetector、unicodedetector。    
    5.   detector按照“谁最先返回非空的探测结果,就以该结果为准”的原则返回探测到的  
    6.   字符集编码。  
    7. --------------------------------------------------------------------------*/  
    8. cpdetector.io.codepagedetectorproxy detector =   
    9. cpdetector.io.codepagedetectorproxy.getinstance();   
    10. /*-------------------------------------------------------------------------  
    11.   parsingdetector可用于检查html、xml等文件或字符流的编码,构造方法中的参数用于  
    12.   指示是否显示探测过程的详细信息,为false不显示。  
    13. ---------------------------------------------------------------------------*/  
    14. detector.add(new cpdetector.io.parsingdetector(false));    
    15. /*--------------------------------------------------------------------------  
    16.   jchardetfacade封装了由mozilla组织提供的jchardet,它可以完成大多数文件的编码  
    17.   测定。所以,一般有了这个探测器就可满足大多数项目的要求,如果你还不放心,可以  
    18.   再多加几个探测器,比如下面的asciidetector、unicodedetector等。  
    19.  ---------------------------------------------------------------------------*/    
    20. detector.add(cpdetector.io.jchardetfacade.getinstance());   
    21. //asciidetector用于ascii编码测定   
    22. detector.add(cpdetector.io.asciidetector.getinstance());   
    23. //unicodedetector用于unicode家族编码的测定   
    24. detector.add(cpdetector.io.unicodedetector.getinstance());   
    25. java.nio.charset.charset charset = null;   
    26. file f=new file("待测的文本文件名");   
    27. try {   
    28.       charset = detector.detectcodepage(f.to);   
    29. catch (exception ex) {ex.printstacktrace();}   
    30. if(charset!=null){   
    31.      system.out.println(f.getname() "编码是:" charset.name());   
    32. }else  
    33.     system.out.println(f.getname() "未知");  

    上面代码中的detector不仅可以用于探测文件的编码,也可以探测任意输入的文本流的编码,方法是调用其重载形式:
    java代码
    1. charset=detector.detectcodepage(待测的文本输入流,测量该流所需的读入字节数);  

    上面的字节数由程序员指定,字节数越多,判定越准确,当然时间也花得越长。要注意,字节数的指定不能超过文本流的最大长度。

    判定文件编码的具体应用举例:
    属性文件(.properties)是java程序中的常用文本存储方式,象struts框架就是利用属性文件存储程序中的字符串资源。它的内容如下所示:
    java代码
    1. #注释语句   
    2. 属性名=属性值   

    读入属性文件的一般方法是:
    java代码
    1. fileinputstream ios=new fileinputstream("属性文件名");   
    2. properties prop=new properties();   
    3. prop.load(ios);   
    4. ios.close();   

    利用java.io.properties的load方法读入属性文件虽然方便,但如果属性文件中有中文,在读入之后就会发现出现乱码现象。发生这个原因是load方法使用字节流读入文本,在读入后需要将字节流编码成为字符串,而它使用的编码是“iso-8859-1”,这个字符集是ascii码字符集,不支持中文编码,所以这时需要使用显式的转码:
    java代码
    1. string value=prop.getproperty("属性名");   
    2. string encvalue=new string(value.getbytes("iso-8859-1"),"属性文件的实际编码");   

    在上面的代码中,属性文件的实际编码就可以利用上面的方法获得。当然,象这种属性文件是项目内部的,我们可以控制属性文件的编码格式,比如约定采用windows内定的gbk,就直接利用"gbk"来转码,如果约定采用utf-8,也可以是使用"utf-8"直接转码。如果想灵活一些,做到自动探测编码,就可利用上面介绍的方法测定属性文件的编码,从而方便开发人员的工作。


    xzc 2008-06-16 14:44
    ]]>
    网站地图