在Angular中消费并解析Spring Boot HATEOAS API的嵌套响应
问题描述
从Spring Boot HATEOAS API收到嵌套JSON响应,需要提取其中的vehicleListingList数组,用于Angular组件的HTML模板渲染。现有代码直接将响应当作VehicleListing[]处理,导致无法正确遍历数据。
后端返回的JSON结构:
{ "_embedded": { "vehicleListingList": [ { "id": 1, "modelYear": "2022", "make": "Honda", "model": "Civic", "_links": { "self": { "href": "http://localhost:8080/listings/1" }, "vehicleListings": { "href": "http://localhost:8080/listings" } } }, { "id": 2, "modelYear": "2017", "make": "Honda", "model": "CR-V", "_links": { "self": { "href": "http://localhost:8080/listings/2" }, "vehicleListings": { "href": "http://localhost:8080/listings" } } } ] }, "_links": { "self": { "href": "http://localhost:8080/listings" } } }
现有app.component.ts代码:
import { HttpErrorResponse } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; import { VehicleListing } from './vehicle-listing'; import { VehicleListingService } from './vehicle-listing.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent implements OnInit { public responseObj: VehicleListing[]; constructor(private listingService: VehicleListingService) {} ngOnInit() { this.getListings(); } public getListings(): void { this.listingService.getListings().subscribe( (response: VehicleListing[]) => { this.responseObj = response; console.log(this.responseObj); }, (error: HttpErrorResponse) => { alert(error.message); } ); } }
解决方案
1. 定义HATEOAS响应包装接口
创建接口匹配后端返回的完整嵌套结构,实现TypeScript类型校验:
// 可放在vehicle-listing.ts或单独文件中 export interface HateoasResponse { _embedded: { vehicleListingList: VehicleListing[]; }; _links: { self: { href: string }; }; }
同时补全VehicleListing接口的所有字段(包括_links):
export interface VehicleListing { id: number; modelYear: string; make: string; model: string; _links: { self: { href: string }; vehicleListings: { href: string }; }; }
2. 调整组件内的数据解析逻辑
修改app.component.ts,将响应对象改为HateoasResponse类型,并提取嵌套的列表数据:
import { HttpErrorResponse } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; import { VehicleListing, HateoasResponse } from './vehicle-listing'; import { VehicleListingService } from './vehicle-listing.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent implements OnInit { public vehicleListings: VehicleListing[] = []; // 存储最终列表数据 constructor(private listingService: VehicleListingService) {} ngOnInit() { this.getListings(); } public getListings(): void { this.listingService.getListings().subscribe( (response: HateoasResponse) => { // 提取_embedded下的vehicleListingList数组 this.vehicleListings = response._embedded.vehicleListingList; console.log(this.vehicleListings); }, (error: HttpErrorResponse) => { alert(error.message); } ); } }
3. 更新服务的返回类型
调整VehicleListingService中的getListings方法,返回类型改为Observable<HateoasResponse>:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { HateoasResponse } from './vehicle-listing'; @Injectable({ providedIn: 'root' }) export class VehicleListingService { private apiUrl = 'http://localhost:8080/listings'; constructor(private http: HttpClient) { } getListings(): Observable<HateoasResponse> { return this.http.get<HateoasResponse>(this.apiUrl); } }
4. HTML模板渲染
在app.component.html中使用*ngFor遍历提取后的列表数据:
<div class="listing-container"> <div *ngFor="let listing of vehicleListings" class="listing-card"> <h3>{{ listing.make }} {{ listing.model }}</h3> <p>年份: {{ listing.modelYear }}</p> <p>ID: {{ listing.id }}</p> <a [href]="listing._links.self.href" target="_blank">查看详情</a> </div> </div>
内容的提问来源于stack exchange,提问作者user14728486
相关产品推荐
相关产品推荐

