1. 程式人生 > >Java Web自定義MVC框架詳解

Java Web自定義MVC框架詳解

分享一個大神的人工智慧教程!http://blog.csdn.net/jiangjunshow

最近給學生講Java Web,希望他們能夠在學完這部分內容後自己實現一個MVC框架。但是突然發現百度上能搜尋到的靠譜的資料並不是很多,有些只是原理沒有程式碼實現,有些有程式碼實現但是對於初學者來說理解起來還是比較困難,於是決定把自己講自定義MVC框架的內容放在這裡分享給大家,不僅僅是程式碼,也有原理和探討。內容會比較長,因為我打算用遞增的方式講解如何寫一個自定義MVC框架,重點是前端控制器的開發。

先說一下什麼是前端控制器(font controller)。Java Web中的前端控制器是應用的門面,簡單的說所有的請求都會經過這個前端控制器,由前端控制器根據請求的內容來決定如何處理並將處理的結果返回給瀏覽器。這就好比很多公司都有一個前臺,那裡通常站著幾位面貌姣好的美女,你要到這家公司處理任何的業務或者約見任何人都可以跟她們說,她們會根據你要做什麼知會相應的部門或個人來處理,這樣做的好處是顯而易見的,公司內部系統運作可能很複雜,但是這些對於外部的客戶來說應該是透明的,通過前臺,客戶可以獲得他們希望該公司為其提供的服務而不需要了解公司的內部實現。這裡說的前臺就是公司內部系統的一個門面,它簡化了客戶的操作。前端控制器的理念就是

GoF設計模式門面模式(外觀模式)在Web專案中的實際應用。SUN公司為Java Web開發定義了兩種模型,Model 1和Model 2。Model 2是基於MVC(Model-View-Controller,模型-檢視-控制)架構模式的,通常將小服務(Servlet)或過濾器(Filter)作為控制器,其作用是接受使用者請求並獲得模型資料然後跳轉到檢視;將JSP頁面作為檢視,用來顯示使用者操作的結果;模型當然是POJO(Plain Old Java Object),它是區別於EJB(Enterprise JavaBean)的普通Java物件,不實現任何其他框架的介面也不扮演其他的角色,而是負責承載資料,可以作為VO(Value Object)或DTO(Data Transfer Object)來使用。當然,如果你對這些概念不熟悉,可以用
百度
或者維基百科查閱一下,想要深入的瞭解這些內容推薦閱讀大師Martin Fowler的《企業應用架構模式》(英文名:Patterns of Enterprise Application Architecture)。

接下來我們就來編寫一個作為處理使用者各種請求門面的前端控制器。


  
  1. package com.lovo.servlet;
  2. import
    java.io.IOException;
  3. import javax.servlet.ServletException;
  4. import javax.servlet.annotation.WebServlet;
  5. import javax.servlet.http.HttpServlet;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8. @WebServlet( "*.do")
  9. public class FrontController extends HttpServlet {
  10. private static final long serialVersionUID = 1L;
  11. private static final String DEFAULT_PACKAGE_NAME = "com.lovo.action."; // 預設的Action類的包名字首
  12. private static final String DEFAULT_ACTION_NAME = "Action"; // 預設的Action類的類名字尾
  13. @Override
  14. protected void service(HttpServletRequest req, HttpServletResponse resp)
  15. throws ServletException, IOException {
  16. // 獲得請求的小服務路徑
  17. String servletPath = req.getServletPath();
  18. // 從servletPath中去掉開頭的斜槓和末尾的.do就是要執行的動作(Action)的名字
  19. int start = 1; // 去掉第一個字元斜槓從第二個字元開始
  20. int end = servletPath.lastIndexOf( ".do"); // 找到請求路徑的字尾.do的位置
  21. String actionName = end > start ? servletPath.substring(start, end) + DEFAULT_ACTION_NAME : "";
  22. String actionClassName = DEFAULT_PACKAGE_NAME + actionName.substring( 0, 1).toUpperCase() + actionName.substring( 1);
  23. // 接下來可以通過反射來建立Action物件並呼叫
  24. System.out.println(actionClassName);
  25. }
  26. }

