??xml version="1.0" encoding="utf-8" standalone="yes"?>久久亚洲精品无码av,亚洲六月丁香婷婷综合,亚洲人成色777777精品http://m.tkk7.com/xuechen0721/category/18009.html<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;——?amp;nbsp;兵城下&nbsp;&nbsp;猫科动物zh-cnWed, 04 Jul 2007 21:41:38 GMTWed, 04 Jul 2007 21:41:38 GMT60ANT的安?配置W记http://m.tkk7.com/xuechen0721/articles/128202.html兵城下兵城下Wed, 04 Jul 2007 14:53:00 GMThttp://m.tkk7.com/xuechen0721/articles/128202.htmlhttp://m.tkk7.com/xuechen0721/comments/128202.htmlhttp://m.tkk7.com/xuechen0721/articles/128202.html#Feedback0http://m.tkk7.com/xuechen0721/comments/commentRss/128202.htmlhttp://m.tkk7.com/xuechen0721/services/trackbacks/128202.html

内容摘要Q?br>ANT是一个基于JAVA的自动化脚本引擎Q脚本格式ؓXML。除了做JAVA~译相关d外,ANTq可以通过插g实现很多应用的调用?br>

  1. ANT的基本概念:
  2. ANT的安装:解包Q设|\?
  3. ANT的用:最好的学习只不q是一个简单实用的例子h……

ANT的基本概念:Java的Makefile

当一个代码项目大了以后,每次重新~译Q打包,试{都会变得非常复杂而且重复Q因此c语言中有make脚本来帮助这些工作的扚w完成。在Java 中应用是q_无关性的Q当然不会用q_相关的make脚本来完成这些批处理d了,ANT本n是q样一个流E脚本引擎,用于自动化调用程序完成项目的~译Q打包,试{。除了基于JAVA是^台无关的外,脚本的格式是ZXML的,比make脚本来说q要好维护一些?br>

每个ant脚本Q缺省叫build.xmlQ中讄了一pdd(target)Q比如对于一个一般的目可能需要有以下d?/p>

  • d1Qusage 打印本脚本的帮助信息Q缺省)
  • d2Qclean <-- init 清空初始化环?
  • d3Qjavadoc <-- build <-- init 生成JAVADOC
  • d4Qjar <-- build <-- init 生成JAR
  • d5Qall <-- jar + javadoc <-- build <-- init 完成以上所有Q务:jar javadoc
而多个Q务之间往往又包含了一定了依赖关系Q比如把整个应用打包d(jar)的这个依赖于~译d(build)Q而编译Q务又依赖于整个环境初始化d(init){?br>
注:我看到很多项目的ant脚本中的命名基本上都是一致的Q比如:~译一般叫build或者compileQ打包一般叫jar或warQ生成文一般命名ؓjavadoc或javadocsQ执行全部Q务all。在每个d的中QANT会根据配|调用一些外部应用ƈ配以相应参数执行。虽然ANT可调用的外部应用U类非常丰富Q但其实最常用的就2Q?个:比如javac javadoc jar{?

ANT的安?/h2> 解包后在pȝ可执行\径中加入指向ant的bin的\径就可以了,比如可以在GNU/Linux上把以下配置加入/etc/profile中:
export ANT_HOME=/home/ant
export JAVA_HOME=/usr/java/j2sdk1.4.1
export PATH=$PATH:$JAVA_HOME/bin:$ANT_HOME/bin

q样执行ant 后,如果不指定配|文件ant会缺省找build.xmlq个配置文gQƈҎ配置文g执行dQ缺省的d讄可以指向最常用的Q务,比如Q?buildQ或指向打印帮助信息QusageQ告诉用h那些脚本选项可以使用?br>

ANT的?br>

最好的学习q程是看懂那些open source目中的build.xml脚本Q然后根据自q需要简化成一个更单的QANT和APACHE上很多非常工E派的项目:单易用,而且适应性非常强Q因些项目的建立往往来源于开发h员日常最直接的需求?br>以下是的一?a >WebLucene应用的例子:修改?a >JDOM的build.xmlQ?br>
<project default="usage" basedir=".">

  <!-- =================================================================== -->
  <!-- Initialization target                                               -->
  <!-- =================================================================== -->
  <target name="init">
    <tstamp/>
    <property file="${basedir}/build.properties" />
    <property name="Name" value="ProjectFullName"/>
    <property name="name" value="project_name"/>
    <property name="version" value="0.2"/>
    <property name="year" value="2003"/>

    <echo message="----------- ${Name} ${version} [${year}] ------------"/>

    <property name="debug" value="off"/>
    <property name="optimize" value="on"/>
    <property name="deprecation" value="on"/>

    <property name="src.dir" value="./src/WEB-INF/src"/>
    <property name="lib.dir" value="./src/WEB-INF/lib"/>
    <property name="packages" value="com.chedong.*,org.apache.lucene.*"/>

    <property name="build.src" value="./src/WEB-INF/build"/>
    <property name="build.dest" value="./src/WEB-INF/classes"/>
    <property name="build.javadocs" value="./src/doc"/>
   
    <path id="classpath">
        <pathelement path="${jsdk_jar}"/>
        <fileset dir="${lib.dir}">
           <include name="**/*.jar"/>
        </fileset>
    </path>
   
    <filter token="year" value="${year}"/>
    <filter token="version" value="${version}"/>
    <filter token="date" value="${TODAY}"/>
    <filter token="log" value="true"/>
    <filter token="verbose" value="true"/>
  </target>

  <!-- =================================================================== -->
  <!-- Help on usage                                                       -->
  <!-- =================================================================== -->
  <target name="usage" depends="init">
    <echo message="${Name} Build file"/>
    <echo message="-------------------------------------------------------------"/>
    <echo message=""/>
    <echo message=" available targets are:"/>
    <echo message=""/>
    <echo message="   jar      --> generates the ${name}.jar file"/>
    <echo message="   build    --> compiles the source code"/>
    <echo message="   javadoc  --> generates the API documentation"/>
    <echo message="   clean    --> cleans up the directory"/>
    <echo message=""/>
    <echo message=" Please rename build.properties.default to build.properties"/>
    <echo message=" and edit build.properties to specify JSDK 2.3 classpath."/>
    <echo message=""/>
    <echo message=" See the comments inside the build.xml file for more details."/>
    <echo message="-------------------------------------------------------------"/>
    <echo message=""/>
    <echo message=""/>
  </target>

  <!-- =================================================================== -->
  <!-- Prepares the source code                                            -->
  <!-- =================================================================== -->
  <target name="prepare-src" depends="init">
    <!-- create directories -->
    <mkdir dir="${build.src}"/>
    <mkdir dir="${build.dest}"/>
   
    <!-- copy src files -->
    <copy todir="${build.src}">
      <fileset dir="${src.dir}"/>
    </copy>
  </target>

  <!-- =================================================================== -->
  <!-- Compiles the source directory                                       -->
  <!-- =================================================================== -->
  <target name="build" depends="prepare-src">
    <javac srcdir="${build.src}"
           destdir="${build.dest}"
           debug="${debug}"
           optimize="${optimize}">
      <classpath refid="classpath"/>
    </javac>
  </target>

  <!-- =================================================================== -->
  <!-- Creates the class package                                           -->
  <!-- =================================================================== -->
  <target name="jar" depends="build">
    <jar jarfile="${lib.dir}/${name}.jar"
         basedir="${build.dest}"
         includes="**"/>
  </target>

  <!-- =================================================================== -->
  <!-- Creates the API documentation                                       -->
  <!-- =================================================================== -->
  <target name="javadoc" depends="build">
    <mkdir dir="${build.javadocs}"/>
    <javadoc packagenames="${packages}"
             sourcepath="${build.src}"
             destdir="${build.javadocs}"
             author="true"
             version="true"
             use="true"
             splitindex="true"
             windowtitle="${Name} API"
             doctitle="${Name}">
      <classpath refid="classpath"/>
    </javadoc>
  </target>

  <!-- =================================================================== -->
  <!-- Clean targets                                                       -->
  <!-- =================================================================== -->
  <target name="clean" depends="init">
    <delete dir="${build.src}"/>
    <delete dir="${build.dest}/org"/>
    <delete dir="${build.dest}/com"/>
    <delete>
      <fileset dir="${build.dest}" includes="**/*.class"/>
    </delete>
  </target>
</project>
<!-- End of file -->

~省dQusage 打印帮助文Q告诉有那些d选项Q可用的有build, jar, javadoc和clean.

初始化环境变量:init
所有Q务都Z一些基本环境变量的讄初始化完成,是后l其他Q务的基础Q在环境初始化过E中Q有2Ҏ较可以方便设|:

1 除了使用却缺省的property讄了JAVA源\径和输出路径外,引用了一个外部的build.properties文g中的讄Q?br><property file="${basedir}/build.properties" />
q样大部分简单配|用户只要会看懂build.properties可以了Q毕竟XML比vkey value的属性文件还是要可读性差一些。用build.properties也可以方便其他用户从~译的细节中解放出来?br>
2 CLASSPATH讄Q用了其中的:
    <path id="classpath">
        <pathelement path="${jsdk_jar}"/>
        <fileset dir="${lib.dir}">
           <include name="**/*.jar"/>
        </fileset>
    </path>
则相当于讄了:CLASSPATH=/path/to/resin/lib/jsdk23.jar; /path/to/project/lib/*.jar;

文g复制Qprepare-src
创徏临时SRC存放目录和输出目录?br>  <!-- =================================================================== -->
  <!-- Prepares the source code                                            -->
  <!-- =================================================================== -->
  <target name="prepare-src" depends="init">
    <!-- create directories -->
    <mkdir dir="${build.src}"/>
    <mkdir dir="${build.dest}"/>
   
    <!-- copy src files -->
    <copy todir="${build.src}">
      <fileset dir="${src.dir}"/>
    </copy>
  </target>

~译dQbuild
~译时的CLASSPATH环境通过一下方式找到引用一个path对象
<classpath refid="classpath"/>

打包dQjar
对应用打包生成项目所写名?jar文g
  <!-- =================================================================== -->
  <!-- Creates the class package                                           -->
  <!-- =================================================================== -->
  <target name="jar" depends="build">
    <jar jarfile="${lib.dir}/${name}.jar"
         basedir="${build.dest}"
         includes="**"/>
  </target>

生成JAVADOC文档d: javadoc
  <!-- =================================================================== -->
  <!-- Creates the API documentation                                       -->
  <!-- =================================================================== -->
  <target name="javadoc" depends="build">
    <mkdir dir="${build.javadocs}"/>
    <javadoc packagenames="${packages}"
             sourcepath="${build.src}"
             destdir="${build.javadocs}"
             author="true"
             version="true"
             use="true"
             splitindex="true"
             windowtitle="${Name} API"
             doctitle="${Name}">
      <classpath refid="classpath"/>
    </javadoc>
  </target>

清空临时~译文gQclean
  <!-- =================================================================== -->
  <!-- Clean targets                                                       -->
  <!-- =================================================================== -->
  <target name="clean" depends="init">
    <delete dir="${build.src}"/>
    <delete dir="${build.dest}/org"/>
    <delete dir="${build.dest}/com"/>
    <delete>
      <fileset dir="${build.dest}" includes="**/*.class"/>
    </delete>
  </target>

TODOQ?br>更多d/扩展Q(样例Q?br>
  • 试dQJUnit试
  • 代码风格查Q务:CheckStyleQJalopy{?
  • 邮g警报dQ可以把以上q些d的输告发送到制定的用户列表中Q这个Q务可以设|每天自动运行?nbsp; 


兵城下 2007-07-04 22:53 发表评论
]]>
目W记QdaoQwebQ模块边界以及Model分类 http://m.tkk7.com/xuechen0721/articles/128200.html兵城下兵城下Wed, 04 Jul 2007 14:45:00 GMThttp://m.tkk7.com/xuechen0721/articles/128200.htmlhttp://m.tkk7.com/xuechen0721/comments/128200.htmlhttp://m.tkk7.com/xuechen0721/articles/128200.html#Feedback0http://m.tkk7.com/xuechen0721/comments/commentRss/128200.htmlhttp://m.tkk7.com/xuechen0721/services/trackbacks/128200.html先从后端的dao说v吧:
已有目的开发以及appfuse的开发,都属于传l的开放方式,内部有daoQ外部还有service?br>
q样的开发方式太学院了,每次改动其实影响面很大,要改二个c,两个接口。^时不忙的时候也q了,目一紧的话,大家׃ؕ来的了。相当部分都是最外层接口实现cd直接讉K了数据库Q而不走规范\Uѝ?br>
现在对外提供一个repository的service接口Q加载该领域模块的root对象Q以便程序利用root对象来游赎ͼddd推荐的做法)Q然后内部有一个dao接口Q承该repository接口Q提供一些内部用的额外服务Q比如一些数据库查询。接着有一个类l承框架提供的如spring的HiberanteTemplate同时实现dao接口Q这h改动的规模就比较,一个接口和一个实现类。这个思\和SS2的思\是一L?br>
框架数据讉K已经提供一些公q操作化开发,当然q利用泛型等。此外,Ibatis3.0的设计思\Q将是下一步的工作目标?br>
另外Q通过root对象游走讉K领域对象Q性能可能有点问题。但q是可以接受的,因ؓ从开发的角度看,通常都root下的对象都是和root对象一起出现操作的Q不可能单一出现一个root以外的对象来操作以及昄的?br>

现在p说Web层:
׃servcie对外都是开放domian model了,不再提供VO对象Q免L谓的copy property操作。而把VO的这部分工作交给自行开发的界面设计工具Q因此在设计面的时候其实已l知道的面的访问的元素以及对象路径Q在设计面完成后由该设计工L成VO对象和映对象。这样VO对象的设计生,以及property的copy都是工具完成Q无Mh工干预?br>
另外Web层采用SWFQ除了完整的抽取出流E控制流转逻辑Q还完整的封装了对于Request以及Response的数据访问操作。这样一个流E中调用了那些model以及servcie都非常清楚。将来有可能通过工具像规则引擎那样可以提供给业务人员直接使用。同时没有了传统的Controlcȝ构的存在Q极大的提高了开发效率问题?br>

模块边界的处理包括两个部分:
一是行为的边界集成上,比如订单理模块对胦务模块的行ؓ要求?br>订单理模块自行设计它所需要的接口Q由一个集成模块提供adapterc,来适配到胦务模块合适的service上。这样就解决了旧pȝ设计现有的问题,旧系l现在都是直接调用胦务模块提供的APIQ这L做法实际上是把集成工作放在了订单理模块下?br>
二是对象的边界集成,是这样做的?br>订单明细对象QOrderItemQ会兌一个品对象,不过产品对象是是属于产品模块而非订单模块Q对于订单模块只兛_id而ƈ不用对象,但在规则引擎或者界面设计工兯L集成环境却是需要品对象的。我们采用代码生成的方式Q在订单明细对象上加一个annotationQ比如Integration的annotation标识Q用aspectj在编译上enhancement生成的classQ得订单明l对象在集成环境上可以拿C品对象,q算是一个集成方面?/p>

最后是domain model部分Q?/strong>
一cLcM保险中的保单对象q样的长生命周期对象Q?br>
另一cLtransaction交易q程的对象,几乎没有生命周期的;

最后一cLrequest/response对象。这cd象以前没有识别,通常和VO混在一P但是在IAA中以及电信业的模型是q类对象是独立存在,q被持久化的?br>当然他们也是几乎没有生命周期的,request对象建立在增量更C很有用?br>
reponse对象目前没有特别用途,依然采用VO处理?br>
request对象的徏立有两个好处?br>1. 以前直接更新订单对象Q虽然记录了log但是只知道减肥前Q减肥后?br>2. request对象的第二个好处Q可以解决一个业务事务跨两个物理事务的设计问题。即一个业务请求可以分多次累进完成Q比如分两天来处理,每天完成一个部分,但在完成之前Q所有操作数据都不生效。在没有持久化request对象前,我们只能把操作的数据写到临时表上?br>
此外Q由于某个领域模块的增量操作通常从一个根对象开始,所依赖的criteria可以从request中加以识别ƈ通过框架提前加蝲Q而service对象的方法接受传递对象而不再关心对象的加蝲工作Q同时也可以通过框架处理基本数据复制工作Q这L序只兛_兌对象的操作。这个做法和SS2是一LQ只不过采用的是AOP的处理方式?/p>

兵城下 2007-07-04 22:45 发表评论
]]>
教你d明白Java的IOpȝ http://m.tkk7.com/xuechen0721/articles/127971.html兵城下兵城下Tue, 03 Jul 2007 15:39:00 GMThttp://m.tkk7.com/xuechen0721/articles/127971.htmlhttp://m.tkk7.com/xuechen0721/comments/127971.htmlhttp://m.tkk7.com/xuechen0721/articles/127971.html#Feedback0http://m.tkk7.com/xuechen0721/comments/commentRss/127971.htmlhttp://m.tkk7.com/xuechen0721/services/trackbacks/127971.html1. stream代表的是M有能力出数据的数据源,或是M有能力接收数据的接收源。在Java的IO中,所有的streamQ包括Input和Out streamQ都包括两种cdQ?br>
1.1 以字节ؓ导向的stream
以字节ؓ导向的streamQ表CZ字节为单位从stream中读取或往stream中写入信息。以字节为导向的stream包括下面几种cdQ?br>1. input stream
1) ByteArrayInputStreamQ把内存中的一个缓冲区作ؓInputStream使用
2) StringBufferInputStreamQ把一个String对象作ؓInputStream
3) FileInputStreamQ把一个文件作为InputStreamQ实现对文g的读取操?br>4) PipedInputStreamQ实Cpipe的概念,主要在线E中使用
5) SequenceInputStreamQ把多个InputStream合ƈZ个InputStream

