iT邦幫忙

2021 iThome 鐵人賽

DAY 30
0
永豐金融APIs

釋放你的潛能用技能交易吧!系列 第 30

[Day30] 第三十 - 總結技能交換系統(整合Laravel以及Express的Microservices)

前言(心得)

昨天在寫Code的時候一不注意時間就超過了
/images/emoticon/emoticon02.gif

其實我本來是很懶惰容易放棄的人
在之前的參賽中我也是寫了幾篇就放棄了
但是這次希望可以堅持完成

完成一件事情不只是技術磨練及進步
而是對一個自我認同跟堅持的展現!!

真的很感謝IT邦跟永豐的機會
在我參賽的期間
我除了學習到了金流系統的交易(從未碰過)
我也加深了對Laravel的技能
之前我也是看教學影片而已
但是在實際做系統時才會發現許多細節要調整~
(Laravel 的MVC還有資料庫設計)

好啦我的心得分享差不多就到此結束了我們來完成最後的部分吧!
雖然有許多遺珠之憾
不過這個系統是我有興趣的
我希望以後可以把這個side project完成!!

目標

  1. Laravel blade layout的用法(類似切割component)
  2. Laravel 多表查詢join的應用
  3. 不同服務的溝通laravel與Express溝通
  4. 增加技能樹
  5. 正式完成金流部分

今天的目標有點多!
我們來把它完成吧

我在寫文章的時候也會遇到失敗的地方
我希望可以把這些紀錄忠實呈現
除了可以提醒自我需要加強的地方外
也想跟大家分享
工程師沒有一開始就做出完美的系統
隨者patch的update我們才會與生活的改變進步!!

/images/emoticon/emoticon08.gif

實作

1. blade 修改layout

先上成果給大家看吧
https://ithelp.ithome.com.tw/upload/images/20211015/201210523qnNDUTy6O.png

我們首先要先製作修改首頁
在這之前我們先製作一個名為layout的樣板
也就是我們上方的navbar為主要樣式
其他的組件都可以套用上方列表
這樣我們就不用在每頁都製作導覽列(這也是許多現代前端框架會用的方法)

Layout.blade.php

<head>
    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"> </script>
    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>

<div class="container">
    <ul class="nav justify-content-center">
        <li class="nav-item">
            <a class="nav-link active" href="{{ url('/') }}">
                <H2>首頁</H2>
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link active" href="{{ url('/skills') }}">
                <H2>全技能列表</H2>
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{{ url('profile') }}">
                <H2>個人檔案</H2>
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{{ url('/points')}}">
                <h2>評分系統</h2>
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{{ url('/trades/record')}}">
                <h2>訂單編號</h2>
            </a>
        </li>
        <li class=" nav-item">
            <a class="nav-link" href="{{ url('/skills/tree')}}">
                <h2>技能樹</h2>
            </a>
        </li>
    </ul>
    <div class="container">
        @yield('content')
    </div>
</div>

這邊的樣板代表我可以把導覽列建立好作為我系統的主要樣板

yeild函數就是可以給其他blade填充的頁面
裡面的變數就是要填聰在哪個相對應的變數裡 -> 我這邊叫做content

再來大家看我簡單的首頁吧就會比較理解我說什麼了
Home.blade.php

@extends('layout')


@section('content')
<div class="jumbotron jumbotron-fluid">
    <div class="container">
        <h1 class="display-4">技能交換平台</h1>
        <p class="lead">交換你的技能是放潛能吧!!</p>
    </div>
</div>

@endsection

@extend 是代表我要延伸哪個樣板 我這邊選擇的是名叫layout的樣板
layout是我的 Layout.blade.php的名字喔 blade.php可以不加上去
接者使用 @section 跟@endsection包起來 變數就使用contnent包進去
聰民的你應該發現了!這樣的作法 我們可以用不同變數包在不同區域
比如說footer或是sidebar等等~~~

有了這樣的概念後我們把其他葉面都補上這個layout搂

user/profile.blade.php

@extends('layout')

<head>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"> </script>
    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
    <style>
        .box {
            display: flex;
            /* align-items: center; */
            justify-content: center;
            height: 100%;
        }
    </style>
</head>

@section('content')
<div class="box">
    <div>
        <table class="table">
            <thead class="thead-dark">
                <tr>
                    <th scope="col">id</th>
                    <th scope="col">姓名</th>
                    <th scope="col">email</th>
                    <th scope="col">會員建立時間</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>
                        {{$user->id}}
                    </td>
                    <td>
                        {{$user->name}}
                    </td>
                    <td>
                        {{$user->email}}
                    </td>
                    <td>
                        {{$user->created_at}}
                    </td>
                </tr>

            </tbody>
        </table>
    </div>