上面的FrontController類中用@WebServlet註解對該小服務做了對映,只要是字尾為.do的請求,都會經過這個小服務,所以它是一個典型的前端控制器(當然,你也可以在web.xml中使用<servlet>和<servlet-mapping>標籤對小服務進行對映,使用註解通常是為了提升開發效率,但需要注意的是註解也是一種耦合,配置檔案在解耦合上肯定是更好的選擇,如果要使用註解,最好是像Spring 3那樣可以基於程式配置應用,此外,使用註解配置Servlet需要你的伺服器支援Servlet 3規範)。假設使用Tomcat作為伺服器(使用預設設定),專案的部署名稱為hw,接下來可以瀏覽器位址列輸入http://localhost:8080/hw/login.do,Tomcat的控制檯會輸出com.lovo.action.LoginAction。

到這裡我們已經將請求對應到一個處理該請求的Action類的名字,不要著急,我們馬上來解釋什麼是Action,怎麼寫Action。我們可以使用不同的Action類來處理使用者不同的請求,那麼如何在前端控制器中根據不同的請求創建出不同的Action物件呢,相信大家都想到了反射,我們剛才已經得到了Action類的完全限定名(帶包名的類名),接下來就可以用反射來建立物件,但是稍等,每個Action要執行的處理是不一樣的,怎樣才能寫一個通用的前端控制器呢?答案是多型!我們可以先定義一個Action介面並定義一個抽象方法,不同的Action子類會對該方法進行重寫,這樣的話用Action的引用引用不同的Action子類物件,再呼叫子類重寫過的方法,那麼就可以執行不同的行為。想到這一層,我們可以繼續編寫我們的前端控制器。

首先,我們需要定義Action類的介面。


  
  1. package com.lovo.action;
  2. import java.io.IOException;
  3. import javax.servlet.ServletException;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. /**
  7. * 處理使用者請求的控制器介面
  8. * @author 駱昊
  9. *
  10. */
  11. public interface Action {
  12. public ActionResult execute(HttpServletRequest req, HttpServletResponse resp)
  13. throws ServletException, IOException;
  14. }
介面中的execute方法是處理使用者請求的方法,所以它的兩個引數分別是HttpServletRequest和HttpServletResponse物件,到時候我們會在前端控制中通過反射建立Action,並呼叫execute方法,由於不同的Action子類通過重寫對execute方法給出了不同的實現版本,因此該方法是一個多型方法。execute方法的返回值是一個ActionResult物件,它的實現程式碼如下所示。


  
  1. package com.lovo.action;
  2. /**
  3. * Action執行結果
  4. * @author 駱昊
  5. *
  6. */
  7. public class ActionResult {
  8. private ResultContent resultContent;
  9. private ResultType resultType;
  10. public ActionResult(ResultContent resultContent) {
  11. this(resultContent, ResultType.Forward);
  12. }
  13. public ActionResult(ResultContent resultContent, ResultType type) {
  14. this.resultContent = resultContent;
  15. this.resultType = type;
  16. }
  17. /**
  18. * 獲得執行結果的內容
  19. */
  20. public ResultContent getResultContent() {
  21. return resultContent;
  22. }
  23. /**
  24. * 獲得執行結果的型別
  25. */
  26. public ResultType getResultType() {
  27. return resultType;
  28. }
  29. }


ActionResult類中的ResultContent代表了Action對使用者請求進行處理後得到的內容,它可以儲存一個字串表示要跳轉或重定向到的資源的URL,它也可以儲存一個物件來儲存對使用者請求進行處理後得到的資料(模型),為了支援Ajax操作,我們可以將此物件處理成JSON格式的字串。


  
  1. package com.lovo.action;
  2. import com.google.gson.Gson;
  3. /**
  4. * Action執行結束產生的內容
  5. * @author 駱昊
  6. *
  7. */
  8. public class ResultContent {
  9. private String url;
  10. private Object obj;
  11. public ResultContent(String url) {
  12. this.url = url;
  13. }
  14. public ResultContent(Object obj) {
  15. this.obj = obj;
  16. }
  17. public String getUrl() {
  18. return url;
  19. }
  20. public String getJson() {
  21. return new Gson().toJson(obj); // 這裡使用了Google的JSON工具類gson
  22. }
  23. }

ActionResult類中的ResultType代表了對使用者請求處理後如何向瀏覽器產生響應,它是一個列舉型別,程式碼如下所示。


  
  1. package com.lovo.action;
  2. /**
  3. * Action執行結果型別
  4. * @author 駱昊
  5. *
  6. */
  7. public enum ResultType {
  8. /**
  9. * 重定向
  10. */
  11. Redirect,
  12. /**
  13. * 轉發
  14. */
  15. Forward,
  16. /**
  17. * 非同步請求
  18. */
  19. Ajax,
  20. /**
  21. * 資料流
  22. */
  23. Stream,
  24. /**
  25. * 跳轉到向下一個控制器
  26. */
  27. Chain,
  28. /**
  29. * 重定向到下一個控制器
  30. */
  31. RedirectChain
  32. }
 
 

