github項目地址javascript
微服務架構圖html
項目描述前端
conf/my.cnf
vue
[mysqld] init_connect='SET collation_connection = utf8_unicode_ci' init_connect='SET NAMES utf8' character-set-server=utf8 collation-server=utf8_unicode_ci skip-character-set-client-handshake skip-name-resolve [client] default-character-set=utf8 [mysql] default-character-set=utf8
啓動容器java
docker run --name mysql3306 -p 3306:3306 -v /var/touchAirMallVolume/mysql/data:/var/lib/mysql -v /var/touchAirMallVolume/mysql/conf/my.cnf:/etc/mysql/my.cnf -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.31
docker run --name mysql -p 3306:3306 --restart=always -v /var/local/mysql/data:/var/lib/mysql -v /var/local/mysql/conf/my.cnf:/etc/mysql/my.cnf -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.31 docker run -p 6379:6379 --name redis --restart=always \ -v /var/local/redis/data:/data \ -v /var/local/redis/conf/redis.conf:/etc/redis/redis.conf \ -d redis redis-server /etc/redis/redis.conf
conf/redis.conf
mysql
啓動容器nginx
docker run -p 6379:6379 --name redis6379 \ -v /var/touchAirMallVolume/redis/data:/data \ -v /var/touchAirMallVolume/redis/conf/redis.conf:/etc/redis/redis.conf \ -d redis redis-server /etc/redis/redis.conf
驗證redisgit
docker exec -it redis6379 redis-cli
默認redis是不持久化的,存在內存中github
修改redis.conf
開啓持久化web
vim /var/touchAirMallVolume/redis/conf/redis.conf #添加如下內容 appendonly yes
重啓redis容器
使用人人開源項目,快速搭建先後端分離項目
renren-fast
、renren-fast-vue
、renren-generator
使用逆向工程,快速生成基本CRUD代碼
Spring Cloud alibaba 爲分佈式應用開發提供了一站式解決方案。它包含開發分佈式應用程序所需的全部組件,使您能夠輕鬆地使用 Spring Cloud 開發應用程序
使用阿里巴巴的 Spring Cloud,你只須要添加一些註釋和少許配置,就能夠將 Spring Cloud 應用程序鏈接到阿里巴巴的分佈式解決方案上,並使用阿里巴巴的中間件構建一個分佈式應用系統
Flow control and service degradation
(流量控制和服務降級)Service registration and discovery
(服務註冊和發現)Distributed Configuration
(分佈式配置)Event-driven
(事件驅動)Message Bus
(消息總線):使用 Spring Cloud Bus RocketMQ 的分佈式系統的連接節點Distributed Transaction
(分佈式事務 Seata)Dubbo RPC
Nacos 致力於幫助您發現、配置和管理微服務,Nacos 提供了一組簡單易用的特性集,幫助您快速實現動態服務發現、服務配置、服務元數據及流量管理
Nacos 幫助您更敏捷和容易地構建、交付和管理微服務平臺。 Nacos 是構建以「服務」爲中心的現代應用架構 (例如微服務範式、雲原生範式) 的服務基礎設施
docker安裝
docker pull nacos/nacos-server docker run --env MODE=standalone --name nacos -d -p 8848:8848 nacos/nacos-server
測試是否安裝成功
瀏覽器輸入:ip:8848/nacos 登陸帳號密碼:nacos nacos
第一步:修改pom.xml文件,引入 Nacos Discovery Starter
<!--nacos 服務註冊與發現--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
第二步:在微服務的yml配置文件中,配置上nacos server的地址,並指定應用名稱
spring: datasource: username: root password: 123456 url: jdbc:mysql://192.168.83.133:3306/touch_air_mall_pms driver-class-name: com.mysql.cj.jdbc.Driver cloud: nacos: discovery: server-addr: 192.168.83.133:8848 application: name: touch-air-mall-product
第三步:在啓動類添加註解 @EnableDiscoveryClient 開啓服務註冊與發現功能
第四步:啓動應用,觀察nacos服務列表是否已註冊進服務中心
注意:每個應用都應該有名字,這樣才能成功註冊進去
注意:項目中部分微服務的 配置文件在nacos中,可自行修改
Fegin是一個聲明式的HTTP客戶端,它的目的就是讓遠程調用更加簡單。Fegin提供了HTTP請求的模板,經過編寫簡單的接口和插入註解,就能夠定義好HTTP請求的參數、格式、地址等信息
Fegin整合了Ribbon(負載均衡)和Hystrix(服務熔斷),可讓咱們再也不須要顯示地使用這兩個組件
SpringCloud Fegin在NetFlix Fegin的基礎上擴展了對SpringMVC註解的支持,在其實現下,咱們只須要建立一個接口並用註解的方式來配置它,便可完成對服務提供方的接口綁定。簡化了SpringCloud Ribbon自選封裝服務調用客戶端的開發量
第一步:引入依賴(對應版本)
<!--openfeign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.3.RELEASE</version> </dependency>
第二步:開啓feign功能
@EnableDiscoveryClient
第三步:聲明遠程接口
測試
正常啓動 用戶服務8000和優惠券服務7000
優惠券服務7000宕機
一、 CouponFeignService.saveSpuBounds(spuBoundTO) 1.一、@RequestBody 將這個對象轉爲json 1.二、找到coupon服務,給 /coupon/spubounds/save 發送請求 將上一步轉的json 放在請求體位置,發送請求 1.三、對方服務收到請求,請求體裏有json數據 @RequestBody SpuBoundsEntity spuBounds:將請求體中的json 轉爲 SpuBoundsEntity 這個類型 二、只有json 數據模型是兼容的,雙方服務無需使用同一個to
兩種不一樣的請求處理
feign 請求的兩種寫法 1. 讓全部請求過網關 1.1 @FeignClient("touch-air-mall-gateway"):給網關服務發請求 1.2 /api/product/skuinfo/info/{skuId} 2. 直接指定具體某個微服務處理 2.1 @FeignClient("touch-air-mall-product"):給商品服務發請求 2.2 /product/skuinfo/info/{skuId}
第一步:引入依賴
<!--nacos 配置中心作配置管理--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
第二步:在應用的 /src/main/resources/bootstrap.properties
配置文件中配置 Nacos Config 元數據
bootstrap.properties
文件內容會優先於 yml
文件被加載
spring.application.name=touch-air-mall-coupon spring.cloud.nacos.config.server-addr=192.168.83.133
觀察啓動類 新增配置的默認ID(默認當前應用的名稱 application name + properties
)
測試
@Value("${coupon.user.name}") private String name; @Value("${coupon.user.age}") private int age; @RequestMapping("/nacos/config") public R testConfig(){ return R.ok().put("name", name).put( "age", age); }
在線修改 nacos 配置中心的配置
必須重啓,再次請求接口
動態獲取 加上註解 @RefreshScope
無需重啓,動態刷新配置
用於進行租戶粒度的配置隔離。不一樣的命名空間下,能夠存在相同的Group或Data ID的配置。NameSpace的經常使用場景之一是不一樣環境的配置的區分隔離,例如開發測試環境和生產環境的資源(如配置、服務)隔離等
public(保留空間):默認新增的全部配置都在public空間
利用命名空間來作環境隔離:開發、測試、生產。注意:在bootstrap.properties中,配置使用哪一個命名空間
每個微服務之間互相隔離配置,每個微服務都建立本身的命名空間,只加載本身命名空間下的全部配置
相似配置文件名
默認全部的配置集都屬於:DEFAULT_GROUP
隨着服務增加,配置文件會愈來愈多,不易於維護。全部一般按類拆分紅多個配置文件
只須要在bootstrap.properties
中說明加載配置中心的哪些配置文件便可
spring.cloud.nacos.config.extension-configs[0].data-id=datasource.yaml spring.cloud.nacos.config.extension-configs[0].group=dev spring.cloud.nacos.config.extension-configs[0].refresh=true spring.cloud.nacos.config.extension-configs[1].data-id=mybatis.yaml spring.cloud.nacos.config.extension-configs[1].group=dev spring.cloud.nacos.config.extension-configs[1].refresh=true spring.cloud.nacos.config.extension-configs[2].data-id=other.yaml spring.cloud.nacos.config.extension-configs[2].group=dev spring.cloud.nacos.config.extension-configs[2].refresh=true
網關做爲流量的入口,經常使用功能包括路由轉發、權限校驗、限流控制等。而SpringCloud gateway做爲SpringCloud官方推出的第二代網關框架,取代了Zuul網關
組件 | RPS(每秒處理請求) |
---|---|
SpringCloud Gateway | 32213.38 |
Zuul | 20800.13 |
Linkerd | 28050.76 |
網關提供API全託管服務,豐富的API管理功能,輔助企業管理大規模的API,以下降管理成本和安全風險,包括協議適配、協議轉發、安全策略、防刷、流量、監控日誌等功能
SpringCloud Gateway 旨在提供一種簡單有效的方式來對API進行路由,併爲他們提供切面,例如:安全性、監控指標和彈性等
網關使用先後對比
web請求,經過一些匹配條件,定位到真正的服務節點。並在這個轉發過程的先後,進行一些精細化控制。perdicate就是咱們的匹配條件。而Filter就能夠理解爲一個無所不能的攔截器,有了這兩個元素,再加上目標uri,就能夠實現一個具體的路由了
Gateway流程:客戶端向Spring Cloud Gateway發出請求。而後在Gateway Handler Mapping 中找到與請求相匹配的路由,將其發送到Gateway Web Handler
Handler再經過指定的過濾器鏈來將請求發送到咱們實際的服務執行業務邏輯,而後返回
過濾器之間用虛線分開是由於過濾器可能會在發送代理請求以前(「pre」)或以後(「post」)執行業務邏輯
Filter在「pre」類型的過濾器能夠作參數校驗、權限校驗、流量監控、日誌輸出、協議轉換等,在「post」類型的過濾器中能夠作響應內容、響應頭的修改,日誌的輸出,流量監控等有很是重要的做用
第一步:引入依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
第二步:編寫配置文件
application.properties
服務名稱和nacos註冊中心地址
spring.cloud.nacos.discovery.server-addr=192.168.83.133:8848 spring.application.name=touch-air-mall-gateway
啓動類添加註解,開啓服務註冊與發現
@EnableDiscoveryClient
bootstrap.properties
#默認加載的配置文件 應用名.properties spring.application.name=touch-air-mall-gateway #配置中心地址 spring.cloud.nacos.config.server-addr=192.168.83.133 #命名空間 spring.cloud.nacos.config.namespace=fa94e939-311c-427a-915a-a6c37bc403ae spring.cloud.nacos.config.extension-configs[0].data-id=touch-air-mall-gateway.yaml spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP spring.cloud.nacos.config.extension-configs[0].refresh=true
nacos配置中心,新增命名空間 touch-air-mall-gateway
,生成的id 對應上面配置文件的namespace
啓動服務,查看狀況
application.yml
,編寫路由規則,詳情參考官方文檔
請求路徑帶參數:url
,而且當值等於 baidu 時,轉發到百度
當值等於 qq 時,轉發到 qq
spring: cloud: gateway: routes: - id: test_route uri: https://www.baidu.com predicates: - Query=url,baidu - id: qq_route uri: https://www.qq.com predicates: - Query=url,qq
重啓
阿里雲官網開通OSS服務
建立bucket
設置子帳戶,得到accessKeyId
和accessKeySecret
並給子帳戶添加權限
1:普通上傳方式
用戶將文件上傳至應用服務器,應用服務器拿到文件流,經過java代碼將文件流數據上傳到文件存儲服務器,流數據通過後臺一層處理,在高併發場景下,安全但性能差
2:服務端簽名後直傳
操做對象存儲的帳號密碼信息仍是存儲在後端服務中
用戶/前端上傳以前先向服務器請求上傳策略,服務器利用阿里雲存儲服務的帳號密碼生成一個防僞的簽名,簽名中包含訪問OSS的受權令牌、以及具體的存儲位置等信息,返回給前端
前端帶着這個防僞的令牌簽名和要上傳的文件,直接上傳到OSS
服務器端加密,前端直傳,須要配置跨域
第一步:商品三級分類實體類CategoryEntity
中添加字段
//建表忽略字段 @TableField(exist = false) private List<CategoryEntity> children;
CategoryServiceImpl
具體實現
Java8
新特性,Stream
流(前提準備)
@Override public List<CategoryEntity> listWithTree() { // 一、查詢出全部分類 List<CategoryEntity> categoryEntities = baseMapper.selectList(null); // 二、組裝成父子的樹形結構 // 2.一、找出全部的一級分類 // 2.二、遞歸查出子類 List<CategoryEntity> level1Menu = categoryEntities.stream().filter(categoryEntity -> categoryEntity.getParentCid() == 0 ).map(menu-> { menu.setChildren(getChildrens(menu, categoryEntities)); return menu; }).sorted((menu1,menu2)->{ return (menu1.getSort()==null?0:menu1.getSort()) - (menu2.getSort()==null?0:menu2.getSort()); }).collect(Collectors.toList()); return level1Menu; } /** * 遞歸查找全部菜單的子菜單 */ public List<CategoryEntity> getChildrens(CategoryEntity root,List<CategoryEntity> all){ List<CategoryEntity> children = all.stream().filter(categoryEntity -> { return categoryEntity.getParentCid().equals(root.getCatId()); }).map(categoryEntity -> { categoryEntity.setChildren(getChildrens(categoryEntity, all)); return categoryEntity; }).sorted((menu1,menu2)->{ return (menu1.getSort()==null?0:menu1.getSort()) - (menu2.getSort()==null?0:menu2.getSort()); }).collect(Collectors.toList()); return children; }
application.yml
文件
spring: cloud: gateway: routes: - id: test_route uri: https://www.baidu.com predicates: - Query=url,baidu - id: qq_route uri: https://www.qq.com predicates: - Query=url,qq - id: admin_route uri: lb://renren-fast predicates: - Path= /api/** filters: - RewritePath= /api/(?<segment>/?.*),/renren-fast/$\{segment}
配置說明
注意是:admin_route
前端項目統一請求都帶有 /api
前綴
lb:renren-fast
:LoadBalance 負載均衡
知足predicates
:http://localhost:9527/api/captcha.jpg ---> http://renren-fast:8080/api/captcha.jpg
可是默認的請求是:http://localhost:8080/renren-fast/captcha.jpg
使用Gateway的Filter 重寫路徑(重寫規則參考官方文檔)
跨域:指的是瀏覽器不能執行其餘網站的腳本。它是由瀏覽器的同源策源形成的,是瀏覽器對javascript
施加的安全限制
同源策略:是指協議、域名、端口都要相同,其中有一個不一樣都會產生跨域
URL | 說明 | 是否容許通訊 |
---|---|---|
http://www.a.com/a.js http://www.a.com/b.js |
同一域名下 | 容許 |
http://www.a.com/ab/a.js http://www.a.com/script/b.js |
同一域名不一樣文件夾下 | 容許 |
http://www.a.com:8000/a.js http://www.a.com/b.js |
同一域名,不一樣端口 | 不容許 |
http://www.a.com/a.js https://www.a.com/b.js |
同一域名不一樣協議 | 不容許 |
http://www.a.com/a.js http://70.32.92.74/b.js |
域名和域名對應ip | 不容許 |
http://www.a.com/a.js http://script.a.com/b.js |
主域相同,子域不一樣 | 不容許 |
http://www.a.com/a.js http://a.com/b.js |
同一域名,不一樣二級域名 | 不容許(cookie這種也不容許訪問) |
http://www.a.com/a.js http://www.a.com/b.js |
不一樣域名 | 不容許 |
非簡單請求(PUT、DELETE)等,須要先發送預檢請求
第一種:使用nginx
部署爲同一域
第二種:配置當次請求容許跨域
MallCorsConfiguration
網關服務添加跨域配置類
@Configuration public class MallCorsConfiguration { @Bean public CorsWebFilter corsWebFilter(){ UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); CorsConfiguration corsConfiguration = new CorsConfiguration(); //跨域配置 corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedOrigin("*"); corsConfiguration.addAllowedMethod("*"); corsConfiguration.setAllowCredentials(true); urlBasedCorsConfigurationSource.registerCorsConfiguration("/**",corsConfiguration); return new CorsWebFilter(urlBasedCorsConfigurationSource); } }
注意:這裏須要註釋掉
renren-fast
中的跨域配置,統一由網關進行配置
數據庫關聯關係圖
數據庫關聯關係圖
File-Settings-Editor-Live Templates
給Bean添加校驗註解:javax.validation.constraints
,並定義本身的message提示
開啓校驗功能@Valid
效果:校驗錯誤之後會有默認的響應
給校驗的bean後緊跟一個BindingResult
,就能夠得到到校驗的結果
每一個方法都這樣作,太麻煩且代碼冗餘
controller
添加註解 @Validated{(AddGroup.class, UpdateGroup.class)}
編寫一個自定義的校驗註解
能夠指定多個不一樣的校驗器,適配不一樣類型的校驗
編寫一個自定義的校驗器
關聯自定義的校驗器和校驗註解
集中處理全部異常
@RestControllerAdvice 等價於 @ControllerAdvice和@ResponseBody 處理全局異常並以json格式返回
x系統錯誤碼和錯誤信息定義類
錯誤碼定義規則爲5位數字
前兩位表示業務場景,最後三位表示錯誤碼
例如:10001 10:通用 001:系統未知異常
維護錯誤碼後須要維護錯誤描述,將他們定義爲枚舉形式
錯誤碼列表:
10:通用
11:商品
12:訂單
13:購物車
14:物流
new
關鍵字建立,由GC
回收UML
元件領域模型中的領域對象。封裝業務邏輯的java
對象,經過調用DAO方法,結合PO、VO進行業務操做。business object:業務對象 主要做用是把業務邏輯封裝爲一個對象。這個對象能夠包括一個或多個對象。好比一個簡歷,有教育經歷、工做經歷、社會關係等等。咱們能夠把教育經歷對應一個PO,工做經歷對應一個PO,社會關係對應一個PO,創建一個簡歷的BO對象去處理簡歷,每一個BO都包含這些PO。這樣處理業務邏輯時,咱們就能夠針對BO去處理sun
的標準j2ee
設計模式,這個模式中有個接口就是DAO,它負責持久層的操做,爲業務層接口。此對象用於訪問數據庫。一般和PO結合使用,DAO中包含了各類數據庫的操做方法。經過它的方法,結合PO對數據庫進行相關的操做,夾在業務邏輯與數據庫資源中間,配合VO,提供數據庫的CRUD操做