主頁 >  其他 > 一篇文帶你從0到1了解建站及完成CMS系統撰寫

一篇文帶你從0到1了解建站及完成CMS系統撰寫

2020-10-27 06:10:44 其他

學習目標

  1. 了解搭建一般網站的簡便方式
  2. 了解最原始一般站點搭建
  3. 了解內容管理站點搭建
  4. 了解權限設計及完成
  5. 了解使用設計模式減少代碼冗余
  6. 了解前端拖拽頁面生成及生成
  7. 了解自定義資料的創建
  8. 了解動態生成的前端頁如何系結自定義資料

開發環境

  • Windows7 *64 SP1
  • php5.6
  • apache/nginx
  • thinkphp5.1
  • mysql
  • phpstudy2018
  • sqlyog
  • layoutit

宣告

文章為從0到1了解內容管理系統搭建與撰寫,由于一篇文章內容篇幅過長,文章內容經過壓縮,該專案中相同邏輯的實作只以一個實體作為描述,主要以核心關鍵功能的開發作為主要的講解步驟,如有想學習完整內容系統撰寫可在留言區留言,我會盡快完成完整版的實戰教程發布,謝謝,本篇不涉及vue、nodejs的前端框架,

知識門檻

以下內容有過一些了解即可:

  • html
  • sql
  • php
  • tp框架

面向人群

  • 剛學了php不懂怎么用的同學
  • 會一點點建站但是又不清楚流程的同學
  • 學習完了一些框架不懂怎么使用的同學
  • 有過一些web開發經驗的同學等
  • 希望本篇文章對每一個閱讀完的同學都有幫助

注意:本篇文章部分細節由于篇幅關系并不會去深入完善,并且相同邏輯的實作只以一個實體作為描述,主要以核心功能的開發作為主要的講解步驟,本篇不涉及vue、nodejs的前端框架,

一、 了解一些專業術語及概念

在了解搭建網站前,需要普及一些基本的知識概念,防止某些同學在一方面有概念性的錯誤,并且我個人認為在學習一方面知識前需要對這一方面的知識有一個廣度的了解,這里所指的廣度為這東西是用來干什么的、作用是什么、為什么要這樣寫;所以在正式開始介紹如何撰寫CMS前將會介紹這一部分內容,為了方便閱讀第一點內容引入我另外一篇原創文章,

1.1了解瀏覽一個網頁的基本流程方式

在學習一門技術的時候,往往是了解整體體系架構才能更好的學習,不然在學習的程序中會出現不知道為什么這樣做,做出這一部分是該整體部分的哪個區域,只會跟著做,但是并不了解這是在干啥,可能一些萌新體會頗深,就照著打,老師教怎么寫,我就怎么寫,反正做出來了,

本篇博文,就來用最接地氣的方式對基本的web開發做一個整體的講解,帶各個萌新過一遍web開發的流程,好讓各位萌新知道學習的時候學習了什么知識點,這個知識點能夠干哈,

最開始,我們就以個人瀏覽網站的方式給大家說一下這一個程序是如何運作的,
在這里插入圖片描述

我們訪問網站,一般先打開瀏覽器(不要杠),輸入一個網址,隨后瀏覽器打開一個網頁,在你在請求這一個網址資料的時候,已經發生了一系列的操作,

1.2了解IP地址

假設你輸入的是“csdn.net”,瀏覽器想要去訪問你這個網站,首先需要的是獲得你這個網站的IP地址,可能就有萌新問了**“什么是IP地址?”,IP地址就是“指互聯網協議地址,或者說網際協議地址”,又有萌新說了“你這么說我怎么懂?”**,好了現在容我慢慢道來,

IP地址就是在網路中,定位你這臺電腦,或者說是設備的一個標記,這個標記是人們指定好的標準協議而產生的(協議就是你和我說好了一件事,拉鉤了,以后要這樣做),就像你家的門牌號例如叫做“CSDN市,CSDN區,CSDN街道的CSDN小區第CSDN棟的第CSDN號”…這是由有關機構制定的一套規范名稱,不允許隨意更改;我們換個例子,例如你家是“深圳市南山區深南大道某某小區第八棟808”,你寫快遞的收件地址肯定是寫這個,難道你寫“宇宙第一星球第一市第一棟第一號”?地址是由專門組織規范且制定的一套定位規范,遵循這個規范可以使遵循該規范的設備或者人之間相互通信,這個通信指可以傳達互動,能夠定位、找到,綜上所述,IP地址就不要糾結為什么要這樣寫,只要知道這個IP地址是你要用的就行,

1.3了解DNS

現在IP地址知道是什么了,那么怎么獲得IP地址?這個時候就需要用到DNS了,啥是DNS??!!
在這里插入圖片描述

DNS的英文全稱是 Domain Name System,翻譯過來就是域名系統,好了,這個時候問題又來了,

1.4了解域名

啥是域名?域名就是用來標識IP地址的一個標記,或者說是昵稱,“為什么不直接用IP地址?”這個問題問得好,如果我們人不用名稱,就用身份證號,我叫你的時候就會叫“450333333333333333…”,,,我覺得這樣不是很好,,,當人們覺得使用IP地址不方便記憶后,就產生了域名地址,就像CSDN,我們就知道是CSDN就好了,難道還要去記她的IP地址嗎?例如CSDN的地址是192.168.1.1,難不難受…以后可能你記網站名稱就在記數字了,又不方便又崩潰,好了,回歸正題,我們輸入了網址后,按下Enter鍵后,瀏覽器將會去DNS請求這個域名對應的IP是什么,如果找到了,就回傳一個IP地址,可能又有萌新問了,“瀏覽器會自動去找DNS?”,會是會,但是我們也會給它一個目標,在我們的網路連接里面,本地連接右鍵屬性,里面有個IPV4,雙擊進去就可以查看自己配置的DNS了,一般別亂改,不然很難過的,有時候瀏覽器打不開網址,就是這個原因,
在這里插入圖片描述
記住,網路IP沖突可能會導致上不了網,這種情況在學校的機房里很常見,只要改成自動獲取IP就ok了,會自動分配閑置的IP地址,

1.5 了解資料請求

在這里插入圖片描述

當找到了IP地址,這個時候就會向該IP地址的設備去請求資料,請求資料的意思就是,這個設備或者說服務器就像一個大型的分發機構,就是送情報的一個部門,一共有65535個視窗,每個視窗送不同的情報;例如我們需要請求網站之類的資料,就通過第80個視窗請求,這個時候瀏覽器派來的小弟來到這個80號視窗,可能會排一下隊,拿到資料后,回到瀏覽器,瀏覽器把拿到的資料顯示給你看,

1.6 了解“ 渲染”

在這里插入圖片描述

其實在這個時候,瀏覽器顯示的資料會根據一些標記,進行排版,這些標記就稱是HTML,HTML是 Hyper Text Markup Language 的縮寫,中文名是超級文本標記語言,其實說那么深奧還不方便理解;簡單來說就是通過特定的標簽,把一段文本資訊標記起來,表示這段文本資訊要怎么樣去進行顯示,或者是這個文本資訊是啥東西;例如 <title>CSDN-專業IT技術社區</title>是CSDN官網首頁的標題,用了title這個標簽把文本資訊標記,標記好后,瀏覽器就知道這個文本要顯示在哪里,要怎么進行顯示,最終瀏覽器把這一段資訊顯示在了瀏覽器標題頭位置:
在這里插入圖片描述
我們再看看另外的一個例子:
在這里插入圖片描述
這一段HTML語言所標記了一個博客的文本,整個標記的情況為了清晰的看清楚,我在這里列出:<a href="//blog.csdn.net/" class="toolbar_to_feed" title="博客">博客</a>,標記語言HTML那一些標記并不會進行顯示,只顯示了博客這個這個文本在網頁上:
在這里插入圖片描述
那是因為瀏覽器是通過標記語言的內容去進行顯示,標記語言的作用就是告訴瀏覽器這里你要怎么顯示這個內容,或者說這個內容有什么功能,這里是博客的一個跳轉,使用的是a標簽,a標簽是什么?a標簽就是<a>這里是要顯示的文本</a>,在a標簽里面可以添加一些固定的操作,例如a標簽的作用是跳轉到指定的頁面,那么這個頁面肯定是有一個鏈接的,那么這個鏈接需要什么來指定呢?

答案就很簡單了,使用href來指定,這個href呢就需要把要跳轉到的頁面的地址給加上,在我們查看到的HTML代碼中是href="//blog.csdn.net/",這就表示會跳轉到blog.csdn.net這個地址,有人點擊就會跳轉到博客了,

class="toolbar_to_feed" 是什么東西?在這里我們可以把它當做給定了一個樣式,給定了一個style,要怎么樣顯示,你要顯示的樣子是什么?可能紅色的底,綠色的字,俗話說,紅配綠,,,這個樣式的名稱就叫做 toolbar_to_feed ,在這里并不會深入的講解這個樣式要讓博客這個文本顯示成啥樣,大家只要通過例子知道這個html是用來告訴瀏覽器怎么樣顯示這個文本,或者這個文本有什么用就ok了,其實還有些動態的資料,但是在這里并不會講解,基本的理解這樣就沒問題了,專業點的說法就是構件編排用戶界面,

1.7 了解前端

在這里插入圖片描述

通過以上描述就很清楚的知道,如果我們做web開發的話,做html相關的就是給頁面制作布局,怎么樣好看,甚至可以做特效,讓頁面顯示多姿多彩;一般我們稱做HTML這種,是為了資料的顯示的排版作業,或者說是為了包裝資料作業的這類職位叫做前端;不過前端是個相對概念,在web上可以這樣理解是沒問題的,不過現在的前端,如果不去大廠,基本上要做的不止是包裝資料的排版那么簡單,可能還會做得更多,如果我們去做前端作業的話,還要掌握跟服務器互動的一些操作,打個比方,用戶點擊了一個按鈕,這個按鈕的功能是獲取到你們的用戶人數,這個時候你需要撰寫一個邏輯,去服務器獲取到這個用戶想要的資料,不過這點只是作為一個提醒,當真正接觸前端的話會了解的,

1.8 了解后端

在這里插入圖片描述

有很多小問號的朋友可能會記得剛剛說的,前端可能要向服務器請求資料,那么這個資料,是不是就是傳說中的后端做的?(聽沒聽過后端某問題,反正就是后端)

