MVC框架浅析(基于PHP)
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
一.MVC概念
MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式,它们各自处理自己的任务:
MVC 模式同时提供了对 HTML、CSS 和 JavaScript 的完全控制。
Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。
通常模型对象负责在数据库中存取数据。
View(视图)是应用程序中处理数据显示的部分。
通常视图是依据模型数据创建的。
Controller(控制器)是应用程序中处理用户交互的部分。
通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
MVC 分层有助于管理复杂的应用程序,因为您可以在一个时间内专门关注一个方面。例如,您可以在不依赖业务逻辑的情况下专注于视图设计。同时也让应用程序的测试更加容易。
MVC 分层同时也简化了分组开发。不同的开发人员可同时开发视图、控制器逻辑和业务逻辑。
有很多程序员往往认为MVC是一种设计模式。实际上MVC是一种框架模式。框架通常是代码重用,而设计模式是设计重用,架构则介于两者之间,部分代码重用,部分设计重用,有时分析也可重用。
简而言之:框架是大智慧,用来对软件设计进行分工;设计模式是小技巧,对具体问题提出解决方案,以提高代码复用率,降低耦合度。
二.MVC理解
面向对象的思维
获取和描述系统的用户需求;
识别角色和用例,画UseCase;
根据功能从用例图中找三种类型类:实体类、边界类和控制类;将所有找到的三种类集中综合在一起得到三大模型:实体模型、视图模型、逻辑模型。实际上对应着MVC。进而进行WEB建模。
三.MVC实践
MVC是一种框架模式,只有在实例中才能更好的理解MVC。本文基于ThinkPHP3.2.3的MVC框架,实现一个简单的留言板系统。
1. ThinkPHP3.2.3
ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架,遵循Apache2开源协议发布,从Struts结构移植过来并做了改进和完善,同时也借鉴了国外很多优秀的框架和模式,使用面向对象的开发结构和MVC,融合了Struts的思想和TagLib(标签库)、RoR的ORM映射和ActiveRecord模式。
ThinkPHP可以支持windows/Unix/Liunx等服务器环境,支持MySql、PgSQL、Sqlite以及PDO等多种数据库。作为一个整体开发解决方案,它包含了底层架构、兼容处理、基类库、数据库访问层、模板引擎、缓存机制、插件机制、角色认证、表单处理等常用的组件,并且对于跨版本、跨平台和跨数据库移植都比较方便。
ThinkPHP3.2.3是最新版本. 获取地址:http://www.thinkphp.cn/,(初学建议下载完版)。
ThinkPHP需要集成环境,这里用Wampserver。Wamp就是Windows Apache Mysql PHP集成安装环境,即在window下的apache、php和mysql的服务器软件。PHP扩展、Apache模块,开启/关闭鼠标点点就搞定,再也不用亲自去修改配置文件了,WAMP它会去做。
获取地址:http://www.wampserver.com/en/
2. 需求分析和原型设计
2.1 系统需求
用户进行注册,然后登陆系统,进行留言。
2.2 原型设计
Axure RP 能帮助网站需求设计者,快捷而简便的创建 基于目录组织的原型文档、功能说明、交互界面以及带注释的wireframe网页,并可自动生成用于演示的网页文件和word文档,以提供演示与开发。
获取地址:http://www.axure.com/
2.2.1 登陆页面:
2.2.2 注册页面:
2.2.3 系统页面:
2.3 功能设计
注册模块:注册用户
登录模块:登录 退出
留言模块:提交留言信息 显示留言信息
2.4 数据库设计
2.4.1 分析:
用户表:用户名、密码、性别
留言表:留言题目、留言内容、附件名、留言时间
用户表与留言表之间是一对多的关系,需要在留言表中设置外键。
2.4.2 设计:
用户表(tp_user)
|
字段 |
类型 |
notnull |
默认值 |
备注 |
|
id |
Int |
notnull |
主键 自增 |
|
|
username |
varchar(30) |
‘’ |
用户名 |
|
|
password |
char(32) |
‘’ |
密码 |
|
|
sex |
tyint |
notnull |
1 |
性别:1代表男 0 代表0 |
留言表(tp_message)
|
字段 |
类型 |
notnull |
默认值 |
备注 |
|
id |
Int |
notnull |
主键 自增 |
|
|
title |
varchar(60) |
‘’ |
题目 |
|
|
content |
test |
‘’ |
内容 |
|
|
filename |
varchar(30) |
notnull |
1 |
附件名 |
|
time |
int |
时间:时间戳格式 |
||
|
uid |
int |
外键:用户表中的id |
3. ThinkPHP设计思想与目录文件
在Wampserver安装地址下的www文件夹下新建项目think_message。将ThinkPHP_3.2.3_full.zip解压放到think_message中。
在浏览器中,打开项目think_message,ThinkPHP会自动在Application文件夹下创建Home文件夹,它是前台模块;同样我们可以在Application下创建后台模块,本留言系统暂时不建立后台模块。到此ThinkPHP环境基本搭建完毕。
3.1 解压缩可以看到初始的目录结构如下:
3.2 ThinkPHP内核 框架设计
3.3 模块设计
每个模块是相对独立的,其目录结构如下:
以后我们主要在Controller、Model和View三个文件下实施项目,即MVC。
4. 实施项目
本项目用sublime编辑器,进行代码编辑。
4.1 打开phpmyadmin,建立数据库messge
新建tp_user表和tp_message表,按照数据库设计对应键入。注意:整理项Collation选择 utf8- general-ci。
4.2 连接数据库
Application->Common->Conf下的config.php,键入一下代码:
//数据库配置信息 \'DB_TYPE\' => \'mysql\', // 数据库类型 \'DB_HOST\' => \'localhost\', // 服务器地址 \'DB_NAME\' => \'message\', // 数据库名 \'DB_USER\' => \'root\', // 用户名 \'DB_PWD\' => \'\', // 密码 \'DB_PORT\' => 3306, // 端口 \'DB_PREFIX\' => \'tp_\', // 数据库表前缀 \'DB_CHARSET\'=> \'utf8\', // 字符集
4.3 编码
在根目录下Public下建立Css、Js、Images和Uploads四个文件夹,分别用于存储系统的css代码、js代码、系统所用的图片资源和用户上传的文件资源。
根据功能设计,我们首先在Application->Home->Controller,建立三个控制器:RegisterController.class.php、LoginController.class.php、MessageController.class.php;以及建立IndexController.class.php控制器,系统默认进入的控制器。以后有需要我们再添加。控制器里面是函数,处理不同逻辑需求。
根据所建控制器及要显示的页面,在Application->Home->View下,分别创建Index(系统页面)、Register(注册页面)和Login(登陆页面)文件夹,用于原型设计的三个页面显示。
4.3.1 注册
功能:实现用户注册
V
注册需要显示注册页面,我们在Home->View->Register文件夹下创建reg.html用于显示注册页面。代码如下:
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>注册</title> <load href="__PUBLIC__/Css/Home/reg.css" /> <load href="__PUBLIC__/Js/jquery.js"/> <load href="__PUBLIC__/Css/basic.css" /> <script> $(function(){ var error=new Array(); $(\'input[name="username"]\').blur(function(){ var username=$(this).val(); $.get(\'__URL__/checkName\',{\'username\':username},function(data){ if(data==\'不允许\'){ error[\'username\']=1; $(\'input[name="username"]\').after(\'<p id="umessage" style="color:red">该用户名已经注册</p>\'); }else{ error[\'username\']=0; $(\'#umessage\').remove(); } }); }); //提交表单 $(\'img.register\').click(function(){ if(error[\'username\']==1){ return false; }else{ $(\'form[name="myForm"]\').submit(); } }); }); </script> </head> <body> <form action=\'__URL__/doReg\' method=\'post\' name=\'myForm\'> 用 户 名:<input type=\'text\' name=\'username\'/><br/> 密 码:<input type=\'password\' name=\'password\'/><br/> 确认密码:<input type=\'password\' name=\'repassword\'/><br/> 性 别:<input type=\'radio\' name=\'sex\' value=\'1\' class=\'radio\'/>男 <input type=\'radio\' name=\'sex\' value=\'0\' class=\'radio\'/>女<br/> 验 证 码:<input type=\'text\' name=\'code\'/> <img src=\'__MODULE__/Public/code\' onclick="this.src=this.src+\'?\'+Math.random()"/> <br/> <img src=\'__PUBLIC__/Images/register.gif\' class=\'register\'/> <img src=\'__PUBLIC__/Images/reset.gif\' class=\'reset\'/> </form> </body> </html>
C
RegisterController.class.php控制器代码如下:
<?php namespace Home\Controller; use Think\Controller; class RegisterController extends Controller { //显示注册页面 public function reg(){ $this->display(); } //检查用户是否注册过 public function checkName(){ $username=$_GET[\'username\']; $user=M(\'User\'); $where[\'username\']=$username; $count=$user->where($where)->count(); if($count){ echo \'不允许\'; }else{ echo \'允许\'; } } //注册 public function doReg(){ $user=D(\'User\'); if(!$user->create()){ $this->error($user->getError()); } $lastId=$user->add(); if($lastId){ $this->redirect(\'Index/index\'); }else{ $this->error(\'用户注册失败\'); } } } ?>
建立了PublicController.class.php控制器,设置验证码的属性。代码如下:
<?php namespace Home\Controller; use Think\Controller; class PublicController extends Controller { public function code(){ $Verify = new \Think\Verify(); $Verify->fontSize = 16; $Verify->length = 4; $Verify->imageW = 130; $Verify->imageH = 30; $Verify->entry(); } } ?>
M
前台的验证只是提供用户体验,安全还是要后台进行验证。TinkPHP实现自动验证,在Home->View->Model下,新建UserModel.class.php模型,进行自动验证。代码如下:
<?php namespace Home\Model; use Think\Model; class UserModel extends Model{ protected $_validate=array( array(\'code\',\'require\',\'验证码必须填写!\'), array(\'code\',\'checkCode\',\'验证码错误!\',0,\'callback\',1), array(\'username\',\'require\',\'用户必须填写!\'), array(\'username\',\'\',\'用户已经存在\',0,\'unique\',1), array(\'username\',\'/^\w{6,}$/\',\'用户名必须6个字母以上\',0,\'regex\',1), array(\'repassword\',\'password\',\'确认密码不正确\',0,\'confirm\'), ); protected function checkCode($code){ function check_verify($code, $id = \'\'){ $verify = new \Think\Verify(); return $verify->check($code, $id); } if(!check_verify($code,$id = \'\')){ return false; }else{ return true; } } } ?>
4.3.2 登陆
功能:实现用户登陆
V
登陆页面需要显示,我们在Home->View->Login文件夹下创建login.html用于显示注册页面。代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Login</title> <load href="__PUBLIC__/Css/basic.css" /> <load href="__PUBLIC__/Css/Home/login.css" /> <load href="__PUBLIC__/Js/jquery.js"/> <script> $(function(){ $(\'img[title="login"]\').click(function(){ $(\'form[name="myForm"]\').submit(); }); $(\'img[class="register"]\').click(function(){ window.location=\'__APP__/Home/Register/reg\'; }); }); </script> </head> <body> <form action=\'__URL__/doLogin\' method=\'post\' name=\'myForm\'> 用户名:<input type=\'text\' name=\'username\'/><br/> 密 码:<input type=\'password\' name=\'password\'/><br/> 验证码:<input type=\'text\' name=\'code\'/> <img src=\'__MODULE__/Public/code\' onclick="this.src=this.src+\'?\'+Math.random()"/><br/> <img src=\'__PUBLIC__/Images/login.gif\' title=\'login\' class=\'submit\'/> <img src=\'__PUBLIC__/Images/register.gif\' class=\'register\'/> </form> </body> </html>
C
LoginController.class.php控制器代码如下:
<?php namespace Home\Controller; use Think\Controller; class LoginController extends Controller { //显示登陆页面 public function index(){ $this->display(); } public function doLogin(){ //接受值 //判断用户在数据库中是否存在 //存在 允许登录 //不存在 显示错误信息 $username=$_POST[\'username\']; $password=$_POST[\'password\']; $code=$_POST[\'code\']; function check_verify($code, $id = \'\'){ $verify = new \Think\Verify(); return $verify->check($code, $id); } if(!check_verify($code,$id = \'\')){ $this->error(\'验证码输入错误!\'); } $user=M(\'User\'); $where[\'username\']=$username; $where[\'password\']=$password; $arr=$user->field(\'id\')->where($where)->find(); if($arr){ $_SESSION[\'username\']=$username; $_SESSION[\'id\']=$arr[\'id\']; $this->success(\'用户登录成功\',U(\'Index/index\')); }else{ $this->error(\'该用户不存在\'); } } } ?>
4.3.3 系统页面
功能:实现用户用户留言
V
系统页面使用frameset将整个页面分为3部分top,left,right,我们在Home->View->Index文件夹下创建index.html、top.html、left.html,right.html。代码如下:
index.html。代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Index</title> </head> <frameset rows=\'20%,*\'> <frame src=\'__URL__/top\' name=\'top\'/> <frameset cols=\'50%,50%\'> <frame src=\'__URL__/left\' name=\'left\'/> <frame src=\'__URL__/right\' name=\'right\'/> </frameset> </frameset> </html>
top.html,用于显示欢迎。代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>top</title> </head> <body> <p>欢迎你 <strong>{$Think.session.username}</strong> !<a href=\'__APP__/Home/Login/doLogout\' target=\'_top\'>退出</a></p> <h1 align="center">ThinkPHP留言板系统</h1> </body> </html>
left.html,用于显示所有的留言内容。代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Left</title> </head> <body> <foreach name=\'list\' item=\'vo\'> 留言题目:{$vo.title}<br/> <p>留言内容:</p>{$vo.content}<br/> 附件名:{$vo.filename}<br/> {$vo.username} {$vo.time|date=\'Y/m/d H:i:s\',###}<br/> <hr/> </foreach> {$show} </body> </html>
right.html,用于提交留言。代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Right</title> </head> <body> <form action=\'__MODULE__/Message/doMess\' method=\'post\' enctype=\'multipart/form-data\'> 留言题目:<input type=\'text\' name=\'title\'/><br/> 留言内容:<textarea name=\'content\'></textarea><br/> 附 件:<input type=\'file\' name=\'filename\'/><br/> <input type=\'submit\' value=\'提交留言\'/> </form> </body> </html>
C
IndexController.class.php控制器,用于页面的整体显示。代码如下:
<?php namespace Home\Controller; use Think\Controller; class IndexController extends CommonController { public function index(){ $this->display(); } public function top(){ $this->display(); } public function left(){ $message=D(\'Message\'); $count=$message->count();//获取数据的总数 $Page = new \Think\Page($count,3);// 实例化分页类 传入总记录数和每页显示的记录数(3) $show = $Page->show();// 分页显示输出 $arr=$message->relation(true)->order(\'time desc\')->limit($Page->firstRow.\',\'.$Page->listRows)->select(); $this->assign(\'list\',$arr); $this->assign(\'show\',$show); $this->display(); } public function right(){ $this->display(); } } ?>
MessageController.class.php控制器,用于留言的逻辑控制。代码如下:
<?php namespace Home\Controller; use Think\Controller; class MessageController extends Controller { public function doMess(){ $upload = new \Think\Upload();// 实例化上传类 $upload->rootPath = \'./Public/Uploads/\';//设置附件上传目录 $info = $upload->upload(); if(!$info) {// 上传错误提示错误信息 $this->error($upload->getError()); }else{// 上传成功 获取上传文件信息 foreach($info as $file){ // $savename=$file[\'savepath\'].$file[\'savename\']; $savename=$file[\'savename\']; } } $message=D(\'Message\'); $message->create(); $message->filename=$savename; // $message->time=time(); // $message->uid=$_SESSION[\'id\']; $lastId=$message->add(); if($lastId){ $this->success(\'留言成功\'); }else{ $this->error(\'留言失败\'); } } } ?>
M
TinkPHP实现自动完成,并实现tp_user表和tp_messgae表的关联取字段值,在Home->View->Model下,新建MessageModel.class.php模型,进行自动验证。代码如下:
<?php namespace Home\Model; use Think\Model\RelationModel; class MessageModel extends RelationModel{ protected $_auto=array( array(\'time\',\'time\',1,\'function\'), array(\'uid\',\'getId\',1,\'callback\'), ); protected $_link=array( \'User\'=> array( \'mapping_type\' => self::BELONGS_TO, \'class_name\'=>\'User\', \'foreign_key\'=>\'uid\', \'mapping_name\'=>\'user\', \'mapping_fields\'=>\'username\', \'as_fields\'=>\'username\', ), ); protected function getId(){ return $_SESSION[\'id\']; } } ?>
为了网站安全
必须进行登录才能进入任何一个页面,添加CommonController.class.php控制器。代码如下:
<?php namespace Home\Controller; use Think\Controller; class CommonController extends Controller { Public function _initialize(){ // 初始化的时候检查用户权限 if(!isset($_SESSION[\'username\']) || $_SESSION[\'username\']==\'\'){ $this->redirect(\'Login/login\'); } } } ?>
最终的文件目录如下:
至此基于PHP的MVC思想建立的留言系统已完成。
四.结束
MVC框架模式对项目的效率和可重用是至关重要的。当然在开发时我们应该灵活的应用MVC。也有新的框架模式不断涌现,相互参考才是最重要的。
留言系统源代码:https://github.com/jingwhale/mvc-php-messagesystem。
完
转载需注明转载字样,标注原作者和原博文地址。