浏览 7471 次
锁定老帖子 主题:关于WEB应用的分层和异常处理的问题
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2006-10-31
数据层自己写,MVC用webwork 每个数据表对应一个DTO,一个VO,一个DAO、一个Manager(Service)和一个Action 其中DTO是对应于数据表的结构的 VO是继承了DTO,并且加入了一些其他的属性,比如和这个表关联的其他表的VO。 DAO层的类继承BaseDAO,BaseDAO包含了一些基本才作,比如执行更新的sql,执行查询的sql,执行查询记数的sql等等。 DAO、DTO和VO都是用自己写的一个代码生成工具生成基本代码,DAO主要生成了插入、删除、修改和查询的方法。 Service层也生成了基本的代码,也是插入删除修改和查询,直接调用DAO的方法。 Action层根据业务不同分别生生成一些代码,有些可能没用。比如基本的有toAddPage,toEditPage,toListPage,performAddAction,performEditAction,performDeleteAction等等。Action层直接调用Service层的方法。 由于为了简化开发提高效率,所以这里的DAO和Service都没用接口。 现在有几个问题不知道如何处理合适: 1、现在的Service层因为业务逻辑比较简单,所以很多方法都是直接调用dao层的一个方法就完成了,所以我感觉和直接调用DAO差不多,觉得挺浪费一样,但如果不加Service层,很多稍复杂一些的业务必须得用几个DAO才能完成。这个地方如何才能平衡一下? 2、异常处理部分我可能没有处理好,现在的方式是,在DAO层遇到异常以后没有抛出,而是直接在BaseDAO里面加了一个errorMessage的属性,每次有异常就把异常信息set进去,然后通过函数的返回值知道这个函数发生了异常,在Service层也是一样的处理方式,感觉这种处理方式很不好,想了一个方法不知道合理不合理:在DAO层直接抛出一个自己定义的DataAccessException,在Service层调用DAO的方法时候补获这个异常以后,再转换成自己定义BusinessException,再抛出,然后在Action里面判断如果出现异常,则调用setActionError把异常信息填入,再转向统一的一个出错页面输出。这样做是否合理? 3、处理数据表关联问题,很多时候需要联合查询两个甚至多个表,这个时候我的做法是把select出来的数据集合先存在一个Hashtable里面,再根据某种字段名和VO的属性的转换关系把这个Hashtable转换成一个或者多个VO,同时每个VO为了DAO的统一处理方便,都要实现IVO里面的parse方法,参数是DataRow,DataRow也是自己定义的工具类,提供了Result和DataRow之间的转换还有DataRow和VO之间的转换。这样,如果我两个表之间有关联需要获取关联的数据,我就可以再parse里面把关联表的那个VO的各个属性也都根据DataRow里面的数据Set进去,这样就可以解决关联的问题。 可能我说的挺乱的,还是看代码吧: DataRow代码 package com.bang.adhibit.util; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; import java.sql.*; import java.util.HashMap; public class DataRow { private HashMap row = new HashMap(); public Object get(String key) { return row.get(key); } public void put(String key,Object obj) { row.put(key,obj); } public int getInt(String key) { Integer i = (Integer)row.get(key); if(i != null) return i.intValue(); return 0; } public long getLong(String key) { Long l = (Long)row.get(key); return (l!=null)?l.longValue():0; } public String getString(String key) { return (String)row.get(key); } public Timestamp getTimestamp(String key) { return (Timestamp)row.get(key); } public Date getDate(String key) { return (Date)row.get(key); } public static DataRow parse(ResultSet rs) throws SQLException { DataRow row = new DataRow(); ResultSetMetaData rsmd = rs.getMetaData(); int count = rsmd.getColumnCount(); for(int i=1;i<=count;i++) { row.put(rsmd.getColumnName(i).toLowerCase(),rs.getObject(i)); } return row; } //定义转换关系,比如user_name字段在DTO里面的属性就是userName private String convert(String name) { String result = ""; for(int i=0;i<name.length();i++) { char c = name.charAt(i); if(c >='A' && c <='Z') result += "_" + c; else result += c; } return result.toLowerCase(); } public Object toObject(Class c) { Object obj = null; try { obj = c.newInstance(); Field[] f = c.getDeclaredFields(); BeanInfo info = Introspector.getBeanInfo(c); PropertyDescriptor[] pds = info.getPropertyDescriptors(); for(int i=0;i<pds.length;i++) { String name = pds[i].getName(); String key = convert(name); Object value = get(key); if(value == null) continue; Method method = pds[i].getWriteMethod(); if(method != null) { try { String type = method.getParameterTypes()[0].getName(); //System.out.println("@"+type+";value="+value.getClass().getName()); if(type.equals("int")) { if(value instanceof BigDecimal) { BigDecimal bd = (BigDecimal)value; method.invoke(obj,new Object[]{new Integer(bd.intValue())}); } if(value instanceof Long) { Long l = (Long)value; method.invoke(obj,new Object[]{new Integer(l.intValue())}); } if(value instanceof Integer) { Long l = (Long)value; method.invoke(obj,new Object[]{(Integer)value}); } } if(type.equals("long")) { if(value instanceof BigDecimal) { BigDecimal bd = (BigDecimal)value; method.invoke(obj,new Object[]{new Long(bd.longValue())}); } if(value instanceof Integer) { Integer intt = (Integer)value; method.invoke(obj,new Object[]{new Long(intt.longValue())}); } if(value instanceof Long) { Long l = (Long)value; method.invoke(obj,new Object[]{(Long)value}); } } if(type.equals("float")) { method.invoke(obj,new Object[]{(Float)value}); } if(type.endsWith("Timstamp")) method.invoke(obj,new Object[]{(Timestamp)value}); if(type.endsWith("Date")){ method.invoke(obj,new Object[]{new Date(((Timestamp)value).getTime())}); } if(type.equals("double")) { method.invoke(obj,new Object[]{(Double)value}); } if(type.endsWith("String")) method.invoke(obj,new Object[]{(String)value}); }catch(Exception e) { e.printStackTrace(); } } } } catch (Exception e) { e.printStackTrace(); return null; } return obj; } } 写不下了,其他见回复 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2006-10-31
DTO的代码:
package com.bang.adhibit.data; import java.sql.*; import java.util.HashMap; /** * * <p>Title: perfect_mobile_type表的数据对象类</p> * * <p>Description: 保存PerfectMobileType各个字段</p> * * <p>Copyright: Copyright (c) 2006</p> * * <p>Company: 邦邦网</p> * * @author not attributable * @version 1.0 */ public class PerfectMobileType { private long typeId; //型号ID private long mobileId; //品牌ID private String typeName; //型号名称(序列) private int width; //宽度 private int height; //高度 private int sortIndex; //排列顺序 private int enableFlag; //显示标记 private int state; //状态 //型号ID public void setTypeId(long typeId) { this.typeId = typeId; } //品牌ID public void setMobileId(long mobileId) { this.mobileId = mobileId; } //型号名称(序列) public void setTypeName(String typeName) { if(typeName == null) typeName = ""; this.typeName = typeName; } //宽度 public void setWidth(int width) { this.width = width; } //高度 public void setHeight(int height) { this.height = height; } //排列顺序 public void setSortIndex(int sortIndex) { this.sortIndex = sortIndex; } //显示标记 public void setEnableFlag(int enableFlag) { this.enableFlag = enableFlag; } //状态 public void setState(int state) { this.state = state; } public long getTypeId(){ return this.typeId; } public long getMobileId(){ return this.mobileId; } public String getTypeName(){ return this.typeName; } public int getWidth(){ return this.width; } public int getHeight(){ return this.height; } public int getSortIndex(){ return this.sortIndex; } public int getEnableFlag(){ return this.enableFlag; } public int getState(){ return this.state; } public String toString() { String retStr = "The value list of PerfectMobileTypeDTO is:\r\n"; retStr += ("[(型号ID)typeId] = " + typeId + "\r\n"); retStr += ("[(品牌ID)mobileId] = " + mobileId + "\r\n"); retStr += ("[(型号名称(序列))typeName] = " + typeName + "\r\n"); retStr += ("[(宽度)width] = " + width + "\r\n"); retStr += ("[(高度)height] = " + height + "\r\n"); retStr += ("[(排列顺序)sortIndex] = " + sortIndex + "\r\n"); retStr += ("[(显示标记)enableFlag] = " + enableFlag + "\r\n"); retStr += ("[(状态)state] = " + state + "\r\n"); return retStr; } //start your code here //finish your code here }//end of file VO的代码: package com.bang.adhibit.data; import com.bang.adhibit.util.*; /** * * <p>Title: Value Object</p> * * <p>Description: </p> * * <p>Copyright: Copyright (c) 2006</p> * * <p>Company: 邦邦网</p> * * @author not attributable * @version 1.0 */ public class PerfectMobileTypeVO extends PerfectMobileType implements IVO { //start your code here public Object parse(DataRow dr) { PerfectMobileTypeVO vo = (PerfectMobileTypeVO)dr.toObject(PerfectMobileTypeVO.class); //这里是关联了perfect_mobile表 PerfectMobileVO pm = (PerfectMobileVO)dr.toObject(PerfectMobileVO.class); vo.setPerfectMobile(pm); return vo; } private PerfectMobileVO perfectMobile; public PerfectMobileVO getPerfectMobile() { return perfectMobile; } public void setPerfectMobile(PerfectMobileVO perfectMobile) { this.perfectMobile = perfectMobile; } //finish your code here }//end of file BaseDAO的代码: package com.bang.adhibit.dao; import java.sql.*; import java.util.*; import com.apan.util.DB; import com.bang.adhibit.data.IVO; import com.bang.adhibit.util.DataRow; public class BaseDAO { //出错信息 private String errorMessage; protected void setErrorMessage(String msg) { errorMessage = msg; } public String getErrorMessage() { return errorMessage; } //获得一个序列的next值 protected long getSeq(String seqName) { long result = 0; DB db = null; try { db = new DB(); ResultSet rs = db.getStat().executeQuery("select " + seqName + ".nextval from dual"); if(rs.next()) result = rs.getLong(1); rs.close(); } catch (Exception e) { e.printStackTrace(); setErrorMessage(e.toString()); }finally{ if(db != null) db.close(); } return result; } //执行非查询语句 protected boolean executeNonQuery(String strSql,Object[] param) { DB db = null; try { db = new DB(); PreparedStatement pstmt = db.getConn().prepareStatement(strSql); if(param != null) { for(int i=0;i<param.length;i++) pstmt.setObject(i+1,param[i]); } pstmt.executeUpdate(); } catch (Exception e) { e.printStackTrace(); setErrorMessage(e.toString()); return false; }finally{ if(db != null) db.close(); } return true; } //执行查询语句 protected List executeQuery(String strSql,Object[] param,Class cls) { DB db = null; ArrayList list = new ArrayList(); try { IVO vo = (IVO)cls.newInstance(); db = new DB(); PreparedStatement pstmt = db.getConn().prepareStatement(strSql); if(param != null) { for(int i=0;i<param.length;i++) pstmt.setObject(i+1,param[i]); } ResultSet rs = pstmt.executeQuery(); while(rs.next()) { DataRow dr = DataRow.parse(rs); Object obj = vo.parse(dr); list.add(obj); } } catch (Exception e) { setErrorMessage(e.toString()); e.printStackTrace(); }finally{ if(db != null) db.close(); } return list; } //获取记数的值,比如需要统计之类的时候select count(*) from .... protected int getNumberField(String strSql,Object[] param) { DB db = null; int result = -1; try { db = new DB(); PreparedStatement pstmt = db.getConn().prepareStatement(strSql); if(param != null) { for(int i=0;i<param.length;i++) pstmt.setObject(i+1,param[i]); } ResultSet rs = pstmt.executeQuery(); while(rs.next()) { result = rs.getInt(1); } } catch (Exception e) { setErrorMessage(e.toString()); e.printStackTrace(); }finally{ if(db != null) db.close(); } return result; } } DAO类的代码: package com.bang.adhibit.dao; import com.bang.adhibit.util.*; import com.bang.adhibit.data.*; import java.sql.*; import java.util.*; /** * * <p>Title: 访问perfect_mobile_type数据访问类</p> * * <p>Description: DAO类,包含了数据库的各种操作</p> * * <p>Copyright: Copyright (c) 2006</p> * * <p>Company: 邦邦网</p> * * @author not attributable * @version 1.0 */ public class PerfectMobileTypeDAO extends BaseDAO { /** * 向数据库插入一条记录 * @param dto PerfectMobileTypeDTO 要插入的数据 * @return PerfectMobileType 返回插入的记录 */ public PerfectMobileType insert(PerfectMobileType perfectMobileType) { long seq = getSeq("perfect_mobile_type_seq"); perfectMobileType.setTypeId(seq); String strSql = "Insert into perfect_mobile_type ("; strSql += "type_id, mobile_id, type_name, width, height, sort_index, enable_flag, state"; strSql += ") values (?, ?, ?, ?, ?, ?, ?, ?)"; Object[] param = new Object[8]; param[0] = new Long(seq); param[1] = new Long(perfectMobileType.getMobileId()); param[2] = perfectMobileType.getTypeName(); param[3] = new Integer(perfectMobileType.getWidth()); param[4] = new Integer(perfectMobileType.getHeight()); param[5] = new Integer(perfectMobileType.getSortIndex()); param[6] = new Integer(perfectMobileType.getEnableFlag()); param[7] = new Integer(perfectMobileType.getState()); boolean result = executeNonQuery(strSql,param); if(!result) return null; else return perfectMobileType; } /** * 编辑一条记录 * @param dto PerfectMobileTypeDTO 要编辑的数据 * @return boolean 返回编辑是否成功,如果失败,错误信息可用getErrorMessage方法获得 */ public boolean edit(PerfectMobileType perfectMobileType) { String strSql = "update perfect_mobile_type set "; strSql += "mobile_id=?, type_name=?, width=?, height=?, sort_index=?, enable_flag=?, state=?"; strSql += " where type_id=? "; Object[] param = new Object[8]; param[0] = new Long(perfectMobileType.getMobileId()); param[1] = perfectMobileType.getTypeName(); param[2] = new Integer(perfectMobileType.getWidth()); param[3] = new Integer(perfectMobileType.getHeight()); param[4] = new Integer(perfectMobileType.getSortIndex()); param[5] = new Integer(perfectMobileType.getEnableFlag()); param[6] = new Integer(perfectMobileType.getState()); param[7] = new Long(perfectMobileType.getTypeId()); return executeNonQuery(strSql,param); } /** * 根据主键查询一条记录 * @param ... 主键的值列表 * @return PerfectMobileTypeVO 返回查询内容,如果返回null表示记录不存在或者出错。 */ public PerfectMobileTypeVO findByPrimaryKey(long typeId) { PerfectMobileTypeVO vo = null; String strSql = "select a.* from " + innerStr + " where type_id=? "; Object[] param = new Object[1]; param[0] = new Long(typeId); List list = executeQuery(strSql,param,PerfectMobileTypeVO.class); if(list != null && list.size()==1) { vo = (PerfectMobileTypeVO)list.get(0); } return vo; } /** * 根据主键删除一条记录 * @param ... 主键的值列表 * @return boolean 返回删除是否成功 */ public boolean deleteByPrimaryKey(long typeId) { String strSql = "delete from perfect_mobile_type where type_id=? "; Object[] param = new Object[1]; param[0] = new Long(typeId); return executeNonQuery(strSql,param); } /** * 查询数据 * @param strSql sql语句 * @param param 预处理参数 * @return 查询结果列表 */ public List query(String strSql,Object[] param) { return executeQuery(strSql,param,PerfectMobileTypeVO.class); } //start your code here private String innerStr = "perfect_mobile_type a inner join perfect_mobile b on a.mobile_id=b.mobile_id"; /** * 根据mobileId获取手机型号列表 * @param mobileId 品牌ID * @return */ public List getMobileTypeList(long mobileId) { String strSql = "select a.*,b.mobile_name from " + innerStr + " where a.mobile_id=? order by a.sort_index"; return query(strSql,new Object[]{new Long(mobileId)}); } /** * 设置有效标志 * @param typeId 手机型号ID * @param flag 有效标志 0-无效 1-有效 * @return */ public boolean enable(long typeId,int flag) { String strSql = "update perfect_mobile_type set enable_flag=? where type_id=?"; return this.executeNonQuery(strSql,new Object[]{new Integer(flag),new Long(typeId)}); } public List getScreenList() { String strSql = "select width,height from perfect_mobile_type group by width,height"; List list = executeQuery(strSql,null,MobileScreen.class); return list; } //finish your code here }//end of file 以上就是现在我采用的数据层代码的处理方式,但是这种方式当两个关联表中有同明字段而且都要使用的时候,就会有问题了,因为同一个Hashtable的key是唯一的,这样肯定就有一个表中的某个字段丢失了。我想请教各位在做数据层的时候,是如何处理表关联的问题的呢?有没有一种简便的方式来处理数据层的问题呢? 我还是菜鸟,不过在这个论坛上收获很多,还请各位不要见笑,请多多指教,谢谢! |
|
返回顶楼 | |
发表时间:2006-11-01
天, 这么长的代码, 有几个能够耐心看完的?
|
|
返回顶楼 | |
发表时间:2006-11-01
把接口放上来看看(要写注释)
|
|
返回顶楼 | |
发表时间:2006-11-21
和我现在公司的代码比好很多很多,(5000行的java类大家见过没有,几乎没有小于2000行的java类,同一个方法每个类里都有定义,所有的类都独立,不依赖任何类,所有业务都在action里)最起码总的思路是正确的
但感觉具体实现上有些乱,需要重构 |
|
返回顶楼 | |
发表时间:2006-11-21
这是我的个人意见:
(1)你对jdbc的封装有点像spring的jdbc模块,不过多了一个直接返回Object的功能。对于数据库的异常处理,其实可以仿照Spring的jdbc模块,抛出一个unchecked的DataAccessException (2)DataAccessException不属于BusinessException,没有必要重新包装。 |
|
返回顶楼 | |
发表时间:2006-11-28
唉,以前没有看过Spring的JDBC模块,今天看到楼上的回复,找了些资料看了一下,真的很方便,才知道自己做了这么多的无用功,人家做好的东西自己还在拼命想,浪费好多时间.以后准备把框架往Spring上转了...多谢各位!!
|
|
返回顶楼 | |