后端可以理解為一些業務邏輯的代碼撰寫實作,就是需要后端,什么是業務邏輯?簡單的舉個例子,就像你淘寶買東西,你點了這個物品,下單了,我要在代碼上怎么實作這個下單這個背后的操作;因為下單后你還需要交易,交易要收錢,收錢你還要把這個記錄記載到你存放資料的地方,我們可以叫做資料庫,存進去后,用戶查看自己的下單記錄,你還需要把這個記錄取出來,用代碼實作這個取出來這個程序給用戶看到,不然沒有記錄那就很尷尬了,只收錢不賣貨!流批!所以一般是指的是資料庫(因為要存盤資料,例如你網站的用戶資料,肯定要用東西來存盤,這個東西就是資料庫)進行互動以處理相應的業務邏輯,雖然后端要考慮很多東西,但是一般來說這樣舉例子就比較方便理解,就不過多的談論其它東西了,

現在整個邏輯基本上就通了,簡單的理解,后端就是實作一些資料操作,業務邏輯的實作(其實可能會運維),前端呢就是負責用戶的頁面資料的展示排版;嗯,大體這樣理解問題不大,

1.9 了解建站

在這里插入圖片描述

既然理解通了,我們就來說說一個網站搭建的流程是什么吧!
首先我們需要租一個服務器,嗯…這個萌新不理解,那我們降一個檔次,那就是我們在我們自己的本地電腦進行試驗,這樣就問題不大了,方便快捷,

搭建一個簡單企業門戶網站其實賊簡單,不吹不黑,幾年前的時候,做這個還是挺得錢的,接接外包,舒舒服服,現在就不行了,畢竟技術在更新,過時的技術也變得更加廉價了,但是依舊是基本,

以下我使用一個靜態網站作為例子演示一個網站的搭建;“啥是靜態網站?”,靜態網站就是沒有后端,好吧,簡單來說就是這樣,由于后端需要一些其它語言,本篇博文針對于普遍人群,為了方便理解就不用后端了,直接靜態網站作為演示,列出html的代碼,到時候萌新們可以直接復制代碼拿去自己試驗,舒舒服服,美滋滋,

1.10 了解集成環境

在這里插入圖片描述

首先我們下載一個集成環境,“啥是集成環境?”

集成環境打個比方,就像你做菜、需要火源、鍋、鍋鏟,這種就是環境;我做網站也要一個環境,這個環境有人給你做好了,你直接拿過來用就好,就不需要自己搭建,有些初學者就喜歡自己搭建,然后發現一堆問題,搞著搞著發現太難就不學了,簡直嚶嚶嚶!初學者我個人建議先別增加自己的難度,先學,不然沒搞懂就上會一臉懵圈的,現在我們下載一個叫做phpstudy的軟體,下載點這里
去官網,然后進行傻瓜式安裝,
在這里插入圖片描述
安裝完后打開服務:
在這里插入圖片描述
Apache可能會有人問是什么,Apache是服務器軟體,它就是你做菜需要的必要工具之一,開啟了就對了,可能你只開啟Apache只能做湯,那也沒事,畢竟我現在演示的是靜態網站,

首先我們把我們的資源檔案帶到網站根目錄下:
在這里插入圖片描述
根目錄不會找?沒關系,我們打開網站,點擊管理找到根目錄就ok:
在這里插入圖片描述
找到后把資源檔案放到根目錄下,洗掉以前的根目錄下的內容即可,
然后在瀏覽器輸入:http://127.0.0.1/ 或者輸入 http://localhost/ 就可以訪問我們本地電腦上的網站了!

二、給所搭建的靜態網站添加后端

在以上第一節內容中,我們已經做好了一個靜態的網站,但該網站并沒有一些后臺功能,例如后臺設定網頁的所展示的內容,那為什么要后臺設定網頁展示的內容呢?當我們的網站成功架設后,假設該網站是雙十一的推廣網站,圖片這些全部都是標有雙十一字樣,當雙十一過后該網站難道就不能繼續使用了嗎?答案當然是不,只需要撰寫一管理后臺,用戶在后臺中可自由設定圖片要顯示哪一張,該功能完成后,用戶可根據自己的需要更改對應的圖片;既然圖片都可以更改了,那么文章也同樣可以更改,這時網站的自由度將會更高,

更改網站圖片的顯示與更改文字內容的顯示都需要使用資料庫,當然其它方式也可以,但我們在這里使用一種較為常規與成熟的資料庫方式進行存盤,并且使用一個php的開發框架thinkphp來方便我們的搭建,thinkphp的版本是5.1版本,可能有些小伙伴們問為什么要使用框架?這不是增加學習成本嗎?其實使用框架并不會增加你的開發時長,并且會增加你的開發效率;框架就像搭建房子時的地基,直接使用一個地基比你自己再去做一個地基更加簡單方便,而且更為標準;如果你是一個新手,自己去搭建一個地基,往往會做到一半就“塌”了,這種情況也不是不可能,

2.1 了解thinkphp5.1 的使用

首先我們下載thinkphp5.1,解壓后目錄如下:
在這里插入圖片描述
目錄參考可以根據thinkpp5.1手冊:
在這里插入圖片描述
thinkphp5.1的目錄結構在本文并不需要了解過多,本文將會說明需要了解的目錄,
我們復制解壓出來的檔案至網站根目錄下,并且洗掉原有網站根目錄下的內容:

在這里插入圖片描述由于thinkphp框架的入口在public目錄下,我們打開public目錄進行查看:

在這里插入圖片描述
在public目錄下找到了index.php檔案,由于該框架的入口檔案是index.php,需要更改網站的根目錄為public,打開phpstudy,依次點擊其它選單選項->軟體設定->埠常規設定:
在這里插入圖片描述
在彈出來的根目錄設定中,選擇public作為根目錄:
在這里插入圖片描述此時輸入localhost進行訪問:
在這里插入圖片描述
出現如上示例則表示當前thinkphp部署成功,接下來就可以進行相應的代碼撰寫了,

2.2 完成第一節靜態網站的移植部署

在第一節中,我們實作了一個靜態網站的搭建,現在將第一節撰寫好的靜態網站index.html檔案復制到如下路徑中:
在這里插入圖片描述

我的目錄是 E:\devlop\phpstuy\PHPTutorial\WWW\application\index\view\index,如果沒有該目錄可以自己創建,我們瀏覽器再次輸入localhost查看,發現依舊出現之前的web頁提示,這是什么回事呢?因為我們需要在thinkphp的控制器中,添加一行跳轉到該html檔案的代碼,控制器檔案在 E:\devlop\phpstuy\PHPTutorial\WWW\application\index\controller 下:
在這里插入圖片描述

該目錄是存放當前模塊下所有控制器的地方(當然你可以不這樣),控制器在thinkphp框架中用于對用戶訪問進行控制,例如用戶需要訪問首頁則需要訪問首頁的控制器,默認是index控制器;index控制器可以對index這個頁面進行邏輯控制,可以傳值、權限控制等一些列操作,換句話說則是控制用戶訪問指定資源的邏輯(不理解也沒關系),我們打開index.php這個控制器:

<?php
namespace app\index\controller;

class Index
{
    public function index()
    {
        return '<style type="text/css">*{ padding: 0; margin: 0; } .think_default_text{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p> ThinkPHP V5.1<br/><span style="font-size:30px">十年磨一劍 - 為API開發設計的高性能框架</span></p></div><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_bd568ce7058a1091"></thinkad>';
    }

    public function hello($name = 'ThinkPHP5')
    {
        return 'hello,' . $name;
    }
}

改php控制器默認index為訪問方法,index方法將會回傳一條html的字串,改字串通過渲染將會顯示成我們之前所看到的部署成功的歡迎界面,在這里需要將該代碼洗掉,換成:

return $this->view->fetch();

整個php檔案則為:

<?php
namespace app\index\controller;
use think\Controller;

class Index extends Controller{
    public function index()
    {
        return $this->view->fetch();
    }

    public function hello($name = 'ThinkPHP5')
    {
        return 'hello,' . $name;
    }
}

return $this->view->fetch(); 我們可以查看thinkphp5.1手冊:
在這里插入圖片描述

使用 fetch 方法將會自動定位到模板檔案,thinkphp已經幫我們寫好了一定的規則,自動定位到默認view目錄下對應控制器名下的index檔案,在此注意,是自動定位到view目錄下與控制器同名的目錄下的檔案,不加引數自動定位到index.html,也就是view/控制器名/index.html,由于控制器名是index,則是view/index/index.html;view目錄下的index目錄則是之前復制靜態網站html檔案的目錄,

保存php檔案,訪問localhost:

在這里插入圖片描述

這時發現整個web頁錯亂,這時因為所有css檔案、js檔案、img檔案的路徑都有所改變,這時需要更改到正確的資源加載目錄,為了方便加載,在網站根目錄public目錄下新建一個home目錄,復制該頁面所需的資源檔案到該目錄下:
在這里插入圖片描述

網站根目錄資源的訪問路徑是“/”表示網站根目錄下,由于在根目錄下創建了一個home目錄,則進一步可以寫為“/home/”,在home目錄下有一個asset,則可以寫為“/home/assets/”,assets下的檔案訪問則可以根據目錄進行具體訪問,例如asset下的目錄img有一個圖片叫做1.png,那么訪問則可以寫成“/home/assets/img/1.png”,

了解了訪問的規則后,修改index.html檔案,將所有 assets/ 都更換為 /home/assets/,我使用的編輯器是 vscode,快捷鍵 ctrl+h 即可調出一鍵替換:
在這里插入圖片描述

點擊如上圖中的一鍵替換即可完成資源內容的目錄修改,隨后保存,再次訪問:
在這里插入圖片描述完美呈現,是不是賊爽?那么接下來就實作這些圖片資源的可后臺更換,

三、完成后臺模塊的撰寫

3.1 完成管理后臺模塊搭建

首先復制application目錄下的index目錄:

在這里插入圖片描述
更改index-副本名為admin:
在這里插入圖片描述
隨后更改admin目錄下controller目錄中的index.php檔案內容,原檔案內容如下:

<?php
namespace app\index\controller;
use think\Controller;

