首頁  >  文章  >  後端開發  >  使用 Go API 建立 Angular CRUD 應用程式

使用 Go API 建立 Angular CRUD 應用程式

Patricia Arquette
Patricia Arquette原創
2024-11-04 21:36:02426瀏覽

Building an Angular CRUD App with a Go API

CRUD 操作(建立、讀取、更新、刪除)是大多數 Web 應用程式的支柱。在本教程中,我們將向您展示如何建立前端使用 Angular、後端使用 GoAPI 的 CRUD 應用程序,從而形成完全整合且高效的全端解決方案。

先決條件

  • Node.js
  • 去1.21
  • MySQL

設定 Angular 項目

安裝 Angular 18 並使用以下命令建立新專案。

npm install -g @angular/cli@18.0.0
ng new view --minimal --routing --style css --no-standalone --ssr=false

Angular 專案結構

└─ src
   ├─ app
   │  ├─ app-routing.module.ts
   │  ├─ app.component.ts
   │  ├─ app.interceptor.ts
   │  ├─ app.module.ts
   │  └─ components
   │     └─ product
   │        ├─ Create.component.ts
   │        ├─ Delete.component.ts
   │        ├─ Detail.component.ts
   │        ├─ Edit.component.ts
   │        ├─ Index.component.ts
   │        └─ Product.service.ts
   ├─ index.html
   ├─ main.ts
   └─ styles.css

*此項目結構將僅顯示我們計劃建立或修改的文件和資料夾。

角度專案文件

主要.ts

import { enableProdMode } from '@angular/core'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'

import { AppModule } from './app/app.module'

platformBrowserDynamic().bootstrapModule(AppModule).catch(e => console.error(e))

這個 main.ts 檔案透過使用 platformBrowserDynamic 函數引導 AppModule 來初始化 Angular 應用程式。它將應用程式設定為在瀏覽器中運行並處理引導過程中發生的任何錯誤。

應用程式模組.ts

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms'
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'
import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { AppInterceptor } from './app.interceptor'

import { ProductIndex } from './components/product/Index.component'
import { ProductCreate } from './components/product/Create.component'
import { ProductDetail } from './components/product/Detail.component'
import { ProductEdit } from './components/product/Edit.component'
import { ProductDelete } from './components/product/Delete.component'

@NgModule({
  declarations: [
    AppComponent,
    ProductIndex,
    ProductCreate,
    ProductDetail,
    ProductEdit,
    ProductDelete,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AppInterceptor, multi: true }
  ],
  bootstrap: [AppComponent]
})

export class AppModule { }

AppModule 是 Angular 應用程式的主要模組。它導入核心 Angular 模組並使用 AppRoutingModule 設定路由。此模組聲明了各種與產品相關的組件。它還將 AppInterceptor 註冊為 HTTP 攔截器。 AppComponent 被設定為引導元件,使其成為應用程式的入口點。

應用程式組件.ts

import { Component } from '@angular/core'

@Component({
  selector: 'app-root',
  template: `<router-outlet></router-outlet>`
})

export class AppComponent { }

app.component.ts 檔案定義了根元件 AppComponent,它使用 。其範本中的指令用於顯示路由視圖。該元件由應用程式根選擇器標識,並作為 Angular 應用程式的入口點。

應用程式攔截器.ts

import { Injectable } from '@angular/core';
import { HttpInterceptor } from '@angular/common/http';
import { HttpRequest, HttpErrorResponse } from '@angular/common/http'
import { Observable, throwError } from 'rxjs'
import { HttpHandler } from '@angular/common/http'
import { HttpEvent } from '@angular/common/http'

@Injectable({
  providedIn: 'root'
})

export class AppInterceptor implements HttpInterceptor {

  baseURL = 'http://localhost:8080/api'

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request.clone({
      url: this.baseURL + request.url,
    }))
  }
}

AppInterceptor 類別是一個 Angular HTTP 攔截器,它在將所有傳出 HTTP 請求 URL 發送到伺服器之前將可配置的 baseURL 附加到它們。這允許應用程式集中並輕鬆管理基本 API 端點。

應用程式路由.module.ts

import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'
import { ProductIndex } from './components/product/Index.component'
import { ProductCreate } from './components/product/Create.component'
import { ProductDetail } from './components/product/Detail.component'
import { ProductEdit } from './components/product/Edit.component'
import { ProductDelete } from './components/product/Delete.component'