2. Out stream
1) ByteArrayOutputStreamQ把信息存入内存中的一个缓冲区?br>2) FileOutputStreamQ把信息存入文g?br>3) PipedOutputStreamQ实Cpipe的概念,主要在线E中使用
4) SequenceOutputStreamQ把多个OutStream合ƈZ个OutStream

1.2 以Unicode字符为导向的stream
以Unicode字符为导向的streamQ表CZUnicode字符为单位从stream中读取或往stream中写入信息。以Unicode字符为导向的stream包括下面几种cdQ?br>1. Input Stream
1) CharArrayReaderQ与ByteArrayInputStream对应
2) StringReaderQ与StringBufferInputStream对应
3) FileReaderQ与FileInputStream对应
4) PipedReaderQ与PipedInputStream对应

2. Out Stream
1) CharArrayWriteQ与ByteArrayOutputStream对应
2) StringWriteQ无与之对应的以字节为导向的stream
3) FileWriteQ与FileOutputStream对应
4) PipedWriteQ与PipedOutputStream对应
以字Wؓ导向的stream基本上对有与之相对应的以字节为导向的stream。两个对应类实现的功能相同,字是在操作时的导向不同。如CharArrayReaderQ和ByteArrayInputStream的作用都是把内存中的一个缓冲区作ؓInputStream使用Q所不同的是前者每ơ从内存中读取一个字节的信息Q而后者每ơ从内存中读取一个字W?br>
1.3 两种不现导向的stream之间的{?br>InputStreamReader和OutputStreamReaderQ把一个以字节为导向的stream转换成一个以字符为导向的stream?br>
2. streamd属?/strong>
2.1 “为streamd属?#8221;的作?br>q用上面介绍的Java中操作IO的APIQ我们就可完成我们想完成的Q何操作了。但通过FilterInputStream和FilterOutStream的子c,我们可以为streamd属性。下面以一个例子来说明q种功能的作用?br>如果我们要往一个文件中写入数据Q我们可以这h作:
FileOutStream fs = new FileOutStream(“test.txt”);
然后可以通过产生的fs对象调用write()函数来往test.txt文g中写入数据了。但是,如果我们惛_?#8220;先把要写入文件的数据先缓存到内存中,再把~存中的数据写入文g?#8221;的功能时Q上面的API没有一个能满我们的需求了。但是通过FilterInputStream和FilterOutStream的子c,为FileOutStreamd我们所需要的功能?br>
2.2 FilterInputStream的各U类?br>2.2.1 用于装以字节ؓ导向的InputStream
1) DataInputStreamQ从stream中读取基本类型(int、char{)数据?br>2) BufferedInputStreamQ用缓冲区
3) LineNumberInputStreamQ会记录input stream内的行数Q然后可以调用getLineNumber()和setLineNumber(int)
4) PushbackInputStreamQ很用刎ͼ一般用于编译器开?br>
2.2.2 用于装以字Wؓ导向的InputStream
1) 没有与DataInputStream对应的类。除非在要用readLine()时改用BufferedReaderQ否则用DataInputStream
2) BufferedReaderQ与BufferedInputStream对应
3) LineNumberReaderQ与LineNumberInputStream对应
4) PushBackReaderQ与PushbackInputStream对应

2.3 FilterOutStream的各U类?br>2.2.3 用于装以字节ؓ导向的OutputStream
1) DataIOutStreamQ往stream中输出基本类型(int、char{)数据?br>2) BufferedOutStreamQ用缓冲区
3) PrintStreamQ生格式化输出

2.2.4 用于装以字Wؓ导向的OutputStream
1) BufferedWriteQ与对应
2) PrintWriteQ与对应

3. RandomAccessFile
1) 可通过RandomAccessFile对象完成Ҏ件的d操作
2) 在生一个对象时Q可指明要打开的文件的性质QrQ只读;wQ只写;rw可读?br>3) 可以直接跛_文g中指定的位置

4. I/O应用的一个例?/strong>


 E序代码
E序代码 E序代码
import java.io.*;
public class TestIO{
public static void main(String[] args)
throws IOException{
//1.以行为单位从一个文件读取数?br>BufferedReader in = 
new BufferedReader(
new FileReader("F:\\nepalon\\TestIO.java"));
String s, s2 = new String();
while((s = in.readLine()) != null)
s2 += s + "\n";
in.close();

//1b. 接收键盘的输?br>BufferedReader stdin = 
new BufferedReader(
new InputStreamReader(System.in));
System.out.println("Enter a line:");
System.out.println(stdin.readLine());

//2. 从一个String对象中读取数?br>StringReader in2 = new StringReader(s2);
int c;
while((c = in2.read()) != -1)
System.out.println((char)c);
in2.close();

//3. 从内存取出格式化输入
try{
DataInputStream in3 = 
new DataInputStream(
new ByteArrayInputStream(s2.getBytes()));
while(true)
System.out.println((char)in3.readByte()); 
}
catch(EOFException e){
System.out.println("End of stream");
}

//4. 输出到文?br>try{
BufferedReader in4 =
new BufferedReader(
new StringReader(s2));
PrintWriter out1 =
new PrintWriter(
new BufferedWriter(
new FileWriter("F:\\nepalon\\ TestIO.out")));
int lineCount = 1;
while((s = in4.readLine()) != null)
out1.println(lineCount++ + "Q? + s);
out1.close();
in4.close();
}
catch(EOFException ex){
System.out.println("End of stream");
}

//5. 数据的存储和恢复
try{
DataOutputStream out2 = 
new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("F:\\nepalon\\ Data.txt")));
out2.writeDouble(3.1415926);
out2.writeChars("\nThas was pi:writeChars\n");
out2.writeBytes("Thas was pi:writeByte\n");
out2.close();
DataInputStream in5 =
new DataInputStream(
new BufferedInputStream(
new FileInputStream("F:\\nepalon\\ Data.txt")));
BufferedReader in5br =
new BufferedReader(
new InputStreamReader(in5));
System.out.println(in5.readDouble());
System.out.println(in5br.readLine());
System.out.println(in5br.readLine());
}
catch(EOFException e){
System.out.println("End of stream");
}

//6. 通过RandomAccessFile操作文g
RandomAccessFile rf =
new RandomAccessFile("F:\\nepalon\\ rtest.dat", "rw");
for(int i=0; i<10; i++)
rf.writeDouble(i*1.414);
rf.close();

rf = new RandomAccessFile("F:\\nepalon\\ rtest.dat", "r");
for(int i=0; i<10; i++)
System.out.println("Value " + i + "Q? + rf.readDouble());
rf.close();

rf = new RandomAccessFile("F:\\nepalon\\ rtest.dat", "rw");
rf.seek(5*8);
rf.writeDouble(47.0001);
rf.close();

rf = new RandomAccessFile("F:\\nepalon\\ rtest.dat", "r");
for(int i=0; i<10; i++)
System.out.println("Value " + i + "Q? + rf.readDouble());
rf.close();
}
}

