我們在學習自定義MVC框架的時候常常會聽到Model1 ,Model2和MVC。那麼什麼是Model1 什麼是Model2什麼又是MVC呢? 什麼是Model1? Model1就是一種純jsp開發技術,將業務邏輯代碼和視圖渲染代碼雜糅在一起。 什麼是Model2? Model2是在Model1的基礎 ...
我們在學習自定義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包的作用就是解析xml文件
第一步:準備配置文檔
既然是框架,那肯定少不了的東西就是配置文件
我們配置一個xml文件,如下
<?xml version="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); //開始讀取xml文件 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.xml"}; }else{ fileNames=configStr.split(","); } //讀取配置文件,將文件中的信息保存到ActionMappingManager中 actionMappingManager=new ActionMappingManager(fileNames); } }
第八步:修改web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <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框架了