張文瑋
  • NEW!
    NEW!  Connect Ideas Across Notes
    Save time and share insights. With Paragraph Citation, you can quote others’ work with source info built in. If someone cites your note, you’ll see a card showing where it’s used—bringing notes closer together.
    Got it
      • Create new note
      • Create a note from template
        • Sharing URL Link copied
        • /edit
        • View mode
          • Edit mode
          • View mode
          • Book mode
          • Slide mode
          Edit mode View mode Book mode Slide mode
        • Customize slides
        • Note Permission
        • Read
          • Only me
          • Signed-in users
          • Everyone
          Only me Signed-in users Everyone
        • Write
          • Only me
          • Signed-in users
          • Everyone
          Only me Signed-in users Everyone
        • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invite by email
        Invitee

        This note has no invitees

      • Publish Note

        Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

        Your note will be visible on your profile and discoverable by anyone.
        Your note is now live.
        This note is visible on your profile and discoverable online.
        Everyone on the web can find and read all notes of this public team.

        Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

        Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

        Explore these features while you wait
        Complete general settings
        Bookmark and like published notes
        Write a few more notes
        Complete general settings
        Write a few more notes
        See published notes
        Unpublish note
        Please check the box to agree to the Community Guidelines.
        View profile
      • Commenting
        Permission
        Disabled Forbidden Owners Signed-in users Everyone
      • Enable
      • Permission
        • Forbidden
        • Owners
        • Signed-in users
        • Everyone
      • Suggest edit
        Permission
        Disabled Forbidden Owners Signed-in users Everyone
      • Enable
      • Permission
        • Forbidden
        • Owners
        • Signed-in users
      • Emoji Reply
      • Enable
      • Versions and GitHub Sync
      • Note settings
      • Note Insights New
      • Engagement control
      • Make a copy
      • Transfer ownership
      • Delete this note
      • Save as template
      • Insert from template
      • Import from
        • Dropbox
        • Google Drive
        • Gist
        • Clipboard
      • Export to
        • Dropbox
        • Google Drive
        • Gist
      • Download
        • Markdown
        • HTML
        • Raw HTML
    Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
    Create Create new note Create a note from template
    Menu
    Options
    Engagement control Make a copy Transfer ownership Delete this note
    Import from
    Dropbox Google Drive Gist Clipboard
    Export to
    Dropbox Google Drive Gist
    Download
    Markdown HTML Raw HTML
    Back
    Sharing URL Link copied
    /edit
    View mode
    • Edit mode
    • View mode
    • Book mode
    • Slide mode
    Edit mode View mode Book mode Slide mode
    Customize slides
    Note Permission
    Read
    Only me
    • Only me
    • Signed-in users
    • Everyone
    Only me Signed-in users Everyone
    Write
    Only me
    • Only me
    • Signed-in users
    • Everyone
    Only me Signed-in users Everyone
    Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- title: '玉山暑期實習學習紀錄' tags: spring boot, vue.js, docker --- 玉山暑期實習紀錄 > [Github](https://github.com/mrwenwei/ESUN-Summer-Project) ## 目錄 [TOC] ## 需求分析 ## 系統設計 ### 開發時程 ```mermaid gantt title 甘特圖 section 需求訪談 5days:2019-07-15, 5d section 資料庫設計 12 days:2019-07-15 , 12d section 後端程式設計 20 days:2019-07-22, 20d section 前端程式設計 20 days:2019-07-29, 20d section 文件撰寫 7 days:2019-08-18, 7d section 測試 14 days:2019-08-18, 14d ``` ## 資料庫 了解需求之後我們需要對每張單據設計一個資料庫,需要有存匯取款的所有資料,包含金額日期等等。 ### ERD 初步設計出來的 ER Diagram ![](https://i.imgur.com/Nx1WOKA.png) 不過如果以這種方式建資料庫,在未來若有單據要擴充的話會很麻煩,因此學長有與我們建議使用 [CLOB](https://en.wikipedia.org/wiki/Character_large_object),後來 ERD 也簡化成如下: ![](https://i.imgur.com/RrOoq10.png)  如此一來就能在其中的一個欄位存一個 JSON,要使用時只需要 parse 過即可。 ### Docker Docker 的好處是可以將自己的 container 存成新的 image,上傳到 Docker Hub 供別人使用,所以你也可以直接使用建好資料庫的 image,不過缺點是若利用 commit 的方式更新 image ,這種方式建立的 Image 是難以重現的,比較好的方式是編寫 dockerfile,不過這個部分還在研究中因此待補上。 MSSQL 在 Docker 上的 image 安裝 (以下為 bash 指令): 1. Pull 官方的 SQL server image ``` $ sudo docker pull mcr.microsoft.com/mssql/server:2017-latest ``` 2. run image 檔 <!-- 2. run image 檔,這裡要注意的點是 SQL Server 設定變更和資料庫檔案都會保存於容器中,即使使用 docker stop 和 docker start 來將容器重新啟動也一樣。不過,如果使用 docker rm 來移除容器,則會刪除容器中的所有項目,因此建議使用 [Volumn](https://docs.docker.com/storage/volumes/)(指令中 -v 的部分) --> ``` $ sudo docker run -e 'ACCEPT_EULA=Y' \ -e 'MSSQL_SA_PASSWORD=<YourStrong!Passw0rd>' \ -p 1433:1433 --name sql1 -d mcr.microsoft.com/mssql/server:2017-latest ``` ACCEPT_EULA 為授權合約需同意,密碼的長度至少必須是 8 個字元,包含下列四種集合的其中三種字元:大寫字母、小寫字母、以 10 為底數的數字,以及符號,1433 為 port,name 為容器名稱可任意定義,-d 為在背景執行。 3. 查看建立的 docker 容器 ``` $ sudo docker ps -a ``` 4. 執行容器(也可以下載 [Kitematic](https://kitematic.com/) 用圖形化介面操作) ``` $ sudo docker exec -it sql1 "bash" ``` 5. 連線到 SQL server ``` root@xxxxxxxxx:/# /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "<YourNewStrong!Passw0rd>" ``` 如果成功,畫面會長這個樣子 ``` 1> ``` 再來就能開始操作 DB 了 6. 建立 Database ``` 1> CREATE DATABASE your_db_name 1> COLLATE Chinese_PRC_CI_AS; 1> GO ``` **Docker 在使用資料庫時會發現無法插入中文資料,因此在建構資料庫時必須輸入以上指令:** 7. 而建立好 Database 的部分後可以直接從 SQLQuery 內的[資料夾](https://github.com/mrwenwei/ESUN-Summer-Project/tree/master/SQLQuery)執行 SQL 碼就行了(四個 table)。 做完以上步驟後即可在終端機中使用 SQL 指令操控資料庫,但如果你用不習慣 command line ,想要使用圖形介面這裡也介紹一個 Microsoft 推出的 [Azure Data Studio](https://docs.microsoft.com/zh-tw/sql/azure-data-studio/download?view=sql-server-2017),下載安裝好後只需要連線本地端的 SQL Server 帳密,並選擇資料庫,就可以使用像 MS SQL 那樣的圖形化介面,還有提供 notebook 的方式可以進行 Query,非常方便。 ![](https://i.imgur.com/PDBmD8g.png) ## Spring Boot ### 建立專案 1. 點擊 command(ctrl)+N 找到 spring starter project,或者是使用官方網站提供的 [spring initializr](https://start.spring.io/) 下載並匯入。 ![](https://i.imgur.com/Cgd4V0K.png) 2. 命名設定 ![](https://i.imgur.com/YxVucnZ.png) 3. 將需要的套件加入專案,點擊 finish 完成專案建置,會自動生成 XML(專案需求需用到 web、JPA、MS SQL driver)。 ![](https://i.imgur.com/m84mLWX.png) pom.xml 內已配置好 dependency,也可以手動在這裡刪減。 ![](https://i.imgur.com/2Urt7A4.png) 4. 將新增的專案新增到 server 上:右鍵點擊 wildfly server 選擇 add and remove,將專案加進 Configured,點擊 finish 即可。 ![](https://i.imgur.com/iZS3T42.png) ### 專案架構 建立不同 package 來分別處理不同事情 ![](https://i.imgur.com/edAMCU9.png =250x) 新增方式: 在 src/main/java 資料夾內點擊右鍵>new>package 共分為 Controller、Entity、Repository、Service 四類,以下我們以實作使用者帳戶的 table 為範例來詳細討論。 * Entity 新增方式: 在 entity 的 package 右鍵>new>class ![](https://i.imgur.com/QsiKNtK.png) Entity 用來對應到資料庫中的 table,下圖是可看出在資料庫中有個叫 "AccountInfo" 的 table,在後端會將一個 row 當作一個這樣的物件來存取,定義好每個欄位的特性(ID、not null 等等),並定義 get/set 函式來取用或更改物件內容。 ![](https://i.imgur.com/LY23mwU.png) "@Entity" 的用途是告知 spring 這是一個 entity 的 class 這些 entity 的內容都是由 javax.persistence 提供,也就是 JPA,用來後續操控資料庫用。 * Repository 新增方式: 在 Repository 的 package 右鍵>new>class 與 DB 連接的橋樑。 DAO(Data Access Object)連接到數據庫,以在數據庫和服務層之間來回讀取和寫入數據。 JpaRepository 是 Spring 提供的 JPA library ([Doc](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/)),用法是在 Repository 裡繼承 JpaRepository 的 interface,底下也可以自己定義 function,不過 Spring 內建就有很多很好用的 function 了,如此一來不僅不需要打到 SQL 語法,也造成程式碼的整潔。 ![](https://i.imgur.com/x3nuqa5.png) * Service 新增方式:在 Service 的 package 右鍵>new>class 定義所有操作的詳細內容,像是新增、查詢、刪除、更新等等,寫出一套屬於自己的服務。 ![](https://i.imgur.com/OLF2MJ4.png) 圖中的 @Autowired 是用來自動對應到別的 class 的內容,建立連結的概念,讓程式知道你是在呼叫前面定義好的 class,而這裡宣告出來的 userRepo 就可以使用 Spring data JPA 提供的 function 了,如圖中 22 行的 findAll(),其意思等同於「SELECT * from AccountInfo」。 其中 save 也是一個很好用的 function,當一個 entity 的 id 不存在 table 裡頭時,呼叫此 function 則會直接新增一個欄位,若 id 存在則是更新該欄位。 ![](https://i.imgur.com/L2z8yjA.png) * Controller 新增方式:在 Controller 的 package 右鍵>new>class Controller 顧名思義是控制整個流程的地方 @RestController 是 @Controller 和 @ResponseBody 註釋的組合。@Controller 包含處理用戶請求的路由邏輯方法。 @ResponseBody 註釋用於提及必須通過具有 @Controller 註釋的類中定義的方法返回 http response。通過將這兩個功能組合到單個註釋中,Spring Boot 可以輕鬆實現,因此我們不會必須使用 @ResponseBody 註釋來註釋 @Controller 類的每個方法。此外,response 的返回類型默認配置為 JSON。 @RequestMapping 可以對應到前端傳送來的要求,例如圖中的 getAll() 是用 "GET/users" 標注起來(method 預設為 GET),當前端傳來 GET 要求並且網址符合就會呼叫此 function,並回傳 list of entity 到前端。 ![](https://i.imgur.com/mUxZmXq.png) 到目前為止就寫出了一個符合 REST API 形式的 API,我們用 Postman 來測試看看。 ![](https://i.imgur.com/mdlVWsw.png) 成功回傳 table 內的所有內容。 ## Vue.js ### Vue.js 開發環境建置 #### 一、vue-cli 安裝 在開發Vue.js專案時,往往會搭配各種套件來取代重複性的人工作業,而 Vue-cli 是由 Vue 官方提供的專案樣板工具,可以快速透過指令建立出一個立即可用的開發環境。 ``` $ npm install -g @vue/cli ``` #### 二、建立 Vue 專案 ``` $ vue init <樣板名稱> <專案名稱> ``` (可用 $ vue list 查看官方預設樣板清單) 我們是以 webpack 樣板建立專案,如下: ``` $ vue init webpack EsunSummerProject ``` - 專案建立過程可依需求調整相關選項。 - 建議安裝 vue-router (作為路由)。 ![](https://i.imgur.com/x7dUMM9.png) - 建立完畢後,按照指示移動到專案路徑,並安裝所需模組 ``` $ cd <專案資料夾> $ npm install ``` - 啟動開發環境 ``` $ npm run dev ``` - 打開瀏覽器就可以看到專案預設的畫面了 (預設是 localhost:8080) #### 三、Visual Studio Code 安裝 https://code.visualstudio.com VS Code是一款很好用的編輯器,除了介面好看易用之外,裡面也有許多好用的套件,這邊就不多作介紹,有興趣的人可以自行google。 #### 四、Vue.js 各種套件的安裝 如果有需要使用到套件,通常有兩種使用方式,一種是透過 npm 下載套件,另一種是直接以 CDN 網址來使用。 以Vuex套件來說,以 npm 安裝: ``` npm install vuex --save ``` 以 CDN 使用直接在 script 中加入: ```javascript= <script src="/path/to/vuex.js"></script> ``` ### Vue.js 專案介紹 #### 一、專案架構 ``` . ├── build // 與 webpack 相關 ├── config // 與 webpack 相關 ├── node_modules // node npm 模組 ├── src // 主要開發環境 source code | ├── assets // 圖片等靜態檔 | ├── router // vue 路由器 | ├── app.vue // 主要的樣板檔 | ├── main.js // 主要的 js 檔,套件 import 的入口文件 | └── components // vue 元件檔 ├── static // 放置第三方 plugin 位置 ├── index.html // 靜態 html檔 ├── package.json └── package-lock.json ``` #### 二、專案的起點 Vue.js 是個專注在視圖層 (View) 的框架,它不僅易於上手,還便於與第三方套件或既有專案整合。 - 一個頁面中的各個部分可以自行決定各自獨立運作或是相連。 ![](https://i.imgur.com/GkGSoZz.png) - 我們先來看 main.js 這個檔案,它是整個 Vue 專案的最源頭,裡面引入了 Vue 並創建了 Vue 實例,這個 Vue 實例有一個引入的 components: App。 這個App就是 components資料夾中的 App.vue 檔案,會有 .vue 這個副檔名是因為專案中有使用 webpack, webpack有一個套件 vue-loader 能夠將 .vue 檔解析成 js。 ```javascript= new Vue({ el: '#app', router, store, components: { App }, template: '<App/>', data: { bgimg1: "../static/bgimg1.jpg" } }) ``` - 以我們的這個專案來說,在 index.html 檔案的內容如下,可以看到上面Vue實例中註冊的 App.vue ,因此網頁一打開就會載入 App.vue 的內容。 ```htmlmixed= <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>esp-front-end</title> </head> <body> <!-- App.vue --> <App></App> </body> </html> ``` ### Vue.js 基本應用 Vue.js的官方文件有中文版,內容也很豐富,可以先從官方文件開始學習。 https://cn.vuejs.org/v2/guide/index.html #### 一、利用 data 與 v-model 達到資料的雙向綁定 - data 用來儲存 vue 元件內部狀態或資料,並與 v-model 合作實現資料的雙向綁定。以下以本專案的匯款表單來說明: ![](https://i.imgur.com/uQAUcFg.png) - 由於合計的部分顯示出來的資料是依據使用者輸入的資料來改變,因此我們以 mastache 語法 (雙大括號)來與 data 中的值綁定,當 data 中的 totalAmount 一改變,網頁顯示出來的合計值也會馬上更新。 ```htmlmixed= <!-- template --> <div class="col-1"> <label>合計</label> </div> <div class="col-2"> <!-- 以 mastache 與 data中的 totalAmount 綁定 --> <label>{{transferForm.totalAmount}}</label> </div> ``` - data 中的 totalAmount 預設為0,當他被計算出來後,數值會同步更新到畫面上。 ```javascript= // script export default { data() { return { transferForm: { //與 totalAmount 綁定 totalAmount: "0" } }; }, } ``` - 上述的 mastache 用法通常用來實現資料的單向流動,而 v-model 則是實現雙向綁定用的,常用在表單元件上,像是 input 、 select 和 textarea 等。以下以本專案的匯款表單來做說明: ![](https://i.imgur.com/dVTUPfY.png) - 我們希望在使用者填寫表單後,輸入的內容可以同步更新在 data 中,因此使用了 v-model ,這樣的用法是雙向的,也就是不管是 html 中的表單元素,還是 javascript 中的 data,只要任一邊改變,另一邊都會同步改變。 ```htmlmixed= <!-- template --> <div class="col-2"> <label for="transactAmount">匯款金額(新台幣)</label> </div> <div class="col-4"> <input type="text" class="form-control" id="transactAmount" placeholder="請輸入金額" @input="transferFeeCounter()" v-model="transferForm.transactAmount" required /> </div> ``` ```javascript= //script export default { data() { return { transferForm: { //預設值是0,當表單被使用者輸入,此處的內容會同步改變 transactAmount: "0", } }; }, } ``` #### 二、事件處理 (Event Handling) 與 Methods - 為了能讓使用者與畫面互動,我們可以使用 v-on:method_name (簡寫@method_name) 綁定事件監聽器,藉此使用我們宣告的 method。以下以本專案的匯款表單來說明: ![](https://i.imgur.com/pGoavZh.png) - 當使用者輸入匯款金額、匯款方式之後,會觸發 method 計算出匯費和合計金額。 ```htmlmixed= <!-- template --> <div class="col-2"> <label for="transactAmount">匯款金額(新台幣)</label> </div> <div class="col-4"> <input type="text" class="form-control" id="transactAmount" placeholder="請輸入金額" @input="transferFeeCounter()" v-model="transferForm.transactAmount" required /> </div> ``` - 在上面的 input 輸入欄位中, @input="transferFeeCounter()" 等同於 v-on:input="transferFeeCounter()" ,也就是當輸入欄位有更動時,就會去呼叫 "transferFeeCounter()" 方法。 ```javascript= export default { methods:{ transferFeeCounter() { //費用的計算方式 } } } ``` #### 三、v-for 迴圈 - v-for 跟一般常見的 for 迴圈差不多,常用來在 template中顯示陣列或是物件的內容。以下以 select 選單中的 v-for 應用來說明: ![](https://i.imgur.com/ktFM98D.png) - 我們希望能將從後端抓來的銀行列表內的資料,當成下拉列表中的選項,因此使用了 v-for 來實作。 ![](https://i.imgur.com/WvZwsdd.png =200x) - 透過我們的 api 傳回來的銀行資料格式大概是這個樣子。 ```json= [ { "name": "台灣銀行", "swiftcode": "004" }, { "name": "土地銀行", "swiftcode": "005" }, { "name": "合作金庫", "swiftcode": "006" } ] ``` - option 指的是 select 選單中的選項,我們以 v-for 遍歷陣列 banks , 把銀行的代碼和名稱顯示在選單中,並以前面提到的 v-model 把使用者選擇的值存入 data 中。 ```htmlmixed= <div class="col-2"> <label for="transferBank">收款銀行</label> </div> <div class="col-2"> <select class="custom-select" id="transferBank" v-model="transferForm.transferBank" required > <option v-for=" bank in banks">{{bank.swiftcode}} {{bank.name}}</option> </select> </div> ``` #### 四、v-if 條件渲染 - 如果希望某些畫面上的元素在特定條件下才出現,可以使用 v-if、 v-if-else 和 v-else,以條件式來決定畫面出現的內容。以下以交易單據中,銀行作業欄位的表單來說明: ![](https://i.imgur.com/Q1Px3Dg.png) - 當交易是存款、匯款、提款時,這些行員必需詢問顧客的問題會不一樣,這時候為了避免同一份表單要設計很多種,可以使用 v-if 將不同的內容依條件顯示在畫面上,在這個例子中,紅圈圈起來的這一個問題在存款、匯款時的內容和提款時的不一樣,因此我們以 v-if 來判斷交易的 type,並顯示相對應的內容。 ```htmlmixed= <!-- 當交易是存款或匯款時顯示 --> <label for="question2" class="col-md-4 col-form-label col-form-label-sm" v-if="this.transact_data.type=='存款' || this.transact_data.type=='匯款'" style="border:1px solid;" >2.申請人是否認識存入帳戶的受款人 </label> <!-- 當交易是提款時顯示 --> <label for="question2" class="col-md-4 col-form-label col-form-label-sm" v-if="this.transact_data.type=='取款'" style="border:1px solid;" >2.申請人是否認識陪同提款者(有陪同提款者時詢問) </label> ``` ### VueRouter 網站路由管理 [VueRouter官方文件](https://router.vuejs.org/zh/) - vue 專案可以透過 vue-router 的設定檔來定義整體網站的路由規則,再利用 router-view 來定位子路由組件渲染的出口。 - 以下是本專案部分的路由檔案,vue router 的設定檔案會放在 components 資料夾中的 router資料夾內。 ```javascript= let router = new VueRouter({ mode: 'history', routes: [ { path: '/', name: 'login', component: login, beforeEnter: (to, from, next) => { if(store.getters.isLoggedIn){ next('home_'+store.getters.authToken) }else{ next() } } }, { path: '/home_customer', name: 'home_customer', component: home_customer, meta: { requiresAuth: true, allowAuth: 'customer' }, }, ] }) export default router ``` #### 一、router-view - router-view 簡單的作用就是在符合路由規則時,把指定路由組件取代父層組件中的視圖;而整個應用程式的第一個視圖就是在 App.vue 檔案中,也就表示在 vue-router 設定中的路由組件在匹配情境下,會直接取代 App.vue 中 router-view 元素。 ![](https://i.imgur.com/a8uQfpv.jpg) - App.vue ```htmlmixed= <template> <div> NavBar </div> <router-view /> </template> ``` 在上面的程式中,可以看到在NavBar的下面我們引入了router-view,因此顯示出來的是路由表中路徑為 '/' 的 login.vue。 #### 二、頁面的跳轉 - router.push 可以跳轉頁面,例如登入成功後,判斷使用者身份,如果是顧客的話,就將它轉移到顧客的首頁 home_customer。 ```javascript= this.$router.push("/home_customer"); ``` ### Axios 發送 http 請求 基本用法可以先參考官方文件,挺詳細的。 https://github.com/axios/axios vue更新到2.0之後,作者就宣告不再對vue-resource更新,而是推薦使用 axios 來發送 http 請求。 以 npm 安裝: ``` $ npm install axios ``` 以 CDN 使用: ```javascript= <script src="https://unpkg.com/axios/dist/axios.min.js"></script> ``` 一般常見的 Axios 寫法如下: ```javascript= axios.get('/user?ID=12345') .then(function (response) { // 請求成功後執行 console.log(response); }) .catch(function (error) { // 錯誤處理 console.log(error); }) .finally(function () { // 不管請求成功或失敗都會執行 }); ``` #### 一、API 呼叫 以下以我們匯款表單發送後的請求來示範 API 呼叫: ```javascript= submit_form() { //if user 點選確定 if (confirm("您確定要送出申請嗎?")) { let uri = "api/POST/transaction"; this.axios //發送 post 請求,將本次交易內容傳到後端 .post(uri, { type: this.transactType, receiptsData: JSON.stringify(this.transferForm), branchCode: this.$store.getters.getBranchCode }) //post 請求成功後,再以 get 請求後端返還本次交易ID .then(response => { this.axios .get("api/GET/transaction/" + response.data.id) .then(res => { alert( "已送出申請,即將返回首頁,您的交易編號為:" + res.data.tnum ); }); }); //以 VueRouter 返回首頁 this.$router.push("home_customer"); } } ``` #### 二、CORS 處理 在 config 資料夾下的 index.js 中, proxyTable 可以設定跨域請求的位置,之後只要以 '/api' 就能取代很長的網址。 ```javascript= proxyTable: { '/api': { target: 'http://172.20.10.2:8080/esp-back-end-0.0.1-SNAPSHOT/', changeOrigin: true, pathRewrite: { '^/api': '' } } }, ``` ### Vuex 與登入管理 基本用法可以先參考官方文件,挺詳細的。 https://vuex.vuejs.org/installation.html 從前幾個範例中,可以發現資料都是存放在各組件 script 的 data 裡面,但是一個大型系統中,重複使用到的資料會有很多(e.g. token, user info, shopping cart list),這樣各個頁面切換之間如何拿到同一筆資料呢? 因此我們需要一個集中管理資料的地方,這樣的需求可以用 Vuex 來完成, 透過 vuex 的 store 可以儲存多頁面共用的資料,像是登入資訊等等。 透過 npm 或 YARN 安裝 ``` npm install vuex --save ``` 打開 main.js 宣告使用 vuex ```javascript= // 引入 vuex import Vuex from 'vuex' // 告訴 Vue 使用 vuex Vue.use(Vuex) ``` 以下以登入管理來示範 vuex 的 store 使用方法: #### 一、建立 token 在 ./src/main.js 檔案加入以下: ```javascript= import store from './store' import Axios from 'axios' Vue.prototype.$http = Axios; const token = localStorage.getItem('token') if (token) { Vue.prototype.$http.defaults.headers.common['Authorization'] = token } [...] ``` #### 二、 store 的寫法 這些內容我們放在 src/store 資料夾下的 index.js 檔案 1. state: 負責記錄應用程式所有的 State。 2. mutations: 負責接收 action(commit) 資料並計算邏輯後改變 State,只有 mutation 可以改變 state。 3. action: 定義了整個應用程式的行為如:按下 login 這顆按鈕,它是一個 action!現在我們要開始登入囉!這樣的行為通常需要與 server 溝通,因此 call API 的行為(非同步)也會在 action 中執行! 它使用 commit 向 Mutations 溝通(傳遞資料)。 4. getters: 讓我們能在各個組件中存取 state 中的資料。例如:this.$store.getters.isLoggedIn 可以得知是否以登入。 ```javascript= export default new Vuex.Store({ //state,存放想要整個網站共享的資料能放在這裡 state: { status: '', token: localStorage.getItem('token') || '', }, //mutation,只能透過 mutation 改變 state 內容 mutations: { auth_request(state) { state.status = 'loading' }, auth_success(state, payload) { state.status = 'success' state.token = payload.token }, auth_error(state) { state.status = 'error' }, }, //action,負責觸發 mutation actions: { login({ commit }, user) { return new Promise((resolve, reject) => { commit('auth_request') //把使用者輸入的帳號密碼傳送到後端做比對 axios({ url: '/api/POST/user/auth/' + user.id, data: user, method: 'POST' }) //將回傳的 token 存到 localstorage中 .then(resp => { const token = resp.data.role localStorage.setItem('token', token) axios.defaults.headers.common['Authorization'] = token //透過 commit 呼叫 mutation,藉此改變 state 中的資料 commit('auth_success', {'token':token}) resolve(resp) }) .catch(err => { commit('auth_error') localStorage.removeItem('token') reject(err) }) }) }, }, //getters getters: { isLoggedIn: state => !!state.token, authStatus: state => state.status, authToken: state => state.token, } }) ``` #### 三、 Login 頁面中,按下 Login 按鈕後所觸發的事件 ```javascript= methods: { login: function() { //user輸入的id和password let id = this.user.id; let password = this.user.password; //使用 vuex 的 store this.$store //呼叫 store 中的 action 中的 login method .dispatch("login", { id, password }) //如果後端處理的結果判斷帳號錯誤 .then(() => { if (this.$store.getters.authToken == "Wrong account") { alert("帳號錯誤"); this.$store.dispatch("logout"); this.$router.push("/"); //如果後端處理的結果判斷密碼錯誤 } else if (this.$store.getters.authToken == "Wrong password") { alert("密碼錯誤"); this.$store.dispatch("logout"); this.$router.push("/"); //如果帳密都正確,依照 token 被 push 到相對應的頁面 } else { this.$router.push("/home_" + this.$store.getters.authToken); this.$router.go() } }) .catch(err => console.log(err)); }, } ``` ### Vue.js 元件式設計作法 在vue.js中,各個元件獨立運作,每個元件都有各自用途,然後再互相組合搭配,讓系統開發上比較結構化。 參考資料: https://ithelp.ithome.com.tw/articles/10196032 https://ithelp.ithome.com.tw/articles/10196169 ### Vue-tables-2 列表設計 vue 之套件,只要把資料傳進去就能輕易顯示出表格,並且做許多操作,像是篩選、搜尋等等,非常方便。 - 安裝 ``` $ npm install vue-tables-2 ``` - Import and register (main.js) ```htmlmixed= import {ServerTable, ClientTable, Event} from 'vue-tables-2'; Vue.use(ClientTable); Vue.use(ServerTable); window.Event = Event; Vue.use(Event); window.moment = require('moment'); ``` - 變數宣告 ```htmlmixed= data() { return { tableData: [], columns: ["type", "tnum", "顧客姓名", "交易金額", "dateTime", "broker", "finishedTime", "finished"], } } ``` tableData 用陣列存所有列資料(Json),columns 可以選擇你想放的欄位,例如:tableData 內的資料含有:id, name, age,此時 columns: ["id", "name"] 就不會把 age 的資料顯示出來。 - 跟後端索取資料 ```htmlmixed= this.axios.get("api/GET/transactions/"+this.$store.getters.getBranchCode).then(res => { this.tableData = res.data; this.tableData.map(x => { x.dateTime = moment(x.dateTime + " GMT+0000"); }); }); ``` 拿到資料後放進 tableData 內,若資料內有 datetime 之類的時間資料必須先用轉成 moment 物件,後面有 GMT+0000 是因為當時件資料庫時沒有設定成台灣時區,時區是在0的位置,而 moment 會預設傳進去的時區是當地的,因此要標示傳進來的時區,moment 才能辨認轉成正確時區。 - 顯示 table ```htmlmixed= <v-client-table ref="myTable" :data="tableData" :columns="columns" :options="options"> </v-client-table> ``` 如此就能顯示出資料表如下 (除 filter) ![](https://i.imgur.com/fnjXmM3.png) - Filter 功能 vue-table-2 其中一項強大的功能就是簡易實現 filter,若我們要針對個別欄位搜尋,只要在 filterable 內加入想要 filter 的欄位即可。 ```htmlmixed= options: { filterable: ["id", "type", "dateTime", "tnum"], } ``` 只不過預設是對字串的搜尋,如果想要客製化 filter 的功能像是 list filter,在 options 裡再加入 filterByColumn 及 listColumns: ```htmlmixed= options: { filterable: ["id", "type", "dateTime", "tnum"], filterByColumn: true, listColumns: { type: [ { id: "存款", text: "存款" }, { id: "取款", text: "取款" }, { id: "匯款", text: "匯款" } ] }, } ``` vue-table-2 有提供許多 [options](https://www.npmjs.com/package/vue-tables-2#options) ,可以實現許多 incredible 的功能。 另外這個 [github](https://github.com/KarateJB/eBooks/tree/master/Vue.js) 的教學寫得相當詳盡也可以參考。

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Google Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully