Home | 简体中文 | 繁体中文 | 杂文 | Search | ITEYE 博客 | OSChina 博客 | Facebook | Linkedin | 作品与服务 | Email

26.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设置为禁用状态

comments powered by Disqus