前言
在博客摘要里提到了,所有的基类的作用都是为了代码复用。java web程序,也不例外。
而java web程序,里面的基类代码复用,主要是复用什么呢?
答:主要是复用各种servlet对象。
除此之外,当前也会有一些共同的通用的业务方法需要复用,比如,web程序里,浏览器发出请求(数据),服务器要把所请求的数据发送到请求端的浏览器,所以可以复用这个响应数据的方法。
基类
package net.jforum;
import java.io.IOException;
import net.jforum.context.RequestContext;
import net.jforum.context.ResponseContext;
import net.jforum.exceptions.ForumException;
import net.jforum.exceptions.TemplateNotFoundException;
import net.jforum.repository.Tpl;
import net.jforum.util.preferences.ConfigKeys;
import net.jforum.util.preferences.SystemGlobals;
import net.jforum.util.preferences.TemplateKeys;
import freemarker.template.SimpleHash;
import freemarker.template.Template;
/**
* Action类的基类,所有的自定义Action类都要继承该基类<p>
*
* <code>Command</code> Pattern implementation.
* All View Helper classes, which are intead to configure and processs
* presentation actions must extend this class.
*
* @author Rafael Steil
* @version $Id: Command.java,v 1.27 2007/07/28 14:17:11 rafaelsteil Exp $
*/
public abstract class Command
{
private static Class[] NO_ARGS_CLASS = new Class[0];
private static Object[] NO_ARGS_OBJECT = new Object[0];
private boolean ignoreAction;
protected String templateName;
protected RequestContext request;
protected ResponseContext response;
protected SimpleHash context;
protected void setTemplateName(String templateName)
{
this.templateName = Tpl.name(templateName);
}
protected void ignoreAction()
{
this.ignoreAction = true;
}
/**
* Base method for listings.
* May be used as general listing or as helper
* to another specialized type of listing. Subclasses
* must implement it to the cases where some invalid
* action is called ( which means that the exception will
* be caught and the general listing will be used )
*/
public abstract void list() ;
/**
* Process and manipulate a requisition.
* @return <code>Template</code> reference
* @param request WebContextRequest
* @param response WebContextResponse
*/
public Template process(RequestContext request, ResponseContext response, SimpleHash context)
{
this.request = request;
this.response = response;
this.context = context;
String action = this.request.getAction(); //获取请求url中的方法名(例如,ForumAction.list()方法)
if (!this.ignoreAction) {
try {
this.getClass().getMethod(action, NO_ARGS_CLASS).invoke(this, NO_ARGS_OBJECT);
}
catch (NoSuchMethodException e) {
this.list();
}
catch (Exception e)
{
throw new ForumException(e);
}
}
if (JForumExecutionContext.getRedirectTo() != null) {
this.setTemplateName(TemplateKeys.EMPTY);
}
else if (request.getAttribute("template") != null) {
this.setTemplateName((String)request.getAttribute("template"));
}
if (JForumExecutionContext.isCustomContent()) {
return null;
}
if (this.templateName == null) {
throw new TemplateNotFoundException("Template for action " + action + " is not defined");
}
// try {
// return JForumExecutionContext.templateConfig().getTemplate(
// new StringBuffer(SystemGlobals.getValue(ConfigKeys.TEMPLATE_DIR)).
// append('/').append(this.templateName).toString());
// }
try {
String sb = new StringBuffer(SystemGlobals.getValue(ConfigKeys.TEMPLATE_DIR)).append('/').append(this.templateName).toString();
return JForumExecutionContext.templateConfig().getTemplate(sb);
}
catch (IOException e) {
throw new ForumException( e);
}
}
}
总结:不知道为什么很多地方要提到命令模式,jforum里面的这个基类的原始注释也是这么介绍的,说使用了命令模式啊什么的。
其实,本质上,就是自定义Action类与基类的关系。
子类
/**
* 论坛Action
*/
package net.jforum.view.forum;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.jforum.Command;
import net.jforum.JForumExecutionContext;
import net.jforum.SessionFacade;
import net.jforum.dao.DataAccessDriver;
import net.jforum.dao.ForumDAO;
import net.jforum.dao.ModerationDAO;
import net.jforum.entities.Forum;
import net.jforum.entities.MostUsersEverOnline;
import net.jforum.entities.UserSession;
import net.jforum.repository.ForumRepository;
import net.jforum.repository.SecurityRepository;
import net.jforum.security.SecurityConstants;
import net.jforum.util.I18n;
import net.jforum.util.preferences.ConfigKeys;
import net.jforum.util.preferences.SystemGlobals;
import net.jforum.util.preferences.TemplateKeys;
import net.jforum.view.admin.ModerationAction;
import net.jforum.view.forum.common.ForumCommon;
import net.jforum.view.forum.common.PostCommon;
import net.jforum.view.forum.common.TopicsCommon;
import net.jforum.view.forum.common.ViewCommon;
/**
* 版块Action(例如,小说版)<p>
* --------------------------------<p>
* 如果一个请求url(例如,document.location = "forums/list.page";)中的模块是forums,那么就由该类来处理!<p>
*
* 注:一个请求url,要注意两点,<br>
* 1.是哪个模块,即由哪个XXXAction类来处理;<br>
* 2.是哪个方法,即由该XXXAction类的这个方法来处理
* @author Rafael Steil
* @version $Id: ForumAction.java,v 1.76 2007/09/03 12:24:32 rafaelsteil Exp $
*/
public class ForumAction extends Command
{
/**
* 进入版块页面(即论坛首页):列出所有的版块
* List all the forums (first page of forum index)?
*/
public void list()
{
this.setTemplateName(TemplateKeys.FORUMS_LIST); //"forums.list"
this.context.put("allCategories", ForumCommon.getAllCategoriesAndForums(true));
this.context.put("topicsPerPage", new Integer(SystemGlobals.getIntValue(ConfigKeys.TOPICS_PER_PAGE)));
this.context.put("rssEnabled", SystemGlobals.getBoolValue(ConfigKeys.RSS_ENABLED));
this.context.put("totalMessages", new Integer(ForumRepository.getTotalMessages()));
this.context.put("totalRegisteredUsers", ForumRepository .totalUsers());
this.context.put("lastUser", ForumRepository.lastRegisteredUser());
SimpleDateFormat df = new SimpleDateFormat(SystemGlobals.getValue(ConfigKeys.DATE_TIME_FORMAT));
GregorianCalendar gc = new GregorianCalendar();
this.context.put("now", df.format(gc.getTime()));
this.context.put("lastVisit", df.format(SessionFacade.getUserSession().getLastVisit()));
this.context.put("forumRepository", new ForumRepository());
// Online Users
this.context.put("totalOnlineUsers", new Integer(SessionFacade.size()));
int aid = SystemGlobals.getIntValue(ConfigKeys.ANONYMOUS_USER_ID);
List onlineUsersList = SessionFacade.getLoggedSessions();
// Check for an optional language parameter
UserSession currentUser = SessionFacade.getUserSession();
if (currentUser.getUserId() == aid) {
String lang = this.request.getParameter("lang");
if (lang != null && I18n.languageExists(lang)) {
currentUser.setLang(lang);
}
}
// If there are only guest users, then just register
// a single one. In any other situation, we do not
// show the "guest" username
if (onlineUsersList.size() == 0) {
UserSession us = new UserSession();
us.setUserId(aid);
us.setUsername(I18n.getMessage("Guest"));
onlineUsersList.add(us);
}
int registeredSize = SessionFacade.registeredSize();
int anonymousSize = SessionFacade.anonymousSize();
int totalOnlineUsers = registeredSize + anonymousSize;
this.context.put("userSessions", onlineUsersList);
this.context.put("totalOnlineUsers", new Integer(totalOnlineUsers));
this.context.put("totalRegisteredOnlineUsers", new Integer(registeredSize));
this.context.put("totalAnonymousUsers", new Integer(anonymousSize));
// Most users ever online
MostUsersEverOnline mostUsersEverOnline = ForumRepository.getMostUsersEverOnline();
if (totalOnlineUsers > mostUsersEverOnline.getTotal()) {
mostUsersEverOnline.setTotal(totalOnlineUsers);
mostUsersEverOnline.setTimeInMillis(System.currentTimeMillis());
ForumRepository.updateMostUsersEverOnline(mostUsersEverOnline);
}
this.context.put("mostUsersEverOnline", mostUsersEverOnline);
}
public void moderation()
{
this.context.put("openModeration", true);
this.show();
}
/**
* 获取子版块的所有帖子<p>
* Display all topics in a forum
*/
public void show()
{
int forumId = this.request.getIntParameter("forum_id");
ForumDAO fm = DataAccessDriver.getInstance().newForumDAO();
// The user can access this forum?
Forum forum = ForumRepository.getForum(forumId);
if (forum == null || !ForumRepository.isCategoryAccessible(forum.getCategoryId())) {
new ModerationHelper().denied(I18n.getMessage("ForumListing.denied"));
return;
}
int start = ViewCommon.getStartPage();
List tmpTopics = TopicsCommon.topicsByForum(forumId, start);
this.setTemplateName(TemplateKeys.FORUMS_SHOW);
// Moderation
UserSession userSession = SessionFacade.getUserSession();
boolean isLogged = SessionFacade.isLogged();
boolean isModerator = userSession.isModerator(forumId);
boolean canApproveMessages = (isLogged && isModerator
&& SecurityRepository.canAccess(SecurityConstants.PERM_MODERATION_APPROVE_MESSAGES));
Map topicsToApprove = new HashMap();
if (canApproveMessages) {
ModerationDAO mdao = DataAccessDriver.getInstance().newModerationDAO();
topicsToApprove = mdao.topicsByForum(forumId);
this.context.put("postFormatter", new PostCommon());
}
this.context.put("topicsToApprove", topicsToApprove);
this.context.put("attachmentsEnabled", SecurityRepository.canAccess(SecurityConstants.PERM_ATTACHMENTS_ENABLED,
Integer.toString(forumId))
|| SecurityRepository.canAccess(SecurityConstants.PERM_ATTACHMENTS_DOWNLOAD));
this.context.put("topics", TopicsCommon.prepareTopics(tmpTopics));
this.context.put("allCategories", ForumCommon.getAllCategoriesAndForums(false));
this.context.put("forum", forum);
this.context.put("rssEnabled", SystemGlobals.getBoolValue(ConfigKeys.RSS_ENABLED));
this.context.put("pageTitle", forum.getName());
this.context.put("canApproveMessages", canApproveMessages);
this.context.put("replyOnly", !SecurityRepository.canAccess(SecurityConstants.PERM_REPLY_ONLY, Integer
.toString(forum.getId())));
this.context.put("readonly", !SecurityRepository.canAccess(SecurityConstants.PERM_READ_ONLY_FORUMS, Integer
.toString(forumId)));
this.context.put("watching", fm.isUserSubscribed(forumId, userSession.getUserId()));
// Pagination
int topicsPerPage = SystemGlobals.getIntValue(ConfigKeys.TOPICS_PER_PAGE);
int postsPerPage = SystemGlobals.getIntValue(ConfigKeys.POSTS_PER_PAGE);
int totalTopics = forum.getTotalTopics();
ViewCommon.contextToPagination(start, totalTopics, topicsPerPage);
this.context.put("postsPerPage", new Integer(postsPerPage));
TopicsCommon.topicListingBase();
this.context.put("moderator", isLogged && isModerator);
}
// Make an URL to some action
private String makeRedirect(String action)
{
String path = this.request.getContextPath() + "/forums/" + action + "/";
String thisPage = this.request.getParameter("start");
if (thisPage != null && !thisPage.equals("0")) {
path += thisPage + "/";
}
String forumId = this.request.getParameter("forum_id");
if (forumId == null) {
forumId = this.request.getParameter("persistData");
}
path += forumId + SystemGlobals.getValue(ConfigKeys.SERVLET_EXTENSION);
return path;
}
// Mark all topics as read
public void readAll()
{
String forumId = this.request.getParameter("forum_id");
if (forumId != null) {
Map tracking = SessionFacade.getTopicsReadTimeByForum();
if (tracking == null) {
tracking = new HashMap();
}
tracking.put(new Integer(forumId), new Long(System.currentTimeMillis()));
SessionFacade.setAttribute(ConfigKeys.TOPICS_READ_TIME_BY_FORUM, tracking);
}
if (forumId != null) {
JForumExecutionContext.setRedirect(this.makeRedirect("show"));
}
else {
JForumExecutionContext.setRedirect(this.request.getContextPath() + "/forums/list"
+ SystemGlobals.getValue(ConfigKeys.SERVLET_EXTENSION));
}
}
// Messages since last visit
public void newMessages()
{
this.request.addParameter("from_date", SessionFacade.getUserSession().getLastVisit());
this.request.addParameter("to_date", new Date());
SearchAction searchAction = new SearchAction(this.request, this.response, this.context);
searchAction.newMessages();
this.setTemplateName(TemplateKeys.SEARCH_NEW_MESSAGES);
}
public void approveMessages()
{
if (SessionFacade.getUserSession().isModerator(this.request.getIntParameter("forum_id"))) {
new ModerationAction(this.context, this.request).doSave();
}
JForumExecutionContext.setRedirect(this.request.getContextPath() + "/forums/show/"
+ this.request.getParameter("forum_id") + SystemGlobals.getValue(ConfigKeys.SERVLET_EXTENSION));
}
/**
* Action when users click on "watch this forum"
* It gets teh forum_id and userId, and put them into a watch_forum table in the database;
*/
public void watchForum()
{
int forumId = this.request.getIntParameter("forum_id");
int userId = SessionFacade.getUserSession().getUserId();
this.watchForum(DataAccessDriver.getInstance().newForumDAO(), forumId, userId);
JForumExecutionContext.setRedirect(this.redirectLinkToShowAction(forumId));
}
public void banned()
{
this.setTemplateName(TemplateKeys.FORUMS_BANNED);
this.context.put("message", I18n.getMessage("ForumBanned.banned"));
}
private String redirectLinkToShowAction(int forumId)
{
int start = ViewCommon.getStartPage();
return this.request.getContextPath() + "/forums/show/" + (start > 0 ? start + "/" : "") + forumId
+ SystemGlobals.getValue(ConfigKeys.SERVLET_EXTENSION);
}
/**
*
* @param dao ForumDAO
* @param forumId int
* @param userId int
*/
private void watchForum(ForumDAO dao, int forumId, int userId)
{
if (SessionFacade.isLogged() && !dao.isUserSubscribed(forumId, userId)) {
dao.subscribeUser(forumId, userId);
}
}
/**
* Unwatch the forum watched.
*/
public void unwatchForum()
{
if (SessionFacade.isLogged()) {
int forumId = this.request.getIntParameter("forum_id");
int userId = SessionFacade.getUserSession().getUserId();
DataAccessDriver.getInstance().newForumDAO().removeSubscription(forumId, userId);
String returnPath = this.redirectLinkToShowAction(forumId);
this.setTemplateName(TemplateKeys.POSTS_UNWATCH);
this.context.put("message", I18n.getMessage("ForumBase.forumUnwatched", new String[] { returnPath }));
}
else {
this.setTemplateName(ViewCommon.contextToLogin());
}
}
}