const routes: Routes = [
  { path: '', redirectTo: 'product', pathMatch: 'full' },
  { path: 'product', component: ProductIndex },
  { path: 'product/create', component: ProductCreate },
  { path: 'product/:id', component: ProductDetail },
  { path: 'product/edit/:id', component: ProductEdit },
  { path: 'product/delete/:id', component: ProductDelete }
]

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})

export class AppRoutingModule { }

AppRoutingModule 為 Angular 應用程式設定路由,包括用於列出、建立、檢視、編輯和刪除產品的產品相關路徑。它還包括一條從根路徑“/”重定向到產品列表頁面“/product”的路由。

創建.component.ts

import { Component } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { ProductService } from './Product.service'

@Component({
  selector: 'product-create',
  template: `
    <div class="container">
      <div class="row">
        <div class="col">
          <form ngNativeValidate method="post" (submit)="create()">
            <div class="row">
              <div class="mb-3 col-md-6 col-lg-4">
                <label class="form-label" for="product_name">Name</label>
                <input id="product_name" name="name" class="form-control" [(ngModel)]="product.Name" maxlength="50" />
                <span *ngIf="errors.name" class="text-danger">{{errors.name}}</span>
              </div>
              <div class="mb-3 col-md-6 col-lg-4">
                <label class="form-label" for="product_price">Price</label>
                <input id="product_price" name="price" class="form-control" [(ngModel)]="product.Price" type="number" />
                <span *ngIf="errors.price" class="text-danger">{{errors.price}}</span>
              </div>
              <div class="col-12">
                <a class="btn btn-secondary" routerLink="/product">Cancel</a>
                <button class="btn btn-primary">Submit</button>
              </div>
            </div>
          </form>
        </div>
      </div>
    </div>`
})
export class ProductCreate {

  product?: any = {}
  errors?: any = {}
  constructor(private router: Router, private route: ActivatedRoute, private ProductService: ProductService) { }

  create() {
    this.ProductService.create(this.product).subscribe(() => {
      this.router.navigateByUrl('/product')
    }, (e) => {
      alert(e.error)
    })
  }
}

ProductCreate 元件提供了一個用於建立新產品的表單,將名稱和價格的輸入欄位綁定到產品物件。提交後,它會呼叫 ProductService 建立產品並導航回產品清單。驗證錯誤會顯示在對應欄位旁邊,任何建立錯誤都會觸發警報。

刪除.component.ts

npm install -g @angular/cli@18.0.0
ng new view --minimal --routing --style css --no-standalone --ssr=false

Delete.component.ts 中的 ProductDelete 元件是一個處理產品刪除的 Angular 元件。它顯示一個帶有唯讀欄位的表單,其中顯示產品的詳細資訊(ID、名稱和價格)。當元件初始化時,它會使用路由中的產品 ID 來取得產品詳細資訊。提交表單時,delete() 方法呼叫 ProductService 刪除產品,然後重定向到產品清單。如果刪除過程中出現錯誤,則會顯示警報。

詳細資料.組件.ts

└─ src
   ├─ app
   │  ├─ app-routing.module.ts
   │  ├─ app.component.ts
   │  ├─ app.interceptor.ts
   │  ├─ app.module.ts
   │  └─ components
   │     └─ product
   │        ├─ Create.component.ts
   │        ├─ Delete.component.ts
   │        ├─ Detail.component.ts
   │        ├─ Edit.component.ts
   │        ├─ Index.component.ts
   │        └─ Product.service.ts
   ├─ index.html
   ├─ main.ts
   └─ styles.css

ProductDetail 元件顯示特定產品的詳細資訊。它根據路線中的 ID 檢索產品信息,並在唯讀欄位中顯示產品的 ID、名稱和價格。此元件提供“後退”和“編輯”按鈕用於導航。組件初始化時會取得並顯示產品詳細資訊。

編輯.component.ts

import { enableProdMode } from '@angular/core'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'

import { AppModule } from './app/app.module'

platformBrowserDynamic().bootstrapModule(AppModule).catch(e => console.error(e))

ProductEdit 元件允許使用者編輯現有產品。它使用路線中的產品 ID 檢索產品詳細信息,並將其顯示在帶有可編輯名稱和價格欄位的表單中。提交表單後,它會透過 ProductService 更新產品並導航回產品清單。取得或更新期間的任何錯誤都會顯示為警報,並且驗證錯誤會顯示在相關欄位旁邊。

索引.component.ts

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms'
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'
import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { AppInterceptor } from './app.interceptor'

import { ProductIndex } from './components/product/Index.component'
import { ProductCreate } from './components/product/Create.component'
import { ProductDetail } from './components/product/Detail.component'
import { ProductEdit } from './components/product/Edit.component'
import { ProductDelete } from './components/product/Delete.component'

