基于laravel框架構建最小內容管理系統

校園失物招領平臺開發

——基于laravel框架構建最小內容管理系統



摘要

?

針對目前大學校園人口密度大、人群活動頻繁、師生學習生活等物品容易遺失的基本現狀,在分析傳統失物招領過程中的工作效率低下、找回率低、保密性差、管理分散等問題和不足的基礎上,提出了WEB模式的失物招領信息管理平臺。該平臺主要通過失物信息發布和失物領取功能,較好的解決了傳統失物招領管理過程中的信息孤島的缺陷,提高了失物招領的工作效率,減少了師生的直接經濟損失,方便了廣大師生的日常生活。 本系統采用了LAMP(ubuntu+Apache+MySQL+php)作為開發環境,后端php框架使用了目前流行的laravel框架,完全遵循MVC的設計模式。選用國產開源的響應式HTML5開發框架AmazeUI作為前端視圖框架,可以很好地適應移動端頁面布局。

關鍵詞:校園;失物招領;信息發布;內容管理系統;php;laravel;MySQL;AmazeUI

?


?

目錄

一、引言

1.課題研究背景及意義

2.系統可行性分析

二、系統需求分析

1.業務流程分析

2.用戶體驗分析

三、系統模塊設計

1.功能模塊

2.用戶界面

四、核心功能的技術實現

1.開發環境

2.技術框架

3.數據庫設計

4.MVC設計模式

5.核心代碼實現

6.測試及操作說明

五、總結

六、參考文獻


引言

1. 課題研究背景及意義

大學生由于攜帶的東西較多,活動多,而且經常來往于不同的地 方,因此很容易發生物品丟失的情況,而目前我們學校又缺乏一套行之有效的可以幫助學生尋找失物的系統。考慮到大學生普遍上網,而且校園網絡覆蓋率高, 那么就通過網絡這一便捷高效的方式來實現一個失物招領系統,優化失物招領業務,使得失物招領管理清晰化、透明化,便于操作,易于管理。通過本系統,拾主可以通過這個平臺發布最新的招領啟事以通知大 家,而失主可以通過這個平臺尋找和聯系拾主。并且只要是網站的注冊用戶,就可以發布管理文章、留言,這樣不僅財產上的損失避 免了,還加強了人與人之間的交流。所以說開發這個失物招領平臺,定會大大便利校園內廣大師生的生活,不必再為丟失尋找物品這類瑣事煩擾,真正地讓技術服務于生活。

?

2.系統可行性分析

  • 技術可行性

    利用穩定的ubuntu linux作為服務器環境,Apache處理客戶端與服務端的通信,MySQL數據庫存放用戶信息和發布的文章、留言,php作為后端語言,實現動態頁面處理,再加上簡潔優雅的響應式前端開發框架,可以開發出符合要求的管理系統。

  • 經濟可行性

    網站平臺的開發及后期的運營維護所需的人力物力很少,并且可以部署在學校的服務器上,由網絡服務中心的工作人員統一管理。

  • 社會可行性

    在校園里,我們經常見到這樣一幕,一位同學在熱水房門口一遍一遍尋找,然后口里說著,怎么又不見了呢?,一邊不甘心的再找一遍。又或許是這么一幕,“尋物啟事——宿舍號,丟失物品,最后再詛咒一下那些撿拾物品不還的人。”現有失物招領處工作繁瑣且效率低,因此開發失物招領管理系統是非常必要的。


系統需求分析

1、業務流程

業務流程分析可以幫助開發者了解該業務處理過程,發現和處理系統調查工作中的錯誤和疏漏。業務流程分析是通過業務流程圖來進行,即用一些規定的符號及連線來表示某個具體業務處理過程。

本系統具體的業務流程如下圖所示:

業務流程.PNG

2、用戶體驗分析

