Web應用的建立筆記(1)_建立一個簡單的前後端+資料庫的WEB應用
最近轉到了研發部門,作為Product Owner,需要了解一下現在開發企業級應用的一些相關技術,為此把學習的成果記錄下來,也希望有需要的朋友可以作為參考。
這個學習成果將會通過一系列的部落格來記錄下來。我的想法是,實現一個比較全面的WEB應用,這個應用將搭建在AZURE雲平臺,涉及到的相關技術包括了Spring boot, Angular, MySQL, Redis, Cassandra, Keycloak, KONG APIgateway, Docker, Microservice等等。
首先第一篇是先從簡單的WEB應用搭建開始,演示一個簡單的伺服器端從資料庫讀取資料,通過REST API把查詢結果返回給前端。前端採用Angular搭建,把結果呈現給客戶。具體分為以下幾個部分:
1. 資料庫採用mysql搭建
2. 後端採用Springboot搭建,通過REST API提供資料
3. 前端用Angular搭建,通過HTTP來呼叫REST API
資料庫的建立
先用MYSQL建立一個數據庫test,裡面包含一張資料表product
mysql> CREATE DATABASE test; mysql> USE test mysql> CREATE TABLE product (id Serial, name VARCHAR(20), description VARCHAR(512)); mysql> INSERT INTO product (name, description) -> VALUES ('product1','this is a test'); mysql> INSERT INTO product (name, description) -> VALUES ('product2','thisis another test');
後端的建立
在start.spring.io網頁中,建立一個project,依賴關係要輸入web, jpa, mysql
在IDEA裡面開啟剛才建立的project
新建一個product entity, 程式碼如下:
package com.example.demo; import javax.persistence.Entity; import javax.persistence.Table; import javax.persistence.Column; import javax.persistence.Id; @Entity @Table(name="product") public class Product { @Id @Column(name="id") private Long id; @Column(name="name") private String name; @Column(name="description") private String description; public Long getId() { return id; } public void setId(Long id){ this.id = id; } public String getName() { return name; } public void setName(Stringname) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
建立一個數據存取的repository,程式碼如下:
package com.example.demo;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product,Long>{
}
建立一個RestController,用於處理web請求,並把處理結果以JSON的格式返回,程式碼如下:
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.CrossOrigin;
import java.util.List;
@RestController
public class ProductController {
private ProductRepository productRepository;
@Autowired
public ProductController(
ProductRepository productRepository) {
this.productRepository = productRepository;
}
@CrossOrigin(origins ="http://localhost:4200") //這個用於解決跨域訪問的問題
@RequestMapping("/all")
public List allProducts(Model model) {
List<Product>productList =
productRepository.findAll();
return productList;
}
}
Springboot自動建立的Application不用更改,程式碼如下:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static voidmain(String[] args) {
SpringApplication.run(DemoApplication.class,args);
}
}
在application.properties檔案中,增加以下配置資訊:
server.port=9090
spring.datasource.url = jdbc:mysql://localhost:3306/test
spring.datasource.username = root
spring.datasource.password = 123456
spring.datasource.driverClassName = com.mysql.jdbc.Driver
REST API的WEB應用已經搭建好,在IDEA的Maven projects裡面執行clean, install。然後plugin裡面選Springboot:run,在瀏覽器中開啟http://localhost:9090/all即可顯示所有的產品的資訊,以json的格式顯示。
前端的建立
前端採用Angular搭建顯示介面
1. 建立一個Angular專案,在命令列輸入ngnew my-app
2. 在my-app/src/app目錄下,建立一個product的類,代表資料實體。新建一個product.ts的檔案,程式碼如下:
export class Product {
id: number;
name: string;
description: string;
}
3. 建立一個顯示所有product的component,在命令列輸入ng generate component products。
對於新建立的my-app/src/app/products下面的products.component.ts檔案,修改程式碼如下:
import { Component, OnInit } from '@angular/core';
import { Product } from '../product';
import { ProductService } from '../product.service'; //productServic是用於讀取資料的Service
@Component({
selector: 'app-products',
templateUrl:'./products.component.html',
styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {
products: Product[];
constructor(private productService: ProductService) { }
ngOnInit() {
this.getProducts();
}
getProducts(): void {
this.productService.getProducts()
.subscribe(products=> this.products = products); //subscribe是非同步方式,在拿到資料後呼叫callback函式
}
selectedProduct: Product;
onSelect(product: Product):void {
this.selectedProduct = product;
}
}
對於products.component.html,修改如下:
<h2>Products</h2>
<ul class="products">
<li *ngFor="letproduct of products"
[class.selected]="product === selectedProduct"
(click)="onSelect(product)">
<span class="badge">{{product.id}}</span> {{product.name}}
</li>
</ul>
<!—這是顯示product具體資訊的一個component,其中的[product]表示其有一個@input的屬性,是依賴於products component來繫結的-->
<app-product-detail [product]="selectedProduct"></app-product-detail>
4. 建立一個service,用於呼叫RESTAPI,讀取資料。在命令列輸入ng generate service product
在自動建立的my-app/src/app/product.service.ts檔案中,修改程式碼如下:
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Product } from './product';
@Injectable()
export class ProductService {
private productsUrl ='http://localhost:9090/all'; //這是REST API的URL
constructor(private http:HttpClient) { }
getProducts ():Observable<Product[]> {
returnthis.http.get<Product[]>(this.productsUrl)
}
}
5. 建立一個用於顯示具體product資訊的component,在命令列輸入ng generate component product-detail
對my-app/src/app/component/product-detail.component.ts檔案,修改程式碼如下:
import { Component, OnInit, Input } from '@angular/core';
import { Product } from '../product';
@Component({
selector:'app-product-detail',
templateUrl:'./product-detail.component.html',
styleUrls:['./product-detail.component.css']
})
export class ProductDetailComponent implements OnInit {
@Input() product: Product; //表示這個屬性是需要外部輸入的
constructor() { }
ngOnInit() {
}
}
對於my-app/src/app/component/product-detail.component.html檔案,修改程式碼如下:
<div *ngIf="product">
<h2>{{ product.name |uppercase }} Details</h2>
<div><span>id:</span>{{product.id}}</div>
<div>
<label>name:
<input [(ngModel)]="product.name" placeholder="name"/>
</label>
</div>
<div>
<label>description:
<input [(ngModel)]="product.description"placeholder="description"/>
</label>
</div>
</div>
6. 對於my-app/src/app/app.module.ts,需要修改程式碼如下:
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { ProductsComponent } from './products/products.component';
import { ProductDetailComponent } from'./product-detail/product-detail.component';
import { ProductService } from './product.service';
@NgModule({
declarations: [
AppComponent,
ProductsComponent,
ProductDetailComponent
],
imports: [
BrowserModule,
FormsModule,
HttpClientModule
],
providers: [
ProductService
],
bootstrap: [AppComponent]
})
export class AppModule { }
7. 最後在命令列輸入ng serve –open,在瀏覽器開啟http://localhost:4020,即可看到顯示了products列表,如果點選某一個product,在下方會顯示該product的具體資訊。
至此,一個簡單的前後端+資料庫的應用已經搭建完畢,以後將繼續豐富這個應用的功能