稍等,我們還需要一個工具類來封裝常用的工具方法。


  
  1. package com.lovo.util;
  2. import java.awt.Color;
  3. import java.text.DateFormat;
  4. import java.text.ParseException;
  5. import java.text.SimpleDateFormat;
  6. import java.util.ArrayList;
  7. import java.util.Date;
  8. import java.util.List;
  9. /**
  10. * 通用工具類
  11. * @author 駱昊
  12. *
  13. */
  14. public final class CommonUtil {
  15. private static final List<String> patterns = new ArrayList<>();
  16. private static final List<TypeConverter> converters = new ArrayList<>();
  17. static {
  18. patterns.add( "yyyy-MM-dd");
  19. patterns.add( "yyyy-MM-dd HH:mm:ss");
  20. }
  21. private CommonUtil() {
  22. throw new AssertionError();
  23. }
  24. /**
  25. * 將字串的首字母大寫
  26. */
  27. public static String capitalize(String str) {
  28. StringBuilder sb = new StringBuilder();
  29. if (str != null && str.length() > 0) {
  30. sb.append(str.substring( 0, 1).toUpperCase());
  31. if (str.length() > 1) {
  32. sb.append(str.substring( 1));
  33. }
  34. return sb.toString();
  35. }
  36. return str;
  37. }
  38. /**
  39. * 生成隨機顏色
  40. */
  41. public static Color getRandomColor() {
  42. int r = ( int) (Math.random() * 256);
  43. int g = ( int) (Math.random() * 256);
  44. int b = ( int) (Math.random() * 256);
  45. return new Color(r, g, b);
  46. }
  47. /**
  48. * 新增時間日期樣式
  49. * @param pattern 時間日期樣式
  50. */
  51. public static void registerDateTimePattern(String pattern) {
  52. patterns.add(pattern);
  53. }
  54. /**
  55. * 取消時間日期樣式
  56. * @param pattern 時間日期樣式
  57. */
  58. public static void unRegisterDateTimePattern(String pattern) {
  59. patterns.remove(pattern);
  60. }
  61. /**
  62. * 新增型別轉換器
  63. * @param converter 型別轉換器物件
  64. */
  65. 相關推薦

    Java Web定義MVC框架

    分享一個大神的人工智慧教程!http://blog.csdn.net/jiangjunshow 最近給學生講Java Web,希望他們能夠在學完這部分內容後自己實現一個MVC框架。但是突然發現百度上能搜尋到的靠譜的資料並不是很多,有些只是原理沒有程式碼實現,有些有程式碼實現但是

    杜鵬的個人部落格 Flex使用Blazeds與Java互動及定義物件轉換

    一、建立Flex與Java互動的工程。   本文中講到的互動是利用Blazeds的,因為這個是免費的,呵呵,我是窮人。   首先就是去下載Blazeds的壓縮包,這個可以從官網或者CSDN、JavaEye上下到。解壓縮這個包,將裡面的Blazeds.war解壓,後面建立工程時要使用。   在MyEclips

    Java定義註解Annotation

    一:簡介 開發中經常使用到註解,在專案中也偶爾會見到過自定義註解,今天就來探討一下這個註解是什麼鬼,以及註解的應用場景和如何自定義註解。 下面列舉開發中常見的註解 @Override:用於標識該方法繼承自超類, 當父類的方法被刪除或修改了,編譯器會提示錯

    簡單封裝定義MVC框架

    ddk dp2 hce gho pku vuex oier ont atrm 自定義Mvc框架結構及其使用方法 一,什麽是MVC框架 MVC框架全名是model(模型)controller(控制器)view(視圖文件)所構成的一種開發框架,是一種典型的軟件設計典範,用一種業

    定義控件(七):drawText()

    字體 相對 awt 除了 4條 nbsp pan ase span 比較基礎的一個方法。即繪制文本 使用如下: Paint paint = new Paint(); paint.setColor(Color.RED); // 紅色字體 paint.setS

    java web--定義jstl標簽

    存儲 使用 spl library 文件 api 設置 exceptio string 類 1、 自定義標簽 1). HelloWorld ①. 創建一個標簽處理器類: 實現 SimpleTag 接口.

    ideat使用struts2之定義MVC框架

    clu src pen mod files 文件導入 exc form over 今天我學習了自定義一個簡單的MVC框架,這個我們首先要知道什麽是MVC框架! MVC框架: MVC全名是Model View Controller,是模型(model)-視圖(view)-

    定義MVC框架之工具類-模型類

    else pri 數據庫連接 執行 field date http one www. 截止目前已經改造了5個類: ubuntu:通過封裝驗證碼類庫一步步安裝php的gd擴展 自定義MVC框架之工具類-分頁類的封裝 自定義MVC框架之工具類-文件上傳類 自定義MVC框

    定義轉場(一)

    assign pda 好的 led hint ext hid case delegate 前言 本文是我學習了onevcat的這篇轉場入門做的一點筆記。 今天我們來實現一個簡單的自定義轉場,我們先來看看這篇文章將要實現的一個效果圖吧: 過程詳解 熱身準備 我們先創建一

    Java執行緒池Executor框架

    Java的執行緒既是工作單元,也是執行機制。從JDK 5開始,把工作單元與執行機制分離開來。工作單元包括Runnable和Callable,而執行機制由Executor框架提供。 Executor框架簡介在HotSpot VM的執行緒模型中,Java執行緒(java.lang.Thread)被一對一對映為本

    Java線程池Executor框架

    keepalive cto 拒絕 cache task 委托 工作單元 shu keepaliv Java的線程既是工作單元,也是執行機制。從JDK 5開始,把工作單元與執行機制分離開來。工作單元包括Runnable和Callable,而執行機制由Executor框架提供。

    pyhanlp 停用詞與使用者定義詞典功能

    hanlp的詞典模式 之前我們看了hanlp的詞性標註,現在我們就要使用自定義詞典與停用詞功能了,首先關於HanLP的詞性標註方式具體請看HanLP詞性標註集。 其核心詞典形式如下: 自定義詞典 自定義詞典有多種新增模式,首先是展示的一個小例子,展示了詞彙的動態增加與強行插入,

    JVM堆記憶體管理與定義分配引數

    堆記憶體模型:   在Java中,堆被劃分成兩個不同的區域:新生代(Young),老年代(Old)。而Permanent屬於永久代(方法區),不屬於堆記憶體。新生代又被分為了三個區域:Eden,from  survivor,to survivor。這樣劃分的目的

    MySQL定義函式用法-複合結構定義變數/流程控制

    自定義函式 (user-defined function UDF)就是用一個象ABS() 或 CONCAT()這樣的固有(內建)函式一樣作用的新函式去擴充套件MySQL。 所以UDF是對MySQL功能的一個擴充套件 建立和刪除自定義函式語法: 建立UDF:   CREATE 

    定義LayoutManager的及其使用

    RecyclerView不斷的普及,越來越多的人使用來代替傳統的ListView,GridView等,為了跟進時代也要不斷的學習RecyclerView的相關知識,下面就來了解一下RecyclerView的LayoutManger。 Recycler RecyclerView內部有一個R

    在ubuntu16.04中安裝apache2+modsecurity以及定義WAF規則

    一、Modsecurity規則語法示例 SecRule是ModSecurity主要的指令,用於建立安全規則。其基本語法如下: SecRule VARIABLES OPERATOR [ACTIONS] VARIABLES 代表HTTP包中的標識項,規定了安全規則針對的物件。常見的

    《Android群英傳》學習筆記之Android控制元件架構與定義控制元件

    一、Android控制元件架構: 控制元件大致分為兩類:ViewGroup控制元件與View控制元件。View是繪製在螢幕上的使用者能與之互動的一個物件。而ViewGroup則是一個用於存放其他Vi

    MVC框架,為什麼要學習這些框架框架到底是什麼?

    部落格轉自這位大哥但是本人感覺甚好,記載一下...希望讀者不要辜負我Ctrl+C,,,Ctrl+V的辛苦,讀完會受益的。 現在許許多多的初學者和程式設計師,都在趨之若鶩地學習Web開發的寶典級框架:Struts2,Spring,Hibernate。似乎這些框架成為了一個

    Android中View定義XML屬性以及R.attr與R.styleable的區別

    為View新增自定義XML屬性 Android中的各種Widget都提供了很多XML屬性,我們可以利用這些XML屬性在layout檔案中為Widget的屬性賦值。 如下所示: <TextView android:layout_wi

    Android定義主題樣式(結合定義title欄講解)

    此篇部落格將總結主題樣式的自定義並且結合例項自定義title欄進行講解。為了方便閱讀,在此先寫明文章結構: 1.對android主題樣式的理解 (簡略結合系統自帶樣式的講解) 2.如何自定義主題樣式 (主要,有例子) 3.如何自定義titl