用戶體驗是現今產品開發過程中非常重視的一個方面,我們開發出一款產品或者提供一項服務,其最終面向的是不重視或不在乎技術層面的廣大用戶,因此在界面友好性、直觀性、易于操作性方面必須加以考慮。本失物招領系統按照下述原則進行:

  • 實用性:系統以用戶需求為目標,以方便用戶使用為原則,充分考慮實際操作的各項細節,使得普通用戶在打開頁面的第一眼即能對操作流程有清晰的理解。真正構建起一個為師生服務的平臺,為用戶的在線失物招領查詢發布提供方便。
  • 高安全性:在設計中,將充分考慮網絡軟、硬件方面的各種安全措施,保障用戶數據信息安全。比如用戶存放在數據庫的賬號密碼采用php的哈希加密,即使數據庫泄露,看到的也將是一堆亂碼。
  • 可維護性:網站的設計要求方便維護,文件目錄及代碼結構清晰。
  • 可擴展性:網站的設計以方便未來的擴展和系統擴充為目標,系統要求能夠方便升級,方便添加功能模塊。

系統模塊設計

1.功能模塊

本管理系統主要能夠實現用戶注冊、用戶(管理員)登錄、首頁展示、失物招領的文章發布、留言板、后臺管理, 以及標簽管理等幾大模塊的功能:

  • 用戶注冊:本功能主要是實現對用戶信息的注冊管理
  • 用戶(管理員)登錄:本功能主要實現用戶(管理員)登錄的功能
  • 首頁模塊:本模塊主要是對失物招領文章的展示功能、添加功能、查看詳情功能及各模塊入口
  • 留言板模塊:主要是實現用戶(管理員)留言功能,以供用戶反饋
  • 后臺管理:用戶信息管理、失物招領文章管理、留言板留言管理、管理員信息管理、標簽管理

本系統主要功能結構如下圖所示:

功能結構圖.PNG

?

2、用戶界面

  • 注冊頁面:本界面主要采集注冊用戶的信息,然后存入系統數據庫
  • 登錄頁面:本頁面根據登錄用戶的信息和類型進行驗證登錄
  • 首頁:本頁面展示用戶所發布的失物招領的文章,以及文章的標簽
  • 留言板頁面:本頁面顯示歷史留言和添加留言的版塊
  • 用戶信息頁面:本頁面顯示當前登錄的用戶的信息及發布的文章管理
  • 管理頁面:本頁面是管理員對本網站各個版塊進行管理的可視化操作頁面

核心功能的技術實現

1、開發環境

網站的本地開發環境使用lamp(即Linux+Apache+MySQL+PHP)。lamp是一組常用來搭建動態網站或者服務器的開源軟件,本身都是各自獨立的程序,但是因為常被放在一起使用,擁有了越來越高的兼容度,共同組成了一個強大的Web應用程序平臺。lamp的所有開發工具都是開源軟件,隨著開源潮流的蓬勃發展,可以預見lamp會是未來web開發的主流,并且由于其零成本、學習資料多,自然成為我的首選開發環境。

2、技術框架

后端的php框架選用了國外流行的開源框架——laravel,也是號稱“最簡潔、優雅的php web開發框架”,基于此可以快速、高效地構建一個web APP,Laravel的目標是給開發者創造一個愉快的開發過程,并且不犧牲應用的功能性。剛開始學習php開發沒多久,對php的一些框架了解甚少,在csdn上看到一篇文章《php開發框架流行度排名:laravel居首》,才知道有laravel這么一個框架,并且其文件目錄、代碼結構清晰,基于MVC的設計模式,對初學者較友好,故選用了此框架,本篇課程設計很大程度上也算是我對laravel框架的學習實踐吧。php的應用框架眾多,如國產的thinkPHP框架在國內也使用者甚廣,前期曾嘗試使用thinkPHP來開發,其結構代碼簡單直接,易于上手,但在代碼規范性方面毀譽參半,不適合初學者養成良好的編碼習慣,故棄之。

下面就對laravel框架體系結構作簡要介紹。

Laravel被稱為“全棧”式框架,因為它能夠處理從網絡服務到數據庫管理、HTML生成的一切事情,垂直集成的web開發環境給開發者提供了更好的體驗。開發人員可以通過命令行工具,生成和管理Laravel項目環境。 Laravel帶有一個名為Artisan的優秀的命令行工具,可以用它來生成框架代碼和數據庫架構,Artisan能夠處理從數據庫架構遷移到資源和配置管理的一切事情。

laravel項目使用composer來創建(Composer是PHP中用來管理依賴(dependency)關系的工具。你可以在自己的項目中聲明所依賴的外部工具庫(libraries),Composer會幫你安裝這些依賴的庫文件)。在linux終端中執行:

