1. 程式人生 > >Web應用的建立筆記(1)_建立一個簡單的前後端+資料庫的WEB應用

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的具體資訊。


至此,一個簡單的前後端+資料庫的應用已經搭建完畢,以後將繼續豐富這個應用的功能