CRUD 操作 (作成、読み取り、更新、削除) は、ほとんどの Web アプリケーションのバックボーンです。このチュートリアルでは、フロントエンドに Angular、バックエンドに GoAPI を使用して CRUD アプリを構築し、完全に統合された効率的なフルスタック ソリューションを実現する方法を示します。
Angular 18 をインストールし、次のコマンドで新しいプロジェクトを作成します。
npm install -g @angular/cli@18.0.0 ng new view --minimal --routing --style css --no-standalone --ssr=false
└─ 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
*このプロジェクト構造には、作成または変更する予定のファイルとフォルダーのみが表示されます。
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 アプリケーションを初期化します。ブラウザーで実行されるようにアプリケーションを設定し、ブートストラップ プロセス中に発生するエラーを処理します。
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 はブートストラップ コンポーネントとして設定され、アプリケーションのエントリ ポイントになります。
import { Component } from '@angular/core' @Component({ selector: 'app-root', template: `<router-outlet></router-outlet>` }) export class AppComponent { }
app.component.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 クラスは、サーバーに送信される前に、すべての送信 HTTP リクエスト URL に構成可能な BaseURL を追加する Angular HTTP インターセプターです。これにより、アプリケーションはベース API エンドポイントを一元化し、簡単に管理できるようになります。
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」にリダイレクトするルートも含まれています。
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 を呼び出して製品を作成し、製品リストに戻ります。検証エラーは対応するフィールドの横に表示され、作成エラーがあるとアラートがトリガーされます。
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 を呼び出して製品を削除し、製品リストにリダイレクトします。削除中にエラーが発生した場合は、アラートが表示されます。
└─ 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、名前、価格を読み取り専用フィールドに表示します。このコンポーネントには、ナビゲーション用の「戻る」ボタンと「編集」ボタンが用意されています。製品の詳細は、コンポーネントの初期化時に取得されて表示されます。
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 を介して製品が更新され、製品リストに戻ります。取得または更新中のエラーはアラートとして表示され、検証エラーは関連フィールドの横に表示されます。
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、名前、価格を表示、各製品を表示、編集、削除するためのアクション ボタンとともに表示します。また、製品作成ページに移動するボタンも含まれています。
import { Component } from '@angular/core' @Component({ selector: 'app-root', template: `<router-outlet></router-outlet>` }) export class AppComponent { }
ProductService は、Angular の HttpClient を使用して、製品管理に関連する HTTP リクエストを実行します。以下のメソッドを提供します:
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 は、コンテナの上にスペースを追加し、ボタンを水平方向に配置することでレイアウトを調整します。
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 は、スタイル用の Bootstrap、アイコン用の Font Awesome、
npm install -g @angular/cli@18.0.0 ng new view --minimal --routing --style css --no-standalone --ssr=false
「example」という名前のテスト データベースを作成し、database.sql ファイルを実行してテーブルとデータをインポートします。
└─ 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
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))
このファイルには、データベースに接続するための構成の詳細が保持されます。
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 接続文字列を構築し、グローバル DB 変数に保存される GORM インスタンスを初期化します。
import { Component } from '@angular/core' @Component({ selector: 'app-root', template: `<router-outlet></router-outlet>` }) export class AppComponent { }
この router.go ファイルは、Gin フレームワークを使用して Go アプリケーションのルーティングを設定します。 SetupRouter 関数は、CORS ミドルウェアを使用して Jin ルーターを初期化し、すべてのオリジンを許可します。 /api/products パスの下で製品関連の操作を処理するためのルートを定義し、それぞれが ProductController のメソッドにマップされます。最後に、Gin サーバーを起動します。
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 で使用する製品モデルを定義します。これは、Id (自動インクリメント主キー)、Name、Price の 3 つのフィールドを持つ Product 構造体を指定します。
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 ファイルは、Gin フレームワークを使用して Go アプリケーションで製品の CRUD 操作を処理するメソッドを含む ProductController 構造体を定義します。
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) }) } }
Web ブラウザを開いて http://localhost:4200 に移動します
こちらの商品一覧ページになります。
「表示」ボタンをクリックすると、製品の詳細ページが表示されます。
商品を変更し、詳細を更新するには、[編集] ボタンをクリックします。
「送信」ボタンをクリックして、更新された製品の詳細を保存します。
「作成」ボタンをクリックして新しい製品を追加し、その詳細を入力します。
「送信」ボタンをクリックして新しい製品を保存します。
以前に作成した製品を削除するには、[削除] ボタンをクリックします。
この製品の削除を確認するには、[削除] ボタンをクリックしてください。
結論として、Gin フレームワークをバックエンドとして使用して API をセットアップしながら、コンポーネント、ビュー、ルーティングを含む基本的な Angular プロジェクトを作成する方法を学びました。データベース操作に GORM を利用することで、強力で効率的なバックエンドとシームレスに統合する動的なフロントエンドの構築に成功しました。この組み合わせにより、最新のフルスタック Web アプリケーションを開発するための強固な基盤が形成されます。
ソースコード: https://github.com/stackpuz/Example-CRUD-Angular-18-Go
Angular CRUD アプリを数分で作成: https://stackpuz.com
以上がGo API を使用した Angular CRUD アプリの構築の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。