关于代码的解释(以区为单位)Q?br>1ZQ当d文gӞ先把文g内容d~存中,当调用in.readLine()Ӟ再从~存中以字符的方式读取数据(以下U?#8220;~存字节d方式”Q?br>1bZQ由于想以缓存字节读取方式从标准IOQ键盘)中读取数据,所以要先把标准IOQSystem.inQ{换成字符导向的streamQ再q行BufferedReader装?br>2ZQ要以字W的形式从一个String对象中读取数据,所以要产生一个StringReadercd的stream?br>4ZQ对String对象s2d数据Ӟ先把对象中的数据存入~存中,再从~冲中进行读取;对TestIO.out文gq行操作Ӟ先把格式化后的信息输出到~存中,再把~存中的信息输出到文件中?br>5ZQ对Data.txt文gq行输出Ӟ是先把基本类型的数据输出屋缓存中Q再把缓存中的数据输出到文g中;Ҏ件进行读取操作时Q先把文件中的数据读取到~存中,再从~存中以基本cd的Ş式进行读取。注意in5.readDouble()q一行。因为写入第一个writeDouble()Q所以ؓ了正显C。也要以基本cd的Ş式进行读取?br>6区是通过RandomAccessFilecd文gq行操作?


兵城下 2007-07-03 23:39 发表评论
]]>
Java抽象cd接口的区?/title><link>http://m.tkk7.com/xuechen0721/articles/95128.html</link><dc:creator>兵城下</dc:creator><author>兵城下</author><pubDate>Sun, 21 Jan 2007 06:34:00 GMT</pubDate><guid>http://m.tkk7.com/xuechen0721/articles/95128.html</guid><wfw:comment>http://m.tkk7.com/xuechen0721/comments/95128.html</wfw:comment><comments>http://m.tkk7.com/xuechen0721/articles/95128.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/xuechen0721/comments/commentRss/95128.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/xuechen0721/services/trackbacks/95128.html</trackback:ping><description><![CDATA[ <div id="nvvjx71" class="postTitle"> <a class="postTitle2" id="viewpost1_TitleUrl" href="/chunkyo/archive/2007/01/21/95093.html">Java抽象cd接口的区?好长旉没看q种文章?</a> </div> <div align="left"> <span style="FONT-WEIGHT: 400"> <span id="rnjjxzx" class="unnamed4"> <font style="FONT-SIZE: 9pt">abstract class和interface是Java语言中对于抽象类定义q行支持的两U机Ӟ正是׃q两U机制的存在Q才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的怼性,甚至可以怺替换Q因此很多开发者在q行抽象cd义时对于abstract class和interface的选择昑־比较随意。其实,两者之间还是有很大的区别的Q对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意囄理解是否正确、合理。本文将对它们之间的区别q行一番剖析,试图l开发者提供一个在二者之间进行选择的依据。 ?br /><br />理解抽象c ?br /><br />abstract class和interface在Java语言中都是用来进行抽象类Q本文中的抽象类q从abstract class译而来Q它表示的是一个抽象体Q而abstract class为Java语言中用于定义抽象类的一U方法,误者注意区分)定义的,那么什么是抽象c,使用抽象c能为我们带来什么好处呢Q ?br /><br />在面向对象的概念中,我们知道所有的对象都是通过cL描绘的,但是反过来却不是q样。ƈ不是所有的c都是用来描l对象的Q如果一个类中没有包含够的信息来描l一个具体的对象Q这Lcd是抽象类。抽象类往往用来表征我们在对问题领域q行分析、设计中得出的抽象概念,是对一pd看上M同,但是本质上相同的具体概念的抽象。比如:如果我们q行一个图形编辑Y件的开发,׃发现问题领域存在着圆、三角Şq样一些具体概念,它们是不同的Q但是它们又都属于Ş状这样一个概念,形状q个概念在问题领域是不存在的Q它是一个抽象概c正是因为抽象的概念在问题领域没有对应的具体概念Q所以用以表征抽象概늚抽象cL不能够实例化的。 ?br /><br />在面向对象领域,抽象cM要用来进行类型隐藏。我们可以构造出一个固定的一l行为的抽象描述Q但是这l行为却能够有Q意个可能的具体实现方式。这个抽象描q就是抽象类Q而这一lQ意个可能的具体实现则表现为所有可能的zcR模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允怿改的Q同Ӟ通过从这个抽象体zQ也可扩展此模块的行为功能。熟悉OCP的读者一定知道,Z能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle)Q抽象类是其中的关键所在。 ?br /><br /><br />从语法定义层面看abstract class和interface  <br /><br />在语法层面,Java语言对于abstract class和interfacel出了不同的定义方式Q下面以定义一个名为Demo的抽象类Z来说明这U不同。 ?br /><br />使用abstract class的方式定义Demo抽象cȝ方式如下Q ?br /><br />abstract class Demo { ?br /> abstract void method1();  <br /> abstract void method2();  <br /> … ?br />} ?br /><br />使用interface的方式定义Demo抽象cȝ方式如下Q ?br /><br />interface Demo {  <br /> void method1();  <br /> void method2();  <br /> … ?br />}  <br /><br />在abstract class方式中,Demo可以有自q数据成员Q也可以有非abstarct的成员方法,而在interface方式的实CQDemo只能够有静态的不能被修改的数据成员Q也是必须是static final的,不过在interface中一般不定义数据成员Q,所有的成员Ҏ都是abstract的。从某种意义上说Qinterface是一U特DŞ式的abstract class。 ?br /><br />      从编E的角度来看Qabstract class和interface都可以用来实?design by contract"的思想。但是在具体的用上面还是有一些区别的。 ?br /><br />首先Qabstract class在Java语言中表C的是一U承关p,一个类只能使用一ơ承关pR但是,一个类却可以实现多个interface。也许,q是Java语言的设计者在考虑Java对于多重l承的支持方面的一U折中考虑吧。 ?br /><br />其次Q在abstract class的定义中Q我们可以赋予方法的默认行ؓ。但是在interface的定义中Q方法却不能拥有默认行ؓQؓ了绕q这个限Ӟ必须使用委托Q但是这会 增加一些复杂性,有时会造成很大的麻烦。 ?br /><br />在抽象类中不能定义默认行存在另一个比较严重的问题Q那是可能会造成l护上的ȝ。因为如果后来想修改cȝ界面Q一般通过abstract class或者interface来表C)以适应新的情况Q比如,d新的Ҏ或者给已用的方法中d新的参数Q时Q就会非常的ȝQ可能要p很多的时_对于zcd多的情况Q尤为如此)。但是如果界面是通过abstract class来实现的Q那么可能就只需要修改定义在abstract class中的默认行ؓ可以了。 ?br /><br />同样Q如果不能在抽象cM定义默认行ؓQ就会导致同LҎ实现出现在该抽象cȝ每一个派生类中,q反?one ruleQone place"原则Q造成代码重复Q同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。 ?br /><br /><br />从设计理念层面看abstract class和interface  <br /><br />上面主要从语法定义和~程的角度论qCabstract class和interface的区别,q些层面的区别是比较低层ơ的、非本质的。本节从另一个层面:abstract class和interface所反映出的设计理念Q来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概늚本质所在。 ?br /><br />前面已经提到q,abstarct class在Java语言中体C一U承关p,要想使得l承关系合理Q父cdzcM间必d?is a"关系Q即父类和派生类在概忉|质上应该是相同的Q参考文献?〕中有关?is a"关系的大幅深入的论qͼ有兴的读者可以参考)。对于interface 来说则不Ӟq不要求interface的实现者和interface定义在概忉|质上是一致的Q仅仅是实现了interface定义的契U而已。ؓ了便于理解Q下面将通过一个简单的实例q行说明。 ?br /><br />考虑q样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Doorh执行两个动作open和closeQ此时我们可以通过abstract class或者interface来定义一个表C抽象概念的类型,定义方式分别如下所C:  <br /><br />使用abstract class方式定义DoorQ ?br /><br />abstract class Door {  <br /> abstract void open();  <br /> abstract void close()Q ?br />}  <br /><br />   <br />使用interface方式定义DoorQ ?br /><br /><br />interface Door {  <br /> void open();  <br /> void close();  <br />}  <br /><br />   <br />其他具体的Doorcd可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看h好像使用abstract class和interface没有大的区别。 ?br /><br />如果现在要求Doorq要h报警的功能。我们该如何设计针对该例子的cȝ构呢Q在本例中,主要是ؓ了展Cabstract class和interface反映在设计理念上的区别,其他斚w无关的问题都做了化或者忽略)Q下面将|列出可能的解决ҎQƈ从设计理念层面对q些不同的方案进行分析。 ?br /><br />解决Ҏ一Q ?br /><br />单的在Door的定义中增加一个alarmҎQ如下:  <br /><br />abstract class Door {  <br /> abstract void open();  <br /> abstract void close()Q ?br /> abstract void alarm();  <br />}  <br /><br />   <br />或者 ?br /><br />interface Door {  <br /> void open();  <br /> void close();  <br /> void alarm();  <br />}  <br /><br />   <br />那么h报警功能的AlarmDoor的定义方式如下:  <br /><br />class AlarmDoor extends Door {  <br /> void open() { … }  <br /> void close() { … }  <br /> void alarm() { … }  <br />}  <br /><br />   <br />或者 ?br /><br />class AlarmDoor implements Door { ?br /> void open() { … }  <br /> void close() { … }  <br /> void alarm() { … }  <br />} ?br /><br />q种Ҏq反了面向对象设计中的一个核心原则ISPQInterface Segregation PricipleQ,在Door的定义中把Door概念本n固有的行为方法和另外一个概?报警?的行为方法؜在了一赗这样引L一个问题是那些仅仅依赖于Doorq个概念的模块会因ؓ"报警?q个概念的改变(比如Q修改alarmҎ的参敎ͼ而改变,反之依然。 ?br /><br />解决Ҏ二:  <br /><br />既然open、close和alarm属于两个不同的概念,ҎISP原则应该把它们分别定义在代表q两个概늚抽象cM。定义方式有Q这两个概念都用abstract class方式定义Q两个概念都使用interface方式定义Q一个概念用abstract class方式定义Q另一个概念用interface方式定义。 ?br /><br />昄Q由于Java语言不支持多重承,所以两个概念都使用abstract class方式定义是不可行的。后面两U方式都是可行的Q但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意囄反映是否正确、合理。我们一一来分析、说明。 ?br /><br />如果两个概念都用interface方式来定义,那么反映出两个问题Q?、我们可能没有理解清楚问题领域,AlarmDoor在概忉|质上到底是Doorq是报警器?2、如果我们对于问题领域的理解没有问题Q比如:我们通过对于问题领域的分析发现AlarmDoor在概忉|质上和Door是一致的Q那么我们在实现时就没有能够正确的揭C我们的设计意图Q因为在q两个概늚定义上(均用interface方式定义Q反映不Zq含义。 ?br /><br />如果我们对于问题领域的理解是QAlarmDoor在概忉|质上是DoorQ同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢Q前面已l说q,abstract class在Java语言中表CZU承关p,而承关pd本质上是"is a"关系。所以对于Doorq个概念Q我们应该用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行ؓQ所以报警概念可以通过interface方式定义。如下所C:  <br /><br />abstract class Door {  <br /> abstract void open();  <br /> abstract void close()Q ?br />}  <br />interface Alarm {  <br /> void alarm();  <br />}  <br />class AlarmDoor extends Door implements Alarm {  <br /> void open() { … }  <br /> void close() { … }  <br />    void alarm() { … }  <br />}  <br /><br />   <br />q种实现方式基本上能够明的反映出我们对于问题领域的理解Q正的揭示我们的设计意图。其实abstract class表示的是"is a"关系Qinterface表示的是"like a"关系Q大家在选择时可以作Z个依据,当然q是建立在对问题领域的理解上的,比如Q如果我们认为AlarmDoor在概忉|质上是报警器Q同时又hDoor的功能,那么上述的定义方式就要反q来了?/font> </span> </span> </div> <img src ="http://m.tkk7.com/xuechen0721/aggbug/95128.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/xuechen0721/" target="_blank">兵城下</a> 2007-01-21 14:34 <a href="http://m.tkk7.com/xuechen0721/articles/95128.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>实现DAO 设计模式http://m.tkk7.com/xuechen0721/articles/92158.html兵城下兵城下Sat, 06 Jan 2007 03:50:00 GMThttp://m.tkk7.com/xuechen0721/articles/92158.htmlhttp://m.tkk7.com/xuechen0721/comments/92158.htmlhttp://m.tkk7.com/xuechen0721/articles/92158.html#Feedback0http://m.tkk7.com/xuechen0721/comments/commentRss/92158.htmlhttp://m.tkk7.com/xuechen0721/services/trackbacks/92158.html实现DAO 设计模式
 