</div>
@endsection

以此類推

2. 建立Trade的 Model,Controller,Resource,Route

依照我前面的習慣
我們先建立Model跟migration吧

php artisan make:Trade -m

create_trades_table.php
接者在mirgration裡面增加這些欄位

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateTradesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('trades', function (Blueprint $table) {
            $table->id();
            $table->string('target_user_id'); // 交換者的User ID
            $table->integer('skill_id'); // 對方的技能ID
            $table->integer('user_id'); // 自己的User ID
            $table->string('my_skill_id'); // 自己的技能ID
            $table->string('shopNo'); // 建立訂單的編號
            $table->integer('amount'); // 價錢 (前方說的技能相減分數*1000)
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('trades');
    }
}

建立這些欄位的解釋麻煩幫我看註解喔
接者我們定義route吧!

Route::resource('trades', 'TradeController');

Trade Model fillable也要修改一下喔

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Trade extends Model
{
    use HasFactory;
    protected $fillable = [
        'target_user_id',
        'user_id', 'skill_id',
        'my_skill_id', 'shopNo', 'amount'
    ];
}

3. 修改之前評分列表 我們新增可以交換的按鈕

為了讓大家了解我的系統流程
先讓大家看圖吧!

https://ithelp.ithome.com.tw/upload/images/20211015/20121052RuCm5NZIEt.png
在評分表裡我們除了秀出個人對該技能的評分以外
我們也多了交易的按鈕
我們來看一下接下來會跳到哪個畫面喽!

https://ithelp.ithome.com.tw/upload/images/20211015/20121052daC7rNPABy.png
接者跳到這畫面

說明 我現在是admin的使用者 我目標是roni的微積分作技能交換
那們作為交換我目前只有化學可以選
點擊過去就可以做交換搂!!

4. point的blade.view修改

@extends('layout')


@section('content')
<div>
  <table class="table table-bordered">
    <thead>
      <tr>
        <th>ID</th>
        <th>標題</th>
        <th>使用者ID</th>
        <th>技能評分</th>
        <th>分數</th>
        <th>交換技能</th>
      </tr>
    </thead>
    <tbody>
      @foreach($skills as $skill )
      <tr>
        <td>{{$skill->id}}</td>
        <td>{{$skill->title}}</td>
        <td>{{$skill->user_id}}</td>
        <td><button type="button" class="btn btn-primary" onclick="myFunction('{{$skill->id}}','{{$skill->user_id}}')">進入評分</button></td>
        <td>{{$skill->point}}</td>
        <td><button class="btn btn-primary" onclick="goTrade('{{$skill->id}}','{{$skill->user_id}}','{{$my_id}}')">進行技能交換</button></td>
      </tr>
      @endforeach
    </tbody>
  </table>
  <!-- {{$skills}} -->
  <!-- {{$my_id}} -->
</div>


<script>
  function myFunction(skill_id, user_id) {
    var data = {
      skill_id,
      user_id
    }
    $.ajax({
        method: "POST",
        url: "/points",
        dataType: 'json',
        data
      })
      .done(function(msg) {
        console.log(msg)
      });
  }

  function goTrade(skill_id, user_id, my_id) {
    var data = {
      skill_id,
      user_id: my_id,
      target_user_id: user_id
    }
    window.location.replace(`/trades?skill_id=${data.skill_id}&user_id=${data.user_id}&target_user_id=${data.target_user_id}`)
  }
</script>

@endsection

我們在評分上面goTrade function上動手角
把一些使用者參數跟技能ID
對方ID帶過去
那麼為了要帶到
交換的選擇頁面我們參數可以用query string的方式導向別的頁面

query string就是網址後面? 接變數然後用&接起來
像是youtube影片 可以接?t=10m20s 這些參數可以讓頁面讀取到指定的參數做api請求
或是js操作

5. 我們先改controller

在Controller/TradeController.php裡的index function

    public function index(Request $request)
    {
        //
        $data = $request->all();
        $user = Auth::user();
        $skill_id = $request->query('skill_id');
        $user_id = $request->query('user_id');
        $target_user_id = $request->query('target_user_id');
        $myskills = Skill::where('user_id', $user->id)->get();
        // dd($myskills);
        return view('trade.index', [
            'skill_id' => $skill_id,
            'user_id' => $user_id,
            'target_user_id' => $target_user_id,
            'myskills' => $myskills
        ]);
    }

