一、實現自定義MVC的體系結構圖
1、Model I模式開發Web應用時,分兩種情況:
*純JSP技術方式開發
*JSP+JavaBean方式開發
2、Model I模式開發的不足:
*JSP頁面中嵌入大量的Java代碼,可讀性差。
*大量代碼在JSP中難以復用。
*后期維護及擴展的難度大。
3、為了克服Model I模式的缺陷,引入了Model II的模式開發
*Model II模式體現了基於MVC(Model-View-Controller,模型-視圖-控制器)的設計模式,簡單的說,Model II模式就是將數據顯示、流程控制和業務邏輯處理分離,使之相互獨立。
4、MVC設計模式由3個部分組成各部分的作用。
*Model:模型,主要用於數據和業務的處理。
*View:視圖,用於數據顯示。
*Controller:控制器,用於流程控制。
5、MVC設計模式的特點
*一個模型可以對應多個視圖。
*顯示與邏輯控制分離。
*分層控制,減低了代碼間的耦合。
二、我們如何創建一個自己的MVC框架??
(一)我們要在lib里面准備一個夾包
dom4j-1.6.1.jar 主要作用:解析xml文件
(二)准備配置文檔(在src下)
<?xml version="1.0" encoding="UTF-8"?> <!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="cn.happy.action.LoginAction"> <result name="success">success.jsp</result> <result name="login">index.jsp</result> </action> </actions> </myframework>
解析:根據上述約束完成的“*”代表多次
(三)自己准備一個Action接口,用於放入結果集和執行方法
package cn.happy.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 response)throws Exception; }
(四)定義一個ActionMapping用來存放Action節點
package cn.happy.action; import java.util.HashMap; import java.util.Map; /* * Action配置文件信息,用來放置Action的節點的 * */ public class ActionMapping { //訪問的Action的名稱 private String name; //訪問Action的對應的Action的類的全稱 private String ClassName; //result定義的結果集 private Map<String,String> resultMaps=new HashMap<String,String>(); //往集合里面添加配置文件中的數據信息 public void addResult(String resultName,String result){ resultMaps.put(resultName, result); } //根據resultName獲取對應的result頁面 public String getResult(String resultName){ return resultMaps.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 cn.happy.action; import java.io.InputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; /* * 用來管理ActionMapping也就是可以保存多個action節點信息 * * */ public class ActionMappingManager { //保存多個action節點信息 private Map<String ,ActionMapping> actionMappings=new HashMap<String,ActionMapping>(); public ActionMapping getActionMapping(String name){ return actionMappings.get(name); } //帶參構造 public ActionMappingManager(String[] configFileNames){ for(String filaName:configFileNames){ //調用根據文件名讀取配置文件的方法 init(filaName); } } //解析xml public void init(String configFileName){ System.out.println("======init"); try { //讀取配置文件,肯定用到了輸入流 InputStream is=this.getClass().getResourceAsStream("/"+configFileName); //開始讀取xml文件 Document doc=new SAXReader().read(is); //獲取根節點 Element root=doc.getRootElement(); //獲取Action節點 Element actions=(Element) root.elementIterator("actions").next(); //開始遍歷Action節點 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 (DocumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
(六)利用反射機制找到自己的實列
package cn.happy.action; /* * 利用反射機制,根據類的類型獲取到類的實列 * */ public class ActionManager { public static Action creatAction(String className){ Class clazz=null; try { //判斷當前線程是否有該Action clazz=Thread.currentThread().getContextClassLoader().loadClass(className); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block 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; } }
(七)寫一個業務邏輯
package cn.happy.action; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class LoginAction implements Action { public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception { String name=request.getParameter("name"); String pwd=request.getParameter("pwd"); if("1".equals(name)&&"1".equals(pwd)){ return SUCCESS; }else{ return LOGIN; } } }
(八)寫一個Servlet
package cn.happy.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 cn.happy.action.Action; import cn.happy.action.ActionManager; import cn.happy.action.ActionMapping; import cn.happy.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) { // TODO Auto-generated catch block 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[]{"MyMvc.xml"}; }else{ fileNames=configStr.split(","); } //讀取配置文件,將文件中的信息保存到ActionMappingManager中 actionMappingManager=new ActionMappingManager(fileNames); } }
(九)修改web.xml
<servlet-mapping> <servlet-name>MVCServlet</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping>
(十)准備一個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> </head> <body> <form action="LoginAction.action" method="post"> 用戶名:<input type="text" name="name"/><br/> 密碼:<input type="password" name="pwd"/><br/> <input type="submit" value="登錄"/> </form> </body> </html>
(十一)准備一個成功頁面代碼省略
總結:自定義的MVC模式
定義ActionMapping,是用來放置Action的節點的
定義ActionMappingManager,管理ActionMapping
定義ActionManager利用反射機制,找到具體類的實列