在JAVA~程的时? 有时候看h非常直接的实现却非要用设计模式{若干个弯dC, q似乎显的很多余,但是采用一些成熟的设计模式,会ɽE序更加的健?松耦合以及好维护和扩展.

实现DAO 设计模式


为DAO实现工厂cȝ{略

1 采用工厂Ҏ设计模式
如果一个DAO 工厂只ؓ一个数据库的实?(比如ORACLE)而创建很多的DAO的时?实现该策略时,我们考虑采用工厂Ҏ设计模式. 假设该工厂类创徏了CustomerDAO, AccountDAO, OrderDAO {一些对象?br />
2 使用抽象工厂设计模式:

如果考虑ZU不同类型的数据库来实现q个{略,我们可以考虑采用抽象工厂设计模式. 假设. q个工厂创徏了CustomerDAO, AccountDAO, OrderDAO的一pd的DAO, 该策略运用了在抽象工厂中产生的工厂类中的工厂Ҏ的实?

代码说明Q?br />
以下代码举例说明了DAO设计模式的具体实?
我们以用抽象工厂的设计模式来对付多U类型数据库Z,在以下的例子中只具体列出CLOUDSCAPE 数据库类型的DAO设计模式的具体实?其他cd数据库DAO设计模式的实现大同小?

1 // Abstract class DAO Factory
public abstract class DAOFactory {

// List of DAO types supported by the factory
public static final int CLOUDSCAPE = 1;
public static final int ORACLE = 2;
public static final int SYBASE = 3;
...

// There will be a method for each DAO that can be
// created. The concrete factories will have to
// implement these methods.
// 所有实现该抽象工厂的工厂类中必L的方?用这些方法来创徏具体的DAOc?
public abstract CustomerDAO getCustomerDAO();
public abstract AccountDAO getAccountDAO();
public abstract OrderDAO getOrderDAO();

//该抽象类的静态方?用他来创建其他具体的DAO工厂c?br />public static DAOFactory getDAOFactory(
int whichFactory) {

switch (whichFactory) {
case CLOUDSCAPE:
return new CloudscapeDAOFactory();
case ORACLE :
return new OracleDAOFactory();
case SYBASE :
return new SybaseDAOFactory();
...
default :
return null;
}
}
}


2 以下是Cloudscape DAO FACTORY cȝ实现,在他里面实现了该cd数据库的q接,以及实现了他所l承的抽象工厂类中所必须实现的那些方?在这些方法中创徏具体的DAO对象.

// Cloudscape concrete DAO Factory implementation
import java.sql.*;

public class CloudscapeDAOFactory extends DAOFactory {
public static final String DRIVER=
"COM.cloudscape.core.RmiJdbcDriver";
public static final String DBURL=
"jdbc:cloudscape:rmi://localhost:1099/CoreJ2EEDB";

// method to create Cloudscape connections
//建立Cloudscape q接
public static Connection createConnection() {
// Use DRIVER and DBURL to create a connection
// Recommend connection pool implementation/usage
}
//创徏 CustomerDAO 对象 当然q回的是一个该cd现的接口,他的好处是实现了实现细节的隐蔽.
public CustomerDAO getCustomerDAO() {
// CloudscapeCustomerDAO implements CustomerDAO
return new CloudscapeCustomerDAO();
}
//创徏 AccountDAO 对象 当然q回的是一个该cd现的接口,他的好处是实现了实现细节的隐蔽.
public AccountDAO getAccountDAO() {
// CloudscapeAccountDAO implements AccountDAO
return new CloudscapeAccountDAO();
}
//创徏 OrderDAO 对象 当然q回的是一个该cd现的接口,他的好处是实现了实现细节的隐蔽.

public OrderDAO getOrderDAO() {
// CloudscapeOrderDAO implements OrderDAO
return new CloudscapeOrderDAO();
}
...
}

3 以下代码是具体DAOcd现的接口也就是CloudscapeCustomerDAO()实现的接? CustomerDAO .在该接口中定义了所有的业务Ҏ.


// Interface that all CustomerDAOs must support
public interface CustomerDAO {
public int insertCustomer(...);
public boolean deleteCustomer(...);
public Customer findCustomer(...);
public boolean updateCustomer(...);
public RowSet selectCustomersRS(...);
public Collection selectCustomersTO(...);
...
}

4 以下CloudscapeCustomerDAOcd现的具体业务l节和数据操作细? 他是要向客户数据端隐蔽的.

import java.sql.*;
public class CloudscapeCustomerDAO implements
CustomerDAO {
public CloudscapeCustomerDAO() {
// initialization
}
// The following methods can use
// CloudscapeDAOFactory.createConnection()
// to get a connection as required
public int insertCustomer(...) {
// Implement insert customer here.
// Return newly created customer number
// or a -1 on error
}
public boolean deleteCustomer(...) {
// Implement delete customer here
// Return true on success, false on failure
}
public Customer findCustomer(...) {
// Implement find a customer here using supplied
// argument values as search criteria
// Return a Transfer Object if found,
// return null on error or if not found
}
public boolean updateCustomer(...) {
// implement update record here using data
// from the customerData Transfer Object
// Return true on success, false on failure or
// error
}
public RowSet selectCustomersRS(...) {
// implement search customers here using the
// supplied criteria.
// Return a RowSet.
}
public Collection selectCustomersTO(...) {
// implement search customers here using the
// supplied criteria.
// Alternatively, implement to return a Collection
// of Transfer Objects.
}
...
}

5 下面的代码是数据客户端向DAO中传输数据的, 他其实就是一个JAVABEAN;

public class Customer implements java.io.Serializable {
// member variables
int CustomerNumber;
String name;
String streetAddress;
String city;
...

// getter and setter methods...
...
}


6 最后就是客h据端对这个设计的应用:
...
// create the required DAO Factory
DAOFactory cloudscapeFactory =
DAOFactory.getDAOFactory(DAOFactory.DAOCLOUDSCAPE);
// Create a DAO
CustomerDAO custDAO =
cloudscapeFactory.getCustomerDAO();
// create a new customer
int newCustNo = custDAO.insertCustomer(...);
// Find a customer object. Get the Transfer Object.
Customer cust = custDAO.findCustomer(...);
// modify the values in the Transfer Object.
cust.setAddress(...);
cust.setEmail(...);
// update the customer object using the DAO
custDAO.updateCustomer(cust);
// delete a customer object
custDAO.deleteCustomer(...);
// select all customers in the same city
Customer criteria=new Customer();
criteria.setCity("New York");
Collection customersList =
custDAO.selectCustomersTO(criteria);
// returns customersList - collection of Customer
// Transfer Objects. iterate through this collection to
// get values.

a而简之,以下6步完成该模式的实玎ͼ

1 创徏一个抽象工厂类,他包含两个重要的部分: W一部分?一些抽象方?q些Ҏ是所有实现该抽象工厂的具体工厂类所必须实现? W二部分 是一个静态方?该方法来创徏一个具体类型数据源的工厂对?比如文中的CloudscapeDAOFactory().

2 然后,分别创徏各个cd数据源的工厂c?(本文以CloudscapeDAOFactoryZ).在这个工厂类中里面也有两个重要组成部? W一部分是实现在他l承的那个抽象工厂类中的左右抽象Ҏ,在该Ҏ中创建具体的DAO对象(q些对象的类在第4不具体定义实?,本文中三个方法分别创Z3个具体的DAO对象,当然Z实现l节的隐?q些Ҏq回的是q些具体DAOc门实现的接?q些接口在第3步实?.

3 定义具体DAOcȝ接口,q在接口中定义所有的业务Ҏ,和数据操作方?

4 定义具体的DAOc?在这个类中才是实际的业务Ҏ,和数据的操作的实?

5 定义数据传输对象,他是用来在客L和DAO之间传递数据的,他其实就是一个JAVABEAN.

6 完成以上5步之后我们就可以在数据客L使用以上由DAO设计模式定义好的各个cM(见最后一个代码例子块).

以上6步大家在~程的时需具体体会,一般来?数据库中的一个表可以对应一个数据传递类也就是在W?步中定义的那个类,cM的属性就是表中的字段,然后加上相应的GET,SET Ҏ. 然后再按模式和以上步骤来定义具体的类.

本文译自Qhttp://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

jegg

JAVA-J2EE-DESIGH PATTERN

׃n是力量Q?/div>


兵城下 2007-01-06 11:50 发表评论
]]>
关于Java文g路径问题Q{Q?http://m.tkk7.com/xuechen0721/articles/90805.html兵城下兵城下Fri, 29 Dec 2006 12:39:00 GMThttp://m.tkk7.com/xuechen0721/articles/90805.htmlhttp://m.tkk7.com/xuechen0721/comments/90805.htmlhttp://m.tkk7.com/xuechen0721/articles/90805.html#Feedback0http://m.tkk7.com/xuechen0721/comments/commentRss/90805.htmlhttp://m.tkk7.com/xuechen0721/services/trackbacks/90805.html 关于Java文g路径问题Q{Q?/a>
转自Q?a >http://blog.csdn.net/soleghost/archive/2006/04/27/679374.aspx

1.如何获得当前文g路径

常用Q?/font>

字符串类型:System.getProperty("user.dir");

l合Q?/font>

package com.zcjl.test.base;
import java.io.File;
public class Test {
    public static void main(String[] args) throws Exception {
        System.out.println(
            Thread.currentThread().getContextClassLoader().getResource(""));
        System.out.println(Test.class.getClassLoader().getResource(""));
        System.out.println(ClassLoader.getSystemResource(""));

        System.out.println(Test.class.getResource(""));
        System.out.println(Test.class.getResource("/"));


        System.out.println(new File("").getAbsolutePath());
        System.out.println(System.getProperty("user.dir"));

    }
}

file:/E:/workSpace/javaTest/target/classes/
file:/E:/workSpace/javaTest/target/classes/
file:/E:/workSpace/javaTest/target/classes/
file:/E:/workSpace/javaTest/target/classes/javaAPI/
file:/E:/workSpace/javaTest/target/classes/
E:\workSpace\javaTest
E:\workSpace\javaTest

 

2.Web服务?/font>

(1).Weblogic

WebApplication的系l文件根目录是你的weblogic安装所在根目录?br />例如Q如果你的weblogic安装在c:\bea\weblogic700.....
那么Q你的文件根路径是c:\.
所以,有两U方式能够让你访问你的服务器端的文gQ?br />a.使用l对路径Q?br />比如你的参数文件放在c:\yourconfig\yourconf.propertiesQ?br />直接使用 new FileInputStream("/yourconfig/yourconf.properties");
b.使用相对路径Q?br />相对路径的根目录是你的webapplication的根路径Q即WEB-INF的上一U目录,你的参数文件放在yourwebapp\yourconfig\yourconf.propertiesQ?br />q样使用Q?br />new FileInputStream("yourconfig/yourconf.properties");
q两U方式均可,自己选择?/font>

(2).Tomcat

在类中输出System.getProperty("user.dir");昄的是%Tomcat_Home%/bin

(3).Resin

不是你的JSP攄相对路径,是JSP引擎执行q个JSP~译成SERVLET
的\径ؓ?比如用新建文件法试File f = new File("a.htm");
q个a.htm在resin的安装目录下

(4).如何ȝ对\径哪Q?/font>

在Java文g中getResource或getResourceAsStream均可

例:getClass().getResourceAsStream(filePath);//filePath可以?/filename",q里?代表web发布根\径下WEB-INF/classes

也可?/font>getClass().getClassLoader().getResourceAsStream(filePath)//filePath不是带?”的

(5).获得文g真实路径

string  file_real_path=request.getRealPath("mypath/filename"); 

通常使用request.getRealPath("/"); 

 4.遗留问题

目前new FileInputStream()只会使用l对路径Q相?/font>


  InputStream in1 = new FileInputStream("abc1.properties"); // 相对路径
  InputStream in2 = new FileInputStream("/abc2.properties"); // l对路径QE盘下
  InputStream in3 = new FileInputStream("e://abc3.properties"); //相对路径

5.按Java文gcd分类d配置文g

?|文件是应用pȝ中不可缺的Q可以增加程序的灉|性。java.util.Properties是从jdk1.2有的类Q一直到现在都支持load ()ҎQjdk1.4以后save(output,string) ->store(output,string)。如果只是单U的读,Ҏ不存在烦恼的问题?font color="#ff0000">web层可以通过 Thread.currentThread().getContextClassLoader().
getResourceAsStream("xx.properties") 获取Q?/font>

Application可以通过new FileInputStream("xx.properties");直接在classes一U获取?/font>关键是有时我们需要通过web修改配置文gQ我们不 能将路径写死了。经q测试觉得有以下心得Q?/font>

1.servlet中读写。如果运用Struts 或者Servlet可以直接在初始化参数中配|,调用时根据servlet的getRealPath("/")获取真实路径Q再ҎString file = this.servlet.getInitParameter("abc");获取相对的WEB-INF的相对\径?br />例:
InputStream input = Thread.currentThread().getContextClassLoader().
getResourceAsStream("abc.properties");
Properties prop = new Properties();
prop.load(input);
input.close();
OutputStream out = new FileOutputStream(path);
prop.setProperty("abc", “test");
prop.store(out, “–test?);
out.close();

2.直接在jsp中操作,通过jsp内置对象获取可操作的l对地址?br />例:
// jsp面
String path = pageContext.getServletContext().getRealPath("/");
String realPath = path+"/WEB-INF/classes/abc.properties";

//java E序
InputStream in = getClass().getClassLoader().getResourceAsStream("abc.properties"); // abc.properties攑֜webroot/WEB-INF/classes/目录?br />prop.load(in);
in.close();

OutputStream out = new FileOutputStream(path); // path为通过面传入的\?br />prop.setProperty("abc", “abcccccc");
prop.store(out, “–test?);
out.close();

3.只通过JavaE序操作资源文g
InputStream in = new FileInputStream("abc.properties"); // 相对路径,目下的路径

OutputStream out = new FileOutputStream("abc.properties");



兵城下 2006-12-29 20:39 发表评论
]]>
TOMCAT配置技?0 http://m.tkk7.com/xuechen0721/articles/90584.html兵城下兵城下Thu, 28 Dec 2006 12:18:00 GMThttp://m.tkk7.com/xuechen0721/articles/90584.htmlhttp://m.tkk7.com/xuechen0721/comments/90584.htmlhttp://m.tkk7.com/xuechen0721/articles/90584.html#Feedback0http://m.tkk7.com/xuechen0721/comments/commentRss/90584.htmlhttp://m.tkk7.com/xuechen0721/services/trackbacks/90584.html TOMCAT配置技?0

1Q?配置pȝ理QAdmin Web ApplicationQ?/strong>

[被屏蔽广告]  大多数商业化的J2EE服务器都提供一个功能强大的理界面Q且大都采用易于理解的Web应用界面。Tomcat按照自己的方式,同样提供一个成熟的理工具Qƈ且丝毫不逊于那些商业化的竞争Ҏ。Tomcat的Admin Web Application最初在4.1版本时出玎ͼ当时的功能包括管理context、data source、user和group{。当然也可以理像初始化参数Quser、group、role的多U数据库理{。在后箋的版本中Q这些功能将得到很大的扩展,但现有的功能已经非常实用了?/p>

  Admin Web Application被定义在自动部v文gQCATALINA_BASE/webapps/admin.xml ?br />Q译者注QCATALINA_BASE即tomcat安装目录下的server目录Q?/p>

  你必ȝ辑这个文Ӟ以确定Context中的docBase参数是绝对\径。也是_CATALINA_BASE/webapps/admin.xml 的\径是l对路径。作为另外一U选择Q你也可以删除这个自动部|文Ӟ而在server.xml文g中徏立一个Admin Web Application的contextQ效果是一L。你不能理Admin Web Applicationq个应用Q换而言之,除了删除CATALINA_BASE/webapps/admin.xml Q你可能什么都做不了?/p>

  如果你用UserDatabaseRealmQ默认)Q你需要添加一个user以及一个role到CATALINA_BASE/conf/tomcat-users.xml 文g中。你~辑q个文gQ添加一个名叫“admin”的role 到该文g中,如下Q?/p>

<role name="admin"/>

  你同样需要有一个用Pq且q个用户的角色是“admin”。象存在的用户那Pd一个用P改变密码使其更加安全Q:

<user name="admin" password="deep_dark_secret" roles="admin"/>

  当你完成q些步骤后,请重新启动TomcatQ访问http://localhost:8080/adminQ你看C个登录界面。Admin Web Application采用Z容器理的安全机Ӟq用了Jakarta Struts框架。一旦你作ؓ“admin”角色的用户d理界面Q你能够用这个管理界面配|Tomcat?/p>

2Q配|应用管理(Manager Web ApplicationQ?/strong>

  Manager Web Application让你通过一个比Admin Web Application更ؓ单的用户界面Q执行一些简单的Web应用d?/p>

  Manager Web Application被被定义在一个自动部|文件中Q?/p>

  CATALINA_BASE/webapps/manager.xml ?/p>

  你必ȝ辑这个文Ӟ以确保context的docBase参数是绝对\径,也就是说CATALINA_HOME/server/webapps/manager的绝对\径?br />  Q译者注QCATALINA_HOME即tomcat安装目录Q?/p>

  如果你用的是UserDatabaseRealmQ那么你需要添加一个角色和一个用户到CATALINA_BASE/conf/tomcat-users.xml文g中。接下来Q编辑这个文Ӟd一个名为“manager”的角色到该文g中:

  <role name=”manager?gt;

  你同样需要有一个角色ؓ“manager”的用户。像已经存在的用户那Pd一个新用户Q改变密码其更加安全)Q?/p>

  <user name="manager" password="deep_dark_secret" roles="manager"/>

  然后重新启动TomcatQ访问http://localhost/manager/listQ将看到一个很朴素的文本型理界面Q或者访问http://localhost/manager/html/listQ将看到一个HMTL的管理界面。不是哪种方式都说明你的Manager Web Application现在已经启动了?/p>

  Manager application让你可以在没有系l管理特权的基础上,安装新的Web应用Q以用于试。如果我们有一个新的web应用位于/home/user/hello下在Qƈ且想把它安装?/hello下,Z试q个应用Q我们可以这么做Q在W一个文件框中输入?hello”(作ؓ讉K时的pathQ,在第二个文本框中输入“file:/home/user/hello”(作ؓConfig URLQ?/p>

  Manager applicationq允怽停止、重新启动、移除以及重新部|一个web应用。停止一个应用其无法被讉KQ当有用户尝试访问这个被停止的应用时Q将看到一?03的错误——?03 - This application is not currently available”?/p>

  U除一个web应用Q只是指从Tomcat的运行拷贝中删除了该应用Q如果你重新启动TomcatQ被删除的应用将再次出现Q也是_U除q不是指从硬盘上删除Q?br />

3Q部|一个web应用

  有两个办法可以在pȝ中部|web服务?/p>

  1> 拯你的WAR文g或者你的web应用文g夹(包括该web的所有内容)?CATALINA_BASE/webapps目录下?br />  2> Z的web服务建立一个只包括context内容的XML片断文gQƈ把该文g攑ֈ$CATALINA_BASE/webapps目录下。这个web应用本n可以存储在硬盘上的Q何地斏V?/p>

  如果你有一个WAR文gQ你若想部v它,则只需要把该文件简单的拯到CATALINA_BASE/webapps目录下即可,文g必须以?war”作为扩展名。一旦Tomcat监听到这个文Ӟ它将Q缺省的Q解开该文件包作ؓ一个子目录Qƈ以WAR文g的文件名作ؓ子目录的名字。接下来QTomcat在内存中徏立一个contextQ就好象你在server.xml文g里徏立一栗当Ӟ其他必需的内容,从server.xml中的DefaultContext获得?/p>

  部vweb应用的另一U方式是写一个Context XML片断文gQ然后把该文件拷贝到CATALINA_BASE/webapps目录下。一个Context片断q一个完整的XML文gQ而只是一个context元素Q以及对该应用的相应描述。这U片断文件就像是从server.xml中切取出来的context元素一P所以这U片断被命名为“context片断”?/p>

  举个例子Q如果我们想部v一个名叫MyWebApp.war的应用,该应用用realm作ؓ讉K控制方式Q我们可以用下面这个片断:

<!-- 
 Context fragment for deploying MyWebApp.war 
-->
<Context path="/demo" docBase="webapps/MyWebApp.war"
        debug="0" privileged="true">
 <Realm className="org.apache.catalina.realm.UserDatabaseRealm"               
        resourceName="UserDatabase"/>
</Context>

  把该片断命名为“MyWebApp.xml”,然后拯到CATALINA_BASE/webapps目录下?/p>

  q种context片断提供了一U便利的Ҏ来部|web应用Q你不需要编辑server.xmlQ除非你x变缺省的部vҎ,安装一个新的web应用时不需要重启动Tomcat?/p>


4Q配|虚拟主机(Virtual HostsQ?/strong>

  关于server.xml中“Host”这个元素,只有在你讄虚拟L的才需要修攏V虚拟主机是一U在一个web服务器上服务多个域名的机ӞҎ个域名而言Q都好象独n了整个主机。实际上Q大多数的小型商务网站都是采用虚拟主机实现的Q这主要是因拟主直接q接到Internetq提供相应的带宽Q以保障合理的访问响应速度Q另外虚拟主能提供一个稳定的固定IP?/p>

  Z名字的虚拟主机可以被建立在Q何web服务器上Q徏立的Ҏ是通过在域名服务器QDNSQ上建立IP地址的别名,q且告诉web服务器把d不同域名的请求分发到相应的网늛录。因文章主要是讲TomcatQ我们不准备介绍在各U操作系l上讄DNS的方法,如果你在q方面需要帮助,请参考《DNS and Bind》一书,作者是Paul Albitz and Cricket Liu (O'Reilly)。ؓ了示范方便,我将使用一个静态的L文gQ因是测试别名最单的Ҏ?br />在Tomcat中用虚拟主机,你需要设|DNS或主机数据。ؓ了测试,为本地IP讄一个IP别名p够了Q接下来Q你需要在server.xml中添加几行内容,如下Q?/p>

<Server port="8005" shutdown="SHUTDOWN" debug="0">
 <Service name="Tomcat-Standalone">
   <Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
port="8080" minProcessors="5" maxProcessors="75"
enableLookups="true" redirectPort="8443"/>
   <Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
port="8443" minProcessors="5" maxProcessors="75"
acceptCount="10" debug="0" scheme="https" secure="true"/>
     <Factory className="org.apache.coyote.tomcat4.CoyoteServerSocketFactory"
clientAuth="false" protocol="TLS" />
   </Connector>
   <Engine name="Standalone" defaultHost="localhost" debug="0">
     <!-- This Host is the default Host -->
     <Host name="localhost" debug="0" appBase="webapps"
     unpackWARs="true" autoDeploy="true">
       <Context path="" docBase="ROOT" debug="0"/>
       <Context path="/orders" docBase="/home/ian/orders" debug="0"
                      reloadable="true" crossContext="true">
       </Context>
     </Host>

     <!-- This Host is the first "Virtual Host": www.example.com -->
     <Host name="www.example.com" appBase="/home/example/webapp">
       <Context path="" docBase="."/>
     </Host>

   </Engine>
 </Service>
</Server>

  Tomcat的server.xml文gQ在初始状态下Q只包括一个虚拟主机,但是它容易被扩充到支持多个虚拟主机。在前面的例子中展示的是一个简单的server.xml版本Q其中粗体部分就是用于添加一个虚拟主机。每一个Host元素必须包括一个或多个context元素Q所包含的context元素中必L一个是默认的contextQ这个默认的context的显C\径应该ؓI(例如Qpath=””)?/p>

5Q配|基验证QBasic AuthenticationQ?/strong>

  容器理验证Ҏ控制着当用戯问受保护的web应用资源Ӟ如何q行用户的n份鉴别。当一个web应用使用了Basic AuthenticationQBASIC参数在web.xml文g中auto-method元素中设|)Q而有用户讉K受保护的web应用ӞTomcat通过HTTP Basic Authentication方式Q弹Z个对话框Q要求用戯入用户名和密码。在q种验证Ҏ中,所有密码将被以64位的~码方式在网l上传输?/p>

  注意Q用Basic Authentication通过被认为是不安全的Q因为它没有强健的加密方法,除非在客L和服务器端都使用HTTPS或者其他密码加密码方式Q比如,在一个虚拟私人网l中Q。若没有额外的加密方法,|络理员将能够截获Q或滥用Q用L密码。但是,如果你是刚开始用TomcatQ或者你惛_你的web应用中测试一下基于容器的安全理QBasic Authenticationq是非常易于讄和用的。只需要添?lt;security-constraint>?lt;login-config>两个元素C的web应用的web.xml文g中,q且在CATALINA_BASE/conf/tomcat-users.xml 文g中添加适当?lt;role>?lt;user>卛_Q然后重新启动Tomcat?/p>

  下面例子中的web.xml摘自一个俱乐部会员|站pȝQ该pȝ中只有member目录被保护v来,q用Basic Authenticationq行w䆾验证。请注意Q这U方式将有效的代替Apache web服务器中?htaccess文g?/p>

<!--
 Define the Members-only area, by defining
 a "Security Constraint" on this Application, and
 mapping it to the subdirectory (URL) that we want
 to restrict.
-->
<security-constraint>
 <web-resource-collection>
   <web-resource-name>
     Entire Application
   </web-resource-name>
   <url-pattern>/members/*</url-pattern>
 </web-resource-collection>
 <auth-constraint>
     <role-name>member</role-name>
 </auth-constraint>
</security-constraint>
<!-- Define the Login Configuration for this Application -->
<login-config>
 <auth-method>BASIC</auth-method>
 <realm-name>My Club Members-only Area</realm-name>
</login-config>

6Q配|单点登录(Single Sign-OnQ?/strong>

  一旦你讄了realm和验证的ҎQ你需要进行实际的用户d处理。一般说来,对用戯言dpȝ是一件很ȝ的事情,你必d量减用L录验证的ơ数。作为缺省的情况Q当用户W一ơ请求受保护的资源时Q每一个web应用都会要求用户d。如果你q行了多个web应用Qƈ且每个应用都需要进行单独的用户验证Q那q看h有点像你在与你的用h斗。用户们不知道怎样才能把多个分ȝ应用整合成一个单独的pȝQ所有他们也׃知道他们需要访问多个不同的应用,只是很迷惑,Z么总要不停的登录?/p>

  Tomcat 4的“single sign-on”特性允许用户在讉K同一虚拟L下所有web应用Ӟ只需d一ơ。ؓ了用这个功能,你只需要在Host上添加一个SingleSignOn Valve元素卛_Q如下所C:

<Valve className="org.apache.catalina.authenticator.SingleSignOn"
      debug="0"/>

  在Tomcat初始安装后,server.xml的注释里面包括SingleSignOn Valve配置的例子,你只需要去掉注释,卛_使用。那么,M用户只要dq一个应用,则对于同一虚拟L下的所有应用同h效?/p>

  使用single sign-on valve有一些重要的限制Q?/p>

  1> value必须被配|和嵌套在相同的Host元素里,q且所有需要进行单炚w证的web应用Q必通过context元素定义Q都位于该Host下?br />  2> 包括׃n用户信息的realm必须被设|在同一UHost中或者嵌套之外?br />  3> 不能被context中的realm覆盖?br />  4> 使用单点d的web应用最好用一个Tomcat的内|的验证方式Q被定义在web.xml中的<auth-method>中)Q这比自定义的验证方式强QTomcat内置的的验证方式包括basic、digest、form和client-cert?br />  5> 如果你用单点登录,q希望集成一个第三方的web应用C的网站中来,q且q个新的web应用使用它自q验证方式Q而不使用容器理安全Q那你基本上没招了。你的用hơ登录原来所有应用时需要登录一ơ,q且在请求新的第三方应用时还得再d一ơ。当Ӟ如果你拥有这个第三方web应用的源码,而你又是一个程序员Q你可以修改它,但那恐怕也不容易做?br />  6> 单点d需要用cookies?/p>

7Q配|用户定制目录(Customized User DirectoresQ?/strong>

  一些站点允怸别用户在服务器上发布|页。例如,一所大学的学院可能想l每一位学生一个公共区域,或者是一个ISP希望l一些webI间l他的客P但这又不是虚拟主机。在q种情况下,一个典型的Ҏ是在用户名前面加一个特D字W(~Q,作ؓ每位用户的网站,比如Q?/p>

http://www.cs.myuniversity.edu/~username
http://members.mybigisp.com/~username

  Tomcat提供两种Ҏ在主Z映射q些个h|站Q主要用一对特D的Listener元素。Listener的className属性应该是org.apache.catalina.startup.UserConfigQuserClass属性应该是几个映射cM一。如果你的系l是UnixQ它有一个标准的/etc/passwd文gQ该文g中的帐号能够被运行中的Tomcat很容易的dQ该文g指定了用Lȝ录,使用PasswdUserDatabase 映射cR?/p>

<Listener className="org.apache.catalina.startup.UserConfig"
directoryName="public_html"
userClass="org.apache.catalina.startup.PasswdUserDatabase"/>

  web文g需要放|在?home/users/ian/public_html 或?/users/jbrittain/public_html一L目录下面。当然你也可以改变public_html 到其他Q何子目录下?/p>

  实际上,q个用户目录Ҏ不一定需要位于用户主目录下里面。如果你没有一个密码文Ӟ但你又想把一个用户名映射到公q?home一L录的子目录里面,则可以用HomesUserDatabasecR?/p>

<Listener className="org.apache.catalina.startup.UserConfig"
directoryName="public_html" homeBase="/home"
userClass="org.apache.catalina.startup.HomesUserDatabase"/>

  q样一来,web文g可以位于像/home/ian/public_html 或?/home/jasonb/public_html一L目录下。这UŞ式对Windows而言更加有利Q你可以使用一个像c:\homeq样的目录?/p>

  q些Listener元素Q如果出玎ͼ则必dHost元素里面Q而不能在context元素里面Q因为它们都用应用于Host本n?/p>

8Q在Tomcat中用CGI脚本

  Tomcat主要是作为Servlet/JSP容器Q但它也有许多传lweb服务器的性能。支持通用|关接口QCommon Gateway InterfaceQ即CGIQ就是其中之一QCGI提供一l方法在响应览器请求时q行一些扩展程序。CGI之所以被UCؓ通用Q是因ؓ它能在大多数E序或脚本中被调用,包括QPerlQPythonQawkQUnix shell scripting{,甚至包括Java。当Ӟ你大概不会把一个Java应用E序当作CGI来运行,毕竟q样太过原始。一般而言Q开发Servlet总要比CGIh更好的效率,因ؓ当用LM个链接或一个按钮时Q你不需要从操作pȝ层开始进行处理?/p>

  Tomcat包括一个可选的CGI ServletQ允怽q行遗留下来的CGI脚本?/p>

  Z使Tomcat能够q行CGIQ你必须做如下几件事Q?/p>

  1. 把servlets-cgi.renametojar Q在CATALINA_HOME/server/lib/目录下)改名为servlets-cgi.jar。处理CGI的servlet应该位于Tomcat的CLASSPATH下?br />  2. 在Tomcat的CATALINA_BASE/conf/web.xml 文g中,把关?lt;servlet-name> CGI的那D늚注释LQ默认情况下Q该D位于第241行)?br />  3. 同样Q在Tomcat的CATALINA_BASE/conf/web.xml文g中,把关于对CGIq行映射的那D늚注释LQ默认情况下Q该D位于第299行)。注意,q段内容指定了HTML链接到CGI脚本的访问方式?br />  4. 你可以把CGI脚本攄在WEB-INF/cgi 目录下(注意QWEB-INF是一个安全的地方Q你可以把一些不惌用户看见或基于安全考虑不想暴露的文件放在此处)Q或者你也可以把CGI脚本攄在context下的其他目录下,qؓCGI Servlet调整cgiPathPrefix初始化参数。这指定的CGI Servlet的实际位|,且不能与上一步指定的URL重名?br />  5. 重新启动TomcatQ你的CGI可以运行了?/p>

  在Tomcat中,CGIE序~省攄在WEB-INF/cgi目录下,正如前面所提示的那PWEB-INF目录受保护的Q通过客户端的览器无法窥探到其中内容Q所以对于放|含有密码或其他敏感信息的CGI脚本而言Q这是一个非常好的地斏Vؓ了兼容其他服务器Q尽你也可以把CGI脚本保存在传l的/cgi-bin目录Q但要知道,在这些目录中的文件有可能被网上好奇的冲浪者看到。另外,在Unix中,L定运行Tomcat的用h执行CGI脚本的权限?/p>

9Q改变Tomcat中的JSP~译器(JSP CompilerQ?/strong>

  在Tomcat 4.1Q或更高版本Q大概)QJSP的编译由包含在Tomcat里面的AntE序控制器直接执行。这听v来有一点点奇怪,但这正是Ant有意Z的一部分Q有一个API文指导开发者在没有启动一个新的JVM的情况下Q用Ant。这是用Antq行Java开发的一大优ѝ另外,q也意味着你现在能够在Ant中用Q何javac支持的编译方式,q里有一个关于Apache Ant使用手册的javac page列表。用v来是Ҏ的,因ؓ你只需要在<init-param> 元素中定义一个名字叫“compiler”,q且在value中有一个支持编译的~译器名字,CZ如下Q?/p>

<servlet>
   <servlet-name>jsp</servlet-name>
   <servlet-class>
     org.apache.jasper.servlet.JspServlet
   </servlet-class>
   <init-param>
     <param-name>logVerbosityLevel</param-name>
     <param-value>WARNING</param-value>
   </init-param>
   <init-param>
     <param-name>compiler</param-name>
     <param-value>jikes</param-value>
   </init-param>
   <load-on-startup>3</load-on-startup>
</servlet>

  当然Q给出的~译器必dl安装在你的pȝ中,q且CLASSPATH可能需要设|,那处决于你选择的是何种~译器?/p>

10Q限制特定主问(Restricting Access to Specific HostsQ?/strong>

  有时Q你可能想限制对Tomcat web应用的访问,比如Q你希望只有你指定的L或IP地址可以讉K你的应用。这样一来,只有那些指定的的客L可以讉K服务的内容了。ؓ了实现这U效果,Tomcat提供了两个参C你配|:RemoteHostValve 和RemoteAddrValve?/p>

  通过配置q两个参敎ͼ可以让你qo来自h的主机或IP地址Qƈ允许或拒l哪些主?IP。与之类似的Q在Apache的httpd文g里有Ҏ个目录的允许/拒绝指定?br />例如你可以把Admin Web application讄成只允许本地讉KQ设|如下:

<Context path="/path/to/secret_files" ...>
 <Valve className="org.apache.catalina.valves.RemoteAddrValve"
        allow="127.0.0.1" deny=""/>
</Context>

  如果没有l出允许L的指定,那么与拒l主机匹配的L׃被拒l,除此之外的都是允许的。与之类|如果没有l出拒绝L的指定,那么与允怸机匹配的L׃被允许,除此之外的都是拒l的?/p>

兵城下 2006-12-28 20:18 发表评论
]]>
java 操作 excelQ引用自IBMQ?/title><link>http://m.tkk7.com/xuechen0721/articles/87375.html</link><dc:creator>兵城下</dc:creator><author>兵城下</author><pubDate>Wed, 13 Dec 2006 00:47:00 GMT</pubDate><guid>http://m.tkk7.com/xuechen0721/articles/87375.html</guid><wfw:comment>http://m.tkk7.com/xuechen0721/comments/87375.html</wfw:comment><comments>http://m.tkk7.com/xuechen0721/articles/87375.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/xuechen0721/comments/commentRss/87375.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/xuechen0721/services/trackbacks/87375.html</trackback:ping><description><![CDATA[ <p> <a name="1"> <span id="bdbr1r5" class="atitle"> <font face="Arial" size="4">JAVA EXCEL API?/font> </span> </a> </p> <p> <font face="Arial" size="4"> </font> </p> <p>Java Excel是一开放源码项目,通过它Java开发h员可以读取Excel文g的内宏V创建新的Excel文g、更新已l存在的Excel文g。用该API非Windows操作pȝ也可以通过UJava应用来处理Excel数据表。因为是使用Java~写的,所以我们在Web应用中可以通过JSP、Servlet来调用API实现对Excel数据表的讉K?/p> <p>现在发布的稳定版本是V2.0Q提供以下功能:</p> <ul> <li>从Excel 95?7?000{格式的文g中读取数据; </li> <li>dExcel公式Q可以读取Excel 97以后的公式)Q? </li> <li>生成Excel数据表(格式为Excel 97Q; </li> <li>支持字体、数字、日期的格式化; </li> <li>支持单元格的阴媄操作Q以及颜色操作; </li> <li>修改已经存在的数据表Q?</li> </ul> <p>现在q不支持以下功能Q但不久׃提供了:</p> <ol> <li>不能够读取图表信息; </li> <li>可以读,但是不能生成公式QQ何类型公式最后的计算值都可以dQ?</li> </ol> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /> <br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /> </td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td> <img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> <br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="center"> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /> <br /> </td> <td valign="top" align="right"> <a class="fbox" > <b> <font color="#996699">回页?/font> </b> </a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p> <a name="2"> <span id="3ppdf1v" class="atitle"> <font face="Arial" size="4">应用CZ</font> </span> </a> </p> <p> <font face="Arial" size="4"> </font> </p> <p> <a name="N1006F"> <span id="lrxlpvh" class="smalltitle"> <strong> <font face="Arial">1 从Excel文gd数据?/font> </strong> </span> </a> </p> <p> <strong> <font face="Arial"> </font> </strong> </p> <p>Java Excel API既可以从本地文gpȝ的一个文?.xls)Q也可以从输入流中读取Excel数据表。读取Excel数据表的W一步是创徏Workbook(术语Q工作薄)Q下面的代码片段举例说明了应该如何操作:(完整代码见ExcelReading.java)</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">import java.io.*; import jxl.*; ???? try { //构徏Workbook对象, 只读Workbook对象 //直接从本地文件创建Workbook //从输入流创徏Workbook InputStream is = new FileInputStream(sourcefile); jxl.Workbook rwb = Workbook.getWorkbook(is); } catch (Exception e) { e.printStackTrace(); } </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>一旦创ZWorkbookQ我们就可以通过它来讉KExcel Sheet(术语Q工作表)。参考下面的代码片段Q?/p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">//获取W一张Sheet? Sheet rs = rwb.getSheet(0); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>我们既可能通过Sheet的名U来讉K它,也可以通过下标来访问它。如果通过下标来访问的话,要注意的一Ҏ下标?开始,像数组一栗?/p> <p>一旦得CSheetQ我们就可以通过它来讉KExcel Cell(术语Q单元格)。参考下面的代码片段Q?/p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">//获取W一行,W一列的? Cell c00 = rs.getCell(0, 0); String strc00 = c00.getContents(); //获取W一行,W二列的? Cell c10 = rs.getCell(1, 0); String strc10 = c10.getContents(); //获取W二行,W二列的? Cell c11 = rs.getCell(1, 1); String strc11 = c11.getContents(); System.out.println("Cell(0, 0)" + " value : " + strc00 + "; type : " + c00.getType()); System.out.println("Cell(1, 0)" + " value : " + strc10 + "; type : " + c10.getType()); System.out.println("Cell(1, 1)" + " value : " + strc11 + "; type : " + c11.getType()); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>如果仅仅是取得Cell的|我们可以方便地通过getContents()ҎQ它可以Q何类型的Cell值都作ؓ一个字W串q回。示例代码中Cell(0, 0)是文本型QCell(1, 0)是数字型QCell(1,1)是日期型Q通过getContents()Q三U类型的q回值都是字W型?/p> <p>如果有需要知道Cell内容的确切类型,API也提供了一pd的方法。参考下面的代码片段Q?/p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">String strc00 = null; double strc10 = 0.00; Date strc11 = null; Cell c00 = rs.getCell(0, 0); Cell c10 = rs.getCell(1, 0); Cell c11 = rs.getCell(1, 1); if(c00.getType() == CellType.LABEL) { LabelCell labelc00 = (LabelCell)c00; strc00 = labelc00.getString(); } if(c10.getType() == CellType.NUMBER) { NmberCell numc10 = (NumberCell)c10; strc10 = numc10.getValue(); } if(c11.getType() == CellType.DATE) { DateCell datec11 = (DateCell)c11; strc11 = datec11.getDate(); } System.out.println("Cell(0, 0)" + " value : " + strc00 + "; type : " + c00.getType()); System.out.println("Cell(1, 0)" + " value : " + strc10 + "; type : " + c10.getType()); System.out.println("Cell(1, 1)" + " value : " + strc11 + "; type : " + c11.getType()); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>在得到Cell对象后,通过getType()Ҏ可以获得该单元格的类型,然后与API提供的基本类型相匚wQ强制{换成相应的类型,最后调用相应的取值方法getXXX()Q就可以得到定cd的倹{API提供了以下基本类型,与Excel的数据格式相对应Q如下图所C:</p> <br /> <img height="218" alt="" src="http://www-128.ibm.com/developerworks/cn/java/l-javaExcel/image001.jpg" width="365" /> <br /> <p>每种cd的具体意义,请参见Java Excel API Document?/p> <p>当你完成对Excel电子表格数据的处理后Q一定要使用close()Ҏ来关闭先前创建的对象Q以释放d数据表的q程中所占用的内存空_在读取大量数据时昑־ؓ重要。参考如下代码片D:</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">//操作完成Ӟ关闭对象Q释攑֍用的内存I间 rwb.close(); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>Java Excel API提供了许多访问Excel数据表的ҎQ在q里我只要地介绍几个常用的方法,其它的方法请参考附录中的Java Excel API Document?/p> <p> <b>WorkbookcL供的Ҏ</b> </p> <p>1. int getNumberOfSheets() <br />获得工作薄(WorkbookQ中工作表(SheetQ的个数Q示例: </p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); int sheets = rwb.getNumberOfSheets(); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>2. Sheet[] getSheets() <br />q回工作薄(WorkbookQ中工作表(SheetQ对象数l,CZQ?</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); Sheet[] sheets = rwb.getSheets(); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>3. String getVersion() <br />q回正在使用的API的版本号Q好像是没什么太大的作用?</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); String apiVersion = rwb.getVersion(); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p> <b>Sheet接口提供的方?/b> </p> <p>1) String getName() <br />获取Sheet的名UͼCZQ?</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); String sheetName = rs.getName(); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>2) int getColumns() <br />获取Sheet表中所包含的d敎ͼCZQ?</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); int rsColumns = rs.getColumns(); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>3) Cell[] getColumn(int column) <br />获取某一列的所有单元格Q返回的是单元格对象数组Q示例: </p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); Cell[] cell = rs.getColumn(0); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>4) int getRows() <br />获取Sheet表中所包含的总行敎ͼCZQ?</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); int rsRows = rs.getRows(); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>5) Cell[] getRow(int row) <br />获取某一行的所有单元格Q返回的是单元格对象数组Q示例子Q?</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); Cell[] cell = rs.getRow(0); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>6) Cell getCell(int column, int row) <br />获取指定单元格的对象引用Q需要注意的是它的两个参敎ͼW一个是列数Q第二个是行敎ͼq与通常的行、列l合有些不同?</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile)); jxl.Sheet rs = rwb.getSheet(0); Cell cell = rs.getCell(0, 0); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p> <a name="N10114"> <span id="pzznbzn" class="smalltitle"> <strong> <font face="Arial">2 生成新的Excel工作?/font> </strong> </span> </a> </p> <p> <strong> <font face="Arial"> </font> </strong> </p> <p>下面的代码主要是向大家介l如何生成简单的Excel工作表,在这里单元格的内Ҏ不带M修饰?如:字体Q颜色等{?Q所有的内容都作为字W串写入?完整代码见ExcelWriting.java)</p> <p>与读取Excel工作表相|首先要用Workbookcȝ工厂Ҏ创徏一个可写入的工作薄(Workbook)对象Q这里要注意的是Q只能通过API提供的工厂方法来创徏WorkbookQ而不能用WritableWorkbook的构造函敎ͼ因ؓcWritableWorkbook的构造函Cؓprotectedcd。示例代码片D如下:</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">import java.io.*; import jxl.*; import jxl.write.*; ???? try { //构徏Workbook对象, 只读Workbook对象 //Method 1Q创建可写入的Excel工作? jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile)); //Method 2Q将WritableWorkbook直接写入到输出流 /* OutputStream os = new FileOutputStream(targetfile); jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(os); */ } catch (Exception e) { e.printStackTrace(); } </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>API提供了两U方式来处理可写入的输出,一U是直接生成本地文gQ如果文件名不带全\径的话,~省的文件会定位在当前目录,如果文g名带有全路径的话Q则生成的Excel文g则会定位在相应的目录Q另外一U是Excel对象直接写入到输出流Q例如:用户通过览器来讉KWeb服务器,如果HTTP头设|正的话,览器自动调用客L的Excel应用E序Q来昄动态生成的Excel电子表格?/p> <p>接下来就是要创徏工作表,创徏工作表的Ҏ与创建工作薄的方法几乎一P同样是通过工厂模式Ҏ获得相应的对象,该方法需要两个参敎ͼ一个是工作表的名称Q另一个是工作表在工作薄中的位|,参考下面的代码片段Q?/p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">//创徏Excel工作? jxl.write.WritableSheet ws = wwb.createSheet("Test Sheet 1", 0); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>"q锅也支好了Q材料也准备齐全了,可以开始下锅了Q?Q现在要做的只是实例化API所提供的Excel基本数据cdQƈ它们添加到工作表中可以了Q参考下面的代码片段Q?/p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">//1.dLabel对象 jxl.write.Label labelC = new jxl.write.Label(0, 0, "This is a Label cell"); ws.addCell(labelC); //d带有字型Formatting的对? jxl.write.WritableFont wf = new jxl.write.WritableFont(WritableFont.TIMES, 18, WritableFont.BOLD, true); jxl.write.WritableCellFormat wcfF = new jxl.write.WritableCellFormat(wf); jxl.write.Label labelCF = new jxl.write.Label(1, 0, "This is a Label Cell", wcfF); ws.addCell(labelCF); //d带有字体颜色Formatting的对? jxl.write.WritableFont wfc = new jxl.write.WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE, jxl.format.Colour.RED); jxl.write.WritableCellFormat wcfFC = new jxl.write.WritableCellFormat(wfc); jxl.write.Label labelCFC = new jxl.write.Label(1, 0, "This is a Label Cell", wcfFC); ws.addCell(labelCF); //2.dNumber对象 jxl.write.Number labelN = new jxl.write.Number(0, 1, 3.1415926); ws.addCell(labelN); //d带有formatting的Number对象 jxl.write.NumberFormat nf = new jxl.write.NumberFormat("#.##"); jxl.write.WritableCellFormat wcfN = new jxl.write.WritableCellFormat(nf); jxl.write.Number labelNF = new jxl.write.Number(1, 1, 3.1415926, wcfN); ws.addCell(labelNF); //3.dBoolean对象 jxl.write.Boolean labelB = new jxl.write.Boolean(0, 2, false); ws.addCell(labelB); //4.dDateTime对象 jxl.write.DateTime labelDT = new jxl.write.DateTime(0, 3, new java.util.Date()); ws.addCell(labelDT); //d带有formatting的DateFormat对象 jxl.write.DateFormat df = new jxl.write.DateFormat("dd MM yyyy hh:mm:ss"); jxl.write.WritableCellFormat wcfDF = new jxl.write.WritableCellFormat(df); jxl.write.DateTime labelDTF = new jxl.write.DateTime(1, 3, new java.util.Date(), wcfDF); ws.addCell(labelDTF); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>q里有两点大家要引v大家的注意。第一点,在构造单元格Ӟ单元格在工作表中的位|就已经定了。一旦创建后Q单元格的位|是不能够变更的Q尽单元格的内Ҏ可以改变的。第二点Q单元格的定位是按照下面q样的规?column, row)Q而且下标都是?开始,例如QA1被存储在(0, 0)QB1被存储在(1, 0)?/p> <p>最后,不要忘记关闭打开的Excel工作薄对象,以释攑֍用的内存Q参见下面的代码片段Q?/p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">//写入Exel工作? wwb.write(); //关闭Excel工作薄对? wwb.close(); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>q可能与dExcel文g的操作有少不同Q在关闭Excel对象之前Q你必须要先调用write()ҎQ因为先前的操作都是存储在缓存中的,所以要通过该方法将操作的内容保存在文g中。如果你先关闭了Excel对象Q那么只能得C张空的工作薄了?/p> <p> <a name="N10144"> <span id="t1rr77h" class="smalltitle"> <strong> <font face="Arial">3 拯、更新Excel工作?/font> </strong> </span> </a> </p> <p>接下来简要介l一下如何更C个已l存在的工作薄,主要是下面二步操作,W一步是构造只ȝExcel工作薄,W二步是利用已经创徏的Excel工作薄创建新的可写入的Excel工作薄,参考下面的代码片段Q?完整代码见ExcelModifying.java)</p> <table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"> <tbody> <tr> <td> <pre> <code class="section"> <font face="Lucida Console">//创徏只读的Excel工作薄的对象 jxl.Workbook rw = jxl.Workbook.getWorkbook(new File(sourcefile)); //创徏可写入的Excel工作薄对? jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile), rw); //dW一张工作表 jxl.write.WritableSheet ws = wwb.getSheet(0); //获得W一个单元格对象 jxl.write.WritableCell wc = ws.getWritableCell(0, 0); //判断单元格的cd, 做出相应的{? if(wc.getType() == CellType.LABEL) { Label l = (Label)wc; l.setString("The value has been modified."); } //写入Excel对象 wwb.write(); //关闭可写入的Excel对象 wwb.close(); //关闭只读的Excel对象 rw.close(); </font> </code> </pre> </td> </tr> </tbody> </table> <br /> <p>之所以用这U方式构建Excel对象Q完全是因ؓ效率的原因,因ؓ上面的示例才是API的主要应用。ؓ了提高性能Q在d工作表时Q与数据相关的一些输Z息,所有的格式信息Q如Q字体、颜色等{,是不被处理的Q因为我们的目的是获得行数据的|既没有了修饎ͼ也不会对行数据的g生什么媄响。唯一的不利之处就是,在内存中会同时保存两个同L工作表,q样当工作表体积比较大时Q会占用相当大的内存Q但现在好像内存的大ƈ不是什么关键因素了?/p> <p>一旦获得了可写入的工作表对象,我们可以对单元格对象进行更新的操作了,在这里我们不必调用API提供的add()ҎQ因为单元格已经于工作表当中Q所以我们只需要调用相应的setXXX()ҎQ就可以完成更新的操作了?/p> <p>单元格原有的格式化修饰是不能去掉的Q我们还是可以将新的单元g饰加上去Q以使单元格的内容以不同的Ş式表现?/p> <p>新生成的工作表对象是可写入的Q我们除了更新原有的单元格外Q还可以d新的单元格到工作表中Q这与示?的操作是完全一L?/p> <p>最后,不要忘记调用write()ҎQ将更新的内容写入到文g中,然后关闭工作薄对象,q里有两个工作薄对象要关闭,一个是只读的,另外一个是可写入的?/p> <img src ="http://m.tkk7.com/xuechen0721/aggbug/87375.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/xuechen0721/" target="_blank">兵城下</a> 2006-12-13 08:47 <a href="http://m.tkk7.com/xuechen0721/articles/87375.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EditPlus使用http://m.tkk7.com/xuechen0721/articles/87130.html兵城下兵城下Tue, 12 Dec 2006 01:24:00 GMThttp://m.tkk7.com/xuechen0721/articles/87130.htmlhttp://m.tkk7.com/xuechen0721/comments/87130.htmlhttp://m.tkk7.com/xuechen0721/articles/87130.html#Feedback0http://m.tkk7.com/xuechen0721/comments/commentRss/87130.htmlhttp://m.tkk7.com/xuechen0721/services/trackbacks/87130.html其实EditPlus不但有编辑程序的功能Q还有灵zȝ~译功能Q下面就单介l一下EditPlus对JAVA的编译设|?br />实现对JAVA的编?br />在配|EditPlus之前Q我们先要将JAVA的运行环境安装ƈ且调试好Q这里我׃再说明了?br />首先Q从菜单“工PToolsQ?“配|用户工?..”进入用户工兯|?br />在类别里展开“工具”树形菜?“用户工具”,选择“组和工具项目”中的“Group 1”,点击面板双的“组名称...”按钮,文本Group1”修Ҏ“编译JAVAE序”?br />然后选择修改的组“编译JAVAE序”,点击“添加新工具”按钮,选择E序Q徏立“新建程序”,选中它?br />然后是最重要的步骤(修改属性)Q?br />1.1 d~译功能
“菜单文字”里的内容修改ؓ“JAVAC”;
“命令”选择安装JDK后的BIN目录中的~译E序JAVAC.EXEQ如果JDK 安装路径为“c:\jdk”,那么此\径ؓ“c:\jdk\bin\javac.exe”;
“参数”选择“文件名U”,xCZؓ?(FileName)”;
“初始目录”选择“文件目录”,昄为?(FileDir)”;选择“捕莯出”复选框?br />1.2 d执行功能
“菜单文字”里的内容修改ؓ“JAVA”;
“命令”选择安装JDK后的BIN目录中的~译E序JAVA.EXEQ\径ؓ“c:\jdk\bin\java.exe”;
“参数”选择“文件名Q不含扩展名Q”,xCZؓ?(FileNameNoExt)”;
“初始目录”选择“文件目录”,昄为?(FileDir)”;选择“捕莯出”复选框?br />q样完成了基本的配|工作,下面来试着~写一个JAVAE序来测试一下(如图Q,~译的所有信息都会显C在输出H口中,双击某一行错误信息,EditPlus会自动定位到出错?
转自Q?a >http://www.neeao.com/blog/article.asp?id=2400Q?img src ="http://m.tkk7.com/xuechen0721/aggbug/87130.html" width = "1" height = "1" />

兵城下 2006-12-12 09:24 发表评论
]]>
Java基础Q关于session的详l解释(转蝲Q?/title><link>http://m.tkk7.com/xuechen0721/articles/44967.html</link><dc:creator>兵城下</dc:creator><author>兵城下</author><pubDate>Mon, 08 May 2006 03:05:00 GMT</pubDate><guid>http://m.tkk7.com/xuechen0721/articles/44967.html</guid><wfw:comment>http://m.tkk7.com/xuechen0721/comments/44967.html</wfw:comment><comments>http://m.tkk7.com/xuechen0721/articles/44967.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/xuechen0721/comments/commentRss/44967.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/xuechen0721/services/trackbacks/44967.html</trackback:ping><description><![CDATA[ <p>一、术语session <br />  在我的经验里Qsessionq个词被滥用的程度大概仅ơ于transactionQ更加有的是transaction与session在某些语境下的含义是相同的?/p> <p>  sessionQ中文经常翻译ؓ会话Q其本来的含义是指有始有l的一pd动作/消息Q比如打电话时从拿v电话拨号到挂断电话这中间的一pdq程可以UCZ个session。有时候我们可以看到这L话“在一个浏览器会话期间Q?..”,q里的会话一词用的就是其本义Q是指从一个浏览器H口打开到关闭这个期间①。最混ؕ的是“用P客户端)在一ơ会话期间”这样一句话Q它可能指用L一pd动作Q一般情况下是同某个具体目的相关的一pd动作Q比如从d到选购商品到结账登样一个网上购物的q程Q有时候也被称Z个transactionQ,然而有时候也可能仅仅是指一ơ连接,也有可能是指含义①,其中的差别只能靠上下文来推断②?/p> <p>  然而当session一词与|络协议相关联时Q它又往往隐含了“面向连接”和/或“保持状态”这样两个含义,“面向连接”指的是在通信双方在通信之前要先建立一个通信的渠道,比如打电话,直到Ҏ接了电话通信才能开始,与此相对的是写信Q在你把信发出去的时候你q不能确认对方的地址是否正确Q通信渠道不一定能建立Q但对发信h来说Q通信已经开始了。“保持状态”则是指通信的一方能够把一pd的消息关联v来,使得消息之间可以互相依赖Q比如一个服务员能够认出再次光的老顾客ƈ且记得上ơ这个顾客还Ơ店里一块钱。这一cȝ例子有“一个TCP session”或者“一个POP3 session”③?/p> <p>  而到了web服务器蓬勃发展的时代Qsession在web开发语境下的语义又有了新的扩展Q它的含义是指一cȝ来在客户端与服务器之间保持状态的解决Ҏ④。有时候session也用来指q种解决Ҏ的存储结构,如“把xxx保存在session里”⑤。由于各U用于web开发的语言在一定程度上都提供了对这U解x案的支持Q所以在某种特定语言的语境下Qsession也被用来指代该语a的解x案,比如l常把Java里提供的javax.servlet.http.HttpSessionUCؓsession⑥?/p> <p>  鉴于q种混ؕ已不可改变,本文中session一词的q用也会Ҏ上下文有不同的含义,请大家注意分辨?/p> <p>  在本文中Q用中文“浏览器会话期间”来表达含义①,使用“session机制”来表达含义④,使用“session”表辑֐义⑤Q用具体的“HttpSession”来表达含义?/p> <p>  二、HTTP协议与状态保?/p> <p>  HTTP协议本n是无状态的Q这与HTTP协议本来的目的是相符的,客户端只需要简单的向服务器h下蝲某些文gQ无论是客户端还是服务器都没有必要纪录彼此过ȝ行ؓQ每一ơ请求之间都是独立的Q好比一个顾客和一个自动售货机或者一个普通的Q非会员Ӟ大卖Z间的关系一栗?/p> <p>  然而聪明(或者贪心?Q的Z很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用Q就像给有线电视加上Ҏ功能一栗这U需求一斚wqHTML逐步d了表单、脚本、DOM{客L行ؓQ另一斚w在服务器端则出现了CGI规范以响应客L的动态请求,作ؓ传输载体的HTTP协议也添加了文g上蝲、cookieq些Ҏ。其中cookie的作用就是ؓ了解决HTTP协议无状态的~陷所作出的努力。至于后来出现的session机制则是又一U在客户端与服务器之间保持状态的解决Ҏ?/p> <p>  让我们用几个例子来描qC下cookie和session机制之间的区别与联系。笔者曾l常ȝ一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠Q然而一ơ性消?杯咖啡的Z微乎其微Q这时就需要某U方式来U录某位֮的消Ҏ量。想象一下其实也无外乎下面的几种ҎQ?/p> <p>  1、该店的店员很厉宻I能记住每位顾客的消费数量Q只要顾客一走进咖啡店,店员q道该怎么对待了。这U做法就是协议本w支持状态?/p> <p>  2、发l顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每ơ消ҎQ如果顾客出C张卡片,则此ơ消费就会与以前或以后的消费相联pv来。这U做法就是在客户端保持状态?/p> <p>  3、发l顾客一张会员卡Q除了卡号之外什么信息也不纪录,每次消费Ӟ如果֮出示该卡片,则店员在店里的纪录本上找到这个卡号对应的U录d一些消费信息。这U做法就是在服务器端保持状态?/p> <p>  ׃HTTP协议是无状态的Q而出于种U考虑也不希望使之成ؓ有状态的Q因此,后面两种Ҏ成为现实的选择。具体来说cookie机制采用的是在客L保持状态的ҎQ而session机制采用的是在服务器端保持状态的Ҏ。同时我们也看到Q由于采用服务器端保持状态的Ҏ在客L也需要保存一个标识,所以session机制可能需要借助于cookie机制来达C存标识的目的Q但实际上它q有其他选择?/p> <p>  三、理解cookie机制 </p> <p>  cookie机制的基本原理就如上面的例子一L单,但是q有几个问题需要解冻I“会员卡”如何分发;“会员卡”的内容Q以及客户如何用“会员卡”?/p> <p>  正统的cookie分发是通过扩展HTTP协议来实现的Q服务器通过在HTTP的响应头中加上一行特D的指示以提C浏览器按照指示生成相应的cookie。然而纯_的客户端脚本如JavaScript或者VBScript也可以生成cookie?/p> <p>  而cookie的用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器查所有存储的cookieQ如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置Q则把该cookie附在h资源的HTTPh头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示Q如果某家分店还发行了自q会员卡,那么q这家店的时候除了要出示麦当劳的会员卡,q要出示q家店的会员卡?/p> <p>  cookie的内容主要包括:名字Q|q期旉Q\径和域?/p> <p>  其中域可以指定某一个域比如.google.comQ相当于d招牌Q比如宝z公司,也可以指定一个域下的具体某台机器比如<a >www.google.com</a>或者froogle.google.comQ可以用飘柔来做比?/p> <p>  路径是跟在域名后面的URL路径Q比?或?foo{等Q可以用某飘柔专柜做比?/p> <p>  路径与域合在一起就构成了cookie的作用范围?/p> <p>  如果不设|过期时_则表C个cookie的生命期为浏览器会话期间Q只要关闭浏览器H口Qcookie消׃。这U生命期为浏览器会话期的cookie被称Z话cookie。会话cookie一般不存储在硬盘上而是保存在内存里Q当然这U行为ƈ不是规范规定的。如果设|了q期旉Q浏览器׃把cookie保存到硬盘上Q关闭后再次打开览器,q些cookie仍然有效直到过讑֮的过期时间?/p> <p>  存储在硬盘上的cookie可以在不同的览器进E间׃nQ比如两个IEH口。而对于保存在内存里的cookieQ不同的览器有不同的处理方式。对于IEQ在一个打开的窗口上按Ctrl-NQ或者从文g菜单Q打开的窗口可以与原窗口共享,而用其他方式新开的IEq程则不能共享已l打开的窗口的内存cookieQ对于Mozilla Firefox0.8Q所有的q程和标{N都可以共享同Lcookie。一般来说是用javascript的window.open打开的窗口会与原H口׃n内存cookie。浏览器对于会话cookie的这U只认cookie不认人的处理方式l常l采用session机制的web应用E序开发者造成很大的困扰?/p> <p>  下面是一个goolge讄cookie的响应头的例?/p> <p>HTTP/1.1 302 Found<br />Location: <a >http://www.google.com/intl/zh-CN/</a><br />Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com<br />Content-Type: text/html</p> <p> <br />  q是使用HTTPLookq个HTTP Sniffer软g来俘LHTTP通讯U录的一部分</p> <p> </p> <p>  览器在再次讉Kgoolge的资源时自动向外发送cookie</p> <p> <br />  使用Firefox可以很容易的观察现有的cookie的?/p> <p>  使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理?/p> <p> </p> <p>  IE也可以设|在接受cookie前询?/p> <p> <br />  q是一个询问接受cookie的对话框?/p> <p>  四、理解session机制</p> <p> session机制是一U服务器端的机制Q服务器使用一U类g散列表的l构Q也可能是使用散列表)来保存信息?/p> <p>  当程序需要ؓ某个客户端的h创徏一个session的时候,服务器首先检查这个客L的请求里是否已包含了一个session标识 - UCؓsession idQ如果已包含一个session id则说明以前已lؓ此客L创徏qsessionQ服务器按照session id把这个session索出来用(如果索不刎ͼ可能会新Z个)Q如果客Lh不包含session idQ则为此客户端创Z个sessionq且生成一个与此session相关联的session idQsession id的值应该是一个既不会重复Q又不容易被扑ֈ规律以仿造的字符Ԍq个session id被在本ơ响应中q回l客L保存?/p> <p>  保存q个session id的方式可以采用cookieQ这样在交互q程中浏览器可以自动的按照规则把q个标识发挥l服务器。一般这个cookie的名字都是类gSEEESIONIDQ而。比如weblogic对于web应用E序生成的cookieQJSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764Q它的名字就是JSESSIONID?/p> <p>  ׃cookie可以被h为的止Q必L其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一U技术叫做URL重写Q就是把session id直接附加在URL路径的后面,附加方式也有两种Q一U是作ؓURL路径的附加信息,表现形式?a href="http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764</a>另一U是作ؓ查询字符串附加在URL后面Q表现Ş式ؓ<a href="http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764</a><br />q两U方式对于用h说是没有区别的,只是服务器在解析的时候处理的方式不同Q采用第一U方式也有利于把session id的信息和正常E序参数区分开来?/p> <p>  Z在整个交互过E中始终保持状态,必d每个客户端可能请求的路径后面都包含这个session id?/p> <p>  另一U技术叫做表单隐藏字Dc就是服务器会自动修改表单,d一个隐藏字D,以便在表单提交时能够把session id传递回服务器。比如下面的表单</p> <p> </p> <p> </p> <p> </p> <p>  在被传递给客户端之前将被改写成</p> <p> </p> <p> <br /> </p> <p>  q种技术现在已较少应用Q笔者接触过的很古老的iPlanet6(SunONE应用服务器的前n)׃用了q种技术。实际上q种技术可以简单的用对action应用URL重写来代ѝ?/p> <p>  在谈论session机制的时候,常常听到q样一U误解“只要关闭浏览器Qsession消׃”。其实可以想象一下会员卡的例子,除非֮d对店家提出销卡,否则店家l对不会L删除֮的资料。对session来说也是一LQ除非程序通知服务器删除一个sessionQ否则服务器会一直保留,E序一般都是在用户做log off的时候发个指令去删除session。然而浏览器从来不会d在关闭之前通知服务器它要关闭Q因此服务器Ҏ不会有机会知道浏览器已经关闭Q之所以会有这U错觉,是大部分session机制都用会话cookie来保存session idQ而关闭浏览器后这个session id消׃Q再ơ连接服务器时也无法找到原来的session。如果服务器讄的cookie被保存到盘上,或者用某U手D|写浏览器发出的HTTPh_把原来的session id发送给服务器,则再ơ打开览器仍然能够找到原来的session?/p> <p>  恰恰是由于关闭浏览器不会Dsession被删除,q服务器ؓseesion讄了一个失效时_当距dL上一ơ用session的时间超q这个失效时间时Q服务器可以认为客L已经停止了活动,才会把session删除以节省存储空间?/p> <p>  五、理解javax.servlet.http.HttpSession</p> <p>  HttpSession是Javaq_对session机制的实现规范,因ؓ它仅仅是个接口,具体到每个web应用服务器的提供商,除了对规范支持之外,仍然会有一些规范里没有规定的细微差异。这里我们以BEA的Weblogic Server8.1作ؓ例子来演C?/p> <p>  首先QWeblogic Server提供了一pd的参数来控制它的HttpSession的实玎ͼ包括使用cookie的开关选项Q用URL重写的开关选项Qsession持久化的讄Qsession失效旉的设|,以及针对cookie的各U设|,比如讄cookie的名字、\径、域Qcookie的生存时间等?/p> <p>  一般情况下Qsession都是存储在内存里Q当服务器进E被停止或者重启的时候,内存里的session也会被清I,如果讄了session的持久化Ҏ,服务器就会把session保存到硬盘上Q当服务器进E重新启动或q些信息能够被再次使用QWeblogic Server支持的持久性方式包括文件、数据库、客Lcookie保存和复制?/p> <p>  复制严格说来不算持久化保存,因ؓsession实际上还是保存在内存里,不过同样的信息被复制到各个cluster内的服务器进E中Q这样即使某个服务器q程停止工作也仍然可以从其他q程中取得session?/p> <p>  cookie生存旉的设|则会媄响浏览器生成的cookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解?/p> <p>  cookie的\径对于web应用E序来说是一个非帔R要的选项QWeblogic Server对这个选项的默认处理方式得它与其他服务器有明昄区别。后面我们会专题讨论?/p> <p>  关于session的设|参考[5] <a >http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869</a></p> <p>  六、HttpSession常见问题</p> <p>  Q在本小节中session的含义ؓ⑤和⑥的混合Q?/p> <p>  1、session在何时被创徏</p> <p>  一个常见的误解是以为session在有客户端访问时p创徏Q然而事实是直到某server端程序调用HttpServletRequest.getSession(true)q样的语句时才被创徏Q注意如果JSP没有昄的?<<a href="mailto:%@page">%@page</a> session="false"%>关闭sessionQ则JSP文g在编译成Servlet时将会自动加上这样一条语句HttpSession session = HttpServletRequest.getSession(true);q也是JSP中隐含的session对象的来历?/p> <p>  ׃session会消耗内存资源,因此Q如果不打算使用sessionQ应该在所有的JSP中关闭它?/p> <p>  2、session何时被删?/p> <p>  l合前面的讨论,session在下列情况下被删除a.E序调用HttpSession.invalidate();或b.距离上一ơ收到客L发送的session id旉间隔过了session的超时设|?或c.服务器进E被停止Q非持久sessionQ?/p> <p>  3、如何做到在览器关闭时删除session</p> <p>  严格的讲Q做不到q一炏V可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作,然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进E这些非常规手段仍然无能为力?/p> <p>  4、有个HttpSessionListener是怎么回事</p> <p>  你可以创Llistenerȝ控session的创建和销毁事Ӟ使得在发生这L事g时你可以做一些相应的工作。注意是session的创建和销毁动作触发listenerQ而不是相反。类似的与HttpSession有关的listenerq有HttpSessionBindingListenerQHttpSessionActivationListener和HttpSessionAttributeListener?</p> <p>5、存攑֜session中的对象必须是可序列化的?/p> <p>  不是必需的。要求对象可序列化只是ؓ了session能够在集中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。在Weblogic Server的session中放|一个不可序列化的对象在控制C会收C个警告。我所用过的某个iPlanet版本如果session中有不可序列化的对象Q在session销毁时会有一个ExceptionQ很奇怪?/p> <p>  6、如何才能正的应付客户端禁止cookie的可能?/p> <p>  Ҏ有的URL使用URL重写Q包括超链接Qform的actionQ和重定向的URLQ具体做法参见[6]<br /><a >http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770</a></p> <p>  7、开两个览器窗口访问应用程序会使用同一个sessionq是不同的session</p> <p>  参见W三节对cookie的讨论,对session来说是只认id不认人,因此不同的浏览器Q不同的H口打开方式以及不同的cookie存储方式都会对这个问题的{案有媄响?/p> <p>  8、如何防止用h开两个览器窗口操作导致的session混ؕ</p> <p>  q个问题与防止表单多ơ提交是cM的,可以通过讄客户端的令牌来解冟뀂就是在服务器每ơ生成一个不同的idq回l客LQ同时保存在session里,客户端提交表单时必须把这个id也返回服务器Q程序首先比较返回的id与保存在session里的值是否一_如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表C层模式的部分。需要注意的是对于用javascript window.open打开的窗口,一般不讄q个idQ或者用单独的idQ以防主H口无法操作Q徏议不要再window.open打开的窗口里做修Ҏ作,q样可以不用设|?/p> <p>  9、ؓ什么在Weblogic Server中改变session的值后要重新调用一ơsession.setValue<br />做这个动作主要是Z在集环境中提示Weblogic Server session中的值发生了改变Q需要向其他服务器进E复制新的session倹{?/p> <p>  10、ؓ什么session不见?/p> <p>  排除session正常失效的因素之外,服务器本w的可能性应该是微乎其微的,虽然W者在iPlanet6SP1加若q补丁的Solaris版本上倒也遇到q;览器插件的可能性次之,W者也遇到q?721插g造成的问题;理论上防火墙或者代理服务器在cookie处理上也有可能会出现问题?/p> <p>  出现q一问题的大部分原因都是E序的错误,最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨个问题?/p> <p>  七、跨应用E序的session׃n</p> <p>  常常有这L情况Q一个大目被分割成若干项目开发,Z能够互不q扰Q要求每个小目作ؓ一个单独的web应用E序开发,可是C最后突然发现某几个项目之间需要共享一些信息,或者想使用session来实现SSO(single sign on)Q在session中保存login的用户信息,最自然的要求是应用E序间能够访问彼此的session?/p> <p>  然而按照Servlet规范Qsession的作用范围应该仅仅限于当前应用程序下Q不同的应用E序之间是不能够互相讉KҎ的session的。各个应用服务器从实际效果上都遵守了q一规范Q但是实现的l节却可能各有不同,因此解决跨应用程序session׃n的方法也各不相同?/p> <p>  首先来看一下Tomcat是如何实现web应用E序之间session的隔ȝQ从Tomcat讄的cookie路径来看Q它对不同的应用E序讄的cookie路径是不同的Q这样不同的应用E序所用的session id是不同的Q因此即使在同一个浏览器H口里访问不同的应用E序Q发送给服务器的session id也可以是不同的?/p> <p> </p> <p>  Ҏq个Ҏ,我们可以推测Tomcat中session的内存结构大致如下?/p> <p> </p> <p>  W者以前用q的iPlanet也采用的是同L方式Q估计SunONE与iPlanet之间不会有太大的差别。对于这U方式的服务器,解决的思\很简单,实际实行h也不难。要么让所有的应用E序׃n一个session idQ要么让应用E序能够获得其他应用E序的session id?/p> <p>  iPlanet中有一U很单的Ҏ来实现共享一个session idQ那是把各个应用程序的cookie路径都设?Q实际上应该?NASAppQ对于应用程序来讲它的作用相当于根)?/p> <p>/NASApp </p> <p> <br />  需要注意的是,操作׃n的session应该遵@一些编E约定,比如在session attribute名字的前面加上应用程序的前缀Q得setAttribute("name", "neo")变成setAttribute("app1.name", "neo")Q以防止命名I间冲突Q导致互相覆盖?/p> <p> <br />  在Tomcat中则没有q么方便的选择。在Tomcat版本3上,我们q可以有一些手D|׃nsession。对于版?以上的TomcatQ目前笔者尚未发现简单的办法。只能借助于第三方的力量,比如使用文g、数据库、JMS或者客LcookieQURL参数或者隐藏字D늭手段?/p> <p>  我们再看一下Weblogic Server是如何处理session的?/p> <p> </p> <p> <br />  从截屏画面上可以看到Weblogic ServerҎ有的应用E序讄的cookie的\径都?Q这是不是意味着在Weblogic Server中默认的可以共享session了呢Q然而一个小实验卛_证明即不同的应用程序用的是同一个sessionQ各个应用程序仍然只能访问自己所讄的那些属性。这说明Weblogic Server中的session的内存结构可能如?/p> <p> </p> <p>  对于q样一U结构,在session机制本n上来解决session׃n的问题应该是不可能的了。除了借助于第三方的力量,比如使用文g、数据库、JMS或者客LcookieQURL参数或者隐藏字D늭手段Q还有一U较为方便的做法Q就是把一个应用程序的session攑ֈServletContext中,q样另外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下,</p> <p>  应用E序A</p> <p>context.setAttribute("appA", session); </p> <p>  应用E序B</p> <p>contextA = context.getContext("/appA");<br />HttpSession sessionA = (HttpSession)contextA.getAttribute("appA"); </p> <p>  值得注意的是q种用法不可ULQ因为根据ServletContext的JavaDocQ应用服务器可以处于安全的原因对于context.getContext("/appA");q回I|以上做法在Weblogic Server 8.1中通过?/p> <p>  那么Weblogic ServerZ么要把所有的应用E序的cookie路径都设?呢?原来是ؓ了SSOQ凡是共享这个session的应用程序都可以׃n认证的信息。一个简单的实验可以证明这一点,修改首先d的那个应用程序的描述Wweblogic.xmlQ把cookie路径修改?appA讉K另外一个应用程序会重新要求dQ即使是反过来,先访问cookie路径?的应用程序,再访问修改过路径的这个,虽然不再提示dQ但是登录的用户信息也会丢失。注意做q个实验时认证方式应该用FORMQ因为浏览器和web服务器对basic认证方式有其他的处理方式Q第二次h的认证不是通过session来实现的。具体请参看[7] secion 14.8 AuthorizationQ你可以修改所附的CZE序来做q些试验?/p> <p>  八、ȝ</p> <p>  session机制本nq不复杂Q然而其实现和配|上的灵zL却使得具体情况复杂多变。这也要求我们不能把仅仅某一ơ的l验或者某一个浏览器Q服务器的经验当作普遍适用的经验,而是始终需要具体情况具体分析?br /></p> <img src ="http://m.tkk7.com/xuechen0721/aggbug/44967.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/xuechen0721/" target="_blank">兵城下</a> 2006-05-08 11:05 <a href="http://m.tkk7.com/xuechen0721/articles/44967.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>论J2EEE序员的武功修ؓ Q{载)http://m.tkk7.com/xuechen0721/articles/43629.html兵城下兵城下Thu, 27 Apr 2006 09:49:00 GMThttp://m.tkk7.com/xuechen0721/articles/43629.htmlhttp://m.tkk7.com/xuechen0721/comments/43629.htmlhttp://m.tkk7.com/xuechen0721/articles/43629.html#Feedback0http://m.tkk7.com/xuechen0721/comments/commentRss/43629.htmlhttp://m.tkk7.com/xuechen0721/services/trackbacks/43629.html EasyJF开源团?/font> (www.easyjf.com) 大

  l常会跟一些朋友讨论怎么h能学好Java,学到什么程度才撑握了Java的问题。其中有一个J2EEE序员层ơ及武功修ؓ的问题,有点意思。这里就把讨论的内容大致整理一下发出来Q大家l讨论?br />
  U观国内的Y件行业,靠Java吃饭的程序员q真不是,而且JavaE序员是有很大优感的,毕竟对于很多用b/s搞开发的业内朋友来说QJava技术意味着隑ֺ大、门槛高Q因此相Ҏ说JavaE序员比其它的程序员(如php?net)收入高就理所当然。然而J2EE所涉及到的范畴是很q的Q不能一个JavaE序员就概括了事Q而应该具有层ơ及水^之分Q很多时候经帔R要进行分cL评Q有时他评、有时自评?br />
  谈到国内J2EE领域的程序员层次水^Q当前流行的U谓及评U不外乎׃面几U:
  W一U是_N掌握记事本、Dreamweaver{工h写JSP+JavaBean数据库应用的是J2EEE序员;
  W二U是用JBuilder、Eclipse{专用Java开发工具写着一堆一堆过E式Java BeanQ而且q能_NStruts+Spring+Hibernate{应用框架的高J2EEE序员;
  W三U是用Together建模Q然后生成一堆Java接口或代码,开口闭口都是设计模式的资深JavaE序同及高pȝ分析、构架师Q?br />  最后还有一U是整天在BlogJava或JavaEye上谈l论道的大师们,q些大师技术水q难以触摸,武功门派也各LԌ不好归类Q有时不好称为程序员Q因为有的时候他们甚至不写或者写不出E序Q,但又做着与J2EEE序员密切相关的事情Q我们暂且就归ؓ“牛牛”或“大师”?br />
  U谓毕竟只是U谓Q带有点主观或者功利色彩,有时很难鉴定一个h应该属于什么,因此Q我们再从纯技术的角度Q也x功修为的角度Q作了一个简单的分析及归c,?EE领域E序员大致分成以下几个层ơ,可以作ؓ大家自评的一个参考标准:

  W一个层ơ:_N掌握Java语法、能调试基本的程序错误,_N掌握JSP+Java Bean写一些Nq前ASP、PHPȝ的Java Web应用E序Q如论坛、网站新d布系l、OA、网上商城等Q,_NJDBC使用、精通SQL语句、精通XML{?br />
  W二个层ơ:掌握设计模式原理及应用,掌握ZOO的分析及设计Ҏ,q能_N熟l用几UJava专业设计及开发工P_N掌握流行的J2EE框架如Hibernate、EJB、Webwork、Spring的原理及应用Q精通J2EE中一两个l成部分(如Servlet、EJB{?的工作原理及l节?br />
  W三个层ơ:林的高僧有两种Q禅僧及武僧。J2EEE序员的W三个层ơ也同样有禅、武两个分支Q这里我们重点分析一下:

  W一个分支属于走的禅僧线路。在l完W二个层ơ中的各U武功基上,l合实际目中的千奇百怪的用户需求,游刃有余的选择适合的技术方案ؓ客户解决问题Qƈ形成自己的一套解x案。达到这一个层ơ的J2EEE序员已l不在乎使用M工具、Q何框架了Q而是Ҏ不同的对手,使用不同的武器或招式来应寏V好比小李飞刀一P只有辑ֈ了“手中无刀、心中有刀”的境界Q才能达到“出手一刀Q例不虚发”的效果。这一层次的武功属于一个熟l度问题Q刀l得多了、遇到的Ҏ多了Q再加上前面的武功修为,q做不C不虚发,也可辑ֈ十发九中?br />
  W二个分支属于走的武僧线路,在撑握熟悉第一二个层次中涉及到的内容后Q进一步专研ƈ撑握J2EE底层开发,J2EE规范制订、规范实现、Java虚拟机的工作原理、各U常见的J2EE服务器内核工作机制、内存管理、进E机制、源代码{。因为涉及的很多东西都比较抽象,代码也很多,l这一层的武功需要有很好的资质及耐性、ƈ兯得有一定的环境及条件。好比神雕大侠杨q拿起“玄铁剑”,q练成“暗焉掌”的成长q程Q需要前面的武功修ؓ作基Q更需那只威力武雕的帮助指点及他处处ؓ民、惩奔R恶的侠之心态?br />  
  胡侃了这么多Q现在来Ҏ自己情况算一下自q份量Q结果如下:
  W一层 l到8成;
  W二层 l到5成;
  W三层 准备走禅僧线路,当前是l到1成;
  
  唉,后面的武功提升越来越难,真不知道要到何年何月才能辑ֈ10成啊。你的武功练到哪一个层ơ了Q不防亮出来大家切磋切磋。嘿嘿,要是有一天,׃中国的JavaE序员h手一把“玄铁剑”、hZ低쀜暗焉掌”,那还了得!?..Q写着写着居然做v白日梦了Q不好意思,此打住?/font>

兵城下 2006-04-27 17:49 发表评论
]]>
վ֩ģ壺 jlzzjlzz߲| ޹Ʒһ| 鶹avŮһ| Ƶվѹۿ| 2019ĻƵ| ޸Ƶ| ޹˾Ʒԭ| aaaëƬѹۿ| ձĻ߿| ŮƵվ| һëƬѿa| ޾Ʒһ| þþƷձľϣ| ѹëƬ | ޾ƷӰԺ| ˳7777Ӱ߹ۿ| þ99Ƶ| Ļ˿Ʒһ| ..ŷһ| 91Ƶ| һӰ| Ƭ߹ۿ| 鸣ۺĻһƵ1 | ĻƵվ| У԰ɫС˵| һëƬaaaaaaѿ| ޸岻߹ۿ| һaɫƬþٸһHƬѷ | 3pƵѹۿ| ҹ޾Ʒ| ߾ѹۿ| ޾Ʒav| ĻAëƬ| ޴߶ר| AëƬþ| һƬվ߹ۿ| ѹۿ˳վ| ߲Ѳ| AV˵| ѿٸƵ| ޹ŷۺһ|