最近转到了研发部门,作为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的具体信息。
至此,一个简单的前后端+数据库的应用已经搭建完毕,以后将继续丰富这个应用的功能