📄 详细分析一.txt
字号:
由于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,其注入了:
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
一个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文件:
<hibernate-mapping package="com.laoer.bbscs.bean">
<class name="AgreeAgainst" table="bbscs_agreeagainst">
<id name="id" column="ID" type="string" unsaved-value="null">
<generator class="uuid"/>
</id>
<property column="UserID" length="40" name="userID" not-null="true" type="string"/>
<property column="PostID" length="60" name="postID" not-null="true" type="string"/>
<property column="BoardID" length="13" name="boardID" not-null="true" type="long"/>
<property column="VoteType" length="1" name="voteType" type="int"/>
<property column="CreateTime" name="createTime" not-null="true" type="long"/>
</class>
</hibernate-mapping>
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文件:
<hibernate-mapping package="com.laoer.bbscs.bean">
<class name="BoardPermission" table="bbscs_boardpermission">
<id name="id" column="ID" type="string" unsaved-value="null">
<generator class="uuid"/>
</id>
<property column="BoardID" length="20" name="boardID" not-null="true" type="long"/>
<property column="GroupID" length="11" name="groupID" not-null="true" type="int"/>
<property column="Permissions" name="permissions" type="com.laoer.bbscs.ext.hibernate.SplitList"/>
</class>
</hibernate-mapping>
注意到: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更加灵活,适用性更强,封装的更透明。
]
其中有以下方法:assemble\deepCopy(重要)\disassmble\equals(重要)\hashCode\isMutable\nullSafeGet\replace\returnedClass\sqlTypes等方法需要实现(不一定)!
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看看是什么东东:
<bean id="userPermissionCache"
class="com.laoer.bbscs.service.imp.OsCacheImp">
<constructor-arg>
<value>${cacheup.config}</value>
</constructor-arg>
</bean>
哦,原来是另外一个服务,${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 {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -