一、Model1與Model2:
Model1:就是一種純jsp開發技術,將業務邏輯代碼和視圖渲染代碼雜糅在一起。
Model2:Model2是在Model1的基礎上,將業務邏輯的代碼分離開來,單獨形成一個Servlet,Model2也是基于MVC開發
二、MVC設計模式:
由3個部分組成,各部分作用如下:
Model:模型,主要用于數據和業務的處理
View:視圖,用于數據的顯示
Controller:控制器,用于進行流程控制
MVC設計模式的特點:
①一個模型可以對應多個視圖
②顯示與邏輯控制的分離
③分層控制,減輕了代碼間的耦合
自定義MVC框架只需dom4j.jar包即可!
三、準備XML文檔Framework.xml
注意點:
<!-- ELEMENT 表示元素 -->
<!-- ATTLIST 表示屬性 -->
<!-- CDATA 表示字符串類型 -->
<!-- REQUIRED 表示此屬性必須的寫 -->
<!-- *代表多個 -->
<!-- IMPLIED 表示此屬性可寫 -->
<!DOCTYPE Framework[ <!ELEMENT Framework (actions)> <!ELEMENT actions (action*)> <!ELEMENT action (result*)> <!ATTLIST action name CDATA #REQUIRED class CDATA #REQUIRED > <!ATTLIST RESULT name CDATA #IMPLIED redirect (true|false) "false" > ]> <Framework> <actions> <action name="loginAction" class="cn.happy.action.LoginAction"> <result name="success">success.jsp</result> <result name="login">index.jsp</result> </action> </actions> </Framework>
四、定義自己的Action接口,用于存放結果集和要執行的方法
public interface Action { //定義兩個靜態字符串常量(邏輯視圖名) public static final String SUCCESS="success"; public static final String LOGIN="login"; //定義一個抽象方法execute public String execute(HttpServletRequest request,HttpServletResponse response)throws Exception; }
五、定義ActionMapping類用于存放Action節點,即一個ActionMapping類可以視為配置文件中的一個action節點
public class ActionMapping { //根據action節點中的屬性 以及action節點中的<result></result>節點定義三個私有屬性 private String name;//action的名稱 private String classname;//action對應程序中的類 private Map<String,String> results=new HashMap<String,String>(); //向results集合中添加數據的方法 public void addResult(String name,String value){ results.put(name, value); } //根據名稱獲取的方法 public String getResults(String name){ return results.get(name); } public Map<String, String> getResults() { return results; } public void setResults(Map<String, String> results) { this.results = results; } 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; }
六、定義ActionMappingManager類用于管理ActionMapping,并通過dom4j解析Framework.xml配置文件。從而獲取根節點,以及actions節點,并通過for循環遍歷actions節點下的action節點拿到name和class的屬性值,由于一個action節點下有多個result節點 及遍歷action下所有的result節點,分別存入到actionMapping中的雙列集合中,最后得到所有action節點的集合
public class ActionMappingManager { //actionMapping類的集合 private Map<String,ActionMapping> maps=new HashMap<String,ActionMapping>(); public ActionMapping getActionMapping(String name){ return maps.get(name); } //解析src下所有配置文件 public ActionMappingManager(String[]files){ for (String filename : files) { init(filename); } } //創建初始化方法,使用dom4j解析配置文件 public void init(String path){ try { //getResourceAsStream取得該資源輸入流的引用保證程序可以從正確的位置抽取數據 InputStream is=this.getClass().getResourceAsStream("/"+path); //解析XML Document doc=new SAXReader().read(is); //獲取根節點 Element root = doc.getRootElement(); //獲取actions節點 Element actions =(Element)root.elementIterator("actions").next(); //使用for循環來 //遍歷actions節點下的所有action節點 for (Iterator<Element> action=actions.elementIterator("action");action.hasNext();) { //獲取到action節點 Element actionnext = action.next(); //分別獲取到action節點中的name屬性和class屬性 String name=actionnext.attributeValue("name"); String classname=actionnext.attributeValue("class"); //將以上兩個屬性保存到ActionMapping類中 ActionMapping mapp=new ActionMapping(); mapp.setClassname(classname); mapp.setName(name); //由于一個action節點下有多個result節點 遍歷action下所有的result節點 for (Iterator<Element> result=actionnext.elementIterator("result");result.hasNext();){ //獲取到result節點 Element resultnext = result.next(); //提取result節點的name屬性值和result節點中的值 String resultname= resultnext.attributeValue("name"); String resultvalue= resultnext.getText(); //將其分別存入到actionMapping中的雙列集合中去,方便調用actionMapping類(actionMapping類中就有數據了!) mapp.addResult(resultname, resultvalue); } //得到所有action節點的集合 maps.put(mapp.getName(), mapp); } } catch (Exception e) { } }
七、使用反射機制根據字符串類型的類名獲取到具體的類--ActionManager
public class ActionManager { public static Action getActionClass(String classname){ Class clazz=null; Action action=null; //獲取當前線程的加載類 try { clazz=Thread.currentThread().getContextClassLoader().loadClass(classname); } catch (ClassNotFoundException e) { e.printStackTrace(); } if(clazz==null){ try { //如果該線程中沒有,那么使用class.forname方法獲取 clazz=Class.forName(classname); } catch (ClassNotFoundException e) { e.printStackTrace(); } } if(action==null){ //將獲取到的類型轉換為action,調用無參構造函數,某種程度上相當于new,不過new需要指定類型 try { action =(Action)clazz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return action; }
八、定義Servlet類,詳情見注釋!注意點在web.xml中添加 <load-on-startup>節點,讓程序一開始就初始化servlet
public class MyServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); } ActionMappingManager man=null; public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //獲取到ActionMapping對象 ActionMapping actionMapping=man.getActionMapping(getname(request)); //獲取action接口利用反射機制 Action action = ActionManager.getActionClass(actionMapping.getClassname()); try { String message=action.execute(request, response); String results=actionMapping.getResults(message); response.sendRedirect(results); } catch (Exception e) { e.printStackTrace(); } } //獲取請求路徑名 public String getname(HttpServletRequest request) { //項目+請求地址 String requestURI =request.getRequestURI(); //項目名稱 String contextPath=request.getContextPath(); //具體的請求 String path=requestURI.substring(contextPath.length()); String filename=path.substring(1,path.lastIndexOf(".")).trim(); return filename; } //重寫servlet的init方法,讓程序一開始就初始化servlet //由于一個項目src根目錄下有可能有多個配置文件,不止一個,所以逐個解析 @Override public void init(ServletConfig config) throws ServletException { //初始化參數信息 String filename = config.getInitParameter("config"); String [] filenames=null; if(filename==null){ //如果沒有別的參數信息,就將已經配好的放入數組中 filenames=new String[]{"Framework.xml"}; } else{ //拆分配置文件名稱字符串 filenames=filename.split(","); } //使用init方法初始化 man=new ActionMappingManager(filenames); }
九、業務邏輯Action并實現Action接口,并重寫自定義的execute方法
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(name.equals("1")&&pwd.equals("1")){ return SUCCESS; } else{ return LOGIN; } }
十、編寫登錄界面
<body> <form action="loginAction.action" method="post"> 姓名:<input type="text" name="name"/><br/> 密碼:<input type="text" name="pwd"/><br/> <input type="submit" value="登錄"> </form> </body>
實現效果:
文章列表