[关闭]
@artman328 2017-12-19T11:40:50.000000Z 字数 9824 阅读 982

Bani Yas 应用开发步骤

wsc wsc45


一、后台 Web 服务 API 开发

1、Web 环境的建立

(1) 安装 XAMPP 应用

将 XAMPP 应用安装到某个文件夹,比如:f:\xampp ,然后修改环境变量 path , 将 f:\xampp\phpf:\xampp\mysql\bin 加到 path 中。

(2) 安装 Laravel 应用

将 Laravel 框架安装到某个文件夹,或直接将提供的 Laravel 框架文件拷贝到此文件夹。如果是拷贝的,请在这个文件夹中的命令行执行:

  1. php artisan key:generate

以重新生成应用程序的键。

(3) 配置站点

f:\xampp\apache\conf\httpd.conf 文件的尾部,加入以下内容(此处假定你的 Laravel 项目在 f:\php_projects\86_Server_A 下):

  1. <Directory "F:/php_projects/86_Server_A/public">
  2. AllowOverride all
  3. Require all granted
  4. </Directory>
  5. Alias /86_Server_A "F:/php_projects/86_Server_A/public/"

然后,在 F:\php_projects\86_Server_A\public\.htaccess 文件中加入 RewriteBase 一行:

  1. <IfModule mod_rewrite.c>
  2. <IfModule mod_negotiation.c>
  3. Options -MultiViews -Indexes
  4. </IfModule>
  5. RewriteEngine On
  6. # 加入下面一行
  7. RewriteBase /86_Server_A
  8. # Handle Authorization Header
  9. RewriteCond %{HTTP:Authorization} .
  10. RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
  11. # Redirect Trailing Slashes If Not A Folder...
  12. RewriteCond %{REQUEST_FILENAME} !-d
  13. RewriteCond %{REQUEST_URI} (.+)/$
  14. RewriteRule ^ %1 [L,R=301]
  15. # Handle Front Controller...
  16. RewriteCond %{REQUEST_FILENAME} !-d
  17. RewriteCond %{REQUEST_FILENAME} !-f
  18. RewriteRule ^ index.php [L]
  19. </IfModule>

然后,重新启动 xampp 的 apache 服务器,在浏览器中输入:

  1. http://localhost/86_Server_A

应该能够看到 laravel 应用程序的默认首页。如果不行,请认真核对以上步骤。

2、数据准备

