此文为转载:http://www.diybl.com/course/1_web/webjs/2007113/82989.html 由于BBSCS8是由数据库设计-bean/hbm.xml-DAO-Service-Web(作者laoer回答)这样的创建过程,因此分析这个系统最好是先查看数据库设计(见http://bbs.laoer.com/main-read-15-ff80808113baa8140113d201333e5274.html下载研究),而我的分析是由Service层开始引出讨论的,所以你需对论坛的常用功能有所体会,知道什么是投票贴,怎么样去用,还要有论坛后台管理使用过等等.如果不知道的话,请先在www.laoer.com处或在自己电脑上本地测试以便先对其功能进行体会,请注意!!! com.laoer.bbscs.service层下有众多的接口: AgreeAgainstService,它有三个方法: AgreeAgainst saveAgreeAgainst(AgreeAgainst agreeAgainst) throws BbscsException; AgreeAgainst findAgreeAgainstByUidPidBid(String userID,String postID,long bid); void removeOutTime(long time)throws BbscsException; AgreeAgainstImp为其实现: 首先定义了一个logger,设置好agreeAgainstDAO;getAgreeAgainstDAO及setAgreeAgainstDAO; public AgreeAgainst saveAgreeAgainst(AgreeAgainst agreeAgainst) throws BbscsException{ try{ return this.getAgreeAgainstDAO().saveAgreeAgainst(agreeAgainst); (注:此处为合写,也可写成: agreeAgainst=this.getAgreeAgainstDAO().saveAgreeAgainst(agreeAgainst); return agreeAgainst;我这里啰嗦了一下,以后源代码中会用到,别问我为什么~~~) }catch(Exception ex) { logger.error(ex); throw new BbscsException(ex); } } 注意的是getAgreeAgainstDAO返回的是AgreeAgainstDAO来自于com.laoer.bbscs.dao包中的interface; 它有三个接口方法: public AgreeAgainst saveAgreeAgainst(AgreeAgainst agreeAgainst); public AgreeAgainst findAgreeAgainstByUidPidBid(String userID,String postID,long bid); public void removeOutTime(long time); 而实现上注入到service方法中的是其实现类: com.laoer.bbscs.dao.hibernate.AgreeAgainstHibernateDAO,其注入了: 一个sessinFacotry唯一,用于获得可操作的session,让我们看看其实现: 它将两个HQL语句都重构成private static final String 了.一个是LOAD_BY_UID_PID_BID,一个是ROMOVE_OUTTIME,注意其extends HibernateDAOSupport抽象类(得到了org.springframework.orm.hibernate3.support.HibernateDAOSupport的支持哦~)这样我们就可以不用get和set这个sessionFacotry了,另外可能使用this.getHibernateTemplate()来进行实际操作了. saveorupdate(agreeAgainst);对于查找: 先构造一个Object[] o={postID,userID,new Long(bid)}; List list=this.getHibernateTemplate().find(LOAD_BY_UID_PID_BID,o); if(l==null||l.isEmpty()){ return null; } else{ return (AgreeAgaist) l.get(0); } } 最后removeOutTime(final long time) { getHibernateTemplate().execute(new HibernateCallback(){ public Object doInHibernate(Session session) throws HibernateException, SQLException{ Query query=s.createQuery(REMOVE_OUTTIME); query.setLong(0,time); query.executeUpdate(); return null; } }); }; } 我们看看hbm.xml文件和bean文件,先是bean(AgreeAgainst.java) 它有如下属性: private String id; private String userID; private String postID; private long boardID; private int voteType; private long createTime; 及其set/get方法的一个构造. 看下AgreeAgainst.hbm.xml文件: id为主键uuid算法,还要其长度的定义等等!其它不是...... 看下数据库表!!! Null Default ID varchar(40) NO UserID varchar(40) No PostID varchar(40)No BoardID bigint(20)No 0 VoteType tinyint(1)Yes 0 CreateTime bigint(20)No 0 我们来看下实现: 在帖子的支持和反对处选择! Hibernate: insert into bbscs_agreeagainst (UserID, PostID, BoardID, VoteType, CreateTime, ID) values (?, ?, ?, ?, ?, ?) Hibernate: select agreeagain0_.ID as ID24_, agreeagain0_.UserID as UserID24_, agreeagain0_.PostID as PostID24_, agreeagain0_.BoardID as BoardID24_, agreeagain0_.VoteType as VoteType24_, agreeagain0_.CreateTime as CreateTime24_ from bbscs_agreeagainst agreeagain0_ where agreeagain0_.PostID=? and agreeagain0_.UserID=? and agreeagain0_.BoardID=? 数据库中的数据: ID:402881 e513bd c85501 13be01 e70d00 1f(32位) UserID:4028818208ed006b0108ed020bd50001 PostID:402881e513bdc8550113bdefb43c0014 BoardID:2(第2个建的) VoteType:1(反对)0(支持) CreateTime:1184303802125 对比一下,就OK了 BoardAuthUserService(版块授权的用户) 有public BoardAuthUser saveBoardAuthUser(BoardAuthUser boardAuthUser) throws BbscsException; punlic BoardAuthUser findBoardAuthUserById(String id); public BoardAuthUser findBoardAuthUserByBidUid(long bid,String uid); public BoardAuthUser findBoardAuthUserByBidUserName(long bid,String userName); public List findBoardAuthUserByBid(long bid); public void removeBoardAuthUser(BoardAuthUser boardAuthUser); public void removeBoardAuthuserByBidUid(long bid,String uid) throws BbscsException; public void removeBoardAuthUserByBidUserName(long bid,String userName) throws BbscsExeption; 同样,imp里BoardAuthUserServiceImp中,注入DAO 由DAO来完成对应方法的实际工作.注意:有Exception方法的写法,例如: public void removeBoardAuthUserByBidUserName(long bid, String userName) throws BbscsException { try { this.getBoardAuthUserDAO().removeBoardAuthUserByBidUserName(bid, userName); } catch (Exception ex) { logger.error(ex); throw new BbscsException(ex); } } 来到DAO接口层,没有一个Exception方法哦!!!同样实现它的HibernateDAO也没有Ecxeption,可见,Serivce层有Exception.而DAO层没有Exception(一般情况下),除了没有Exception外,接口层与Serivce接口层好象.说说Exception:这里用到的只不过是一个BbscsException而已,在专门的com.laoer.bbscs.exception包中有这个类:原来它也继承了Exception而已,有三个重载的方法: public BbscsException(String message) { super(message); } public BbscsException(String message, Throwable cause) { super(message, cause); } public BbscsException(Throwable cause) { super(cause); } 自定义异常类的主要作用是区分异常发生的位置,当用户遇到异常时,根据异常名就可以知道哪里有异常,根据异常提示信息进行修改。 看其hibernate实现: 整个源码重构过似的,上面为HQL语句字串常量定义: private static final String LOAD_BY_BID_UID = "from BoardAuthUser where boardID = ? and userID = ?"; private static final String LOADS_BY_BID = "from BoardAuthUser where boardID = ? order by createTime asc"; 看看方法吧: public BoardAuthUser findBoardAuthUserById(String id) { return (BoardAuthUser)this.getHibernateTemplate().get(BoardAuthUser.class, id); } 这个ID明显是对象标识! public BoardAuthUser findBoardAuthUserByBidUserName(long bid, String userName) { Object[] o = {new Long(bid), userName}; List l = this.getHibernateTemplate().find(LOAD_BY_BID_USERNAME, o); if (l == null || l.isEmpty()) { return null; } else { return (BoardAuthUser) l.get(0); } } public List findBoardAuthUsersByBid(long bid) { return this.getHibernateTemplate().find(LOADS_BY_BID, new Long(bid)); } 需要注意的是Object数组中的元素必为对象;我们来看看是怎么删除操作的: public void removeBoardAuthUser(BoardAuthUser boardAuthUser) { this.getHibernateTemplate().delete(boardAuthUser); } 而不是一个BoradAuthUser对象,是通过以下代码实现: public void removeBoardAuthUserByBidUid(final long bid, final String uid) { getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session s) throws HibernateException, SQLException { Query query = s.createQuery(REMOVE_BY_BID_UID); query.setLong(1, bid); query.setString(0, uid); query.executeUpdate(); return null; } }); } BoardPermissionService是版区(版块)的权限对应服务;其BEAN BoardPermission如下: private String id; private long boardID; private int groupID; private List permissions = new ArrayList(); //特殊的哦~~~ 再看下其hbm.xml文件: 注意到:permissions对应于表的Permssions,而其type为com.laoer.bbscs.ext.hibernate.SplitList; 让我们看看SplitList这个类:(它在ext.hibernate包中): [转自网络: 使用Hibernate自定义UserType遇到的一个问题 Hibernate自定义UserType可以使设计更为优雅,逻辑更为清晰。第一次使用遇到了问题。Rule表中有一个字段methods,类型为VARCHAR(30),not null, 允许有多个method,中间用逗号分开,之所以这么设计是不想为此增加一个关联表。为methods实现了一个自定义UserType叫MethodsList,该类对用户隐藏了实现细节,使用户不用处理method的连接和拆分,而使用List来操作就行了,非常直观。在保存Rule实体的时候,Hibernate报methods字段不允许为空,说明methods在持久化的时候还是null,DEBUG发现在调用session.saveOrUpdate()方法的时候methods不为空,但在调用MethodsList的nullSafeSet(PreparedStatement st, Object value, int index)时显示value的值为null,Google了很久仍然没有找到原因 后来发现只要把methods字段的not null属性设为false(即允许为空)问题就不复存在了,很是奇怪... 据此猜测,Hibernate在应用自定义UserType(即MethodsList)之前进行字段是否为空之类的检查,而这时methods字段还是null,所以出现以上错误,把该字段改为允许为空之后自然就没有问题了。个人愚见,仅供参考,有空研究一下Hibernate源码一探究 robbin: 1、UserType不是用来做主键的(虽然也可以,但是那样和复合主键没有区别了,并且复合主键是非常不推荐的做法) 2、UserType比Component更加灵活,适用性更强,封装的更透明。 ] 其中有以下方法:assembledeepCopy(重要)disassmbleequals(重要)hashCodeisMutable ullSafeGet eplace eturnedClasssqlTypes等方法需要实现(不一定)! rs--->Object public Object nullSafeGet(ResultSet resultSet, String[] stringArray, Object object) throws HibernateException, SQLException { String value = (String) Hibernate.STRING.nullSafeGet(resultSet, stringArray[0]); if (value != null) { return parse(value); } else { return new ArrayList(); } } 用了parse方法: private List parse(String value) { String[] strs = StringUtils.split(value, SPLITTER); List set = new ArrayList(); for (int i = 0; i < strs.length; i++) { if (!StringUtils.isBlank(strs[i])) { set.add(Long.valueOf(strs[i])); // System.out.println(strs[i]); // set.add(new Long(Long.parseLong(strs[i]))); } } return set; } object--->rs public void nullSafeSet(PreparedStatement preparedStatement, Object object, int _int) throws HibernateException, SQLException { if (object != null) { String str = assemble((List) object); Hibernate.STRING.nullSafeSet(preparedStatement, str, _int); } else { Hibernate.STRING.nullSafeSet(preparedStatement, "", _int); } } 用了assemble方法: private String assemble(List set) { StringBuffer sb = new StringBuffer(); Iterator it = set.iterator(); while (it.hasNext()) { sb.append(it.next()); sb.append(SPLITTER); } String fs = sb.toString(); if (fs != null && fs.length() > 0 && fs.endsWith(SPLITTER)) { fs = fs.substring(0, fs.length() - 1); } return fs; } 附参考资料:http://blog.csdn.net/ckangtai/archive/2007/05/23/1622396.aspx 好,看完这个后,我们进入到服务内容: public BoardPermission saveBoardPermission(BoardPermission bp) throws BbscsException; public BoardPermission updateBoardPermission(BoardPermission bp) throws BbscsException; public BoardPermission findBoardPermissionByID(String id); public BoardPermission findBoardPermissionByBidGid(long bid, int gid); public List findBoardPermissionsByBid(long bid); public List findBoardPermissionsByGid(int gid); public void removeBoardPermissionsByBid(long bid) throws BbscsException; public void removeBoardPermissionsByGid(int gid) throws BbscsException; 实际是由注入的boardPermissionDAO其实现类完成的. 注意这里引入了 private Cache userPermissionCache;这个缓存类! 我们从applicationContext.xml看看是什么东东: ${cacheup.config} 哦,原来是另外一个服务,${cacheup.config}指的是cacheup.config=oscache_up.properties; 在classes下有许多配置文件,是用不同的配置文件是为了方便集群,以区分是不同的缓存。 我们从com.laoer.bbscs.serivce.Cache接口看起,它提供了如下方法: public void add(Object key,Object value); public Object get(Object key); public void remove(Object key); public void removeAll(); 再看imp: 由于spring中的bean带construtctor-arg: 将调用构造方法: public OsCacheImp(String profile) { Properties properties = new Properties(); ClassPathResource classPathResource = new ClassPathResource(profile); //这个类标识从classpath获得的资源 try { logger.info("Init Cache..."); properties.load(classPathResource.getInputStream());//使用Properties的load(InputStream inStream) 来读取配置文件的时候 admin = new GeneralCacheAdministrator(properties); } catch (Exception ex) { logger.error(ex); admin = new GeneralCacheAdministrator(); } } 注意,这个admin对象来自OSCache包,用于管理Cache内容吧.另外,我们看看其对Cache的实现: public void add(Object key, Object value) { logger.debug("Add into cache [Key:" + key + "]"); this.admin.putInCache(String.valueOf(key), value); } public Object get(Object key) { try { logger.debug("Get from cache [Key:" + key + "]"); return this.admin.getFromCache(String.valueOf(key)); } catch (NeedsRefreshException ex) { logger.debug("Object not in cache, return null"); this.admin.cancelUpdate(String.valueOf(key)); return null; } } public void remove(Object key) { logger.debug("Remove from cache [Key:" + key + "]"); this.admin.flushEntry(key.toString()); } public void removeAll() { logger.debug("Remove all"); this.admin.flushAll(); } 这样就可以对缓存内容进行控制操作了(就用这几个方法)!让我们回到BoardPermissionSerivceImp类中: 注入了DAO和Cache(userPermissionCache)后,进行方法实现时,主要还是DAO去做,不过在saveBoardPermission和updateBoardPermission,还有各种remove方法中还用了this.clearPermissionCache();(除了find),让我们来看看它的代码吧: private void clearPermissionCache() { if (Constant.USE_PERMISSION_CACHE) { //public static final boolean USE_PERMISSION_CACHE = true; this.getUserPermissionCache().removeAll();//调用Cache中的方法哦!removeALL看上面this.admin.flushAll();! } } 555555,这个服务类也了Cache服务(与别的服务结合了),下面是DAO实现: private static final String LOAD_BY_BID_GID ="from BoardPermission where boardID = ? and groupID = ?"; private static final String LOADS_BY_BID = "from BoardPermission where boardID = ?"; private static final String LOADS_BY_GID = "from BoardPermission where groupID = ?"; private static final String REMOVE_BY_BID = "delete from BoardPermission where boardID = ?"; private static final String REMOVE_BY_GID = "delete from BoardPermission where groupID = ?"; 我们看update: public BoardPermission updateBoardPermission(BoardPermission bp) { //System.out.println("update bp"); this.getHibernateTemplate().update(bp); return bp; } 再看: /** * 根据GroupID删除BoardPermission对象 * * @param gid int * @todo Implement this com.laoer.bbscs.dao.BoardPermissionDAO method */ public void removeBoardPermissionsByGid(final int gid) { getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session s) throws HibernateException, SQLException { Query query = s.createQuery(REMOVE_BY_GID); query.setLong(0, gid); query.executeUpdate(); return null; } }); } 接下来,是BoardSaveService: 先看bean吧,它实现了implements Serializable...,加入private static final long serialVersionUID = 5390014211916049604L;它有三个属性: private String id; private String userID; private long boardID; [ Java的JavaBeans. Bean的状态信息通常是在设计时配置的。Bean的状态信息必须被存起来,以便当程序运行时能恢复这些状态信息。这也需要serializaiton机制。 总之如果在网络的环境下做类传输,应该还是implements Serializable。 ] 再看其hbm.xml: 从这样便知是用于收藏版区的对象模型啊!那接下来看其接口中的方法: public BoardSave saveBoardSave(BoardSave boardSave) throws BbscsException; public BoardSave findBoardSaveById(String id); public BoardSave findBoardSaveByUidBid(String userId, long bid); public List findBoardSavesByUid(String userId); public List findBoardSaveBidsByUid(String userId);//找Bid的List public void removeBoardSave(BoardSave boardSave) throws BbscsException; public void removeBoardSaveByUidBid(String userId, long bid) throws BbscsException; public void removeBoardSaveByBid(long bid) throws BbscsException; public void removeBoardSaveByBidsUid(String userId, List ids) throws BbscsException; 对于imp调用dao-->daoimp我们直接进入dao的imp中: 其中的常量定义如下: private static final String LOAD_BY_UID_BID = "from BoardSave where userID = ? and boardID = ?"; private static final String LOADS_BY_USERID = "from BoardSave where userID = ?"; private static final String LOADS_BOARDID_BY_USERID = "select boardID from BoardSave where userID = ?";//很特别哦!(其实也没什么,相对而已) private static final String REMOVE_BY_UID_BID = "delete from BoardSave where userID = ? and boardID = ?"; private static final String REMOVE_BY_BID = "delete from BoardSave where boardID = ?"; private static final String REMOVE_IN_IDS_BY_UID = "delete from BoardSave where userID = :userID and boardID in (:ids)"; 我们来看方法实现吧. public BoardSave saveBoardSave(BoardSave boardSave) { this.getHibernateTemplate().saveOrUpdate(boardSave); return boardSave; } 可用于保存,也可以用于更新! public List findBoardSaveBidsByUid(String userId) { return this.getHibernateTemplate().find(LOADS_BOARDID_BY_USERID, userId); //一个参数 public void removeBoardSaveByBidsUid(final String userId, final List ids) { getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session s) throws HibernateException, SQLException { Query query = s.createQuery(REMOVE_IN_IDS_BY_UID); query.setString("userID", userId); query.setParameterList("ids", ids); query.executeUpdate(); return null; } }); } OK! 接下来,是BoardService,先看其相关的Bean!它也实现了可序列化操作...它的属性特别多.. 很关键哦! private Long id;//主键 private long parentID;//父级版区ID private List parentIDs;//所有父级版区ID列表 private List childIDs; private String boardName;//版区名称 private String explains;(说明) private String bulletin;(公告) private String boardPic;//图片 private int useStat;(使用状态) private int orders;//序 private int needPasswd;//是否需要密码访问 private String passwd;//访问密码 private int level;---->数据库中的BoardLevel//级别 private int boardType;(类型1,2,3)//版区类型 private int allowHTML;//HTML是否支持 private int allowUBB;//UBB... private int auditPost; (帖子是否需要审核) private int auditAttach;//附件是否需要审核 private int addUserPostNum;//是否增加用户发贴数 private int isHidden; private int isAuth;//是否需要论证用户才能访问 private long mainPostNum;//主贴数 private long postNum;//帖子数量 private Map boardMaster=new HashMap(); private Set boardTag=new HashSet(); 我们看看Board.hbm.xml,错了,我们应该看看applicationCotext.xml中的内容是不是这个,经查看: com/laoer/bbscs/bean/Board-${datasource.type}.hbm.xml ,我用mysql当然是Board-mysql.hbm.xml,其内容主要如下: //long类型的identity! //parentIDs有用了userType //text类型 //一个开关的功能 //论坛排序 //开关 //不懂??? //应该是一个开关吧 //关键点,boardMaster和boardTag均为one-to-many类型!看完这些后,我们就知道这个bean是用于版区操作了,让我们看看方法:(先看接口BoardService) public Board saveBoard(Board board) throws BbscsException;//保存或更新Board对象 public Board createBoard(Board board) throws BbscsException; public Board updateBoard(Board board, long oldParentID) throws BbscsException; public Board getBoardByID(long id); public List findBoardsByParentID(long pid, int useStat, int hidden, int orderType); public List findBoardsAllTree(long pid, List topList, int useStat, int hidden, int orderType); public int getNextOrder(long pid); public int getPostSumNum(int mainorall, int useStat, int hidden); public void removeBoard(Board board) throws BbscsException; public Map[] getBoardPermission(long bid, int groupID); public Map[] getBoardMasterPermission(int roleID); public boolean isBoardMaster(Board board, String userName); public List findBoardsInIDs(List ids); public void removeBoardTag(Board board, String tagID) throws BbscsException; public List getBoardIDs(List boards); public void saveBoardsPostNumCount() throws BbscsException; 这里方法有16个左右,注意我们进行除了查询后的其它CURD操作都可能会产生异常.对于具体方法我们需要去了解其实现才能理清其作用.看下服务实现层:(注BoardServiceCacheImp为其实现类,可能是加入了许多缓存的原因吧): 首先仍是logger(这里发现了原来其实在service层和dao层只有这里需要logger,其它地方都没,对于异常也只有service接口和实现层有BbscsException这个异常处理,而对于DAO层的异常则已经由HibernateTemplate完全抛出了,如: public void saveOrUpdate(final Object entity) throws DataAccessException { execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { checkWriteOperationAllowed(session); session.saveOrUpdate(entity); return null; } } , true); } )
对天乙社区bbscs8实现的详细分析一
最新推荐文章于 2024-07-25 19:26:22 发布