ActivatedRoute 和 Router的區別
前臺angular使用這兩個來進行路由的操作,但是好像一直不大清楚區別。這裡簡單記錄一下。
區別
constructor(private route: ActivatedRoute,
private router: Router) {
}
- ActivatedRoute是當前元件的路由物件,包含了當前的路由資訊。
- router是全域性路由器物件。可以在各個路由之間跳轉
所以最大的區別我認為就是作用域不同,一個是在獲取當前路由的資訊,另一個則是對全域性路由操作跳轉。
ActivatedRoute:
constructor(private route: ActivatedRoute){
}
ngOnInit() {
console.log(this.route);
}
將ActivatedRoute在ngOnit中列印之後,可以看到有如下屬性。
component, date , fragment,params,queryParams,snapshot,url,_futurnSnapshot
_routerState等。
Angular 文件將 ActivatedRoute 定義為。提供給每個路由元件的服務,其中包含路由特定資訊,例如路由引數、靜態資料、解析資料、全域性查詢引數和全域性片段。每個都Route將一個 URL 對映path到一個元件。
這裡講一下常看到或者用到的幾個屬性:
component
我們可以看到對應的是IndexComponet, 也就是當前路由物件對應著的是IndexCompoent.
snapshot
在Snapshot 中,我們在元件和路由中的值是不同步的。如果使用 snapshot 並且在路由定義中有一個引數,例如 product/:id,那麼如果頁面更改了id,那麼將不會獲得任何新的 id。快照意味著它是在 ngOnInit 執行時,這是它在那個時間點的狀態。
我們可以通過如下的方式獲取snapshot快照, 並可以獲取它的params路由引數。
constructor(private route: ActivatedRoute){
}
ngOnInit() {
const id = this.route.snapshot.params.id;
}
這裡params和queryParams用的比較多,所以重點講一下。
params 路由引數
params生成的URL採用matrix法(;key=value;kye1=value1)
Angular 路由器使用它來確定路由。它們是路由定義的一部分。我們需要 product/:id 這種形式來跳轉到正確的路由。
我們常使用這樣的形式,當如下定義路由時,id就是params引數
{ path: 'product/:id', component: ProductDetailComponent }
獲取id就是params引數:
constructor(private route:ActivatedRoute){
}
this.route.params.subscribe(param => {
const id = +param.id;
});
queryParams 查詢引數
queryParams生成的URL採用傳統表示法(?key=value&key1=value1)
queryParams查詢引數是可選的,通常會以 /product?page=10 的形式傳遞。
傳遞查詢引數:
第一種是通過[queryParams]指令新增。
<a [routerLink]="['product']" [queryParams]="{ page:10 }">Page 10</a>
第二種使用navigate方式導航新增。
this.router.navigate(['/product'], { queryParams: { page: 10 } });
讀取查詢引數:
constructor(private route:ActivatedRoute){
}
this.route.queryParams.subscribe(param => {
const page = +params['page'];
});
Params 和 queryParams總結
兩種都有不同的用法:
當我們希望根據productID 識別產品,在這種情況下,可以使用Params引數。
獲取/product/{id}
再舉一個例子,您想根據指定過濾產品,在這種情況下,可以使用queryParams引數。
GET /product?colour=red
專案中採取了這樣的方式:
訂閱了params引數。
public subscribeParams(): void {
this.route.params.subscribe((params: {page?: string, size?: string}) => {
this.params = params;
});
}
在路由跳轉的時候,將引數轉換為路由引數。
onSubmit(queryForm: FormGroup) {
this.params = {...this.params, ...queryForm.value}
this.reload(this.params);
}
reload(params: Params): void {
// 將引數轉換為路由引數
const queryParams = CommonService.convertToRouteParams(params);
this.router.navigate(['./'],
{
relativeTo: this.route,
queryParams: queryParams,
}).then();
}
這樣使得路由顯示的是matrix法,比較美觀。也統一了引數獲取方式。
Router
它載入與所請求路由相關聯的元件,以及獲取特定路由的相關資料。這允許我們通過控制不同的路由,獲取不同的資料,從而渲染不同的頁面.
簡單來說就是跳轉頁面。
它根據我們提供的路由來跳轉,如下。我們需要把這個TaskRoutingModule引入所處的元件,當前元件跳轉到時候,就能根據提供的路徑來跳轉到相應的元件
const routes: Routes = [
{
path: '',
component: IndexComponent,
},
{
path: 'view/:id',
component: ViewComponent,
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class TaskRoutingModule { }
跳轉方式:
第一種方式可以使用routerLink指令跳轉。
<a routerLink="view/{{id}}">view頁面</a>
第二種方式可以使用navigate方法進行相對路徑跳轉
this.router.navigate(['./'],
{
relativeTo: this.route,
queryParams: queryParams,
}).then();
也可以使用navigateByUrl方法進行絕對路徑跳轉
this.router.navigateByUrl('volunteer').then();
總結:當我們需要獲取路由的資訊的時候,可以使用activatedRoute, 當需要使用路由跳轉,使用Router。
後臺遇到的問題
另外說一下之前遇到的問題。
當前臺向後臺傳值的時候,後臺沒有接收到如圖的name。
後面排查原因的時候,才發現前臺傳的是欄位名是content,而不是name。並沒有與後臺的欄位名對應。
@RequestParam
@RequestParam註解,等價於request.getParam,可以解決前臺引數名稱與後臺接收引數變數名稱不一致的問題。
RequestParam: 主要用在Controller層,用於獲取URL中“?”後攜帶的引數的值,如:
http://localhost:8080/request...中id引數的值
- 相關屬性:
- 1、name/value:url中指定引數的名稱
- 2、required: 為true時,這個引數必選填寫,預設是true,為false時:引數可選是否填寫
- 3、defaultValue:引數不填寫時的預設值
所以當前後臺引數不一致的時候我們可以使用
RequestParam(value="前端傳值的欄位") <T> 後端要求的欄位名)
雖然這種方式可以處理,但是前後臺引數一致比較規範,所以我改了前臺傳遞的的欄位名。
獲取認證為null
@Override
public Optional<AuthUserDetails> getAuthUserDetailWithoutTransaction() {
logger.debug("根據認證獲取當前登入使用者名稱,並獲取該使用者");
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
}
列印了下SecurityContextHolder.getContext().getAuthentication()結果為null。
查閱了Baeldunghttps://www.baeldung.com/spri...
得知
預設情況下,Spring Security Authentication 繫結到ThreadLocal(也就是執行緒本地. )因此,當執行流在帶有 @Async 的新執行緒中執行時,它不會是經過身份驗證的上下文,會丟失掉上下文資訊。
解決方法
1.可以傳遞上下文資訊:
// 1. 在主執行緒中獲取安全上下文。
SecurityContext securityContext = SecurityContextHolder.getContext();
threadTaskExecutor.execute(() -> {
try {
// 2. 將主執行緒中的安全上下文設定到子執行緒中的ThreadLocal中。
SecurityContextHolder.setContext(securityContext);
// 業務程式碼
} catch (Exception e) {
// 異常資訊捕獲
} finally {
// 清除操作
// 3. 將呼叫者中的安全上下文設定到當前業務子執行緒中的ThreadLocal中。
SecurityContextHolder.clearContext();
}
});
詳細:https://blog.csdn.net/qq_3725...。
2.在主執行緒中獲取好需要的資訊再作為引數傳遞到非同步方法中
這個方法也是最簡單的方法,在非同步方法的上一層根據上下文獲取好想要的資訊之後,比如id等,再作為引數傳遞到非同步方法。
當然還有很多方法,可以谷歌搜尋關鍵字 非同步安全上下文配置