修改提供的 sql 脚本文件,建立相应的外键关联,加入必须的表定义。修改后内容如下:

  1. -- phpMyAdmin SQL Dump
  2. -- version 4.7.0
  3. -- https://www.phpmyadmin.net/
  4. --
  5. -- Host: 127.0.0.1
  6. -- Generation Time: Oct 10, 2017 at 05:46 AM
  7. -- Server version: 10.1.26-MariaDB
  8. -- PHP Version: 7.1.8
  9. SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
  10. SET AUTOCOMMIT = 0;
  11. START TRANSACTION;
  12. SET time_zone = "+00:00";
  13. DROP DATABASE IF EXISTS baniyas_db;
  14. CREATE DATABASE IF NOT EXISTS baniyas_db DEFAULT CHARSET utf8;
  15. USE baniyas_db;
  16. /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
  17. /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
  18. /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
  19. /*!40101 SET NAMES utf8mb4 */;
  20. --
  21. -- Database: `worldskills_2017_serverside_default`
  22. --
  23. -- --------------------------------------------------------
  24. --
  25. -- Table structure for table `places`
  26. --
  27. CREATE TABLE `places` (
  28. `id` int(11) NOT NULL,
  29. `name` varchar(100) DEFAULT NULL,
  30. `latitude` float DEFAULT NULL,
  31. `longitude` float DEFAULT NULL,
  32. `x` int(11) DEFAULT NULL,
  33. `y` int(11) DEFAULT NULL,
  34. `image_path` varchar(50) DEFAULT NULL,
  35. `description` text
  36. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  37. -- --------------------------------------------------------
  38. --
  39. -- Table structure for table `schedules`
  40. --
  41. CREATE TABLE `schedules` (
  42. `id` int(11) NOT NULL,
  43. `type` enum('TRAIN','BUS') DEFAULT 'TRAIN',
  44. `line` int(11) DEFAULT NULL,
  45. `from_place_id` int(11) NOT NULL,
  46. `to_place_id` int(11) NOT NULL,
  47. `departure_time` time DEFAULT NULL,
  48. `arrival_time` time DEFAULT NULL,
  49. `distance` int(11) DEFAULT NULL,
  50. `speed` int(11) DEFAULT NULL,
  51. `status` enum('AVAILABLE','UNAVAILABLE') DEFAULT 'AVAILABLE'
  52. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  53. --
  54. -- Indexes for dumped tables
  55. --
  56. --
  57. -- Indexes for table `places`
  58. --
  59. ALTER TABLE `places`
  60. ADD PRIMARY KEY (`id`);
  61. --
  62. -- Indexes for table `schedules`
  63. --
  64. ALTER TABLE `schedules`
  65. ADD PRIMARY KEY (`id`);
  66. --
  67. -- AUTO_INCREMENT for dumped tables
  68. --
  69. --
  70. -- AUTO_INCREMENT for table `places`
  71. --
  72. ALTER TABLE `places`
  73. MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
  74. -- **** 以下为加入内容 *************************** -------
  75. ALTER TABLE `schedules`
  76. ADD foreign key(`from_place_id`) references `places`(`id`);
  77. ALTER TABLE `schedules`
  78. ADD foreign key(`to_place_id`) references `places`(`id`);
  79. -- ************************************** --
  80. --
  81. -- AUTO_INCREMENT for table `schedules`
  82. --
  83. ALTER TABLE `schedules`
  84. MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
  85. /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
  86. /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
  87. /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
  88. -- ** 增加用户表定义 ** --
  89. CREATE TABLE users(
  90. `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  91. `username` varchar(30) NOT NULL UNIQUE,
  92. `password` varchar(100),
  93. `role` varchar(50) NOT NULL DEFAULT 'USER'
  94. );
  95. -- *************************** --
  96. -- ** 插入测试所需数据 **--
  97. INSERT INTO users
  98. VALUES
  99. (1,'admin','adminpass','ADMIN'),
  100. (2,'user1','user1pass','USER'),
  101. (3,'user2','user2pass','USER')
  102. ;
  103. -- ******************** --
  104. -- ** 增加旅行路线历史记录表定义 ** --
  105. CREATE TABLE route_histories(
  106. id int(11) not null AUTO_INCREMENT PRIMARY KEY,
  107. from_id int(11) NOT NULL,
  108. to_id int(11) NOT NULL,
  109. schedule_ids varchar(200),
  110. count int default 0,
  111. FOREIGN KEY(from_id) REFERENCES `places`(`id`),
  112. FOREIGN KEY(to_id) REFERENCES `places`(`id`)
  113. );
  114. -- **************************** --
  115. -- ** 增加地点搜索历史记录表定义 ** --
  116. CREATE TABLE place_histories(
  117. id int(11) not null AUTO_INCREMENT PRIMARY KEY,
  118. user_id int(11) not null,
  119. place_id int(11) not null,
  120. count int default 0,
  121. unique (user_id,place_id),
  122. foreign key(user_id) references `users`(`id`),
  123. foreign key(place_id) references `places`(`id`)
  124. );
  125. -- ***************************** --
  126. -- ** 载入提供的地点数据 **--
  127. load data local infile "d:/csv/place.csv"
  128. into table places
  129. fields terminated by ','
  130. lines terminated by '\r\n'
  131. ignore 1 lines;
  132. -- ** 载入提供的运行时刻数据 ** --
  133. load data local infile "d:/csv/schedule.csv"
  134. into table schedules
  135. fields terminated by ','
  136. lines terminated by '\r\n'
  137. ignore 1 lines;
  138. --******************** --
  139. -- ** 提交修改 ** --
  140. COMMIT;
  141. -- ************** --

在命令行中执行:

  1. mysql -uroot -p

登录 mysql 客户端,执行以下命令(假定以上内容在 D:\baniyas.sql 文件中):

  1. source d:/baniyas_db.sql

如果输出显示执行无误,可进行下一步。

3、确定路由分组

编辑项目文件夹下的 routes 文件夹中的 web.php 路由文件,内容如下:

  1. <?php
  2. Route::get('/', function () {
  3. return view('welcome');
  4. });
  5. Route::get("/api/v1/auth/unauthorized","LoginController@unauthorized");
  6. Route::post("/api/v1/auth/login", "LoginController@login");
  7. // API for User and Admin
  8. Route::prefix("/api/v1/")->middleware(['check.token'])->group(function(){
  9. //次分组加入需要用户登录才能使用的功能
  10. Route::get("auth/logout","LoginController@logout");
  11. });
  12. // API for Admin
  13. Route::prefix("/api/v1/")->middleware(['check.token','check.role'])->group(function(){
  14. //次分组加入需要用户登录且角色为 ADMIN 才能使用的功能
  15. });

此文件的路由组定义中,需要用到两个中间件:check.tokencheck.role,还需要一个控制器类:LoginController。我们在后面分别创建它们。

4、创建中间件

利用以下命令分别创建两个中间件。
CheckToken:

  1. F:\php_projects\86_Server_A> php artisan make:middleware CheckToken

CheckRole:

  1. F:\php_projects\86_Server_A> php artisan make:middleware CheckRole

两个文件在 F:\php_projects\86_Server_A\app\Http\Middleware 文件夹中。

CheckToken.php 内容:

  1. <?php
  2. namespace App\Http\Middleware;
  3. use Closure;
  4. class CheckToken
  5. {
  6. /**
  7. * Handle an incoming request.
  8. *
  9. * @param \Illuminate\Http\Request $request
  10. * @param \Closure $next
  11. * @return mixed
  12. */
  13. public function handle($request, Closure $next)
  14. {
  15. $token1 = $request->input("token"); //客户端发送的 token
  16. $token2 = session()->get("token"); //服务器端存储的 token
  17. //如果客户端没有传来 token
  18. //或者传来的 token 与服务器端的 token 不符
  19. if(!$token1 || $token1!==$token2){
  20. //请求被重定向
  21. return redirect("/api/v1/auth/unauthorized");
  22. }
  23. //把请求继续向下传递
  24. return $next($request);
  25. }
  26. }

CheckRole.php 内容:

  1. <?php
  2. namespace App\Http\Middleware;
  3. use Closure;
  4. class CheckRole
  5. {
  6. /**
  7. * Handle an incoming request.
  8. *
  9. * @param \Illuminate\Http\Request $request
  10. * @param \Closure $next
  11. * @return mixed
  12. */
  13. public function handle($request, Closure $next)
  14. {
  15. //取出服务器端保存的用户角色名称
  16. $role = session()->get("role");
  17. //如果没有保存过的huo或者保存的名称不是 ADMIN
  18. if(!$role || $role !== "ADMIN"){
  19. //请求被重定向
  20. return redirect("/api/v1/auth/unauthorized");
  21. }
  22. //把请求继续向下传递
  23. return $next($request);
  24. }
  25. }

5、配置中间件

修改 F:\php_projects\86_Server_A\app\Http\Kernel.php 文件,内容如下:

  1. <?php
  2. namespace App\Http;
  3. use Illuminate\Foundation\Http\Kernel as HttpKernel;
  4. class Kernel extends HttpKernel
  5. {
  6. /**
  7. * The application's global HTTP middleware stack.
  8. *
  9. * These middleware are run during every request to your application.
  10. 这些中间件是所有请求都要按顺序经过的
  11. *
  12. * @var array
  13. */
  14. protected $middleware = [
  15. \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
  16. \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
  17. \App\Http\Middleware\TrimStrings::class,
  18. \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
  19. \App\Http\Middleware\TrustProxies::class,
  20. ];
  21. /**
  22. * The application's route middleware groups.
  23. * 这些中间件被归类到一个组,共同加给特定路由。web.php 中的所有路由都要经过 web 中间件分组。
  24. * @var array
  25. */
  26. protected $middlewareGroups = [
  27. 'web' => [
  28. \App\Http\Middleware\EncryptCookies::class,
  29. \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
  30. \Illuminate\Session\Middleware\StartSession::class,
  31. // \Illuminate\Session\Middleware\AuthenticateSession::class,
  32. \Illuminate\View\Middleware\ShareErrorsFromSession::class,
  33. //我们需要把下面这个中间件注释掉(不让请求经过它)
  34. //\App\Http\Middleware\VerifyCsrfToken::class,
  35. \Illuminate\Routing\Middleware\SubstituteBindings::class,
  36. ],
  37. 'api' => [
  38. 'throttle:60,1',
  39. 'bindings',
  40. ],
  41. ];
  42. /**
  43. * The application's route middleware.
  44. *
  45. * These middleware may be assigned to groups or used individually.
  46. *
  47. * @var array
  48. */
  49. protected $routeMiddleware = [
  50. 'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
  51. 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
  52. 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
  53. 'can' => \Illuminate\Auth\Middleware\Authorize::class,
  54. 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
  55. 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
  56. //把我们的两个中间件在此注册,才可以在路由中指定使用
  57. 'check.token' => \App\Http\Middleware\CheckToken::class,
  58. 'check.role' => \App\Http\Middleware\CheckRole::class,
  59. ];
  60. }

6、创建控制器

在命令行执行:

  1. F:\php_projects\86_Server_A> php artisan make:controller LoginController

得到文件 F:\php_projects\86_Server_A\app\Http\Controllers\LoginController.php,内容如下:

  1. <?php
  2. namespace App\Http\Controllers;
  3. use Illuminate\Http\Request;
  4. class LoginController extends Controller
  5. {
  6. //
  7. }

将三个相应处理路由的函数实现,内容如下:

  1. <?php
  2. namespace App\Http\Controllers;
  3. use Illuminate\Http\Request;
  4. class LoginController extends Controller
  5. {
  6. public function login(Request $request){
  7. // 从请求获取用户名和密码
  8. $username = $request->input("username");
  9. $password = $request->input("password");
  10. // 从数据库检索具有此用户名和密码的第一位用户(应当只有一位,first()取出了它)
  11. $user = User::where("username",$username)->where("password",$password)->first();
  12. // 如果用户存在
  13. if($user){
  14. // 将登录的用户对象信息保存在会话对象中并保存
  15. session()->put('token',md5($username));
  16. session()->put('role',md5($user->role));
  17. session()->save();
  18. // 返回数据与状态码:200
  19. return response()->json(['token'=>md5($username),'role'=>$user->role],200);
  20. }
  21. // 如果没有从以上返回语句返回,说明用户不存在,返回错误信息的状态码:401
  22. return response()->json(['message'=>"invalid login"],401);
  23. }
  24. public function logout(){
  25. // 清除会话记录
  26. session()->flush();
  27. return response()->json(["message"=>"logout success"],200);
  28. }
  29. public function unauthorized(){
  30. return response()->json(["message"=>"Unauthorized user"],401);
  31. }
  32. }

7、测试API

打开素材提供的 Testing_Server_A.postman_collection.json 文件,将其中的 <server>localhost 替换,将其中的 <XX>XX86 替换。
打开 Postman,用 Import 菜单引入以上文件,对其中的各个请求写出相应测试,即可进行 API 测试了。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注