我們可以用Auth::user先把登入者也就是自己抓出來
然後把query()抓取query string的參數
然後我們要把自己的技能抓出來
在丟回去

自己的技能丟回去是要給作為交換的技能
才會有我們看到的這個畫面
https://ithelp.ithome.com.tw/upload/images/20211015/20121052wecjAr4zSj.png

對了這邊有小提醒!我們在開發時php可以用dd()把變數印出來
前端也可以找個位置用{{}}花括號印在旁邊來參考

接者我們有了這些參數後
選擇化學跟roni的微積分進行技能交換吧

6.交換的Controller API

在看code之前我要提醒大家一件事
我們除了存進資料庫外還有一些是要做
比如說我們要新建一筆訂單
那麼我們要先跟nodejs的服務溝通
在跟永豐API 溝通完建立完成後
如果有成功我們再把這筆交易存進資料庫裡

為了溝通我們先使用這個Class吧

use Illuminate\Support\Facades\Http;

Controller/TradeController.php

    public function store(Request $request)
    {

        $targetPoint = Point::find($request->point_id);
        $myskillsPoint = Point::query()->where('skill_id', $request->my_skill_id)->get()->first();
        $ScoreGap = abs($myskillsPoint->point - $targetPoint['point']);
// 這邊是要 計算分數差
        $datenow = date('YmdHis');
        $OrderNo = "A$datenow" . "1";
        $Amount = $ScoreGap * 1000;
// 這邊data是php內建函數 可以抓現在時間 我把這當作訂單編號
// 最後前面補上A字串最後加上1防止訂單錯誤 (永豐尾數是9會模擬交易失敗)
// . 點 是php在接字串的方法 跟javascript  + 一樣
// amount 的分數差 乘上 一千代表要交易的錢 

        $result = Http::post('http://localhost:8888/createOrder', [
            'OrderNo' => $OrderNo,
            'Amount' => $Amount * 100,
        ]);
  // 對了這邊補上100是因為永豐會把尾數去掉兩個0
 // 我們這邊把 可以在laravel做post
 // 這個是我們nodejs的建立訂單的api
 
 // 最後我們簡單判斷如果result有回傳version == 1.0.0代表我們有建立訂單成功
 // 接者再把訂單存進資料庫的動作
        if ($result['Version'] == "1.0.0") {
            $trade = Trade::create([
                'target_user_id' => $targetPoint['user_id'],
                'user_id' => $myskillsPoint->user_id,
                'skill_id' => $targetPoint['skill_id'],
                'my_skill_id' => $myskillsPoint->skill_id, 'shopNo' => $OrderNo, 'amount' => $Amount
            ]);
            return response(['trade' => $trade, 'nonce' =>  $result['Nonce'], 'msg' => $result['Message']]);
            // return response($response);
        }
        // dd($response);
        return "交易失敗";
    }

補充
https://ithelp.ithome.com.tw/upload/images/20211015/20121052BrblIdKrQx.png
我們可以觀察這個表
透過這兩個分數表的技能分數相減
可以得到2喔
(roni 的微積分 跟admin的化學)

好啦我們來看結果吧!!

https://ithelp.ithome.com.tw/upload/images/20211015/20121052iGgBdIQxbZ.png

畫面有點長XD
但是為了表現有成功
把network教出來給大家看

小提醒: Chrome開發工具打開network可以幫助我們看APi 是否有叫成功喔!!

接者使用者就可以進到付款畫面喽
https://ithelp.ithome.com.tw/upload/images/20211015/20121052AJzZwOL5mZ.png

7. 接者我們來做本人所有交易的紀錄吧

我們先新建一個紀錄個人所有交易的路由

Route::get('trades/record', 'TradeController@record');

接者去調整controller

    public function record(Request $request)
    {
        if (!Auth::check()) {
            return view('user.login');
        }
        $user = Auth::user();

        $myresult = DB::table('trades')
            ->join('users', 'trades.target_user_id', '=', 'users.id')
            ->join('skills', 'skills.id', '=', 'trades.skill_id')
            ->where('trades.user_id', $user->id)->select('trades')
            ->select(
                'users.name as target_user_name',
                'skills.title as tatget_skill_title',
                'ShopNo',
                'amount',
                'trades.created_at'
            )
            ->get();
        // $target_user_id = $myresult['target_user_id'];

        // $target_user = User::find($target_user_id);

        return view('trade.record', ['result' => $myresult]);
    }

這邊用query builder的功能把sql串在一起
我們要把對方使用者名稱跟技能做聯表查詢

