先熟悉一下javax.servlet.http.Cookie和javax.servlet.http.HttpSession。
JForum系统有一项功能是:实时显示在线的注册会员数、匿名访客数。
登录本机的JForum,并选择“自动登录”后,可以看到如下的Cookie信息:
SystemGlobals.properties中关于Cookie的配置如下:
cookie.name.data = jforumUserId
cookie.name.user = jforumUserInfo
cookie.name.autologin = jforumAutoLogin
cookie.name.userHash = jforumUserHash
在Eclipse中,使用“文件搜索”搜索“COOKIE_NAME_USER”,只有一条记录。可见,在2.1.8版本中根本没有用到jforumUserInfo。
jforumUserId的值为jforum_users表中user_id列的值,匿名用户的user_id为1。登录时如果选择了“自动登录”,则jforumAutoLogin的值为1,jforumUserHash的值为一个散列值,否则,客户端不会有jforumAutoLogin和jforumUserHash。
jforumUserHash的生成规则如下(即systemHash):
// Generate the user-specific hash
String systemHash = MD5.crypt(SystemGlobals.getValue(ConfigKeys.USER_HASH_SEQUENCE) + user.getId());
String userHash = MD5.crypt(System.currentTimeMillis() + systemHash);
// Persist the user hash
UserDAO dao = DataAccessDriver.getInstance().newUserDAO();
dao.saveUserAuthHash(user.getId(), userHash);
systemHash = MD5.crypt(userHash);
其中,SystemGlobals.getValue()是读取配置值,默认值为:
user.hash.sequence = 04904SDFfhfh449911-**%$nvMDFHDhskda6546546as4df4ads6f54ads654
在正式环境下使用JForum时,应该修改该值。
net.jforum.entities.UserSession用于抽象用户会话信息。很奇怪它的构造函数:
public UserSession() {}
public UserSession(UserSession us)
{
if (us.getStartTime() != null) {
this.startTime = new Date(us.getStartTime().getTime());
}
if (us.getLastVisit() != null) {
this.lastVisit = new Date(us.getLastVisit().getTime());
}
this.sessionTime = us.getSessionTime();
this.userId = us.getUserId();
this.sessionId = us.getSessionId();
this.username = us.getUsername();
this.autoLogin = us.getAutoLogin();
this.lang = us.getLang();
this.privateMessages = us.getPrivateMessages();
this.imageCaptcha = us.imageCaptcha;
this.ip = us.getIp();
}
用一个UserSession对象来构造另一个UserSession对象?第6、10行,为什么不直接this.startTime = us.getStartTime();而多此一举呢?我觉得这样做的目的是想实现“clone”效果,利用一个UserSession对象,克隆另一个UserSession对象。
关于net.jforum.SessionFacade类
从类名中Facade单词中可以看出,作者想让SessionFacade担任UserSession的门面,即门面模式。门面模式是对象的结构模式。外部与一个子系统的通信必须通过一个统一的门面对象进行,这就是门面模式。[1] 在门面模式中,通常只需要一个门面类,并且此门面类只有一个实例,换言之它是一个单例类。[2] 具体到JForum而言,“子系统”包括:UserSession类、CacheEngine实现类以及和Session DAO方法相关的类。SessionFacade类中除了setCacheEngine()方法外,都是静态方法,也算是单例类了。这些和教科书中所说的还是比较一致的。
门面不是不能越过的。JForum中也有一小部分代码直接使用的UserSession us = new UserSession(); us.方法调用,即越过了SessionFacade门面。
让我们再读一下《Java与模式》第32章 门面(Facade)模式和《设计模式》第4.5节 FACADE(外观)——对象结构模式吧。
[1] 引自《Java与模式》P561
[2] 引自《Java与模式》P563