$ composer create-project laravel/laravel --prefer-dist web 5.1

就會在/home目錄下創建一個名為web的項目文件夾,指定的laravel版本為5.1 。其目錄結構如下圖所示:

071625168621849.png

下面是各個文件夾和文件的基本介紹:

頂級文件夾 作用
app 包含了站點的controller(控制器),models(模型),views(視圖)和assets(資源)。這些事網站運行的主要代碼,你將會花費大部分的時間在這些上面。
bootstrap 用來存放系統啟動時需要的文件,這些文件會被如index.php這樣的文件調用。
這個文件夾是外界唯一可以看到的,是必須指向你web服務器的目錄。它含有laravel框架核心的引導文件index.php,這個目錄也可以用來存放任何可以公開的靜態資源,如css,JavaScript,images等。
vendor 用來存放所有的第三方代碼,在一個典型的laravel應用程序,這包括larceny源代碼及其相關,并含有額外的預包裝功能的插件。

如上所述,/app是其核心部分,/app文件夾的詳細信息如下:

071625258005786.png

?

下面是詳細介紹:

文件及文件夾 作用
/app/config/ 配置應用程序的運行時規則、 數據庫、 session等等。包含大量的用來更改框架的各個方面的配置文件。大部分的配置文件中返回的選項關聯PHP數組。
/app/config/app.php 各種應用程序級設置,即時區、 區域設置(語言環境)、 調試模式和獨特的加密密鑰。
/app/config/auth.php 控制在應用程序中如何進行身份驗證,即身份驗證驅動程序。
/app/config/cache.php 如果應用程序利用緩存來加快響應時間,要在此配置該功能。
/app/config/compile.php 在此處可以指定一些額外類,去包含由‘artisan optimize’命令聲稱的編譯文件。這些應該是被包括在基本上每個請求到應用程序中的類。
/app/config/database.php 包含數據庫的相關配置信息,即默認數據庫引擎和連接信息。
/app/config/mail.php 為電子郵件發件引擎的配置文件,即 SMTP 服務器。
/app/config/session.php 控制Laravel怎樣管理用戶sessions,即session driver, session lifetime。
/app/config/view.php 模板系統的雜項配置。
/app/controllers 包含用于提供基本的邏輯、 數據模型交互以及加載應用程序的視圖文件的控制器類。
/app/database/migrations/ 包含一些 PHP 類,允許 Laravel更新當前數據庫的架構并同時保持所有版本的數據庫的同步。遷移文件是使用Artisan工具生成的。
/app/database/seeds/ 包含允許Artisan工具用關系數據來填充數據庫表的 PHP 文件。
/app/lang/ PHP 文件,其中包含使應用程序易于本地化的字符串的數組。默認情況下目錄包含英語語言的分頁和表單驗證的語言行。
/app/models/ 模型是代表應用程序的信息(數據)和操作數據的規則的一些類。在大多數情況下,數據庫中的每個表將對應應用中的一個模型。應用程序業務邏輯的大部分將集中在模型中。
/app/start/ 包含與Artisan工具以及全球和本地上下文相關的自定義設置。
/app/storage/ 該目錄存儲Laravel各種服務的臨時文件,如session, cache, compiled view templates。這個目錄在web服務器上必須是可以寫入的。該目錄由Laravel維護,我們可以不關心。
/app/tests/ 該文件夾給你提供了一個方便的位置,用來做單元測試。如果你使用PHPUnit,你可以使用Artisan工具一次執行所有的測試。
/app/views/ 該文件夾包含了控制器或者路由使用的HTML模版。請注意,這個文件夾下你只能放置模版文件。其他的靜態資源文件如css, javascript和images文件應該放在/public文件夾下。
/app/filters.php 此文件包含各種應用程序和路由篩選方法,用來改變您的應用程序的結果。Laravel 具有訪問控制和 XSS 保護的一些預定義篩選器。
/app/routes.php 這是您的應用程序的路由文件,其中包含路由規則,告訴 Laravel 如何將傳入的請求連接到路由處理的閉包函數、 控制器和操作。該文件還包含幾個事件聲明,包括錯誤頁的,可以用于定義視圖的composers。

3、模型-視圖-控制器(MVC)

