??xml version="1.0" encoding="utf-8" standalone="yes"?>夜夜精品视频一区二区,国产精品91xxx,国内精品国产成人国产三级粉色http://www.aygfsteel.com/jhengfei/爱JAVAQ爱生活zh-cnFri, 20 Jun 2025 00:27:01 GMTFri, 20 Jun 2025 00:27:01 GMT60~写安全的Java代码http://www.aygfsteel.com/jhengfei/archive/2006/12/19/88676.htmlҎ铸就辉煌Ҏ铸就辉煌Tue, 19 Dec 2006 01:29:00 GMThttp://www.aygfsteel.com/jhengfei/archive/2006/12/19/88676.htmlhttp://www.aygfsteel.com/jhengfei/comments/88676.htmlhttp://www.aygfsteel.com/jhengfei/archive/2006/12/19/88676.html#Feedback0http://www.aygfsteel.com/jhengfei/comments/commentRss/88676.htmlhttp://www.aygfsteel.com/jhengfei/services/trackbacks/88676.html

radic 发表?2006-12-15 12:24:05
作?Radic     来源:sun
评论?5 点击?592     投票d?6 投票Mh?2
关键?Java;安全~码

摘要:

本文是来自Sun官方站点的一关于如何编写安全的Java代码的指?开发者在~写一般代码时Q可以参照本文的指南
本文是来自Sun官方站点的一关于如何编写安全的Java代码的指?开发者在~写一般代码时Q可以参照本文的指南Q?br />
•        静态字D?br />•        羃作用域
•        公共方法和字段
•        保护包
•        equalsҎ
•        如果可能对象不可改变
•        不要返回指向包含敏感数据的内部数组的引?br />•        不要直接存储用h供的数组
•        序列化
•        原生函?br />•        清除敏感信?/span>

