一:需求分析
ThinkPHP(3.2.3完整版)了解:mvc开发框架.
1.主目录结构:
index.php访问入口配置文件
Application应用目录里面放的是每个模块文件。
Public资源文件目录,里面存放的是css,js,image等静态文件
ThinkPHP里面是框架的核心内容
2:ThinkPHP目录
Common存放的函数,在任何地方都可以直接使用,所以是公共函数目录
Conf里面是核心配置目录
thinkphp.php是框架入口文件,其它目录就不再深入了解了。
结合Thinkphp文档学习。
3.框架的运行原理
首先运行项目时会先到index.php入口配置文件.
进入入口文件首先 require './ThinkPHP/ThinkPHP.php'; 这样就会加载Thinkphp目录下的核心内容功能。
第一次执行这个项目后Application目录(一开始里面没内容)下会自动生成这三个目录。Common(公用目录),Home目录是模块目录。应用模块下的目录Common公共函数模块,Conf配置模块,Controller(实现业务模块)控制器模块,Model模型模块,View视图模块。
数据库:(需要索引的字段要创建索引)
cms_admin(后台用户表):admin_id(主键),username(创建索引),password,lastloginip,lastlogintime,email,realname,status;
cms_menu(菜单表):menu_id(主键),name,parentid(创建索引),m,c,f,listorder(创建索引),status,type.
cms_news(文章表主表):news_id.........等
cms_news_content(文章详情表):id,......等----主要存放文章主表的文章内容。
cms_position(推荐位表):id,name,status,descripation,createtime,update_time等
cms_postion_content(推荐位详情表):id,postion_id,title,thumb,url,news_id,listorder,status...等----主要存放推荐位里面存放的文章内容。
根据自己的需要设计文章内容。
后台管理系统:
在Application下创建目录Admin:
首先创建后台登录url:localhost/thinkphp/index.php?m=admin&c=login&f=index
提交按钮的表单内容:
上面要记得引入这些js文件才能实现对应的逻辑。__PUBLIC__指的是public目录。
dialog.js的内容为:
var dialog = {
// 错误弹出层
error: function(message) {
layer.open({
content:message,
icon:2,
title : '错误提示',
});
},
//成功弹出层
success : function(message,url) {
layer.open({
content : message,
icon : 1,
yes : function(){
location.href=url;
},
});
},
// 确认弹出层
confirm : function(message, url) {
layer.open({
content : message,
icon:3,
btn : ['是','否'],
yes : function(){
location.href=url;
},
});
},
//无需跳转到指定页面的确认弹出层
toconfirm : function(message) {
layer.open({
content : message,
icon:3,
btn : ['确定'],
});
},
}
login.js的内容为:
/**
* 前端登录业务类
* @author singwa
*/
var login = { //声明login类 ,方法check:function(){....}
check : function() {
// 获取登录页面中的用户名 和 密码
var username = $('input[name="username"]').val();
var password = $('input[name="password"]').val();
if(!username) {
dialog.error('用户名不能为空'); //弹出窗口,一般我们使用alter,这里对弹出做了美化.使用Layer(网)layer.layui.cpm
}在Controller创建控制器LoginController.class.php文件内容为:
namespace Admin\Controller; //声明类的命名空间通过路径加载类
use Think\Controller; //控制器需要继承的父类引入
class LoginController extends Controller {
public function index(){ //引入方法名index
if(session('adminUser')){//检查session 判断用户是否已经登陆了,如果未登录回到登录页面。如果登录跳转到后台页面
$this->redirect('/thinkphp/admin.php?c=index');
//这里也可以写/thinkphp/index.php?m=admin&c=index&a=index
}}
//getMd5Password是Commont公共函数写的MD5加密函数。
if($ret['password']!=getMd5Password($password)){}
//登录后更新登录时间
D('Admin')->updateByAdminId($ret['admin_id'],array('lastlogintime'=>time()));}
show函数的编写 (在公共模块下编写)
function show($status,$message,$data=array()){ //传入状态 信息 数组默认空数组
$result=array( //result数组对应信息编写。
'status'=>$status,
'message'=>$message,
'data'=>$data,
);
exit(json_encode($result));//json数据格式返回前台。
}
配置文件db.php(因为数据库是前后台都要访问的所以写在Common目录下,db.php是配置数据的配置文件)
return array(
'DB_TYPE'=>'mysql',
'DB_HOST'=>'127.0.0.1',
'DB_USER'=>'root',
'DB_PWD'=>'root',
'DB_PORT'=>3306,
'DB_NAME'=>'singcms',
'DB_CHARSET'=>'utf8',
'DB_PREFIX'=>'cms_',//数据表前缀
);
?>
配置文件config.php
return array(
//'配置项'=>'配置值'
'URL_CASE_INSENSITIVE'=>true,
'URL_MODEL'=>0,
'LOAD_EXT_CONFIG'=>'db', //上面配置的数据库配置文件加载进来。
'MD5_PRE'=>'sing_cms',
'HTML_FILE_SUFFIX'=>'.html',
);
Common模块下创建Model文件夹(操作数据库)
namespace Common\Model;
use Think\Model;
/**
* 用户组操作
* @author singwa
*/
class AdminModel extends Model {
private $_db = '';
//构造函数
public function __construct() {
$this->_db = M('admin');
}
//根据用户名查找用户下面根据对应函数名了解其中的含义
public function getAdminByUsername($username='') {
$res = $this->_db->where(array(
'username'=>$username,
'status'=>1,
))->find();
return $res;
}
public function getAdminByAdminId($adminId=0) {
$res = $this->_db->where('admin_id='.$adminId)->find();
return $res;
}
public function updateByAdminId($id, $data) {
if(!$id || !is_numeric($id)) {
throw_exception("ID不合法");
}
if(!$data || !is_array($data)) {
throw_exception('更新的数据不合法');
}
return $this->_db->where('admin_id='.$id)->save($data); // 根据条件更新记录
}
public function insert($data = array()) {
if(!$data || !is_array($data)) {
return 0;
}
return $this->_db->add($data);
}
public function getAdmins() {
$data = array(
'status' => array('neq',-1),
);
return $this->_db->where($data)->order('admin_id desc')->select();
}
/**
* 通过id更新的状态
* @param $id
* @param $status
* @return bool
*/
public function updateStatusById($id, $status) {
if(!is_numeric($status)) {
throw_exception("status不能为非数字");
}
if(!$id || !is_numeric($id)) {
throw_exception("ID不合法");
}
$data['status'] = $status;
return $this->_db->where('admin_id='.$id)->save($data); // 根据条件更新记录
}
public function getLastLoginUsers() {
$time = mktime(0,0,0,date("m"),date("d"),date("Y"));
$data = array(
'status' => 1,
'lastlogintime' => array("gt",$time),
);
$res = $this->_db->where($data)->count();
return $res['tp_count'];
}
}
在目录下添加一个后台url admin.php内容为 这样设置访问localhost/thinkphp/admin.php
相当于localhost/thinkphp/admin.php?m=admin&c=index&a=index
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st
// +----------------------------------------------------------------------
// 应用入口文件
// 检测PHP环境
if(version_compare(PHP_VERSION,'5.3.0','<')) die('require PHP > 5.3.0 !');
// 开启调试模式 建议开发阶段开启 部署阶段注释或者设为false
define('APP_DEBUG',True);
$_GET['m'] = (!isset($_GET['m']) || !$_GET['m']) ? 'admin' : $_GET['m'];
$_GET['c'] = (!isset($_GET['c']) || !$_GET['c']) ? 'index' : $_GET['c'];
$_GET['a'] = (!isset($_GET['a']) || !$_GET['a']) ? 'index' : $_GET['a'];
// 定义应用目录
define('APP_PATH','./Application/');
// 引入ThinkPHP入口文件
require './ThinkPHP/ThinkPHP.php';
// 亲^_^ 后面不需要任何代码了 就是如此简单
以上就完成了后台用户的登录。
接下来需要完成菜单管理功能:url localhost/thinkphp/index.php?m=admin&c=menu&a=index
这个页面应该显示默认存在的菜单内容,但是第一次创建是没有数据的,这时候在这个页面添加一个添加按钮。
这个按钮跳转到添加菜单内容。
$("#button-add").click(function(){
var url = SCOPE.add_url; //这个url是写在菜单管理的默认index.html内,url为localhost/thinkphp/index.php?m=admin&c=menu&a=add
window.location.href=url;});
按钮添加点击事件后,点击按钮就跳转的页面SCOPE.add_url。跳转到这个页面后,填入表单提交的数据内容。
后台控制器对应方法接收数据,并处理,这里使用ajax异步发送数据。
$("#singcms-button-submit").click(function(){
var data = $("#singcms-form").serializeArray(); //表单数据序列化后。
postData = {};
$(data).each(function(i){//把这个表单序列化数据转换成数组
postData[this.name] = this.value;
});
//console.log(postData);
// 将获取到的数据post给服务器
url = SCOPE.save_url;
jump_url = SCOPE.jump_url;
$.post(url,postData,function(result){
if(result.status == 1) {
//成功后跳转回菜单管理默认页面
return dialog.success(result.message,jump_url);
}else if(result.status == 0) {
// 失败
return dialog.error(result.message);
}
},"JSON");
});
namespace Admin\Controller;
use Think\Controller;
use Think\Exception;
class MenuController extends CommonController{
public function index(){ //菜单默认页面现在先不需要看
$data=array();
if(isset($_REQUEST['type'])&&in_array($_REQUEST['type'],array(0,1))){
$data['type']=intval($_REQUEST['type']);
$this->assign('type',$data['type']);
}
else{
$this->assign('type',-1);
}
/**
* 分页操作逻辑
*/
$page=$_REQUEST['p']? $_REQUEST['p']:1;
$pageSize=$_REQUEST['pageSize']? $_REQUEST['pageSize']:3;
$menus=D('Menu')->getMenus($data,$page,$pageSize);
$menusCount=D('Menu')->getMenusCount($data);
$res=new \Think\Page($menusCount,$pageSize); //Thinkphp自带分页函数传入数量和每页大小会生成对应的分页效果
$pageRes=$res->show();
$this->assign('pageRes',$pageRes);//向页面传递数据
$this->assign('menus',$menus);//向页面传递数据
$this ->display();//跳转到对应的文件名
}
public function add(){//这里就是add的方法,把数据发送到这里
if($_POST){//如果提交的数据不为空
if(!isset($_POST['name'])|| !$_POST['name']){
return show(0,'菜单名不能为空');
}
if(!isset($_POST['m'])|| !$_POST['m']){
return show(0,'模块名不能为空');
}
if(!isset($_POST['c'])|| !$_POST['c']){
return show(0,'控制器名不能为空');
}
if(!isset($_POST['f'])|| !$_POST['f']){
return show(0,'方法名不能为空');
}
if($_POST['menu_id']){
return $this->save($_POST);
}
$menuId=D('Menu')->insert($_POST);
if($menuId){
return show(1,'新增成功',$menuId);
}
return show(0,'新增失败',$menuId);
}
else{
$this->display();
}
}
public function edit(){
$menuId=$_GET['id'];
$menu=D('Menu')->find($menuId);
$this->assign('menu',$menu);
$this->display();
}
public function save($data){
$menuId=$data['menu_id'];
unset($data['menu_id']);
try{
$id=D('Menu')->updateMenuById($menuId,$data);
if($id === false){
return show(0,'更新失败');
}
return show(1,'更新成功');
}catch(Exception $e){
return show(0,$e->getMessage());
}
}
public function setStatus(){
try{
if($_POST){
$id=$_POST['id'];
$status=$_POST['status'];
//执行数据更新操作;
$res=D('Menu')->updateStatusById($id,$status);
if($res){
return show(1,'操作成功');
}
else{
return show(0,'操作失败');
}
}
}catch(Exception $e){
return show(0,$e->getMessage());
}
return show(0,'没有提交数据');
}
public function listorder(){
$listorder=$_POST['listorder'];
// return show(0,$jumpUrl);
$jumpUrl = $_SERVER['HTTP_REFERER'];
$errors=array();
if($listorder){
try{
foreach ($listorder as $menuId=>$v){
//执行更新
$id= D('Menu')->updateMenuListorderById($menuId,$v);
if($id === false){
$errors[]=$menuId;
}
}
}catch (Exception $e){
return show(0,$e->getMessage(),array('jump_url' => $jumpUrl));
}
if($errors){
return show(0,'排序失败-'.implode(',',$errors),array('jump_url' => $jumpUrl));
}
return show(1,'排序成功',array('jump_url' => $jumpUrl));
}
return show(0,'排序数据失败',array('jump_url' => $jumpUrl));
}
}
这是一个例子,接下来的内容类似的,其它模块的编写相似,这里就不一一重复了。
这里来详细了解一下文章的添加,其中的富文本编辑,已经图片上传功能。这里使用了party插件
/**
* 图片上传功能
*/
$(function() {
$('#file_upload').uploadify({
'swf' : SCOPE.ajax_upload_swf,
'uploader' : SCOPE.ajax_upload_image_url, //url=localhost/thinkphp/admin.php?c=image&a=ajaxuploadimage
'buttonText': '上传图片',
'fileTypeDesc': 'Image Files',
'fileObjName' : 'file',
//允许上传的文件后缀
'fileTypeExts': '*.gif; *.jpg; *.png',
'onUploadSuccess' : function(file,data,response) {
// response true ,false
if(response) {
var obj = JSON.parse(data); //由JSON字符串转换为JSON对象
//console.log(data);
//console.log(obj);
$('#' + file.id).find('.data').html(' 上传完毕');
$("#upload_org_code_img").attr("src",obj.data);//把返回的url填入表单
$("#file_upload_image").attr('value',obj.data);//把返回的url填入表单
$("#upload_org_code_img").show();//图片展示,一开始隐藏图片位置
}else{
alert('上传失败');
}
},
});
});
model图片上传类:
namespace Common\Model;
use Think\Model;
/**
* 上传图片类
* @author singwa
*/
class UploadImageModel extends Model {
private $_uploadObj = '';
private $_uploadImageData = '';
const UPLOAD = 'upload';
public function __construct() {
$this->_uploadObj = new \Think\Upload(); //Thinkphp自带上传功能
$this->_uploadObj->rootPath = './'.self::UPLOAD.'/'; //上传根路径
$this->_uploadObj->subName = date(Y) . '/' . date(m) .'/' . date(d); //上传子文件名字
}
public function upload() {//上传方法上传成功后返回url路径
$res = $this->_uploadObj->upload();
if($res) {
return '/thinkphp/' .self::UPLOAD . '/' . $res['imgFile']['savepath'] . $res['imgFile']['savename'];
}else{
return false;
}
}
public function imageUpload() {//上传方法上传成功后返回url路径
$res = $this->_uploadObj->upload();
if($res) {
return '/thinkphp/' .self::UPLOAD . '/' . $res['file']['savepath'] . $res['file']['savename'];
}else{
return false;
}
}
}
控制器
/**
* 图片相关
*/
namespace Admin\Controller;
use Think\Controller;
use Think\Upload;
/**
* 文章内容管理
*/
class ImageController extends CommonController {
private $_uploadObj;
public function __construct() {
}
public function ajaxuploadimage() {
$upload = D("UploadImage");
$res = $upload->imageUpload();
if($res===false) {
return show(0,'上传失败','');
}else{
return show(1,'上传成功',$res);
}
}
public function kindupload(){
$upload = D("UploadImage");
$res = $upload->upload();
if($res === false) {
return showKind(1,'上传失败');
}
return showKind(0,$res);
}
}
接下来是富文本内容的上传
后台内容就差不多这样类似的编写结束了,接下来是前台的展示。
有些模块为了防止未登陆就进入这里需要设置一个控制类
namespace Admin\Controller;
use Think\Controller;
/**
* use Common\Model 这块可以不需要使用,框架默认会加载里面的内容
*/
class CommonController extends Controller {
public function __construct() {
parent::__construct();
$this->_init();
}
/**
* 初始化
* @return
*/
private function _init() {
// 如果已经登录
$isLogin = $this->isLogin();
if(!$isLogin) {
// 跳转到登录页面
$this->redirect('/thinkphp/admin.php?c=login');
}
}
/**
* 获取登录用户信息
* @return array
*/
public function getLoginUser() {
return session("adminUser");
}
/**
* 判定是否登录
* @return boolean
*/
public function isLogin() {
$user = $this->getLoginUser();
if($user && is_array($user)) {
return true;
}
return false;
}
public function setStatus($data, $models) {
try {
if ($_POST) {
$id = $data['id'];
$status = $data['status'];
if (!$id) {
return show(0, 'ID不存在');
}
$res = D($models)->updateStatusById($id, $status);
if ($res) {
return show(1, '操作成功');
} else {
return show(0, '操作失败');
}
}
return show(0, '没有提交的内容');
}catch(Exception $e) {
return show(0, $e->getMessage());
}
}
public function listorder($model='') {
$listorder = $_POST['listorder'];
$jumpUrl = $_SERVER['HTTP_REFERER'];
$errors = array();
try {
if ($listorder) {
foreach ($listorder as $id => $v) {
// 执行更新
$id = D($model)->updateListorderById($id, $v);
if ($id === false) {
$errors[] = $id;
}
}
if ($errors) {
return show(0, '排序失败-' . implode(',', $errors), array('jump_url' => $jumpUrl));
}
return show(1, '排序成功', array('jump_url' => $jumpUrl));
}
}catch (Exception $e) {
return show(0, $e->getMessage());
}
return show(0,'排序数据失败',array('jump_url' => $jumpUrl));
}
}
需要登陆才能访问的页面要继承这个类。
前台展示系统:
前台登录的主页控制器类
namespace Home\Controller;
use Think\Controller;
class IndexController extends CommonController {
public function index($type=''){
//获取首页大图数据
$rankNews = $this->getRank();
$topPicNews=D('PositionContent')->select(array('status'=>1,'position_id'=>3),1);
// print_r( $topPicNews);
// exit;
//首页3张小图
$topSmailNews=D('PositionContent')->select(array('status'=>1,'position_id'=>4),3);
$listNews = D("News")->select(array('status'=>1,'thumb'=>array('neq','')),30);
$advNews = D("PositionContent")->select(array('status'=>1,'position_id'=>5),2);
$this->assign('result',array(
'topPicNews'=>$topPicNews,
'topSmailNews'=>$topSmailNews,
'listNews'=>$listNews,
'advNews' => $advNews,
'rankNews' => $rankNews,
));
/*
*
* 生成页面静态化
*/
if($type== 'buildHtml'){
$this->buildHtml('index',HTML_PATH,'Index/index'); //系统生成静态页面的方法 ,index名字, 路径,模板
}
else{
$this->display();
}
}
public function build_html(){
$this->index('buildHtml');
return show(1,'首页缓存生成成功');
}
public function crontab_build_html(){
if(APP_CRONTAB != 1) {
die("the_file_must_exec_crontab");
}
$result = D("Basic")->select();
if(!$result['cacheindex']) {
die('系统没有设置开启自动生成首页缓存的内容');
}
$this->index('buildHtml');
}
public function getCount() {
if(!$_POST) {
return show(0, '没有任何内容');
}
$newsIds = array_unique($_POST);
try{
$list = D("News")->getNewsByNewsIdIn($newsIds);
}catch (Exception $e) {
return show(0, $e->getMessage());
}
if(!$list) {
return show(0, 'notdataa');
}
$data = array();
foreach($list as $k=>$v) {
$data[$v['news_id']] = $v['count'];
}
return show(1, 'success', $data);
}
}
其它的类似都是负责展示页面的逻辑