/app文件夾下有三個子目錄:models/,views/和controllers/。這說明laravel遵循MVC架構模式。這就是強制將輸入到展示邏輯關系的“業務邏輯”與圖形用戶界面(GUI)分開。就laravel web應用而言,業務邏輯通常由像用戶,文章這樣的數據模型組成。GUI只是瀏覽器中的網頁而已。MVC設計模式在web開發領域中很流行。

MVC模式包括三個組件:

  • 模型(model)
  • 視圖(view)
  • 控制器(controller)

一個典型的laravel應用程序包含上面提到的MVC組件,如下圖:


071626088464369.png

laravel的響應流程

當與Laravel交互時,瀏覽器發送一個請求,web服務器接收到請求并且傳給Laravel路由引擎。Laravel路由接收到請求,然后重定向給基于路由的URL模式的合適的控制器類方法。然后控制器類接管。在某種情況下,控制器會立即呈現出一個視圖,它是一個被轉換成HTML并送回瀏覽器的模版。更常見的動態網站,控制器與模型交互,這是一個PHP對象,它表示應用程序(如用戶、博客文章)中的一個元素,并負責與數據庫進行通信的。調用模型后,控制器則呈現最終視圖( HTML,CSS和圖像),并返回完整的網頁到用戶的瀏覽器。Laravel促進了這樣的概念——模型、視圖和控制器,應通過存儲這些元素在不同的目錄中的單獨的代碼文件中來保持相當的獨立性。這就是Laravel目錄結構發揮了作用。

? ——laravel文檔

4、數據庫設計

使用phpmyadmin來對MySQL數據庫進行可視化操作,在MySQL中先創建名為web的數據庫,然后配置laravel的數據庫配置文件/config/database.php如下:

'mysql' => [
? 'driver' => 'mysql',
? 'host' => env('DB_HOST', 'localhost'),
? 'database' => env('DB_DATABASE', 'web'),
? 'username' => env('DB_USERNAME', 'root'),
? 'password' => env('DB_PASSWORD', 'sheng'),
? 'charset' => 'utf8',
? 'collation' => 'utf8_unicode_ci',
? 'prefix' => '',
? 'strict' => false,
],

MySQL數據庫中存在的表如下圖所示:

選區_015.png

?

部分表的說明:

articles:存放用戶發布的失物招領文章

article_tag:發布的文章的標簽

migrations:php做遷移數據時產生,與核心功能無關

tags:用戶標簽

users:存放用戶賬戶信息

5、核心代碼實現

web程序的代碼一般都較多,如果把所有的代碼均放到論文里,事無巨細,一一說明,是不現實的,故只會選擇核心的業務邏輯部分代碼,配以必要的解釋。在前端方面,使用了AmazeUI響應式開發框架和jQuery的JavaScript庫,與流行的bootstrap類似,故對前端的div,css等樣式也不做過多說明。

著重解釋的主要包括以下內容:

  • 路由管理
  • 用戶管理,如用戶注冊、修改信息、鎖定用戶等
  • 文章管理,如發表文章、修改文章等
  • 標簽管理,文章會有一到多個標簽
  • 數據庫管理,如遷移、填充數據等
  • Web表單驗證
  • Blade模版引擎
  • 分頁處理
  • 安全處理

laravel使用blade模板引擎,故視圖文件均須以xxx.blade.php方式命名,web/resources/views/文件夾下的目錄結構如圖所示:

選區_017.png

?

網站入口文件首先會加載的視圖文件是layouts/defalut.blade.php:

<!DOCTYPE html>
<html>
<head lang="zh">

<meta charset="UTF-8"/>
<title>校園失物招領平臺</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport"
      content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="format-detection" content="telephone=no"/>
<meta name="renderer" content="webkit"/>
<meta http-equiv="Cache-Control" content="no-siteapp"/>
<link rel="alternate icon" type="image/x-icon" href="{{ asset('img/favicon.ico') }}"/>
<link rel="stylesheet" />
<link rel="stylesheet" href="{{asset('css/custom.css')}}">
<script src="http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script>

</head>
<body>
<header class="am-topbar am-topbar-fixed-top">

<div class="am-container">
    <h1 class="am-topbar-brand">
        <a href="/">校園失物招領平臺</a>
    </h1>
    @include('layouts.nav')
</div>

</header>

@yield('main')

@include('layouts.footer')

<script src="http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script>
<script src="http://cdn.amazeui.org/amazeui/2.7.2/js/amazeui.min.js"></script>
</body>
</html>

其中amazeui前端框架文件以及jQuery文件均是存放在cdn網絡上,無需在本地加載,精簡了網站文件夾的結構。

  • asset('img/favicon.ico') 會生成 http://localhost:8000/img/favicon.ico
  • asset('css/custom.css') 會生成 <link media="all" type="text/css"rel="stylesheet" href="http://localhost:8000/css/custom.css">,其中的 img 和 css 文件夾是放在 public 目錄下的,public 目錄是項目的資源文件夾
  • @include('layouts.nav') 會包含 app/views/layouts/nav.blade.php 文件
  • @yield('main') 用于模版繼承

大部分的視圖文件都會繼承default.blade.php的模板框架,例如index.blade.php:

@extends('layouts.default')

@section('main')

<div class="am-g am-g-fixed">
    <div class="am-u-md-8">
        <!-- 循環輸出文章 -->
        @foreach ($articles as $article)
            <article class="blog-main">
                <h3 class="am-article-title blog-title">
                    <a href="{{ URL::route('article.show', $article->id) }}">{{{ $article->title }}}</a>
                </h3>
                <h4 class="am-article-meta blog-meta">
                    由 <a href="{{ URL::to('user/' . $article->user->id . '/articles') }}">{{{ $article->user->nickname }}}</a> 發布于 {{ $article->created_at->format('Y/m/d H:i') }}  標簽:
                    <!-- 輸出標簽 -->
                    @foreach ($article->tags as $tag)
                        <a  href="{{ URL::to('tag/' . $tag->id . '/articles') }}">{{ $tag->name }}</a>
                    @endforeach
                </h4>
                <div class="am-g">
                    <div class="am-u-sm-12">
                        @if ($article->summary)
                            <p>{!! $article->summary !!}</p>
                        @endif
                        <hr class="am-article-divider"/>
                    </div>
                </div>
            </article>
        @endforeach
    </div>

?

  • @extends('layouts.default') 會繼承 app/views/layouts/default.blade.php 文件
  • @yield('main')對應 @section('main') 并填充為其中的內容

用戶登錄表單(在login.blade.php文件中)如下:

  <form action="login" method="post" accept-charset="utf-8" class="am-form">
    <!-- 添加 token 值 -->
    <input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
    <label  for="email">郵箱:
        <input type="email" name="email" value="{{Input::old('email')}}" placeholder="">
    </label>
    <br>
    <label for="password">密碼:
        <input type="password" name="password" value="" placeholder="">
    </label>
    <br>
    <label for="remember_me">
      <input id="remember_me" name="remember_me" type="checkbox" value="1">
      記住我
    </label>
    <br>
    <div class="am-cf">
    <input type="submit" name="submit" value="登錄" class="am-btn am-btn-primary am-btn-sm am-fl">
    </div>
  </form>

laravel及大多數php框架使用路由(route)來生成URL,處理http請求,用戶登錄數據的驗證也是放在了路由文件里(web/app/route.php):

//post登陸數據
Route::post('login', function()

{
  //數據驗證規則
  $rules = array(
    'email'       => 'required|email',
    'password'    => 'required|min:6',
    'remember_me' => 'boolean',
  );
  $validator = Validator::make(Request::all(), $rules);
  //驗證通過
  if ($validator->passes())
  {
    if (Auth::attempt([
      'email'    => Request::input('email'),
      'password' => Request::input('password'),
      'block'    => 0], 
      (boolean) Request::input('remember_me')))
    {
      return Redirect::to('home');
    } 
    //賬號或密碼錯誤
    else {
      return Redirect::to('login')->withInput()->with('message', array('type' => 'danger', 'content' => 'E-mail or password error'));
    }
  } 
  //數據格式錯誤
  else {
    return Redirect::to('login')->withInput()->withErrors($validator);
  }
});

//訪問主頁
Route::get('home', ['middleware' => 'auth', function()
{
return view('home');
}]);

注冊操作路由:

