最近在考虑以前做项目的时候,设计的异常处理方式是不是合理,这里共享出来给大家讨论,也想了解一下大家的异常处理的方法。异常处理主要包括2种,一种是系统的异常,另外一种是业务逻辑的不合法,这里称为业务逻辑异常可能不太确切,不过我还是把它当做业务逻辑的异常来处理。系统异常直接通过捕获给与友好的错误页面也好,直接报出来也好,我这里不做说明了,对于项目的开发存在大量的业务逻辑的判断合法性,然后给与提示,我主要说说这里。
我认为的业务逻辑的异常打个比方比如,用户输入了一张单据,在单据保存的时候来判断单据的编号是否重复(如果允许输入单据编号的话),给与提示比如“单据编号重复”,然后让用户重新输入。这里是用asp.net做的,在aspx.cs后台代码中,我是这样处理的,
try
{
Bill bill = new Bill();
//给以单据实体类赋值.
//实例话一个实体操作类
BillMng mng = new BillMng();
//然后保存
mng.Save(bill);
}
catch(Exception ex)
{
CommFunc.ShowErrorMessage(this,ex.Message.ToString());
}
{
Bill bill = new Bill();
//给以单据实体类赋值.
//实例话一个实体操作类
BillMng mng = new BillMng();
//然后保存
mng.Save(bill);
}
catch(Exception ex)
{
CommFunc.ShowErrorMessage(this,ex.Message.ToString());
}
通过BillMng 管理类来管理保存业务单据代码:
/// <summary>
/// 保存业务单据
/// </summary>
/// <param name="bill">单据</param>
public void Save(Bill bill)
{
DB db= new DB();
try
{
//连接数据库,传递bill参数,调用存储过程
}
catch(Exception e)
{
throw e;
}
finally
{
if (db != null)
db.Close();
}
}
/// 保存业务单据
/// </summary>
/// <param name="bill">单据</param>
public void Save(Bill bill)
{
DB db= new DB();
try
{
//连接数据库,传递bill参数,调用存储过程
}
catch(Exception e)
{
throw e;
}
finally
{
if (db != null)
db.Close();
}
}
然后,具体的业务逻辑判断,比如保存前判断单据编号是否在数据库中已经存在。或者通过存储过程直接抛出我经过格式化以后的异常。以下是Oracle存储过程中的代码。
先自定义一个异常变量:
existedData EXCEPTION ;
编号重复判断:
SELECT COUNT(1) INTO vCount FROM yourTable WHERE billNo=vsYouinputBillNo;
if (vCount > 0) then
raise existedData ;
end if;
--处理其他业务逻辑并保存
EXCEPTION
WHEN existedData THEN
RAISE_APPLICATION_ERROR(-20000,'#单据编号重复!#');
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20004, '数据库错误:' || SQLERRM);
if (vCount > 0) then
raise existedData ;
end if;
--处理其他业务逻辑并保存
EXCEPTION
WHEN existedData THEN
RAISE_APPLICATION_ERROR(-20000,'#单据编号重复!#');
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20004, '数据库错误:' || SQLERRM);
注意:这里的错误我是通过#号来做了区分,这样业务逻辑的中间层只负责有异常就抛出,在页面展示后台代码中统一捕获。我根据解析#号来判断业务逻辑的处理逻辑出现的异常,其他的异常在这里也直接抛出来,或者可以通过转向另外一个友好错误页面,我这里把所有异常都抛出来,业务逻辑抛出来的异常是自定义的。
/// <summary>
/// 解析数据库和页面中抛出的错误,无白屏
/// 1.页面的错误直接抛出
/// 2.数据库中报的用户定义的异常提示须加#,如提示:#没有数据!#
/// 3.数据库中系统报的错误.
/// </summary>
/// <param name="page">当前页面,可以直接在页面中用this</param>
/// <param name="ErrorMessage">异常的消息,如:ex.Message</param>
public static void ShowErrorMessage(Page page,string ErrorMessage)
{
char[] cha = new char[1];
cha[0]='#'; //自定义的业务逻辑异常规则
Random Ram=new Random(unchecked((int)DateTime.Now.Ticks));
string vsName="Name" + Ram.NextDouble().ToString(); //生成不重复NAME
string strRepString =ErrorMessage.Replace("\n","\\n");//替换回车符为空格
strRepString =strRepString.Replace("\r","\\r"); //替换换行符为空格
strRepString =strRepString.Replace("\"","’"); //替换"符,为中文单引号
string[] mess = strRepString.Split(cha,3); //解析#号,分3段取中间的段是用户提示
int intErrorIndex = 1;
if(mess.Length ==1) //如果是页面报错,直接显示,或者转向另外一个友好页面
intErrorIndex =0;
page.RegisterStartupScript(vsName,"<script language='javascript'>alert(\""+mess[intErrorIndex]+"\");</script>");
}
/// 解析数据库和页面中抛出的错误,无白屏
/// 1.页面的错误直接抛出
/// 2.数据库中报的用户定义的异常提示须加#,如提示:#没有数据!#
/// 3.数据库中系统报的错误.
/// </summary>
/// <param name="page">当前页面,可以直接在页面中用this</param>
/// <param name="ErrorMessage">异常的消息,如:ex.Message</param>
public static void ShowErrorMessage(Page page,string ErrorMessage)
{
char[] cha = new char[1];
cha[0]='#'; //自定义的业务逻辑异常规则
Random Ram=new Random(unchecked((int)DateTime.Now.Ticks));
string vsName="Name" + Ram.NextDouble().ToString(); //生成不重复NAME
string strRepString =ErrorMessage.Replace("\n","\\n");//替换回车符为空格
strRepString =strRepString.Replace("\r","\\r"); //替换换行符为空格
strRepString =strRepString.Replace("\"","’"); //替换"符,为中文单引号
string[] mess = strRepString.Split(cha,3); //解析#号,分3段取中间的段是用户提示
int intErrorIndex = 1;
if(mess.Length ==1) //如果是页面报错,直接显示,或者转向另外一个友好页面
intErrorIndex =0;
page.RegisterStartupScript(vsName,"<script language='javascript'>alert(\""+mess[intErrorIndex]+"\");</script>");
}
ok.这就是我处理异常的方式,这样代码比较简洁,不用通过函数的返回值来判断是否错误编号,通过alert来显示提示信息。
当然还有很多好的方法,大家都是通过什么方式来处理业务逻辑异常和系统的异常的, 在系统的维护性,扩展性,和健壮性方面这样的做法是不是合理,欢迎回帖讨论。