1. 程式人生 > >Java Servlet開發的輕量級MVC框架最佳實踐

Java Servlet開發的輕量級MVC框架最佳實踐

在Servlet開發的工程實踐中,為了減少過多的業務Servlet編寫,會採用構建公共Servlet的方式,通過反射來搭建輕量級的MVC框架,從而加快應用開發。

關於Servlet開發的基礎知識,請看:JavaWeb開發之詳解Servlet及Servlet容器

前後端互動的基本形式

一般來說,前端提交資料請求有三種基本方式,分別是表單、連結和Ajax

1. 按鈕

1 <form action="/BaseServlet/ServletDemo02?method=addStu" method="post">
2     使用者<input type="text" name
="username"/><br/> 3 <button>提交</button> 4 </form>

2. 連結

<a href="/BaseServlet/ServletDemo02?method=delStu">刪除學生</a><br/>

3. Ajax

1 <button onclick="fn()">按鈕</button>
2 <script>
3 function fn(){
4     $.post("/BaseServlet/ServletDemo02
",{"method":"checkStu","user":"tom"},function(data){ 5 alert(data); 6 }); 7 }

在Servlet開發的語境中,它們的共同點都是:指定處理的Servlet類路徑(在web.xml中指定)以及附帶在請求中的“method”引數

通過呼叫request引數匹配業務處理邏輯

前端按照以上方法發起請求,Servlet容器就會把請求交給對應的Servlet處理,並且附帶上形如 method=delStu 的引數,利用這個原理,就可以構建一個基礎Servlet類,用來優化開發:

 1 protected
void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 2 //獲取客戶端提交到服務端的method對應的值 3 String md=request.getParameter("method"); 4 //定義變數,存放功能執行完畢之後要轉發的路徑 5 String path=null; 6 7 //通過判斷md中不同的內容來決定本次功能 8 if("addStu".equals(md)){ 9 path=addStu(request, response); 10 }else if("delStu".equals(md)){ 11 path=delStu(request, response); 12 }else if("checkStu".equals(md)){ 13 path=checkStu(request, response); 14 }else if("".equals(md)){ 15 16 } 17 if(null!=path){ 18 //服務端的請求轉發 19 request.getRequestDispatcher(path).forward(request, response); 20 } 21 } 22 23 24 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 25 doGet(request, response); 26 } 27 28 protected String addStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 29 System.out.println("新增學生"); 30 return "/test.html"; 31 32 } 33 protected String delStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 34 System.out.println("刪除學生"); 35 return "/test.html"; 36 37 } 38 protected String checkStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 39 System.out.println("檢查學生"); 40 response.getWriter().println("DDDDDD"); 41 return null; 42 }

以上的Servlet對請求進行了處理,通過獲取index.html的請求,最後請求轉發至目標頁面,其核心思想是:

1. 提取request的method引數的值;

2. 定義變數,儲存請求轉發的路徑;

3. 通過判斷method引數中的值的內容,來決定呼叫哪個業務功能。

4. 完成業務功能後,使用請求轉發處理

通過反射匹配業務處理邏輯

當業務量多的時候,以上實踐仍是不夠,此時比較好的方式就是採用反射。

 1 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 2         doGet(request, response);
 3     }
 4     
 5     public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 6         //獲取客戶端提交到服務端的method對應的值
 7         String md=request.getParameter("method");
 8         //定義變數,存放功能執行完畢之後要轉發的路徑
 9         String path=null;
10         //獲取到當前位元組碼物件(ServletDemo02.class在記憶體中物件)
11         Class<? extends ServletDemo02> clazz = this.getClass();
12         try {
13             //獲取clazz上名稱為md, 引數為HttpServletRequest和HttpServletResponse的方法
14             Method method=clazz.getMethod(md, HttpServletRequest.class,HttpServletResponse.class);
15             if(null!=method){
16                 //呼叫找到的方法
17                 path=(String)method.invoke(this, request,response);
18             }
19             if(null!=path){
20                 //服務端的轉發
21                 request.getRequestDispatcher(path).forward(request, response);
22             }
23         } catch (Exception e) {
24             e.printStackTrace();
25         }     
26         
27     }
28 
29     public String addStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
30         System.out.println("新增學生");
31         return "/test.html";
32         
33     }
34     public String delStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
35         System.out.println("刪除學生");
36         return "/test.html";
37         
38     }
39     public String checkStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
40         System.out.println("檢查學生");
41         response.getWriter().println("DDDDDD");
42         return null;
43     }

1. 提取request的method引數的值;

2. 定義變數,儲存請求轉發的路徑;

3. 獲取到當前Servlet物件在記憶體中的Class物件

4. 獲取Class物件上名稱為md, 引數為HttpServletRequest和HttpServletResponse的方法

5. 根據是否返回方法物件,呼叫業務功能並使用請求轉發處理

Java HttpServlet的父類GenericServlet,就是通過這個方法來調取HttpServlet的doGet或doPost方法的。

最佳實踐

在實踐開發中,一般會搭建一個BaseServlet,繼承了HttpServlet並重寫其Service方法,通過反射來找到業務功能子類對應的業務方法。

 1 public class BaseServlet extends HttpServlet {
 2     private static final long serialVersionUID = 12197442526341123L;
 3        
 4     @Override
 5     protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 6         System.out.println("service.....");
 7         //獲取客戶端提交到服務端的method對應的值
 8         String md=request.getParameter("method");
 9         //定義變數,存放功能執行完畢之後要轉發的路徑
10         String path=null;
11         //獲取到當前位元組碼物件(ServletDemo02.class在記憶體中物件)
12         Class<? extends BaseServlet> clazz = this.getClass();
13         try {
14             //獲取clazz上名稱為md方法
15             Method method=clazz.getMethod(md, HttpServletRequest.class,HttpServletResponse.class);
16             if(null!=method){
17                 //呼叫找到的方法
18                 path=(String)method.invoke(this, request,response);
19             }
20             if(null!=path){
21                 //服務端的轉發
22                 request.getRequestDispatcher(path).forward(request, response);
23             }
24         } catch (Exception e) {
25             e.printStackTrace();
26         }
27     }
28 
29 }

而業務功能子類,則繼承BaseServlet,專注於業務邏輯的開發

 1 public class ServletDemo03 extends BaseServlet {
 2 
 3     private static final long serialVersionUID = 11248215356242123L;
 4     
 5     public ServletDemo03() {
 6         System.out.println("沒有引數的建構函式");
 7     }
 8     
 9     public String addStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
10         System.out.println("新增學生");
11         return "/test.html";
12         
13     }
14     public String delStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
15         System.out.println("刪除學生");
16         return "/test.html";
17         
18     }
19     public String checkStu(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
20         System.out.println("檢查學生");
21         response.getWriter().println("DDDDDD");
22         return null;
23     }
24 
25 }