回傳的名稱可以用as就可以變更名稱
最後再把訂單編號、價錢、訂單日期回傳回來
我們可以先用dd來看回傳資料
https://ithelp.ithome.com.tw/upload/images/20211015/20121052fxh6aBoLg7.png

給大家看對照比較好懂

接者我們就把index畫面補上吧

@extends('layout')


@section('content')
<div>
  <table class="table table-bordered">
    <thead>
      <tr>
        <th>交易對象</th>
        <th>交易技能名稱</th>
        <th>訂單編號</th>
        <th>價錢</th>
        <th>交易時間</th>
      </tr>
    </thead>
    <tbody>
      @foreach($result as $res)
      <tr>
        <td>{{$res->target_user_name}}</td>
        <td>{{$res->tatget_skill_title}}</td>
        <td>{{$res->ShopNo}}</td>
        <td>{{$res->amount}}</td>
        <td>{{$res->created_at}}</td>
      </tr>
      @endforeach
    </tbody>
  </table>
</div>

@endsection

接者就是成果拉
https://ithelp.ithome.com.tw/upload/images/20211015/20121052f7hwYIVDxJ.png

8.遺珠之憾 技能樹

接者讓大家看一下
我本來是希望可以把自己有的技能以技能樹呈現出來給跟別人交換
但是案於時間關係沒有把它串完
可以讓大家看一下用d3js做的圖
https://ithelp.ithome.com.tw/upload/images/20211015/20121052dfZ3ALCwxE.png

使用d3js可以把既能呈現成這種形狀並且無限延伸

總結

好啦
今天總結突然爆了一堆程式碼
相信大家也看得頭昏眼花了
先給大家程式碼聯結有興趣的可以玩看看喔
Laravel 的程式碼

Nodejs Microservices永豐API微服務

這邊有一些地方可以跟大家分享
今天你得主服務可能是laravel可能是spring
但是其他小的服務比如說machine用python我們使用flask接
或是使用nodejs來串

那這些小型的微服務好處是把耦合性分離
不會因為一個service壞了整個系統
也很好把邏輯分開
但缺點是需要有人去維護處理
還有溝通之間的資安風險喔!!

最後如果要看每一天的篇章可以回到首篇來參考喔感謝大家!!

感謝這幾天有follow我的觀眾們!

看完我整包專案
應該可以對以下概念有所了解

我把一些重點篇章整理出來可以
由下方參考找到篇章喔
/images/emoticon/emoticon08.gif

  1. laravel 專案建置流程(先建立migration,model,再來定義路由跟controller最後呈現的畫面) 詳細說明可以看我前面說明喔 第八章的laravel建置習慣
  2. php artisan 指令(這邊有快速建立model跟migration還有Controller --resource對應route的應用)
  3. 資料庫的設計(紀錄id 還有laravel慣例用法可以操作相當輕鬆)
  4. 一對一級一對多的設計 第十六章 技能skill服務
  5. Blade的應用 我們可以使用laravel blade快速建立前端操作起來也相當便利
  6. Nodejs (Express服務建置) 可以看我第一篇章到第五篇章的教學
  7. Postman的操作 測試微服務的好工具
  8. aes加密的方法 透過nodejs的方法製作永豐需求的簽章及加密過程
  9. passport套件 雖然不只有laravel才有 但是我這邊說明如何使用passport做驗證動作 可以參考 十一到十三 第十一篇章 安裝passport
  10. JWT 解釋了JWT的用途 第十三章JWT 應用在登入上
  11. User Story概念 我認為對工程師分析軟體架構來說相當重要是訂一一個軟體架構的好方法第十章 user story
  12. Bootstrap套入laravel使用 可以參考19,20章 第十九篇章 開雙B blade跟 bootstrap
  13. Ajax應用 對網頁工程師而言 這項技術是不可或缺的溝通橋樑不管是前端對後端,還是後端對其他服務都是很重要的 詳細可以參考 第21,22篇章喔 使用Ajax來做登入API界接
  14. query build 我覺得好的query可以增加效能跟減少跟資料庫要的loading 第二十四章 query builder應用
  15. 整合工作 最後就是前後端、資料庫、路由、controller的整併工作這些可以參考我最後的五章喔

最後真的很感謝大家觀看
最後一篇章1萬5千多字的超長文XD
有興趣陪我一起技術可以透過我github找我信箱寫信喔!

如果喜歡我的分享可以幫我按讚喔XD


上一篇
[Day29] 第二十九 - 補充技能交換前端以及與Express溝通api
系列文
釋放你的潛能用技能交易吧!30

尚未有邦友留言

立即登入留言