Route::post('register', function()
{
$rules = [

'email' => 'required|email|unique:users,email',
'nickname' => 'required|min:4|unique:users,nickname',
'password' => 'required|min:6|confirmed',

];
$validator = Validator::make(Request::all(), $rules);
if ($validator->passes())
{

$user = new App\User();
$user->email = Request::input('email');
$user->nickname = Request::input('nickname');
$user->password = Hash::make(Request::input('password'));
if ($user->save())
{
  return Redirect::to('login')->with('message', array('type' => 'success', 'content' => 'Register successfully, please login'));
} else {
  return Redirect::to('register')->withInput()->with('message', array('type' => 'danger', 'content' => 'Register failed'));
}

} else {

return Redirect::to('register')->withInput()->withErrors($validator);

}
});

上面表單驗證規則的unique:users,email能確保 users 表中的 email 字段是唯一的,例如當輸入已存在的 email 時,會出現錯誤提示:

選區_013.png

?

若注冊成功就會跳轉到登錄頁面,并給出成功的提示:

選區_014.png

?

用戶發布失物招領啟事,即文章發布模塊,在數據庫中對應三張表:articles 、 tags 以及 article_tag,每篇文章會有一到多個標簽,每個標簽會有一到多篇文章。模型文件/app/Article.php和Tag.php、User.php的核心代碼如下:

User.php:

<?php

namespace App;

use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;

class User extends Model implements AuthenticatableContract, CanResetPasswordContract
{

use Authenticatable, CanResetPassword;
/**
 * The database table used by the model.
 *
 * @var string
 */
protected $table = 'users';

/**
 * The attributes that are mass assignable.
 *
 * @var array
 */
protected $fillable = ['name', 'email', 'password'];

/**
 * The attributes excluded from the model's JSON form.
 *
 * @var array
 */
protected $hidden = ['password', 'remember_token'];
//模型關聯
public function articles()
{
    return $this->hasMany('App\Article');
}

}

?

一個用戶會有多篇文章。

?

Article.php:

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; //使用軟刪除 trait

class Article extends Model
{

use SoftDeletes;
protected $fillable = ['title', 'content'];
public function tags()
{
    return $this->belongsToMany('App\Tag');
}

public function user()
{
    return $this->belongsTo('App\User');
}

}

一篇文章會有多個標簽并屬于一個用戶。

Tag.php:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Tag extends Model
{

use SoftDeletes;
protected $fillable = ['name'];
public function articles()
{
    return $this->belongsToMany('App\Article');
}

}

一個標簽會有多篇文章。

此文章編輯器使用了markdown編輯器,markdown簡潔優雅的排版格式可以使文章樣式更美觀(可能也需要一定的學習成本)

向數據庫中添加文章,要用到MVC中的control了./web/app/http/Controllers/ArticleController.php的核心代碼如下:

<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Markdown;
use Validator;
use App\Article;
use Auth;
use App\Tag;
use Redirect;

class ArticleController extends Controller

******
******

  //保存文章
public function store(Request $request)
{
    $rules = [
    'title'   => 'required|max:100',
    'content' => 'required',
    'tags'    => ['required', 'regex:/^\w+$|^(\w+,)+\w+$/'],
    ];
  //數據校驗
    $validator = Validator::make($request->all(), $rules);
    if ($validator->passes()) {
        $article = Article::create($request->only('title', 'content'));
        $article->user_id = Auth::id();
        $resolved_content = Markdown::parse($request->input('content'));
        $article->resolved_content = $resolved_content;
        $tags = explode(',', $request->input('tags'));
          //添加 summary
      if (str_contains($resolved_content, '<p>')) {
            $start = strpos($resolved_content, '<p>');
            $length = strpos($resolved_content, '</p>') - $start - 4;
            $article->summary = substr($resolved_content, $start + 3, $length);
        } else if (str_contains($resolved_content, '</h')) {
            $start = strpos($resolved_content, '<h>');
            $length = strpos($resolved_content, '</h>') - $start - 4;
            $article->summary = substr($resolved_content, $start + 4, $length);
        }
        $article->save();
      //處理標簽
        foreach ($tags as $tagName) {
            $tag = Tag::whereName($tagName)->first();
            if (!$tag) {
                $tag = Tag::create(array('name' => $tagName));
            }
            $tag->count++;
            $article->tags()->save($tag);
        }
        return Redirect::route('article.show', $article->id);
    } else {
        return Redirect::route('article.create')->withInput()->withErrors($validator);
    }
}
//展示文章詳情
public function show($id)
{
    return view('articles.show')->with('article', Article::find($id));
}