class Index extends Controller{
    public function index()
    {
        return $this->view->fetch();
    }
}

更改為:

<?php
namespace app\admin\controller;
use think\Controller;

class Index extends Controller{
    public function index()
    {
        return $this->view->fetch();
    }
}

以上的內容主要更改在命名空間,從 namespace app\index\controller;更改為了 namespace app\admin\controller;,命名空間主要是為了區分不同區域或空間內的不同“東西”,例如學校中A班的小明與B班的小明,這兩者有著班別的區別,命名空間也是如此,表示不同區域不同空間內的值,

更改完成后訪問 http://localhost/index.php/admin/index,這行url地址表示該網站中admin模塊下的index方法,其中index.php在訪問首頁的時候是默認隱藏,即http://localhost/index.php等于localhost,由于當下訪問其他模塊在此需要寫全(當然可以配置隱藏,但不是本節內容則不過多增加難度),訪問后發現該頁面與訪問localhost出現的內容一致,這是因為admin模塊中的index方法也用了return $this->view->fetch();這一行代碼輸出了html檔案的代碼,這個html檔案并不是index模塊下的view/index下的index.html,而是admin模塊下的view/index下的index.html,因為剛剛整個模塊我們都進行了復制,這時該html不符合我們的需求,需要更換html內容,在此我使用了一模板(該模板撰寫是前端內容,在此并不過多贅述,實作邏輯與index.html型別,均是修改頁面的資源路徑即可),訪問效果如下:
在這里插入圖片描述

注:本節專案代碼將會打包分享給大家,

3.2 完成資料庫的匯入

完成后臺管理頁的搭建后,發現該后臺所有用戶均可訪問,這對于一個網站是不好的權限行為;必須實作可控的權限管理,使得網站內容不得隨意更改,

首先打開sqlyog,輸入資料庫的帳號密碼,一般帳號為root密碼為root或空:
在這里插入圖片描述
連接成功后,郵件你本地資料庫點擊創建資料:
在這里插入圖片描述
輸入資料庫名,我創建資料庫名為minimalism_cms,并且選擇字符集,字符集為utf8即可,點擊創建:
在這里插入圖片描述在出現的新建資料庫中,選擇創建表:
在這里插入圖片描述
輸入表資訊如以下:
在這里插入圖片描述
以上所有所需的資料庫表我將會匯出sql檔案,同學們使用時在資料庫匯入即可,匯入步驟如下:
在這里插入圖片描述
在對應資料庫中右鍵選擇匯入點擊執行sql腳本即可,

匯入完將會出現如下的資料庫表:
在這里插入圖片描述
以上資料庫表考慮排錯等操作并沒有過多約束,

3.3 完成權限內容添加功能撰寫

權限管理首先需要有賬戶,賬戶屬于什么角色,該角色又有什么權限,這是實作權限管理的思想,例如有個賬戶名為admin,admin屬于超級管理員這個角色,該角色擁有所有的權限,接下來首先創建管理員用戶,
在權限管理下拉串列中選擇管理員管理進入頁面:
在這里插入圖片描述我們查看url連接:http://localhost/index.php/admin/auth/adminauth.html
以上鏈接中,admin表示admin這個模塊,auth表示控制器,adminauth表示方法名;auth控制器我們還未創建,在admin模塊下的index控制器同目錄創建一個名為Auth.php檔案,內容如下:

<?php
/**
 * |-----------------------
 * | 頁面跳轉
 * |-----------------------
 */
namespace app\admin\controller;
use think\Controller;

class Auth extends Controller{

    //Auth 管理首頁
    public function adminAuth(){
        return $this->view->fetch();
    }
}

通過以上控制器,可以使url連接訪問到該控制器并且訪問adminAuth所對應的html檔案,該html對應的檔案在view目錄下的auth目錄中,在thinkphp中,對應的view目錄根據控制器名分配,Auth控制器需要一個名為auth的目錄存放該控制器下的html檔案;在auth目錄下創建一個名為admin_auth的html檔案,為什么要名為admin_auth?thinkphp會訪問方法名默認控制器對應的目錄中一同方法名的html檔案,如方法名有大寫,則表示在該名稱前有一下劃線,則adminAuth則為admin_auth,該html代碼將會打包下載即用,

點擊添加,添加管理員進入頁面:
在這里插入圖片描述該url為:http://localhost/index.php/admin/auth/adminadd.html
在控制器中添加方法:

<?php
/**
 * |-----------------------
 * | 頁面跳轉
 * |-----------------------
 */
namespace app\admin\controller;
use think\Controller;

class Auth extends Controller{

    //Auth 管理首頁
    public function adminAuth(){
        return $this->view->fetch();
    }
    //管理員添加頁
    public function adminAdd(){
        return $this->view->fetch();
    }
}
	

該頁面擁有管理員賬戶、管理員密碼、名稱及角色組內容,暫時我們并沒有角色組,首先創建一個管理員賬戶,查看html中的關鍵代碼:

<form class="form-horizontal" role="form">
                                
   <div class="form-group">
         <label class="col-md-2 control-label">管理員賬戶</label>
         <div class="col-md-10">
             <input id="user" type="text" class="form-control" placeholder="帳號">
         </div>
     </div>

     <div class="form-group">
         <label class="col-md-2 control-label">管理員密碼</label>
         <div class="col-md-10">
             <input id="password" type="password" class="form-control" placeholder="密碼">
         </div>
     </div>

     <div class="form-group">
         <label class="col-md-2 control-label">名稱</label>
         <div class="col-md-10">
             <input id="realname" type="text" class="form-control" placeholder="輸入名稱或代號">
         </div>
     </div>
 </form>

通過以上html得知,id為user是賬戶,id為password為密碼,id為realname為真實姓名,在此使用ajax進行資料提交到php后臺實作內容訪問,查看ajax代碼:

<script>
            function add(){
                var user=$('#user').val();
                var password=$('#password').val();
                var realname=$('#realname').val();
                $.ajax({
                    type:'post',
                    url:'/index.php?s=/admin/Authpost/adminAdd/',
                    data:{"user":user,"password":md5(password),"realname":realname,"group":group},
                    dataType:"json", 
                    success:function(data){
                        if(data.success==1){
                            alert(data.msg);
                        }else{
                            alert(data.msg);
                        }
                    },error:function(jqXHR){

                    }
                }) 
            }
        </script>

從以上ajax代碼中,使用jq獲取了id為user、password、realname元素的值,在此并沒有做檢查是否合規,希望小伙伴們在使用該代碼的時候注意,在獲取密碼時使用了md5加密,md5我是在線引入的,引入如下:

<script src="https://cdn.bootcss.com/blueimp-md5/2.10.0/js/md5.js"></script>

獲取值后使用ajax傳遞給 /index.php?s=/admin/Authpost/adminAdd/ 這個url地址,該地址使用了兼容模式,因為擔心一些同學本地環境有問題,所以特地在此使用該模式進行傳值,該模式的格式為:http://serverName/index.php(或者其它應用入口檔案)?s=/模塊/控制器/操作/[引數名/引數值…],則admin為模塊名,Authpost表示控制器名,adminAdd表示控制器中的方法,我們在admin的控制器目錄創建一個名為Authpost的控制器,并且撰寫adminAdd方法,代碼如下:

<?php
/**
 * |-----------------------
 * | 對資料庫操作
 * |-----------------------
 */
namespace app\admin\controller;
use think\Controller;
use think\Db;
use think\facade\Request;

use app\admin\model\Admin;
use app\admin\code\ReturnCodeInfo;

class Authpost extends Controller{

    //administartor add 
    public function adminadd(){
        $request_data = Request::post();

        $data['password'] = md5(trim($request_data['password']));
        $data['username']=$request_data['user'];
        $data['realname']=$request_data['realname'];
        $data['group']=$request_data['group'];

        $data['logintime'] = time();
        $data['create_time'] = time();
        $data['loginip'] = Request::ip();
        $data['status'] = 1;

        $res = Admin::create($data);

        if($res){
            return json((new ReturnCodeInfo())->actionSuccess());
        }else{
            return json((new ReturnCodeInfo())->actionError());
        }
    }
    }

先不看以上代碼,我們查看需要存盤值的資料庫欄位有哪些:
在這里插入圖片描述
通過表得知,資料庫欄位包括 username、password、logintime、loginip、realname、create_time,我們接收值需要設定這幾個初始欄位,Authpost 控制器adminadd方法中這部分代碼為:

$request_data = Request::post();

$data['password'] = md5(trim($request_data['password']));
$data['username']=$request_data['user'];
$data['realname']=$request_data['realname'];
$data['group']=$request_data['group'];

$data['create_time'] = time();
$data['loginip'] = Request::ip();
$data['status'] = 1;

以上代碼使用了 Request::post();接收post值,在使用Request時必須參考use think\facade\Request;;隨后將值賦給$request_data變數,隨后使用 $data 變數存盤即將要存盤到資料庫的值,在存盤password密碼時使用了md5加密,提高安全性,最后使用模型的create方法將資料庫的值存盤:

$res = Admin::create($data);

模型方法可以方便的使值進行存盤,模型對應的是一個資料庫,例如我資料庫名為tp_admin,設定前綴為tp_后可以直接創建一個名為Admin的模型,其實也就是名為Admin的php檔案,檔案中類名也為Admin,該類集成model基類故此有模型特性,創建模型的方法如下,在admin下的controller同目錄,注意是同目錄創建一個model檔案夾,在該檔案夾下創建一個Admin的php檔案,內容如下:

<?php
namespace app\admin\model;
use think\Model;

class Admin extends Model {
    
}

創建完成后,在需要使用到該模型的檔案中引入,我們在Authpost頭部引入 ,添加代碼:

use app\admin\model\Admin;

其實以上代碼是通過模型所在目錄進行引入,app表示根目錄,根目錄下的admin模塊中model目錄下的Admin模型,
在引入后還差很關鍵的一步,需要配置資料的連接,
在application目錄下config檔案夾中找到database.php檔案,打開修改hostname為127.0.0.1或者是localhost、修改database為我們創建的資料庫的名稱例如minimalism_cms、修改username帳號為root、修改password密碼為root,配置內容如下:

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------