静态字D?/b>
•        避免用非final的公共静态变?br />应尽可能地避免用非final公共静态变量,因ؓ无法判断代码有无权限改变q些变量倹{?br />•        一般地Q应谨慎使用易变的静态状态,因ؓq可能导致设想中怺独立的子pȝ之间发生不可预知的交互?br />
~小作用?/b>
作ؓ一个惯例,可能羃方法和字段的作用域。检查包讉K权限的成员能否改成私有的Q保护类型的成员可否Ҏ包访问权限的或者私有的Q等{?br />
公共Ҏ/字段
避免使用公共变量Q而是使用讉K器方法访问这些变量。用q种方式Q如果需要,可能增加集中安全控制?br />对于M公共ҎQ如果它们能够访问或修改M敏感内部状态,务必使它们包含安全控制?br />参考如下代码段Q该代码D中不可信Q代码可能讄TimeZone的|
private static TimeZone  defaultZone = null;

      public static synchronized void setDefault(TimeZone zone)
      {
          defaultZone = zone;
      }


保护?/b>
有时需要在全局防止包被不可信Q代码讉KQ本节描qC一些防护技术:
•        防止包注入Q如果不可信M码想要访问类的包保护成员Q可以尝试在被攻ȝ包内定义自己的新cȝ以获取这些成员的讉K权。防止这cLȝ方式有两U:
1.        通过向java.security.properties文g中加入如下文字防止包内被注入恶意cR?br />
          ... 
package.definition=Package#1 [,Package#2,...,Package#n]

...


q会D当试囑֜包内定义新类时类装蝲器的defineClassҎ会抛出异常,除非赋予代码一下权限:
... 
RuntimePermission("defineClassInPackage."+package)

...


2.        另一U方式是通过包内的cd入到装的Jar文g里?br />Q参看http://java.sun.com/j2se/sdk/1.2/docs/guide/extensions/spec.htmlQ?br />    通过使用q种技巧,代码无法获得扩展包的权限Q因此也无须修改java.security.properties文g?br />•        防止包讉KQ通过限制包访问ƈ仅赋予特定代码访问权限防止不可信M码对包成员的讉K。通过向java.security.properties文g中加入如下文字可以达到这一目的Q?br />
      ... 
package.access=Package#1 [,Package#2,...,Package#n]

...


q会D当试囑֜包内定义新类时类装蝲器的defineClassҎ会抛出异常,除非赋予代码一下权限:
... 
RuntimePermission("defineClassInPackage."+package)

...


如果可能使对象不可改?/b>
如果可能Q对象不可改变。如果不可能Q得它们可以被克隆q返回一个副本。如果返回的对象是数l、向量或哈希表等Q牢记这些对象不能被改变Q调用者修改这些对象的内容可能D安全漏洞。此外,因ؓ不用上锁Q不可改变性能够提高ƈ发性。参考Clear sensitive information了解该惯例的例外情况?br />
不要q回指向包含敏感数据的内部数l的引用
该惯例仅仅是不可变惯例的变型Q在q儿提出是因为常常在q里犯错。即使数l中包含不可变的对象Q如字符ԌQ也要返回一个副本这栯用者不能修Ҏl中的字W串。不要传回一个数l,而是数组的拷贝?br />
不要直接在用h供的数组里存?/b>
该惯例仅仅是不可变惯例的另一个变型。用对象数l的构造器和方法,比如说PubicKey数组Q应当在数l存储到内部之前克隆数组Q而不是直接将数组引用赋给同样cd的内部变量。缺这个警惕,用户对外部数l做得Q何变动(在用讨Z的构造器创徏对象后)可能意外地更改对象的内部状态,即该对象可能是无法改变?br />
序列?/b>
当对对象序列化时Q直到它被反序列化,它不在Javaq行时环境的控制之下Q因此也不在Javaq_提供的安全控制范围内?br />在实现Serializable时务必将以下事宜牢记在心Q?br />•        transient

在包含系l资源的直接句柄和相对地址I间信息的字D前使用transient关键字?如果资源Q如文g句柄Q不被声明ؓtransientQ该对象在序列化状态下可能会被修改Q从而得被反序列化后获取对资源的不当访问?br />
•        特定类的序列化/反序列化Ҏ

Z保反序列化对象不包含违反一些不变量集合的状态,cd该定义自q反序列化Ҏq用ObjectInputValidation接口验证q些变量?br />
如果一个类定义了自q序列化方法,它就不能向Q何DataInput/DataOuputҎ传递内部数l。所有的DataInput/DataOuputҎ都能被重写。注意默认序列化不会向DataInput/DataOuput字节数组Ҏ暴露U有字节数组字段?br />
如果Serializablecȝ接向DataOutput(write(byte [] b))Ҏ传递了一个私有数l,那么黑客可以创徏ObjectOutputStream的子cdƈ覆盖write(byte [] b)ҎQ这样他可以讉Kq修改私有数l。下面示例说明了q个问题?br />你的c?
      public class YourClass implements Serializable {

            private byte [] internalArray;
....
private synchronized void writeObject(ObjectOutputStream stream) {
...

               stream.write(internalArray);
                ...
}
}


黑客代码

       public class HackerObjectOutputStream extends ObjectOutputStream{
            public void write (byte [] b) {
               Modify b
      }
}
...
             YourClass yc = new YourClass();
              ...

             HackerObjectOutputStream hoos = new HackerObjectOutputStream();

              hoos.writeObject(yc);


•        字节流加密

保护虚拟机外的字节流的另一方式是对序列化包产生的流q行加密。字节流加密防止解码或读取被序列化的对象的私有状态。如果决定加密,应该理好密钥,密钥的存攑֜点以及将密钥交付l反序列化程序的方式{?br />
•        需要提防的其他事宜

如果不可信Q代码无法创徏对象Q务必确保不可信M码也不能反序列化对象。切记对对象反序列化是创建对象的另一途径?br />比如_如果一个applet创徏了一个frameQ在该frame上创Z警告标签。如果该frame被另一应用E序序列化ƈ被一个applet反序列化Q务必该frame出现时带有同一个警告标{?br />
原生Ҏ
应从以下几个斚w查原生方法:
•        它们返回什?br />•        它们需要什么参?br />•        它们是否绕q了安全?br />•        它们是否是公共的,U有的等
•        它们是否包含能l过包边界的Ҏ调用Q从而绕q包保护

清除敏感信息
当保存敏感信息时Q如机密Q尽量保存在如数l这L可变数据cd中,而不是保存在字符串这L不可变对象中Q这样得敏感信息可以尽早显式地被清除。不要指望Javaq_的自动垃圑֛收来做这U清除,因ؓ回收器可能不会清除这D内存,或者很久后才会回收。尽早清除信息得来自虚拟机外部的堆查攻d得困难?br />


Ҏ铸就辉煌 2006-12-19 09:29 发表评论
]]>
有关MySQL的数据同步备份复刉?http://www.aygfsteel.com/jhengfei/archive/2006/11/14/81085.htmlҎ铸就辉煌Ҏ铸就辉煌Tue, 14 Nov 2006 03:29:00 GMThttp://www.aygfsteel.com/jhengfei/archive/2006/11/14/81085.htmlhttp://www.aygfsteel.com/jhengfei/comments/81085.htmlhttp://www.aygfsteel.com/jhengfei/archive/2006/11/14/81085.html#Feedback0http://www.aygfsteel.com/jhengfei/comments/commentRss/81085.htmlhttp://www.aygfsteel.com/jhengfei/services/trackbacks/81085.htmlMySQL?.23.15版本以后提供数据库复制功能。利用该功能可以实现两个数据库同步,M模式Q互相备份模式的功能

数据库同步复制功能的讄都在mysql的设|文件中体现。mysql的配|文Ӟ一般是my.cnfQ,在unix环境下在/etc/mysql/my.cnf 或者在mysql用户的home目录下的my.cnf?

window环境中,如果c:根目录下有my.cnf文g则取该配|文件。当q行mysql的winmysqladmin.exe工具时候,该工具会把c:根目录下的my.cnf 命名为mycnf.bak。ƈ在winnt目录下创建my.ini。mysql服务器启动时候会读该配置文g。所以可以把my.cnf中的内容拯到my.ini文g中,用my.ini文g作ؓmysql服务器的配置文g?

讄ҎQ?

讄范例环境Q?

操作pȝQwindow2000 professional

mysqlQ?.0.4-beta-max-nt-log

A ip:10.10.10.22

B ip:10.10.10.53

A:讄

1.增加一个用h为同步的用户帐号Q?

																GRANT FILE ON *.* TO backup@'10.10.10.53' IDENTIFIED BY ?234?/ccid_code>
														

2.增加一个数据库作ؓ同步数据库:

																create database backup
														

B:讄

1.增加一个用h为同步的用户帐号Q?

																GRANT FILE ON *.* TO backup@'10.10.10.22' IDENTIFIED BY ?234?/ccid_code>
														

2.增加一个数据库作ؓ同步数据库:

																create database backup
														

M模式QA->B

A为master

修改A mysql的my.ini文g。在mysqld配置中加入下面配置Q?

server-id=1log-bin#讄需要记录log 可以讄log-bin=c:mysqlbakmysqllog 讄日志文g的目录,#其中mysqllog是日志文件的名称Qmysql徏立不同扩展名Q文件名为mysqllog的几个日志文件。binlog-do-db=backup #指定需要日志的数据?

重v数据库服务?

用show master status 命o看日志情c?

B为slave

修改B mysql的my.ini文g。在mysqld配置中加入下面配置Q?

																server-id=2master-host=10.10.10.22master-user=backup
														

#同步用户帐号

																master-password=1234master-port=3306master-connect-retry=60
														

预设重试间隔60Ureplicate-do-db=backup 告诉slave只做backup数据库的更新

重v数据?

用show slave status看同步配|情c?

注意Q由于设|了slave的配|信息,mysql在数据库目录下生成master.infoQ所以如有要修改相关slave的配|要先删除该文g。否则修改的配置不能生效?

双机互备模式?

如果在A加入slave讄Q在B加入master讄Q则可以做B->A的同步?

在A的配|文件中 mysqld 配置加入以下设|:

																master-host=10.10.10.53master-user=backupmaster-password=1234replicate-do-db=
backupmaster-connect-retry=10
														

在B的配|文件中 mysqld 配置加入以下设|:

																log-bin=c:mysqllogmysqllogbinlog-do-db=backup
														

注意Q当有错误生时*.err日志文g。同步的U程退出,当纠正错误后要让同步机制q行工作Q运行slave start

重vAB机器Q则可以实现双向的热备?

试Q?

向B扚w插入大数据量表AAQ?872000Q条QA数据库每U钟可以更新2500条数据?



Ҏ铸就辉煌 2006-11-14 11:29 发表评论
]]>
SQL语句优化的原?/title><link>http://www.aygfsteel.com/jhengfei/archive/2006/11/12/80679.html</link><dc:creator>Ҏ铸就辉煌</dc:creator><author>Ҏ铸就辉煌</author><pubDate>Sun, 12 Nov 2006 03:27:00 GMT</pubDate><guid>http://www.aygfsteel.com/jhengfei/archive/2006/11/12/80679.html</guid><wfw:comment>http://www.aygfsteel.com/jhengfei/comments/80679.html</wfw:comment><comments>http://www.aygfsteel.com/jhengfei/archive/2006/11/12/80679.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/jhengfei/comments/commentRss/80679.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/jhengfei/services/trackbacks/80679.html</trackback:ping><description><![CDATA[ <span id="wmqeeuq" class="oblog_text">优化数据库的思想Q?br />  ================<br />  1、关键字D徏立烦引?br />  2、用存储过E,它SQL变得更加灉|和高效?br />  3、备份数据库和清除垃圾数据?br />  4、SQL语句语法的优化。(可以用Sybase的SQL ExpertQ可惜我没找到unexpired?br />序列P<br />  5、清理删除日志?br /><br />  SQL语句优化的原则:  <br />  ==================<br />  1、用烦引来更快地遍历表?br />  ~省情况下徏立的索引是非集索引Q但有时它ƈ不是最佳的。在非群集烦引下Q数据在物理上随机存攑֜数据上。合理的索引设计要徏立在对各U查询的分析和预上。一般来_<br />  ?有大量重复倹{且l常有范围查?br />  Qbetween, > ,< Q?gt; =,< =Q和order by、group by发生的列Q可考虑建立集索引Q?br />  ?l常同时存取多列Q且每列都含有重复值可考虑建立l合索引Q?br />  ?l合索引要尽量关键查询形成索引覆盖Q其前导列一定是使用最频繁的列。烦引虽有助于提高性能但不是烦引越多越好,恰好相反q多的烦引会Dpȝ低效。用户在表中每加q一个烦引,l护索引集合p做相应的更新工作?br />  2、IS NULL ?IS NOT NULL<br />  不能用null作烦引,M包含null值的列都不会被包含在烦引中。即使烦引有多列q样的情况下Q只要这些列中有一列含有nullQ该列就会从索引中排除。也是说如果某列存在空|即对该列徏索引也不会提高性能。Q何在where子句中用is null或is not null的语句优化器是不允许使用索引的?br />  3、IN和EXISTS<br />  EXISTS要远比IN的效率高。里面关pdfull table scan和range scan。几乎将所有的IN操作W子查询改写Z用EXISTS的子查询?br />  4、在量查询时尽量少用格式{换?br />  5、当在SQL SERVER 2000中,如果存储q程只有一个参敎ͼq且是OUTPUTcd的,必须在调用这个存储过E的时候给q个参数一个初始的|否则会出现调用错误?br />  6、ORDER BY和GROPU BY<br />  使用ORDER BY和GROUP BY短语QQ何一U烦引都有助于SELECT的性能提高。注意如果烦引列里面有NULL|Optimizer无法优化?br />  7、Q何对列的操作都将D表扫描,它包括数据库函数、计表辑ּ{等Q查询时要尽可能操作移至等号右辏V?br />  8、IN、OR子句怼使用工作表,使烦引失效。如果不产生大量重复|可以考虑把子句拆开。拆开的子句中应该包含索引?br />  9、SET SHOWPLAN_ALL ON 查看执行Ҏ。DBCC查数据库数据完整性?br />  DBCC(DataBase Consistency CheckerQ是一l用于验?SQL Server 数据库完整性的E序?br />  10、慎用游?br />  在某些必M用游标的场合Q可考虑符合条件的数据行{入时表中,再对临时表定义游标进行操作,q样可性能得到明显提高?br /><br />  ȝQ?br />  所谓优化即WHERE子句利用了烦引,不可优化卛_生了表扫描或额外开销。经验显C,SQL Server性能的最大改q得益于逻辑的数据库设计、烦引设计和查询设计斚w。反q来_最大的性能问题常常是由其中q些相同斚w中的不引v的。其实SQL优化的实质就是在l果正确的前提下Q用优化器可以识别的语句Q充份利用烦引,减少表扫描的I/Oơ数Q尽量避免表搜烦的发生。其实SQL的性能优化是一个复杂的q程Q上q这些只是在应用层次的一U体玎ͼ深入研究q会涉及数据库层的资源配|、网l层的流量控制以及操作系l层的M设计。?br /></span> <img src ="http://www.aygfsteel.com/jhengfei/aggbug/80679.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/jhengfei/" target="_blank">Ҏ铸就辉煌</a> 2006-11-12 11:27 <a href="http://www.aygfsteel.com/jhengfei/archive/2006/11/12/80679.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Zstruts+spring+ibatis的轻量J2EE开?/title><link>http://www.aygfsteel.com/jhengfei/archive/2006/11/11/80545.html</link><dc:creator>Ҏ铸就辉煌</dc:creator><author>Ҏ铸就辉煌</author><pubDate>Sat, 11 Nov 2006 01:59:00 GMT</pubDate><guid>http://www.aygfsteel.com/jhengfei/archive/2006/11/11/80545.html</guid><wfw:comment>http://www.aygfsteel.com/jhengfei/comments/80545.html</wfw:comment><comments>http://www.aygfsteel.com/jhengfei/archive/2006/11/11/80545.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/jhengfei/comments/commentRss/80545.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/jhengfei/services/trackbacks/80545.html</trackback:ping><description><![CDATA[ <p>xbeanaction?查到的资?Z做个备䆾<br /><br />多数IT l织都必解决三个主要问题:1Q帮助组l减成?2Q增加ƈ且保持客?3Q加快业务效率。完成这些问题一般都需要实现对多个业务pȝ的数据和业务逻辑的无~访问,也就是说Q要实施pȝ集成工程Q以便联l业务流E、实现数据的讉K与共享?</p> <p>JpetStore 4.0是ibatis的最新示例程序,ZStruts MVC框架Q注Q非传统Struts开发模式)Q以ibatis作ؓ持久化层。该CZE序设计优雅Q层ơ清晎ͼ可以学习以及作ؓ一个高效率的编E模型参考。本文是在其基础上,采用Spring对其中间层(业务层)q行攚w。开发量q一步减,同时又拥有了Spring的一些好处?/p> <p> <a name="IDABCIKB"> <span id="wmqeeuq" class="atitle2"> <strong>1. 前言</strong> </span> </a> <br />JpetStore 4.0是ibatis的最新示例程序。ibatis是开源的持久层品,包含SQL Maps 2.0 ?Data Access Objects 2.0 框架。JpetStoreCZE序很好的展CZ如何利用ibatis来开发一个典型的J2EE web应用E序。JpetStore有如下特点:</p> <ul xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <li>ibatis数据? </li> <li>POJO业务? </li> <li>POJO领域c? </li> <li>Struts MVC </li> <li>JSP 表示?</li> </ul> <p>以下是本文用到的关键技术介l,本文假设您已l对StrutsQSpringFramewokQibatis有一定的了解Q如果不是,请首先查阅附录中的参考资料?/p> <ul xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <li>Struts 是目前Java Web MVC框架中不争的王者。经q长达五q的发展QStruts已经逐渐成长Z个稳定、成熟的框架Qƈ且占有了MVC框架中最大的市场份额。但是Struts某些技术特性上已经落后于新兴的MVC框架。面对Spring MVC、Webwork2 q些设计更精密,扩展性更强的框架QStruts受到了前所未有的挑战。但站在产品开发的角度而言QStruts仍然是最E_的选择。本文的原型例子JpetStore 4.0是ZStruts开发的Q但是不拘惔于Struts的传l固定用法,例如只用了一个自定义Actionc,q且在form beancȝ定义上也是开创性的Qo目一斎ͼE后具体剖析一下? </li> <li>Spring Framework 实际上是Expert One-on-One J2EE Design and Development 一书中所阐述的设计思想的具体实现。Spring Framework的功能非常多。包含AOP、ORM、DAO、Context、Web、MVC{几个部分组成。Web、MVC暂不用考虑QJpetStore 4.0用的是更成熟的Struts和JSPQDAO׃目前Hibernate、JDO、ibatis的流行,也不考虑QJpetStore 4.0用的是ibatis。因此最需要用的是AOP、ORM、Context。Context中,最重要的是BeanfactoryQ它能将接口与实现分开Q非常强大。目前AOP应用最成熟的还是在事务理上? </li> <li>ibatis 是一个功能强大实用的SQL Map工具Q不同于其他ORM工具Q如hibernateQ,它是SQL语句映射成Java对象Q而对于ORM工具Q它的SQL语句是根据映定义生成的。ibatis 以SQL开发的工作量和数据库移植性上的让步,为系l设计提供了更大的自q间。有ibatis代码生成的工P可以ҎDDL自动生成ibatis代码Q能减少很多工作量?</li> </ul> <p> <a name="IDASCIKB"> <span id="wmqeeuq" class="atitle2"> <strong>2. JpetStoreq?/strong> </span> </a> <br /> </p> <p> <a name="IDAXCIKB"> <span id="wmqeeuq" class="atitle3"> <strong>2.1. 背景</strong> </span> </a> <br />最初是Sun公司的J2EE petstoreQ其最主要目的是用于学习J2EEQ但是其~点也很明显Q就是过度设计了。接着Oracle用J2EE petstore来比较各应用服务器的性能。微软推ZZ.Netq_?Pet shopQ用于竞争J2EE petstore。而JpetStore则是l过改良的基于struts的轻便框架J2EE web应用E序Q相比来_JpetStore设计和架构更优良Q各层定义清晎ͼ使用了很多最佛_践和模式Q避免了很多"反模?Q如使用存储q程Q在java代码中嵌入SQL语句Q把HTML存储在数据库中等{。最新版本是JpetStore 4.0?/p> <p> <a name="IDA3CIKB"> <span id="wmqeeuq" class="atitle3"> <strong>2.2. JpetStore开发运行环境的建立</strong> </span> </a> <br />1、开发环?/p> <ul xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <li>Java SDK 1.4.2 </li> <li>Apache Tomcat 4.1.31 </li> <li>Eclipse-SDK-3.0.1-win32 </li> <li>HSQLDB 1.7.2 </li> </ul> <p>2、Eclipse插g</p> <ul xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <li>EMF SDK 2.0.1QEclipse建模框架Qlomboz插g需要,可以使用runtime版本? </li> <li>lomboz 3.0QJ2EE插gQ用来在Eclipse中开发J2EE应用E序 </li> <li>Spring IDE 1.0.3QSpring Bean配置理插g </li> <li>xmlbuddy_2.0.10Q编辑XMLQ用免费版功能即? </li> <li>tomcatPluginV3Qtomcat理插g </li> <li>Properties EditorQ编辑java的属性文?q可以预览以及自动存盘ؓUnicode格式。免M手工或者ANT调用native2ascii的麻烦?</li> </ul> <p>3、示例源E序</p> <ul xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <li>ibatisCZE序JpetStore 4.0 http://www.ibatis.com/jpetstore/jpetstore.html </li> <li>攚w后的源E序Q?springQ(源码链接Q?</li> </ul> <p> <a name="IDAUDIKB"> <span id="wmqeeuq" class="atitle3"> <strong>2.3. 架构</strong> </span> </a> <br /> </p> <p> <a name="IDA0DIKB"> <b>? JpetStore架构?/b> </a> <br /> <img height="279" alt="? JpetStore架构? src="http://www.uml.org.cn/j2ee/images/12281.jpg" width="553" border="0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /> </p> <p>? 是JPetStore架构图,更详l的内容请参见JPetStore的白皮书。参照这个架构图Q让我们E微剖析一下源代码Q得出JpetStore 4.0的具体实现图Q见?Q,思\一下子p然开朗了。前a中提到的非传l的struts开发模式,关键在struts Actioncdform beancM?/p> <p>struts Actioncd有一个:BeanAction。没错,实是一个!与传l的struts~程方式很不同。再仔细研究BeanActionc,发现它其实是一个通用c,利用反射原理Q根据URL来决定调用formbean的哪个方法。BeanAction大大化了struts的编E模式,降低了对struts的依赖(与struts以及WEB容器有关的几个类都放在com.ibatis.struts包下Q其它的c都可以直接复用Q。利用这U模式,我们会很Ҏ的把它移植到新的框架如JSFQspring?/p> <p>q样重心p{Udform bean上了Q它已经不是普通意义上的form bean了。查看源代码Q可以看到它不仅仅有数据和校?重置ҎQ而且已经h了行为,从这个意义上来说Q它更像一个BO(Business Object)。这是前文讲到的,BeanActioncd用反原理,ҎURL来决定调用form bean的哪个方法(行ؓQ。form bean的这些方法的{֐很简单,例如Q?/p> <br /> <table cellspacing="0" cellpadding="5" width="47%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td class="content"> <pre> <code class="content"> public String myActionMethod() { //..work return "success"; } </code> </pre> </td> </tr> </tbody> </table> <p>Ҏ的返回值直接就是字W串Q对应的是forward的名Uͼ而不再是ActionForward对象Q创建ActionForward对象的Q务已l由BeanActioncM劳了?/p> <p>另外Q程序还提供了ActionContext工具c,该工L装了request 、response、form parameters、request attributes、session attributes?application attributes中的数据存取操作Q简单而线E安全,form beancM用该工具cd以进一步从表现层框架解耦?/p> <p>在这里需要特别指出的是,BeanActioncL对struts扩展的一个有益尝试,虽然提供了非常好的应用开发模式,但是它还非常斎ͼ一直在发展中?/p> <p> <a name="IDAVEIKB"> <b>? JpetStore 4.0具体实现</b> </a> <br /> <img height="588" alt="? JpetStore 4.0具体实现" src="http://www.uml.org.cn/j2ee/images/12282.jpg" width="600" border="0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /> </p> <p> <span id="wmqeeuq" class="content"> <a name="IDACFIKB"> <strong>2.4. 代码剖析</strong> </a> </span> <br />下面p我们开始进一步分析JpetStore4.0的源代码Qؓ下面的改造铺路?/p> <ul xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <li>BeanAction.java是唯一一个Struts actionc,位于com.ibatis.struts包下。正如上文所aQ它是一个通用的控制类Q利用反机Ӟ把控制{Udform bean的某个方法来处理。详l处理过E参考其源代码,单明晰? </li> <li> <p>Form beancM于com.ibatis.jpetstore.presentation包下Q命名规则ؓ***Bean。Form beancd部承于BaseBeanc,而BaseBeancd际承于ActionFormQ因此,Form beancd是Struts?ActionFormQForm beancȝ属性数据就由struts框架自动填充。而实际上QJpetStore4.0扩展了struts中ActionForm的应用: Form beanc还h行ؓQ更像一个BO,其行为(ҎQ由BeanActionҎ配置Qstruts-config.xmlQ的URL来调用。虽然如此,我们q是把Form beancd位于表现层?/p> <p>Struts-config.xml的配|里?U映方式,来告诉BeanAction把控制{到哪个form bean对象的哪个方法来处理?/p> <p>以这个请求连接ؓ例http://localhost/jpetstore4/shop/viewOrder.do</p> <p>1. URL Pattern</p> <table class="content" cellspacing="0" cellpadding="5" width="59%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td> <pre> <code class="content"> <action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction" name="orderBean" scope="session" validate="false"> <forward name="success" path="/order/ViewOrder.jsp"/> </action> </code> </pre> </td> </tr> </tbody> </table> <p>此种方式表示Q控制将被{发到"orderBean"q个form bean对象 ?viewOrder"ҎQ行为)来处理。方法名?path"参数的以"/"分隔的最后一部分?/p> <p>2. Method Parameter</p> <table class="content" cellspacing="0" cellpadding="5" width="52%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td> <pre> <code class="content"> <action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction" name="orderBean" parameter="viewOrder" scope="session" validate="false"> <forward name="success" path="/order/ViewOrder.jsp"/> </action> </code> </pre> </td> </tr> </tbody> </table> <p>此种方式表示Q控制将被{发到"orderBean"q个form bean对象?viewOrder"ҎQ行为)来处理。配|中?parameter"参数表示form beancM的方法?parameter"参数优先?path"参数?/p> <p>3. No Method call</p> <table class="content" cellspacing="0" cellpadding="5" width="55%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td> <pre> <code class="content"> <action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction" name="orderBean" parameter="*" scope="session" validate="false"> <forward name="success" path="/order/ViewOrder.jsp"/> </action> </code> </pre> </td> </tr> </tbody> </table> <p>此种方式表示Qform bean上没有Q何方法被调用。如果存?name"属性,则struts把表单参数等数据填充到form bean对象后,把控制{发到"success"。否则,如果name为空Q则直接转发控制?success"?/p> <p>q就相当于struts内置的org.apache.struts.actions.ForwardAction的功?/p> <table class="content" cellspacing="0" cellpadding="5" width="51%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td> <pre> <code class="content"> <action path="/shop/viewOrder" type="org.apache.struts.actions.ForwardAction" parameter="/order/ViewOrder.jsp " scope="session" validate="false"> </action> </code> </pre> </td> </tr> </tbody> </table> </li> <li>ServicecM于com.ibatis.jpetstore.service包下Q属于业务层。这些类装了业务以及相应的事务控制。Servicecȝform beancL调用? </li> <li>com.ibatis.jpetstore.persistence.iface包下的类是DAO接口Q属于业务层Q其屏蔽了底层的数据库操作,供具体的ServicecL调用。DaoConfigcL工具c(DAO工厂c)QServicec通过DaoConfigcL获得相应的DAO接口Q而不用关心底层的具体数据库操作,实现了如?中{耦合2}的解耦? </li> <li>com.ibatis.jpetstore.persistence.sqlmapdao包下的类是对应DAO接口的具体实玎ͼ在JpetStore4.0中采用了ibatis来实现ORM。这些实现类l承BaseSqlMapDaoc,而BaseSqlMapDaocdl承ibatis DAO 框架中的SqlMapDaoTemplatecRibatis的配|文件存攑֜com.ibatis.jpetstore.persistence.sqlmapdao.sql目录下。这些类和配|文件位于数据层 </li> <li>DomaincM于com.ibatis.jpetstore.domain包下Q是普通的javabean。在q里用作数据传输对象QDTOQ,贯穿视图层、业务层和数据层Q用于在不同层之间传输数据?</li> </ul> <p>剩下的部分就比较单了Q请看具体的源代码,非常清晰?/p> <p> <a name="IDAGGIKB"> <span id="wmqeeuq" class="atitle3"> <strong>2.5. 需要改造的地方</strong> </span> </a> <br />JpetStore4.0的关键就在struts Actioncdform beancMQ这也是其精华之一Q虽然该实现方式是试验性,待扩充和验证Q,在此ơ改造中我们要保留下来,x制层一点不变,表现层获取相应业务类的方式变了(要加载spring环境Q,其它保持不变。要特别x的改动是业务层和持久层,q运的是JpetStore4.0设计非常好,需要改动的地方非常,而且由模式可循,如下Q?/p> <p>1. 业务层和数据层用Spring BeanFactory机制理?/p> <p>2. 业务层的事务由spring 的aop通过声明来完成?/p> <p>3. 表现层(form beanQ获取业务类的方法改p定义工厂cL实现Q加载spring环境Q?/p> <p> <a name="IDAPGIKB"> <span id="wmqeeuq" class="atitle2"> <strong>3. JPetStore的改?/strong> </span> </a> <br /> </p> <p> <a name="IDAUGIKB"> <span id="wmqeeuq" class="atitle3"> <strong>3.1. 攚w后的架?/strong> </span> </a> <br /> </p> <p> <br /> <img height="640" alt="" src="http://www.uml.org.cn/j2ee/images/12283.jpg" width="582" border="0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /> </p> <p>其中U色部分是要增加的部分,蓝色部分是要修改的部分。下面就让我们逐一剖析?/p> <p> <a name="IDAHHIKB"> <span id="wmqeeuq" class="atitle3"> <strong>3.2. Spring Context的加?/strong> </span> </a> <br />Z在Struts中加载Spring ContextQ一般会在struts-config.xml的最后添加如下部分:</p> <br /> <table class="content" cellspacing="0" cellpadding="5" width="56%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td> <pre> <code class="content"> <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"> <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml" /> </plug-in> </code> </pre> </td> </tr> </tbody> </table> <p>Spring在设计时充分考虑C与Struts的协同工作,通过内置的Struts Plug-in在两者之间提供了良好的结合点。但是,因ؓ在这里我们一点也不改动JPetStore的控制层(q是JpetStore4.0的精华之一)Q所以本文不准备采用此方式来加蝲ApplicationContext。我们利用的是spring framework 的BeanFactory机制,采用自定义的工具c(bean工厂c)来加载spring的配|文Ӟ从中可以看出Spring有多灉|Q它提供了各U不同的方式来用其不同的部?层次Q您只需要用你想用的Q不需要的部分可以不用?/p> <p>具体的来_是在com.ibatis.spring包下创徏CustomBeanFactoryc,spring的配|文件applicationContext.xml也放在这个目录下。以下就是该cȝ全部代码Q很单:</p> <br /> <table class="content" cellspacing="0" cellpadding="5" width="63%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td> <pre> <code class="content"> public final class CustomBeanFactory { static XmlBeanFactory factory = null; static { Resource is = new InputStreamResource( CustomBeanFactory.class.getResourceAsStream("applicationContext.xml")); factory = new XmlBeanFactory(is); } public static Object getBean(String beanName){ return factory.getBean(beanName); } } </code> </pre> </td> </tr> </tbody> </table> <p>实际上就是封装了Spring 的XMLBeanFactory而已Qƈ且Spring的配|文件只需要加载一ơ,以后可以直接用CustomBeanFactory.getBean("someBean")来获得需要的对象?例如someBean)Q而不需要知道具体的cRCustomBeanFactorycȝ于{耦合1}的解耦?/p> <p>CustomBeanFactorycd本文中只用于表现层的form bean对象获得servicecȝ对象Q因为我们没有把form bean对象配置在applicationContext.xml中。但是,Z么不把表现层的form beancM配置h呢,q样q不着qCustomBeanFactory个类了,Spring会帮助我们创建需要的一切?问题的答案就在于form beancLstruts的ActionFormc!如果大家熟悉strutsQ就会知道ActionFormcLstruts自动创徏的:在一ơ请求中Qstruts判断Q如果ActionForm实例不存在,创Z个ActionForm对象Q把客户提交的表单数据保存到ActionForm对象中。因此formbeancȝ对象׃能由spring来创建,但是servicecM及数据层的DAOcd以,所以只有他们在spring中配|?/p> <p>所以,很自然的Q我们就创徏了CustomBeanFactoryc,在表现层来衔接struts和spring。就q么单,实现了另一U方式的{耦合一}的解耦?/p> <p> <a name="IDADYNKB"> <span id="wmqeeuq" class="atitle3"> <strong>3.3. 表现?/strong> </span> </a> <br />?面分析到Qstruts和spring是在表现层衔接v来的Q那么表现层p做稍微的更改Q即所需要的servicecȝ对象创徏上。以表现层的AccountBeancMؓ例:</p> <p>原来的源代码如下</p> <br /> <table class="content" cellspacing="0" cellpadding="5" width="59%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td height="95"> <pre> <code> <span id="wmqeeuq" class="content"> private static final AccountService accountService = AccountService.getInstance(); private static final CatalogService catalogService = CatalogService.getInstance(); </span> </code> </pre> </td> </tr> </tbody> </table> <p>攚w后的源代码如下</p> <br /> <table cellspacing="0" cellpadding="5" width="75%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td class="content"> <pre> <code class="content"> private static final AccountService accountService = (AccountService)CustomBeanFactory.getBean("AccountService"); private static final CatalogService catalogService = (CatalogService)CustomBeanFactory.getBean("CatalogService"); </code> </pre> </td> </tr> </tbody> </table> <p>其他的几个presentationcM同样方式攚w。这P表现层就完成了。关于表现层的其它部分如JSP{一概不动。也许您会说Q没有看Z么特别之处的好处啊?你还是额外实C一个工厂类。别着急,帷幕刚刚开启,spring是在表现层引入,但您发没发现Q?/p> <ul xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <li>presentationcM仅面向servicecȝ接口~程Q具?AccountService"是哪个实现类QpresentationcM知道Q是在spring的配|文仉配置。(本例中,Z最大限度的保持原来的代码不作变化,没有抽象出接口)。Spring鼓励面向接口~程Q因为是如此的方便和自然Q当然您也可以不q么做? </li> <li>CustomBeanFactoryq个工厂cMؓ什么会如此单,因ؓ其直接用了Spring的BeanFactory。Spring从其核心而言Q是一个DI容器Q其设计哲学是提供一U无侵入式的高扩展性的框架。ؓ了实现这个目标,Spring 大量引入了Java 的Reflection机制Q通过动态调用的方式避免编码方式的U束Qƈ在此基础上徏立了其核心组件BeanFactoryQ以此作为其依赖注入机制的实现基。org.springframework.beans包中包括了这些核心组件的实现c,核心中的核心为BeanWrapper和BeanFactorycR?</li> </ul> <p> <a name="IDA4YNKB"> <span id="wmqeeuq" class="atitle3"> <strong>3.4. 持久?/strong> </span> </a> <br />在讨Z务层之前Q我们先看一下持久层Q如下图所C:</p> <p> <br /> <img height="416" alt="" src="http://www.uml.org.cn/j2ee/images/12284.jpg" width="320" border="0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /> </p> <p>在上文中Q我们把iface包下的DAO接口归ؓ业务层,在这里不需要做修改。ibatis的sql配置文g也不需要改。要改的是DAO实现c,q在spring的配|文件中配置h?/p> <p>1、修改基c?/p> <p>所有的DAO实现c都l承于BaseSqlMapDaocR修改BaseSqlMapDaocd下:</p> <br /> <table cellspacing="0" cellpadding="5" width="57%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td class="content"> <pre> <code class="content"> public class BaseSqlMapDao extends SqlMapClientDaoSupport { protected static final int PAGE_SIZE = 4; protected SqlMapClientTemplate smcTemplate = this.getSqlMapClientTemplate(); public BaseSqlMapDao() { } } </code> </pre> </td> </tr> </tbody> </table> <p>使BaseSqlMapDaocL为承于Spring提供的SqlMapClientDaoSupportc,q定义了一个保护属性smcTemplateQ其cd为SqlMapClientTemplate。关于SqlMapClientTemplatecȝ详细说明请参照附录中?Spring中文参考手?</p> <p>2、修改DAO实现c?/p> <p>所有的DAO实现c还是承于BaseSqlMapDaoc,实现相应的DAO接口Q但其相应的DAO操作委托SqlMapClientTemplate来执行,以AccountSqlMapDaocMؓ例,部分代码如下Q?/p> <br /> <table class="content" cellspacing="0" cellpadding="5" width="61%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td> <pre> <code class="content"> public List getUsernameList() { return smcTemplate.queryForList("getUsernameList", null); } public Account getAccount(String username, String password) { Account account = new Account(); account.setUsername(username); account.setPassword(password); return (Account) smcTemplate.queryForObject("getAccountByUsernameAndPassword", account); } public void insertAccount(Account account) { smcTemplate.update("insertAccount", account); smcTemplate.update("insertProfile", account); smcTemplate.update("insertSignon", account); } </code> </pre> </td> </tr> </tbody> </table> <p>p么简单,所有函数的{֐都是一LQ只需要查找替换就可以了!</p> <p>3、除d厂类以及相应的配|文?/p> <p>除去DaoConfig.javaq个DAO工厂cd相应的配|文件dao.xmlQ因为DAO的获取现在要用spring来管理?/p> <p>4、DAO在Spring中的配置QapplicationContext.xmlQ?/p> <br /> <table class="content" cellspacing="0" cellpadding="5" width="60%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td> <pre> <code class="content"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>org.hsqldb.jdbcDriver</value> </property> <property name="url"> <value>jdbc:hsqldb:hsql://localhost/xdb</value> </property> <property name="username"> <value>sa</value> </property> <property name="password"> <value></value> </property> </bean> <!-- ibatis sqlMapClient config --> <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation"> <value> classpath:com\ibatis\jpetstore\persistence\sqlmapdao\sql\sql-map-config.xml </value> </property> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean> <!-- Transactions --> <bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean> <!-- persistence layer --> <bean id="AccountDao" class="com.ibatis.jpetstore.persistence.sqlmapdao.AccountSqlMapDao"> <property name="sqlMapClient"> <ref local="sqlMapClient"/> </property> </bean> </code> </pre> </td> </tr> </tbody> </table> <p>具体的语法请参照附录中的"Spring中文参考手?。在q里只简单解释一下:</p> <p>1. 我们首先创徏一个数据源dataSourceQ在q里配置的是hsqldb数据库。如果是ORACLE数据库,driverClassName的值是"oracle.jdbc.driver.OracleDriver"QURL的值类g"jdbc:oracle:thin:@wugfMobile:1521:cdcf"。数据源现在由spring来管理,那么现在我们可以去掉properties目录下database.propertiesq个配置文g了;q有不要忘记修改sql-map-config.xmlQ去?lt;properties resource="properties/database.properties"/>对它的引用?/p> <p>2. sqlMapClient节点。这个是针对ibatis SqlMap的SqlMapClientFactoryBean配置。实际上配置了一个sqlMapClient的创建工厂类。configLocation属性配|了ibatis映射文g的名U。dataSource属性指向了使用的数据源Q这h有用sqlMapClient的DAO都默认用了该数据源Q除非在DAO的配|中另外昑ּ指定?/p> <p>3. TransactionManager节点。定义了事务Q用的是DataSourceTransactionManager?/p> <p>4. 下面可以定义DAO节点了,如AccountDaoQ它的实现类是com.ibatis.jpetstore.persistence.sqlmapdao.AccountSqlMapDaoQ用的SQL配置从sqlMapClient中读取,数据库连接没有特别列出,那么是默认使用sqlMapClient配置的数据源datasource?/p> <p>q样Q我们就把持久层攚w完了,其他的DAO配置cM于AccountDao。怎么P单吧。这ơ有接口了:Q?AccountDao接口Q?gt;AccountSqlMapDao实现?/p> <p> <a name="IDAW0NKB"> <span id="wmqeeuq" class="atitle3"> <strong>3.5. 业务?/strong> </span> </a> <br />业务层的位置以及相关c,如下图所C:</p> <p> <br /> <img height="240" alt="" src="http://www.uml.org.cn/j2ee/images/12285.jpg" width="259" border="0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /> </p> <p>在这个例子中只有3个业务类Q我们以OrderServicecMؓ例来攚w,q个cL最复杂的,其中涉及了事务?/p> <p>1、在ApplicationContext配置文g中增加bean的配|:</p> <br /> <table class="content" cellspacing="0" cellpadding="5" width="57%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td> <pre> <code class="content"> <bean id="OrderService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"> <ref local="TransactionManager"></ref> </property> <property name="target"> <bean class="com.ibatis.jpetstore.service.OrderService"> <property name="itemDao"> <ref bean="ItemDao"/> </property> <property name="orderDao"> <ref bean="OrderDao"/> </property> <property name="sequenceDao"> <ref bean="SequenceDao"/> </property> </bean> </property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> </code> </pre> </td> </tr> </tbody> </table> <p>定义了一个OrderServiceQ还是很Ҏ懂的。ؓ了简单v见,使用了嵌套beanQ其实现cLcom.ibatis.jpetstore.service.OrderServiceQ分别引用了ItemDaoQOrderDaoQSequenceDao。该bean的insert*实现了事务管?AOP方式)。TransactionProxyFactoryBean自动创徏一个事务advisorQ?该advisor包括一个基于事务属性的pointcut,因此只有事务性的Ҏ被拦截?/p> <p>2、业务类的修?/p> <p>以OrderServiceZQ?/p> <br /> <table class="content" cellspacing="0" cellpadding="5" width="50%" bgcolor="#cccccc" border="1"> <tbody> <tr> <td> <pre> <code class="content"> public class OrderService { /* Private Fields */ private ItemDao itemDao; private OrderDao orderDao; private SequenceDao sequenceDao; /* Constructors */ public OrderService() { } /** * @param itemDao 要设|的 itemDao? */ public final void setItemDao(ItemDao itemDao) { this.itemDao = itemDao; } /** * @param orderDao 要设|的 orderDao? */ public final void setOrderDao(OrderDao orderDao) { this.orderDao = orderDao; } /** * @param sequenceDao 要设|的 sequenceDao? */ public final void setSequenceDao(SequenceDao sequenceDao) { this.sequenceDao = sequenceDao; } //剩下的部? …? } </code> </pre> </td> </tr> </tbody> </table> <p>U色部分Z攚w分。Spring采用的是Type2的设|依赖注入,所以我们只需要定义属性和相应的设值函数就可以了,ItemDaoQOrderDaoQSequenceDao的值由spring在运行期间注入。构造函数就可以为空了,另外也不需要自q写代码处理事务了Q事务在配置中声明)QdaoManager.startTransaction();{与事务相关的语句也可以L了。和原来的代码比较一下,是不是处理精了很多!可以更关注业务的实现?/p> <p> <a name="IDA31NKB"> <span id="wmqeeuq" class="atitle2"> <strong>4. l束?/strong> </span> </a> <br />ibatis是一个功能强大实用的SQL Map工具Q可以直接控制SQL,为系l设计提供了更大的自q间。其提供的最新示例程序JpetStore 4.0,设计优雅Q应用了q今为止很多最佛_践和设计模式Q非帔R于学习以及在此基础上创量的J2EE WEB应用E序。JpetStore 4.0是基于struts的,本文在此基础上,最大程度保持了原有设计的精华以及最的代码改动量,在业务层和持久化层引入了Spring。在您阅M本文以及攚w后的源代码后,会深切的感受到Spring带来的种U好处:自然的面向接口的~程Q业务对象的依赖注入Q一致的数据存取框架和声明式的事务处理,l一的配|文件…更重要的是Spring既是全面的又是模块化的,Spring有分层的体系l构Q这意味着您能选择仅仅使用它Q何一个独立的部分Q就像本文,而它的架构又是内部一致?/p> <img src ="http://www.aygfsteel.com/jhengfei/aggbug/80545.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/jhengfei/" target="_blank">Ҏ铸就辉煌</a> 2006-11-11 09:59 <a href="http://www.aygfsteel.com/jhengfei/archive/2006/11/11/80545.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HTTPh头所包含的信?/title><link>http://www.aygfsteel.com/jhengfei/archive/2006/10/24/76906.html</link><dc:creator>Ҏ铸就辉煌</dc:creator><author>Ҏ铸就辉煌</author><pubDate>Tue, 24 Oct 2006 02:25:00 GMT</pubDate><guid>http://www.aygfsteel.com/jhengfei/archive/2006/10/24/76906.html</guid><wfw:comment>http://www.aygfsteel.com/jhengfei/comments/76906.html</wfw:comment><comments>http://www.aygfsteel.com/jhengfei/archive/2006/10/24/76906.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/jhengfei/comments/commentRss/76906.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/jhengfei/services/trackbacks/76906.html</trackback:ping><description><![CDATA[ <p>因了需要用到这些信?所以ȝ一?方便以后参阅<br />通过request.getHeader("User-Agent")大致可以取得用户览器的信息<br />如果里面包含Q?br />"msie"-->MicroSoft <br />"opera" -->Opera Software<br />"mozilla"-->Netscape Communications<br /><br />如果取浏览器版本信息<br />String str = request.getHeader("User-Agent");<br />MS :  str.substring(str.indexOf("msie") + 5);<br />Other :<br />tmpString = (str.substring(tmpPos = (str.indexOf("/")) + 1, tmpPos + str.indexOf(" "))).trim();  //没有亲自?br /><br />操作pȝ部分,不啰嗦了<br />private void setOs()<br />{<br />if (this.userAgent.indexOf("win") > -1){<br />  if (this.userAgent.indexOf("windows 95") > -1 || this.userAgent.indexOf("win95") > -1){<br />     this.os = "Windows 95";<br />  }<br />  if (this.userAgent.indexOf("windows 98") > -1 || this.userAgent.indexOf("win98") > -1){<br />     this.os = "Windows 98";<br />  }<br />  if (this.userAgent.indexOf("windows nt") > -1 || this.userAgent.indexOf("winnt") > -1){<br />      this.os = "Windows NT";<br />  }<br />  if (this.userAgent.indexOf("win16") > -1 || this.userAgent.indexOf("windows 3.") > -1){<br />      this.os = "Windows 3.x";<br />  }<br /> }<br />}</p> <p>获取语言request.getHeader("Accept-Language");<br /><br />详细信息可以再分?...<br /><br /></p> <img src ="http://www.aygfsteel.com/jhengfei/aggbug/76906.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/jhengfei/" target="_blank">Ҏ铸就辉煌</a> 2006-10-24 10:25 <a href="http://www.aygfsteel.com/jhengfei/archive/2006/10/24/76906.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>?Lucene 加?Web 搜烦应用E序的开?/title><link>http://www.aygfsteel.com/jhengfei/archive/2006/10/17/75581.html</link><dc:creator>Ҏ铸就辉煌</dc:creator><author>Ҏ铸就辉煌</author><pubDate>Tue, 17 Oct 2006 05:05:00 GMT</pubDate><guid>http://www.aygfsteel.com/jhengfei/archive/2006/10/17/75581.html</guid><wfw:comment>http://www.aygfsteel.com/jhengfei/comments/75581.html</wfw:comment><comments>http://www.aygfsteel.com/jhengfei/archive/2006/10/17/75581.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/jhengfei/comments/commentRss/75581.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/jhengfei/services/trackbacks/75581.html</trackback:ping><description><![CDATA[ <blockquote>Lucene 是基?Java 的全文信息检索包Q它目前?Apache Jakarta 家族下面的一个开源项目。在q篇文章中,我们首先来看如何利用 Lucene 实现高搜烦功能Q然后学习如何利?Lucene 来创Z个健壮的 Web 搜烦应用E序?/blockquote> <!--START RESERVED FOR FUTURE USE INCLUDE FILES--> <!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES--> <p>在本文章中Q你会学习到如何利用 Lucene 实现高搜烦功能以及如何利用 Lucene 来创?Web 搜烦应用E序。通过q些学习Q你可以利?Lucene 来创q搜烦应用E序?/p> <p> <a name="N1005F"> <span id="wmqeeuq" class="atitle">架构概览</span> </a> </p> <p>通常一?Web 搜烦引擎的架构分为前端和后端两部分,像<a ><font color="#996699">图一</font></a>中所C。在前端程中,用户在搜索引擎提供的界面中输入要搜烦的关键词Q这里提到的用户界面一般是一个带有输入框?Web 面Q然后应用程序将搜烦的关键词解析成搜索引擎可以理解的形式Qƈ在烦引文件上q行搜烦操作。在排序后,搜烦引擎q回搜烦l果l用戗在后端程中,|络爬虫或者机器h从因特网上获?Web 面Q然后烦引子pȝ解析q些 Web 面q存入烦引文件中。如果你惛_?Lucene 来创Z?Web 搜烦应用E序Q那么它的架构也和上面所描述的类|如<a ><font color="#996699">图一</font></a>中所C?/p> <br /> <a name="figure1"> <b>Figure 1. Web 搜烦引擎架构</b> </a> <br /> <img height="380" alt="Web搜烦引擎架构" src="http://www-128.ibm.com/developerworks/cn/web/wa-lucene2/figure1.gif" width="449" /> <br /> <p> <a name="N10080"> <span id="wmqeeuq" class="atitle">利用 Lucene 实现高搜烦</span> </a> </p> <p>Lucene 支持多种形式的高U搜索,我们在这一部分中会q行探讨Q然后我会?Lucene ?API 来演C如何实现这些高U搜索功能?/p> <p> <a name="N10089"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">布尔操作W?/font> </strong> </span> </a> </p> <p>大多数的搜烦引擎都会提供布尔操作W让用户可以l合查询Q典型的布尔操作W有 AND, OR, NOT。Lucene 支持 5 U布操作符Q分别是 AND, OR, NOT, ?+), ?-)。接下来我会讲述每个操作W的用法?</p> <ul> <li> <b>OR</b>: 如果你要搜烦含有字符 A 或?B 的文,那么需要?OR 操作W。需要记住的是,如果你只是简单的用空格将两个关键词分割开Q其实在搜烦的时候搜索引擎会自动在两个关键词之间加上 OR 操作W。例如,“Java OR Lucene??“Java Lucene?都是搜烦含有 Java 或者含?Lucene 的文? </li> <li> <b>AND</b>: 如果你需要搜索包含一个以上关键词的文,那么需要?AND 操作W。例如,“Java AND Lucene?q回所有既包含 Java 又包?Lucene 的文档? </li> <li> <b>NOT</b>: Not 操作W得包含紧跟在 NOT 后面的关键词的文档不会被q回。例如,如果你想搜烦所有含?Java 但不含有 Lucene 的文,你可以用查询语?“Java NOT Lucene”。但是你不能只对一个搜索词使用q个操作W,比如Q查询语?“NOT Java?不会q回Ml果? </li> <li> <b>加号Q?Q?/b>: q个操作W的作用?AND 差不多,但它只对紧跟着它的一个搜索词起作用。例如,如果你想搜烦一定包?JavaQ但不一定包?Lucene 的文,可以用查询语句?Java Lucene”? </li> <li> <b>减号Q?Q?/b>: q个操作W的功能?NOT 一P查询语句 “Java -Lucene?q回所有包?Java 但不包含 Lucene 的文?</li> </ul> <p>接下来我们看一下如何利?Lucene 提供?API 来实现布查询?a ><font color="#996699">清单1</font></a> 昄了如果利用布操作符q行查询的过E?/p> <br /> <a name="Listing1"> <b>清单1Q用布操作符</b> </a> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode"> //Test boolean operator public void testOperator(String indexDirectory) throws Exception{ Directory dir = FSDirectory.getDirectory(indexDirectory,false); IndexSearcher indexSearcher = new IndexSearcher(dir); String[] searchWords = {"Java AND Lucene", "Java NOT Lucene", "Java OR Lucene", "+Java +Lucene", "+Java -Lucene"}; Analyzer language = new StandardAnalyzer(); Query query; for(int i = 0; i < searchWords.length; i++){ query = QueryParser.parse(searchWords[i], "title", language); Hits results = indexSearcher.search(query); System.out.println(results.length() + "search results for query " + searchWords[i]); } } </pre> </td> </tr> </tbody> </table> <br /> <p> <a name="N100BF"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">域搜?Field Search)</font> </strong> </span> </a> </p> <p>Lucene 支持域搜索,你可以指定一ơ查询是在哪些域(Field)上进行。例如,如果索引的文包含两个域Q?code>Title</code> ?<code>Content</code>Q你可以用查?“Title: Lucene AND Content: Java?来返回所有在 Title 域上包含 Lucene q且?Content 域上包含 Java 的文?a ><font color="#996699">清单 2</font></a> 昄了如何利?Lucene ?API 来实现域搜烦?</p> <br /> <a name="Listing2"> <b>清单2Q实现域搜烦</b> </a> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">//Test field search public void testFieldSearch(String indexDirectory) throws Exception{ Directory dir = FSDirectory.getDirectory(indexDirectory,false); IndexSearcher indexSearcher = new IndexSearcher(dir); String searchWords = "title:Lucene AND content:Java"; Analyzer language = new StandardAnalyzer(); Query query = QueryParser.parse(searchWords, "title", language); Hits results = indexSearcher.search(query); System.out.println(results.length() + "search results for query " + searchWords); } </pre> </td> </tr> </tbody> </table> <br /> <p> <a name="N100DE"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">通配W搜?Wildcard Search)</font> </strong> </span> </a> </p> <p>Lucene 支持两种通配W:问号Q?Q和星号Q?Q。你可以使用问号Q?Q来q行单字W的通配W查询,或者利用星P*Q进行多字符的通配W查询。例如,如果你想搜烦 tiny 或?tonyQ你可以用查询语?“t?ny”;如果你想查询 Teach, Teacher ?TeachingQ你可以用查询语?“Teach*”?a ><font color="#996699">清单3</font></a> 昄了通配W查询的q程?</p> <br /> <a name="Listing3"> <b>清单3Q进行通配W查?/b> </a> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">//Test wildcard search public void testWildcardSearch(String indexDirectory)throws Exception{ Directory dir = FSDirectory.getDirectory(indexDirectory,false); IndexSearcher indexSearcher = new IndexSearcher(dir); String[] searchWords = {"tex*", "tex?", "?ex*"}; Query query; for(int i = 0; i < searchWords.length; i++){ query = new WildcardQuery(new Term("title",searchWords[i])); Hits results = indexSearcher.search(query); System.out.println(results.length() + "search results for query " + searchWords[i]); } } </pre> </td> </tr> </tbody> </table> <br /> <p> <a name="N100F5"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">模糊查询</font> </strong> </span> </a> </p> <p>Lucene 提供的模p查询基于编辑距ȝ?Edit distance algorithm)。你可以在搜索词的尾部加上字W?~ 来进行模p查询。例如,查询语句 “think~?q回所有包含和 think cM的关键词的文档?a ><font color="#996699">清单 4</font></a> 昄了如果利?Lucene ?API q行模糊查询的代码?</p> <br /> <a name="Listing4"> <b>清单4Q实现模p查?/b> </a> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">//Test fuzzy search public void testFuzzySearch(String indexDirectory)throws Exception{ Directory dir = FSDirectory.getDirectory(indexDirectory,false); IndexSearcher indexSearcher = new IndexSearcher(dir); String[] searchWords = {"text", "funny"}; Query query; for(int i = 0; i < searchWords.length; i++){ query = new FuzzyQuery(new Term("title",searchWords[i])); Hits results = indexSearcher.search(query); System.out.println(results.length() + "search results for query " + searchWords[i]); } } </pre> </td> </tr> </tbody> </table> <br /> <p> <a name="N1010C"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">范围搜烦(Range Search)</font> </strong> </span> </a> </p> <p>范围搜烦匚w某个域上的值在一定范围的文档。例如,查询 “age:[18 TO 35]?q回所?age 域上的值在 18 ?35 之间的文档?a ><font color="#996699">清单5</font></a>昄了利?Lucene ?API q行q回搜烦的过E?</p> <br /> <a name="Listing5"> <b>清单5Q测试范围搜?/b> </a> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">//Test range search public void testRangeSearch(String indexDirectory)throws Exception{ Directory dir = FSDirectory.getDirectory(indexDirectory,false); IndexSearcher indexSearcher = new IndexSearcher(dir); Term begin = new Term("birthDay","20000101"); Term end = new Term("birthDay","20060606"); Query query = new RangeQuery(begin,end,true); Hits results = indexSearcher.search(query); System.out.println(results.length() + "search results is returned"); } </pre> </td> </tr> </tbody> </table> <br /> <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="N10123"> <span id="wmqeeuq" class="atitle">?Web 应用E序中集?Lucene</span> </a> </p> <p>接下来我们开发一?Web 应用E序利用 Lucene 来检索存攑֜文g服务器上?HTML 文档。在开始之前,需要准备如下环境:</p> <ol> <li>Eclipse 集成开发环? </li> <li>Tomcat 5.0 </li> <li>Lucene Library </li> <li>JDK 1.5 </li> </ol> <p>q个例子使用 Eclipse q行 Web 应用E序的开发,最l这?Web 应用E序跑在 Tomcat 5.0 上面。在准备好开发所必需的环境之后,我们接下来进?Web 应用E序的开发?</p> <p> <a name="N1013E"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">1、创Z个动?Web 目</font> </strong> </span> </a> </p> <ol> <li>?Eclipse 里面Q选择 <b>File > New > Project</b>Q然后再弹出的窗口中选择<b>动?Web 目</b>Q如<a ><font color="#996699">图二</font></a>所C?</li> </ol> <br /> <a name="figure2"> <b>图二Q创建动态Web目</b> </a> <br /> <img height="473" alt="创徏动态Web目" src="http://www-128.ibm.com/developerworks/cn/web/wa-lucene2/figure2.jpg" width="496" /> <br /> <ol start="2"> <li>在创建好动?Web 目之后Q你会看到创建好的项目的l构Q如<a ><font color="#996699">图三</font></a>所C,目的名UCؓ sample.dw.paper.lucene?</li> </ol> <br /> <a name="figure3"> <b>图三Q动?Web 目的结?/b> </a> <br /> <img height="338" alt="动?Web 目的结? src="http://www-128.ibm.com/developerworks/cn/web/wa-lucene2/figure3.jpg" width="329" /> <br /> <p> <a name="N1017D"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">2. 设计 Web 目的架?/font> </strong> </span> </a> </p> <p>在我们的设计中,把该pȝ分成如下四个子系l:</p> <ol> <li> <b>用户接口</b>: q个子系l提供用L面用户可以?Web 应用E序服务器提交搜索请求,然后搜烦l果通过用户接口来显C出来。我们用一个名?search.jsp 的页面来实现该子pȝ? </li> <li> <b>h理?/b>: q个子系l管理从客户端发送过来的搜烦hq把搜烦h分发到搜索子pȝ中。最后搜索结果从搜烦子系l返回ƈ最l发送到用户接口子系l。我们用一?Servlet 来实现这个子pȝ? </li> <li> <b>搜烦子系l?/b>: q个子系l负责在索引文g上进行搜索ƈ把搜索结构传递给h理器。我们?Lucene 提供?API 来实现该子系l? </li> <li> <b>索引子系l?/b>: q个子系l用来ؓ HTML 面来创建烦引。我们?Lucene ?API 以及 Lucene 提供的一?HTML 解析器来创徏该子pȝ?</li> </ol> <p> <a > <font color="#996699">?</font> </a>昄了我们设计的详细信息Q我们将用户接口子系l放?webContent 目录下面。你会看C个名?search.jsp 的页面在q个文g多w面。请求管理子pȝ在包 <code>sample.dw.paper.lucene.servlet</code> 下面Q类 <code>SearchController</code> 负责功能的实现。搜索子pȝ攑֜?<code>sample.dw.paper.lucene.search</code> 当中Q它包含了两个类Q?code>SearchManager</code> ?<code>SearchResultBean</code>Q第一个类用来实现搜烦功能Q第二个cȝ来描q搜索结果的l构。烦引子pȝ攑֜?<code>sample.dw.paper.lucene.index</code> 当中。类 <code>IndexManager</code> 负责?HTML 文g创徏索引。该子系l利用包 <code>sample.dw.paper.lucene.util</code> 里面的类 <code>HTMLDocParser</code> 提供的方?<code>getTitle</code> ?<code>getContent</code> 来对 HTML 面q行解析?</p> <br /> <a name="figure4"> <b>囑֛Q项目的架构设计</b> </a> <br /> <img height="324" alt="目的架构设? src="http://www-128.ibm.com/developerworks/cn/web/wa-lucene2/figure4.jpg" width="384" /> <br /> <p> <a name="N101DF"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">3. 子系l的实现</font> </strong> </span> </a> </p> <p>在分析了pȝ的架构设计之后,我们接下来看pȝ实现的详l信息?</p> <ol> <li> <b>用户接口</b>: q个子系l有一个名?search.jsp ?JSP 文g来实玎ͼq个 JSP 面包含两个部分。第一部分提供了一个用h口去?Web 应用E序服务器提交搜索请求,?a ><font color="#996699">?</font></a>所C。注意到q里的搜索请求发送到了一个名?SearchController ?Servlet 上面。Servlet 的名字和具体实现的类的对应关pd web.xml 里面指定?</li> </ol> <br /> <a name="figure5"> <b>?Q向Web服务器提交搜索请?/b> </a> <br /> <img height="207" alt="向Web服务器提交搜索请? src="http://www-128.ibm.com/developerworks/cn/web/wa-lucene2/figure5.jpg" width="532" /> <br /> <p>q个JSP的第二部分负责显C搜索结果给用户Q如<a ><font color="#996699">?</font></a>所C: </p> <br /> <a name="figure6"> <b>?Q显C搜索结?/b> </a> <br /> <img height="360" alt="昄搜烦l果" src="http://www-128.ibm.com/developerworks/cn/web/wa-lucene2/figure6.jpg" width="572" /> <br /> <ol start="2"> <li> <b>h理?/b>: 一个名?<code>SearchController</code> ?servlet 用来实现该子pȝ?a ><font color="#996699">清单Q?/font></a>l出了这个类的源代码?</li> </ol> <br /> <a name="Listing6"> <b>清单Q:h理器的实现</b> </a> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">package sample.dw.paper.lucene.servlet; import java.io.IOException; import java.util.List; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import sample.dw.paper.lucene.search.SearchManager; /** * This servlet is used to deal with the search request * and return the search results to the client */ public class SearchController extends HttpServlet{ private static final long serialVersionUID = 1L; public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ String searchWord = request.getParameter("searchWord"); SearchManager searchManager = new SearchManager(searchWord); List searchResult = null; searchResult = searchManager.search(); RequestDispatcher dispatcher = request.getRequestDispatcher("search.jsp"); request.setAttribute("searchResult",searchResult); dispatcher.forward(request, response); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ doPost(request, response); } } </pre> </td> </tr> </tbody> </table> <br /> <p>?a ><font color="#996699">清单6</font></a>中,<code>doPost</code> Ҏ从客L获取搜烦词ƈ创徏c?<code>SearchManager</code> 的一个实例,其中c?<code>SearchManager</code> 在搜索子pȝ中进行了定义。然后,<code>SearchManager</code> 的方?search 会被调用。最后搜索结果被q回到客L?</p> <ol start="3"> <li> <b>搜烦子系l?/b>: 在这个子pȝ中,我们定义了两个类Q?code>SearchManager</code> ?<code>SearchResultBean</code>。第一个类用来实现搜烦功能Q第二个cL个JavaBeanQ用来描q搜索结果的l构?a ><font color="#996699">清单7</font></a>l出了类 <code>SearchManager</code> 的源代码?</li> </ol> <br /> <a name="Listing7"> <b>清单7Q搜索功能的实现</b> </a> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">package sample.dw.paper.lucene.search; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import sample.dw.paper.lucene.index.IndexManager; /** * This class is used to search the * Lucene index and return search results */ public class SearchManager { private String searchWord; private IndexManager indexManager; private Analyzer analyzer; public SearchManager(String searchWord){ this.searchWord = searchWord; this.indexManager = new IndexManager(); this.analyzer = new StandardAnalyzer(); } /** * do search */ public List search(){ List searchResult = new ArrayList(); if(false == indexManager.ifIndexExist()){ try { if(false == indexManager.createIndex()){ return searchResult; } } catch (IOException e) { e.printStackTrace(); return searchResult; } } IndexSearcher indexSearcher = null; try{ indexSearcher = new IndexSearcher(indexManager.getIndexDir()); }catch(IOException ioe){ ioe.printStackTrace(); } QueryParser queryParser = new QueryParser("content",analyzer); Query query = null; try { query = queryParser.parse(searchWord); } catch (ParseException e) { e.printStackTrace(); } if(null != query >> null != indexSearcher){ try { Hits hits = indexSearcher.search(query); for(int i = 0; i < hits.length(); i ++){ SearchResultBean resultBean = new SearchResultBean(); resultBean.setHtmlPath(hits.doc(i).get("path")); resultBean.setHtmlTitle(hits.doc(i).get("title")); searchResult.add(resultBean); } } catch (IOException e) { e.printStackTrace(); } } return searchResult; } } </pre> </td> </tr> </tbody> </table> <br /> <p>?a ><font color="#996699">清单7</font></a>中,注意到在q个c里面有三个U有属性。第一个是 <code>searchWord</code>Q代表了来自客户端的搜烦词。第二个?<code>indexManager</code>Q代表了在烦引子pȝ中定义的c?<code>IndexManager</code> 的一个实例。第三个?<code>analyzer</code>Q代表了用来解析搜烦词的解析器。现在我们把注意力放在方?<code>search</code> 上面。这个方法首先检查烦引文件是否已l存在,如果已经存在Q那么就在已l存在的索引上进行检索,如果不存在,那么首先调用c?<code>IndexManager</code> 提供的方法来创徏索引Q然后在新创建的索引上进行检索。搜索结果返回后Q这个方法从搜烦l果中提取出需要的属性ƈ为每个搜索结果生成类 <code>SearchResultBean</code> 的一个实例。最后这?<code>SearchResultBean</code> 的实例被攑ֈ一个列表里面ƈq回l请求管理器?/p> <p>在类 <code>SearchResultBean</code> 中,含有两个属性,分别?<code>htmlPath</code> ?<code>htmlTitle</code>Q以及这个两个属性的 get ?set Ҏ。这也意味着我们的搜索结果包含两个属性:<code>htmlPath</code> ?<code>htmlTitle</code>Q其?<code>htmlPath</code> 代表?HTML 文g的\径,<code>htmlTitle</code> 代表?HTML 文g的标题?</p> <ol start="4"> <li> <b>索引子系l?/b>: c?<code>IndexManager</code> 用来实现q个子系l?a ><font color="#996699">清单8</font></a> l出了这个类的源代码?</li> </ol> <br /> <a name="Listing8"> <b>清单8Q烦引子pȝ的实?/b> </a> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">package sample.dw.paper.lucene.index; import java.io.File; import java.io.IOException; import java.io.Reader; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import sample.dw.paper.lucene.util.HTMLDocParser; /** * This class is used to create an index for HTML files * */ public class IndexManager { //the directory that stores HTML files private final String dataDir = "c:\\dataDir"; //the directory that is used to store a Lucene index private final String indexDir = "c:\\indexDir"; /** * create index */ public boolean createIndex() throws IOException{ if(true == ifIndexExist()){ return true; } File dir = new File(dataDir); if(!dir.exists()){ return false; } File[] htmls = dir.listFiles(); Directory fsDirectory = FSDirectory.getDirectory(indexDir, true); Analyzer analyzer = new StandardAnalyzer(); IndexWriter indexWriter = new IndexWriter(fsDirectory, analyzer, true); for(int i = 0; i < htmls.length; i++){ String htmlPath = htmls[i].getAbsolutePath(); if(htmlPath.endsWith(".html") || htmlPath.endsWith(".htm")){ addDocument(htmlPath, indexWriter); } } indexWriter.optimize(); indexWriter.close(); return true; } /** * Add one document to the Lucene index */ public void addDocument(String htmlPath, IndexWriter indexWriter){ HTMLDocParser htmlParser = new HTMLDocParser(htmlPath); String path = htmlParser.getPath(); String title = htmlParser.getTitle(); Reader content = htmlParser.getContent(); Document document = new Document(); document.add(new Field("path",path,Field.Store.YES,Field.Index.NO)); document.add(new Field("title",title,Field.Store.YES,Field.Index.TOKENIZED)); document.add(new Field("content",content)); try { indexWriter.addDocument(document); } catch (IOException e) { e.printStackTrace(); } } /** * judge if the index exists already */ public boolean ifIndexExist(){ File directory = new File(indexDir); if(0 < directory.listFiles().length){ return true; }else{ return false; } } public String getDataDir(){ return this.dataDir; } public String getIndexDir(){ return this.indexDir; } } </pre> </td> </tr> </tbody> </table> <br /> <p>q个cd含两个私有属性,分别?<code>dataDir</code> ?<code>indexDir</code>?code>dataDir</code> 代表存放{待q行索引?HTML 面的\径,<code>indexDir</code> 代表了存?Lucene 索引文g的\径。类 <code>IndexManager</code> 提供了三个方法,分别?<code>createIndex</code>, <code>addDocument</code> ?<code>ifIndexExist</code>。如果烦引不存在的话Q你可以使用Ҏ <code>createIndex</code> dZ个新的烦引,用方?<code>addDocument</code> d一个烦引上d文。在我们的场景中Q一个文档就是一?HTML 面。方?<code>addDocument</code> 会调用由c?<code>HTMLDocParser</code> 提供的方法对 HTML 文档q行解析。你可以使用最后一个方?<code>ifIndexExist</code> 来判?Lucene 的烦引是否已l存在?</p> <p>现在我们来看一下放在包 <code>sample.dw.paper.lucene.util</code> 里面的类 <code>HTMLDocParser</code>。这个类用来?HTML 文g中提取出文本信息。这个类包含三个ҎQ分别是 <code>getContent</code>Q?code>getTitle</code> ?<code>getPath</code>。第一个方法返回去除了 HTML 标记的文本内容,W二个方法返?HTML 文g的标题,最后一个方法返?HTML 文g的\径?a ><font color="#996699">清单9</font></a> l出了这个类的源代码?</p> <br /> <a name="Listing9"> <b>清单9QHTML 解析?/b> </a> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">package sample.dw.paper.lucene.util; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; import org.apache.lucene.demo.html.HTMLParser; public class HTMLDocParser { private String htmlPath; private HTMLParser htmlParser; public HTMLDocParser(String htmlPath){ this.htmlPath = htmlPath; initHtmlParser(); } private void initHtmlParser(){ InputStream inputStream = null; try { inputStream = new FileInputStream(htmlPath); } catch (FileNotFoundException e) { e.printStackTrace(); } if(null != inputStream){ try { htmlParser = new HTMLParser(new InputStreamReader(inputStream, "utf-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } public String getTitle(){ if(null != htmlParser){ try { return htmlParser.getTitle(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } return ""; } public Reader getContent(){ if(null != htmlParser){ try { return htmlParser.getReader(); } catch (IOException e) { e.printStackTrace(); } } return null; } public String getPath(){ return this.htmlPath; } } </pre> </td> </tr> </tbody> </table> <br /> <p> <a name="N1032B"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">5Q在 Tomcat 5.0 上运行应用程?/font> </strong> </span> </a> </p> <p>现在我们可以?Tomcat 5.0 上运行开发好的应用程序?</p> <ol> <li>右键单击 <b>search.jsp</b>Q然后选择 <b>Run as > Run on Server</b>Q如<a ><font color="#996699">?</font></a>所C?</li> </ol> <br /> <a name="figure7"> <b>?Q配|?Tomcat 5.0</b> </a> <br /> <img height="434" alt="配置 Tomcat 5.0" src="http://www-128.ibm.com/developerworks/cn/web/wa-lucene2/figure7.jpg" width="478" /> <br /> <ol start="2"> <li>在弹出的H口中,选择 <b>Tomcat v5.0 Server</b> 作ؓ目标 Web 应用E序服务器,然后点击 <b>Next</b>Q如<a ><font color="#996699">?</font></a> 所C: </li> </ol> <br /> <a name="figure8"> <b>?Q选择 Tomcat 5.0</b> </a> <br /> <img height="433" alt="选择 Tomcat 5.0" src="http://www-128.ibm.com/developerworks/cn/web/wa-lucene2/figure8.jpg" width="467" /> <br /> <ol start="3"> <li>现在需要指定用来运?Web 应用E序?Apache Tomcat 5.0 以及 JRE 的\径。这里你所选择?JRE 的版本必d你用来编?Java 文g?JRE 的版本一致。配|好之后Q点?<b>Finish</b>。如 <a ><font color="#996699">?</font></a> 所C?</li> </ol> <br /> <a name="figure9"> <b>?Q完成Tomcat 5.0的配|?/b> </a> <br /> <img height="436" alt="完成Tomcat 5.0的配|? src="http://www-128.ibm.com/developerworks/cn/web/wa-lucene2/figure9.jpg" width="468" /> <br /> <ol start="4"> <li>配置好之后,Tomcat 会自动运行,q且会对 search.jsp q行~译q显C给用户。如 <a ><font color="#996699">?0</font></a> 所C?</li> </ol> <br /> <a name="figure10"> <b>?0Q用L?/b> </a> <br /> <img height="403" alt="用户界面" src="http://www-128.ibm.com/developerworks/cn/web/wa-lucene2/figure10.jpg" width="521" /> <br /> <ol start="5"> <li>在输入框中输入关键词 “information?然后单击 <b>Search</b> 按钮。然后这个页面上会显C出搜烦l果来,?<a ><font color="#996699">?1</font></a> 所C?</li> </ol> <br /> <a name="figure11"> <b>?1Q搜索结?/b> </a> <br /> <img height="416" alt="搜烦l果" src="http://www-128.ibm.com/developerworks/cn/web/wa-lucene2/figure11.jpg" width="526" /> <br /> <ol start="6"> <li>单击搜烦l果的第一个链接,面上就会显C出所链接到的面的内宏V如 <a ><font color="#996699">?2</font></a> 所C? </li> </ol> <br /> <a name="figure12"> <b>?2Q详l信?/b> </a> <br /> <img height="419" alt="详细信息" src="http://www-128.ibm.com/developerworks/cn/web/wa-lucene2/figure12.jpg" width="525" /> <br /> <p>现在我们已经成功的完成了CZ目的开发,q成功的用Lucene实现了搜索和索引功能。你可以下蝲q个目的源代码Q?a ><font color="#996699">下蝲</font></a>Q?</p> <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="N103E8"> <span id="wmqeeuq" class="atitle">ȝ</span> </a> </p> <p>Lucene 提供了灵zȝ接口使我们更加方便的设计我们?Web 搜烦应用E序。如果你惛_你的应用E序中加入搜索功能,那么 Lucene 是一个很好的选择。在设计你的下一个带有搜索功能的应用E序的时候可以考虑使用 Lucene 来提供搜索功能?</p> <img src ="http://www.aygfsteel.com/jhengfei/aggbug/75581.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/jhengfei/" target="_blank">Ҏ铸就辉煌</a> 2006-10-17 13:05 <a href="http://www.aygfsteel.com/jhengfei/archive/2006/10/17/75581.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA EXCEL APIhttp://www.aygfsteel.com/jhengfei/archive/2006/08/29/66481.htmlҎ铸就辉煌Ҏ铸就辉煌Tue, 29 Aug 2006 09:32:00 GMThttp://www.aygfsteel.com/jhengfei/archive/2006/08/29/66481.htmlhttp://www.aygfsteel.com/jhengfei/comments/66481.htmlhttp://www.aygfsteel.com/jhengfei/archive/2006/08/29/66481.html#Feedback0http://www.aygfsteel.com/jhengfei/comments/commentRss/66481.htmlhttp://www.aygfsteel.com/jhengfei/services/trackbacks/66481.htmlJAVA EXCEL API?br />
Java Excel是一开放源码项目,通过它Java开发h员可以读取Excel文g的内宏V创建新的Excel文g、更新已l存在的Excel文g。用该API非Windows操作pȝ也可以通过UJava应用来处理Excel数据表。因为是使用Java~写的,所以我们在Web应用中可以通过JSP、Servlet来调用API实现对Excel数据表的讉K?br />
现在发布的稳定版本是V2.0Q提供以下功能:

