你的位置:首页 > ASP.net教程

[ASP.net教程]自定义MVC框架


我们在学习自定义MVC框架的时候常常会听到Model1 ,Model2和MVC。那么什么是Model1 什么是Model2什么又是MVC呢?

什么是Model1?

Model1就是一种纯jsp开发技术,将业务逻辑代码和视图渲染代码杂糅在一起。

 

什么是Model2?

 

Model2是在Model1的基础上,将业务逻辑的代码分离开来,单独形成一个Servlet,Model2也是基于MVC开发

 

什么是MVC框架?

MVC是三个单词的缩写,这三个单词分别为:模型(Model)、视图(View)和控制(Controller)。一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

 

其实我们之前也使用过MVC的思想,我们在学习Model2也就是Servlet的时候,用的思想就是基于MVC开发思想

既然我们已经知道了MVC的作用,那么我们就可以开发自己的MVC框架了,就以我们之前学习的Struts2框架为例,定义一个自己的MVC框架

 

如何开发自己的MVC框架?

开发前的准备   jar包

 

一个就够了,该jar包的作用就是解析文件

 

第一步:准备配置文档

既然是框架,那肯定少不了的东西就是配置文件

我们配置一个文件,如下

 

<?"1.0" encoding="UTF-8"?><!-- 定义我们的DOC约束文件 --><!-- 定义根节点 (包含元素)--><!-- ELEMENT 表示元素 --><!-- ATTLIST 表示属性 --><!DOCTYPE myframework[    <!ELEMENT myframework (actions)>  <!ELEMENT actions (action*)>  <!ELEMENT action (result*)>    <!ATTLIST action         name CDATA #REQUIRED        class CDATA #REQUIRED  >  <!ATTLIST result         name CDATA #IMPLIED        redirect (true|false) "false"  >]  ><myframework>  <actions>    <action name="loginAction" class="action.LoginAction">      <result name="success">success.jsp</result>      <result name="input">index.jsp</result>    </action>  </actions></myframework>

 

第二步:我们准备自己的Action接口,用于存放结果集和要执行的方法

package action;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public interface Action {    //定义字符串常量  public static final String SUCCESS="success";  public static final String NONE="none";  public static final String ERROR="error";  public static final String INPUT="input";  public static final String LOGIN="login";    //准备一个方法,用于获取数据  public String execute(HttpServletRequest request, HttpServletResponse sponse)throws Exception; }

第三步:定义一个ActionMapping用来存放Action节点

package action;import java.util.HashMap;import java.util.Map;/* *   Action 的配置文件信息 * */public class ActionMapping {    //访问的Action的名称    private String name;    //访问的Action的对应的Action的类全称    private String ClassName;    //result定义的结果集    private Map<String,String> resultMAp=new HashMap<String, String>();            //往集合里面添加配置文件中的数据信息    public void addResult(String resultName,String result){      resultMAp.put(resultName, result);    }            //根据resultName获取对应的result页面    public String getResult(String resultName){      return resultMAp.get(resultName);    }        public String getName() {      return name;    }    public void setName(String name) {      this.name = name;    }    public String getClassName() {      return ClassName;    }    public void setClassName(String className) {      ClassName = className;    }            }

 

 

第四步:定义ActionMappingManager,管理ActionMapping

package action;import java.io.InputStream;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;/* * ActionMapping 的管理类 * */public class ActionMappingManager {  /**管理ActionMapping 一个ActionMapping表示一个Action    * 但是我们配置文件中可能出现多个Action节点,所以我们需要一个ActionMapping的管理类   * */  private static Map<String,ActionMapping> actionMappings=new HashMap<String,ActionMapping>();  public ActionMappingManager() {      }  //带参构造  public ActionMappingManager(String[] configFileNames){    for (String filaName : configFileNames) {      //调用根据文件名读取配置文件的方法      init(filaName);    }  }    //根据Action名称获取到某一个具体的Action  public ActionMapping getActionMapping(String actionName){    //根据ActionName获取到Action    ActionMapping actionMapping=actionMappings.get(actionName);    return actionMapping;  }      public void init(String configFileName){    try {      //读取配置文件,肯定用到了输入流      InputStream is=this.getClass().getResourceAsStream("/"+configFileName);      //开始读取      Document doc=new SAXReader().read(is);      //获取根节点      Element root=doc.getRootElement();      //获取Actions节点      Element actions = (Element)root.elementIterator("actions").next();      //开始遍历Actions节点      for(Iterator<Element> action=actions.elementIterator("action");action.hasNext();){        //获取到Action节点,将其属性进行封装        Element actionElement=action.next();        //获取到name        String name=actionElement.attributeValue("name");        //获取到ClassName        String ClassName=actionElement.attributeValue("class");        //一个Action对应着一个ActionMapping,创建ActionMapping进行赋值        ActionMapping actionMapping =new ActionMapping();        actionMapping.setName(name);        actionMapping.setClassName(ClassName);        //遍历Action的子元素result        for(Iterator<Element> result=actionElement.elementIterator("result");result.hasNext();){          Element resultElement = result.next();          //获取result属性值          String resultName=resultElement.attributeValue("name");          String resultValue=resultElement.getText();          //将每个result封装到ActionMapping中去          actionMapping.addResult(resultName, resultValue);        }        //将ActionMapping放入ActionMappingManager中去        actionMappings.put(actionMapping.getName(), actionMapping);      }                } catch (Exception e) {      e.printStackTrace();    }  }  }

 

 

 

第五步:利用反射机制,找到具体类的实例

package action;/* * 利用反射机制,根据类的类类型获取到类的实例 * */public class ActionManager {  public static Action creatAction(String className){    Class clazz=null;        try {      //判断当前线程是否有该Action       clazz = Thread.currentThread().getContextClassLoader().loadClass(className);    } catch (ClassNotFoundException e) {      e.printStackTrace();    }    if(clazz==null){      try {        //根据类的全路径,手动创建一个类的类类型        clazz=Class.forName(className);      } catch (ClassNotFoundException e) {        e.printStackTrace();      }    }    Action action=null;    try {      //根据类的类类型创建出一个类的实例      action=(Action)clazz.newInstance();    } catch (InstantiationException e) {      e.printStackTrace();    } catch (IllegalAccessException e) {      e.printStackTrace();    }    return action;  }}  

 

 

第六步:写业务逻辑Action

package action;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class LoginAction implements Action {  public String execute(HttpServletRequest request, HttpServletResponse sponse)      throws Exception {    //写具体的业务逻辑        return SUCCESS;  }}

第七步:准备Servlet

package servlet;import java.io.IOException;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import action.Action;import action.ActionManager;import action.ActionMapping;import action.ActionMappingManager;public class MVCServlet extends HttpServlet {  /**    出品:巴黎的雨季   */  public void doGet(HttpServletRequest request, HttpServletResponse response)      throws ServletException, IOException {    doPost(request, response);  }  /**    出品:巴黎的雨季     */    ActionMappingManager actionMappingManager=null;    public void doPost(HttpServletRequest request, HttpServletResponse response)      throws ServletException, IOException {    try {      //根据ActionName获取到ActionMapping      ActionMapping actionMapping = actionMappingManager.getActionMapping(getActionName(request));      //根据ActionMapping中的ClassName获取到具体的类的实例      Action action = ActionManager.creatAction(actionMapping.getClassName());      //执行业务逻辑,获取到resultName      String resultName = action.execute(request, response);      //根据resultName获取具体的result视图      String result = actionMapping.getResult(resultName);      //重定向到页面      response.sendRedirect(result);              } catch (Exception e) {        e.printStackTrace();      }      }    //根据请求的上下文获取到ActionName  public String getActionName(HttpServletRequest request){    //获取到URI    String uri = request.getRequestURI();    //获取上下文路径    String contextPath = request.getContextPath();    //从上下文中截取ActionPath    String actionPath = uri.substring(contextPath.length());    //获取到ActionName    String actionName=actionPath.substring(1,actionPath.lastIndexOf('.')).trim();    return actionName;  }    //在加载Servlet的时候就读取配置文件信息  @Override  public void init(ServletConfig config) throws ServletException {    //读取配置信息    String configStr = config.getInitParameter("config");    String[] fileNames=null;    if(configStr==null||configStr.isEmpty()){      fileNames=new String[]{"myframework."};    }else{      fileNames=configStr.split(",");    }    //读取配置文件,将文件中的信息保存到ActionMappingManager中    actionMappingManager=new ActionMappingManager(fileNames);  }}

 

 

第八步:修改web.

<?"1.0" encoding="UTF-8"?><web-app version="2.5"   ="http://java.sun.com/"   ="http://www.w3.org/2001/"   xsi:schemaLocation="http://java.sun.com/  http://java.sun.com/ <display-name></display-name> <servlet>  <description>This is the description of my J2EE component</description>  <display-name>This is the display name of my J2EE component</display-name>  <servlet-name>MVCServlet</servlet-name>  <servlet-class>servlet.MVCServlet</servlet-class> </servlet> <servlet-mapping>  <servlet-name>MVCServlet</servlet-name>  <url-pattern>*.action</url-pattern> </servlet-mapping>   <welcome-file-list>  <welcome-file>login.jsp</welcome-file> </welcome-file-list></web-app>

 

 

测试页面(login.jsp)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head>  <base href="<%=basePath%>">    <title>My JSP 'index.jsp' starting page</title>  <meta http-equiv="pragma" content="no-cache">  <meta http-equiv="cache-control" content="no-cache">  <meta http-equiv="expires" content="0">    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  <meta http-equiv="description" content="This is my page">  <!--  <link rel="stylesheet" type="text/css" href="styles.css">  --> </head>  <body>      <form action="loginAction.action" method="post">        用户名:<input type="text" name="uname"/><br/>        密码:<input type="password" name="pwd"/><br/>        <input type="submit" value="登录"/>      </form> </body></html>

 

这样我们就完成了一个自定义的MVC框架了