return [
    // 資料庫型別
    'type'            => 'mysql',
    // 服務器地址
    'hostname'        => '127.0.0.1',
    // 資料庫名
    'database'        => 'minimalism_cms',
    // 用戶名
    'username'        => 'root',
    // 密碼
    'password'        => 'root',
    // 埠
    'hostport'        => '',
    // 連接dsn
    'dsn'             => '',
    // 資料庫連接引數
    'params'          => [],
    // 資料庫編碼默認采用utf8
    'charset'         => 'utf8',
    // 資料庫表前綴
    'prefix'          => 'tp_',
    // 資料庫除錯模式
    'debug'           => true,
    // 資料庫部署方式:0 集中式(單一服務器),1 分布式(主從服務器)
    'deploy'          => 0,
    // 資料庫讀寫是否分離 主從式有效
    'rw_separate'     => false,
    // 讀寫分離后 主服務器數量
    'master_num'      => 1,
    // 指定從服務器序號
    'slave_no'        => '',
    // 自動讀取主庫資料
    'read_master'     => false,
    // 是否嚴格檢查欄位是否存在
    'fields_strict'   => true,
    // 資料集回傳型別
    'resultset_type'  => 'array',
    // 自動寫入時間戳欄位
    'auto_timestamp'  => false,
    // 時間欄位取出后的默認時間格式
    'datetime_format' => 'Y-m-d H:i:s',
    // 是否需要進行SQL性能分析
    'sql_explain'     => false,
    // Builder類
    'builder'         => '',
    // Query類
    'query'           => '\\think\\db\\Query',
    // 是否需要斷線重連
    'break_reconnect' => false,
    // 斷線標識字串
    'break_match_str' => [],
];

修改完成后保存,
修改完成后查看 adminadd 方法中:

if($res){
            return json((new ReturnCodeInfo())->actionSuccess());
        }else{
            return json((new ReturnCodeInfo())->actionError());
        }

以上代碼為回傳通用的操作回傳值碼,減少代碼冗余,使用 json回傳json值,該值為new ReturnCodeInfo中的actionSuccess方法回傳值,代碼內容為:

<?php
namespace app\admin\code;

class ReturnCodeInfo{
    //驗證器成功代碼 10001,錯誤 10002
    private $validate_success=10001;
    private $validate_error=10002;
    private $validate_info='驗證成功';
    
    //資料庫存
    private $action_success=10003;
    private $action_error=10004;
    private $action_sinfo='操作成功';
    private $action_einfo='操作失敗';

    //驗證器 Code
    public function validataSuccess(){
        return ['code'=>$this->validate_success,'msg'=>$this->validate_info];
    }
    public function validataError($msg){
        return ['code'=>$this->validate_error,'msg'=>$msg];
    }

    //規則 Code
    public function actionSuccess(){
        return ['code'=>$this->action_success,'msg'=>$this->action_sinfo];
    }
    public function actionError(){
        return ['code'=>$this->action_error,'msg'=>$this->action_einfo];
    }

}

以上類定義了操作失敗或成功的回傳狀態,方便之后的操作呼叫該狀態碼,該php檔案我寫在controller同目錄下的code目錄中,名為ReturnCodeInfo的php檔案,則在Authpost代碼中使用了如下代碼引入:

use app\admin\code\ReturnCodeInfo;

接著我們回傳到html中,在提交按鈕上系結onclick事件,當然你使用別的方式也行,代碼如下:

<button type="button" onclick="add()" class="btn btn-success btn-bordered waves-effect w-md waves-light m-b-5">提交</button>

隨后在頁面中填入內容:
在這里插入圖片描述
點擊提交:
在這里插入圖片描述
操作成功,
我們按照如上方式創建角色組的創建,點擊角色組管理:
在這里插入圖片描述角色組實作邏輯與管理員實作邏輯類似,不再贅述,點擊添加進入添加頁:
在這里插入圖片描述填入組名后點擊提交,操作成功:
在這里插入圖片描述該邏輯實作一致,均是創建模型后進行資料插入,
隨后開始添加規則,進入規則添加頁:
在這里插入圖片描述點擊提交進行添加,

上述相同程序完成后開始實作權限認證的邏輯,
接下來完全用戶對角色組的系結,進入管理員管理頁,點擊編輯:
在這里插入圖片描述進入編輯頁后選擇超級管理員:
在這里插入圖片描述
點擊提交,完成系結:
在這里插入圖片描述
提交方法使用ajax,所訪問的介面為Authpost下的groupBindUser方法:

//組系結用戶
    public function groupBindUser(){
        $request_data = Request::post();

        $data['uid']=$request_data['uid'];
        $data['group_id']=$request_data['gid'];
        
        $data['create_time']=$data['update_time']=time();

        //存盤
        $res = AuthGroupAccess::create($data);
        
        if($res){
            return json((new ReturnCodeInfo())->actionSuccess());
        }else{
            return json((new ReturnCodeInfo())->actionError());
        }
    }

該方法主要使用AuthGroupAccess模型呼叫create方法進行資料插入,資料庫存盤如下:
在這里插入圖片描述
為用戶id對應的組id,
隨后進入組頁面,進行組系結規則的操作,點擊編輯進入超級管理員編輯頁:
在這里插入圖片描述
選擇需要的規則,點擊提交完成規則與組的系結:
在這里插入圖片描述資料庫存盤如下:
在這里插入圖片描述
以上表中,id為組id,rules則為規則的id,

3.4 完成權限管理邏輯撰寫

為了使驗證層能夠靈活的使用,在admin目錄下創建一個AuthRuleValidate目錄,新建一php檔案名為AuthRuleValidateBase,內容如下:

<?php

namespace app\admin\AuthRuleValidate;
use think\Controller;
use think\Db;

class AuthRuleValidateBase extends Controller{
    //傳入uid 與當前 路由驗證是否有此權限
    public function check($uid,$access){
        $res=Db::table('tp_admin')
        ->alias('a')
        ->field('rules')
        ->join('tp_auth_group_access agc','a.id = '.$uid)
        ->join('tp_auth_group ag','ag.id = agc.group_id')
        ->find(); 

        $rules=Db::name('auth_rule')->field('rule')->where('id','in',$res['rules'])->select();
        $rules=array_column($rules, 'rule');
        in_array($access,$rules)?:$this->error('權限不足');
    }

}

邏輯很簡單,該方法接受當前的uid用于查詢用戶所屬組,改組擁有的規則,再通過規則與當前規則進行匹配,如含有則表示擁有該權限,
首先查詢tp_admin管理員表所在的組:

$res=Db::table('tp_admin')
        ->alias('a')
        ->field('rules')
        ->join('tp_auth_group_access agc','a.id = '.$uid)
        ->join('tp_auth_group ag','ag.id = agc.group_id')
        ->find(); 

得到結果后,查詢與改組id匹配的規則,最后判斷該權限是否在當前的規則內,是的話不做任何操作,否則提示權限不足,
隨后在controller控制器目錄下創建一基類php檔案,名為Base,內容為:

<?php
namespace app\admin\controller;

use think\Controller;
use think\facade\Session;
use app\admin\AuthRuleValidate\AuthRuleValidateBase;

class Base extends Controller{
    protected $beforeActionList = [
        'ruleCheck'=>['except' => 'login']
    ];

    protected function ruleCheck()
    {
        session('?admin')?:$this->error('未登錄或已失效','Index/login');
        $AuthRuleValidate=new AuthRuleValidateBase();
        $s=session('admin');
        /*echo request()->module().'/'.request()->controller().'/'.request()->action(); */
        
        $AuthRuleValidate->check($s['id'],strtolower(request()->controller()).'/'.strtolower(request()->action()));
    }
}

該檔案引入了剛剛創建的權限判斷類,在此基礎上并且判斷了該用戶是否登錄,
查看代碼:

protected $beforeActionList = [
        'ruleCheck'=>['except' => 'login']
    ];

該代碼為設定前置曹祖,其中except表示除什么方法之外,在這里設定除login登錄方法外,因為所有用戶都必須登錄后才能判斷權限,登錄方法則不受此影響,隨后查看ruleCheck方法,該方法首先判斷用戶是否登錄:

session('?admin')?:$this->error('未登錄或已失效','Index/login');

隨后新建權限判斷類:

$AuthRuleValidate=new AuthRuleValidateBase();

接著使用seesion獲取uid:

$s=session('admin');

最后呼叫權限判斷方法傳入當前控制器方法與uid進行權限判斷:

 $AuthRuleValidate->check($s['id'],strtolower(request()->controller()).'/'.strtolower(request()->action()));

完全權限判斷基類后,使所有管理后臺的控制器繼承與該方法,例Auth控制器(該操作可以等待登錄頁撰寫后再進行):

class Auth extends Base{

3.5 完成登錄功能撰寫

在admin模塊中,index控制器添加方法login,內容為:

public function login(){
        return $this->view->fetch();
    }

前端代碼使用ajax傳值,前端頁顯示如下:
在這里插入圖片描述
隨后填入帳號及密碼通過ajax傳值到admin模塊下的Authpost控制器中login方法中,內容如下:

//登錄
    public function login(){
        $request_data = Request::post();
        $data['username']=$request_data['user'];
        $data['password']=md5(trim($request_data['password']));

        $res=db('admin')->where($data)->find();
        $res?session('admin', $res):$this->error('帳號或密碼錯誤');
    }

使用find方法對傳入值進行對比,密碼正確則將值傳入到seesion否則將提示帳號密碼錯誤,

3.6 完成傳入值的判斷

在基本權限實作完成后,使用驗證器對傳入值進行判斷,畢竟外部值都是不可靠的值,
在controller同級下創建一目錄validate,創建目錄后在該目錄下創建一php檔案名為BaseValidate作為對資料進行判斷類的基類,代碼內容如下:

<?php
namespace app\admin\validate;

use think\Validate;
use think\Controller;
use app\admin\code\ReturnCodeInfo;

class BaseValidate extends Validate{

    public function gocheck($validata){
        if(!$this->check($validata)){
            return (new ReturnCodeInfo())->validataError($this->getError());
        }
        return (new ReturnCodeInfo())->validataSuccess();
    }
}

該類繼承驗證器類,具有驗證器特性,驗證器的使用查看tp5.1檔案,
查看gocheck方法,gocheck方法呼叫了驗證器本身的check方法,其接收的引數$validata為需要驗證的資料,check判斷錯誤則呼叫 ReturnCodeInfo類中的報錯資料回傳,否則則回傳正確,
假設在管理員添加時需要驗證資料是否合規,那么在validate目錄中創建一名為AdminValidate的php檔案,內容為:

<?php
namespace app\admin\validate;

use app\admin\validate\BaseValidate;

class AdminValidate extends BaseValidate{
    protected $rule = [
        'password'  =>  'require|max:50',
        'username'  =>  'require|max:30',
        'realname'  =>  'require|max:30',
        'group'  =>  'require|max:30'
    ];

}

在管理員添加方法中(Authpost控制器中的adminadd方法)添加:

//驗證器
        $valires=(new AdminValidate())->gocheck($data);
        if ($valires['code']==10002){
            return json($valires);
        }

即可完成,但一定要注意,需要引入該驗證器:

use app\admin\validate\AdminValidate;

四、完成內容管理功能的撰寫

4.1 完成管理后臺模塊搭建

我們首先實作查看輪播圖區域元素:
在這里插入圖片描述

發現元素包含輪播圖示題、簡介,以及輪播圖示題1、簡介1以及背景圖,資料庫設計如下:

在這里插入圖片描述

我們通過sqlyog的可視化操作添加輪播圖所需要資源的資料,可以通過郵件檢查直接獲取資源路徑及內容:
在這里插入圖片描述

首先得到輪播圖第一張圖片的資料:
在這里插入圖片描述
復制內容填入sqlyog表中:
在這里插入圖片描述
同理獲取所有的內容填入至表:
在這里插入圖片描述
所有內容填入資料庫:
在這里插入圖片描述

回到index模塊下的index控制器中,在index方法中添加獲取輪播圖資料表中資料:

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;

class Index extends Controller{
    public function index()
    {
        $banner_res=Db::table('tp_home_banner')
        ->order('id', 'desc')
        ->limit(4)
        ->select();
        print_r($banner_res);
        die;
        return $this->view->fetch();
    }

}

在以上代碼中,使用select方法查詢輪播圖資料表中的資料,查詢方式是id的降序,這樣使輪播圖將會以最新添加的作為顯示依據,并且每次只查詢前4條;查詢結構復制給變數banner_res,使用print_r對該變數進行輸出,隨后在輸出模板前使用die終止,查看輸出,
訪問localhost成功獲得資料:
在這里插入圖片描述
在index方法中添加代碼,像前端傳遞banner_res變數,并且洗掉die代碼:

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;

class Index extends Controller{
    public function index()
    {
        $banner_res=Db::table('tp_home_banner')
        ->order('id', 'desc')
        ->limit(4)
        ->select();

        $this->view->assign('banner',$banner_res);
        return $this->view->fetch();
    }

}

接下來我們將在html代碼中使用tp的前端模板語法對一些html元素進行控制,我們通過元素查詢得知輪播圖元素id為homev1:
在這里插入圖片描述在代碼中找到id為homev1的元素,查看代碼,每個輪播圖示簽類似,只有默認選項多了個class修飾:
在這里插入圖片描述
但是有些小伙伴覺得很麻煩,那我們換一種方式,使用tp框架前端的模板語法,類似if判斷,從而輸出內容:
在這里插入圖片描述

首先使用volist標簽進行回圈,在標簽中設定回圈變數key,該key回圈第一次的值為1,當為1使用eq標簽判斷,是1則輸出第一個輪播圖的html代碼:

{eq name="k" value="1"}

需要輸出的html代碼需要使用成對的eq標簽包含,結束的eq標簽為 {/eq},
代碼如下:

<div class="carousel-inner" role="listbox">
                        <!-- Third Slide -->
                        {volist name="banner" id="vo" key="k" }
                        {eq name="k" value="1"}
                        <div class="item active">
                            <!-- Slide Background -->
                            <img src="{$vo.img}" alt="SeoPress Slider" />
                            <div class="bs-slider-overlay"></div>

                            <div class="container">
                                <div class="row">
                                    <div class="col-md-8 col-md-offset-2">
                                        <div class="slide-text slide_style_center">
                                            <h1 class="text-white" data-animation="animated zoomInRight">{$vo.title}</h1>
                                            <p class="text-white m-top-10" data-animation="animated fadeInLeft">{$vo.content}</p>
                                            <a class="btn btn-primary btn-round m-top-30" data-animation="animated fadeInLeft" href="" target="_blank">Read More</a>
                                            <a class="btn btn-default btn-round m-top-30" data-animation="animated fadeInRight" href="" target="_blank">Read More</a>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        {/eq}
                        <!-- End of Slide -->
                        {eq name="k" value="2"}
                        <!-- Second Slide -->
                        <div class="item">
                            <img src="{$vo.img}" alt="SeoPress Slider" />
                            <div class="bs-slider-overlay"></div>
                            <div class="container">
                                <div class="row">
                                    <!-- Slide Text Layer -->
                                    <div class="col-md-6">
                                        <div class="slide-text slide_style_left">
                                            <h1 class="text-white" data-animation="animated fadeInRight">{$vo.title}</h1>
                                            <p class="text-white m-top-10" data-animation="animated zoomInLeft">{$vo.content}
                                            </p>

                                            <a class="btn btn-default btn-round m-top-30" data-animation="animated fadeInRight" href="" target="_blank">Read More</a>
                                            <a class="btn btn-primary btn-round m-top-30" data-animation="animated fadeInLeft" href="" target="_blank">Read More</a>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <!-- End of Slide -->
                        {/eq}
                        {eq name="k" value="3"}
                        <!-- Third Slide -->
                        <div class="item">
                            <img src="{$vo.img}" alt="SeoPress Slider" />
                            <div class="bs-slider-overlay"></div>
                            <div class="container">
                                <div class="row">
                                    <!-- Slide Text Layer -->
                                    <div class="col-md-6">
                                        <div class="slide-text slide_style_left">
                                            <h1 class="text-white" data-animation="animated fadeInDown">{$vo.title}</h1>
                                            <p class="text-white m-top-10" data-animation="animated fadeInLeft">{$vo.content}
                                            </p>

                                            <a class="btn btn-primary btn-round m-top-30" data-animation="animated fadeInLeft" href="" target="_blank">Read More</a>
                                            <a class="btn btn-default btn-round m-top-30" data-animation="animated fadeInRight" href="" target="_blank">Read More</a>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        {/eq}
                        {eq name="k" value="4"}
                        <!-- Fourth Slide -->
                        <div class="item">
                            <img src="{$vo.img}" alt="SeoPress Slider" />
                            <div class="bs-slider-overlay"></div>
                            <div class="container">
                                <div class="row">
                                    <!-- Slide Text Layer -->
                                    <div class="col-md-6">
                                        <div class="slide-text slide_style_left">
                                            <h1 class="text-white" data-animation="animated fadeInLeft">{$vo.title} <br />
                                                Online Marketing Needs</h1>
                                            <p class="text-white m-top-10" data-animation="animated fadeInRight">{$vo.content}
                                            </p>
                                            <a class="btn btn-primary btn-round m-top-30" data-animation="animated fadeInLeft" href="" target="_blank">Read More</a>
                                            <a class="btn btn-default btn-round m-top-30" data-animation="animated fadeInRight" href="" target="_blank">Read More</a>
                                        </div>
                                    </div>