从Excel 95?7?000{格式的文g中读取数据;
dExcel公式Q可以读取Excel 97以后的公式)Q?
生成Excel数据表(格式为Excel 97Q;
支持字体、数字、日期的格式化;
支持单元格的阴媄操作Q以及颜色操作;
修改已经存在的数据表Q?
现在q不支持以下功能Q但不久׃提供了:

不能够读取图表信息;
可以读,但是不能生成公式QQ何类型公式最后的计算值都可以dQ?
应用CZ

1 从Excel文gd数据?br />
Java Excel API既可以从本地文gpȝ的一个文?.xls)Q也可以从输入流中读取Excel数据表。读取Excel数据表的W一步是创徏Workbook(术语Q工作薄)Q下面的代码片段举例说明了应该如何操作:(完整代码见ExcelReading.java)


import java.io.*;
import jxl.*;
????br />try
{
//构徏Workbook对象, 只读Workbook对象
//直接从本地文件创建Workbook
//从输入流创徏Workbook
   InputStream is = new FileInputStream(sourcefile);
   jxl.Workbook rwb = Workbook.getWorkbook(is);
}
catch (Exception e)
{
e.printStackTrace();
}



一旦创ZWorkbookQ我们就可以通过它来讉KExcel Sheet(术语Q工作表)。参考下面的代码片段Q?br />

