第1章-系統設計與工程搭建
第一章節-系統設計與工程搭建
學習目標
- 瞭解需求分析
- 理解系統設計以及restful
- 完成專案前期準備工作 (JDK 與 本地倉庫)
- 完成專案父模組的搭建
- 完成基礎微服務-標籤crud的功能,掌握公共異常類處理
1. 需求分析
1.1 本專案簡介
- 這是一個專屬社交平臺,包括頭條,問答,活動,社交,吐槽,招聘 等六大板塊
1.2 需求規格說明書
在需求規格說明書.doxc
2.系統設計
2.1 系統架構
- 採用前後端分離設計
- 後端使用spring的全家桶實現
- SpringBoot
- SpringCloud
- SpringMVC
- SpringData
2.2 模組劃分
- 本專案共分為18個模組(其中17個是微服務)
- 結構資訊如下
模組名稱 | 模組中文名 |
---|---|
tensquare_common | 公共模組 |
tensquare_article | 文章微服務 |
tensquare_base | 基礎微服務 |
tensquare_friend | 交友微服務 |
tensquare_gathering | 活動微服務 |
tensquare_qa | 問答微服務 |
tensquare_recruit | 招聘微服務 |
tensquare_user | 使用者微服務 |
tensquare_spit | 吐槽微服務 |
tensquare_search | 搜尋微服務 |
tensquare_web | 前臺微服務閘道器 |
tensquare_manager | 後臺為服務閘道器 |
tensquare_eureka | 註冊中心 |
tensquare_config | 配置中心 |
tensquare_sms | 簡訊微服務 |
tensquare_article_crawler | 文章爬蟲微服務 |
tensquare_user_crawler | 使用者爬蟲微服務 |
tensquare_ai | 人工智慧微服務 |
本章我們需要搭建的是
搭建父工程 tensquare-parent、
公共子模組tensquare-common、
基礎微服務 tensquare-base。
2.3 表結構分析
這裡我們採用分庫分表的設計,每個業務模組為一個獨立的資料庫
詳細請看資料庫文件.xlsx
- tensquare_article 文章
- tensquare_base 基礎
- tensquare_friend 交友
- tensquare_gathering 活動
- tensquare_qa 問答
- tensquare_recruit 招聘
- tensquare_user 使用者
- tensquare_spit 吐槽
2.4 API文件
課程提供了前後端開發介面文件(採用Swagger語言進行編寫),並與Ngin進行了整
合。雙擊Nginx執行檔案啟動後,在位址列輸入 http://localhost:801 即可訪問API文件
- 前後端約定的返回碼列表:
狀態描述 | 返回碼 |
---|---|
成功 | 20000 |
失敗 | 20001 |
使用者名稱密碼錯誤 | 20002 |
許可權不足 | 20003 |
遠端呼叫失敗 | 20004 |
重複操作 | 20005 |
2.5 理解RESTFUL
2.5.1 什麼是RestFul
RESTful架構,就是目前最流行的一種網際網路軟體架構。它結構清晰、符合標準、易
於理解、擴充套件方便,所以正得到越來越多網站的採用。REST這個詞,是Roy Thomas
Fielding在他2000年的博士論文中提出的 .
REST 是Representational State Transfer的縮寫,翻譯是”表現層狀態轉化”。 可以
總結為一句話:REST是所有Web應用都應該遵守的架構設計指導原則。
面向資源是REST最明顯的特徵,對於同一個資源的一組不同的操作。資源是伺服器
上一個可命名的抽象概念,資源是以名詞為核心來組織的,首先關注的是名詞。REST要
求,必須通過統一的介面來對資源執行各種操作。對於每個資源只能執行一組有限的操
作。
7個HTTP方法:
GET
、POST
、PUT
、DELETE
、PATCH
、HEAD
、OPTIONS
- GET
安全且冪等
獲取表示
變更時獲取表示(快取)
響應狀態碼 | 含義 |
---|---|
200(OK) | 表示已在響應中發出 |
204(無內容) | 資源有空表示 |
301(Moved Permanently) | 資源的URI已被更新 |
303(See Other) | 其他(如,負載均衡) |
304(not modified) | 資源未更改(快取) |
400 (bad request) | 指代壞請求(如,引數錯誤) |
404 (not found) | 資源不存在 |
406 (not acceptable) | 服務端不支援所需表示 |
500 (internal server error) | 通用錯誤響應 |
503 (Service Unavailable) | 服務端當前無法處理請求 |
- POST
不安全且不冪等
使用服務端管理的(自動產生)的例項號建立資源
建立子資源
北京市昌平區建材城西路金燕龍辦公樓一層 電話:400-618-9090部分更新資源
如果沒有被修改,則不過更新資源(樂觀鎖)
響應狀態碼 | 含義 |
---|---|
200(OK) | -如果現有資源已被更改 |
201(created) | - 如果新資源被建立 |
202(accepted) | - 已接受處理請求但尚未完成(非同步處理) |
301(Moved Permanently) | - 資源的URI被更新 |
303(See Other) | - 其他(如,負載均衡) |
400(bad request) | - 指代壞請求 |
404 (not found) | - 資源不存在 |
406 (not acceptable) | - 服務端不支援所需表示 |
409 (conflict) | - 通用衝突 |
412 (Precondition Failed) | - 前置條件失敗(如執行條件更新時的衝突) |
415 (unsupported media type) | - 接受到的表示不受支援 |
500 (internal server error) | - 通用錯誤響應 |
503 (Service Unavailable) | - 服務當前無法處理請求 |
- PUT
不安全但冪等
用客戶端管理的例項號建立一個資源
通過替換的方式更新資源
如果未被修改,則更新資源(樂觀鎖)
響應狀態碼 | 含義 |
---|---|
200 (OK) | – 如果已存在資源被更改 |
201 (created) | – 如果新資源被建立 |
301(Moved Permanently) | – 資源的URI已更改 |
303 (See Other) | – 其他(如,負載均衡) |
400 (bad request) | – 指代壞請求 |
404 (not found) | – 資源不存在 |
406 (not acceptable)- 服務端不支援所需表示
409 (conflict)|-- 通用衝突
412 (Precondition Failed)|-- 前置條件失敗(如執行條件更新時的衝突)
415 (unsupported media type)|-- 接受到的表示不受支援
500 (internal server error)|-- 通用錯誤響應
503 (Service Unavailable)|-- 服務當前無法處理請求
- DELETE
不安全但冪等
刪除資源
響應狀態碼 | 含義 |
---|---|
200 (OK) | - 資源已被刪除 |
301 (Moved Permanently) | - 資源的URI已更改 |
303 (See Other) | - 其他,如負載均衡 |
400 (bad request) | - 指代壞請求 |
404 (not found) | - 資源不存在 |
409 (conflict) | - 通用衝突 |
500 (internal server error) | - 通用錯誤響應 |
503 (Service Unavailable) | - 服務端當前無法處理請求 |
3.專案前期準備
3.1 開發環境
本課程所環境都是基於Docker的,所以需要一個centos7的linux並且安裝docker,記憶體建議最小4G以上
- JDK1.8
- 資料庫mysql 5.7
- 開發工具 idea 2017.1.2
- maven版本3.3.9
- docker 最新版本
- centos7
- VMware Workstation Pro 12
3.2 MySql 建庫建表
使用docker環境建立
- (1) 下載映象
docker pull centos/mysql-57-centos7
- (2) 建立容器
docker run -di --name=tensquare_mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1230 centos/mysql-57-centos7
- (3) SQLyog 連線,並執行建立表語句
3.3 測試工具Postman
Postman中文版是postman這款強大網頁除錯工具的windows客戶端,提供功能強大的
Web API & HTTP 請求除錯。軟體功能非常強大,介面簡潔明晰、操作方便快捷,設計得
很人性化。Postman中文版能夠傳送任何型別的HTTP 請求 (GET, HEAD, POST, PUT…),
附帶任何數量的引數
- (1) 預設安裝
- (2) 註冊賬號
- (3) 使用註冊賬號登入
4. 工程搭建
4.1 父工程搭建
- (1) 新建Maven工程
- (2) 填寫GroupId 和 Artifacetld
- (3) 選擇儲存位置,完成建立
- (4) 刪除src目錄
- (5) 修改基礎pom.xml檔案 增加如下配置
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.12</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
- (6) 你可以啟用Enable Auto-Import 自動匯入依賴(修改了pom檔案idea右下角會提示)
4.2 搭建公共子模組
4.2.1 建立 搭建公共子模組 tensquare-common
略
4.2.2 建立返回結果實體類
- (1) 新建entity包,包下建立類Result,用於控制器類返回結果
如果需要用idea生成getset
alt + insert
package entity;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@NoArgsConstructor
@Accessors(chain = true)
@Builder
public class Result {
private boolean flag;//是否成功
private Integer code;// 返回碼
private String message;//返回資訊
private Object data;// 返回資料
public Result(boolean flag, Integer code, String message) {
this.flag = flag;
this.code = code;
this.message = message;
}
public Result(boolean flag, Integer code, String message, Object data) {
this.flag = flag;
this.code = code;
this.message = message;
this.data = data;
}
/**
* 成功返回實體
* @param message
* @return
*/
public static Result success(String message) {
return new Result(true,StatusCode.OK,message);
}
/**
* 成功返回實體
* @param message
* @param data
* @return
*/
public static Result success(String message,Object data) {
return new Result(true,StatusCode.OK,message,data);
}
/**
* 失敗返回實體
* @param code
* @param message
* @return
*/
public static Result fail(Integer code,String message) {
return new Result(false,code,message);
}
/**
* 失敗返回實體
* @param code
* @param message
* @param object
* @return
*/
public static Result fail(Integer code,String message,Object object) {
return new Result(true,code,message,object);
}
}
- (2) 建立類PageResult ,用於返回分頁結果
package entity;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 分頁的結果類
*
* @param <T>
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
@Builder
public class PageResult<T> {
private Long total;
private List<T> rows;
public PageResult(Long total, List<T> rows) {
super();
this.total = total;
this.rows = rows;
}
}
4.2.3 返回碼定義類
package entity;
/**
* 狀態碼實體類
*/
public class StatusCode {
public static final int OK = 20000;//成功
public static final int ERROR = 20001;//失敗
public static final int LOGIN_ERROR = 20002;//使用者名稱或密碼錯誤
public static final int ACCESS_ERROR = 20003;//許可權不足
public static final int REMOTE_ERROR = 20004;//遠端呼叫失敗
public static final int REP_ERROR = 20005;//重複操作
}
4.2.4 分散式ID生成器
由於我們的資料庫在生產環境中要分片部署(MyCat),所以我們不能使用資料庫本
身的自增功能來產生主鍵值,只能由程式來生成唯一的主鍵值。我們採用的是開源的
twitter( 非官方中文慣稱:推特.是國外的一個網站,是一個社交網路及微部落格服務) 的
snowflake (雪花)演算法。
snowflake 共有64bit組成
- 1 bit: 不用 (1)
- 41 bit : 時間戳 (2-42)
- 10 bit : 工作機器ID (41-52)
- 12 bit : 序列號 (52-64)
預設情況下41bit的時間戳可以支援該演算法使用到2082年,10bit的工作機器id可以
支援1024臺機器,序列號支援1毫秒產生4096個自增序列id . SnowFlake的優點是,整
體上按照時間自增排序,並且整個分散式系統內不會產生ID碰撞(由資料中心ID和機器ID
作區分),並且效率較高,經測試,SnowFlake每秒能夠產生26萬ID左右
我們課程中已經提供了分散式ID生成器.
tensquare-common 工程建立util包,將IdWorker.java 直接拷貝到 tensquare-common
工程的util包中。
5.基礎微服務-標籤CRUD
5.1 模組搭建
(1) 搭建基礎微服務模組 tensquare-base
, pom.xml引入依賴
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.tensquare</groupId>
<artifactId>tensquare-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
(2) 建立啟動類
tips : IDEA建立main方法的快捷鍵是 psvm
package com.tensquare.base;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import util.IdWorker;
/**
* 啟動類
*/
@EnableAspectJAutoProxy
@EnableAutoConfiguration
@SpringBootApplication
public class BaseApplication {
public static void main(String[] args) {
SpringApplication.run(BaseApplication.class);
}
@Bean
public IdWorker idWorker() {
return new IdWorker(1, 1);
}
}
(3) 在resources 下建立application.yml
server:
port: 9001
spring:
application:
name: tensquare-base
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/tensquare_base?characterEncoding=utf-8
username: root
password: 1230
# jpa 相關配置
jpa:
database: mysql
show-sql: true
generate-ddl: true
5.2 標籤管理-CRUD
5.2.1 表結構分析
表名稱:tb_label
欄位名 | 欄位含義 | 欄位型別 | 備註 |
---|---|---|---|
id | ID | 文字 | |
labelname | 標籤名稱 | 文字 | |
state | 狀態 | 文字 | 0:無效 1:有效 |
count | 使用數量 | 整型 | |
fans | 關注數 | 整型 | |
recommend | 是否推薦 | 文字 | 0:不推薦 1:推薦 |
5.2.2 CRUD實現
- (1) 實體類(entity)
com.tensquare.base.pojo 包下建立
Label
package com.tensquare.base.pojo;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Data
@Entity
@Table(name="tb_label")
public class Label {
@Id
private String id;//
private String labelname;//標籤名稱
private String state;//狀態
private Long count;//使用數量
private Long fans;//關注數
private String recommend;//是否推薦
}
- (2) 建立資料訪問介面(dao)
package com.tensquare.base.dao;
import com.tensquare.base.pojo.Label;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* 標籤資料訪問介面
* JpaRepository提供了基本的增刪改查
* JpaSpecificationExecutor用於做複雜的條件查詢
*/
public interface LabelDao
extends JpaRepository<Label,String>,
JpaSpecificationExecutor<Label> {
}
- (3) 業務邏輯類(service)
com.tensquare.base.service 包下建立
LabelService
package com.tensquare.base.service;
import com.tensquare.base.dao.LabelDao;
import com.tensquare.base.pojo.Label;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype