Java EE项目中的异常处理(四)

2014-11-24 09:19:26 · 作者: · 浏览: 2
常对象时,异常信息就被自动记录。
java 代码
public class BusinessException extends Exception {
private void logTrace() {
StringBuffer buffer=new StringBuffer();
buffer.append("Business Error in Class: ");
buffer.append(getClassName());
buffer.append(",method: ");
buffer.append(getMethodName());
buffer.append(",messsage: ");
buffer.append(this.getMessage());
logger.error(buffer.toString());
}
public BusinessException(String s) {
super(s);
race();
}
这似乎看起来是十分美妙的,其实必然导致了异常被重复记录。同时违反了“类的职责分配原则”,是一种不好的设计。记录异常不属于异常类的行为,记录异常应该由专门的日志系统去做。并且异常的记录信息是不断变化的。我们在记录异常同应该给更丰富些的信息。以利于我们能够根据异常信息找到问题的根源,以解决问题。
虽然我们对记录异常讨论了很多,过多的强调这些反而使开发人员更为疑惑,一种好的方式是为系统提供一个异常处理框架。由框架来决定是否记录异常和怎么记录异常。而不是由普通程序员去决定。但是了解些还是有益的。
5. J2EE项目中的异常处理
目前,J2ee项目一般都会从逻辑上分为多层。比较经典的分为三层:表示层,业务层,集成层(包括 数据库访问和外部 系统的访问)。
J2ee项目有着其复杂性,J2ee项目的异常处理需要特别注意几个问题。
在分布式应用时,我们会遇到许多checked异常。所有RMI调用(包括EJB远程接口调用)都会抛出java.rmi.RemoteException;同时RemoteException是checked异常,当我们在业务系统中进行远程调用时,我们都需要编写大量的代码来处理这些checked异常。而一旦发生RemoteException这些checked异常对系统是非常严重的,几乎没有任何进行重试的可能。也就是说,当出现RemoteException这些可怕的checked异常,我们没有任何重试的必要性,却必须要编写大量的try…catch代码去处理它。一般我们都是在最底层进行RMI调用,只要有一个RMI调用,所有上层的接口都会要求抛出RemoteException异常。因为我们处理RemoteException的方式就是把它继续往上抛。这样一来就破坏了我们业务接口。RemoteException这些J2EE系统级的异常严重的影响了我们的业务接口。我们对系统进行分层的目的就是减少系统之间的依赖,每一层的技术改变不至于影响到其它层。
java 代码
//
public class UserSoaImplimplements UserSoa{
public UserInfo getUserInfo(String userId)throws RemoteException{
//……
远程方法调用.
//……
}
}
public interface UserManager{
public UserInfo getUserInfo(Stirng userId)throws RemoteException;
}
同样JDBC访问都会抛出SQLException的checked异常。
为了避免系统级的checked异常对业务系统的深度侵入,我们可以为业务方法定义一个业务系统自己的异常。针对像SQLException,RemoteException这些非常严重的异常,我们可以新定义一个unChecked的异常,然后把SQLException,RemoteException封装成unChecked异常后抛出。
如果这个系统级的异常是要交由上一级调用者处理的,可以新定义一个checked的业务异常,然后把系统级的异常封存装成业务级的异常后再抛出。
一般地,我们需要定义一个unChecked异常,让集成层接口的所有方法都声明抛出这unChecked异常。
java 代码
public DataAccessExceptionextends RuntimeException{
……
}
public interface UserDao{
public String getPassword(String userId)throws DataAccessException;
}
public class UserDaoImplimplements UserDAO{
public String getPassword(String userId)throws DataAccessException{
String sql = “select password from userInfo where userId= ‘”+userId+”’”;
try{

//JDBC调用
s.executeQuery(sql);

}catch(SQLException ex){
throw new DataAccessException(“数据库查询失败”+sql,ex);
}
}
}
定义一个checked的业务异常,让业务层的接口的所有方法都声明抛出Checked异常.
java 代码
public class BusinessExceptionextends Exception{
…..
}
public interface UserManager{
public Userinfo copyUserInfo(Userinfo user)throws BusinessException{
Userinfo newUser = null;
try{
newUser = (Userinfo)user.clone();
}catch(CloneNotSupportedException ex){
throw new BusinessException(“不支持clone方法:”+Userinfo.class.getName(),ex);
}
}
}
J2ee表示层应该是一个很薄的层,主要的功能为:获得页面请求,把页面的参数组装成POJO对象,调用相应的业务方法,然后进行页面转发,把相应的业务数据呈现给页面。表示层需要注意一个问题,表示层需要对数据的合法性进行校验,比如某些录入域不能为空,字符长度校验等。
J2ee从页面所有传给后台的参数都是字符型的,如果要求输入数值或日期类型的参数时,必须把字符值转换为相应的数值或日期值。
如果表示层代码校验参数不合法时,应该返回到原始页面,让用户重新录入数据,并提示相关的错误信息。
通常把一个从页面传来的参数转换为数值,我们可以看到这样的代码
java 代码
ModeAndView handleRequest(HttpServletRequest request,HttpServletResponse response)throws Exception{
String ageStr = request.getP