//获取W一张Sheet?br />Sheet rs = rwb.getSheet(0);



我们既可能通过Sheet的名U来讉K它,也可以通过下标来访问它。如果通过下标来访问的话,要注意的一Ҏ下标?开始,像数组一栗?br />
一旦得CSheetQ我们就可以通过它来讉KExcel Cell(术语Q单元格)。参考下面的代码片段Q?br />

//获取W一行,W一列的?br />Cell c00 = rs.getCell(0, 0);
String strc00 = c00.getContents();

//获取W一行,W二列的?br />Cell c10 = rs.getCell(1, 0);
String strc10 = c10.getContents();

//获取W二行,W二列的?br />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());



如果仅仅是取得Cell的|我们可以方便地通过getContents()ҎQ它可以Q何类型的Cell值都作ؓ一个字W串q回。示例代码中Cell(0, 0)是文本型QCell(1, 0)是数字型QCell(1,1)是日期型Q通过getContents()Q三U类型的q回值都是字W型?br />
如果有需要知道Cell内容的确切类型,API也提供了一pd的方法。参考下面的代码片段Q?br />

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());



在得到Cell对象后,通过getType()Ҏ可以获得该单元格的类型,然后与API提供的基本类型相匚wQ强制{换成相应的类型,最后调用相应的取值方法getXXX()Q就可以得到定cd的倹{API提供了以下基本类型,与Excel的数据格式相对应Q如下图所C:





每种cd的具体意义,请参见Java Excel API Document?br />
当你完成对Excel电子表格数据的处理后Q一定要使用close()Ҏ来关闭先前创建的对象Q以释放d数据表的q程中所占用的内存空_在读取大量数据时昑־ؓ重要。参考如下代码片D:


//操作完成Ӟ关闭对象Q释攑֍用的内存I间
rwb.close();



Java Excel API提供了许多访问Excel数据表的ҎQ在q里我只要地介绍几个常用的方法,其它的方法请参考附录中的Java Excel API Document?br />
WorkbookcL供的Ҏ

1. int getNumberOfSheets()
获得工作薄(WorkbookQ中工作表(SheetQ的个数Q示例:


jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
int sheets = rwb.getNumberOfSheets();



2. Sheet[] getSheets()
q回工作薄(WorkbookQ中工作表(SheetQ对象数l,CZQ?br />

jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
Sheet[] sheets = rwb.getSheets();



3. String getVersion()
q回正在使用的API的版本号Q好像是没什么太大的作用?br />

jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
String apiVersion = rwb.getVersion();



Sheet接口提供的方?br />
1) String getName()
获取Sheet的名UͼCZQ?br />

jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
String sheetName = rs.getName();



2) int getColumns()
获取Sheet表中所包含的d敎ͼCZQ?br />

jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
int rsColumns = rs.getColumns();



3) Cell[] getColumn(int column)
获取某一列的所有单元格Q返回的是单元格对象数组Q示例:


jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
Cell[] cell = rs.getColumn(0);



4) int getRows()
获取Sheet表中所包含的总行敎ͼCZQ?br />

jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
int rsRows = rs.getRows();



5) Cell[] getRow(int row)
获取某一行的所有单元格Q返回的是单元格对象数组Q示例子Q?br />

jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
Cell[] cell = rs.getRow(0);



6) Cell getCell(int column, int row)
获取指定单元格的对象引用Q需要注意的是它的两个参敎ͼW一个是列数Q第二个是行敎ͼq与通常的行、列l合有些不同?br />

jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
Cell cell = rs.getCell(0, 0);



2 生成新的Excel工作?br />
下面的代码主要是向大家介l如何生成简单的Excel工作表,在这里单元格的内Ҏ不带M修饰?如:字体Q颜色等{?Q所有的内容都作为字W串写入?完整代码见ExcelWriting.java)

与读取Excel工作表相|首先要用Workbookcȝ工厂Ҏ创徏一个可写入的工作薄(Workbook)对象Q这里要注意的是Q只能通过API提供的工厂方法来创徏WorkbookQ而不能用WritableWorkbook的构造函敎ͼ因ؓcWritableWorkbook的构造函Cؓprotectedcd。示例代码片D如下:


import java.io.*;
import jxl.*;
import jxl.write.*;
????br />try
{
//构徏Workbook对象, 只读Workbook对象
//Method 1Q创建可写入的Excel工作?br />   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();
}



API提供了两U方式来处理可写入的输出,一U是直接生成本地文gQ如果文件名不带全\径的话,~省的文件会定位在当前目录,如果文g名带有全路径的话Q则生成的Excel文g则会定位在相应的目录Q另外一U是Excel对象直接写入到输出流Q例如:用户通过览器来讉KWeb服务器,如果HTTP头设|正的话,览器自动调用客L的Excel应用E序Q来昄动态生成的Excel电子表格?br />
接下来就是要创徏工作表,创徏工作表的Ҏ与创建工作薄的方法几乎一P同样是通过工厂模式Ҏ获得相应的对象,该方法需要两个参敎ͼ一个是工作表的名称Q另一个是工作表在工作薄中的位|,参考下面的代码片段Q?br />

