对天乙社区bbscs8实现的详细分析一

来源:互联网 发布:javascript实例教程 编辑:程序博客网 时间:2024/04/29 05:44
此文为转载: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 DefaultID varchar(40) NO UserID varchar(40) NoPostID varchar(40)NoBoardID bigint(20)No 0VoteType tinyint(1)Yes 0CreateTime 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:4028818208ed006b0108ed020bd50001PostID:402881e513bdc8550113bdefb43c0014BoardID: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--->Objectpublic 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--->rspublic 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的Listpublic 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;//父级版区IDprivate 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);    }) 
原创粉丝点击