Operasi CRUD (Buat, Baca, Kemas Kini, Padam) ialah tulang belakang kebanyakan aplikasi web. Dalam tutorial ini, kami akan menunjukkan kepada anda cara membina apl CRUD dengan Angular di bahagian hadapan dan GoAPI di bahagian belakang, menghasilkan penyelesaian tindanan penuh bersepadu dan cekap.
Pasang Angular 18 dan buat projek baharu dengan arahan berikut.
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
*Struktur projek ini akan memaparkan hanya fail dan folder yang kami merancang untuk mencipta atau mengubah suai.
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))
Fail main.ts ini memulakan aplikasi Sudut dengan bootstrap AppModule menggunakan fungsi platformBrowserDynamic. Ia menyediakan aplikasi untuk dijalankan dalam penyemak imbas dan mengendalikan sebarang ralat yang berlaku semasa proses bootstrap.
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 ialah modul utama aplikasi Sudut. Ia mengimport modul teras Sudut dan menyediakan penghalaan dengan AppRoutingModule. Modul ini mengisytiharkan pelbagai komponen berkaitan produk. Ia juga mendaftarkan AppInterceptor sebagai pemintas HTTP. AppComponent ditetapkan sebagai komponen bootstrap, menjadikannya titik masuk aplikasi.
import { Component } from '@angular/core' @Component({ selector: 'app-root', template: `<router-outlet></router-outlet>` }) export class AppComponent { }
Fail app.component.ts mentakrifkan komponen akar, AppComponent, yang menggunakan
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, })) } }
Kelas AppInterceptor ialah pemintas HTTP Sudut yang menambahkan baseURL boleh dikonfigurasikan pada semua URL permintaan HTTP keluar sebelum ia dihantar ke pelayan. Ini membolehkan aplikasi memusatkan dan mengurus titik akhir API asas dengan mudah.
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 menyediakan penghalaan untuk aplikasi Sudut, termasuk laluan berkaitan produk untuk menyenaraikan, mencipta, melihat, mengedit dan memadamkan produk. Ia juga termasuk laluan yang mengubah hala dari laluan akar "/" ke halaman penyenaraian produk "/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) }) } }
Komponen ProductCreate menyediakan borang untuk mencipta produk baharu, mengikat medan input untuk nama dan harga pada objek produk. Semasa penyerahan, ia memanggil ProductService untuk mencipta produk dan menavigasi kembali ke senarai produk. Ralat pengesahan dipaparkan di sebelah medan yang sepadan dan sebarang ralat penciptaan mencetuskan makluman.
npm install -g @angular/cli@18.0.0 ng new view --minimal --routing --style css --no-standalone --ssr=false
Komponen ProductDelete dalam Delete.component.ts ialah komponen Sudut yang mengendalikan pemadaman produk. Ia memaparkan borang dengan medan baca sahaja yang menunjukkan butiran produk (ID, nama dan harga). Apabila komponen dimulakan, ia mengambil butiran produk menggunakan ID produk daripada laluan. Semasa penyerahan borang, kaedah delete() memanggil ProductService untuk memadamkan produk dan kemudian mengubah hala ke senarai produk. Jika terdapat ralat semasa pemadaman, amaran ditunjukkan.
└─ 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
Komponen ProductDetail memaparkan butiran produk tertentu. Ia mendapatkan semula maklumat produk berdasarkan ID daripada laluan dan menunjukkan ID, nama dan harga produk dalam medan baca sahaja. Komponen ini menyediakan butang "Kembali" dan "Edit" untuk navigasi. Butiran produk diambil dan dipaparkan apabila komponen dimulakan.
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))
Komponen ProductEdit membolehkan pengguna mengedit produk sedia ada. Ia mendapatkan semula butiran produk menggunakan ID produk daripada laluan dan memaparkannya dalam bentuk dengan medan boleh diedit untuk nama dan harga. Semasa penyerahan borang, ia mengemas kini produk melalui ProductService dan menavigasi kembali ke senarai produk. Sebarang ralat semasa mengambil atau mengemas kini ditunjukkan sebagai makluman dan ralat pengesahan dipaparkan di sebelah medan yang berkaitan.
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 { }
Komponen ProductIndex memaparkan senarai produk dalam format jadual. Ia mengambil senarai produk daripada ProductService pada permulaan dan menunjukkan ID, nama dan harga setiap produk, dengan butang tindakan untuk melihat, mengedit dan memadam setiap produk. Ia juga termasuk butang untuk menavigasi ke halaman penciptaan produk.
import { Component } from '@angular/core' @Component({ selector: 'app-root', template: `<router-outlet></router-outlet>` }) export class AppComponent { }
ProductService menggunakan HttpClient Angular untuk melaksanakan permintaan HTTP yang berkaitan untuk pengurusan produk. Ia menyediakan kaedah untuk:
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 melaraskan reka letak dengan menambah ruang di atas bekas dan menjarakkan butang secara mendatar.
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 berfungsi sebagai titik masuk utama untuk aplikasi Sudut, termasuk Bootstrap untuk penggayaan, Font Awesome untuk ikon dan
npm install -g @angular/cli@18.0.0 ng new view --minimal --routing --style css --no-standalone --ssr=false
Buat pangkalan data ujian bernama "contoh" dan laksanakan fail database.sql untuk mengimport jadual dan data.
└─ 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))
Fail ini menyimpan butiran konfigurasi untuk menyambung ke pangkalan data.
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 { }
Fail db.go ini mengkonfigurasi sambungan pangkalan data dengan GORM. Fungsi SetupDatabase memuatkan pembolehubah persekitaran, membina rentetan sambungan MySQL dan memulakan tika GORM, yang disimpan dalam pembolehubah DB global.
import { Component } from '@angular/core' @Component({ selector: 'app-root', template: `<router-outlet></router-outlet>` }) export class AppComponent { }
Fail router.go ini menyediakan penghalaan untuk aplikasi Go menggunakan rangka kerja Gin. Fungsi SetupRouter memulakan penghala Gin dengan perisian tengah CORS untuk membenarkan semua asal. Ia mentakrifkan laluan untuk mengendalikan operasi berkaitan produk di bawah laluan /api/products, setiap satu dipetakan kepada kaedah dalam ProductController. Akhirnya, ia memulakan pelayan 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, })) } }
Fail product.go ini mentakrifkan model Produk untuk digunakan dengan GORM. Ia menentukan struktur Produk dengan tiga medan: Id (kunci utama yang meningkat secara automatik), Nama, Harga.
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 { }
Fail product_controller.go mentakrifkan struct ProductController dengan kaedah untuk mengendalikan operasi CRUD untuk produk dalam aplikasi Go menggunakan rangka kerja Gin.
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) }) } }
Fail main.go ini ialah titik masuk untuk aplikasi Go. Ia mengimport pakej konfigurasi dan penghalaan, kemudian memanggil config.SetupDatabase()untuk memulakan sambungan pangkalan data dan penghala.SetupRouter() untuk menyediakan laluan aplikasi.
Jalankan projek 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) }) } }
Jalankan projek API Go
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) }) } }
Buka pelayar web dan pergi ke http://localhost:4200
Anda akan menemui halaman senarai produk ini.
Klik butang "Lihat" untuk melihat halaman butiran produk.
Klik butang "Edit" untuk mengubah suai produk dan mengemas kini butirannya.
Klik butang "Serah" untuk menyimpan butiran produk yang dikemas kini.
Klik butang "Buat" untuk menambah produk baharu dan masukkan butirannya.
Klik butang "Serah" untuk menyimpan produk baharu.
Klik butang "Padam" untuk mengalih keluar produk yang dibuat sebelum ini.
Klik butang "Padam" untuk mengesahkan penyingkiran produk ini.
Kesimpulannya, kami telah mempelajari cara mencipta projek Sudut asas dengan komponen, pandangan dan penghalaan, sambil menyediakan API menggunakan rangka kerja Gin sebagai bahagian belakang. Dengan menggunakan GORM untuk operasi pangkalan data, kami telah berjaya membina bahagian hadapan dinamik yang disepadukan dengan lancar dengan bahagian belakang yang berkuasa dan cekap. Gabungan ini membentuk asas yang kukuh untuk membangunkan aplikasi web tindanan penuh moden.
Kod sumber: https://github.com/stackpuz/Example-CRUD-Angular-18-Go
Buat Apl CRUD Sudut dalam Minit: https://stackpuz.com
Atas ialah kandungan terperinci Membina Apl CRUD Sudut dengan API Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!