//创徏Excel工作?br />jxl.write.WritableSheet ws = wwb.createSheet("Test Sheet 1", 0);



"q锅也支好了Q材料也准备齐全了,可以开始下锅了Q?Q现在要做的只是实例化API所提供的Excel基本数据cdQƈ它们添加到工作表中可以了Q参考下面的代码片段Q?br />

//1.dLabel对象
jxl.write.Label labelC = new jxl.write.Label(0, 0, "This is a Label cell");
ws.addCell(labelC);

//d带有字型Formatting的对?br />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的对?br />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);



q里有两点大家要引v大家的注意。第一点,在构造单元格Ӟ单元格在工作表中的位|就已经定了。一旦创建后Q单元格的位|是不能够变更的Q尽单元格的内Ҏ可以改变的。第二点Q单元格的定位是按照下面q样的规?column, row)Q而且下标都是?开始,例如QA1被存储在(0, 0)QB1被存储在(1, 0)?br />
最后,不要忘记关闭打开的Excel工作薄对象,以释攑֍用的内存Q参见下面的代码片段Q?br />

//写入Exel工作?br />wwb.write();

//关闭Excel工作薄对?br />wwb.close();



q可能与dExcel文g的操作有少不同Q在关闭Excel对象之前Q你必须要先调用write()ҎQ因为先前的操作都是存储在缓存中的,所以要通过该方法将操作的内容保存在文g中。如果你先关闭了Excel对象Q那么只能得C张空的工作薄了?br />
3 拯、更新Excel工作?br />
接下来简要介l一下如何更C个已l存在的工作薄,主要是下面二步操作,W一步是构造只ȝExcel工作薄,W二步是利用已经创徏的Excel工作薄创建新的可写入的Excel工作薄,参考下面的代码片段Q?完整代码见ExcelModifying.java)


//创徏只读的Excel工作薄的对象
jxl.Workbook rw = jxl.Workbook.getWorkbook(new File(sourcefile));

//创徏可写入的Excel工作薄对?br />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, 做出相应的{?br />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();



之所以用这U方式构建Excel对象Q完全是因ؓ效率的原因,因ؓ上面的示例才是API的主要应用。ؓ了提高性能Q在d工作表时Q与数据相关的一些输Z息,所有的格式信息Q如Q字体、颜色等{,是不被处理的Q因为我们的目的是获得行数据的|既没有了修饎ͼ也不会对行数据的g生什么媄响。唯一的不利之处就是,在内存中会同时保存两个同L工作表,q样当工作表体积比较大时Q会占用相当大的内存Q但现在好像内存的大ƈ不是什么关键因素了?br />
一旦获得了可写入的工作表对象,我们可以对单元格对象进行更新的操作了,在这里我们不必调用API提供的add()ҎQ因为单元格已经于工作表当中Q所以我们只需要调用相应的setXXX()ҎQ就可以完成更新的操作了?br />
单元格原有的格式化修饰是不能去掉的Q我们还是可以将新的单元g饰加上去Q以使单元格的内容以不同的Ş式表现?br />
新生成的工作表对象是可写入的Q我们除了更新原有的单元格外Q还可以d新的单元格到工作表中Q这与示?的操作是完全一L?br />
最后,不要忘记调用write()ҎQ将更新的内容写入到文g中,然后关闭工作薄对象,q里有两个工作薄对象要关闭,一个是只读的,另外一个是可写入的?br />
以上摘自IBM|站

Ҏ铸就辉煌 2006-08-29 17:32 发表评论
]]>
字符Q字节和~码http://www.aygfsteel.com/jhengfei/archive/2006/06/23/54641.htmlҎ铸就辉煌Ҏ铸就辉煌Fri, 23 Jun 2006 03:30:00 GMThttp://www.aygfsteel.com/jhengfei/archive/2006/06/23/54641.htmlhttp://www.aygfsteel.com/jhengfei/comments/54641.htmlhttp://www.aygfsteel.com/jhengfei/archive/2006/06/23/54641.html#Feedback0http://www.aygfsteel.com/jhengfei/comments/commentRss/54641.htmlhttp://www.aygfsteel.com/jhengfei/services/trackbacks/54641.html [原创文章Q{载请保留或注明出处:http://www.regexlab.com/zh/encoding.htm]

U别Q中U?/p>

摘要Q本文介l了字符与编码的发展q程Q相x늚正确理解。D例说明了一些实际应用中Q编码的实现Ҏ。然后,本文讲述了通常对字W与~码的几U误解,׃q些误解而导致ؕ码生的原因Q以及消除ؕ码的办法。本文的内容늛了“中文问题”,“ؕ码问题”?/p>

掌握~码问题的关键是正确地理解相x念,~码所涉及的技术其实是很简单的。因此,阅读本文旉要慢d惻I多思考?/p>

引言

“字W与~码”是一个被l常讨论的话题。即使这P时常出现的ؕ码仍然困扰着大家。虽然我们有很多的办法可以用来消除ؕ码,但我们ƈ不一定理解这些办法的内在原理。而有的ؕ码生的原因Q实际上׃底层代码本n有问题所D的。因此,不仅是初学者会对字W编码感到模p,有的底层开发h员同样对字符~码~Z准确的理解?/p>

1. ~码问题的由来,相关概念的理?/h4>

1.1 字符与编码的发展

从计机对多国语a的支持角度看Q大致可以分Z个阶D:

  pȝ内码 说明