上面代碼實現了保存文章和顯示文章的業務邏輯,保存文章時驗證 tags 用了 regex 正則表達式來驗證標簽是否用逗號分隔。

用戶修改已經發布的文章的核心代碼如下:

?

@extends('layouts.default')

@section('main')
<div class="am-g am-g-fixed">
<div class="am-u-sm-12">

  <h1>Edit Article</h1>
  <hr/>
@if ($errors->has())
<div class="am-alert am-alert-danger" data-am-alert>
  <p>{{ $errors->first() }}</p>
</div>
@endif


<form action="{{ URL::route('article.update',$article->id)}}" method="post" accept-charset="utf-8" class="am-form">

  <input type="hidden" name="_token" id="token" value="<?php echo csrf_token(); ?>">
  <div class="am-form-group">
    <label for="title">Title:</label>
    <input type="text" name="title" id="title" value="{{ $article->title}}" placeholder="">
  </div>
  <div class="am-form-group">
    <label for="content">Content:</label>
    <textarea name="content" id="content" rows="20" >{{ $article->content }}</textarea>
    <p class="am-form-help">
      <button id="preview" type="button" class="am-btn am-btn-xs am-btn-primary">
      <span class="am-icon-eye"></span> Preview
      </button>
    </p>
  </div>
  <div class="am-form-group">
    <label for="tags">Tags:
        <input type="text" name="tags" value="{{ $article->tags }}" placeholder="">
    </label>
    <p class="am-form-help">Separate multiple tags with a comma ","</p>
  </div>
  <p><button type="submit" class="am-btn am-btn-success">
    <span class="am-icon-pencil"></span> Modify</button>
  </p>
</form>
</div>

</div>

<div class="am-popup" id="preview-popup">
<div class="am-popup-inner">

<div class="am-popup-hd">
  <h4 class="am-popup-title"></h4>
  <span data-am-modal-close
        class="am-close">×</span>
</div>
<div class="am-popup-bd">
</div>
</div>

</div>
<script>
$(function() {

  $('#preview').on('click', function() {
      $('.am-popup-title').text($('#title').val());
      $.post('preview', {'content': $('#content').val(),'_token':$('#token').val()}, function(data, status) {
        $('.am-popup-bd').html(data);
      });
      $('#preview-popup').modal();
  });
});

</script>
@endsection

標簽是為了給用戶發布的文章分類,便于查找相關信息,其核心代碼實現為:

@extends('layouts.default')

@section('main')
<div class="am-g am-g-fixed blog-g-fixed">
<div class="am-u-sm-12">

  <table class="am-table am-table-hover am-table-striped ">
  <thead>
  <tr>
    <th>TagName</th>
    <th>ArticleCount</th>
    <th>CreateDateTime</th>
    <th>Managment</th>
  </tr>
  </thead>
  <tbody>
    @foreach ($tags as $tag)
    <tr>
      <td>{{{ $tag->name }}}</td>
      <td>{{ $tag->count }}</td>
      <td>{{ $tag->created_at->format('Y-m-d H:i') }}</td>
      <td>
          <a href="{{ URL::to('tag/'. $tag->id . '/edit') }}" class="am-btn am-btn-xs am-btn-primary"><span class="am-icon-pencil"></span> Edit</a>
          <form action="{{ URL::to('tag/'.$tag->id.'/delete')}}" method="get" accept-charset="utf-8" style="display: inline;">
             <button type="button" class="am-btn am-btn-xs am-btn-danger" id="delete{{ $tag->id }}">
                 <span class="am-icon-remove"></span> Delete
             </button>
          </form>
       </td>
    </tr>
    @endforeach
  </tbody>
</table>

</div>
</div>


<div class="am-modal am-modal-confirm" tabindex="-1" id="my-confirm">
<div class="am-modal-dialog">

<div class="am-modal-bd">
</div>
<div class="am-modal-footer">
  <span class="am-modal-btn" data-am-modal-cancel>No</span>
  <span class="am-modal-btn" data-am-modal-confirm>Yes</span>
</div>

</div>
</div>
<script>
$(function() {

$('[id^=delete]').on('click', function() {
  $('.am-modal-bd').text('Sure you want to delete it?');
  $('#my-confirm').modal({
    relatedTarget: this,
    onConfirm: function(options) {
      $(this.relatedTarget).parent().submit();
    },
    onCancel: function() {
    }
  });
});

});
</script>
@endsection

錯誤處理:

如果用戶訪問的URL不存在或者服務器存在錯誤時,我們不希望返回一個默認的錯誤頁面,而想返回一個友好提示的頁面,在 Laravel 中可以很輕松地實現,Laravel有很簡單的錯誤和日志處理,當服務器端存在錯誤時,app\Exceptions\Handler.php 里默認有一個報告所有異常的程序:

/**

* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param  \Exception  $e
* @return void
*/

public function report(Exception $e)
{

   return parent::report($e);

}

當訪問的URL不存在時,服務器會拋出一個 404 錯誤,laravel 對 HTTP 異常有特別的處理方式:

@extends('layouts.default')

@section('main')

<h1 style="text-align:center;">啊哦,你訪問的頁面不存在!</h1>
<h2 style="text-align:center;">返回 <a href="/">首頁</a></h2>

@endsection

現在當你訪問的 URL 不存在時,laravel 會自動到模板目錄去尋找狀態碼為 404 的錯誤模板頁面 404.blade.php

6、測試及操作說明

主頁展示:

主頁展示.png

整體頁面做的比較簡潔,因為我側重在功能實現,故對界面設計方面沒有花太多時間。

用戶登錄:

管理員登錄.png

這里的登錄注冊使用了laravel框架的regex正則表達式匹配。

登錄之后,會出現文章管理界面:

文章管理.png

這里隨便添加了一些測試數據。

刪除文章:


預覽文章.png

點擊刪除文章會調用一段js代碼,實現模態彈出框。

發布文章:

發布信息.png

這個編輯器使用了markdown語法來編輯文字,可能對于普通用戶來說有比較高的門檻,本想用富文本編輯器的,但是由于時間較為緊張,而markdown插件易于使用,故在beta版本中以此來暫時代替。

點擊預覽:

預覽文章.png

這里也調用了js解析markdown,生成html。

發布之后:

失物招領啟事詳情.png

這樣一個簡單的失物招領啟事發布管理系統就完成了,測試各功能正常。

總結

通過開發這個校園失物招領平臺,其實就完成了一個最小內容管理系統,一個完整的內容管理系統包括這幾個核心的模塊:

  • 用戶管理
  • 文章管理
  • 權限管理
  • 標簽管理

90%的網站功能開發都可以歸納為CRUD(即增刪改查)操作,可能對于一個這樣功能簡單的管理系統來說,沒有必要去使用重型的laravel框架,看起來有點過度設計了,但是我作為一個php初學者來說,也是想通過這個機會來學習一下這個優秀的框架,學習框架的過程也加深了對php語言的理解,對于以后開發更大型的網站能夠積累一點相關經驗。

這個系統目前還存在很多問題,比如界面不太符合失物招領的常規設計,有很多當初的設想也沒能實現,markdown的編輯器不可能用在面向普通用戶的網頁中,入口首頁和留言板功能由于時間關系沒能加上,頗為遺憾。我希望以后能有時間去逐步地完善它,改造為我的個人博客,或者以此為基礎,實現我一直以來的一個想法——搭建一個學生門戶網站,當然這個工程量就非常大了。

回顧一下這整個的學習開發過程,深感不易。從最基本的前端html+css+js學起,到php的基本語法,再到laravel框架的學習,期間查閱了大量的資料,觀看了100+小時的在線mooc視頻,才完成了這份課程設計。感謝那些技術博客博主的無私分享,前人的經驗與見解避免后人少走了多少彎路,也由此深感開源分享精神之重要,正是開源運動才使得現今的互聯網行業獲得如此蓬勃的發展。所以我想在以后的學習過程中,也應當時時勿忘總結個人的經驗,并且要分享出來,讓自己的彎路成為別人的橋梁。

也感謝我的小伙伴們的鼓勵和付出,正是一個團隊的合作才使得這份作品能夠如期完成。

參考文獻

  1. 《php與MySQL web程序設計》
  2. 《html+css+js 網頁設計》
  3. 《laravel 5.1 官方文檔》
  4. 眾多博客及慕課網、網易云課堂相關教程
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容