??xml version="1.0" encoding="utf-8" standalone="yes"?>
new ActionError("user.name")从资源中得到key
ActionErrors.add("username",new ActionError("user.name"));
在jsp中用时
前提条g是validate讄为false,input需要设|一? 我不太喜ƢactionForm当中的validateҎ(gu),业务逻辑或者是验证逻辑写在q里感觉不爽
2.如果不想从properties中取得key,即不想配|?则?
ActionError("test",false),此处表示不启用配|资源中的key
q个Ҏ(gu)?.1.之前没有
3.另摘抄于|络一?如下
在Struts里进行表单验证和业务逻辑验证真是一个很ȝ的事情,看书、上|了解了ActionMessage与ActionErrors的基本知识,可以拿来书上或网上的例程来试试。错、错Q又错,q是有错Q我说是的我的程序结果有错误Q而不是真的显C出了验证错误信息?怎么回事呢?l过一天的不断试Q成功了... l验是Q?在ActionFrom中用ActionErrors 错误信息d用add(“error_key?new ActionError(“error.input.name?) jsp中用显C错误?html:errors property="error_key"> 在Actoin中用ActionMessages 错误信息d使用add(“error_key?new ActioinMessage(“errors.loginerror?)
============================================= HTML:MESSAGES,HTML:ERRORS,用法2007-08-12 22:09=======
]]>
]]>
Eclipse插gQ?a >http://findbugs.sourceforge.net/downloads.html
插g理技?/strong>
提示Q新下蝲的插件PlugIn一定不要都攑֜原始的Eclipse目录下去?br />
使用
重新启动Eclipse后,在Help => About Eclipse SDK => Plug-in Details你可以看到由“FindBugs Project”提供的“FindBugs Plug-in”版?.0.17插gQ如下图所C:
FindBugs的用方?/strong>
FindBugs是一个可以在JavaE序中发现Bugs的程序?
它是专门用来L处于“Bug Patterns”列表中的代码的?
Bug Patterns指很有可能是错误的代码的实例?br />
目前FindBugs最高版?.9.4Q不q更新速度很快的,你应当经怸ȝ看是否有新版本发布。Eclipse plugin for FindBugs最高版?.0.17?br />
pȝ要求
使用FindBugs臛_需要JDK1.4.0以上版本QFindBugs是^台独立的Q可以运行于GNU/Linux、Windows、MacOS X {^C?br />
q行FindBugs臛_需要有256 MB内存Q如果你要分析一个很大的目Q那需要更加多的内存了?br />
FindBugs独立q行和与Antl合的详l操作就不介l了Q可以看官方的文?a target="_blank">http://findbugs.sourceforge.net/manual/
独立q行的效果图如下Q?br />
本文主要介绍在Eclipse中用的情况
打开Bug Details视图
Windows => Show View => Other?=> FindBugs => BugDetails
在Package Explorer或Navigator视图中,选中你的Java目Q右键,可以看到“Find Bugs”菜单项Q子菜单w有“Find Bugs”和“Clear Bug Markers”两内容,如下图所C:
我们建立一个简单的试文gTest.java 内容如下Q?
public class Test { private String[] name; public String[] getName() { return name; } public void setName(String[] name) { this.name = name; } }
我们点中“Find Bugs”,q行时会出现如下q度框:
q行l束后可以在Problems中看到增加了如下的警告信息内?br />
FindBugsq行后的警告信息内容不仅在Problems视图中显C,而且标记在源代码标记框中,在源代码~辑器中我们可以看到警告标识Q如下图Q?
当光标指向你的警告信息的代码上面Ӟ׃有相应的错误提示信息Q与Eclipse本n的错误或警告信息提示cM?
选中Problems视图里出现的相应问题Q就会在代码~辑器里切换到相应的代码上去Q方便根据相应的提示信息q行代码的修攏V?
在Problems视图里,选中相应的问题条目,右键Q在弹出的菜单中Q可以看到“Show Bug Details”,如下图所C:
点中它,会切换到Bug Details视图上去Q显C更加详l的提示信息?br />
当然Q在代码~辑H口中,点击带有警告提示信息的图标时Q也会自动切换到Bud DetailsH口去,查看详细的警告信息,如下图所C?br />
Ҏ(gu)q里详细的信息,你可以得到FindBugsZ么会对你的代码报警告信息Q及相应的处理办法,Ҏ(gu)它的提示Q你可以快速方便地q行代码修改?br />
Ҏ(gu)提示Q我们将代码修改成如下,再运行就不会报有警告信息了?br />
public class Test { private String[] name; public String[] getName() { String[] temp = name; return temp; } public void setName(String[] name) { String[] temp = name; this.name = temp; } }
配置FindBugs
选择你的目Q右?=> Properties => FindBugs =>
可以配置的信息包括如上图所C的四个选项的相兌|:
ȝ
此插件的功能很不错,可以帮助我们提升Java代码的编写能力,写出更加安全可靠的代码。徏议用或加在Ant里进行持l构建?
现在Q你可以马上拿出你已l开发的一个项目,查一下你的代码有没有问题?/p>
cs_convert: cslib user api layer: common library error: The conversion/operation was stopped due to a syntax error in the source field.
CSLIB Message: - L0/O0/S0/N36/1/0:
导入表对应的列数量不正确
cs_convert: cslib user api layer: common library error: The conversion/operation was stopped due to a syntax error in the source field.
导入数据存在自增长列Q但数据源不存在自增长列
blk_rowxfer(): blk layer: internal BLK-Library error: Data truncated while doing local character set conversion. col = 3
导入表对应的字段长度不
ct_sendpassthru(): network packet layer: internal net library error: Net-Library operation terminated due to disconnect
CTLIB Message: - L5/O3/S5/N5/5/0:
可能原因:action没有再struts-config.xml中定义,或没有找到匹配的actionQ例如在JSP文g中?
处理:如果出现上述异常Q请查看struts-config.xml中的定义部分Q有时可能是打错了字W或者是某些不符合规则,可以使用strutsconsole工具来检查?/p>
2异常
org.apache.jasper.JasperException:Cannotretrievedefinitionforformbeannull
可能原因:q个异常是因为StrutsҎ(gu)struts-config.xml中的mapping没有扑ֈaction期望的formbean。大部分的情况可能是因ؓ在form-bean中设|的name属性和action中设|的name属性不匚w所致。换句话_action和form都应该各自有一个name属性,q且要精匹配,包括大小写。这个错误当没有name属性和action兌时也会发生,如果没有在action中指定name属性,那么没有name属性和action相关联。当然当action制作某些控制Ӟ譬如Ҏ(gu)参数D转到相应的jsp面Q而不是处理表单数据,q是׃用name属性,q也是action的用方法之一?/p>
3异常
Noactioninstanceforpath/xxxxcouldbecreated
可能原因
特别提示Q因为有很多中情况会Dq个错误的发生,所以推荐大家调高你的web服务器的日志/调试U别Q这样可以从更多的信息中看到潜在的、在试图创徏actioncL发生的错误,q个actioncM已经在struts-config.xml中设|了兌Q即d?action>标签Q?/p>
在struts-config.xml中通过action标签的class属性指定的actioncM能被扑ֈ有很多种原因Q例如:
定位~译后的.class文gp|。Failuretoplacecompiled.classfilefortheactionintheclasspath(在web开发中Qclass的的位置在rWEB-INF/classesQ所以你的actionclass必须要在q个目录下。例如你的actioncM于WEB-INF/classes/action/Login.class,那么在struts-config.xml中设|a(chn)ction的属性type时就是action.Login).
拼写错误Q这个也时有发生Qƈ且不易找刎ͼ特别注意W一个字母的大小写和包的名称?/p>
在struts-config.xml中指定的actioncL有承自Stuts的Actionc,或者你自定义的ActioncL有承自Struts提供的ActioncR?/p>
你的actioncdȝ承自Struts提供的ActioncR?/p>
你的classpath的问题。例如webserver没有发现你的资源文gQ资源文件必dWEB-INF/classes/目录下?/p>
4异常
javax.servlet.jsp.JspException:Nogettermethodforpropertyusernameofbeanorg.apache.struts.taglib.html.BEAN
可能原因
没有位formbean中的某个变量定义getterҎ(gu)
q个错误主要发生在表单提交的FormBean中,用struts标记
5Exceptionjavax.servlet.jsp.JspException:CannotfindActionMappingsorActionFormBeanscollection
可能原因
不是标识StrutsactionServlet?servlet>标记是映射.do扩展名的
在struts-config.xml中的打字或者拼写错误也可导致这个异常的发生。例如缺一个标记的关闭W号/>。最好用strutsconsole工具查一下?/p>
另外Qload-on-startup必须在web.xml中声明,q要么是一个空标记Q要么指定一个数|q个数值用来表servletq行的优先Q数D大优先低?/p>
q有一个和使用load-on-startup有关的是使用Struts预编译JSP文g时也可能Dq个异常?/p>
6Exception
javax.servlet.jsp.JspException:Cannotfindbeanorg.apache.struts.taglib.html.BEANinanyscope
ProbableCauses
试图在Struts的form标记外用form的子元素。这常常发生在你?/p>
后面使用Struts的html标记?/p>
另外要注意可能你不经意用的无主体的标记Q如Q这样web服务器解析时当作一个无M的标讎ͼ随后使用的所有标记都被认为是在这个标C外的Q如又用了
q有是在用taglib引入HTML标记库时Q你使用的prefix的g是html?/p>
<html:link> 标签有以下重要属性:
(1) forwardQ指定全局转发链接?br />(2) hrefQ指定完整的URL 键接?br />(3) pageQ指定相对于当前|页的URL?/p>
<html:rewrite> 用于输出链接中的URI部分Q但它ƈ不生成HTML <a> 元素。URI指的是URL 中协议、主机和端口以后的内宏VURI 用于指定具体的请求资源。例如,对于URLQHTTPQ?/localhost:8080/HtmlBasic.doQ它的URI?HtmlBasic.do
CZQ?br />1、创建全局转发链接
首先Q在Struts-config.xml ?lt;global-forwards> 元素中定义一?lt;forward> 元素Q?br /> <global-forwards>
<forward name = "index" path="/index.jsp"/>
</global-forwards>
接着Q在JSP 文g中创?lt;html:link> 标签Q?br /> <html:link forward="index">
Link to Global ActionForward
</html:link>
<html:link> 标签的forward 属性和<global-forwards> 元素中的<forward> 子元素匹配。以上代码生成如下HTML 内容Q?br /> <a href="/index.jsp">Link to Global ActionFoward</a>
值得注意的是Q?lt;html:link> 的forward 属性只引用Struts-config.xml 配置文g?lt;global-forwards>内的<forward> 子元素,如果引用<action> 内的<forward> 子元素,在运行时会抛出异常Q?br /> Cannot create rewrite URL: Java.Net.MalfomedURlException: Cannot retrieve ActionForward
2、创建具有完整URL 的链?br /> 如果Web 应用需要链接到其他站点Q应该给出其他站点完_QԌQ例如: 3、从当前|页中创建相对URL 4、在URL ?URI 中包含请求参?br /> 如果要在URL或URI 中包含请求参敎ͼ只要把请求参数加在URL ?URI的末ְ可以了。例如: 提示Q在HTML ?amp;amp 代表Ҏ(gu)字符 "&" 5、在URL ?URI 中包含单个请求变?br /> rewrite: <html:rewrite page="/HtmlBasic.do" <html:link> 标签?paramId 属性指定请求参数名QparamName 属性指定变量的名字。如果变量ؓJavaBean Q用paramProperty 属性指定JavaBean 的属性?br /> 对于本例的stringBeanQ请求参数gؓstringBean 的字W串倹{对于customerBeanQ指定了paramProperty 属性,h参数gؓcustomerBean ?name 属性倹{?br /> 以上代码生成如下HTML 内容Q?br /> <a href="/HtmlBasic.do?urlParamName=Value to Pass on Url"> <a href="/HtmlBasic.do?urlParamName=weiqin"> rewrite: /HtmlBasic.do?urlParamName=Value to Pass on Url <html:link> 标签的name 属性指定包含请求变量的HashMap 对象。HashMap 对象中的每一?key/value" 代表一Ҏ(gu)多对"h参数?h参数?。以上代码生成如下的Html 内容Q?br /> <a href="/HtmlBasic.do?myString=myStringValue&myArray=str1&myArray=str2&myArray=str3">
<html:link href=" Generate an "href" directly
</html:link>
生成HTML 代码如下Q?br /> <a href=" an "href" directly</a>
值得注意的是Q如果指定了<html:link> 标签的href 属性,即用户览器的Cookie 关闭Q?lt;html:link> 标签也不会把用户SessionID 作ؓh参数加和到URL 中?/p>
如果从一个网链接到同一个应用中的另一|页Q可以采用以下方式:
<html:link page="/HtmlBasic.do">
A relative link from this page
</html:link>
<html:link> 标签?page 属性用于指定相对于当前应用的URI。以上代码生成如下HTML 内容Q?br /> <a href="/lib/HtmlBasic.do">......</a>
<html:link page="/HtmlBasic.do?prop1=abc&prop2=123">
Hard-code the url parameters
</html:link>
<!-- or -->
<html:rewrite page="/HtmlBasic.do?prop1=abc&prop2=123"/>
以上代码生成如下HTML 内容Q?br /> <a href=/lib/HtmlBasic.do?prop1=abc&prop2=123">......</a>
rewrite: /HtmlBasic.do?prop1=abc&prop2=123
如果要在URL 中包含一个请求参敎ͼ而这人参数的值存在于当前|页可访问的一个变量中Q可以按以下Ҏ(gu)来实现?br /> Z演示q一功能Q首先创Z个当前网可讉K的变量。例如,本例中创Z两个变量Q一个是字符cdQ一个是CustomerBean Q?它们存存于一?page 范围内:
<%
/*
* Create a string object to store as a bean in
* the page content and embed in this link
*/
String stringBean = "Value to Pass ont URL";
pageContext.setAttribute("stringBean", stringBean);
%>
<jsp:useBean id = "customerBean" scope="page" class="htmltaglibs.beans.CurstomerBean"/>
<jsp:setProperty name="customerBean" property="name" value="weiqin"/>
接着Q把q两个变量作求参敎ͼ加入到URL或URI 中:
<html:link page="/HtmlBasic.do"
paramId="urlParamName"
paramName="stringBean">
URL encode a parameter based on a string bean value
</html:link>
<html:link page="/HtmlBasic.do"
paramId="urlParamName"
paramName="customerBean"
paramProperty="name">
URL encode a parameter based on a customer bean value
</html:link>
paramId="urlParamName" paramName="stringBean"/>
rewrite: <html:rewrite page="/HtmlBasic.do"
paramId="urlParamName" paramName="customerBean"
paramProperty="name"/>
Url encode a paramter based on a string bean value
</a>
url encode a parameter based on a customer bean value
</a>
rewrite: /HtmlBasic.do?urlParamName=weiqin
6、在URL ?URI 中包含多个请求变?br /> 如果在URL ?URI 中包含多个请求参敎ͼ而这些参数的值来自多个变量,需要先定义一个Mapcd的java c,如java.util.HashMapQ用它来存放h变量。例如:
<%
/*
* Strore values int a Map(HashMap in this case)
* and construct the URL based on the Map
* /
java.util.HashMap myMap = new java.util.HashMap();
myMap.put("myString", new String("myStringValue"));
myMap.put("myArray" , new String[]{"str1","str2","str3"} );
pageContext.setAttribute("map", myMap);
%>
在以上代码的HaspMap 中存放了两个对象Q其中第二个对象是个字符串数l。HashMap 被存攑֜PageContext 中?接下来就可以把这个HashMap 作ؓh参数Q加入到URL ?URI 中:
<%-- For this version of the <html:link> tag: --%>
<%-- map = a map with name/value pairs to pass on the url --%>
<html:link page="/HtmlBasic.do" name="map">
URL encode a parameter based on value in a Map
</html:link>
<%-- Create the same rewrite string for the above link. --%>
rewrite:<html:rewrite page="/HtmlBasic.do" name="map"/>
URL encode a parameter based on value in a Map
</a>
rewrite:/HtmlBasic.do?myString=myStringValue&myArray=str1&myArray=str2&myArray=str3
]]>
----对这两个概念的不明好久,l于扑ֈ一好文,拿来׃nQhttp://www.duduwolf.com/cmd.asp?act=tb&id=3 Q?/p>
1. ?stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同QJava自动理栈和堆,E序员不能直接地讄栈或堆?
2. 栈的优势是,存取速度比堆要快Q仅ơ于直接位于CPU中的寄存器。但~点是,存在栈中的数据大与生存期必L定的,~Z灉|性。另外,栈数据可以共享,详见W?炏V堆的优势是可以动态地分配内存大小Q生存期也不必事先告诉编译器QJava的垃圾收集器会自动收走这些不再用的数据。但~点是,׃要在q行时动态分配内存,存取速度较慢?/p>
3. Java中的数据cd有两U?/p>
一U是基本cd(primitive types), 共有8U,即int, short, long, byte, float, double, boolean, char(注意Qƈ没有string的基本类?。这U类型的定义是通过诸如int a = 3; long b = 255L;的Ş式来定义的,UCؓ自动变量。值得注意的是Q自动变量存的是字面|不是cȝ实例Q即不是cȝ引用Q这里ƈ没有cȝ存在。如int a = 3; q里的a是一个指向intcd的引用,指向3q个字面倹{这些字面值的数据Q由于大可知,生存期可?q些字面值固定定义在某个E序块里面,E序块退出后Q字D值就消失?Q出于追求速度的原因,存在于栈中?/p>
另外Q栈有一个很重要的特D性,是存在栈中的数据可以共享。假设我们同时定义:
int a = 3 ;
int b = 3Q?/span>
特别注意的是Q这U字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了q个对象的内部状态,那么另一个对象引用变量也卛_反映个变化。相反,通过字面值的引用来修改其|不会D另一个指向此字面值的引用的g跟着改变的情c如上例Q我们定义完a与b的值后Q再令a=4Q那么,b不会{于4Q还是等?。在~译器内部,遇到a=4Q时Q它?yu)׃重新搜烦栈中是否?的字面|如果没有Q重新开辟地址存放4的|如果已经有了Q则直接a指向q个地址。因此a值的改变不会影响到b的倹{?/p>
另一U是包装cL据,如Integer, String, Double{将相应的基本数据类型包装v来的cR这些类数据全部存在于堆中,Java用new()语句来显C地告诉~译器,在运行时才根据需要动态创建,因此比较灉|Q但~点是要占用更多的时间?4. String是一个特D的包装cL据。即可以用String str = new String("abc");的Ş式来创徏Q也可以用String str = "abc"Q的形式来创?作ؓҎ(gu)Q在JDK 5.0之前Q你从未见过Integer i = 3;的表辑ּQ因为类与字面值是不能通用的,除了String。而在JDK 5.0中,q种表达式是可以的!因ؓ~译器在后台q行Integer i = new Integer(3)的{?。前者是规范的类的创E,卛_Java中,一切都是对象,而对象是cȝ实例Q全部通过new()的Ş式来创徏。Java中的有些c,如DateFormatc,可以通过该类的getInstance()Ҏ(gu)来返回一个新创徏的类Q似乎违反了此原则。其实不然。该c运用了单例模式来返回类的实例,只不q这个实例是在该cd部通过new()来创建的Q而getInstance()向外部隐藏了此细节。那Z么在String str = "abc"Q中Qƈ没有通过new()来创建实例,是不是违反了上述原则Q其实没有?/p>
5. 关于String str = "abc"的内部工作。Java内部此语句转化Z下几个步骤:
(1)先定义一个名为str的对Stringcȝ对象引用变量QString strQ?/p>
(2)在栈中查找有没有存放gؓ"abc"的地址Q如果没有,则开辟一个存攑֭面gؓ"abc"的地址Q接着创徏一个新的Stringcȝ对象oQƈo的字W串值指向这个地址Q而且在栈中这个地址旁边Cq个引用的对象o。如果已l有了gؓ"abc"的地址Q则查找对象oQƈq回o的地址?/p>
(3)str指向对象o的地址?/p>
值得注意的是Q一般StringcM字符串值都是直接存值的。但像String str = "abc"Q这U场合下Q其字符串值却是保存了一个指向存在栈中数据的引用Q?/p>
Z更好地说明这个问题,我们可以通过以下的几个代码进行验证?/p>
Stringstr1="abc";
Stringstr2="abc";
System.out.println(str1==str2);//true
我们再来更进一步,以上代码改成:
Stringstr1="abc";
Stringstr2="abc";
str1="bcd";
System.out.println(str1+","+str2);//bcd,abc
System.out.println(str1==str2);//false
q就是说Q赋值的变化D了类对象引用的变化,str1指向了另外一个新对象Q而str2仍旧指向原来的对象。上例中Q当我们str1的值改?bcd"ӞJVM发现在栈中没有存放该值的地址Q便开辟了q个地址Qƈ创徏了一个新的对象,其字W串的值指向这个地址?/p>
事实上,Stringc被设计成ؓ不可改变(immutable)的类。如果你要改变其|可以Q但JVM在运行时Ҏ(gu)新值?zhn)?zhn)创Z一个新对象Q然后将q个对象的地址q回l原来类的引用。这个创E虽说是完全自动q行的,但它毕竟占用了更多的旉。在Ҏ(gu)间要求比较敏感的环境中,会带有一定的不良影响?/p>
再修改原来代码:
Stringstr1="abc";
Stringstr2="abc";str1="bcd";
Stringstr3=str1;
System.out.println(str3);//bcdStringstr4="bcd";
System.out.println(str1==str4);//true
我们再接着看以下的代码?/p>
Stringstr1=newString("abc");
Stringstr2="abc";
System.out.println(str1==str2);//false
创徏了两个引用。创Z两个对象。两个引用分别指向不同的两个对象?/p>
String str1 = "abc";
String str2 = new String("abc");
System.out.println(str1==str2); //false
创徏了两个引用。创Z两个对象。两个引用分别指向不同的两个对象?/p>
以上两段代码说明Q只要是用new()来新建对象的Q都会在堆中创徏Q而且其字W串是单独存值的Q即使与栈中的数据相同,也不会与栈中的数据共享?/p>
6. 数据cd包装cȝg可修攏V不仅仅是Stringcȝg可修改,所有的数据cd包装c都不能更改其内部的倹{?7. l论与徏议:
(1)我们在用诸如String str = "abc"Q的格式定义cLQL惛_然地认ؓQ我们创ZStringcȝ对象str。担心陷阱!对象可能q没有被创徏Q唯一可以肯定的是Q指向Stringcȝ引用被创Z。至于这个引用到底是否指向了一个新的对象,必须Ҏ(gu)上下文来考虑Q除非你通过new()Ҏ(gu)来显要地创徏一个新的对象。因此,更ؓ准确的说法是Q我们创Z一个指向Stringcȝ对象的引用变量strQ这个对象引用变量指向了某个gؓ"abc"的StringcR清醒地认识到这一点对排除E序中难以发现的bug是很有帮助的?/p>
(2)使用String str = "abc"Q的方式Q可以在一定程度上提高E序的运行速度Q因为JVM会自动根据栈中数据的实际情况来决定是否有必要创徏新对象。而对于String str = new String("abc")Q的代码Q则一概在堆中创徏新对象,而不其字符串值是否相{,是否有必要创建新对象Q从而加重了E序的负担。这个思想应该是n元模式的思想Q但JDK的内部在q里实现是否应用了这个模式,不得而知?/p>
(3)当比较包装类里面的数值是否相{时Q用equals()Ҏ(gu)Q当试两个包装cȝ引用是否指向同一个对象时Q用==?/p>
(4)׃Stringcȝimmutable性质Q当String变量需要经常变换其值时Q应该考虑使用StringBufferc,以提高程序效率?/p>
作?langm
版权声明Q本文可以自p{载,转蝲时请务必以超链接形式标明文章原始出处和作者信息及本声?
作?langm
原文:http://www.matrix.org.cn/resource/article/44/44056_NoClassDefDoundErr.html
关键?NoClassDefDoundErr ClassNotFoundException
在读q篇文章之前Q你最好了解一下Java的Exception机制?/p>
也许你在开发的q程中经常地见到ClassNotFoundException和NoClassDefFoundErrq两个异常,每每看到之后Q都会一概而论的是cL有找刎ͼ但有些时候见C们的时候又有些疑惑Q至我是这PQؓ什么Java要用两个异常来表C类定义没有扑ֈ那?他们之间有什么区别那Q?/p>
正y今天我又到了这个问题,Z的仔l研I了一下这两个异常的区别?
首先Q?
ClassNotFoundException直接l承与ExceptionQ它是一个checked的异常?
NoClassDefFoundErr l承自Error->LinkageError Q它是一个unchecked的异常?/p>
下面让我们看一下两个异常在API文档中的说明
ClassNotFoundExceptionQ?
当应用尝试用字符串名U通过下面的方法装载一个类时这个类的定义却没有扑ֈ时会抛出的异常?
Class.forName
ClassLoader.findSystemClass
ClassLoader.loadClass
NoClassDefFoundErrQ?
当JVM或者ClassLoader实例试装蝲一个类的定义(q通常是一个方法调用或者new表达式创Z个实例过E的一部分Q而这个类定义q没有找时所抛出的错误?
当编译的时候可以找到这个类的定义,但是以后q个cM再存在?/p>
q比较显而易见了吧,d文档是很重要的事情。这里我p一下我对这两个cȝ区别的理解?/p>
ClassNotFoundException异常只出现在你的应用E序d的装载类的过E中Q这个异常很多时候出现在我们的应用框架在初始化或者运行中动态装载已配置的类的过E中。这U情况下我们应该首先查我们的配置或者参数是否错误,是否企图装蝲一个ƈ不存在的c,如果配置没有错误Q我们就应该查看Classpath是否配置错误而导致ClassLoader无法扑ֈq个c,也应该检查要装蝲的类是否在一个jar包中而我们在引入q个jar包的q程中是否有遗漏或错误(q里jar包的版本也是一个需要格外注意的问题Q很多时候qjar包版本会造成太多的麻烦)?
NoClassDefFoundErr异常一般出现在我们~译环境和运行环境不一致的情况下,是说我们有可能在编译过后更改了Classpath或者jar包所以导致在q行的过E中JVM或者ClassLoader无法扑ֈq个cȝ定义Q我曄在编译后作了一ơjar包的清理Q然后应用就送给了我一个这LC物Q?/p>
我们l常用SDK开发应用,开发的q程中要引入很多jar包,有些SDK也会讑֮自己的Classpath。编译过E结束后在运行的q程中就要将已开发的应用和所有引入的jar包拷贝到应用服务器的相应目录下才可以q行Q而应用服务器使用的Classpath也很有可能与SDK的不同,在这个过E中有很大的几率造成双方环境不一致。所以很多开发者就会遇到在SDK中可以编译,q行也没有问题,但是同样的程序放到应用服务器上就出现NoClassDefFoundErrq个异常q种情况Q这是让初学者很挠头的一个问题?/p>
以上是我对q两个异常的一点个人理解,希望对各位开发者有所帮助Q可以让各位开发者在以后的开发过E中能够更快的找到问题所在。祝开发顺?/p>
在第二种模型中,我们可以清楚的把q?个类分ؓ三层Q?/p>
1、实体类层,即ItemQ带有domain logic的domain object
2、DAO层,即ItemDao和ItemDaoHibernateImplQ抽象持久化操作的接口和实现c?
3、业务逻辑层,即ItemManagerQ接受容器事务控Ӟ向Web层提供统一的服务调?/p>
在这三层中我们大家可以看刎ͼdomain object和DAO都是非常E_的层Q其实原因也很简单,因ؓdomain object是映数据库字段的,数据库字D不会频J变动,所以domain object也相对稳定,而面向数据库持久化编E的DAO层也不过是CRUD而已Q不会有更多的花P所以也很稳定?/p>
问题在于这个充当business workflow facade的业务逻辑对象Q它的变动是相当频繁的?span style="COLOR: red">业务逻辑对象通常都是无状态的、受事务控制的、Singletonc?/span>Q我们可以考察一下业务逻辑对象都有哪几cM务逻辑Ҏ(gu)Q?/p>
W一c:DAO接口Ҏ(gu)的代?/span>Q就是上面例子中的loadItemByIdҎ(gu)和findAllҎ(gu)?/p>
ItemManager之所以要代理q种c,目的有两个:向Web层提供统一的服务调用入口点和给持久化方法增加事务控制功?/span>。这两点都很Ҏ(gu)理解Q你不能既给Web层程序员提供xxxManagerQ也l他提供xxxDaoQ所以你需要用xxxManager装xxxDaoQ在q里Q充当了一个简单代理功能;而事务控制也是持久化Ҏ(gu)必须的,事务可能需要跨多个DAOҎ(gu)调用Q所以必L在业务逻辑层,而不能放在DAO层?/p>
但是必须看到Q对于一个典型的web应用来说Q绝大多数的业务逻辑都是单的CRUD逻辑Q所以这U情况下Q针Ҏ(gu)个DAOҎ(gu)QxxxManager都需要提供一个对应的装Ҏ(gu)Q这不但是非常枯燥的Q也是o人感觉非怸好的?/p>
W二c:domain logic的方法代?/span>。就是上面例子中placeBidҎ(gu)。虽然Item已经有了placeBidҎ(gu)Q但是ItemManager仍然需要封装一下Item的placeBidQ然后再提供一个简单封装之后的代理Ҏ(gu)?/p>
q和W一U情늱|其原因也一P也是ZlWeb层提供一个统一的服务调用入口点和给隐式的持久化动作提供事务控制?/p>
同样Q和W一U情况一P针对每个domain logicҎ(gu)QxxxManager都需要提供一个对应的装Ҏ(gu)Q同h枯燥的,令h不爽的?/p>
W三c:需要多个domain object和DAO参与协作的business workflow。这U情冉|业务逻辑对象真正应该完成的职责?/p>
在这个简单的例子中,没有涉及到这U情况,不过大家都可以想像的出来q种应用场景Q因此不必D例说明了?/p>
通过上面的分析可以看出,只有W三cM务逻辑Ҏ(gu)才是业务逻辑对象真正应该承担的职责,而前两类业务逻辑Ҏ(gu)都是“无奈之䏀,不得不ؓ之的事情Q不但枯燥,而且令h沮?/p>
分析完了业务逻辑对象Q我们再回头看一下domain objectQ我们要仔细考察一下domain logic的话Q会发现domain logic也分Zc:
W一c:需要持久层框架隐式的实现透明持久化的domain logicQ例如Item的placeBidҎ(gu)中的q一句: 对于q一cdomain logicQ业务逻辑对象必须提供相应的封装方法,以实C务控制?/p> W二c:完全不依赖持久化的domain logicQ例如readonly例子中的TopicQ如下: 注意q个isAllowReplyҎ(gu)Q他和持久化完全不发生一丁点关系。在实际的开发中Q我们同样会遇到很多q种不需要持久化的业务逻辑(主要发生在日期运、数D和枚Dq算斚w)Q这Udomain logic不管q不脱L在的框架Q它的行为都是一致的。对于这Udomain logicQ业务逻辑层ƈ不需要提供封装方法,它可以适用于Q何场合?/p>
this
.
getBids
().
add
(
newBid
);
上面已经着重提刎ͼ虽然q仅仅只是一个Java集合的添加新元素的操作,但是实际上通过事务的控Ӟ会潜在的触发两条SQLQ一条是insert一条记录到bid表,一条是更新item表相应的记录。如果我们让ItemqHibernateq行单元试Q它?yu)是一个单U的Java集合操作Q如果我们把他加入到Hibernate框架中,他就会潜在的触发两条SQLQ?span style="COLOR: red">q就是隐式的依赖于持久化的domain logic?
特别h意的一Ҏ(gu)Q在没有Hibernate/JDOq类可以实现“透明的持久化”工具出C前,q类domain logic是无法实现的?
class Topic{
booleanisAllowReply(){
CalendardueDate=Calendar.getInstance();
dueDate.setTime(lastUpdatedTime);
dueDate.add(Calendar.DATE,forum.timeToLive);
Datenow=newDate();
returnnow.after(dueDate.getTime());
}
}
W一U模型:只有getter/setterҎ(gu)的纯数据c,所有的业务逻辑完全由business object来完?又称TransactionScript)Q这U模型下的domain object被Martin FowlerUC为“血的domain object”。下面用举一个具体的代码来说明,代码来自Hibernate的caveatemptorQ但l过我的改写Q?/p>
一个实体类叫做ItemQ指的是一个拍卖项?
一个DAO接口cd做ItemDao
一个DAO接口实现cd做ItemDaoHibernateImpl
一个业务逻辑cd做ItemManager(或者叫做ItemService)
public class Item implements Serializable {
private Long id = null ;
private int version ;
private String name ;
private User seller ;
private String description ;
private MonetaryAmount initialPrice ;
private MonetaryAmount reservePrice ;
private Date startDate ;
private Date endDate ;
private Set categorizedItems = new HashSet ();
private Collection bids = new ArrayList ();
private Bid successfulBid ;
private ItemState state ;
private User approvedBy ;
private Date approvalDatetime ;
private Date created = new Date ();
/ / getter / setterҎ(gu)省略不写Q避免篇q太?/span>
}
public interface ItemDao {
public Item getItemById ( Long id );
public Collection findAll ();
public void updateItem ( Item item );
}
ItemDao定义持久化操作的接口Q用于隔L久化代码?/p>
public class ItemDaoHibernateImpl implements ItemDao extends HibernateDaoSupport {
public Item getItemById ( Long id ) {
return ( Item ) getHibernateTemplate (). load ( Item . class , id );
}
public Collection findAll () {
return ( List ) getHibernateTemplate (). find (" from Item ");
}
public void updateItem ( Item item ) {
getHibernateTemplate (). update ( item );
}
}
publicclass ItemManager{
privateItemDaoitemDao;
publicvoidsetItemDao(ItemDaoitemDao){this.itemDao=itemDao;}
publicBidloadItemById(Longid){
itemDao.loadItemById(id);
}
publicCollectionlistAllItems(){
returnitemDao.findAll();
}
publicBidplaceBid(Itemitem,Userbidder,MonetaryAmountbidAmount,
BidcurrentMaxBid,BidcurrentMinBid)throwsBusinessException{
if(currentMaxBid!=null&¤tMaxBid.getAmount().compareTo(bidAmount)>0){
thrownewBusinessException("Bid too low.");
}
//Auctionisactive
if(!state.equals(ItemState.ACTIVE))
thrownewBusinessException("Auction is not active yet.");
//Auctionstillvalid
if(item.getEndDate().before(newDate()))
thrownewBusinessException("Can't place new bid, auction already ended.");
//CreatenewBid
BidnewBid=newBid(bidAmount,item,bidder);
//PlacebidforthisItem
item.getBids().add(newBid);
itemDao.update(item);// 调用DAO完成持久化操?/span>
returnnewBid;
}
}
事务的管理是在ItemMangerq一层完成的QItemManager实现具体的业务逻辑。除了常见的和CRUD有关的简单逻辑之外Q这里还有一个placeBid的逻辑Q即目的竞标?/p>
以上是一个完整的W一U模型的CZ代码。在q个CZ中,placeBidQloadItemByIdQfindAll{等业务逻辑l统攑֜ItemManager中实玎ͼ而Item只有getter/setterҎ(gu)?br />
W二U模型,也就是Martin Fowler指的rich domain object是下面这样子的:
一个带有业务逻辑的实体类Q即domain object是Item
一个DAO接口ItemDao
一个DAO实现ItemDaoHibernateImpl
一个业务逻辑对象ItemManager
publicclass ItemimplementsSerializable{
// 所有的属性和getter/setterҎ(gu)同上Q省?/span>
publicBidplaceBid(Userbidder,MonetaryAmountbidAmount,
BidcurrentMaxBid,BidcurrentMinBid)
throwsBusinessException{
//Checkhighestbid(canalsobeadifferentStrategy(pattern))
if(currentMaxBid!=null&¤tMaxBid.getAmount().compareTo(bidAmount)>0){
thrownewBusinessException("Bid too low.");
}
//Auctionisactive
if(!state.equals(ItemState.ACTIVE))
thrownewBusinessException("Auction is not active yet.");
//Auctionstillvalid
if(this.getEndDate().before(newDate()))
thrownewBusinessException("Can't place new bid, auction already ended.");
//CreatenewBid
BidnewBid=newBid(bidAmount,this,bidder);
//PlacebidforthisItem
this.getBids.add(newBid);// h意这一句,透明的进行了持久化,但是不能在这里调?span class="constant">ItemDaoQItem不能对ItemDao产生依赖Q?/span>
returnnewBid;
}
}
竞标q个业务逻辑被放入到Item中来。请注意this.getBids.add(newBid); 如果没有Hibernate或者JDOq种O/R Mapping的支持,我们是无法实现这U透明的持久化行ؓ的。但是请注意QItem里面不能去调用ItemDAOQ对ItemDAO产生依赖Q?/p>
ItemDao和ItemDaoHibernateImpl的代码同上,省略?/p>
publicclass ItemManager{
privateItemDaoitemDao;
publicvoidsetItemDao(ItemDaoitemDao){this.itemDao=itemDao;}
publicBidloadItemById(Longid){
itemDao.loadItemById(id);
}
publicCollectionlistAllItems(){
returnitemDao.findAll();
}
publicBidplaceBid(Itemitem,Userbidder,MonetaryAmountbidAmount,
BidcurrentMaxBid,BidcurrentMinBid)throwsBusinessException{
item.placeBid(bidder,bidAmount,currentMaxBid,currentMinBid);
itemDao.update(item);// 必须昑ּ的调?span class="constant">DAOQ保持持久化
}
}
在第二种模型中,placeBid业务逻辑是放在Item中实现的Q而loadItemById和findAll业务逻辑是放在ItemManager中实现的。不q值得注意的是Q即使placeBid业务逻辑攑֜Item中,你仍焉要在ItemManager中简单的装一层,以保证对placeBid业务逻辑q行事务的管理和持久化的触发?/p>
q种模型是Martin Fowler所指的真正的domain model。在q种模型中,有三个业务逻辑Ҏ(gu)QplaceBidQloadItemById和findAllQ现在的问题是哪个逻辑应该攑֜Item中,哪个逻辑应该攑֜ItemManager中。在我们q个例子中,placeBid攑֜Item?但是ItemManager也需要对它进行简单的装)QloadItemById和findAll是放在ItemManager中的?/p>
切分的原则是什么呢Q?Rod Johnson提出原则是“case by case”,可重用度高的Q和domain object状态密切关联的攑֜Item中,可重用度低的Q和domain object状态没有密切关联的攑֜ItemManager中?/p>
我提出的原则是:看业务方法是否显式的依赖持久化?/span>
Item的placeBidq个业务逻辑Ҏ(gu)没有昑ּ的对持久化ItemDao接口产生依赖Q所以要攑֜Item中?span style="COLOR: red">h意,如果q了Hibernateq个持久化框ӞItemq个domain object是可以进行单元测试的Q他不依赖于Hibernate的持久化机制。它是一个独立的Q可UL的,完整的,自包含的域对?/span>?/p>
而loadItemById和findAllq两个业务逻辑Ҏ(gu)是必L式的Ҏ(gu)久化ItemDao接口产生依赖Q否则这个业务逻辑无法完成。如果你要把q两个方法放在Item中,那么Item无法脱Hibernate框架Q无法在Hibernate框架之外独立存在?br />
W三U模型印象中好像是firebody或者是Archie提出?也有可能不是Q记不清楚了)Q简单的来说Q这U模型就是把W二U模型的domain object和business object合二Z了。所以ItemManager׃需要了Q在q种模型下面Q只有三个类Q他们分别是Q?/p>
ItemQ包含了实体cM息,也包含了所有的业务逻辑
ItemDaoQ持久化DAO接口c?
ItemDaoHibernateImplQDAO接口的实现类
׃ItemDao和ItemDaoHibernateImpl和上面完全相同,q略了?/p>
publicclass ItemimplementsSerializable{
// 所有的属性和getter/setterҎ(gu)都省?/span>
privatestaticItemDaoitemDao;
publicvoidsetItemDao(ItemDaoitemDao){this.itemDao=itemDao;}
publicstaticItemloadItemById(Longid){
return(Item)itemDao.loadItemById(id);
}
publicstaticCollectionfindAll(){
return(List)itemDao.findAll();
}publicBidplaceBid(Userbidder,MonetaryAmountbidAmount,
BidcurrentMaxBid,BidcurrentMinBid)
throwsBusinessException{
//Checkhighestbid(canalsobeadifferentStrategy(pattern))
if(currentMaxBid!=null&¤tMaxBid.getAmount().compareTo(bidAmount)>0){
thrownewBusinessException("Bid too low.");
}
//Auctionisactive
if(!state.equals(ItemState.ACTIVE))
thrownewBusinessException("Auction is not active yet.");
//Auctionstillvalid
if(this.getEndDate().before(newDate()))
thrownewBusinessException("Can't place new bid, auction already ended.");
//CreatenewBid
BidnewBid=newBid(bidAmount,this,bidder);
//PlacebidforthisItem
this.addBid(newBid);
itemDao.update(this);// 调用DAOq行昑ּ持久?/span>
returnnewBid;
}
}
在这U模型中Q所有的业务逻辑全部都在Item中,事务理也在Item中实现?/p>