1. 程式人生 > >Java學習不走彎路教程(18 Web框架)

Java學習不走彎路教程(18 Web框架)

image tar 分享圖片 strong value doget 程序 aio size

Web框架

一. 前言
在前上一章教程中,我們實現了程序在Tomcat上的部署。
本章將在上一章的基礎上,進一步擴展程序。

註:
1.本文針對初學Java的同學訓練學習思路,請不要太糾結於細節問題。
2.本文旨在達到拋磚引玉的效果,希望大家擴展本例子,以學到更多知識的精髓。

學習本章需要準備的知識:
1.讀完本系列教程的前面章節。
2.理解Java註解

二. 步入正題
話不多說,大家自己理解,下面步入正題:

我們來做一個簡單的Web框架如下:
修改前:
技術分享圖片

修改後:
技術分享圖片

工程結構如下:
技術分享圖片

我們希望用一個普通的Java類而不是Servlet來處理Web請求,
比如如下的代碼:

 1 /**
 2  * 
 3  * 
@author http://www.java123.vip 4 * 5 */ 6 @Controller // 用@Controller註解表示這個類可以處理web請求 7 public class PersonController { 8 9 @Request(path="/person.do") // 請求路徑 10 public String query(@Parameter(name="personid")String personId) { //參數名 11 12 MyContainer container = MyContainer.getInstance();
13 PersonService personService = (PersonService)container.getObject(PersonService.class); 14 15 Person personResult = personService.getPerson(personId); 16 17 StringBuffer result = new StringBuffer(); 18 result.append("id:"+personResult.id); 19 result.append("<br/>username:"+personResult.username);
20 result.append("<br/>password:"+personResult.passwd); 21 22 return result.toString(); 23 } 24 25 }

引用的註解定義如下:

 1 /**
 2  * 
 3  * @author http://www.java123.vip
 4  *
 5  */
 6 @Target(value = { ElementType.TYPE })
 7 @Retention(value = RetentionPolicy.RUNTIME)
 8 public @interface Controller {
 9 
10 }
 1 /**
 2  * 
 3  * @author http://www.java123.vip
 4  *
 5  */
 6 @Target(value = { ElementType.PARAMETER })
 7 @Retention(value = RetentionPolicy.RUNTIME)
 8 public @interface Parameter {
 9 
10     String name();
11 
12 }
 1 /**
 2  * 
 3  * @author http://www.java123.vip
 4  *
 5  */
 6 @Target(value = { ElementType.METHOD })
 7 @Retention(value = RetentionPolicy.RUNTIME)
 8 public @interface Request {
 9 
10     String path();
11 
12 }

要把請求分發到這個普通的Java類上,我們需要在框架層處理這個映射:
首先,我們把所有的請求都放到一個Servlet中,然後通過這個Servlet來根據請求的路徑,去調用具體的業務邏輯方法。
修改web.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>fileview_web05</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
      <servlet-name>dispacherServlet</servlet-name>
      <servlet-class>vip.java123.fileview.fw.web.DispacherServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
      <servlet-name>dispacherServlet</servlet-name>
      <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

