源代碼放在sharesources@126.com的郵箱的收件箱里,用戶名:sharesource,密碼:javafans
希望保留給有用的人,謝謝。
取這樣一個標(biāo)題太大,吸引眼球嘛@_@。
事實是最近讀《
J2EE設(shè)計模式》講述表達(dá)層模式的那幾章,書中有一個前端控制器+command模式的workflow例子,就琢磨著可以很簡單地擴展成一個MVC框架?;艘粋€下午改寫了下,對書中所述的理解更為深入。我想這也許對于學(xué)習(xí)和理解設(shè)計模式,以及初次接觸
struts等MVC框架的人可能有點幫助。因為整個模型類似于struts,我把它取名叫strutslet^_^。學(xué)習(xí)性質(zhì),切勿認(rèn)真。
(一)完整的類圖如下:
點擊查看大圖1。前端控制器(FrontController):前端控制器提供了一個統(tǒng)一的位置來封裝公共請求處理,它的任務(wù)相當(dāng)簡單,執(zhí)行公共的任務(wù),然后把請求轉(zhuǎn)交給相應(yīng)的控制器。在strutslet中,前端控制器主要作用也在于此,它初始化并解析配置文件,接受每個請求,并簡單地把請求委托給調(diào)度器(Dispatcher),由調(diào)度器執(zhí)行相應(yīng)的動作(Action)。調(diào)度器把action返回的url返回給FrontController,F(xiàn)rontController負(fù)責(zé)轉(zhuǎn)發(fā)。
2。Action接口:command模式很好的例子,它是一個命令接口,每一個實現(xiàn)了此接口的action都封裝了某一個請求:新增一條數(shù)據(jù)記錄并更新model,或者把某個文件寫入磁盤。命令解耦了發(fā)送者和接受者之間聯(lián)系。 發(fā)送者調(diào)用一個操作,接受者接受請求執(zhí)行相應(yīng)的動作,因為使用Command模式解耦,發(fā)送者無需知道接受者任何接口。
3。Dispatcher:調(diào)度器,負(fù)責(zé)流程的轉(zhuǎn)發(fā),負(fù)責(zé)調(diào)用action去執(zhí)行業(yè)務(wù)邏輯。由調(diào)度器選擇頁面和action,它去除了應(yīng)用行為和前端控制器間的耦合。調(diào)度器服務(wù)于前端控制器,它把model的更新委托給action,又提供頁面選擇給FrontController
4。ActionForward:封裝了轉(zhuǎn)向操作所需要信息的一個模型,包括name和轉(zhuǎn)向url
5。ActionModel:解析配置文件后,將每一個Action封裝成一個ActionModel對象,所有ActionModel構(gòu)成一個map,并
存儲在ServletContext中,供整個框架使用。
(二)源代碼簡單分析
1。Action接口,只有一個execute方法,任何一個action都只要實現(xiàn)此接口,并實現(xiàn)相應(yīng)的業(yè)務(wù)邏輯,最后返回一個ActionForward,提供給Dispacher調(diào)用。
public interface Action { public ActionForward execute(HttpServletRequest request,ServletContext context); }
比如,我們要實現(xiàn)一個登陸系統(tǒng)(demo的例子),LoginAction驗證用戶名和密碼,如果正確,返回success頁面,如果登陸失敗,返回fail頁面:
public class LoginAction implements Action { private String name=""; public ActionForward execute(HttpServletRequest request, ServletContext context) { String userName=request.getParameter("userName"); String password=request.getParameter("password"); if(userName.equals("dennis")&&password.equals("123")){ request.setAttribute("name", name); return ActionForward.SUCCESS; //登陸成功,返回success }else return ActionForward.FAIL; //否則,返回fail }
2.還是先來看下兩個模型:ActionForward和ActionModel,沒什么東西,屬性以及相應(yīng)的getter,setter方法:
/** * 類說明:轉(zhuǎn)向模型 * @author dennis * * */ public class ActionForward { private String name; //forward的name private String viewUrl; //forward的url public static final ActionForward SUCCESS=new ActionForward("success"); public static final ActionForward FAIL=new ActionForward("fail"); public ActionForward(String name){ this.name=name; } public ActionForward(String name, String viewUrl) { super(); this.name = name; this.viewUrl = viewUrl; } //...name和viewUrl的getter和setter方法 }
我們看到ActionForward預(yù)先封裝了SUCCESS和FAIL對象。
public class ActionModel { private String path; // action的path private String className; // action的class private Map<String, ActionForward> forwards; // action的forward public ActionModel(){} public ActionModel(String path, String className, Map<String, ActionForward> forwards) { super(); this.path = path; this.className = className; this.forwards = forwards; } //...相應(yīng)的getter和setter方法 }
3。知道了兩個模型是什么樣,也應(yīng)該可以猜到我們的配置文件大概是什么樣的了,與
struts的配置
文件格式類似:
<?xml version="1.0" encoding="UTF-8"?> <actions> <action path="/login" class="com.strutslet.demo.LoginAction"> <forward name="success" url="hello.jsp"/> <forward name="fail" url="fail.jsp"/> </action> </actions>
path是在應(yīng)用中將被調(diào)用的路徑,class指定了調(diào)用的哪個action,forward元素指定了轉(zhuǎn)向,比如我們這里如果是success就轉(zhuǎn)向hello.jsp,失敗的話轉(zhuǎn)向fail.jsp,這里配置了demo用到的LoginAction。
4。Dispacher接口,主要是getNextPage方法,此方法負(fù)責(zé)獲得下一個頁面將導(dǎo)向哪里,提供給前端控制器轉(zhuǎn)發(fā)。
public interface Dispatcher { public void setServletContext(ServletContext context); public String getNextPage(HttpServletRequest request,ServletContext context); }
5。5。原先書中實現(xiàn)了一個WorkFlow的Dispatcher,按照順序調(diào)用action,實現(xiàn)工作流調(diào)用。而我們所需要的是根據(jù)請求的path調(diào)用相應(yīng)的action,執(zhí)行action的execute方法返回一個ActionForward,然后得到ActionForward的viewUrl,將此viewUrl提供給前端控制器轉(zhuǎn)發(fā),看看它的getNextPage方法:
public String getNextPage(HttpServletRequest request, ServletContext context) { setServletContext(context); Map<String, ActionModel> actions = (Map<String, ActionModel>) context .getAttribute(Constant.ACTIONS_ATTR); //從ServletContext得到所有action信息 String reqPath = (String) request.getAttribute(Constant.REQUEST_ATTR);//發(fā)起請求的path ActionModel actionModel = actions.get(reqPath); //根據(jù)path得到相應(yīng)的action String forward_name = ""; ActionForward actionForward; try { Class c = Class.forName(actionModel.getClassName()); //每個請求對應(yīng)一個action實例 Action action = (Action) c.newInstance(); actionForward = action.execute(request, context); //執(zhí)行action的execute方法 forward_name = actionForward.getName(); } catch (Exception e) { log.error("can not find action "+actionModel.getClassName()); e.printStackTrace(); } actionForward = actionModel.getForwards().get(forward_name); if (actionForward == null) { log.error("can not find page for forward "+forward_name); return null; } else return actionForward.getViewUrl(); //返回ActionForward的viewUrl }