@NgModule({
  declarations: [
    AppComponent,
    ProductIndex,
    ProductCreate,
    ProductDetail,
    ProductEdit,
    ProductDelete,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AppInterceptor, multi: true }
  ],
  bootstrap: [AppComponent]
})

export class AppModule { }

ProductIndex 元件以表格格式顯示產品清單。它在初始化時從 ProductService 取得產品列表,並顯示每個產品的 ID、名稱和價格,以及用於檢視、編輯和刪除每個產品的操作按鈕。它還包括一個用於導航到產品創建頁面的按鈕。

產品.服務.ts

import { Component } from '@angular/core'

@Component({
  selector: 'app-root',
  template: `<router-outlet></router-outlet>`
})

export class AppComponent { }

ProductService 使用 Angular 的 HttpClient 來執行產品管理的相關 HTTP 請求。它提供了以下方法:

  • get(id?):透過 ID 取得產品詳細信息,如果沒有提供 ID,則取得產品清單。
  • create(data?): 如果提供了數據,則建立一個新產品,否則取得建立產品頁面。
  • edit(id, data?):如果提供了數據,則透過 ID 更新產品,否則取得產品詳細資訊進行編輯。
  • delete(id, data?):如果提供了數據,則按ID刪除產品,否則獲取產品詳細資訊以進行確認。

樣式.css

import { Injectable } from '@angular/core';
import { HttpInterceptor } from '@angular/common/http';
import { HttpRequest, HttpErrorResponse } from '@angular/common/http'
import { Observable, throwError } from 'rxjs'
import { HttpHandler } from '@angular/common/http'
import { HttpEvent } from '@angular/common/http'

@Injectable({
  providedIn: 'root'
})

export class AppInterceptor implements HttpInterceptor {

  baseURL = 'http://localhost:8080/api'

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request.clone({
      url: this.baseURL + request.url,
    }))
  }
}

CSS 透過在容器上方新增空間並水平間隔按鈕來調整佈局。

索引.html

import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'
import { ProductIndex } from './components/product/Index.component'
import { ProductCreate } from './components/product/Create.component'
import { ProductDetail } from './components/product/Detail.component'
import { ProductEdit } from './components/product/Edit.component'
import { ProductDelete } from './components/product/Delete.component'

const routes: Routes = [
  { path: '', redirectTo: 'product', pathMatch: 'full' },
  { path: 'product', component: ProductIndex },
  { path: 'product/create', component: ProductCreate },
  { path: 'product/:id', component: ProductDetail },
  { path: 'product/edit/:id', component: ProductEdit },
  { path: 'product/delete/:id', component: ProductDelete }
]

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})

export class AppRoutingModule { }

HTML 作為 Angular 應用程式的主要入口點,包括用於樣式的 Bootstrap、用於圖示的 Font Awesome 和 。作為 Angular 應用程式的佔位符。

設定 Go API 項目

npm install -g @angular/cli@18.0.0
ng new view --minimal --routing --style css --no-standalone --ssr=false

建立一個名為「example」的測試資料庫,並執行database.sql檔案導入表和資料。

Go API 專案結構

└─ src
   ├─ app
   │  ├─ app-routing.module.ts
   │  ├─ app.component.ts
   │  ├─ app.interceptor.ts
   │  ├─ app.module.ts
   │  └─ components
   │     └─ product
   │        ├─ Create.component.ts
   │        ├─ Delete.component.ts
   │        ├─ Detail.component.ts
   │        ├─ Edit.component.ts
   │        ├─ Index.component.ts
   │        └─ Product.service.ts
   ├─ index.html
   ├─ main.ts
   └─ styles.css

Go API 專案文件

.env

import { enableProdMode } from '@angular/core'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'

import { AppModule } from './app/app.module'

platformBrowserDynamic().bootstrapModule(AppModule).catch(e => console.error(e))

此文件保存連接資料庫的設定詳細資訊。

資料庫Go

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms'
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'
import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { AppInterceptor } from './app.interceptor'

import { ProductIndex } from './components/product/Index.component'
import { ProductCreate } from './components/product/Create.component'
import { ProductDetail } from './components/product/Detail.component'
import { ProductEdit } from './components/product/Edit.component'
import { ProductDelete } from './components/product/Delete.component'

@NgModule({
  declarations: [
    AppComponent,
    ProductIndex,
    ProductCreate,
    ProductDetail,
    ProductEdit,
    ProductDelete,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AppInterceptor, multi: true }
  ],
  bootstrap: [AppComponent]
})