然後做一個DispacherServlet來做請求分發:

  1 /**
  2  * 
  3  * @author http://www.java123.vip
  4  *
  5  */
  6 public class DispacherServlet extends HttpServlet{
  7 
  8     private Map<String,ControllerInvoker> controllerMap = new HashMap<String,ControllerInvoker>();
  9     
 10     public DispacherServlet() {
 11         // load all controller
 12         String controllerPackage = "vip.java123.fileview.app.web";
 13         
 14         try {
 15             // 掃描controller包下面的所有類,並加載包含註解@Controller的類
 16             Class[] controllerClasses = ClassScaner.getClasses(controllerPackage);
 17             for(int i = 0; i < controllerClasses.length; i ++) {
 18                 Class controller = controllerClasses[i];
 19                 
 20                 // 判斷是否含有註解@Controller
 21                 if(controller.getAnnotation(Controller.class) != null) {
 22                     
 23                     // 生成新的Controller實例
 24                     Object obj = controller.newInstance();
 25                     
 26                     // 掃描所有的方法
 27                     Method[] methods = controller.getMethods();
 28                     for(int j = 0; j < methods.length; j ++) {
 29                         Method method = methods[j];
 30                         
 31                         // 加載含有@Request註解的方法
 32                         Request requestAnnotation = method.getAnnotation(Request.class);
 33                         if(requestAnnotation != null) {
 34                             
 35                             // 註解聲明的請求路徑
 36                             String path = requestAnnotation.path();
 37                             
 38                             // 做一個invoker,以便請求過來時調用
 39                             ControllerInvoker invoker = new ControllerInvoker();
 40                             invoker.path = path;
 41                             invoker.obj = obj;
 42                             invoker.method = method;
 43                             
 44                             // 處理@Parameter註解
 45                             List<String> parameterNameList = new ArrayList<String>();
 46                             Annotation[][] annotations = method.getParameterAnnotations();
 47                             for(int k = 0; k < annotations.length; k ++) {
 48                                 if(annotations[k].length > 0) {
 49                                     Parameter parameterAnnotaion = (Parameter)annotations[k][0];
 50                                     String parameterName = parameterAnnotaion.name();
 51                                     parameterNameList.add(parameterName);
 52                                 }
 53                             }
 54                             invoker.paramNames = new String[parameterNameList.size()];
 55                             for(int m = 0; m < parameterNameList.size(); m ++) {
 56                                 invoker.paramNames[m] = parameterNameList.get(m);
 57                             }
 58                             
 59                             // 將做好的invoker放入Map中,key為請求路徑
 60                             System.out.println("load controller:"+path);
 61                             controllerMap.put(path, invoker);
 62                         }
 63                     }
 64                 }
 65             }
 66             
 67         } catch (ClassNotFoundException e) {
 68             e.printStackTrace();
 69         } catch (IOException e) {
 70             e.printStackTrace();
 71         } catch (InstantiationException e) {
 72             e.printStackTrace();
 73         } catch (IllegalAccessException e) {
 74             e.printStackTrace();
 75         }
 76         
 77     }
 78     
 79     /**
 80      * 處理Get請求
 81      */
 82     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 83         // 獲得請求路徑
 84         String contextPath = request.getContextPath();
 85         String requestPath = request.getRequestURI();
 86         String path = requestPath.replace(contextPath, "");
 87         
 88         System.out.println("request:"+path);
 89         
 90         // 根據請求路徑獲得做好的invoker
 91         ControllerInvoker invoker = controllerMap.get(path);
 92         
 93         if(invoker != null) {
 94             // 根據請求的參數值設置invoker
 95             invoker.paramValues = new String[invoker.paramNames.length];
 96             for(int i = 0; i < invoker.paramNames.length; i ++) {
 97                 invoker.paramValues[i] = request.getParameter(invoker.paramNames[i]);
 98             }
 99             
100             // 調用invoker,並將結果寫到response中
101             String result = invoker.invokMethod();
102             response.getWriter().println(result);
103         }
104     }
105 
106 }

需要一個輔助類ControllerInvoker來支持:

 1 /**
 2  * 
 3  * @author http://www.java123.vip
 4  *
 5  */
 6 public class ControllerInvoker {
 7 
 8     public String path;
 9     public Object obj;
10     public Method method;
11     public String[] paramNames;
12     public String[] paramValues;
13     
14     // 調用制定的方法
15     public String invokMethod() {
16         try {
17             return (String)method.invoke(obj, paramValues);
18         } catch (IllegalArgumentException e) {
19             e.printStackTrace();
20         } catch (IllegalAccessException e) {
21             e.printStackTrace();
22         } catch (InvocationTargetException e) {
23             e.printStackTrace();
24         }
25         
26         return null;
27     }
28 }

三. 測試

啟動服務器:

技術分享圖片

向服務器請求person.html文件,在瀏覽器端輸入1,點query按鈕:
技術分享圖片

顯示查詢結果:

技術分享圖片

完整程序請大家從[這裏]下載

如有問題,大家來我的網站進行提問。
https://www.java123.vip/qa

版權聲明:本教程版權歸java123.vip所有,禁止任何形式的轉載與引用。

Java學習不走彎路教程(18 Web框架)