                                </div>
                            </div>
                        </div>
                        {/eq}
                        {/volist}
                        <!-- End of Slide -->
                    </div><!-- End of Wrapper For Slides -->

接著我們往下查看首頁內容:
在這里插入圖片描述

個人覺得該區域可以放一個“有利于”之類的宣傳語,那么建一表存放標題、圖片、內容資訊:
在這里插入圖片描述
在該表中填入網頁中原有的資料:
在這里插入圖片描述
在index控制器中添加查詢tp_home_advantageous表資料的代碼并將結果傳至前端:

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;

class Index extends Controller{
    public function index()
    {
        $banner_res=Db::table('tp_home_banner')
        ->order('id', 'desc')
        ->limit(4)
        ->select();

        $advantageous_res=Db::table('tp_home_advantageous')
        ->order('id', 'desc')
        ->limit(6)
        ->select();

        $this->view->assign('advantageous',$advantageous_res);
        $this->view->assign('banner',$banner_res);
        return $this->view->fetch();
    }

}

修改前端代碼,發現該區域代碼的html幾乎一致,前3個的class=“service-item sm-m-top-65”,后3個的class=“service-item m-top-65”:

<div class="main-service-area text-center m-top-80">
                            <div class="col-md-4 col-sm-6">
                                <div class="service-item sm-m-top-65">
                                    <div class="service-icon">
                                        <img src="/home/assets/images/service1.png" alt="" />
                                    </div>
                                    <h5 class="text-info m-top-50">Search Engine Optimization</h5>
                                    <p class="text-black m-top-20">With our 17+ years of experience, our SEO services will get your site ranking.</p>
                                </div>
                            </div>
                            <div class="col-md-4 col-sm-6">
                                <div class="service-item sm-m-top-65">
                                    <div class="service-icon">
                                        <img src="/home/assets/images/service3.png" alt="" />
                                    </div>
                                    <h5 class="text-info m-top-50">Content Marketing</h5>
                                    <p class="text-black m-top-20">From blogs and social posts to 
                                        infographics videos we create and promote quality.</p>
                                </div>
                            </div>
                            <div class="col-md-4 col-sm-6">
                                <div class="service-item sm-m-top-65">
                                    <div class="service-icon">
                                        <img src="/home/assets/images/service2.png" alt="" />
                                    </div>
                                    <h5 class="text-info m-top-50">Social Media Marketing</h5>
                                    <p class="text-black m-top-20">Boost brand awareness and reach your 
                                        customers on a human level.</p>
                                </div>
                            </div>
                            <div class="col-md-4 col-sm-6">
                                <div class="service-item m-top-65">
                                    <div class="service-icon">
                                        <img src="/home/assets/images/service4.png" alt="" />
                                    </div>
                                    <h5 class="text-info m-top-50">Web Design & Development</h5>
                                    <p class="text-black m-top-20">Our designers and developers will create an attractive, SEO-friendly & fully functional.</p>
                                </div>
                            </div>
                            <div class="col-md-4 col-sm-6">
                                <div class="service-item m-top-65">
                                    <div class="service-icon">
                                        <img src="/home/assets/images/service5.png" alt="" />
                                    </div>
                                    <h5 class="text-info m-top-50">eCommerce Solutions</h5>
                                    <p class="text-black m-top-20">With our 17+ years of experience, 
                                        our SEO services will get your site ranking.</p>
                                </div>
                            </div>
                            <div class="col-md-4 col-sm-6">
                                <div class="service-item m-top-65">
                                    <div class="service-icon">
                                        <img src="/home/assets/images/service6.png" alt="" />
                                    </div>
                                    <h5 class="text-info m-top-50">Inbound Marketing</h5>
                                    <p class="text-black m-top-20">With our ecommerce solutions, 
                                        you'll provide an enjoyable, seamless.</p>
                                </div>
                            </div>
                        </div>

這是把其它div洗掉,留下1個div,使用volist標簽進行遍歷輸出值,并且設定回圈變數key,使用tp框架的前端判斷標簽,判斷小于4時輸出class為col-sm-6:

{lt name="k" value="4"}col-sm-6{/eq}

當回圈后3三位,則是k值大于3,大于3輸出col-sm-6,使用gt標簽:

{gt name="k" value="3"}col-sm-6{/eq}

將兩個前端代碼撰寫與div中,完整代碼如下:

<div class="main-service-area text-center m-top-80">
    {volist name="advantageous" id="vo" key="k" }
    <div class="col-md-4 col-sm-6">
        <div class='service-item {lt name="k" value="4"}col-sm-6{/eq} {gt name="k" value="3"}col-sm-6{/eq}'>
            <div class="service-icon">
                <img src="{$vo.img}" alt="" />
            </div>
            <h5 class="text-info m-top-50">{$vo.title}</h5>
            <p class="text-black m-top-20">{$vo.content}</p>
        </div>
    </div>
    {/volist}
</div>

運行結果:
在這里插入圖片描述
接著往下,查看頁面區域:
在這里插入圖片描述

我們將該頁面撰寫成產品展示區域,新建一資料庫表:
在這里插入圖片描述
填入內容:
在這里插入圖片描述在index控制器index方法中添加product資料庫查詢代碼并傳至前端:

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;

class Index extends Controller{
    public function index()
    {
        $banner_res=Db::table('tp_home_banner')
        ->order('id', 'desc')
        ->limit(4)
        ->select();

        $advantageous_res=Db::table('tp_home_advantageous')
        ->order('id', 'desc')
        ->limit(6)
        ->select();

        $product_res=Db::table('tp_home_product')
        ->order('id', 'desc')
        ->limit(2)
        ->select();

        $this->view->assign('product',$product_res);
        $this->view->assign('advantageous',$advantageous_res);
        $this->view->assign('banner',$banner_res);
        return $this->view->fetch();
    }

}

隨后在html代碼中輸出內容即可:

<section id="leading" class="leading bg-primary sections2">
                <div class="container">
                    <div class="row">
                        <div class="main-leading">
                            <div class="col-md-6">
                                <div class="leading-content">
                                    <div class="head-title">
                                        <h2 class="text-white">{$product[0]['title']}</h2>
                                        <p class="m-top-30 text-white">{$product[0]['specs']}</p>

                                        <div class="separator2 hv2"><span></span><span></span><span></span></div>
                                    </div>

                                    <p class="m-top-40">{$product[0]['content']}</p>
                                    <a href="" class="btn btn-default btn-round m-top-20">Our Team</a>

                                </div>
                            </div>
                            <div class="col-md-5">
                                <div class="leading-img sm-m-top-50">
                                    <img src="{$product[0]['img']}" alt="" />
                                </div>
                            </div>
                        </div>
                    </div><!-- End off row-->
                </div><!-- End off container -->
            </section><!-- End off leading section-->
            <!--Allies Section-->
            <section id="allies" class="allies sections">
                <div class="container">
                    <div class="row">

                        <div class="main-allies">
                            <div class="col-md-5">
                                <div class="allies-img">
                                    <img src="{$product[1]['img']}" alt="" />
                                </div>
                            </div>

                            <div class="col-md-7">
                                <div class="allies-content sm-m-top-50">
                                    <div class="head-title">
                                        <h2 class="text-black">O{$product[1]['title']}</h2>
                                        <h5 class="text-black m-top-30">{$product[1]['content']}</h5>
                                        <div class="separator2"><span></span><span></span><span></span></div>

                                    </div>
                                    <p class="m-top-40">{$product[1]['specs']}</p>

                                    <a href="" class="btn btn-primary btn-round m-top-30">Portfolio</a>

                                </div>
                            </div>
                        </div>

                    </div><!-- End off row -->
                </div><!--End off container -->
            </section><!-- End off Allies Section-->

接著往下看:
在這里插入圖片描述

該區域可以更改成文章的展示,創建已資料庫表:
在這里插入圖片描述
添加內容:
在這里插入圖片描述

查看html代碼:

<div class="col-md-4 col-sm-6">
                                        <div class="studies-item">
                                            <div class="studies-feature border">
                                                <img class="img-rounded" src="/home/assets/images/studies-img-01.jpg" alt="" />
                                                <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
                                                <div class="custom-hover"></div>
                                            </div>
                                            <div class="studies-conten m-top-30">
                                                <h4><a href="">Acme Corporation</a></h4>
                                                <p class="m-top-10">Objective: Build a larger twitter community</p>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4 col-sm-6">
                                        <div class="studies-item xs-m-top-35">
                                            <div class="studies-feature border">
                                                <img class="img-rounded" src="/home/assets/images/studies-img-02.jpg" alt="" />
                                                <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
                                            </div>
                                            <div class="studies-conten m-top-30">
                                                <h4><a href="">Soylent Corp </a></h4>
                                                <p class="m-top-10">Objective: Make tone & branding consistency</p>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4 col-sm-6">
                                        <div class="studies-item sm-m-top-35">
                                            <div class="studies-feature border">
                                                <img class="img-rounded" src="/home/assets/images/studies-img-03.jpg" alt="" />
                                                <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
                                            </div>
                                            <div class="studies-conten m-top-30">
                                                <h4><a href="">Umbrella Corporation</a></h4>
                                                <p class="m-top-10">Objective: Eliminate the residue of black-hat methods</p>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4 col-sm-6">
                                        <div class="studies-item m-top-35">
                                            <div class="studies-feature border">
                                                <img class="img-rounded" src="/home/assets/images/studies-img-04.jpg" alt="" />
                                                <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
                                            </div>
                                            <div class="studies-conten m-top-30">
                                                <h4><a href="">Initech</a></h4>
                                                <p class="m-top-10">Objective: Improve site load speed & functionality</p>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4 col-sm-6">
                                        <div class="studies-item m-top-35">
                                            <div class="studies-feature border">
                                                <img class="img-rounded" src="/home/assets/images/studies-img-05.jpg" alt="" />
                                                <div class="studies-overlay img-rounded">
                                                    <a href="">
                                                        <span class="icon icon-arrows-2 hvr-hang"></span>
                                                    </a>
                                                </div>
                                            </div>
                                            <div class="studies-conten m-top-30">
                                                <h4><a href="">Vehement Capital Partners </a></h4>
                                                <p class="m-top-10">Objective: Increase nationwide sales</p>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4 col-sm-6">
                                        <div class="studies-item m-top-35">

                                            <div class="studies-feature border">
                                                <img class="img-rounded" src="/home/assets/images/studies-img-06.jpg" alt="" />
                                                <div class="studies-overlay img-rounded">
                                                    <a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a>
                                                </div>
                                            </div>
                                            <div class="studies-conten m-top-30">
                                                <h4><a href="">Massive Dynamic</a></h4>
                                                <p class="m-top-10">Objective: Increase qualified traffic</p>
                                            </div>
                                        </div>
                                    </div>

發現該html代碼中前3個div的class有所變化,后3個div布局內容則無變化,我們使用eq標簽使前3個div照原樣輸出,后3個div遍歷輸出:

{volist name="article" id="vo" key="k" }
{eq name="k" value="1"}
 <div class="col-md-4 col-sm-6">
     <div class="studies-item">
         <div class="studies-feature border">
             <img class="img-rounded" src="{$vo.img}" alt="" />
             <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
             <div class="custom-hover"></div>
         </div>
         <div class="studies-conten m-top-30">
             <h4><a href="">{$vo.title}</a></h4>
             <p class="m-top-10">{$vo.content}</p>
         </div>
     </div>
 </div>
 {/eq}
 {eq name="k" value="2"}
 <div class="col-md-4 col-sm-6">
     <div class="studies-item xs-m-top-35">
         <div class="studies-feature border">
             <img class="img-rounded" src="{$vo.img}" alt="" />
             <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
         </div>
         <div class="studies-conten m-top-30">
             <h4><a href="">{$vo.title}</a></h4>
             <p class="m-top-10">{$vo.content}</p>
         </div>
     </div>
 </div>
 {/eq}
 {eq name="k" value="3"}
 <div class="col-md-4 col-sm-6">
     <div class="studies-item sm-m-top-35">
         <div class="studies-feature border">
             <img class="img-rounded" src="{$vo.img}" alt="" />
             <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
         </div>
         <div class="studies-conten m-top-30">
             <h4><a href="">{$vo.title}</a></h4>
             <p class="m-top-10">{$vo.content}</p>
         </div>
     </div>
 </div>
 {/eq}
 {gt name="k" value="3"}
 <div class="col-md-4 col-sm-6">
     <div class="studies-item m-top-35">
         <div class="studies-feature border">
             <img class="img-rounded" src="{$vo.img}" alt="" />
             <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
         </div>
         <div class="studies-conten m-top-30">
             <h4><a href="">{$vo.title}</a></h4>
             <p class="m-top-10">{$vo.content}</p>
         </div>
     </div>
 </div>
 {/gt}
 {/volist}

在index控制器的首頁方法index中添加對article表資料的查詢:

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;

class Index extends Controller{
    public function index()
    {
        $banner_res=Db::table('tp_home_banner')
        ->order('id', 'desc')
        ->limit(4)
        ->select();

        $advantageous_res=Db::table('tp_home_advantageous')
        ->order('id', 'desc')
        ->limit(6)
        ->select();

        $product_res=Db::table('tp_home_product')
        ->order('id', 'desc')
        ->limit(2)
        ->select();

        $article_res=Db::table('tp_home_article')
        ->order('id', 'desc')
        ->limit(6)
        ->select();

        $this->view->assign('article',$article_res);
        $this->view->assign('product',$product_res);
        $this->view->assign('advantageous',$advantageous_res);
        $this->view->assign('banner',$banner_res);
        return $this->view->fetch();
    }

}

其它的前端內容通過資料庫更改不再贅述,

4.2 完成通過后臺設定更改與添加前端內容

創建控制器Contentmanger,添加方法bannerManger,bannerManger方法跳轉到一頁面用于顯示banner資料,點擊每條資料可進行編輯:
在這里插入圖片描述

由于有資料的查詢,在控制器中需要查詢banner表資料,代碼為:

<?php
/**
 * |-----------------------
 * | 頁面跳轉
 * |-----------------------
 */
namespace app\admin\controller;
use think\Controller;
use think\Db;
use think\facade\Request;

class Contentmanger extends Base{

