框架模式學習 ———— MVC

mvc模式

結構圖:
框架模式學習 ———— MVC - stanley - 小老頭
 
示例:
實現一個mvc框架步驟:
  1. 定義配置文件dtd

    <!-- 示例 -->

    <?xml version="1.0" encoding="UTF-8"?>

    <!ELEMENT myMvc (actions)>
    <!ELEMENT actions (action*)>
    <!ELEMENT action (result*)>
    <!ATTLIST action
    name CDATA #REQUIRED
    class CDATA #REQUIRED>
    <!ELEMENT result (#PCDATA)>
    <!ATTLIST result
    name CDATA #IMPLIED
    redirect (true|false) "false">


  2. 定義配置文件

    <!-- 創建一個使用剛創建的dtd的配置文件 -->

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE myMvc PUBLIC "-//UNKOWN/" "mymvc.dtd"><!--此處引用上面的自定義dtd-->
    <myMvc>
    <actions>
    <action name="login" class="cn.stanley.action.LoginAction">
    <result name="success">pages/success.jsp</result>
    <result name="input">pages/login.jsp</result>
    </action>
    <action name="regist" class="cn.stanley.action.LoginAction">
    <result name="success">pages/success.jsp</result>
    <result name="input">pages/login.jsp</result>
    </action>
    </actions>
    </myMvc>


  3. 創建 請求——操作 映射類

    /**

    * 映射 響應結果與視圖之間的關係

    */
    public class ResultMapping {
    private String name;
    private boolean redirect;
    private String path;
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public boolean isRedirect() {
    return redirect;
    }
    public void setRedirect(boolean redirect) {
    this.redirect = redirect;
    }
    public String getPath() {
    return path;
    }
    public void setPath(String path) {
    this.path = path;
    }

    public ResultMapping(){}

    public ResultMapping(String name, boolean redirect, String path) {
    super();
    this.name = name;
    this.redirect = redirect;
    this.path = path;
    }
    }

    /**

    * 映射 請求與處理請求方法之間的關聯

    */

    public class ActionMapping {

    private String name;

    private String className;

    private Map<String,ResultMapping> resultMap=

    new HashMap<String, ResultMapping>(0);


    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String getClassName() {
    return className;
    }

    public void setClassName(String className) {
    this.className = className;
    }

    public Map<String, ResultMapping> getResultMap() {
    return resultMap;
    }

    public void setResultMap(Map<String, ResultMapping> resultMap) {
    this.resultMap = resultMap;
    }

    public ActionMapping(String name, String className) {
    super();
    this.name = name;
    this.className = className;
    }

    public ActionMapping(){}


    public void addResult(ResultMapping result){
    this.resultMap.put(result.getName(), result);
    }
    }


  4. 創建 配置文件解析類,解析配置文件並生成 請求——操作的映射對象

    /**

    * 解析配置文件生成相就的映射對象 ,並管理

    */

    public class ActionMappingManager {

    private Map<String, ActionMapping> actionMappings = 

    new HashMap<String, ActionMapping>();

    public ActionMappingManager(String[] configFileNames) {
    for (String configFileName : configFileNames) {
    try {
    init(configFileName);
    } catch (DocumentException e) {
    e.printStackTrace();
    }
    }
    }

    @SuppressWarnings("rawtypes")
    public void init(String configFileName) 

    throws DocumentException {
    // dom4j 解析器
    SAXReader reader = new SAXReader();
    // 設置 dtd 解析器 此片因爲是自定義dtd,所以寫了一個FindDTD類設定dtd
    reader.setEntityResolver(new FindDTD());
    //讀取根節點
    Document document = reader.read(DocumentException.class
    .getResourceAsStream("/" + configFileName));
    //子節點集合
    List nodes = document.getRootElement().element("actions")
    .elements("action");
    //遍楞子節集合
    for (Iterator iterator = nodes.iterator();

    iterator.hasNext();) {

    Element node = (Element) iterator.next();
    ActionMapping acm = new ActionMapping(
    node.attributeValue("name"),

    node.attribute("class").getValue());

    // 遍歷 result
    for (Iterator it2 = node.elements("result")

    .iterator(); it2.hasNext();) {

    Element ele = (Element) it2.next();

    String name = ele.attributeValue("name");
    boolean redirect = 

    Boolean.valueOf(ele.attributeValue("redirect"));

    String path = ele.getText();
    acm.addResult(new ResultMapping(

    name, redirect, path));
    }
    actionMappings.put(acm.getName(), acm);
    }
    }

    /**
    * 根據 請求中的 actionName 取 ActionMapping
    *
    * @param actionName
    * @return
    * @throws Exception
    */
    public ActionMapping getActionMapping(String actionName) {
    if (null == actionName || actionName.isEmpty()) {
    return null;
    }
    ActionMapping mapping = actionMappings.get(actionName);
    if (mapping == null) {
    throw new RuntimeException("不存在此mapping:" + 

    actionName);
    }
    return mapping;
    }
    }

    /**

    * 自定義DTE 解析器,因爲是自定義DTD,web容器會默認在bin目錄下找,

    * 而指定相對路徑與絕對路徑都不能正確獲取,所以得自定義

    */

    public class FindDTD implements EntityResolver {

    @Override
    public InputSource resolveEntity(String publicId, String systemId)
    throws SAXException, IOException {

    //自已的dtd所在的位置
    String path = "mymvcframework/" +

    systemId.substring(systemId.lastIndexOf("/")+1);
    InputStream in=this.getClass()

    .getClassLoader()

    .getResourceAsStream(path);
    InputSource so=new InputSource(in);
    return so;
    }

    }


  5. 定義 action 接口


    /**
    * Action 接口
    * @author Administrator
    *
    */
    public interface Action {

    /**
    * 執行 業務與 數據 訪問操作
    * @param req
    * @param res
    * @return
    * @throws Exception
    */
    String execute(HttpServletRequest req, HttpServletResponse res)
    throws Exception;

    }



  6. 創建 controller

    /**

    * 這是整個mvc框加的核心

    */

    public class ActionFilter implements Filter {
    /**
    * actionMappingManager 實例
    */
    private ActionMappingManager mappingManage;

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
    FilterChain chain) throws IOException, ServletException {
    //請求類型轉換
    HttpServletRequest hreq = (HttpServletRequest) req;
    HttpServletResponse hres = (HttpServletResponse) res;
    //獲取 動作映射
    ActionMapping aMapping=null;
    try {
    aMapping = getActionMapping(hreq, hres);
    } catch (Exception e1) {
    throw new RuntimeException(e1);
    }
    if (null == aMapping) {
    throw new RuntimeException("資源不存在");
    }
    //創建 動作對象 並執行
    Action action = ActionFactory

    .createAction(aMapping.getClassName());
    String resultName = null;
    try {
    resultName = action.execute(hreq, hres);
    } catch (Exception e) {
    e.printStackTrace();
    }
    if (resultName == null) {
    throw new RuntimeException("結果視圖不存在");
    }
    //取出 結果映射
    ResultMapping result = aMapping. getResultMap()

    .get(resultName);
    //判斷 結果映射 晌應方式
    if (result.isRedirect()) { //重定向
    hres.sendRedirect(result.getPath());
    } else { //轉發
    req.getRequestDispatcher(result.getPath())
    .forward(req, res);
    }

    }

    /**
    * 初始化操作 :: 讀取web.xml 中的 初始參數配置 ,

    * 創建 ActionMappingManager 類
    */
    @Override
    public void init(FilterConfig config) throws ServletException {
    //獲取配置參數 config
    String conStr=config.getInitParameter("config");
    //配置的文件名數組
    String[] configFileNames=null;
    if(conStr==null|| conStr.isEmpty()){

    }else{
    configFileNames=conStr.split(",");
    }
    // 創建 actionMappingManager 類
    this.mappingManage=new ActionMappingManager(configFileNames);

    }

    /**
    * 獲取動作
    * @param req
    * @param res
    * @return
    * @throws Exception
    */
    private ActionMapping getActionMapping(HttpServletRequest req,
    HttpServletResponse res) throws Exception {
    //獲取 uri
    String url = req.getRequestURI();
    //獲取應用名
    String contextPath = req.getContextPath();
    //獲取 *.action...
    String actionPath = url.substring(contextPath.length());
    //獲取 *.action 中 的 * 部分
    String actionName = actionPath
    .substring(1, actionPath.lastIndexOf("."));
    // 返加 actionMapping
    return mappingManage.getActionMapping(actionName);
    }

    }


    /**

    * 此處用一個返射工廠來創建Action實例

    */

    public class ActionManager {

    public static Action createAction(String className){
    try {
    return (Action) Class.forName(className)

    .newInstance();
    } catch (InstantiationException e) {
    e.printStackTrace();
    } catch (IllegalAccessException e) {
    e.printStackTrace();
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    }

    return null;
    }

    }


  7. 將控制器配置到 web.xml中


MVC的優點:
1、可以爲一個模型在運行時同時建立和使用多個視圖。變化-傳播機制可以確保所有相關的視圖及時得到模型數據變化,從而使所有關聯的視圖和控制器做到行爲同步。 
2、視圖與控制器的可接插性,允許更換視圖和控制器對象,而且可以根據需求動態的打開或關閉、甚至在運行期間進行對象替換。
3、模型的可移植性。因爲模型是獨立於視圖的,所以可以把一個模型獨立地移植到新的平臺工作。需要做的只是在新平臺上對視圖和控制器進行新的修改。
 
MVC的不足之處
1、增加了系統結構和實現的複雜性。對於簡單的界面,嚴格遵循MVC,使模型、視圖與控制器分離,會增加結構的複雜性,並可能產生過多的更新操作,降低運行效率。
2、視圖與控制器間的過於緊密的連接。視圖與控制器是相互分離,但確實聯繫緊密的部件,視圖沒有控制器的存在,其應用是很有限的,反之亦然,這樣就妨礙了他們的獨立重用。
3、視圖對模型數據的低效率訪問。依據模型操作接口的不同,視圖可能需要多次調用才能獲得足夠的顯示數據。對未變化數據的不必要的頻繁訪問,也將損害操作性能。  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章