浅谈web开发中的异常
浅谈web开发中的异常。
序:
异常,估计n多人都知道,至于那些定义、分类,我就不扯了。
在web开发中,凡是过来的人都应该知道,在action层调用义务层处理后,成功执行还好,
非成功执行就得通过某种方式通知action,然后action才知道将要显示何种提示信息给用户。
说到这,那就进入今天的话题了。
正文----开整
在web开发中异常应该有两类,一类为java程序中定义的异常,即如果按照我们设想的不应该
出现的异常,而另一类就是开发中很重要的业务异常。
何为业务异常呢,先举个例子说明一下,例如在修改一个用户信息时,传递用户的年龄(age)不
应该大于其父母亲的年龄,因此在service层中必然会做一个和父母亲年龄作比较的业务判断,
一旦判断失败,在通常的处理中是返回一个标识,而我认为在业务中我们应该只关心正确流程,
也就是说整个程序没有执行失败的返回路径,作为替代,我们定义一种异常,向上层抛出,以标
识的失败,这种异常就是我们称为的业务异常。
在action层,业务异常是应该要捕获的,并提示相应的信息给用户,这样用户才知道哪里出了错。
而对于其他异常,一旦出现,普通的做法是,定义一个页面,提示:系统正忙,请稍后再试。。。
如果是使用struts2进行开发的时候,对于业务异常,可以根据相应的异常标识,使用addActionError
等,返回INPUT页面,提示用户相应的信息;对于其他异常,可以使用在struts的包中定义一个
GlobalException来捕获,然后在result中返回公共的异常处理页面,如上面提到的系统正忙页面。
下面是一个简单的ServiceException异常类。
public class ServieException
{
//异常码,标识异常,也可以是国际化资源文件中的key值
private long exceptionCode;
//异常参数,也可以是国际化资源文件中对应key标识的资源所需的参数
private String[] parameters;
//构造器
public ServiceException(long exceptionCode, String... parameters)
{
this.exceptionCode = exceptionCode;
this.parameters = parameters;
}
public long getExceptionCode()
{
return exceptionCode;
}
public void setExceptionCode(long exceptionCode)
{
this.exceptionCode = exceptionCode;
}
public String[] getParameters()
{
return parameters;
}
public void setParameters(String[] parameters)
{
this.parameters = parameters;
}
}
如果exceptionCode对应的是国际化资源文件中的key值,那么在action调用service层方法
时,一旦出现异常(ServiceException e),便可以使用如下语句
addActionError(getExceptionCode, getParameters());
return INPUT;
这样就可以把相关业务异常所代表的信息提示给用户。
注意,并不是每个action都可以定义INPUT页面的,所以在实际应用中,还应该提供一个公共
的失败页面,以供那些不能返回INPUT的页面,提示错误信息。当然,最好也提供一个公共成
功的页面,好事成双嘛。哈哈。。。
简单理解,请批评指教。
OK,打完收工
41 楼 cy729215495 2009-02-06 airport 写道这个问题老生常谈了。
我记得Appfuse里面的代码就有UserNotExistException这样的类定义
定义业务异常最大的好处就是对于设计上和将来代码维护上能够更加方面直观
过去那种返回状态吗的,必须配合注释和文档,时间长了不易读。
效率上自然是返回状态吗的要更加快捷了,所有有个取舍,没什么正确性与否,
很多事情本来就没有对和错的。
举双手赞成,其实看看jive,里面就有很多业务异常,它的这个业务异常比楼主所认为的业务异常还要
广,比如UnauthorizedException,如果是用户名和密码这两个参数为空,也抛这个异常。个人还是偏向
业务异常。 42 楼 funcreal 2009-02-06 建议楼主再多学习学习,就算你对异常的理解是对的,你举的那个例子也实在不靠谱。
用户输入的年龄比自己的母亲大,这个不是异常,这个是开发期间完全可以预知的事情,应该使用条件判断。 43 楼 wendong007 2009-02-07 <p><span style="font-size: large;">我基本赞同楼主的观点——如果异常带来的性能开销没有那么大的话</span></p>
<p>?</p>
<p><span style="font-size: large;">如果考虑到性能问题的话,我觉得这样确实有点奢侈</span></p> 44 楼 ellen_1397 2009-02-09 一般情况下,使用业务异常大家觉得是使用编译时异常好还是运行时异常好?我点用的特别乱!请教一下!
45 楼 stenlylee 2009-02-18 seam中已经定义了不错的WEB异常处理机制,何必这么费力 46 楼 yidao620c 2009-02-18 寫的好。領用了 47 楼 fengyifei11228 2009-02-18 miaodezhi 写道colorfish 写道
个人觉得用异常要慎重,处理异常耗费资源,且处理不好容易造成很多不必要的麻烦....
呵呵,抛出异常确实要比返回错误码浪费掉更多的资源。
但是把异常分类,归总的话,以后出了问题,容易查找和排除啊
如果直接返回错误码,那么你在日志里看到了一个异常,你怎么能知道是在哪抛出的,因为什么抛出的,你不可能一下就判断出来,只能根据上下文,确定抛出异常的地点,然后查找,太麻烦啊 (特别是对于大项目而言更是如此)
个人觉得在项目开发之前设计出一套异常体系是很有必要的 48 楼 flyingchen 2009-02-20 这些东西都是可知的,为什么还要用异常呢 49 楼 l7810 2009-02-28 我在像一个问题,对于异常来说,每抛一次异常,比正常判断异常更耗系统资源;对于一些不可预测的异常,只有牺牲部分系统资源去捕获;不知道各位是否同意。 50 楼 luodaijun 2009-03-19 支持LZ,某些业务异常是需要显示给用户看的,并且这些信息需要国际化!!老外和中国人看的异常信息不能一样吧
类似下面的代码
业务层
--------------------------------
deleteEmployee(){
//判断是否还有借款
if(...){
throw new ServiceException("ERROR_001");
// return 0; 返回0表示用户还有借款
}
}
----------------------------------
采用返回值的方式
你要自己国际化错误信息,还有写一堆的if..else,然后跳转页面
控制层
deleteEmployee(){
int rtnCode=service.deleteEmployee(....
//国际化错误信息
String message= ....
if(rtnCode==0){
//处理
//跳转某页面
}else if(rtnCode==1){
}
}
--多么繁杂的代码,如果业务方法多返回了一种状态码,是不是所有调用了这个业务方法的地方都要改动呢?
使用抛出异常的方式,可以在控制层统一捕获ServiceException,跳转到统一页面,并根据异常编码国际化信息,业务方法的调用就不必关系业务逻辑检查的错误了。
而且,我认为,业务逻辑异常,比如用户输入的订单编号不存在,调用者几乎不可能再处理的,不如直接抛出RuntimeException来的简洁,spring,hibernate,有多少异常需要强行try或者throws了 51 楼 miaodezhi 2009-03-26 luodaijun 写道 支持LZ,某些业务异常是需要显示给用户看的,并且这些信息需要国际化!!老外和中国人看的异常信息不能一样吧
类似下面的代码
业务层
--------------------------------
deleteEmployee(){
//判断是否还有借款
if(...){
throw new ServiceException("ERROR_001");
// return 0; 返回0表示用户还有借款
}
}
----------------------------------
采用返回值的方式
你要自己国际化错误信息,还有写一堆的if..else,然后跳转页面
控制层
deleteEmployee(){
int rtnCode=service.deleteEmployee(....
//国际化错误信息
String message= ....
if(rtnCode==0){
//处理
//跳转某页面
}else if(rtnCode==1){
}
}
--多么繁杂的代码,如果业务方法多返回了一种状态码,是不是所有调用了这个业务方法的地方都要改动呢?
使用抛出异常的方式,可以在控制层统一捕获ServiceException,跳转到统一页面,并根据异常编码国际化信息,业务方法的调用就不必关系业务逻辑检查的错误了。
而且,我认为,业务逻辑异常,比如用户输入的订单编号不存在,调用者几乎不可能再处理的,不如直接抛出RuntimeException来的简洁,spring,hibernate,有多少异常需要强行try或者throws了
对,只不过要多创建一些对象而已罢了。