export class AppModule { }

這個 db.go 檔案配置與 GORM 的資料庫連線。 SetupDatabase函數載入環境變量,建構MySQL連接字串,並初始化GORM實例,該實例儲存在全域DB變數中。

路由器.go

import { Component } from '@angular/core'

@Component({
  selector: 'app-root',
  template: `<router-outlet></router-outlet>`
})

export class AppComponent { }

此 router.go 檔案使用 Gin 框架為 Go 應用程式設定路由。 SetupRouter 函數使用 CORS 中間件初始化 Gin 路由器以允許所有來源。它定義了在 /api/products 路徑下處理產品相關操作的路由,每個路由都會對應到 ProductController 中的一個方法。最後,它啟動了 Gin 伺服器。

產品.go

import { Injectable } from '@angular/core';
import { HttpInterceptor } from '@angular/common/http';
import { HttpRequest, HttpErrorResponse } from '@angular/common/http'
import { Observable, throwError } from 'rxjs'
import { HttpHandler } from '@angular/common/http'
import { HttpEvent } from '@angular/common/http'

@Injectable({
  providedIn: 'root'
})

export class AppInterceptor implements HttpInterceptor {

  baseURL = 'http://localhost:8080/api'

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request.clone({
      url: this.baseURL + request.url,
    }))
  }
}

此product.go 檔案定義了與 GORM 一起使用的產品模型。它指定了一個具有三個欄位的 Product 結構體:Id(自動遞增主鍵)、Name、Price。

產品控制器.go

import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'
import { ProductIndex } from './components/product/Index.component'
import { ProductCreate } from './components/product/Create.component'
import { ProductDetail } from './components/product/Detail.component'
import { ProductEdit } from './components/product/Edit.component'
import { ProductDelete } from './components/product/Delete.component'

const routes: Routes = [
  { path: '', redirectTo: 'product', pathMatch: 'full' },
  { path: 'product', component: ProductIndex },
  { path: 'product/create', component: ProductCreate },
  { path: 'product/:id', component: ProductDetail },
  { path: 'product/edit/:id', component: ProductEdit },
  { path: 'product/delete/:id', component: ProductDelete }
]

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})

export class AppRoutingModule { }

product_controller.go 檔案定義了一個 ProductController 結構,其中包含使用 Gin 框架處理 Go 應用程式中產品的 CRUD 操作的方法。

  • Index 檢索並傳回所有產品的清單。
  • Get 透過 ID 取得並傳回單一產品。
  • 建立 從請求主體建立新產品。
  • 更新 使用請求正文中的資料更新現有產品。
  • 刪除 按產品 ID 刪除產品。

主機程式

import { Component } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { ProductService } from './Product.service'

@Component({
  selector: 'product-create',
  template: `
    <div class="container">
      <div class="row">
        <div class="col">
          <form ngNativeValidate method="post" (submit)="create()">
            <div class="row">
              <div class="mb-3 col-md-6 col-lg-4">
                <label class="form-label" for="product_name">Name</label>
                <input id="product_name" name="name" class="form-control" [(ngModel)]="product.Name" maxlength="50" />
                <span *ngIf="errors.name" class="text-danger">{{errors.name}}</span>
              </div>
              <div class="mb-3 col-md-6 col-lg-4">
                <label class="form-label" for="product_price">Price</label>
                <input id="product_price" name="price" class="form-control" [(ngModel)]="product.Price" type="number" />
                <span *ngIf="errors.price" class="text-danger">{{errors.price}}</span>
              </div>
              <div class="col-12">
                <a class="btn btn-secondary" routerLink="/product">Cancel</a>
                <button class="btn btn-primary">Submit</button>
              </div>
            </div>
          </form>
        </div>
      </div>
    </div>`
})
export class ProductCreate {

  product?: any = {}
  errors?: any = {}
  constructor(private router: Router, private route: ActivatedRoute, private ProductService: ProductService) { }

  create() {
    this.ProductService.create(this.product).subscribe(() => {
      this.router.navigateByUrl('/product')
    }, (e) => {
      alert(e.error)
    })
  }
}

這個 main.go 檔案是 Go 應用程式的入口點。它導入配置和路由包,然後呼叫 config.SetupDatabase() 初始化資料庫連接,呼叫 router.SetupRouter() 設定應用程式的路由。

運行專案

運行 Angular 專案

import { Component } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { ProductService } from './Product.service'

