Home | 簡體中文 | 繁體中文 | 雜文 | 知乎專欄 | Github | OSChina 博客 | 雲社區 | 雲棲社區 | Facebook | Linkedin | 視頻教程 | 打賞(Donations) | About
知乎專欄多維度架構 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者”

35.3. 微信公眾平台開發

我看到網上很多人做法都是這樣實現的

if input = '天氣' {
	...
} else if(input = '飲食'){
	...
} else if(xxx){
....
} ....
....

switch (input){
	case '天氣':
		xxxx
	case '飲食':
		xxxx
	case xxxx
		xxxxx
		...
		...
	default:
		xxxx
}

		

稍微高級的做法是,定義一個數組,或者一個hashmap,或者使用資料庫實現key,value定義。然後判斷keyword 是否存在,如果存在就處理 key 所對應的 value。

這樣的做法會導致後期,極難維護,可讀性極差,增加一個需求,就增加一段代碼,新的代碼會影響整個程序。國內開發者很喜歡使用if來拼接一個sql語句,這是坑爹的寫法。

下面談談我思路,我將採用傳統的MVC模式,

微信  ---post xml---> 入口URL
                      |
                      V
              +----------------+
              | Router         |     這裡是路由映射,用戶輸入keyword 映射到 controller 上,
              +----------------+
                      |
                      V
              +----------------+
              | Controller     |     Controller 會加載請求的class 做一系列處理,包括數據模型處理,視圖渲染,
              +----------------+
                      |
                      V
+--------------- Application -------------------+
| class xxx | class xxx | class xxx | class xxx |
+-----------------------------------------------+
                      |
                      V
               +--------------+
               | Model        |     處理數據
               +--------------+
                      |
                      V
               +--------------+
               | View         |     最後呈現xml。 微信會通過返回的xml將消息推送給用戶
               +--------------+
		

任務處理圖,程序應該有一個入口,多個出口,而不是層層循環,層層判斷。一半來說for/if/while等等 超過三層,程序閲讀就會非常困難。

		
                               .---> 終結
                              /                        .-->  終結
                             /            .--> 終結               /
                            /            /           /
微信 ---> Post XML ---> 介面程序 --------------------------------------------->  - 終結
                            \      \            \
                             \      `---> 終結               \
                              \                   `--->  終結
                               `--->  終結
		
		

實現菜單結構

		
<menu>
	<menuitem>
		<item>[1] 天氣 </item>
		<controller></controller>
	<menuitem>
	<menuitem>
		<item>[2] 新聞 </item>
		<controller></controller>
	<menuitem>
	<menuitem>
		<item>[3] 飲食 </item>
		<submenu>
			<menuitem>
				<item>[31] 肯德基 </item>
				<controller></controller>
			</menuitem>
			<menuitem>
				<item>[32] 麥當勞 </item>
				<controller></controller>
			</menuitem>
		</submenu>
	<menuitem>
</menu>
		
		

XML 不太靈活,下面是資料庫方案

CREATE TABLE menu
(
  id serial NOT NULL,
  mid integer, -- mid 欄位
  menuitem character varying NOT NULL, -- menuitem 欄位
  controller character varying, -- 映射控製器
  submenu_id integer, -- 子菜單ID
  status boolean DEFAULT true, -- 啟用,禁用狀態
  ctime timestamp without time zone DEFAULT now(), -- 創建時間
  mtime timestamp without time zone DEFAULT now(), -- 修改時間
  CONSTRAINT id PRIMARY KEY (id),
  CONSTRAINT submenu_id FOREIGN KEY (submenu_id)
      REFERENCES menu (mid) MATCH SIMPLE
      ON UPDATE RESTRICT ON DELETE RESTRICT,
  CONSTRAINT mid UNIQUE (mid)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE menu
  OWNER TO dba;
COMMENT ON TABLE menu
  IS 'menu table';
COMMENT ON COLUMN menu.mid IS 'mid 欄位';
COMMENT ON COLUMN menu.menuitem IS 'menuitem 欄位';
COMMENT ON COLUMN menu.controller IS '映射控製器';
COMMENT ON COLUMN menu.submenu_id IS '子菜單ID';
COMMENT ON COLUMN menu.status IS '啟用,禁用狀態';
COMMENT ON COLUMN menu.ctime IS '創建時間';
COMMENT ON COLUMN menu.mtime IS '修改時間';
		

數據

INSERT INTO "menu" ("mid", "menuitem", "controller", "submenu_id", "status") VALUES (1, '天氣', 'weather', NULL, true);
INSERT INTO "menu" ("mid", "menuitem", "controller", "submenu_id", "status") VALUES (2, '新聞焦點', NULL, NULL, true);
INSERT INTO "menu" ("mid", "menuitem", "controller", "submenu_id", "status") VALUES (21, '國內新聞', 'news/1', 2, true);
INSERT INTO "menu" ("mid", "menuitem", "controller", "submenu_id", "status") VALUES (22, '國際新聞', 'news/2', 2, true);
		

這裡id欄位可有可無,實際上mid可以設置為主鍵,考慮到中國人習慣性才增加了id. submenu_id外鍵指向了mid 而沒有指向id. 因為id是serial會順序增加,會使整個菜單排序混亂。這樣有也缺點,就是菜單項不能超過十個。

接下來實現路由到控製器的分發。

關註:顯示菜單
[1] 天氣
[2] 新聞焦點

發送:1
取出weather, 實例化 weather 類 執行index() 方法。 返回天氣預報
$weather = new Weather()

發送:2
[21] 國內新聞
[22] 國際新聞

發送:21
實例化 news 類,構造方法參數指定為 1 返回國內新聞列表
$news = new News(1);
		

當 submenu_id 為 NULL 時表示他有子菜單,如果非 NULL 就取controller參數。

接下來要做的就是需求增加,只需要在menu表中增加一個記錄,然後開發對應的controller. 有一些不使用的項目隨時可以將status設置為禁用狀態