    //官網首頁內容管理
    public function bannerManger(){

        $list=Db::table('tp_home_banner')
        ->order('id')
        ->select();
        
        $this->view->assign('list',$list);
        return $this->view->fetch();
    }
}

此處可添加驗證器檢測傳入值是否正確,為了節省篇幅接下來的代碼中不再過多的添加其它內容,
html代碼前端的編輯修改按鈕,使用了url方法傳參,傳參后獲取該id的內容,方便進行修改:
在這里插入圖片描述
點擊編輯后將會可以隨意修改banner的值:
在這里插入圖片描述
點擊choosefile可選擇img檔案,修改banner圖片,

創建一控制器用來管理內容修改操作的邏輯,創建一php檔案名為 Contentmangerpost ,添加 bannerEdit 方法:

<?php
/**
 * |-----------------------
 * | 頁面跳轉
 * |-----------------------
 */
namespace app\admin\controller;
use think\Controller;
use think\Db;
use think\facade\Request;
use \think\File;

use app\admin\model\Goods;
use app\admin\validate\IdValidate;
use app\admin\code\ReturnCodeInfo;

class Contentmangerpost extends Base{
    //輪播圖編輯
    public function bannerEdit(){
        $save_path='/public';
        $save_path_='/uploads/imgs/';
        $request_data = Request::post();
        $con['id']=$request_data['id'];
        $data['title']=$request_data['title'];
        $data['title_2']=$request_data['title_2'];
        $data['content']=$request_data['content'];
        $data['content_2']=$request_data['content_2'];


        // 獲取表單上傳檔案 例如上傳了001.jpg
        $file = request()->file('file');
        if($file){
            // 移動到框架應用根目錄/uploads/ 目錄下
            $info = $file->move('..'.$save_path.$save_path_);
            if($info){
                // 成功上傳后 獲取上傳資訊
                $data['img']=$save_path_.str_replace('\\','/',$info->getSaveName());
            }else{
                // 上傳失敗獲取錯誤資訊
                echo $file->getError();
            }  
        }else{
            $data['img']='/home/assets/images/slide-bg-01.jpg';
        }


        $res=Db::name('home_banner')
        ->where($con)
        ->update($data);

        if($res){
            return json((new ReturnCodeInfo())->actionSuccess());
        }else{
            return json((new ReturnCodeInfo())->actionError());
        }
    }
}

以上代碼使用request()->file(‘file’);判斷是否接收到file值,如接收到說明用戶選擇了新圖片,那么使用move方法保存圖片,通過getSaveName方法獲取保存圖片名,最終更新至資料庫中,其它資料的更新方法與該步驟類似,不再贅述,接下來通過拖拽實作web并且系結資料,

五、完成頁面拖拽生成并系結資料功能的撰寫

拖拽頁面在此提供一個思想,通過bootstrap的layoutit可視化布局可以完成簡單頁面拖拽生成,需要完成更多復雜的界面需要對layoutit進行二次開發,本篇內容為一個demo,通過可視化layoutit生成界面且進行代碼替換完成對于thinkphp模板的制作,最后通過可視化資料系結生成php代碼,

5.1 完成拖拽界面的前端搭建

首先為layoutit添加一個控制器并更改資源路徑,此操作不再贅述,部署完成后打開界面:
在這里插入圖片描述

可拖拽布局實作界面編輯:
在這里插入圖片描述

拖拽成如下界面:
在這里插入圖片描述
點擊下載可查看生成的html代碼:
在這里插入圖片描述

在點擊下載時,我通過js保存了生成的代碼:

	  var template=''; 
	  $("[data-target=#downloadModal]").click(function(e) {
	    e.preventDefault();
	    downloadLayoutSrc();
	  });
	
	  function downloadLayoutSrc() {
	    var e = "";
	    $("#download-layout").children().html($(".demo").html());
	    var t = $("#download-layout").children();
	    t.find(".preview, .configuration, .drag, .remove").remove();
	    t.find(".lyrow").addClass("removeClean");
	    t.find(".box-element").addClass("removeClean");
	    t.find(".lyrow .lyrow .lyrow .lyrow .lyrow .removeClean").each(function() {
	      cleanHtml(this)
	    });
	    t.find(".lyrow .lyrow .lyrow .lyrow .removeClean").each(function() {
	      cleanHtml(this)
	    });
	    t.find(".lyrow .lyrow .lyrow .removeClean").each(function() {
	      cleanHtml(this)
	    });
	    t.find(".lyrow .lyrow .removeClean").each(function() {
	      cleanHtml(this)
	    });
	    t.find(".lyrow .removeClean").each(function() {
	      cleanHtml(this)
	    });
	    t.find(".removeClean").each(function() {
	      cleanHtml(this)
	    });
	    t.find(".removeClean").remove();
	    $("#download-layout .column").removeClass("ui-sortable");
	    $("#download-layout .row-fluid").removeClass("clearfix").children().removeClass("column");
	    if ($("#download-layout .container").length > 0) {
	      changeStructure("row-fluid", "row")
	    }
	    formatSrc = $.htmlClean($("#download-layout").html(), {
	      format: true,
	      allowedAttributes: [
	        ["id"],
	        ["class"],
	        ["data-toggle"],
	        ["data-target"],
	        ["data-parent"],
	        ["role"],
	        ["data-dismiss"],
	        ["aria-labelledby"],
	        ["aria-hidden"],
	        ["data-slide-to"],
	        ["data-slide"]
	      ]
	    });
	    $("#download-layout").html(formatSrc);
	    $("#downloadModal textarea").empty();
	    $("#downloadModal textarea").val(formatSrc)
	    console.log(formatSrc);
	    template=formatSrc;
	  }

此代碼為layoutit的js代碼,在此基礎上我新建了已js全域變數保存資料,變數為template,在js代碼清洗完成后把清洗后的值賦值給全域變數template,
隨后點擊保存:

<button class="btn btn-primary" onclick="bc()">保存</button>

保存按鈕點擊后對應的js代碼為:

function bc(){
                {literal} 
                template='{$head|raw}'+'<body style="min-height: 816px; cursor: auto;" class="devpreview sourcepreview">'+template+'</body>';
                {/literal} 
                $.ajax({
                    type:'post',
                    url:'/index.php?s=/admin/Autoviewpost/test/',
                    data:{"template":template},
                    dataType:"json", 
                    success:function(data){
    
                    },error:function(jqXHR){
    
                    }
                })  
              }

在因為生成的代碼需要一定的js檔案引入,在此我添加了{$head|raw}為前端的模板代碼,使用了{literal} 標簽對thinkphp的模板代碼進行修飾,表示不決議其中內容,head變數的內容為:

$head='<link href="/autoview/css/bootstrap-combined.min.css" rel="stylesheet">
        <link href="/autoview/css/layoutit.css" rel="stylesheet">
        <!-- Le styles -->
        <link href="/autoview/css/bootstrap-combined.min.css" rel="stylesheet">
        <link href="/autoview/css/layoutit.css" rel="stylesheet">
        
        <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
        <!--[if lt IE 9]>
                <script src="/autoview/js/html5shiv.js"></script>
            <![endif]-->
        
            <!-- Fav and touch icons -->
            <link rel="shortcut icon" href="/autoview/img/favicon.png">
            