@Component({
  selector: 'product-delete',
  template: `
    <div class="container">
      <div class="row">
        <div class="col">
          <form ngNativeValidate method="post" (submit)="this.delete()">
            <div class="row">
              <div class="mb-3 col-md-6 col-lg-4">
                <label class="form-label" for="product_id">Id</label>
                <input readonly id="product_id" name="id" class="form-control" value="{{product.Id}}" type="number" required />
              </div>
              <div class="mb-3 col-md-6 col-lg-4">
                <label class="form-label" for="product_name">Name</label>
                <input readonly id="product_name" name="name" class="form-control" value="{{product.Name}}" maxlength="50" />
              </div>
              <div class="mb-3 col-md-6 col-lg-4">
                <label class="form-label" for="product_price">Price</label>
                <input readonly id="product_price" name="price" class="form-control" value="{{product.Price}}" type="number" />
              </div>
              <div class="col-12">
                <a class="btn btn-secondary" routerLink="/product">Cancel</a>
                <button class="btn btn-danger">Delete</button>
              </div>
            </div>
          </form>
        </div>
      </div>
    </div>`
})
export class ProductDelete {

  product?: any = {}
  constructor(private router: Router, private route: ActivatedRoute, private ProductService: ProductService) { }

  ngOnInit() {
    this.get()
  }

  get() {
    return this.ProductService.delete(this.route.snapshot.params['id']).subscribe(data => {
      this.product = data
    }, e => {
      alert(e.error)
    })
  }

  delete() {
    this.ProductService.delete(this.route.snapshot.params['id'], this.product).subscribe(() => {
      this.router.navigateByUrl('/product')
    }, (e) => {
      alert(e.error)
    })
  }
}

運行 Go API 專案

import { Component } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { ProductService } from './Product.service'

@Component({
  selector: 'product-detail',
  template: `
    <div class="container">
      <div class="row">
        <div class="col">
          <form ngNativeValidate method="post">
            <div class="row">
              <div class="mb-3 col-md-6 col-lg-4">
                <label class="form-label" for="product_id">Id</label>
                <input readonly id="product_id" name="id" class="form-control" value="{{product.Id}}" type="number" required />
              </div>
              <div class="mb-3 col-md-6 col-lg-4">
                <label class="form-label" for="product_name">Name</label>
                <input readonly id="product_name" name="name" class="form-control" value="{{product.Name}}" maxlength="50" />
              </div>
              <div class="mb-3 col-md-6 col-lg-4">
                <label class="form-label" for="product_price">Price</label>
                <input readonly id="product_price" name="price" class="form-control" value="{{product.Price}}" type="number" />
              </div>
              <div class="col-12">
                <a class="btn btn-secondary" routerLink="/product">Back</a>
                <a class="btn btn-primary" routerLink="/product/edit/{{product.Id}}">Edit</a>
              </div>
            </div>
          </form>
        </div>
      </div>
    </div>`
})
export class ProductDetail {

  product?: any = {}
  constructor(private route: ActivatedRoute, private ProductService: ProductService) { }

  ngOnInit() {
    this.get()
  }

  get() {
    return this.ProductService.get(this.route.snapshot.params['id']).subscribe(data => {
      this.product = data
    }, e => {
      alert(e.error)
    })
  }
}

開啟網頁瀏覽器並前往http://localhost:4200

你會發現這個產品清單頁面。

Building an Angular CRUD App with a Go API

測試

點選「檢視」按鈕即可查看商品詳情頁面。

Building an Angular CRUD App with a Go API

點擊「編輯」按鈕可以修改產品並更新其詳細資料。

Building an Angular CRUD App with a Go API

點選「提交」按鈕儲存更新的產品詳細資料。

Building an Angular CRUD App with a Go API

點擊「建立」按鈕以新增產品並輸入其詳細資料。

Building an Angular CRUD App with a Go API

點選「提交」按鈕儲存新產品。

Building an Angular CRUD App with a Go API

點選「刪除」按鈕即可刪除先前建立的產品。

Building an Angular CRUD App with a Go API

點選「刪除」按鈕確認刪除該產品。

Building an Angular CRUD App with a Go API

結論

總之,我們學習如何建立一個包含元件、視圖和路由的基本 Angular 項目,同時使用 Gin 框架作為後端設定 API。透過利用 GORM 進行資料庫操作,我們成功建立了一個動態前端,該前端與強大而高效的後端無縫整合。這種組合為開發現代全端 Web 應用程式奠定了堅實的基礎。

原始碼:https://github.com/stackpuz/Example-CRUD-Angular-18-Go

在幾分鐘內建立一個 Angular CRUD 應用程式:https://stackpuz.com

以上是使用 Go API 建立 Angular CRUD 應用程式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn