<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                # 集成測試 前后臺全部完成后,原則可以進行集成測試了。 ``` compiler.js:2175 Uncaught Error: Template parse errors: Can't bind to 'formGroup' since it isn't a known property of 'form'. ("<div class="row justify-content-center"> <div class="col-4"> <form [ERROR ->][formGroup]="formGroup" (ngSubmit)="onSubmit()"> ``` src/app/app.module.ts ```javascript RouterModule, ReactiveFormsModule ? ], ``` # 數據準備 現在可以為登錄組件先映射一個路由。前臺啟動的時候做一個用戶是否已登錄的判斷,如果未登錄則跳轉到登錄的界面,用戶使用用戶名密碼登錄成功則跳轉到首頁,否則提示用戶名或密碼錯誤。 按此思路先做一些準備工作:啟動前后臺并添加一個測試教師。 ![](https://img.kancloud.cn/03/94/039425327a377436e92255589c9e7b35_316x205.png) # 添加路由 src/app/app-routing.module.ts ```javascript { path: 'login', component: LoginComponent }, ``` 打開`http://localhost:4200/login`測試路由綁定成功。 # 默認跳轉到首頁 當前系統的啟動組件為Appcomponent,同時意味著只要前臺啟動那么AppComponent必然被渲染。那么可以將系統啟動時跳轉到登錄界面的按鈕 src/app/app.component.ts ```javascript export class AppComponent implements OnInit { constructor(private route: Router) { } ngOnInit(): void { this.route.navigateByUrl('login'); } } ``` 測試效果 ![](https://img.kancloud.cn/06/85/0685b717e7bae2a3711051f701aa8185_914x409.gif) 整體的效果雖然有了,但最上側的菜單卻一直顯示著而且點擊的時候直接就繞過了認證,這并不是我們想看到了。導航的菜單之所以會出現,是由于游離在路由以外,這點可以由app.component.html得到驗證: src/app/app.component.html ```html <app-nav></app-nav> ? <div class="container"> <router-outlet></router-outlet> ? </div> <app-footer></app-footer> ``` * ? 顯示導航菜單 * ? 顯示登錄組件 # 登錄狀態數據源 解決這個問題的方法有幾種,比如先在app組件中設置isLogin字段來記錄用戶是否登錄的信息,當用戶于登錄組件登錄成功后登錄app組件改變isLogin的值。然后在V層來使用ng-if來控制是否顯示導航組件。示例代碼如下: src/app/app.component.ts ```javascript isLogin = false; ``` src/app/app.component.html ```html <app-nav *ngIf="isLogin"></app-nav> ``` src/app/login/login.component.ts ``` constructor(private teacherService: TeacherService, private appComponent: AppComponent, private router: Router) { } onSubmit() { const username = this.formGroup.get('username').value; const password = this.formGroup.get('password').value; this.teacherService.login(username, password).subscribe(result => { if (result) { this.appComponent.isLogin = true; this.router.navigateByUrl(''); } else { console.log('用戶名密碼錯誤'); } }); } ``` 此方案的測試效果如下: ![](https://img.kancloud.cn/1e/4b/1e4b500f09819b84a6a675f3ba9a8bab_984x390.gif) 該方案雖然暫時的解決了當前的問題,但在生產項目中依賴于"用戶是否已登錄"的功能不止"決定是否顯示導航組件"一個,這將需要在login組件中依次對依賴用戶登錄狀態的組件做通知。這不僅破壞了"對擴展開放、對修改關閉"的原則,而且在login組件中獲取不到非app模塊中聲明的其它組件。 >[success] 對擴展開放、對修改關閉。以login組件為例,對修改關閉是指:其它的組件需要是用戶的登錄狀態時,不應該修正login組件中的內容;對擴展開放是指:其它的組件需要是用戶的登錄狀態時,可以調用login組件的相關方法來獲得。 ## 服務層數據流 服務層的數據源恰好能夠很好的解決此類問題。把一些公共的數據由組件中抽離到服務層中,由于服務層是貫穿于整個應用的,所以任何組件都可以很輕松的獲取到該服務。用戶的登錄狀態信息會隨著用戶登錄->用戶注銷->用戶再登錄->用戶再注銷而不斷的產生新值,這是非常典型的數據流。 所以可以在TeacherService中建立是否登錄數據流,其它需要用戶登錄狀態的組件可以隨時的訂閱該數據流從而獲取用戶是否登錄的狀態。 service/teacher.service.ts ```javascript export class TeacherService { /** 數據源 */ private isLogin = new BehaviorSubject<boolean>(false); ? /** 數據源對應的訂閱服務 */ public isLogin$ = this.isLogin.asObservable(); ? /** * 設置登錄狀態 * @param isLogin 登錄狀態 */ setIsLogin(isLogin: boolean) { this.isLogin.next(isLogin); ? } ``` * ? BehaviorSubject是新建數據源的一種方式。該數據源中緩存著最后一次發送的數據,當有新的訂閱者時,首先將緩存的數據發送給訂閱者。 * ? BehaviorSubject相當于雜志社,調用其asObservable()相當于返回其報刊訂閱部門,專門提供訂閱服務。(雜志社可以做的事情大多了,直接使用雜志社對外提供所有的服務是會出亂子的) * ? 接收到新的登錄狀態時,向所有的訂閱者們發送最新的登錄狀態的值 然后App組件便可改寫為: src/app/app.component.ts ``` export class AppComponent implements OnInit { isLogin = false; constructor(private route: Router, private teacherService: TeacherService) { } ngOnInit(): void { this.teacherService.isLogin$.subscribe(isLogin => this.isLogin = isLogin); this.route.navigateByUrl('login'); } } ``` login組件改寫為: src/app/login/login.component.ts ``` constructor(private teacherService: TeacherService, private appComponent: AppComponent, ? private router: Router) { } ... this.teacherService.login(username, password).subscribe(result => { if (result) { this.appComponent.isLogin = true; ? this.router.navigateByUrl(''); this.teacherService.setIsLogin(true); } else { console.log('用戶名密碼錯誤'); } }); ``` 最終的測試結果 ![](https://img.kancloud.cn/1e/4b/1e4b500f09819b84a6a675f3ba9a8bab_984x390.gif) 但這里有個小問題:無論用戶在哪個url刷新頁面,用戶輸入用戶名密碼后都會跳轉到首頁。而用戶更希望能夠跳轉到原來的url。比如用戶在教師管理上點刷新頁面,此時跳轉到登錄頁,輸入用戶名密碼后用戶還希望能夠自動的跳轉到教師管理頁面。這當然可以通過加入用戶點擊緩存來實現:先把用戶跳轉到登錄頁面前的地址緩存起來,登錄成功后再取出該緩存的地址。接下來我們會提供一種更好更簡單的解決方法。 # 集成登錄界面 找開src/app/app.component.html,按以下代碼進行整理: ```html <app-nav *ngIf="isLogin"></app-nav> <div class="container"> <app-login *ngIf="!isLogin"></app-login> ? <router-outlet *ngIf="isLogin"></router-outlet> ? </div> <app-footer></app-footer> ``` * ? 將組件與路由并列直接顯示在啟動組件中 * ? 如果用戶未登錄,則顯示登錄組件;如果已登錄則顯示路由渲染的內容 此時,便可以一些冗余的邏輯了: src/app/login/login.component.ts ```javascript constructor(private teacherService: TeacherService, private appComponent: AppComponent, private router: Router?) { } if (result) { this.router.navigateByUrl(''); ? this.teacherService.setIsLogin(true); } else { console.log('用戶名密碼錯誤'); } ``` src/app/app-routing.module.ts ```javascript { path: '', component: WelcomeComponent }, { ? path: 'login', ? component: LoginComponent ? }, ? { ``` src/app/app.component.ts ```javascript= constructor(private teacherService: TeacherService, private router: Router ?) { ngOnInit(): void { this.teacherService.isLogin$.subscribe(isLogin => this.isLogin = isLogin); this.route.navigateByUrl('login'); ? } ``` 測試效果: ![](https://img.kancloud.cn/5c/e0/5ce0f9877db85a9b56c1518858ac1aab_984x390.gif) 至此一個簡單的不實用的登錄功能便完成了。 # 參考文檔 | 名稱 | 鏈接 | 預計學習時長(分) | | --- | --- | --- | | 源碼地址 | [https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step5.1.4](https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step5.1.4) | - | | BehaviorSubject | [https://cn.rx.js.org/manual/overview.html#h26](https://cn.rx.js.org/manual/overview.html#h26) | 5 |
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看