            <script type="text/javascript" src="/autoview/js/jquery-2.0.0.min.js"></script>
            <!--[if lt IE 9]>
            <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
            <![endif]-->
            <script type="text/javascript" src="/autoview/js/bootstrap.min.js"></script>
            <script type="text/javascript" src="/autoview/js/jquery-ui.js"></script>
            <script type="text/javascript" src="/autoview/js/jquery.ui.touch-punch.min.js"></script>
        <script type="text/javascript" src="/autoview/js/jquery.htmlClean.js"></script>
        <script type="text/javascript" src="/autoview/ckeditor/ckeditor.js"></script>
        <script type="text/javascript" src="/autoview/ckeditor/config.js"></script>
        <script type="text/javascript" src="/autoview/js/scripts.js"></script>';

點擊保存后,生成的html代碼文本將會傳到Autoviewpost控制器下的test方法中,test方法代碼如下:

public function test(){
        $request_data = Request::post();
        $template=$request_data['template'];

        /* $regex4="/<div class=\"media\".*?>.*?<\/div>.*?<\/div>/ism";   */
        $template=preg_replace(getMediaReStr(),getMediaHtmlStr(),$template);//media 替換
        $template=preg_replace(getCarouselReStr(),getCarouselHtmlStr(),$template);//輪播圖 替換
        $template=preg_replace(getThumbnailsReStr(),getThumbnailsHtmlStr(),$template);//縮略圖 替換
        $template=preg_replace(getUnitReStr(),getUnitHtmlStr(),$template);//概述 替換

        $template=str_replace("{eq name=&quot;key&quot; value=&quot;1&quot;}active{/eq}",'{eq name="key" value="1"}active{/eq}',$template);
        
        file_put_contents(dirname(dirname(__FILE__)).'\view\templates\t1.html',$template);
        /* print_r($request_data['template']);  */
    }

該方法在接收值后對一部分進行替換,使用preg_replace對文本進行替換,在該對比中我使用了正則對資料進行匹配,該方法我撰寫在common公共函式的php檔案中,地址為application\common.php,內容為:

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 流年 <liu21st@gmail.com>
// +----------------------------------------------------------------------

// 應用公共檔案
function arrunset(&$arr){
    array_splice($arr,0,1);
}

//Media php code
function getMediaHtmlStr(){
    $str='{volist name="media" id="data" }'.
    '<div class="media">'.
    '<a href="{$data.src}" class="pull-left"><img src="{$data.img}" class="media-object" alt=\'\' /></a>'.
    '<div class="media-body">'.
    '<h4 class="media-heading">'.
    '{$data.title}'.
    '</h4> {$data.content}'.
    '</div>'.
    '</div>'.
    '{:arrunset($media)}'.
    '{/volist}';
    return $str;
}
//Media regex str
function getMediaReStr(){
    $re="/<div class=\"media\".*?>.*?<\/div>.*?<\/div>/ism"; 
    return $re;
}

//輪播圖 php code
function getCarouselHtmlStr(){
    $str='<div class="carousel slide" id="carousel-998124"><div class="carousel-inner"> '.
    '{volist name="banner" id="data"}'.
    '<div class=\'item {eq name="key" value="1"}active{/eq} \'>'.
    '<img alt="" src="{$data.img}" />'.
    '<div class="carousel-caption">'.
    '<h4>'.
    '{$data.title}'.
    '</h4>'.
    '<p>'.
    '{$data.content}'.
    '</p>'.
    '</div>'.
    '</div>'.
    '{/volist} '.
    '</div> '.
    '<a data-slide="prev" href="#carousel-998124" class="left carousel-control">?</a><a data-slide="next" href="#carousel-998124" class="right carousel-control">?</a></div>';
    return $str;
}
//輪播圖 regex str
function getCarouselReStr(){
    $re="/<div class=\"carousel slide\".*?>.*?class=\"right carousel-control\">.*?<\/div>/ism"; 
    return $re;
}


//縮略圖 php code
function getThumbnailsHtmlStr(){
    $str='<ul class="thumbnails">'.
    '{volist name="article" id="data"}'.
    '<li class="span4">'.
    '<div class="thumbnail"> <img alt="300x200" src="{$data.faceimg}">'.
    '<div class="caption" contenteditable="true">'.
    '<h3>{$data.title}</h3>'.
    '<p>{$data.content}</p>'.
    '<p><a class="btn btn-primary" href="#">瀏覽</a> <a class="btn" href="#">分享</a></p>'.
    '</div>'.
    '</div>'.
    '</li>'.
    '{/volist}'.
    '</ul>';
    return $str;
}
//縮略圖 regex str
function getThumbnailsReStr(){
    $re="/<ul class=\"thumbnails\".*?>.*?<\/ul>/ism"; 
    return $re;
}

//概述 php code
function getUnitHtmlStr(){
    $str='{volist name="ad" id="data" offset="0" length=\'1\'}'.
    '<div class="hero-unit" contenteditable="true">'.
    '<h1>{$data.title}</h1>'.
    '<p>{$data.content} </p>'.
    '<p><a class="btn btn-primary btn-large" href="#">參看更多 ?</a></p>'.
    '</div>'.
    '{:arrunset($ad)}'.
    '{/volist}' ;
    return $str;
}
//概述 regex str
function getUnitReStr(){
    $re="/<div class=\"hero-unit\".*?>.*?<\/div>/ism"; 
    return $re;
}

使用不同的方法回傳不同組件、html代碼的正則匹配,替換成所需的帶有thinkphp框架語法的html代碼,這些代碼同樣在common檔案中,完成替換后由于發現某些字符需要進行替換,撰寫代碼:

$template=str_replace("{eq name=&quot;key&quot; value=&quot;1&quot;}active{/eq}",'{eq name="key" value="1"}active{/eq}',$template);

完成清洗替換后生成html模板生成危機:

file_put_contents(dirname(dirname(__FILE__)).'\view\templates\t1.html',$template);

由于是demo,所以位置寫死了,
隨后訪問Autoview控制器下的createcontrol方法(頁面沒寫):
在這里插入圖片描述
輸入你想要生成的控制器名、方法名,該方法需要系結資料表中哪些元素,以及系結的頁面路徑:
在這里插入圖片描述
輸入完成后點擊提交,資料將會傳到Autoview控制器中的buildcontrol方法中,方法代碼如下:

//控制器生成 方法名及資料庫
    public function buildcontrol(){
        $request_data = Request::post();
        $data['controll'] = $request_data['controll'];
        $data['function']=$request_data['function'];
        $data['datas']=$request_data['datas'];
        $data['templatepath']=$request_data['templatepath'];

        $controlcode='<?php

        namespace app\admin\controller;
        use think\Controller;
        use think\Db;
        
        class '.$data['controll'].' extends AutoviewBase{
        
            public function '.$data['function'].'(){
        
                return $this->view->fetch(dirname(dirname(__FILE__)).'.$data['templatepath'].');
            }
        }';

        file_put_contents(dirname(dirname(__FILE__)).'\controller\\'.$data['controll'].'.php',$controlcode);

        $res = Url_datas::create($data);

        if($res){
            return json((new ReturnCodeInfo())->actionSuccess());
        }else{
            return json((new ReturnCodeInfo())->actionError());
        }
    }

該方法controlcode變數為控制器模板變數,該模板文本可以得知該控制器名稱為自定義名稱,繼承于AutoviewBase基類,方法名也是自定義,模板位置根據指定路徑進行輸出渲染,最后使用 file_put_contents 進行控制器生成,最后將資料存入到Url_datas模型中,也是Url_datas表中,資料表結構資料如下:
在這里插入圖片描述

在這里插入圖片描述我們從控制器生成路徑中可以得知,是admin內的控制器,我們訪問生成的控制器方法查看效果:

在這里插入圖片描述

資料頁面得到顯示,這些資料都是資料庫中的資料,在創建控制器時,我們在指定資料表及欄位時使用的格式內容為如下:

{             
"banner":"id,title,img,content",            
 "article":"id,title,content,faceimg",             
 "media":"id,src,img,title,content",             
 "ad":"id,title,content,img"        
  }

資料指定格式為“資料表”:“欄位1,欄位2…”,通過在AutoviewBase的前置方法中對該json資料進行決議,AutoviewBase基類如下:

<?php
/**
 * |-----------------------
 * | 前端頁面自定義
 * |-----------------------
 */
namespace app\admin\controller;
use think\Controller;
use think\Db;

class AutoviewBase extends Controller{
    protected $beforeActionList = [
        'toview'
    ];

    public function toview(){
        $head='<link href="/autoview/css/bootstrap-combined.min.css" rel="stylesheet">
        <link href="/autoview/css/layoutit.css" rel="stylesheet">
        <!-- Le styles -->
        <link href="/autoview/css/bootstrap-combined.min.css" rel="stylesheet">
        <link href="/autoview/css/layoutit.css" rel="stylesheet">
        
        <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
        <!--[if lt IE 9]>
                <script src="/autoview/js/html5shiv.js"></script>
            <![endif]-->
        
            <!-- Fav and touch icons -->
            <link rel="shortcut icon" href="/autoview/img/favicon.png">
            
            <script type="text/javascript" src="/autoview/js/jquery-2.0.0.min.js"></script>
            <!--[if lt IE 9]>
            <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
            <![endif]-->
            <script type="text/javascript" src="/autoview/js/bootstrap.min.js"></script>
            <script type="text/javascript" src="/autoview/js/jquery-ui.js"></script>
            <script type="text/javascript" src="/autoview/js/jquery.ui.touch-punch.min.js"></script>
        <script type="text/javascript" src="/autoview/js/jquery.htmlClean.js"></script>
        <script type="text/javascript" src="/autoview/ckeditor/ckeditor.js"></script>
        <script type="text/javascript" src="/autoview/ckeditor/config.js"></script>
        <script type="text/javascript" src="/autoview/js/scripts.js"></script>';
        
        $con['controll']=strtolower(request()->controller());
        $con['function']=strtolower(request()->action());

        //by controll and action select rules
        $data_rules=Db::name('url_datas')
        ->where($con)
        ->order('id', 'desc')
        ->field('datas')
        ->find();
        
        //get datas
        $datas=[];
        $tables = json_decode($data_rules['datas'], true);
        foreach($tables as $key => $value){
            $datas[$key]=Db::name($key)
                        ->column($value);
        }

        //輸出到前端
        foreach($datas as $key => $value){
            $this->view->assign($key,$value);
        }


        $this->view->assign('head',$head);

        return $this->view->fetch(dirname(dirname(__FILE__)).'\view\templates\t1.html');
    }

}

以上代碼中定義了前置操作toview方法,在toview方法中定義了head為頭部資源檔案,之后使用如下代碼獲取當前控制器及方法名:

$con['controll']=strtolower(request()->controller());
$con['function']=strtolower(request()->action());

把控制器及方法名當作條件至url_datas資料表中查詢所需的資料要求及格式:

//by controll and action select rules
        $data_rules=Db::name('url_datas')
        ->where($con)
        ->order('id', 'desc')
        ->field('datas')
        ->find();

得到了所需資料后,對該資料進行json決議,決議后遍歷該資料作為對指定表與資料的查詢:

		$datas=[];
        $tables = json_decode($data_rules['datas'], true);
        foreach($tables as $key => $value){
            $datas[$key]=Db::name($key)
                        ->column($value);
        }

之后使用遍歷把得到的資料結果輸出到前端:

 //輸出到前端
    foreach($datas as $key => $value){
        $this->view->assign($key,$value);
    }

最后把head傳遞值前端代碼,渲染輸出:

 $this->view->assign('head',$head);
return $this->view->fetch(dirname(dirname(__FILE__)).'\view\templates\t1.html');

以上內容準備過于匆忙,只講解了實作中較為重要的地方,很多優化及細節沒有說明,希望下次將會撰寫一份完全的教程給大家!如有錯誤歡迎指出,想要深入學習可以關注博主,點贊博主、收藏博文,謝謝~
原創作品@CSDN 1_bit https://blog.csdn.net/A757291228

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/193161.html

標籤:其他

上一篇:2020年首發70道阿里巴巴高級Java開發面試題(帶詳細答案)

下一篇:2020-1024程式員節首屆嗶哩嗶哩安全挑戰賽Write Up

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more