J2EE项目异常处理(转)
Posted fashflying
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了J2EE项目异常处理(转)相关的知识,希望对你有一定的参考价值。
public String getPassword(String userId)throws DataAccessException{ String sql = “select password from userinfo where userid=’”+userId +”’”; String password = null; Connection con = null; Statement s = null; ResultSet rs = null; try{ con = getConnection();//获得数据连接 s = con.createStatement(); rs = s.executeQuery(sql); while(rs.next()){ password = rs.getString(1); } rs.close(); s.close(); } Catch(SqlException ex){ throw new DataAccessException(ex); } finally{ try{ if(con != null){ con.close(); } } Catch(SQLException sqlEx){ throw new DataAccessException(“关闭连接失败!”,sqlEx); } } return password; }
可以看出Java的异常处理机制具有的优势:
public String getPassword(String userId){ try{ …… Statement s = con.createStatement(); …… Catch(SQLException sqlEx){ …… } …… }
或者
public String getPassword(String userId)throws SQLException{ Statement s = con.createStatement(); }
(当然,像Connection,Satement这些资源是需要及时关闭的,这里仅是为了说明checked 异常必须强制调用者进行捕获或继续抛出)
String str = “123”; int value = Integer.parseInt(str);
parseInt的方法签名为:
public static int parseInt(String s) throws NumberFormatException
当传入的参数不能转换成相应的整数时,将会抛出NumberFormatException。因为NumberFormatException扩展于RuntimeException,是unChecked异常。所以调用parseInt方法时无需要try…catch
try{ …… Statement s = con.createStatement(); …… Catch(SQLException sqlEx){ sqlEx.PrintStackTrace(); } 或者 try{ …… Statement s = con.createStatement(); …… Catch(SQLException sqlEx){ //什么也不干 }
checked异常导致了许多难以理解的代码产生
public void methodA()throws ExceptionA{ ….. throw new ExceptionA(); } public void methodB()throws ExceptionB{ try{ methodA(); …… }catch(ExceptionA ex){ throw new ExceptionB(ex); } } Public void methodC()throws ExceptinC{ try{ methodB(); … } catch(ExceptionB ex){ throw new ExceptionC(ex); } }
我们看到异常就这样一层层无休止的被封装和重新抛出。
如
IllegalArgumentException, UnsupportedOperationException
不管是新的异常是chekced异常还是unChecked异常。我们都必须考虑异常的嵌套问题。
public void methodA()throws ExceptionA{ ….. throw new ExceptionA(); }
public void methodB()throws ExceptionB{ try{ methodA(); …… }catch(ExceptionA ex){ throw new ExceptionB(ex); } }
public Class ExceptionB extends Exception{ private Throwable cause; public ExceptionB(String msg, Throwable ex){ super(msg); this.cause = ex; } public ExceptionB(String msg){ super(msg); } public ExceptionB(Throwable ex){ this.cause = ex; } }
public void printStackTrace(PrintStrean ps){ if(cause == null){ super.printStackTrace(ps); }else{ ps.println(this); cause.printStackTrace(ps); } }
public NestedException extends Exception{ private Throwable cause; public NestedException (String msg){ super(msg); } public NestedException(String msg, Throwable ex){ super(msg); This.cause = ex; } public Throwable getCause(){ return (this.cause == null ? this :this.cause); } public getMessage(){ String message = super.getMessage(); Throwable cause = getCause(); if(cause != null){ message = message + “;nested Exception is ” + cause; } return message; } public void printStackTrace(PrintStream ps){ if(getCause == null){ super.printStackTrace(ps); }else{ ps.println(this); getCause().printStackTrace(ps); } } public void printStackTrace(PrintWrite pw){ if(getCause() == null){ super.printStackTrace(pw); } else{ pw.println(this); getCause().printStackTrace(pw); } } public void printStackTrace(){ printStackTrace(System.error); } }
public String getPassword(String userId)throws NoSuchUserException{ UserInfo user = userDao.queryUserById(userId); If(user == null){ Logger.info(“找不到该用户信息,userId=”+userId); throw new NoSuchUserException(“找不到该用户信息,userId=”+userId); } else{ return user.getPassword(); } } public void sendUserPassword(String userId)throws Exception { UserInfo user = null; try{ user = getPassword(userId); //…….. sendMail(); // }catch(NoSuchUserException ex)( logger.error(“找不到该用户信息:”+userId+ex); throw new Exception(ex); }
我们注意到,一个错误被记录了两次.在错误的起源位置我们仅是以info级别进行记录。而在sendUserPassword方法中,我们还把整个异常信息都记录了。
笔者曾看到很多项目是这样记录异常的,不管三七二一,只有遇到异常就把整个异常全部记录下。如果一个异常被不断的封装抛出多次,那么就被记录了多次。那么异常倒底该在什么地方被记录?
异常应该在最初产生的位置记录!
如果必须捕获一个无法正确处理的异常,仅仅是把它封装成另外一种异常往上抛出。不必再次把已经被记录过的异常再次记录。
如果捕获到一个异常,但是这个异常是可以处理的。则无需要记录异常
java 代码
public Date getDate(String str){ Date applyDate = null; SimpleDateFormat format = new SimpleDateFormat(“MM/dd/yyyy”); try{ applyDate = format.parse(applyDateStr); } catch(ParseException ex){ //乎略,当格式错误时,返回null } return applyDate; }
捕获到一个未记录过的异常或外部系统异常时,应该记录异常的详细信息
try{ …… String sql=”select * from userinfo”; Statement s = con.createStatement(); …… Catch(SQLException sqlEx){ Logger.error(“sql执行错误”+sql+sqlEx); }
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(); }
// public class UserSoaImpl implements UserSoa{ public UserInfo getUserInfo(String userId)throws RemoteException{ //…… 远程方法调用. //…… } } public interface UserManager{ public UserInfo getUserInfo(Stirng userId)throws RemoteException; }
同样JDBC访问都会抛出SQLException的checked异常。
public DataAccessException extends RuntimeException{ …… } public interface UserDao{ public String getPassword(String userId)throws DataAccessException; } public class UserDaoImpl implements 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异常.
public class BusinessException extends 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对象,调用相应的业务方法,然后进行页面转发,把相应的业务数据呈现给页面。表示层需要注意一个问题,表示层需要对数据的合法性进行校验,比如某些录入域不能为空,字符长度校验等。
ModeAndView handleRequest(HttpServletRequest request,HttpServletResponse response)throws Exception{ String ageStr = request.getParameter(“age”); int age = Integer.parse(ageStr); ………… String birthDayStr = request.getParameter(“birthDay”); SimpleDateFormat format = new SimpleDateFormat(“MM/dd/yyyy”); Date birthDay = format.parse(birthDayStr); }
上面的代码应该经常见到,但是当用户从页面录入一个不能转换为整型的字符或一个错误的日期值。
ModeAndView handleRequest(HttpServletRequest request,HttpServletResponse response)throws Exception{ String ageStr = request.getParameter(“age”); String birthDayStr = request.getParameter(“birthDay”); int age = 0; Date birthDay = null; try{ age=Integer.parse(ageStr); }catch(NumberFormatException ex){ error.reject(“age”,”不是合法的整数值”); } ………… try{ SimpleDateFormat format = new SimpleDateFormat(“MM/dd/yyyy”); birthDay = format.parse(birthDayStr); }catch(ParseException ex){ error.reject(“birthDay”,”不是合法的日期,请录入’MM/dd/yyy’格式的日期”); } }
在表示层一定要弄清楚调用方法的是否会抛出unChecked异常,什么情况下会抛出这些异常,并作出正确的处理。
以上是关于J2EE项目异常处理(转)的主要内容,如果未能解决你的问题,请参考以下文章
[查异常网]-20160331-谈谈J2EE项目中的异常处理
java.util.MissingResourceException: Can't find bundle for base name init, locale zh_CN问题的处理(代码片段