阶段一 ASCII 计算机刚开始只支持pQ其它语a不能够在计算Z存储和显C?/td> 英文 DOS
阶段?/td> ANSI~码
Q本地化Q?/td>
Z计算机支持更多语aQ通常使用 0x80~0xFF 范围?2 个字节来表示 1 个字W。比如:汉字 '? 在中文操作系l中Q?[0xD6,0xD0] q两个字节存储?br />
不同的国家和地区制定了不同的标准Q由此生了 GB2312, BIG5, JIS {各自的~码标准。这些?2 个字节来代表一个字W的各种汉字延׾~码方式Q称?b> ANSI ~码。在体中文系l下QANSI ~码代表 GB2312 ~码Q在日文操作pȝ下,ANSI ~码代表 JIS ~码?br />
不同 ANSI ~码之间互不兼容Q当信息在国际间交流Ӟ无法属于两U语a的文字,存储在同一D?b> ANSI ~码的文本中?/td>
中文 DOSQ中?Windows 95/98Q日?Windows 95/98
阶段?/td> UNICODE
Q国际化Q?/td>
Z使国际间信息交流更加方便Q国际组l制定了 UNICODE 字符?/b>Qؓ各种语言中的每一个字W设定了l一q且唯一的数字编P以满语言、跨q_q行文本转换、处理的要求?/td> Windows NT/2000/XPQLinuxQJava

字符串在内存中的存放ҎQ?/p>

?ASCII 阶段Q?b>单字节字W串使用一个字节存放一个字W(SBCSQ。比如,"Bob123" 在内存中为:

42 6F 62 31 32 33 00
B o b 1 2 3 \0

在?ANSI ~码支持多种语言阶段Q每个字W用一个字节或多个字节来表C(MBCSQ,因此Q这U方式存攄字符也被UC多字节字W?/b>。比如,"中文123" 在中?Windows 95 内存中ؓ7个字节,每个汉字?个字节,每个英文和数字字W占1个字节:

D6 D0 CE C4 31 32 33 00
?/td> ?/td> 1 2 3 \0

?UNICODE 被采用之后,计算机存攑֭W串Ӟ改ؓ存放每个字符?UNICODE 字符集中的序受目前计机一般?2 个字节(16 位)来存放一个序PDBCSQ,因此Q这U方式存攄字符也被UC宽字节字W?/b>。比如,字符?"中文123" ?Windows 2000 下,内存中实际存攄?5 个序P

2D 4E 87 65 31 00 32 00 33 00 00 00      ??x86 CPU 中,低字节在?/font>
?/td> ?/td> 1 2 3 \0  

一共占 10 个字节?/p>

1.2 字符Q字节,字符?/h5>

理解~码的关键,是要把字W的概念和字节的概念理解准确。这两个概念ҎhQ我们在此做一下区分:

  概念描述 举例
字符 Z使用的记P抽象意义上的一个符受?/td> '1', '?, 'a', '$', 'K?, …?/td>
字节 计算Z存储数据的单元,一?位的二进制数Q是一个很具体的存储空间?/td> 0x01, 0x45, 0xFA, …?/td>
ANSI
字符?/td>
在内存中Q如果“字W”是?ANSI ~码形式存在的,一个字W可能用一个字节或多个字节来表C,那么我们U这U字W串?ANSI 字符?/b>或?b>多字节字W串?/td> "中文123"
Q占7字节Q?/font>
UNICODE
字符?/td>
在内存中Q如果“字W”是以在 UNICODE 中的序号存在的,那么我们U这U字W串?UNICODE 字符?/b>或?b>宽字节字W串?/td> L"中文123"
Q占10字节Q?/font>

׃不同 ANSI ~码所规定的标准是不相同的Q因此,对于一个给定的多字节字W串Q我们必ȝ道它采用的是哪一U编码规则,才能够知道它包含了哪些“字W”。而对?UNICODE 字符?/b>来说Q不在什么环境下Q它所代表的“字W”内ҎL不变的?/p>

回页?/a>

1.3 字符集与~码

各个国家和地区所制定的不?ANSI ~码标准中,都只规定了各自语a所需的“字W”。比如:汉字标准QGB2312Q中没有规定韩国语字W怎样存储。这?ANSI ~码标准所规定的内容包含两层含义:

  1. 使用哪些字符。也是说哪些汉字,字母和符号会被收入标准中。所包含“字W”的集合叫做?b>字符?/b>”?
  2. 规定每个“字W”分别用一个字节还是多个字节存储,用哪些字节来存储Q这个规定就叫做?b>~码”?

各个国家和地区在制定~码标准的时候,“字W的集合”和“编码”一般都是同时制定的。因此,q_我们所说的“字W集”,比如QGB2312, GBK, JIS {,除了有“字W的集合”这层含义外Q同时也包含了“编码”的含义?/p>

?b>UNICODE 字符?/b>”包含了各种语言中用到的所有“字W”。用来给 UNICODE 字符集编码的标准有很多种Q比如:UTF-8, UTF-7, UTF-16, UnicodeLittle, UnicodeBig {?/p>

回页?/a>

1.4 常用的编码简?/h5>

单介l一下常用的~码规则Qؓ后边的章节做一个准备。在q里Q我们根据编码规则的特点Q把所有的~码分成三类Q?/p>
分类 ~码标准 说明
单字节字W编?/td> ISO-8859-1 最单的~码规则Q每一个字节直接作Z?UNICODE 字符。比如,[0xD6, 0xD0] q两个字节,通过 iso-8859-1 转化为字W串Ӟ直接得?[0x00D6, 0x00D0] 两个 UNICODE 字符Q即 "ÖÐ"?br />
反之Q将 UNICODE 字符串通过 iso-8859-1 转化为字节串Ӟ只能正常转化 0~255 范围的字W?/td>
ANSI ~码 GB2312,
BIG5,
Shift_JIS,
ISO-8859-2 …?/td>
?UNICODE 字符串通过 ANSI ~码转化为“字节串”时Q根据各自编码的规定Q一?UNICODE 字符可能转化成一个字节或多个字节?br />
反之Q将字节串{化成字符串时Q也可能多个字节转化成一个字W。比如,[0xD6, 0xD0] q两个字节,通过 GB2312 转化为字W串Ӟ得?[0x4E2D] 一个字W,?'? 字?br />
“ANSI ~码”的特点Q?br />1. q些“ANSI ~码标准”都只能处理各自语言范围之内?UNICODE 字符?br />2. “UNICODE 字符”与“{换出来的字节”之间的关系是h定的?/td>
UNICODE ~码 UTF-8,
UTF-16, UnicodeBig …?/td>
与“ANSI ~码”类似的Q把字符串通过 UNICODE ~码转化成“字节串”时Q一?UNICODE 字符可能转化成一个字节或多个字节?br />
与“ANSI ~码”不同的是:
1. q些“UNICODE ~码”能够处理所有的 UNICODE 字符?br />2. “UNICODE 字符”与“{换出来的字节”之间是可以通过计算得到的?/td>

我们实际上没有必要去q每一U编码具体把某一个字W编码成了哪几个字节Q我们只需要知道“编码”的概念是把“字W”{化成“字节”就可以了。对于“UNICODE ~码”,׃它们是可以通过计算得到的,因此Q在Ҏ的场合,我们可以M解某一U“UNICODE ~码”是怎样的规则?/p>

回页?/a>

2. 字符与编码在E序中的实现

2.1 E序中的字符与字?/h5>

?C++ ?Java 中,用来代表“字W”和“字节”的数据cdQ以及进行编码的ҎQ?/p>
cd或操?/b> C++ Java
字符 wchar_t char
字节 char byte
ANSI 字符?/td> char[] byte[]
UNICODE 字符?/td> wchar_t[] String
字节东y字符?/td> mbstowcs(), MultiByteToWideChar() string = new String(bytes, "encoding")
字符东y字节?/td> wcstombs(), WideCharToMultiByte() bytes = string.getBytes("encoding")

以上需要注意几点:

  1. Java 中的 char 代表一个“UNICODE 字符Q宽字节字符Q”,?C++ 中的 char 代表一个字节?
  2. MultiByteToWideChar() ?WideCharToMultiByte() ?Windows API 函数?

回页?/a>

2.2 C++ 中相兛_现方?/h5>

声明一D字W串帔RQ?/p>
// ANSI 字符Ԍ内容长度 7 字节
char
     sz[20] = "中文123";

// UNICODE 字符Ԍ内容长度 5 ?wchar_tQ?0 字节Q?/span>
wchar_t wsz[20] = L"\x4E2D\x6587\x0031\x0032\x0033";

UNICODE 字符串的 I/O 操作Q字W与字节的{换操作:

// q行时设定当?ANSI ~码QVC 格式
setlocale(LC_ALL, ".936");

// GCC 中格?/span>
setlocale(LC_ALL, "zh_CN.GBK");

// Visual C++ 中用小?%sQ按?setlocale 指定~码输出到文?br />// GCC 中用大?%S
fwprintf(fp, L"%s\n", wsz);

// ?UNICODE 字符串按?setlocale 指定的编码{换成字节
wcstombs(sz, wsz, 20);
// 把字节串按照 setlocale 指定的编码{换成 UNICODE 字符?br />
mbstowcs(wsz, sz, 20);

?Visual C++ 中,UNICODE 字符串常量有更简单的表示Ҏ。如果源E序的编码与当前默认 ANSI ~码不符Q则需要?#pragma setlocaleQ告诉编译器源程序用的~码Q?/p>
// 如果源程序的~码与当前默?ANSI ~码不一_
// 则需要此行,~译时用来指明当前源E序使用的编?/font>

#pragma setlocale
(".936")

// UNICODE 字符串常量,内容长度 10 字节
wchar_t wsz[20] = L"中文123";

以上需要注?#pragma setlocale ?setlocale(LC_ALL, "") 的作用是不同的,#pragma setlocale 在编译时起作用,setlocale() 在运行时起作用?/p>

回页?/a>

2.3 Java 中相兛_现方?/h5>

字符串类 String 中的内容?UNICODE 字符Ԍ

// Java 代码Q直接写中文
String
string = "中文123";

// 得到长度?5Q因为是 5 个字W?/span>
System.out.println(string.length());

字符?I/O 操作Q字W与字节转换操作。在 Java ?java.io.* 中,以“Stream”结cM般是用来操作“字节串”的c,以“Reader”,“Writer”结cM般是用来操作“字W串”的cR?/p>
// 字符串与字节串间怺转化

// 按照 GB2312 得到字节Q得到多字节字符Ԍ

byte
[] bytes = string.getBytes("GB2312");

// 从字节按?GB2312 得到 UNICODE 字符?/span>
string = newString(bytes, "GB2312");

// 要将 String 按照某种~码写入文本文gQ有两种ҎQ?br />
// W一U办法:?Stream cd入已l按照指定编码{化好的字节串

OutputStream os = new FileOutputStream("1.txt");
os.write(bytes);
os.close();

// W二U办法:构造指定编码的 Writer 来写入字W串
Writer ow = new OutputStreamWriter(new FileOutputStream("2.txt"), "GB2312");
ow.write(string);
ow.close();

/* 最后得到的 1.txt ?2.txt 都是 7 个字?*/

如果 java 的源E序~码与当前默?ANSI ~码不符Q则在编译的时候,需要指明一下源E序的编码。比如:

E:\>javac -encoding BIG5 Hello.java

以上需要注意区分源E序的编码与 I/O 操作的编码,前者是在编译时起作用,后者是在运行时起作用?/p>

回页?/a>

3. 几种误解Q以及ؕ码生的原因和解军_?/h4>

3.1 Ҏ产生的误?/h5>
  对编码的误解
误解一 在将“字节串”{化成“UNICODE 字符东y时Q比如在d文本文gӞ或者通过|络传输文本ӞҎ“字节串”简单地作ؓ单字节字W串Q采用每“一个字节”就是“一个字W”的Ҏq行转化?br />
而实际上Q在非英文的环境中,应该“字节串”作?ANSI 字符Ԍ采用适当的编码来得到 UNICODE 字符Ԍ有可能“多个字节”才能得到“一个字W”?br />
通常Q一直在英文环境下做开发的E序员们Q容易有q种误解?/td>
误解?/td> ?DOSQWindows 98 {非 UNICODE 环境下,字符串都是以 ANSI ~码的字节Ş式存在的。这U以字节形式存在的字W串Q必ȝ道是哪种~码才能被正地使用。这使我们Ş成了一个惯性思维Q“字W串的编码”?br />
?UNICODE 被支持后QJava 中的 String 是以字符的“序号”来存储的,不是以“某U编码的字节”来存储的,因此已经不存在“字W串的编码”这个概念了。只有在“字W串”与“字节串”{化时Q或者,一个“字节串”当成一?ANSI 字符串时Q才有编码的概念?br />
不少的h都有q个误解?/td>

W一U误解,往往是导致ؕ码生的原因。第二种误解Q往往D本来ҎU正的ؕ码问题变得更复杂?/p>

在这里,我们可以看到Q其中所讲的“误解一”,即采用每“一个字节”就是“一个字W”的转化ҎQ实际上也就{同于采?iso-8859-1 q行转化。因此,我们常常使用 bytes = string.getBytes("iso-8859-1") 来进行逆向操作Q得到原始的“字节串”。然后再使用正确?ANSI ~码Q比?string = new String(bytes, "GB2312")Q来得到正确的“UNICODE 字符东y?/p>

回页?/a>

3.2 ?UNICODE E序在不同语a环境间移植时的ؕ?/h5>

?UNICODE E序中的字符Ԍ都是以某U?ANSI ~码形式存在的。如果程序运行时的语a环境与开发时的语a环境不同Q将会导?ANSI 字符串的昄p|?/p>

比如Q在日文环境下开发的?UNICODE 的日文程序界面,拿到中文环境下运行时Q界面上显CZؕ码。如果这个日文程序界面改为采?UNICODE 来记录字W串Q那么当在中文环境下q行Ӟ界面上将可以昄正常的日文?/p>

׃客观原因Q有时候我们必d中文操作pȝ下运行非 UNICODE 的日文YӞq时我们可以采用一些工P比如Q南极星QAppLocale {,暂时的模拟不同的语言环境?/p>

回页?/a>

3.3 |页提交字符?/h5>

当页面中的表单提交字W串Ӟ首先把字W串按照当前面的编码,转化成字节串。然后再每个字节{化成 "%XX" 的格式提交到 Web 服务器。比如,一个编码ؓ GB2312 的页面,提交 "? q个字符串时Q提交给服务器的内容?"%D6%D0"?/p>

在服务器端,Web 服务器把收到?"%D6%D0" 转化?[0xD6, 0xD0] 两个字节Q然后再Ҏ GB2312 ~码规则得到 "? 字?/p>

?Tomcat 服务器中Qrequest.getParameter() 得到qӞ常常是因为前面提到的“误解一”造成的。默认情况下Q当提交 "%D6%D0" l?Tomcat 服务器时Qrequest.getParameter() 返?[0x00D6, 0x00D0] 两个 UNICODE 字符Q而不是返回一?"? 字符。因此,我们需要?bytes = string.getBytes("iso-8859-1") 得到原始的字节串Q再?string = new String(bytes, "GB2312") 重新得到正确的字W串 "??/p>

回页?/a>

3.4 从数据库d字符?/h5>

通过数据库客LQ比?ODBC ?JDBCQ从数据库服务器中读取字W串Ӟ客户端需要从服务器获知所使用?ANSI ~码。当数据库服务器发送字节流l客LӞ客户端负责将字节按照正的~码转化?UNICODE 字符丌Ӏ?/p>

如果从数据库d字符串时得到qQ而数据库中存攄数据又是正确的,那么往往q是因ؓ前面提到的“误解一”造成的。解决的办法q是通过 string = new String( string.getBytes("iso-8859-1"), "GB2312") 的方法,重新得到原始的字节串Q再重新使用正确的编码{化成字符丌Ӏ?/p>

回页?/a>

3.5 电子邮g中的字符?/h5>

当一D?Text 或?HTML 通过电子邮g传送时Q发送的内容首先通过一U指定的字符~码转化成“字节串”,然后再把“字节串”通过一U指定的传输~码QContent-Transfer-EncodingQ进行{化得到另一东y字节串”。比如,打开一电子邮件源代码Q可以看到类似的内容Q?/p>
Content-Type: text/plain;
        charset="gb2312"
Content-Transfer-Encoding: base64

sbG+qcrQuqO17cf4yee74bGjz9W7+b3wudzA7dbQ0MQNCg0KvPKzxqO6uqO17cnnsaPW0NDEDQoNCg==

最常用?Content-Transfer-Encoding ?Base64 ?Quoted-Printable 两种。在对二q制文g或者中文文本进行{化时QBase64 得到的“字节串”比 Quoted-Printable 更短。在对英文文本进行{化时QQuoted-Printable 得到的“字节串”比 Base64 更短?/p>

邮g的标题,用了一U更短的格式来标注“字W编码”和“传输编码”。比如,标题内容?"?Q则在邮件源代码中表CZؓQ?/p>
// 正确的标题格?/span>
Subject: =?GB2312?B?1tA=?=

其中Q?/p>

  • W一个??”与?”中间的部分指定了字W编码,在这个例子中指定的是 GB2312?
  • ?”与?”中间的“B”代?Base64。如果是“Q”则代表 Quoted-Printable?
  • 最后?”与?=”之间的部分Q就是经q?GB2312 转化成字节串Q再l过 Base64 转化后的标题内容?

如果“传输编码”改?Quoted-PrintableQ同P如果标题内容?"?Q?/p>
// 正确的标题格?/span>
Subject: =?GB2312?Q?=D6=D0?=

如果阅读邮g时出Cؕ码,一般是因ؓ“字W编码”或“传输编码”指定有误,或者是没有指定。比如,有的发邮件组件在发送邮件时Q标?"?Q?/p>
// 错误的标题格?/span>
Subject: =?ISO-8859-1?Q?=D6=D0?=

q样的表C,实际上是明确指明了标题ؓ [0x00D6, 0x00D0]Q即 "ÖÐ"Q而不?"??/p>

回页?/a>

4. 几种错误理解的纠?/h4>

误解Q“ISO-8859-1 是国际编码??/h5>

非也。iso-8859-1 只是单字节字W集中最单的一U,也就是“字节编号”与“UNICODE 字符~号”一致的那种~码规则。当我们要把一个“字节串”{化成“字W串”,而又不知道它是哪一U?ANSI ~码Ӟ先暂时地把“每一个字节”作为“一个字W”进行{化,不会造成信息丢失。然后再使用 bytes = string.getBytes("iso-8859-1") 的方法可恢复到原始的字节丌Ӏ?/p>

误解Q“Java 中,怎样知道某个字符串的内码Q?/h5>

Java 中,字符串类 java.lang.String 处理的是 UNICODE 字符Ԍ不是 ANSI 字符丌Ӏ我们只需要把字符串作为“抽象的W号的串”来看待。因此不存在字符串的内码的问题?/p>

Ҏ铸就辉煌 2006-06-23 11:30 发表评论
]]>java 5.0 新特?/title><link>http://www.aygfsteel.com/jhengfei/archive/2006/06/02/49996.html</link><dc:creator>Ҏ铸就辉煌</dc:creator><author>Ҏ铸就辉煌</author><pubDate>Fri, 02 Jun 2006 09:21:00 GMT</pubDate><guid>http://www.aygfsteel.com/jhengfei/archive/2006/06/02/49996.html</guid><wfw:comment>http://www.aygfsteel.com/jhengfei/comments/49996.html</wfw:comment><comments>http://www.aygfsteel.com/jhengfei/archive/2006/06/02/49996.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/jhengfei/comments/commentRss/49996.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/jhengfei/services/trackbacks/49996.html</trackback:ping><description><![CDATA[     摘要: 1 、重要的语言变化 l         泛型Q? Generics Q? l         ...  <a href='http://www.aygfsteel.com/jhengfei/archive/2006/06/02/49996.html'>阅读全文</a><img src ="http://www.aygfsteel.com/jhengfei/aggbug/49996.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/jhengfei/" target="_blank">Ҏ铸就辉煌</a> 2006-06-02 17:21 <a href="http://www.aygfsteel.com/jhengfei/archive/2006/06/02/49996.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用java诅R写Excel http://www.aygfsteel.com/jhengfei/archive/2006/05/22/47480.htmlҎ铸就辉煌Ҏ铸就辉煌Mon, 22 May 2006 07:51:00 GMThttp://www.aygfsteel.com/jhengfei/archive/2006/05/22/47480.htmlhttp://www.aygfsteel.com/jhengfei/comments/47480.htmlhttp://www.aygfsteel.com/jhengfei/archive/2006/05/22/47480.html#Feedback0http://www.aygfsteel.com/jhengfei/comments/commentRss/47480.htmlhttp://www.aygfsteel.com/jhengfei/services/trackbacks/47480.html
读:rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
在Java中读取Excel文g的内?br />在这里,我用的是一个叫Java Excel API的东西,cM的还有jakarta的POIQ不q感觉那?br />太复杂了点儿。而且jxl对中文的支持相当的好Q至我在用的过E中一炚w题没出?br />
一、下载地址
http://sourceforge.net/project/showfiles.php?group_id=79926

二、特?br />可以dExcel 95, 97, 2000文g
可以L写Excel 97及其以后版本的的公式Q不q我发现好像有bugQ?br />生成Excel 97格式的电子表?br />支持字体、数字和日期格式?br />支持单元格的颜色和阴?br />可以~辑现有的文?

三、读文g
//声明一下,记得后面要关闭哦。?br />Workbook workbook = null;

try {
workbook = Workbook.getWorkbook(new File("d:\\temp\\TestRead.xls"));
} catch (Exception e) {
throw new Exception("file to import not found!");
}

Sheet sheet = workbook.getSheet(0);
Cell cell = null;

int columnCount=3;
int rowCount=sheet.getRows();
for (int i = 0; i <rowCount; i++) {
for (int j = 0; j <columnCount; j++) {
//注意Q这里的两个参数Q第一个是表示列的Q第二才表示?br />cell=sheet.getCell(j, i);
//要根据单元格的类型分别做处理Q否则格式化q的内容可能会不正确
if(cell.getType()==CellType.NUMBER){
System.out.print(((NumberCell)cell).getValue());
}
else if(cell.getType()==CellType.DATE){
System.out.print(((DateCell)cell).getDate());
}
else{
System.out.print(cell.getContents());
}

//System.out.print(cell.getContents());
System.out.print("\t");
}
System.out.print("\n");
}
//关闭它,否则会有内存泄露
workbook.close();

写:wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
在Java中向Excel文g写入内容


四、导出数据到Excel文g?br />下面的例子,讄了数字、日期的格式Q还有字体,颜色{?br />
File tempFile=new File("d:/temp/output.xls");
WritableWorkbook workbook = Workbook.createWorkbook(tempFile);
WritableSheet sheet = workbook.createSheet("TestCreateExcel", 0);

//一些时变量,用于写到excel?br />Label l=null;
jxl.write.Number n=null;
jxl.write.DateTime d=null;

//预定义的一些字体和格式Q同一个Excel中最好不要有太多格式
WritableFont headerFont = new WritableFont(WritableFont.ARIAL, 12, WritableFont.BOLD, false, Underlinestyle.NO_UNDERLINE, jxl.format.Colour.BLUE);
WritableCellFormat headerFormat = new WritableCellFormat (headerFont);

WritableFont titleFont = new WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false, Underlinestyle.NO_UNDERLINE, jxl.format.Colour.RED);
WritableCellFormat titleFormat = new WritableCellFormat (titleFont);

WritableFont detFont = new WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false, Underlinestyle.NO_UNDERLINE, jxl.format.Colour.BLACK);
WritableCellFormat detFormat = new WritableCellFormat (detFont);

NumberFormat nf=new NumberFormat("0.00000"); //用于Number的格?br />WritableCellFormat priceFormat = new WritableCellFormat (detFont, nf);

DateFormat df=new DateFormat("yyyy-MM-dd");//用于日期?br />WritableCellFormat dateFormat = new WritableCellFormat (detFont, df);

//剩下的事情,是用上面的内容和格式创Z些单元格Q再加到sheet?br />l=new Label(0, 0, "用于试的Excel文g", headerFormat);
sheet.addCell(l);

//add Title
int column=0;
l=new Label(column++, 2, "标题", titleFormat);
sheet.addCell(l);
l=new Label(column++, 2, "日期", titleFormat);
sheet.addCell(l);
l=new Label(column++, 2, "货币", titleFormat);
sheet.addCell(l);
l=new Label(column++, 2, "h", titleFormat);
sheet.addCell(l);

//add detail
int i=0;
column=0;
l=new Label(column++, i+3, "标题 "+i, detFormat);
sheet.addCell(l);
d=new DateTime(column++, i+3, new java.util.Date(), dateFormat);
sheet.addCell(d);
l=new Label(column++, i+3, "CNY", detFormat);
sheet.addCell(l);
n=new jxl.write.Number(column++, i+3, 5.678, priceFormat);
sheet.addCell(n);

i++;
column=0;
l=new Label(column++, i+3, "标题 "+i, detFormat);
sheet.addCell(l);
d=new DateTime(column++, i+3, new java.util.Date(), dateFormat);
sheet.addCell(d);
l=new Label(column++, i+3, "SGD", detFormat);
sheet.addCell(l);
n=new jxl.write.Number(column++, i+3, 98832, priceFormat);
sheet.addCell(n);

//讄列的宽度
column=0;
sheet.setColumnView(column++, 20);
sheet.setColumnView(column++, 20);
sheet.setColumnView(column++, 10);
sheet.setColumnView(column++, 20);

workbook.write();
workbook.close();



Ҏ铸就辉煌 2006-05-22 15:51 发表评论
]]>
վ֩ģ壺 | Զ| | | | Ͳ| | ٺ| ͼ| Ϫ| | ʡ| ƽ̶| | | | | ͳ| ԭ| ʡ| ˮ| | ͨ| | ɽ| | ̨| | | | | º| ɽ| ͨ| ˶| | | | ̨| | |