日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

5w 字 | 172 图 | 超级赛亚级 Spring Cloud 实战

發布時間:2023/12/20 javascript 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 5w 字 | 172 图 | 超级赛亚级 Spring Cloud 实战 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊上方?好好學java?,選擇?星標?公眾號

重磅資訊、干貨,第一時間送達

今日推薦:硬剛一周,3W字總結,一年的經驗告訴你如何準備校招!

個人原創100W+訪問量博客:點擊前往,查看更多

一、PassJava 項目簡介

  • PassJava 是一款 Java 面試刷題 的開源系統,可以用零碎時間利用小程序查看常見面試題,夯實 Java 基礎。

  • PassJava 項目可以教會你如何搭建 SpringBoot 項目,Spring Cloud 項目

  • 采用流行的技術,如 SpringBoot、MyBatis、Redis、 MySql、 MongoDB、 RabbitMQ、Elasticsearch,采用 Docker 容器化部署。

項目地址

  • [后臺平臺] https://github.com/Jackson0714/PassJava-Platform

  • [后臺管理] https://github.com/Jackson0714/PassJava-Portal

  • [學習教程] https://github.com/Jackson0714/PassJava-Learning

項目演示

  • 后臺管理系統

添加題目管理菜單
  • 小程序

PassJava 中使用的技術

SpringBoot、MyBatis、Redis、 MySql、 MongoDB、 RabbitMQ、Elasticsearch

PassJava 實現的功能概覽

PassJava 數據庫表概覽

數據庫表前綴說明

  • ums_*:會員模塊相關表

  • cms_*:內容管理模塊相關表

  • qms_*:題目模塊相關表

  • chms_*:渠道模塊相關表

  • sms_*:學習模塊相關表

二、項目微服務架構圖

微服務架構圖

三、項目前置要求

由于 PassJava 項目涉及到很多知識點,希望大家先補下功課,推薦的書籍如下。

推薦資料

IDEA

《IntelliJ-IDEA-Tutorial》:https://github.com/judasn/IntelliJ-IDEA-Tutorial

Spring

《Spring 實戰(第 4 版)》:https://book.douban.com/subject/26767354/

SpringBoot

《Spring Boot 實戰》:https://book.douban.com/subject/26857423/

MyBatis

《MyBatis 從入門到精通》:https://book.douban.com/subject/27074809/

MySql

《深入淺出 MySQL》:https://book.douban.com/subject/25817684/

Linux

《循序漸進 Linux(第 2 版)》:https://book.douban.com/subject/26758194/

Elasticsearch

《Elasticsearch 權威指南》:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html

《Elasticsearch 技術解析與實戰》:https://book.douban.com/subject/26967826/

Mongodb

《MongoDB 實戰 (第二版)》:https://book.douban.com/subject/27061123/

Docker

《Spring Cloud 與 Docker 微服務架構實戰》:https://book.douban.com/subject/27028228/

四、環境搭建篇

4.1 Vagrant 快速搭建 Ubuntu 虛擬機環境

1. 開啟虛擬機服務

Windows 啟動配置:Intel Virtualization Technology -> Enabled

2. 下載安裝 VirtualBox

VirtualBox:虛擬機管理軟件

https://www.virtualbox.org/wiki/Downloads

3. 下載安裝 Vagrant

Vagrant:創建和管理虛擬機

Vagrant 軟件:https://www.vagrantup.com/downloads.html

Vagrant 官方鏡像:https://app.vagrantup.com/boxes/search

  • check 是否安裝好了 vagrant

命令行輸入 vagrant

vagrant

4. 安裝 vagrant ubuntu 國內鏡像

#?ubuntu?18.04?LTS: vagrant?box?add?https://mirrors.tuna.tsinghua.edu.cn/ubuntu-cloud-images/bionic/current/bionic-server-cloudimg-amd64-vagrant.box?--name?ubuntu18# ubunt 16.04 LTS: vagrant?box?add?https://mirrors.tuna.tsinghua.edu.cn/ubuntu-cloud-images/xenial/current/xenial-server-cloudimg-amd64-vagrant.box?--name?ubuntu16# ubuntu14: vagrant?box?add?https://mirrors.tuna.tsinghua.edu.cn/ubuntu-cloud-images/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box?--name?ubuntu14

安裝 ubuntu 18

vagrant?box?add?https://mirrors.tuna.tsinghua.edu.cn/ubuntu-cloud-images/bionic/current/bionic-server-cloudimg-amd64-vagrant.box?--name?ubuntu18

  • 創建 vagrant 配置文件

vagrant?init
  • 打開 C:\Users\Administrator\Vagrantfile 文件

config.vm.box = "base" 修改為 config.vm.box = "ubuntu18"

5. 啟動虛擬機

vagrant?up

6. 連接虛擬機

vagrant?ssh

7. 配置密碼登錄

  • 配置密碼登錄 vagrant

Vagrant?ssh?進入系統之后 sudo?su 編輯?sshd_config vi?/etc/ssh/sshd_config PasswordAuthentication?no?改為?PasswordAuthentication?yes PermitRootLogin?prohibit-password?改為?PermitRootLogin?yes 重啟服務 service?sshd?restart
  • 安裝 XShell 工具和 XFTP 工具

  • XShell 連接虛擬機

    賬號:root

    密碼:vagrant

連接成功

4.2 配置虛擬機網絡

1.查看VirtualBox Host-Only Network

本地VirtualBox 網絡地址 192.168.56.1,則修改虛擬機IP地址為同一個網段下,比如192.168.56.10

2.配置虛擬機IP地址

打開Vagrant 配置文件 C:\Users\Administrator\Vagrantfile

# config.vm.network "private_network", ip: "192.168.33.10" 修改為 config.vm.network "private_network", ip: "192.168.56.10"

3.重新加載虛擬機

vagrant?reload

4.查看虛擬機IP地址

虛擬機IP地址:192.168.56.10,和配置文件中的一致

5.測試本機是否可以ping通虛擬機

ping 192.168.56.10,可以ping通

6.測試虛擬機是否可以ping通本機

ping 192.168.10.160,可以ping通

4.3 安裝docker

https://docs.docker.com/engine/install/ubuntu/

1.卸載老版本docker

sudo?apt-get?remove?docker?docker-engine?docker.io?containerd?runc

2.設置倉庫

//?命令1 $?sudo?apt-get?install?\apt-transport-https?\ca-certificates?\curl?\gnupg-agent?\software-properties-common //?命令2 curl?-fsSL?https://download.docker.com/linux/ubuntu/gpg?|?sudo?apt-key?add?-//?命令3 sudo?apt-key?fingerprint?0EBFCD88//?命令4 sudo?add-apt-repository?\"deb?[arch=amd64]?https://download.docker.com/linux/ubuntu?\$(lsb_release?-cs)?\stable"

3.安裝docker

sudo?apt-get?update sudo?apt-get?install?docker-ce?docker-ce-cli?containerd.io

4.測試安裝成功

sudo?docker?run?hello-world

5.設置開機自啟動

sudo systemctl enable docker

6.配置鏡像加速

https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors

sudo?mkdir?-p?/etc/docker sudo?tee?/etc/docker/daemon.json?<<-'EOF' {"registry-mirrors":?["您的專屬加速器地址"] } EOF sudo?systemctl?daemon-reload sudo?systemctl?restart?docker

7. 免sudo使用docker命令

當以普通用戶身份去使用docker images時,出現以下錯誤:

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.26/images/json: dial unix /var/run/docker.sock: connect: permission denied 可以看都,最后告知我們時權限的問題。那么在linux文件權限有三個數據左右drwxrwxrwx,

img

其中第一為d代表該文件是一個文件夾 前三位、中三位、后三位分別代表這屬主權限、屬組權限、其他人權限。如圖,其中 第三列、第四列分別代表文件的屬主、屬組。

上圖是報錯文件的權限展示,可以看到其屬主為root,權限為rw,可讀可寫;其屬組為docker,權限為rw,可讀可寫。如果要當前用戶可直接讀取該文件,那么我們就為當前用戶添加到docker屬組即可。

如果還沒有 docker group 就添加一個:

sudo?groupadd?docker將用戶加入該 group 內。然后退出并重新登錄就生效啦。 sudo?gpasswd?-a?${USER}?docker重啟?docker?服務 sudo?service?docker?restart切換當前會話到新?group?或者重啟?X?會話 newgrp?-?docker注意:最后一步是必須的,否則因為 groups 命令獲取到的是緩存的組信息,剛添加的組信息未能生效,所以 docker images 執行時同樣有錯。

8. apt-get update更新慢

Ubantu 18.04 apt-get update 無法更新,更新慢的問題 https://blog.csdn.net/stopping5/article/details/80493643

sudo?cp?/etc/apt/sources.list?/etc/apt/sources.list.old sudo?vim?/etc/apt/sources.list 替換成阿里源#阿里源: deb?http://mirrors.aliyun.com/ubuntu/?trusty?main?restricted?universe?multiverse deb?http://mirrors.aliyun.com/ubuntu/?trusty-security?main?restricted?universe?multiverse deb?http://mirrors.aliyun.com/ubuntu/?trusty-updates?main?restricted?universe?multiverse deb?http://mirrors.aliyun.com/ubuntu/?trusty-proposed?main?restricted?universe?multiverse deb?http://mirrors.aliyun.com/ubuntu/?trusty-backports?main?restricted?universe?multiverse deb-src?http://mirrors.aliyun.com/ubuntu/?trusty?main?restricted?universe?multiverse deb-src?http://mirrors.aliyun.com/ubuntu/?trusty-security?main?restricted?universe?multiverse deb-src?http://mirrors.aliyun.com/ubuntu/?trusty-updates?main?restricted?universe?multiverse deb-src?http://mirrors.aliyun.com/ubuntu/?trusty-proposed?main?restricted?universe?multiverse deb-src?http://mirrors.aliyun.com/ubuntu/?trusty-backports?main?restricted?universe?multiverse

其他命令

docker update redis --restart=always 虛擬機重啟后,redis自動啟動

docker update mysql --restart=always 虛擬機重啟后,mysql自動啟動

4.4 docker 安裝mysql

1.下載鏡像

sudo?docker?pull?mysql:5.7 ubuntu@VM-0-13-ubuntu:~$?sudo?docker?pull?mysql:5.7 5.7:?Pulling?from?library/mysql c499e6d256d6:?Pull?complete? 22c4cdf4ea75:?Pull?complete? 6ff5091a5a30:?Pull?complete? 2fd3d1af9403:?Pull?complete? 0d9d26127d1d:?Pull?complete? 54a67d4e7579:?Pull?complete? fe989230d866:?Pull?complete? 466a91a95e2f:?Pull?complete? 3e4554c238f1:?Pull?complete? 603b48ead88c:?Pull?complete? 1e86a9aa7171:?Pull?complete? Digest:?sha256:fbaeced79cfdae5d3c8d4a8c41e883f254f72ed7428c6b93a498824b76d97121 Status:?Downloaded?newer?image?for?mysql:5.7 docker.io/library/mysql:5.7

2.查看下載的鏡像

sudo?docker?images

3.創建mysql實例并啟動

  • 創建mysql實例并啟動

sudo?docker?run?-p?3306:3306?--name?mysql?\ -v?/mydata/mysql/log:/var/log/mysql?\ -v?/mydata/mysql/data:/var/lib/mysql?\ -v?/mydata/mysql/conf:/etc/mysql?\ -e?MYSQL_ROOT_PASSWORD=root?\ -d?mysql:5.7 參數說明 -p?3306:3306?將容器的3306端口映射到主機 -v?/mydata/mysql/log:/var/log/mysql\?將日志文件掛載到主機 -v?/mydata/mysql/data:/var/lib/mysql\?將數據文件掛載到主機 -v?/mydata/mysql/conf:/etc/mysql\?將配置文件掛載到主機

  • 查看docker容器

    mysql容器已啟動

4.連接數據庫

  • 用Workbench連接數據庫

  • 查看數據庫

5.進入mysql 容器

sudo?docker?exec?-it?mysql?/bin/bash

6.查看虛擬機映射文件

cd?/mydata/mysql ls

7.修改mysql賬號密碼

1.進入mysql容器 docker?exec?-it?mysql?/bin/bash2.登錄mysql mysql?-u?root?-p 輸入密碼:root3.切換數據庫 use?mysql4.查詢root用戶 select?*?from?user?where?user?=?root;5.修改密碼 update?user?set?authentication_string?=?password('新的密碼'),?password_expired?=?'N',?password_last_changed?=?now()?where?user?=?'root';6.這條命令暫不清楚 update?user?set?plugin="mysql_native_password";7.刷新權限 flush?privileges;8.退出 quit;9.重新登錄 mysql?-u?root?-p?輸入新的密碼,登錄成功

8.其他命令

  • 設置容器在機器重啟后自動啟動

docker?update?84c?--restart=always

4.5 docker安裝redis

1.下載鏡像

  • 下載鏡像

sudo?docker?pull?redis ubuntu@VM-0-13-ubuntu:~$?sudo?docker?pull?redis Using?default?tag:?latest latest:?Pulling?from?library/redis c499e6d256d6:?Already?exists? bf1bc8a5a7e4:?Pull?complete? 7564fb795604:?Pull?complete? ec6e86f783e4:?Pull?complete? 1371d6223f46:?Pull?complete? 021fd554320f:?Pull?complete? Digest:?sha256:a732b1359e338a539c25346a50bf0a501120c41dc248d868e546b33e32bf4fe4 Status:?Downloaded?newer?image?for?redis:latest docker.io/library/redis:latest
  • 查看下載的鏡像

sudo?docker?images

2.啟動redis

  • 創建redis.conf 配置文件

sudo?mkdir?-p?/mydata/redis/conf sudo?touch?/mydata/redis/conf/redis.conf
  • 啟動redis

sudo?docker?run?-p?6379:6379?--name?redis?-v?/mydata/redis/data:/data?\ -v?/mydata/redis/conf/redis.conf:/etc/redis/redis.conf?\ -d?redis?redis-server?/etc/redis/redis.conf

3.連接redis

sudo?docker?exec?-it?redis?redis-cli

4.測試redis

設置a=100,返回OK

set?a?100

獲取a的值,返回"100"

get?a

5.設置redis持久化存儲

  • 修改虛擬機映射的redis配置文件

修改配置文件: sudo?vim??/mydata/redis/conf/redis.conf 添加配置: appendonly?yes
  • 檢查是否生效

重啟redis容器: docker?restart?redis 設置a=200,返回OK set?a?200 獲取a的值,返回"200" get?a 重啟redis容器 sudo?docker?restart?redis 重新連接redis容器 sudo?docker?exec?-it?redis?redis-cli 獲取a的值 get?a,返回"200"

6.安裝redis可視化工具

  • 安裝redis可視化工具

    redis-desktop-manager

  • 連接redis

  • 查看redis數據庫

4.6 本地開發環境配置

1. 本地環境安裝Java

我本地環境的java版本 1.8.0_131

java?-version

java安裝和環境變量配置:https://www.cnblogs.com/jackson0714/p/6591942.html

2.本地環境配置Maven

(1)下載Maven,拷貝文件夾到C盤

C:\apache-maven-3.6.2

(2)添加到環境變量

cmder里面 執行命令 mvn -v

如果報錯命令不存在,則重新啟動cmder

(3)設置Maven代理

阿里云代理 https://maven.aliyun.com/mvn/view

點擊使用指南,拷貝配置指南

<mirror><id>aliyunmaven</id><mirrorOf>*</mirrorOf><name>阿里云公共倉庫</name><url>https://maven.aliyun.com/repository/public</url> </mirror>

(4)配置jdk1.8編譯項目

<profiles><profile><id>jdk-1.8</id><activation><activeByDefault>true</activeByDefault><jdk>1.8</jdk></activation><properties><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion></properties></profile> <profiles>

3.IDEA Maven構建工具配置

  • Maven配置

Maven配置
  • 字符集配置

字符集配置

4. IDEA 安裝Lombok插件

Lombok:簡化JavaBean的開發

5. IDEA 安裝mybatisx 插件

mybatisx:mybatis plus開發的一個插件,從mapper方法快速定位到xml文件

6.安裝VSCode

https://code.visualstudio.com/

7.添加VSCode插件

  • Auto Close Tag 自動加上關閉標簽

  • Auto Rename Tag 自動命名配對標簽

  • Chinese 中文簡體包

  • ESLint 語法檢查

  • HTML CSS Support 幫助CSS開發

  • HTML Snippets 幫忙HTML開發

  • JavaScript (ES6) 幫助JavaScript開發

  • Liver Server 啟動一個本地服務

  • open in browser 用瀏覽器打開文件

  • Vetur ?幫助Vue開發

  • minapp 幫助小程序開發

問題

1.新項目導入main1,main2

刪除main1.iml,main2.iml

4.7 配置Git

1.配置git 用戶名和郵箱

git?config?--global?user.name?"jackson0714" git?config?--global?user.email?"jackson0585@163.com"

2.生成ssh key

ssh-keygen?-t?rsa?-b?4096?-C?"jackson0585@163.com"

3.設置ssh key

  • 打開文件

C:\Users\Administrator.ssh\id_rsa.pub

  • 拷貝里面的內容

  • 打開這個鏈接

https://github.com/settings/ssh/new

  • 粘貼已拷貝的內容

  • 保存ssh key

4.遇到的問題

如果遇到Fatal: HttpRequestException encountered問題

則下載這個安裝包解決:

Git Credential Manager for Windows v1.20

鏈接:https://github.com/Microsoft/Git-Credential-Manager-for-Windows/releases/

git每次提交都需要輸入用戶名和密碼

解決辦法:git config --global credential.helper store

下次提交輸入用戶名和密碼后就會記住了

5.讓一個項目同時提交到碼云和GitHub兩個倉庫

在項目目錄里找到.git文件夾然后找到config文件。

打開這個文件后找到下面的代碼

[remote?"origin"]url?=?git提交地址fetch?=?+refs/heads/*:refs/remotes/origin/*

將其改成

[remote?"origin"]url?=?碼云Git提交地址url?=?GitHub提交地址fetch?=?+refs/heads/*:refs/remotes/origin/*

問題:

c731c6f..69bae9b ?master -> master To https://gitee.com/jayh2018/passjava-portal.git ! [rejected] ? ? ? ?master -> master (fetch first) error: failed to push some refs to 'https://gitee.com/jayh2018/passjava-portal.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.

4.8 Windows安裝mysql

1.安裝截圖

2.遇到的問題 1

windows用syslog連接本地mysql數據庫,提示 plugin caching_sha2_password

解決方案:

ALTER?USER?'root'@'%'?IDENTIFIED?WITH?mysql_native_password?BY?'123';

2.遇到的問題 2

Host is not allowed to connect to this MySQL server

使用遠程連接mysql的時候碰到這樣的錯誤:

Host is not allowed to connect to this MySQL server。

簡單的解決方式如下:

(1)修改表。可能是你的帳號不允許從遠程登陸,只能在localhost。這個時候只要在localhost的那臺電腦,登入mysql后,更改 "mysql" 數據庫里的 "user" 表里的 "host" 項,從"localhost"改稱"%"

mysql -u root -p

按照提示輸入密碼

mysql>use mysql;

mysql>update user set host = '%' where user = 'root';

(2)修改完后執行如下SQL命令

flush privileges

五、PassJava 基礎實踐篇

5.1 初始化項目和添加微服務

1.GitHub上創建一個空的倉庫

2.從GitHub上引入空的項目

3.添加內容服務

passjava-content

序號字段內容
1groupcom.jackson0714.passjava
2Artifactpassjava-content
3Namepassjava-content
4Description佳必過-內容服務
5Packagecom.jackson0714.passjava.content

  • 添加依賴組件SpringWeb, OpenFeign

3.添加其他微服務

序號服務描述服務名
1內容微服務passjava-content
2會員微服務passjava-member
3題目微服務passjava-question
4學習微服務passjava-study
5渠道微服務passjava-channel

4.PassJava-Platform添加Pom.xml文件

<?xml?version="1.0"?encoding="UTF-8"?> <project?xmlns="http://maven.apache.org/POM/4.0.0"?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.jackson0714.passjava</groupId><artifactId>passjava</artifactId><version>0.0.1-SNAPSHOT</version><name>passjava</name><description>佳必過-聚合服務</description><packaging>pom</packaging><modules><module>passjava-content</module><module>passjava-member</module><module>passjava-question</module><module>passjava-study</module><module>passjava-channel</module></modules> </project>

5.添加根目錄Maven 配置

Maven操作根項目就可以了,試下clean

6. 配置.gitignore文件

提交代碼時,忽略某些文件

###?gradle?### .gradle /build/ !gradle/wrapper/gradle-wrapper.jar###?STS?### .settings/ .apt_generated .classpath .factorypath .project .settings .springBeans bin/###?IntelliJ?IDEA?### .idea *.iws *.iml *.ipr rebel.xml###?NetBeans?### nbproject/private/ build/ nbbuild/ dist/ nbdist/ .nb-gradle/###?maven?### target/ *.war *.ear *.zip *.tar *.tar.gz **/mvnw **/mvnw.cmd **/.mvn###?logs?#### /logs/ *.log###?temp?ignore?### *.cache *.diff *.patch *.tmp *.java~ *.properties~ *.xml~###?system?ignore?### .DS_Store Thumbs.db Servers .metadata upload gen_code###?database?###db/db_back_dir/###?redis?### /redis/

刪除子項目的.gitignore文件

7.提交代碼

可以用IDEA的git工具提交,也可以用git bash命令行提交

git?add?. git?commit?-m?'xxx' git?push?origin?master

5.2 初始化數據庫和表

用PowerDisigner工具創建數據庫

  • 用PowerDisigner工具創建數據庫

用PowerDisigner工具創建數據庫

總共有5個微服務數據庫:內容、學習、渠道、用戶、題目

5個數據庫
  • 內容微服務的數據庫

內容微服務的數據庫 學習微服務的數據庫 渠道微服務的數據庫 用戶微服務的數據庫
  • 學習微服務的數據庫

  • 渠道微服務的數據庫

  • 用戶微服務的數據庫

  • 題目微服務的數據庫

題目微服務的數據庫

SQL文件在這個項目里面:https://github.com/Jackson0714/PassJava-Platform.git

SQL文件

5.3 搭建管理后臺

管理后臺使用人人開源的后臺管理框架,完成快速搭建。

1.下載人人開源后臺管理框架

  • renren-fast

https://gitee.com/renrenio/renren-fast.git

  • renren-fast-vue

https://gitee.com/renrenio/renren-fast-vue.git

2.添加人人開源后端代碼

PassJava項目

拷貝文件夾renren-fast到PassJava根目錄

POM文件 添加依賴

<module>renren-fast</module>

3.初始化后臺管理數據庫

  • 創建數據庫:passjava_admin

  • 執行renren-fast/db/mysql.sql腳本

4.修改renren-fast 服務的配置文件

文件路徑:src/main/resources/application-dev.yml

  • 修改數據庫連接為自己的mysql數據庫連接

5.啟動renren-fast服務

  • 配置SDK為1.8

-

  • 運行renren-fast后臺

出現錯誤:com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large...

解決方案:修改mysql容器的配置文件

cd?/mydata/mysql/conf sudo?vim?my.cnf添加配置,[mysqld_safe]如果有,則不需要添加 [mysqld_safe] max_allowed_packet=32M
  • 執行結果

  • 測試服務運行狀態

    瀏覽器輸入:http://localhost:8080/renren-fast/

    顯示結果:

    {"msg":"invalid?token","code":401}

    結果如上所示,則表示服務運行正常。另外結果里面的invalid token說明權限不足,不是指服務不正常。

6.啟動前端項目

  • 配置cnpm

    npm?install?-g?cnpm?--registry=https://registry.npm.taobao.org
  • 安裝node_modules依賴包

    cnpm?install
  • 打包前端項目

    npm?run?dev
  • 瀏覽后臺

    http://localhost:8002

7.前后端聯調登錄

  • 登錄后臺

    賬號:admin

    密碼:admin

    登錄成功

  • 查看后端服務日志

說明前端登錄請求發送到了后端服務,并驗證了用戶名和密碼是否正確。

5.4 自動生成前后端代碼

1.下載代碼生成器框架

git?clone?https://gitee.com/renrenio/renren-generator.git

2.添加人人開源后端代碼

PassJava項目

拷貝文件夾renren-fast到PassJava根目錄

POM文件 添加依賴

<module>renren-generator</module>

3.修改renren-generator服務的配置文件

(1)修改數據庫鏈接 src/main/resources/application-dev.yml

  • 修改數據庫連接為自己的mysql數據庫連接

  • 數據庫名改為要生成代碼的服務,如passjava_qms數據庫

    url:?jdbc:mysql://129.211.188.xxx:3306/passjava_qms?useUnicode=true&characterEncoding=UTF-8&useSSL=false username:?root password:?root

(2)修改屬性配置文件 src/main/resources/generator.properties

# 以question微服務為例 mainPath=com.jackson0714 package=com.jackson0714.passjava moduleName=question author=jackson0714 email=jackson0585@163.com tablePrefix=qms_

(3)修改controller 模板文件

src/main/resources/template/Controller.java.vm

刪除引入的包,后面再引入

import?org.apache.shiro.authz.annotation.RequiresPermissions;

注釋RequiresPermissions注解,后面再引入

@RequiresPermissions("${moduleName}:${pathName}:list")

4.啟動代碼生成器服務

啟動代碼生成器服務

瀏覽器打開localhost,可以看到數據庫qms的兩張表已經顯示在后臺了

5.生成代碼

  • 生成代碼

生成代碼

代碼生成器生成的pms服務代碼 代碼結構
  • 拷貝main文件夾到question模塊src目錄

  • 刪除前端代碼passjava-question\src\main\resources\src目錄

  • 代碼結構

生成的代碼包含controller,dao層,實體類,接口實現類,mapper映射文件

6.添加common 模塊

因為自動生成的代碼引用了一些工具類,而我們的項目中沒有,所以需要加個common模塊添加一些工具類

引用工具類報錯 選擇Maven
  • 添加passjava-common

    New Module: 選擇Maven

Name: passjava-common

添加common模塊

7.question模塊添加common模塊依賴

pom文件添加依賴

<dependency><groupId>com.jackson0714.passjava</groupId><artifactId>passjava-common</artifactId><version>0.0.1-SNAPSHOT</version> </dependency>

8.common模塊添加依賴

  • MyBatis-Plus

    <!--mybatis-plus?DAO層工具?https://mp.baomidou.com/--> <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>3.2.0</version> </dependency>
  • lombok依賴

    <!--lombok?不需要寫getter,setter方法了--> <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version> </dependency>
  • httpcore依賴

    <!--httpcore?依賴--> <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.12</version> </dependency>
  • commons-lang依賴

    <!--commons-lang?依賴?--> <dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version> </dependency>
  • servlet依賴

    <!--??導入servlet-api?依賴??--> <dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope> </dependency>

9.common模塊添加工具類

  • 添加包com.jackson0714.common.utils

  • 從renren-fast項目copy文件

    Constans.java、PageUtils.java、Query.java、R.java、RRException.java

  • 添加包com.jackson0714.common.xss

  • 從renren-fast項目copy文件

    HTMLFilter.java、SQLFilter.java

passjava-common代碼結構圖

拷貝renren-fast文件

5.5 整合MyBatis-Plus實現CRUD

1.添加Mybatis-Plus依賴

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.2.0</version> </dependency>

2.配置數據源

  • 導入數據庫的驅動

    • 查看mysql版本 5.7.29

到maven倉庫查看適用的mysql驅動,5.7的沒有,8.0兼容5.7的,所以選擇8.0的驅動

<!--添加mysql驅動--> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.17</version> </dependency>

3.配置MyBatis-Plus

配置mabatis-plus時的智能提示
  • 添加application.yml 文件配置數據源

    文件路徑:/passjava-question/src/main/resources/application.yml

    spring:datasource:driver-class-name:?com.mysql.cj.jdbc.Driverurl:?jdbc:mysql://129.211.188.xxx:3306/passjava_admin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername:?rootpassword:?xxx
  • 配置mapper映射文件路徑

    mybatis-plus:mapper-locations: classpath:/mapper/**/*.xmlglobal-config:db-config:id-type: auto
  • 添加MapperScan注解

    @MapperScan("com.jackson0714.passjava.question.dao") @SpringBootApplication public?class?PassjavaQuestionApplication?{public?static?void?main(String[]?args)?{SpringApplication.run(PassjavaQuestionApplication.class,?args);} }

4.測試mybatis-plus的CRUD方法

創建類型為javaBasic的type表數據 更新id=1的表數據
  • 創建類型為javaBasic的type表數據

    @Autowired TypeService?typeService;//?創建題目類型 @Test void?testCreateType()?{TypeEntity?typeEntity?=?new?TypeEntity();typeEntity.setType("javaBasic");typeService.save(typeEntity);System.out.println("創建成功"); }
  • 更新id=1的表數據

    //?更新type=jvm @Test void?testUpdateType()?{TypeEntity?typeEntity?=?new?TypeEntity();typeEntity.setId(1L);typeEntity.setType("jvm");typeService.updateById(typeEntity);System.out.println("修改成功"); }
  • 查詢id=1的表數據

    //?查詢題目類型 @Test void?testSelectType()?{List<TypeEntity>?typeEntityList?=?typeService.list(new?QueryWrapper<TypeEntity>().eq("id",1L));typeEntityList.forEach((item)->?{System.out.println(item);});System.out.println("查詢成功"); }

查詢id=1的表數據
  • 刪除id=1的表數據

    //?刪除題目類型記錄 @Test void?testRemoveType()?{typeService.removeById(1L);System.out.println("刪除成功"); }

刪除id=1的表數據

5.6 生成所有微服務的CRUD代碼

1. 修改代碼生成器配置文件

(1)\renren-generator\src\main\resources\generator.properties

mainPath=com.jackson0714 package=com.jackson0714.passjava moduleName=channel author=jackson0714 email=jackson0585@163.com tablePrefix=chms_

(2)\renren-generator\src\main\resources\application.yml

修改連接的數據庫:passjava_chms

2.生成渠道微服務代碼

啟動服務,打開瀏覽器:http://localhost:8003/#generator.html

注意:端口地址默認是8080,我配置成了8003。

生成渠道微服務代碼

3.添加生成的代碼

  • 刪除自動生成的代碼中的文件夾:main\resources\src

  • 拷貝main文件夾到channel模塊src目錄下

4.配置渠道微服務

  • pom.xml引入common模塊

    <dependency><groupId>com.jackson0714.passjava</groupId><artifactId>passjava-common</artifactId><version>0.0.1-SNAPSHOT</version> </dependency>
  • 添加application.yml

    spring:datasource:driver-class-name:?com.mysql.cj.jdbc.Driverurl:?jdbc:mysql://129.211.188.xxx:3306/passjava_chms?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername:?rootpassword:?xxxmybatis-plus:mapper-locations:?classpath:/mapper/**/*.xmlglobal-config:db-config:id-type:?auto
  • 5.測試channel服務接口

    訪問:http://localhost:8000/channel/channel/list

    返回:

    {"msg":"success","code":0,"page":{"totalCount":0,"pageSize":10,"totalPage":0,"currPage":1,"list":[]}}

5.生成所有微服務的CRUD代碼

生成所有微服務代碼

6.配置微服務端口

passjava-channel??端口8000 passjava-content??端口9000 passjava-member?端口10000 passjava-question?端口11000 passjava-study?端口12000

所有微服務都啟動成功并測試接口通過

http://localhost:8000/channel/channel/list http://localhost:9000/content/banner/list http://localhost:10000/member/member/list http://localhost:11000/question/question/list http://localhost:12000/study/studytime/list

5.7 管理后臺-題目類型功能

1.環境準備

  • 代碼準備

    將renren-fast-vue代碼copy到自己的前端項目中

  • 安裝node_module

cnpm?install
  • 啟動前端portal

npm?run?dev PassJava后臺
  • 登陸后臺

    1.啟動RenrenAplication

    2.輸入用戶名和密碼登陸

2. 添加目錄和菜單

  • 添加題目中心目錄(一級菜單)

添加題目管理菜單

刷新頁面,就可以看到題目中心菜單

  • 添加題目類型維護菜單(二級菜單)

題目類型維護菜單

題目中心菜單

可以看到數據庫新增了兩條記錄,分別對應兩個菜單

sys_menu表

點擊類型維護菜單,打開了鏈接:http://localhost:8002/#/question-type,頁面顯示空白頁面.

3.自動生成前端頁面

用renren-generator自動生成前端代碼,可以參考這篇:13.SpringCloud實戰項目-自動生成前后端代碼

拷貝question目錄到前端目錄 \src\views\modules

自動生成前端代碼

前端Vue頁面

4. 測試類型維護功能

點擊類型維護菜單,可以看到請求報404

http://localhost:8080/renren-fast/question/type/list?t=1587825969456&page=1&limit=10&key=

因為頁面的請求都訪問到renren-fast服務了,所以要修改為訪問題目微服務。但是前端有很多請求訪問的是不同的服務,所以我們可以通過網關來作為請求的入口,然后將不同的請求路由到不同的服務。

SpringCloud整合網關可以看之前寫的一篇文章:20.SpringCloud整合Gateway網關

5.配置請求到網關

文件:\static\config\index.js

api接口請求地址替換為gateway的地址

window.SITE_CONFIG['baseUrl']?=?'http://localhost:8080/renren-fast'; 替換為 window.SITE_CONFIG['baseUrl']?=?'http://localhost:8060';?//?網關地址

刷新頁面,發現會回到登錄頁面,而且驗證碼獲取不到,F12調試工具可以看到驗證碼請求發送到網關上,而網關上找不到這個請求地址(http://localhost:8060/captcha.jpg),所以報404。其實驗證碼請求應該訪問renren-fast服務,所以我們要將驗證碼請求通過網關轉發到renren-fast服務(http://localhost:8080/renren-fast/captcha.jpg)。

#?驗證碼請求: GET?http://localhost:8060/captcha.jpg?uuid=1ce21f53-1866-40b1-8b20-2f4515d59f0d?404?(Not?Found)

獲取驗證碼報404 “

可以將renren-fast注冊到注冊中心,然后通過網關將請求轉發到renren-fast服務。

6.注冊renren-fast服務

  • renren-fast項目添加common依賴

<dependency><groupId>com.jackson0714.passjava</groupId><artifactId>passjava-common</artifactId><version>0.0.1-SNAPSHOT</version> </dependency>
  • 配置注冊中心地址

cloud:nacos:discovery:server-addr:?127.0.0.1:8848
  • 配置應用程序的名稱

application:name:?renren-fast
  • 應用類添加@EnableDiscoveryClient注解

  • 查看服務是否注冊成功

Nacos服務列表

7. 添加網關路由規則

  • 配置路由規則

passjava-gateway項目中application.yml文件配置路由規則,并重啟passjava-gateway服務

spring:cloud:gateway:routes:-?id:?route_portal?#?路由規則iduri:?lb://renren-fast?#?負載均衡,renren-fast服務predicates:?#?斷言-?Path=/api/**?#?如果前端請求路徑包含?api,則應用這條路由規則filters:?#過濾器-?RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}?#?將訪問路徑中包含的api替換成renren-fast,但是替換的url不會在前端顯示,還是網關的訪問路徑。這里不是跳轉到新的路徑,而是轉發請求。
  • 修改前端請求路徑

文件:\static\config\index.js

請求路徑添加api

?window.SITE_CONFIG['baseUrl']?=?'http://localhost:8086';替換為window.SITE_CONFIG['baseUrl']?=?'http://localhost:8060/api';?//?添加api
  • 刷新登錄頁面,可以正常獲取驗證碼,請求路徑為網關地址 + /api/captcha

http://localhost:8060/api/captcha.jpg?uuid=84d36089-07ae-4201-85c0-8217b032f21b “

前端將請求發送到網關http://localhost:8060/api/captcha.jpg,網關將請求轉發到http://localhost:8060/api/renren-fast/captcha.jpg。

  • 登錄,報跨域問題

Access?to?XMLHttpRequest?at?'http://localhost:8060/api/sys/login'?from?origin?'http://localhost:8002'?has?been?blocked?by?CORS?policy:?Response?to?preflight?request?doesn't?pass?access?control?check:?No?'Access-Control-Allow-Origin'?header?is?present?on?the?requested?resource. “

登錄頁面url:http://localhost:8002,點擊登錄訪問的請求url:http://localhost:8060/api/sys/login,兩個url的端口號不一樣,產生了跨域問題。

8.跨域問題

跨域場景
  • 跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器 讓運行在一個 origin (domain) 上的Web應用被準許訪問來自不同源服務器上的指定的資源。當一個資源從與該資源本身所在的服務器不同的域、協議或端口請求一個資源時,資源會發起一個跨域 HTTP 請求。

  • 比如,站點 http://domain-a.com 的某 HTML 頁面通過 ?的 src 請求 http://domain-b.com/image.jpg。網絡上的許多頁面都會加載來自不同域的CSS樣式表,圖像和腳本等資源。

  • 出于安全原因,瀏覽器限制從腳本內發起的跨源HTTP請求。例如,XMLHttpRequest和Fetch API遵循同源策略。這意味著使用這些API的Web應用程序只能從加載應用程序的同一個域請求HTTP資源,除非響應報文包含了正確CORS響應頭。

9.解決跨域問題

  • 添加響應頭,配置當次請求允許跨域

    • Access-Control-Allow-Origin:支持哪些來源的請求跨域

    • Access-Control-Allow-Methods:支持哪些方法跨域

    • Access-Control-Allow-Credentials:跨域請求默認不包含cookie,設置為true可以包含cookie

    • Access-Control-Expose-Headers:跨域請求暴露的字段CORS請求時,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定。

    • Access-Control-Max-Age:表明該響應的有效時間為多少秒。在有效時間內,瀏覽器無 須為同一請求再次發起預檢請求。請注意,瀏覽器自身維護了一個最大有效時間,如果 該首部字段的值超過了最大有效時間,將不會生效。

  • 添加跨域配置

    passjava-gateway應用中添加配置類PassJavaCorsConfiguration.java

package?com.jackson0714.passjava.gateway.config;import?org.springframework.context.annotation.Bean; import?org.springframework.context.annotation.Configuration; import?org.springframework.web.cors.CorsConfiguration; import?org.springframework.web.cors.reactive.CorsWebFilter; import?org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;@Configuration public?class?PassJavaCorsConfiguration?{@Beanpublic?CorsWebFilter?corsWebFilter()?{UrlBasedCorsConfigurationSource?source?=?new?UrlBasedCorsConfigurationSource();CorsConfiguration?corsConfiguration?=?new?CorsConfiguration();//?配置跨域corsConfiguration.addAllowedHeader("*");?//?允許所有請求頭跨域corsConfiguration.addAllowedMethod("*");?//?允許所有請求方法跨域corsConfiguration.addAllowedOrigin("*");?//?允許所有請求來源跨域corsConfiguration.setAllowCredentials(true);?//允許攜帶cookie跨域,否則跨域請求會丟失cookie信息source.registerCorsConfiguration("/**",?corsConfiguration);return?new?CorsWebFilter(source);} }
  • 注釋renren-fast里面的跨域配置

    文件路徑:src/main/java/io/renren/config/CorsConfig.java

  • 登錄成功

    可以看到login請求的響應報文中包含了已配置的CORS響應頭

login請求

10.配置題目服務的路由規則

我們訪問題目中心的類型頁面,發現還是報404找不到資源

所以我們需要配置題目服務的路由規則,將題目中心的頁面請求經網關轉發到題目服務。

spring:cloud:gateway:routes:-?id:?route_question?#?題目微服務路由規則uri:?lb://passjava-question?#?負載均衡,將請求轉發到注冊中心注冊的renren-fast服務predicates:?#?斷言-?Path=/api/question/**?#?如果前端請求路徑包含?api/question,則應用這條路由規則filters:?#過濾器-?RewritePath=/api/(?<segment>.*),/$\{segment}?#?將跳轉路徑中包含的api替換成question “

注意:若predicates的Path更精確,則將路由規則放到更上面,優先命中更上面的路由規則。

11.測試類型維護功能

類型維護頁面 修改類型logo
  • 數據庫插入3條測試數據

  • 測試查詢列表,可以看到有三條記錄查詢出來了

  • 測試修改一條數據,可以看到數據庫里面記錄更新為23了

  • 測試刪除一條數據,可以看到界面和數據庫都刪除了一條數據

12.打開新增和批量刪除功能

注釋權限判斷,默認返回true

//?src\utils\index.js /***?是否有權限*?@param?{*}?key*/ export?function?isAuth?(key)?{//?return?JSON.parse(sessionStorage.getItem('permissions')?||?'[]').indexOf(key)?!==?-1?||?falsereturn?true }

新增和批量刪除按鈕

5.8 管理后臺-題目維護功能

1.配置邏輯刪除

  • 所有表字段添加del_flag字段

    del_flag?tinyint(1)?DEFAULT?0?COMMENT?'刪除標記(0-正常,1-刪除)',
  • MyBatisPlus配置邏輯刪除

mybatis-plus:mapper-locations:?classpath:/mapper/**/*.xmlglobal-config:db-config:id-type:?autologic-delete-field:?delFlag??#全局邏輯刪除字段值 3.3.0開始支持,詳情看下面。logic-delete-value:?1?#?邏輯已刪除值(默認為?1)logic-not-delete-value:?0?#?邏輯未刪除值(默認為?0)
  • log中打印查詢SQL語句

SELECT?id,type,comments,logo_url,del_flag,create_time,update_time?FROM?qms_type?WHERE?del_flag=0?
  • log打印刪除SQL語句

UPDATE?qms_type?SET?del_flag=1?WHERE?id?IN?(?1?)?AND?del_flag=0?

2.快速顯示開關

想要將是否顯示改為快速開關

  • 自定義列模板

    1.通過 Scoped slot 可以獲取到 row, column, $index 和 store(table 內部的狀態管理)的數據

    2.使用Switch開關

Scoped slot:https://element.eleme.cn/#/zh-CN/component/table Switch開關:https://element.eleme.cn/#/zh-CN/component/switch<el-table-column prop="enable"header-align="center"align="center"label="是否顯示"><template slot-scope="scope"> <el-switchv-model="scope.row.enable":active-value=1:inactive-value=0active-color="#13ce66"inactive-color="#ff4949"@change="updateQuestionStatus(scope.row)"></el-switch></template> </el-table-column>

添加更新方法

//?更新題目是否顯示 updateQuestionStatus(data)?{console.log(data)let?{id,?enable}?=?datathis.$http({url:?this.$http.adornUrl('/question/question/update'),method:?'post',data:?this.$http.adornData({id,?enable},?false)}).then(({?data?})?=>?{this.$message({type:"success",message:?"狀態更新成功"})}); },

3.前端字段校驗

對排序字段限制:必須為正整數

dataRule: {displayOrder: [{validator: (rule, value, callback) => {if (value == "") {callback(new Error("排序字段必須填寫"));} else if (!Number.isInteger(value) || value<0) {callback(new Error("排序必須是一個大于等于0的整數"));} else {callback();}},trigger: "blur"}] }

4.后端字段校驗

  • 實體類字段上添加注解@Positive必須是大于0的數字

/***?排序*/ @Positive private?Integer?displayOrder;
  • API 添加注解@Valid

/** *?保存 */ @RequestMapping("/save") public?R?save(@Valid?@RequestBody?QuestionEntity?question){questionService.save(question);return?R.ok(); }

測試結果

后端字段校驗

-1,0,0.2 不通過

測試1,1.2通過

5.模糊查詢題目列表

修改實現類QuestionServiceImpl的queryPage方法

原方法:

public?PageUtils?queryPage(Map<String,?Object>?params)?{IPage<QuestionEntity>?page?=?this.page(new?Query<QuestionEntity>().getPage(params),new?QueryWrapper<QuestionEntity>());return?new?PageUtils(page); }

修改后:

@Override public?PageUtils?queryPage(Map<String,?Object>?params)?{//1.get?keyString?key?=?(String)?params.get("key");QueryWrapper<QuestionEntity>?queryWrapper?=?new?QueryWrapper<>();if?(!StringUtils.isEmpty(key))?{queryWrapper.eq("id",?key).or().like("title",?key).or().like("answer",?key);}IPage<QuestionEntity>?page?=?this.page(new?Query<QuestionEntity>().getPage(params),queryWrapper);return?new?PageUtils(page); }

6.添加分頁插件

沒有分頁插件顯示共0條

添加分頁插件

package?com.jackson0714.passjava.question.config;import?com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import?org.mybatis.spring.annotation.MapperScan; import?org.springframework.context.annotation.Bean; import?org.springframework.context.annotation.Configuration; import?org.springframework.transaction.annotation.EnableTransactionManagement;@Configuration @EnableTransactionManagement?//開啟事務 @MapperScan("com.jackson0714.passjava.question.dao") public?class?MyBatisConfig?{//引入分頁插件@Beanpublic?PaginationInterceptor?paginationInterceptor()?{PaginationInterceptor?paginationInterceptor?=?new?PaginationInterceptor();//?設置請求的頁面大于最大頁后操作,?true調回到首頁,false?繼續請求??默認falsepaginationInterceptor.setOverflow(true);//?設置最大單頁限制數量,默認?500?條,-1?不受限制paginationInterceptor.setLimit(1000);return?paginationInterceptor;} }

添加分頁插件后的顯示

配置了分頁插件的顯示

六、PassJava 高級實踐篇

6.1 Spring Cloud Alibaba 組件簡介

1.SpringCloud Alibaba概述

Spring Cloud Alibaba 致力于提供微服務開發的一站式解決方案。此項目包含開發分布式應用微服務的必需組件,方便開發者通過 Spring Cloud 編程模型輕松使用這些組件來開發分布式應用服務。

依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以將 Spring Cloud 應用接入阿里微服務解決方案,通過阿里中間件來迅速搭建分布式應用系統。

Github:https://github.com/alibaba/spring-cloud-alibaba

Spring Cloud的幾大痛點

  • 部分組件停止維護和更新,有問題也不易解決

  • 部分環境搭建起來比較復雜,沒有非常友好的可視化界面

  • 配置相對來說復雜,需要較高的學習成本

Spring Cloud Alibaba的優勢

  • 阿里經歷過了時間的考驗

  • 設計合理

  • 擁有不錯的可視化界面,方便運維監控和排查問題

  • 環境搭建和配置簡單,學習成本低

PassJava項目搭配SpringCloud Alibaba技術的搭配方案

描述Spring CloudSpring Cloud Alibaba組合選用
服務發現組件Eureka(停止維護)服務發現組件Nacos 注冊中心Spring Cloud Alibaba - Nacos
配置中心組件Spring Cloud Config 配置中心Nacos 配置中心Spring Cloud Alibaba - Nacos
斷路保護組件Hystrix 斷路保護Sentinel 服務容錯Spring Cloud Alibaba - Sentinel
鏈路追蹤組件Sleuth 調用鏈監控/Spring Cloud - Sleuth
負載均衡組件Ribbon/Spring Cloud - Ribbon
遠程調用組件OpenFeign (HTTP+JSON)Dubbo(RPC框架)Spring Cloud - OpenFeign
分布式事務/Seata 分布式事務Spring Cloud Alibaba - Seata
API 網關Gateway/Spring Cloud - Gateway

最后技術選型:

Spring?Cloud?Alibaba?-?Nacos?實現注冊中心 Spring?Cloud?Alibaba?-?Nacos?實現配置中心 Spring?Cloud?Alibaba?-?Sentinel??實現服務容錯 Spring?Cloud?Alibaba?-?Seata?實現分布式事務Spring?Cloud?-?Ribbon?實現負載均衡 Spring?Cloud?-?Feign?實現遠程調用 Spring?Cloud?-?Gateway?API網關 Spring?Cloud?-?Sleuth?實現調用鏈監控

2.Spring Cloud Alibaba版本

項目的版本號格式為 x.x.x 的形式,其中 x 的數值類型為數字,從 0 開始取值,且不限于 0~9 這個范圍。項目處于孵化器階段時,第一位版本號固定使用 0,即版本號為 0.x.x 的格式。

由于 Spring Boot 1 和 Spring Boot 2 在 Actuator 模塊的接口和注解有很大的變更,且 spring-cloud-commons 從 1.x.x 版本升級到 2.0.0 版本也有較大的變更,因此阿里采取跟 SpringBoot 版本號一致的版本:

  • 1.5.x 版本適用于 Spring Boot 1.5.x

  • 2.0.x 版本適用于 Spring Boot 2.0.x

  • 2.1.x 版本適用于 Spring Boot 2.1.x

  • 2.2.x 版本適用于 Spring Boot 2.2.x

Spring Cloud Alibaba 版本和Spring Cloud 和Spring Boot 版本兼容性列表

Spring Cloud 版本Spring Cloud Alibaba 版本Spring Boot 版本
Spring Cloud Hoxton.SR32.2.x.RELEASE2.2.x.RELEASE
Spring Cloud Greenwich2.1.x.RELEASE2.1.x.RELEASE
Spring Cloud Finchley2.0.x.RELEASE2.0.x.RELEASE
Spring Cloud Edgware1.5.x.RELEASE1.5.x.RELEASE

我們采用Spring Cloud Hoxton.SR3, Spring Cloud Alibaba 2.2.0.RELEASE, Spring Boot 2.2.6 RELEASE

PassJava-Common的pom.xml文件引入Spring Cloud Alibaba依賴

<dependencyManagement><dependencies><!--??Spring?Cloud?Alibaba?依賴??--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.2.0.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies> </dependencyManagement>

6.2 SpringCloud整合Alibaba-Nacos組件

Nacos 是阿里巴巴開源的一個更易于構建云原生應用的動態服務發現、配置管理和服務管理平臺。

1.引入Nacos 服務發現組件

passjava-common模塊的pom.xml文件引入Nacos 服務發現組件

<!--?nacos?discovery?服務發現組件--> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>

2.下載Nacos Server并啟動

  • 下載Nacos Server 壓縮包

https://github.com/alibaba/nacos/releases

啟動 Server,進入解壓后文件夾或編譯打包好的文件夾,找到如下相對文件夾 nacos/bin,并對照操作系統實際情況之下如下命令。

  • Linux/Unix/Mac 操作系統,執行命令 sh startup.sh -m standalone

  • Windows 操作系統,執行命令 cmd startup.cmd

  • windows執行startupm.cmd遇到問題:

    λ?startup.cmd??????????????????????????????????????????????????????Please?set?the?JAVA_HOME?variable?in?your?environment,?We?need?java(x64)!?jdk8?or?later?is?better!?

    解決方案:

    修改startup.cmd文件中的%JAVA_HOME%

    %JAVA_HOME%?替換為?C:\Program?Files\Java\jdk1.8.0_131

    啟動成功:

    3.每個微服務都配置Nacos Server 地址

    • 配置Nacos Server 地址

    在passjava-question、passjava-channel、passjava-content、passjava-member、passjava-study 應用的 /src/main/resources/application.yml配置文件中配置 Nacos Server 地址

    spring:cloud:nacos:discovery:server-addr:?127.0.0.1:8848

    4.添加注解

    為每個服務使用 @EnableDiscoveryClient 注解開啟服務注冊與發現功能

    @EnableDiscoveryClient @MapperScan("com.jackson0714.passjava.question.dao") @SpringBootApplication public?class?PassjavaQuestionApplication?{public?static?void?main(String[]?args)?{SpringApplication.run(PassjavaQuestionApplication.class,?args);}}

    5.配置微服務的名稱

    spring:application:name:?passjava-question

    6.訪問nacos server后臺

    • 登錄后臺

    http://localhost:8848/nacos/index.html#/login

    用戶名:nacos

    密碼:nacos

    • 查看已注冊的服務

      passjava-channel?渠道微服務 passjava-member?用戶微服務 passjava-study?學習微服務 passjava-question?問題微服務 passjava-content?內容微服務

    6.3 SpringCloud整合OpenFeign遠程調用

    1.Feign 概述

    • Feign聲明式客的HTTP客戶端,讓遠程調用更簡單。

    • 提供了HTTP請求的模板,編寫簡單的接口和插入注解,就可以定義好HTTP請求的參數、格式、地址等信息

    • 整合了Ribbon(負載均衡組件)和Hystix(服務熔斷組件),不需要顯示使用這兩個組件

    • Spring Cloud Feign 在Netflix Feign的基礎上擴展了對SpringMVC注解的支持

    2. 遠程調用示例

    示例:查詢用戶的學習時長

    用戶微服務passjava-member調用學習微服務passjava-study的方法

    2.1 引入openfeign依賴

    passjava-member和passjava-study項目的pom文件引入openfeign依賴

    <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>

    2.2 StudyTimeController定義遠程調用測試方法

    返回某個用戶學習題目的總時長

    @RequestMapping("/member/list/test") public?R?memberStudyTimeTest()?{StudyTimeEntity?studyTimeEntity?=?new?StudyTimeEntity();studyTimeEntity.setTotalTime(100);?//?學習時長:100分鐘studyTimeEntity.setQuesTypeId(1L);?//?題目類型:1 (javaBasic)return?R.ok().put("studyTime",?Arrays.asList(studyTimeEntity)); }

    2.3 member目錄下創建feign service

    接口測試結果
    • 創建package: com.jackson0714.passjava.member.feign

    • 創建StudyTimeFeignService接口

    • 添加注解@FeignClient。顯示聲明這個接口用來遠程調用study服務。

      @FeignClient("passjava-study") public?interface?StudyTimeFeignService?{}
    • 添加遠程調用方法

      public?R?memberStudyTime();
    • 給方法添加要遠程調用的方法的路徑study/studytime/member/list/test

      @RequestMapping("study/studytime/member/list/test") public?R?getMemberStudyTimeListTest();
    • 添加注解@EnableFeignClients開啟遠程調用服務。

      給類PassjavaStudyApplication.java添加注解@EnableFeignClients。

      basePackages代表自動掃碼指定路徑下所有帶有@FeignClient注解的接口。

      @EnableFeignClients(basePackages?=?"com.jackson0714.passjava.member.feign") @EnableDiscoveryClient @MapperScan("com.jackson0714.passjava.member.dao") @SpringBootApplication public?class?PassjavaMemberApplication?{public?static?void?main(String[]?args)?{SpringApplication.run(PassjavaMemberApplication.class,?args);}}
    • 測試接口

      studytime和member都有數據,學習時長:100分鐘,昵稱:悟空聊架構

      • 啟動passjava-member和passjava-study服務

      • 用postman工具或瀏覽器輸入請求地址

        http://localhost:10000/member/member/studytime/list/test

      • 返回結果如下圖

    2.4 測試OpenFeign傳參

    示例:用戶id作為參數在服務間傳遞

    MemberController

    @RequestMapping("/studytime/list/test/{id}") public?R?getMemberStudyTimeListTest(@PathVariable("id")?Long?id)?{//mock數據庫查到的會員信息MemberEntity?memberEntity?=?new?MemberEntity();memberEntity.setId(id);?//?學習時長:100分鐘memberEntity.setNickname("悟空聊架構");//遠程調用拿到該用戶的學習時長(學習時長是mock數據)R?memberStudyTimeList?=?studyTimeFeignService.getMemberStudyTimeListTest(id);return?R.ok().put("member",?memberEntity).put("studytime",?memberStudyTimeList.get("studytime")); }

    StudyTimeFeignService

    @FeignClient("passjava-study") public?interface?StudyTimeFeignService?{@RequestMapping("study/studytime/member/list/test/{id}")public?R?getMemberStudyTimeListTest(@PathVariable("id")?Long?id); }

    StudyTimeController

    @RequestMapping("/member/list/test/{id}") public?R?memberStudyTimeTest(@PathVariable("id")?Long?id)?{StudyTimeEntity?studyTimeEntity?=?new?StudyTimeEntity();studyTimeEntity.setTotalTime(100);?//?學習時長:100分鐘studyTimeEntity.setQuesTypeId(1L);?//?題目類型:1 (javaBasic)return?R.ok().put("studytime",?Arrays.asList(studyTimeEntity)); }

    請求地址和參數:http://localhost:10000/member/member/studytime/list/test/1

    執行結果:

    執行結果

    2.5 總結FeignClient使用方法

    • 引入OpenFeign依賴

    • 定義FeignClient接口類(注解@FeignClient),聲明這個接口類是用來遠程調用其他服務的

    • 接口類中定義要遠程調用的接口方法,指定遠程服務方法的路徑

    • Controller類中調用接口方法

    • 開啟遠程調用(注解@EnableFeignClients)

    • 遠程調用的流程:

      • @RequestBody將這個對象轉為json

      • 找到passjava-study服務,給study/studytime/member/list/test服務發送請求

      • 將json放到請求體里面,發送請求

      • 對方服務收到請求,請求體里有json數據

      • 將請求體中的json數據轉換成對方服務的參數類型。只需要兩邊的字段名稱和類型是一致的。

    6.4 Spring Cloud 整合 Nacos配置中心

    1.傳統配置方式

    • application.properties文件中定義兩個配置:

    member.nickname = "悟空聊架構" member.age = "18"
    • 示例控制器中定義私有變量nickname和age,@value代表從配置中取值

    @Value("${member.nickname}") private??String?nickname;@Value("$member.age") private??Integer?age;
    • 示例控制器中定義方法:獲取nick和age的值

    @RequestMapping("/test-local-config") public?R?testLocalConfig()?{return?R.ok().put("nickname",?nickname).put("age",?age); }
    • 測試結果

    總結:從配置文件中獲取配置。

    這種方式的缺點是什么呢?如果要修改配置參數,則需要重新啟動服務。如果服務很多,則需要重啟所有服務,非常不方便。

    有沒有什么辦法不停服務修改配置而且使其生效呢?

    答案:有的,用Spring Cloud Alibaba的Nacos 組件就可以完成。

    2.引入Nacos依賴

    PassJava-Common項目的pom.xml文件引入Spring Cloud Alibaba Nacos Config依賴

    <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>

    3.配置Nacos元數據

    • passjava-member 添加 /src/main/resources/bootstrap.properties 配置文件(注意:bootstrap.properties 優先級高于其他配置文件)

    • 配置 Nacos Config 元數據

    bootstrap.properties spring.application.name=passjava-member spring.cloud.nacos.config.server-addr=127.0.0.1:8848

    4.Nacos后臺新增配置

    Data ID: passjava-member.properties

    Group: DEFAULT_GROUP

    配置格式:

    member.nick="悟空" member.age=10

    Nacos后臺新增配置

    5.開啟動態刷新配置功能

    添加注解@RefreshScope開啟動態刷新配置功能

    @RefreshScope @RestController @RequestMapping("member/sample") public?class?SampleController?{}

    可以從控制臺看到日志信息:

    Refresh keys changed: [member.age] 2020-04-19 23:34:07.154 INFO 8796 --- [-127.0.0.1_8848] c.a.nacos.client.config.impl.CacheData : [fixed-127.0.0.1_8848] [notify-ok] dataId=passjava-member.properties, group=DEFAULT_GROUP, md5=df136e146c83cbf857567e75acb11e2b, listener=com.alibaba.cloud.nacos.refresh.NacosContextRefresher$1@4f49b78b 2020-04-19 23:34:07.154 INFO 8796 --- [-127.0.0.1_8848] c.a.nacos.client.config.impl.CacheData : [fixed-127.0.0.1_8848] [notify-listener] time cost=529ms in ClientWorker, dataId=passjava-member.properties, group=DEFAULT_GROUP, md5=df136e146c83cbf857567e75acb11e2b, listener=com.alibaba.cloud.nacos.refresh.NacosContextRefresher$1@4f49b78b

    member.age 更新了,通知了member服務,刷新了配置。對應的配置id為passjava-member.properties,分組為DEFAULT_GROUP。監聽器為com.alibaba.cloud.nacos.refresh.NacosContextRefresher

    6.測試結果

    訪問:http://localhost:10000/member/sample/test-local-config

    結果:nickname和age和Nacos后臺配置一致

    結論:只用在Nacos后臺改配置即可實時修改配置。

    注意:Nacos的配置項優先級高于application.propertite里面的配置。

    測試結果

    7.命名空間

    我們現在有5個微服務,每個微服務用到的配置可能都不一樣,那不同微服務怎么樣獲取自己微服務的配置呢?

    這里可以用到命名空間,我們針對每個微服務,都創建一個命名空間。

    創建命名空間
    • 創建命名空間

    #?創建5個命名空間 passjava-channel passjava-content passjava-member passjava-question passjava-study

    命名空間 命名空間下創建配置
    • 命名空間下創建配置

      我們打開配置列表菜單,可以看到有五個命名空間。

    選中passjava-channel命名空間,然后新增配置項,與之前新增配置的步驟一致,也可以通過克隆命名空間來克隆配置。

    克隆配置 passjava-member.properties
    • 修改指定的命名空間

      bootstrap.properties配置命名空間

      spring.cloud.nacos.config.namespace=passjava-member
    • 測試配置是否生效

      修改passjava-member.properties的配置內容

      重啟member服務

      訪問方法:/member/sample/test-local-config

      執行結果:

      {"msg":?"success","code":?0,"nickname":?"\"悟空member\"","age":?30 }

      說明獲取的是passjava-member命名空間的配置

    8.分組

    如果我們有多套環境,比如開發環境,測試環境,生產環境,每一套環境的配置參數不一樣,那配置中心該如何配置呢?

    我們可以使用配置中心的分組功能。每一套環境都是一套分組。

    • 首先創建一套dev環境配置項,然后克隆配置到test和prod環境

    dev環境

    dev、test、prod分組
    • bootstrap.properties配置當前使用的分組:prod

    spring.cloud.nacos.config.group=prod
    • 測試獲取生產環境配置

      {"msg":?"success","code":?0,"nickname":?"\"悟空-prod\"","age":?10 }

      可以看到獲取到的是prod分組的配置

    9.多配置集

    我們可以將application.yml文件中的datasource、mybatis-plus等配置進行拆解,放到配置中心。group可以創建3套,dev/test/prod。

    1.配置中心新建datasource.yml 配置

    datasource.yml 配置

    2.配置中心新建mybatis.yml 配置

    mybatis.yml配置

    3.配置中心新建more.yml 配置

    more.yml配置

    4.克隆dev環境配置到test和prod環境

    5.bootstrap.properties增加nacos配置,application.yml注釋配置

    spring.application.name=passjava-member spring.cloud.nacos.config.server-addr=127.0.0.1:8848spring.cloud.nacos.config.namespace=passjava-member spring.cloud.nacos.config.group=prodspring.cloud.nacos.config.extension-configs[0].data-id=datasource.yml spring.cloud.nacos.config.extension-configs[0].group=dev spring.cloud.nacos.config.extension-configs[0].refresh=truespring.cloud.nacos.config.extension-configs[1].data-id=mybatis.yml spring.cloud.nacos.config.extension-configs[1].group=dev spring.cloud.nacos.config.extension-configs[1].refresh=truespring.cloud.nacos.config.extension-configs[2].data-id=more.yml spring.cloud.nacos.config.extension-configs[2].group=dev spring.cloud.nacos.config.extension-configs[2].refresh=true

    6.測試配置是否生效

    • 測試passjava-member.properties和more.yml配置是否生效

    請求url:http://localhost:10000/member/sample/test-local-config

    返回配置的nick和age,且端口是10000,且member服務注冊到注冊中心

    {"msg":?"success","code":?0,"nickname":?"\"悟空-prod1\"","age":?22 }
    • 測試datasource.yml和mybatis.yml配置是否生效

    請求url:http://localhost:10000/member/member/list

    返回數據庫查詢結果

    {"msg":?"success","code":?0,"page":?{"totalCount":?0,"pageSize":?10,"totalPage":?0,"currPage":?1,"list":?[]j} }

    說明以上配置都生效了。

    更多配置項

    配置項key默認值說明
    服務端地址spring.cloud.nacos.config.server-addr
    DataId前綴spring.cloud.nacos.config.prefixspring.application.name
    Groupspring.cloud.nacos.config.groupDEFAULT_GROUP
    dataID后綴及內容文件格式spring.cloud.nacos.config.file-extensionpropertiesdataId的后綴,同時也是配置內容的文件格式,目前只支持 properties
    配置內容的編碼方式spring.cloud.nacos.config.encodeUTF-8配置的編碼
    獲取配置的超時時間spring.cloud.nacos.config.timeout3000單位為 ms
    配置的命名空間spring.cloud.nacos.config.namespace常用場景之一是不同環境的配置的區分隔離,例如開發測試環境和生產環境的資源隔離等。
    AccessKeyspring.cloud.nacos.config.access-key
    SecretKeyspring.cloud.nacos.config.secret-key
    相對路徑spring.cloud.nacos.config.context-path服務端 API 的相對路徑
    接入點spring.cloud.nacos.config.endpointUTF-8地域的某個服務的入口域名,通過此域名可以動態地拿到服務端地址
    是否開啟監聽和自動刷新spring.cloud.nacos.config.refresh-enabledtrue

    10.使用Nacos總結

    • 1.引入Nacos依賴

    • 2.配置Nacos數據源

    • 3.配置中心配置數據集DataId和配置內容

    • 4.開啟動態刷新配置@RefreshScope

    • 5.獲取配置項的值@value

    • 6.優先使用配置中心的配置

    • 7.使用命名空間namespace來創建各服務的配置

    • 8.使用分組group來區分不同環境

    • 9.使用多配置集extension-configs區分不同類型的配置

    6.5 SpringCloud整合Gateway網關

    1.Gateway網關介紹

    • 網關:流量的入口

    • 網關常用功能:路由轉發,權限校驗,限流控制

    • Spring Cloud Gateway是Spring Cloud官方推出的第二代網關框架

    • Spring Cloud Gateway取代了netflix的Zuul網關

    2.Gateway原理

    PassJava項目中,小程序和管理后臺請求先訪問到API網關.

    API網關通過注冊中心實時感知微服務的狀態的路由地址,準確地將請求路由到各個服務.

    Spring Cloud Gateway

    官方文檔:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/

    Gateway原理
    • 請求到達網關后,先經過斷言Predicate,是否符合某個路由規則

    • 如果符合,則按路由規則路由到指定地址

    • 請求和響應都可以通過過濾器Filter進行過濾

    3.創建Gateway 模塊

    • 適用Spring 初始化器創建Gateway module

    Spring 初始化器
    • 創建module

    Gateway module
    • 選擇Gateway依賴

    選擇Gateway依賴
    • 引入Gateway模塊

    <module>passjava-gateway</module>

    4.配置Gateway

    • 引入Nacos組件

    因common模塊引入了nacos注冊中心組件,所以我們可以直接引用common模塊

    <dependency><groupId>com.jackson0714.passjava</groupId><artifactId>passjava-common</artifactId><version>0.0.1-SNAPSHOT</version> </dependency>
    • 應用類上添加注解@EnableDiscoveryClient

    @RefreshScope @EnableDiscoveryClient @SpringBootApplication(exclude?=?{DataSourceAutoConfiguration.class}) public?class?PassjavaGatewayApplication?{public?static?void?main(String[]?args)?{SpringApplication.run(PassjavaGatewayApplication.class,?args);} }

    5.使用Gateway demo

    • 新建application.yml文件

      spring:cloud:gateway:routes:-?id:?route_qquri:?http://www.qq.compredicates:-?Query=url,qq-?id:?route_baiduuri:?http://www.baidu.compredicates:-?Query=url,baidu

      第一條路由規則:當請求路徑中包含url=qq,則跳轉到http://www.qq.com

      第二條路由規則:當請求路徑中包含url=baidu,則跳轉到http://www.baidu.com

    后續在PassJava項目中使用Gateway的強大功能.

    6.6 整合OSS對象存儲

    1.緣起

    文件上傳在系統中用的很頻繁,所以我們需要將上傳的文件進行存儲,傳統的將文件上傳到本機已不適用分布式系統。自己搭建文件服務器有復雜性和維護成本。所以我們可以采用市面上成熟的文件存儲服務,如阿里云的OSS對象存儲服務。

    上傳圖片

    每個 OSS 的用戶都會用到上傳服務。Web 端常見的上傳方法是用戶在瀏覽器或 APP 端上傳文件到應用服務器,應用服務器再把文件上傳到 OSS。具體流程如下圖所示。

    和數據直傳到 OSS 相比,以上方法有三個缺點:

    • 上傳慢:用戶數據需先上傳到應用服務器,之后再上傳到OSS。網絡傳輸時間比直傳到OSS多一倍。如果用戶數據不通過應用服務器中轉,而是直傳到OSS,速度將大大提升。而且OSS采用BGP帶寬,能保證各地各運營商之間的傳輸速度。

    • 擴展性差:如果后續用戶多了,應用服務器會成為瓶頸。

    • 費用高:需要準備多臺應用服務器。由于OSS上傳流量是免費的,如果數據直傳到OSS,不通過應用服務器,那么將能省下幾臺應用服務器。

    2.技術方案

    2.1 服務端簽名后直傳

    2.1.1 背景

    采用JavaScript客戶端直接簽名(參見JavaScript客戶端簽名直傳)時,AccessKeyID和AcessKeySecret會暴露在前端頁面,因此存在嚴重的安全隱患。因此,OSS提供了服務端簽名后直傳的方案。

    2.1.2 原理介紹

    原理介紹

    服務端簽名后直傳的原理如下:

  • 用戶發送上傳Policy請求到應用服務器。

  • 應用服務器返回上傳Policy和簽名給用戶。

  • 用戶直接上傳數據到OSS。

  • 3.實現案例

    3.1 開通阿里云OSS

    • 登錄阿里云官網

      https://www.aliyun.com/sale-season/2020/procurement-new-members?userCode=thp9caen

    登錄阿里云官網 創建Bucket 存儲桶
    • 創建Bucket 存儲桶

    • 獲取accesskey id和secret

    獲取accesskey id和secret

    獲取accesskey id和secret

    獲取accesskey id和secret 分配權限
    • 分配權限

      分配 管理對象存儲服務(OSS)權限

    3.2 使用OSS SDK

    3.2.1 安裝SDK

    在Maven項目中加入依賴項

    https://help.aliyun.com/document_detail/32009.html?spm=a2c4g.11186623.6.769.2c5145dc4TUgTa <dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.8.0</version> </dependency>

    3.2.2 ?上傳文件到OSS

    @Test void?testUploadByOss()?throws?FileNotFoundException?{// Endpoint以杭州為例,其它Region請按實際情況填寫。String?endpoint?=?"http://oss-cn-beijing.aliyuncs.com";//?阿里云主賬號AccessKey擁有所有API的訪問權限,風險很高。強烈建議您創建并使用RAM賬號進行API訪問或日常運維,請登錄 https://ram.console.aliyun.com 創建RAM賬號。String?accessKeyId?=?"xxxx";String?accessKeySecret?=?"xxxx";String?bucketName?=?"passjava";//?<yourObjectName>上傳文件到OSS時需要指定包含文件后綴在內的完整路徑,例如abc/efg/123.jpg。String?localFile?=?"C:\\Users\\Administrator\\Pictures\\coding_java.png";String?fileKeyName?=?"coding_java.png";//?創建OSSClient實例。OSS?ossClient?=?new?OSSClientBuilder().build(endpoint,?accessKeyId,?accessKeySecret);InputStream?inputStream?=?new?FileInputStream(localFile);ossClient.putObject(bucketName,?fileKeyName,?inputStream);//?關閉OSSClient。ossClient.shutdown(); }

    3.3 整合Spring Cloud Alicloud OSS

    3.3.1 ?passjava-common項目引入spring-cloud-starter-alicloud-oss依賴

    <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alicloud-oss</artifactId> </dependency>

    3.3.2 ?配置alicloud oss

    spring:cloud:alicloud:access-key:?xxxxsecret-key:?xxxxoss:endpoint:?oss-cn-beijing.aliyuncs.com

    3.3.3 ?測試上傳

    @Autowired OSSClient?ossClient;@Test void?testUploadByAlicloudOss()?throws?FileNotFoundException?{String?bucketName?=?"passjava";String?localFile?=?"C:\\Users\\Administrator\\Pictures\\coding_java.png";String?fileKeyName?=?"coding_java.png";InputStream?inputStream?=?new?FileInputStream(localFile);ossClient.putObject(bucketName,?fileKeyName,?inputStream);ossClient.shutdown(); }

    上傳成功

    3.4 獲取服務端簽名

    3.4.1 準備工作:

    • 創建一個第三方服務passjava-thirdparty

    • 引入passjava-common模塊,并且排除mybatis-plus依賴

    <dependency><groupId>com.jackson0714.passjava</groupId><artifactId>passjava-common</artifactId><version>0.0.1-SNAPSHOT</version><exclusions><exclusion><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></exclusion></exclusions> </dependency>
    • 配置服務發現和端口

    spring:cloud:nacos:discovery:server-addr:?127.0.0.1:8848application:name:?passjava-thirdparty server:port:?14000
    • 配置配置中心

    spring.application.name=passjava-thirdparty spring.cloud.nacos.config.server-addr=127.0.0.1:8848 spring.cloud.nacos.config.namespace=passjava-thirdpartyspring.cloud.nacos.config.extension-configs[0].data-id=oss.yml spring.cloud.nacos.config.extension-configs[0].group=DEFAULT_GROUP spring.cloud.nacos.config.extension-configs[0].refresh=true
    • 配置Nacos命名空間和oss.yml

    spring:cloud:alicloud:access-key:?LTAI4G3KxBJ26EUbWsenmqhPsecret-key:?RHtADVlvlKJvVBQnFNNvnne9p4NwnAoss:endpoint:?oss-cn-beijing.aliyuncs.com

    配置oss.yml
    • 開啟服務發現@EnableDiscoveryClient

    @EnableDiscoveryClient @SpringBootApplication public?class?PassjavaThirdpartyApplication?{public?static?void?main(String[]?args)?{SpringApplication.run(PassjavaThirdpartyApplication.class,?args);} }

    3.4.2 獲取簽名類

    @RestController @RequestMapping("/thirdparty/v1/admin/oss") public?class?OssController?{@AutowiredOSS?ossClient;@Value("${spring.cloud.alicloud.access-key}")private?String?accessId;@Value("${spring.cloud.alicloud.secret-key}")private?String?accessKey;@Value("${spring.cloud.alicloud.oss.endpoint}")private?String?endpoint;@Value("${spring.cloud.alicloud.oss.bucket}")private?String?bucket;@RequestMapping("/getPolicy")public?Map<String,?String>?getPolicy()?{String?host?=?"https://"?+?bucket?+?"."?+?endpoint;?//?host的格式為?bucketname.endpoint// callbackUrl為?上傳回調服務器的URL,請將下面的IP和Port配置為您自己的真實信息。//?String?callbackUrl?=?"http://88.88.88.88:8888";String?formatDate?=?new?SimpleDateFormat("yyyy-MM-dd").format(new?Date());String?dir?=?formatDate?+?"/";?//?用戶上傳文件時指定的前綴。Map<String,?String>?respMap?=?new?LinkedHashMap<String,?String>();try?{long?expireTime?=?30;long?expireEndTime?=?System.currentTimeMillis()?+?expireTime?*?1000;Date?expiration?=?new?Date(expireEndTime);PolicyConditions?policyConds?=?new?PolicyConditions();policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE,?0,?1048576000);policyConds.addConditionItem(MatchMode.StartWith,?PolicyConditions.COND_KEY,?dir);String?postPolicy?=?ossClient.generatePostPolicy(expiration,?policyConds);byte[]?binaryData?=?postPolicy.getBytes("utf-8");String?encodedPolicy?=?BinaryUtil.toBase64String(binaryData);String?postSignature?=?ossClient.calculatePostSignature(postPolicy);respMap.put("accessid",?accessId);respMap.put("policy",?encodedPolicy);respMap.put("signature",?postSignature);respMap.put("dir",?dir);respMap.put("host",?host);respMap.put("expire",?String.valueOf(expireEndTime?/?1000));}?catch?(Exception?e)?{//?Assert.fail(e.getMessage());System.out.println(e.getMessage());}?finally?{ossClient.shutdown();}return?respMap;} }

    測試接口

    http://localhost:14000/api/thirdparty/v1/admin/oss/getPolicy? {"accessid":?"LTAI4G3KxBJ26EUbWsenmqhP","policy":?"eyJleHBpcmF0aW9uIjoiMjAyMC0wNC0yOFQwMjozMzowNy42NzNaIiwiY29uZGl0aW9ucyI6W1siY29udGVudC1sZW5ndGgtcmFuZ2UiLDAsMTA0ODU3NjAwMF0sWyJzdGFydHMtd2l0aCIsIiRrZXkiLCIyMDIwLTA0LTI4LyJdXX0=","signature":?"pfn4cggFTMMNqTs+qUnDN5c+k5M=","dir":?"2020-04-28/","host":?"https://passjava.oss-cn-beijing.aliyuncs.com","expire":?"1588041187" }

    3.4.3 配置網關路由

    因為前端頁面配置的統一訪問路徑是http://localhost:8060/api/,所以需要將訪問thirdparty的服務通過網關路由到thirdparty服務

    將請求 http://localhost:8060/api/thirdparty/v1/admin/oss/getPolicy 轉發到 http://localhost:14000/api/thirdparty/v1/admin/oss/getPolicy?

    配置網關:

    spring:cloud:gateway:routes:-?id:?route_thirdparty?#?題目微服務路由規則uri:?lb://passjava-thirdparty?#?負載均衡,將請求轉發到注冊中心注冊的assjava-thirdparty服務predicates:?#?斷言-?Path=/api/thirdparty/**?#?如果前端請求路徑包含?api/thirdparty,則應用這條路由規則filters:?#過濾器-?RewritePath=/api/(?<segment>.*),/$\{segment}?#?將跳轉路徑中包含的api替換成空

    測試可以上傳成功

    3.4.4 配置跨域訪問

    配置跨域訪問,所有post請求都可以跨域訪問

    配置跨域訪問

    3.4.5 Web端上傳組件

    • 單文件上傳組件

    singleUpload.vue <template>?<div><el-uploadaction="http://passjava.oss-cn-beijing.aliyuncs.com":data="dataObj"list-type="picture":multiple="false"?:show-file-list="showFileList":file-list="fileList":before-upload="beforeUpload":on-remove="handleRemove":on-success="handleUploadSuccess":on-preview="handlePreview"><el-button?size="small"?type="primary">點擊上傳</el-button><div?slot="tip"?class="el-upload__tip">只能上傳jpg/png文件,且不超過10MB</div></el-upload><el-dialog?:visible.sync="dialogVisible"><img?width="100%"?:src="fileList[0].url"?alt=""></el-dialog></div> </template> <script>import?{policy}?from?'./policy'import?{?getUUID?}?from?'@/utils'export?default?{name:?'singleUpload',props:?{value:?String},computed:?{imageUrl()?{return?this.value;},imageName()?{if?(this.value?!=?null?&&?this.value?!==?'')?{return?this.value.substr(this.value.lastIndexOf("/")?+?1);}?else?{return?null;}},fileList()?{return?[{name:?this.imageName,url:?this.imageUrl}]},showFileList:?{get:?function?()?{return?this.value?!==?null?&&?this.value?!==?''&&?this.value!==undefined;},set:?function?(newValue)?{}}},data()?{return?{dataObj:?{policy:?'',signature:?'',key:?'',ossaccessKeyId:?'',dir:?'',host:?'',//?callback:'',},dialogVisible:?false};},methods:?{emitInput(val)?{this.$emit('input',?val)},handleRemove(file,?fileList)?{this.emitInput('');},handlePreview(file)?{this.dialogVisible?=?true;},beforeUpload(file)?{let?_self?=?this;return?new?Promise((resolve,?reject)?=>?{policy().then(response?=>?{_self.dataObj.policy?=?response.data.policy;_self.dataObj.signature?=?response.data.signature;_self.dataObj.ossaccessKeyId?=?response.data.accessid;_self.dataObj.key?=?response.data.dir?+?getUUID()+'_${filename}';_self.dataObj.dir?=?response.data.dir;_self.dataObj.host?=?response.data.host;resolve(true)}).catch(err?=>?{reject(false)})})},handleUploadSuccess(res,?file)?{console.log("上傳成功...")this.showFileList?=?true;this.fileList.pop();this.fileList.push({name:?file.name,?url:?this.dataObj.host?+?'/'?+?this.dataObj.key.replace("${filename}",file.name)?});this.emitInput(this.fileList[0].url);}}} </script> <style></style>
    • 獲取簽名的JS文件

    import?http?from?'@/utils/httpRequest.js' export?function?policy?()?{return?new?Promise((resolve)?=>?{http({url:?http.adornUrl('/thirdparty/v1/admin/oss/getPolicy'),method:?'get',params:?http.adornParams({})}).then(({?data?})?=>?{resolve(data)})}) }
    • 使用單文件上傳組件

    使用上傳圖片組件 <el-form-item?label="類型logo路徑"?prop="logoUrl"><single-upload?v-model="dataForm.logoUrl"></single-upload> </el-form-item><script>import?SingleUpload?from?"@/components/upload/singleUpload"?//?引入單文件上傳組件export?default?{components:{?SingleUpload?}} </script>

    上傳圖片

    上傳文件成功

    6.7 整合統一異常處理

    1.緣起

    我們在寫代碼的時候,通常會在方法里面添加各種try catch來捕獲異常,會發現有很多重復的代碼,所以我們可以整合統一異常處理來優化代碼結構。

    攔截異常并統一處理我們可以用到@RestControllerAdvice注解

    2.自定義異常處理類

    • 添加統一異常處理類注解@RestControllerAdvice

    • 添加日志注解@Slf4j

    • 添加異常處理方法注解@ExceptionHandler

    package?com.jackson0714.passjava.question.exception;/* *?集中處理所有異常*/ @Slf4j @RestControllerAdvice(basePackages?=?"com.jackson0714.passjava.question.controller") public?class?PassjavaExceptionControllerAdvice?{@ResponseBody@ExceptionHandler(value=?MethodArgumentNotValidException.class)public?R?handleValidException(MethodArgumentNotValidException?e)?{log.error("數據校驗出現問題{},異常類型:{}",?e.getMessage(),?e.getClass());BindingResult?bindingResult?=?e.getBindingResult();Map<String,?String>?errorMap?=?new?HashMap<>();bindingResult.getFieldErrors().forEach((fieldError)->{errorMap.put(fieldError.getField(),?fieldError.getDefaultMessage());});return?R.error(BizCodeEnum.VALID_EXCEPTION.getCode(),?BizCodeEnum.VALID_EXCEPTION.getMsg()).put("data",?errorMap);}@ExceptionHandler(value=Throwable.class)public?R?handleException(Throwable?throwable)?{log.error("未知異常{},異常類型:{}",?throwable.getMessage(),?throwable.getClass());return?R.error(BizCodeEnum.UNKNOWN_EXCEPTION.getCode(),?BizCodeEnum.UNKNOWN_EXCEPTION.getMsg());} }

    3.推薦的系統錯誤碼

    3.1 錯誤碼和錯誤信息定義類

    • 1.錯誤碼長度:5個數字

    • 2.前兩位:業務場景

    • 3.后三位:錯誤碼

    10:通用業務001:參數格式校驗錯誤(10001) 11:會員業務 12:題目業務 13:內容業務 14:學習業務

    3.2 錯誤碼枚舉類

    com.jackson0714.common.exception.BizCodeEnum

    定義了兩種異常枚舉:系統未知異常、參數格式校驗失敗

    package?com.jackson0714.common.exception;public?enum?BizCodeEnum?{UNKNOWN_EXCEPTION(10000,?"系統未知異常"),VALID_EXCEPTION(10001,?"參數格式校驗失敗");private?int?code;private?String?msg;BizCodeEnum(int?code,?String?msg)?{this.code?=?code;this.msg?=?msg;}public?int?getCode()?{return?code;}public?String?getMsg()?{return?msg;} }

    4.測試代碼

    測試場景1:校驗參數displayOrder必須為正整數,如果displayOrder不為正整數,則會拋出異常

    • 1.實體類上添加校驗注解@Positive

    /***?排序*/ @Positive private?Integer?displayOrder;
    • 2.controller類里面添加save方法,并添加校驗參數注解@Valid

    /** *?保存 */ @RequestMapping("/save") public?R?save(@Valid?@RequestBody?QuestionEntity?question){questionService.save(question);return?R.ok(); }

    測試:

    用Postman工具調用save方法

    請求地址:

    http://192.168.10.160:8060/api/question/v1/admin/question/save

    請求參數:

    {"displayOrder":?0.2 }

    返回結果:

    {"msg":?"參數格式校驗失敗","code":?10001,"data":?{"displayOrder":?"必須是正數"} } “

    測試場景2:對于代碼里面直接拋出的異常,也可以handle

    1.controller類里面添加查詢題目的方法,并拋出Exception異常

    /** *?信息 */ @RequestMapping("/info/{id}") //@RequiresPermissions("question:question:info") public?R?info(@PathVariable("id")?Long?id)?throws?Exception?{QuestionEntity?question?=?questionService.getById(id);throw?new?Exception("test");//return?R.ok().put("question",?question); }

    測試:

    用Postman工具調用save方法

    請求地址:

    http://192.168.10.160:8060/api/question/v1/admin/question/save

    返回結果:

    {"msg":?"系統未知異常","code":?10000 }

    證明統一處理方法被調用了:

    @ExceptionHandler(value=Throwable.class) public?R?handleException(Throwable?throwable)?{return?R.error(BizCodeEnum.UNKNOWN_EXCEPTION.getCode(),?BizCodeEnum.UNKNOWN_EXCEPTION.getMsg()); } 推薦文章
    • 硬剛一周,3W字總結,一年的經驗告訴你如何準備校招!

    • 今年的校招,Java 好拿 offer 嗎?

    • 10月了,該聊聊今年秋招了!

    • 聊聊在騰訊實習快一個月的感受

    原創電子書歷時整整一年總結的?Java 面試 + Java 后端技術學習指南,這是本人這幾年及校招的總結,各種高頻面試題已經全部進行總結,按照章節復習即可,已經拿到了大廠offer。 原創思維導圖掃碼或者微信搜?程序員的技術圈子?回復?面試?領取原創電子書和思維導圖。

    總結

    以上是生活随笔為你收集整理的5w 字 | 172 图 | 超级赛亚级 Spring Cloud 实战的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    久久精品网址 | 日韩一级电影在线观看 | 免费亚洲婷婷 | 久久激情电影 | 五月婷婷欧美 | 国产美女视频免费观看的网站 | 免费观看黄 | 五月婷婷黄色网 | 在线观看免费观看在线91 | 日韩成人精品一区二区 | 亚洲精品一区二区三区在线观看 | 在线看日韩av| 国产成人黄色av | 日韩在线观看精品 | 91精品国产自产在线观看永久 | 五月av在线| 在线观看免费av网 | 免费99| 欧美日韩精品久久久 | 国产久草在线 | 亚洲在线看 | 综合色影院| 美女国内精品自产拍在线播放 | 欧美日韩国产伦理 | 日本中文字幕观看 | 成人精品视频久久久久 | 激情影院在线观看 | 欧美精品久久久久久久久久久 | 国产精品久久久久久久7电影 | www.福利视频 | 久久婷婷精品视频 | 2018亚洲男人天堂 | 又黄又网站 | 色婷婷亚洲 | 免费视频区 | 色婷婷88av视频一二三区 | 黄色a视频 | 精品国产乱码久久久久久浪潮 | 波多野结衣一区三区 | 国产亚洲91 | 丝袜美腿亚洲综合 | 人人爱在线视频 | 四虎在线视频免费观看 | 91麻豆精品国产91久久久无限制版 | 成人午夜电影久久影院 | 国产淫a| 国产精品一区二区美女视频免费看 | 国产久草在线观看 | 国产免费美女 | 香蕉视频导航 | 国产一区二区在线免费视频 | 国产手机在线播放 | 欧美精品久久久久久久久久白贞 | 精品人妖videos欧美人妖 | 奇米影视8888在线观看大全免费 | 99精品视频播放 | 日韩av网页| 亚洲一级片在线看 | 一区二区激情 | 精品国产乱码 | av在线播放免费 | 黄色片网站av | 99在线精品视频在线观看 | 欧美伦理一区 | 黄色软件在线观看视频 | 99久久er热在这里只有精品15 | 日韩精品免费在线 | 国产精品第一 | 久久免费电影网 | 欧美日韩国产精品一区二区三区 | 欧美色噜噜 | 久久理论电影网 | 人人模人人爽 | 午夜.dj高清免费观看视频 | 久久免费国产视频 | 91丨精品丨蝌蚪丨白丝jk | 国产精品久久久区三区天天噜 | 久久99久久99精品免观看粉嫩 | 久久久婷 | 久久免费国产 | 亚洲永久精品一区 | www黄在线| 久久久www成人免费毛片麻豆 | 成片免费观看视频 | 自拍超碰在线 | 国产精品免费视频网站 | 不卡的av电影 | 色综合 久久精品 | 九九久久在线看 | 中文字幕在线看视频国产中文版 | 亚洲成人一区 | 狠狠干综合网 | 成人久久久精品国产乱码一区二区 | 亚洲免费婷婷 | 手机色站| 91av在线播放视频 | 国产色网 | 天天色综合久久 | 狠狠色香婷婷久久亚洲精品 | 亚洲一级电影在线观看 | 久久国产亚洲精品 | 欧洲成人av | a级国产毛片 | 亚洲免费在线看 | 日韩欧美成 | 天天色婷婷 | 999久久a精品合区久久久 | 视频三区在线 | 亚洲成a人片在线www | 色综合久久悠悠 | 免费成人结看片 | 国内亚洲精品 | 成人av视屏| 在线黄色国产 | 亚洲最新视频在线播放 | va视频在线 | 国产视频第二页 | 精品久久久久一区二区国产 | 91麻豆精品久久久久久 | 久久免费视频5 | 成人精品一区二区三区电影免费 | 玖玖爱免费视频 | 91超级碰碰 | 最新99热 | 亚洲永久精品国产 | 亚洲最新视频在线播放 | 欧美精品久久久久性色 | 午夜.dj高清免费观看视频 | 欧美亚洲国产一卡 | 亚洲天堂网在线视频观看 | 91精品日韩 | 啪啪凸凸 | 欧美伊人网 | 亚洲精品乱码久久久久久写真 | 曰本三级在线 | 免费看黄色小说的网站 | 国产高清在线观看 | 在线亚洲欧美视频 | 久草在线这里只有精品 | 日韩网站免费观看 | 日韩av在线一区二区 | 麻豆视传媒官网免费观看 | 久久久久国产成人免费精品免费 | 免费h漫在线观看 | 在线免费观看国产 | 久久乐九色婷婷综合色狠狠182 | 91视频在线观看下载 | 在线观看免费高清视频大全追剧 | 国产成人在线精品 | 激情综合色播五月 | 国产永久网站 | 麻豆精品在线视频 | 国内视频在线观看 | 最近中文字幕免费av | 伊人视频 | 国产不卡av在线播放 | 91在线中文字幕 | 在线看黄网站 | 欧美日韩一级在线 | 亚洲伊人第一页 | 少妇视频一区 | 高清国产一区 | 国产专区欧美专区 | 亚洲欧洲日韩 | 成人av网站在线播放 | 在线免费看片 | 亚洲精品乱码久久久久久按摩 | 婷婷激情小说网 | 91精品国产91p65 | 日韩高清一区在线 | 精品欧美在线视频 | 日韩免费观看一区二区 | 国产麻豆精品久久一二三 | 中文在线字幕免费观看 | 最新av网址大全 | 亚洲精品视频中文字幕 | 久久不卡日韩美女 | 伊人久久国产精品 | 久久激情视频网 | 黄色网在线播放 | 天天天干 | 狠狠狠狠狠操 | 99热这里只有精品免费 | 日本中文在线播放 | 久久久国产精品成人免费 | 欧美一级片免费在线观看 | 国产亚洲精品成人 | 国产一区不卡在线 | 久色免费视频 | 久久69精品久久久久久久电影好 | 久草在线高清视频 | 91香蕉视频 mp4| 亚洲精品影视在线观看 | 在线观看日韩免费视频 | 91在线最新 | av免费在线播放 | 国产精品视频全国免费观看 | 色综合久久久久久中文网 | 天天插日日插 | 日韩a免费 | 综合网色 | 日本久久电影 | 国产精久久久 | 成年人视频免费在线播放 | 色小说在线 | 91精品视频一区 | 欧美精品在线视频 | 久久影视精品 | 超碰免费在线公开 | 亚州av网站大全 | 国产一区二区三区免费在线观看 | 中文在线中文资源 | a级片久久久 | 欧美亚洲专区 | 国产小视频在线看 | 亚洲精品2区 | 伊人永久在线 | 韩日成人av | 男女男视频 | 免费视频一区二区 | 日日麻批40分钟视频免费观看 | 99视频 | 色婷婷伊人 | 一级欧美黄 | 一区二区三区四区影院 | 69久久99精品久久久久婷婷 | 成人免费视频观看 | 永久av免费在线观看 | 人人澡av| 国产成人精品一区一区一区 | 在线免费国产 | 成 人 黄 色 视频 免费观看 | 日韩成人不卡 | 毛片网站在线观看 | 视频在线国产 | av片在线看 | 日免费视频| 91精品国产自产老师啪 | 日日夜夜操操操操 | 深爱开心激情 | 91香蕉久久 | 国产成人精品午夜在线播放 | 日韩专区在线观看 | 久久久久激情电影 | 免费亚洲一区二区 | 日躁夜躁狠狠躁2001 | 欧美影院久久 | 在线观看国产亚洲 | 国产黄色精品在线 | 91日韩国产| 国产亚洲字幕 | 深爱激情开心 | 在线中文字幕观看 | 婷婷中文在线 | 日韩av网站在线播放 | av色综合网 | 亚洲精品在线观看免费 | 天天干夜夜夜 | 99在线视频精品 | 成年人在线免费看片 | 日日精品| 99精品欧美一区二区蜜桃免费 | 国产经典av | 激情丁香综合五月 | 丁香色婷婷 | 丁香婷婷网 | 天天操天天舔天天干 | 国产精品18久久久久久久久久久久 | 日韩色高清| 免费日韩一区 | 免费aa大片| 久久久精品欧美 | 天天草av| 天天爽夜夜爽精品视频婷婷 | 免费合欢视频成人app | 一区免费视频 | 国产午夜剧场 | 99久久国产免费看 | 91爱在线| 精油按摩av | 欧美日韩不卡在线观看 | 国产精品一区久久久久 | 久久久精品国产一区二区 | 国产亚洲精品久久久久久无几年桃 | 美女视频黄频大全免费 | 爱色av.com| 五月导航| 日韩1页 | 亚洲精品福利在线 | 欧美成人性战久久 | 亚洲日本中文字幕在线观看 | a在线免费观看视频 | 黄色网www| 亚洲国产成人av网 | 成人av一区二区兰花在线播放 | 亚洲一级电影 | 狠狠干五月天 | 99高清视频有精品视频 | 在线观看www. | 国产精品久久久久影院 | 欧美片一区二区三区 | 777久久久 | 丁香花在线视频观看免费 | 国产福利资源 | 免费成视频 | 国产精品一区欧美 | 精品国产免费观看 | 五月天中文字幕 | 99久久婷婷国产精品综合 | 91精品视频在线免费观看 | 国产三级视频在线 | 午夜免费福利视频 | 中文字幕中文字幕中文字幕 | 在线电影播放 | 国产视频高清 | www日韩欧美 | 中文字幕一区二区三区久久 | 欧美日韩中文在线观看 | 国产综合在线观看视频 | 中文在线a天堂 | 91麻豆传媒 | 久久伊人精品天天 | 最新中文字幕在线播放 | 婷婷六月久久 | 中文字幕免费观看全部电影 | 欧女人精69xxxxxx | 玖玖精品在线 | avove黑丝| 亚洲va天堂va欧美ⅴa在线 | 99视频在线观看免费 | wwxxxx日本 | 99久久99视频| 国产中文字幕在线播放 | 国产高清视频在线播放一区 | 97av在线 | 黄色a在线观看 | 亚洲精品在线观看中文字幕 | 97视频在线观看网址 | 中文字幕在线观看第二页 | 久久av中文字幕片 | 久久人人爽人人 | 婷婷五情天综123 | 久久精品伊人 | 国产资源在线视频 | 韩国中文三级 | 六月色播| 91成人免费看片 | 成年人视频免费在线 | 成人影视免费 | 五月婷影院 | 五月天狠狠操 | 97国产在线视频 | 欧美性猛片 | 97超碰精品| 国产无套视频 | 久热色超碰 | 黄色一级网 | 欧美性色xo影院 | 五月激情站| 国产精品视频免费在线观看 | 国产成人精品一区二区三区在线 | 99九九99九九九视频精品 | 国产成人精品一区二区三区在线观看 | 久久www免费人成看片高清 | 国产精品久久久久久电影 | 丝袜护士aⅴ在线白丝护士 天天综合精品 | 亚洲资源在线观看 | 成年人国产在线观看 | 一区二区三区高清不卡 | 免费在线成人av电影 | 亚洲综合色站 | 天天骚夜夜操 | 久久久国产视频 | 怡春院av | 国产精品久久久久久久久免费 | 欧美做受高潮 | 蜜桃传媒一区二区 | 韩日精品在线观看 | 欧美一二三视频 | 超碰免费公开 | 国产精品日韩精品 | 日韩av男人的天堂 | 91精品国产九九九久久久亚洲 | 欧美国产日韩激情 | 久久国产精品成人免费浪潮 | 综合久久久久久 | 亚洲黄在线观看 | 亚洲视频免费在线观看 | 91精品爽啪蜜夜国产在线播放 | 一级黄色免费 | 亚洲黄色av网址 | 中文字幕av在线 | 狠狠干夜夜操天天爽 | 69国产盗摄一区二区三区五区 | 一级黄色片在线 | 五月婷在线 | 国产免费又爽又刺激在线观看 | 免费看国产曰批40分钟 | 99草在线视频 | 欧美日韩观看 | 亚洲丁香久久久 | 成人久久久久久久久 | 99视频在线观看一区三区 | 人人爽久久涩噜噜噜网站 | 日韩综合视频在线观看 | 91成熟丰满女人少妇 | 国产91在线观看 | 国产裸体无遮挡 | 欧美一级视频一区 | 一级一片免费观看 | 日韩av网页| 九九九在线观看视频 | 国产黄色特级片 | 伊人电影在线观看 | 欧美日韩一级视频 | 午夜精品久久久久久久久久久久 | 国产亚州av | 激情综合啪 | 特级片免费看 | 亚州精品天堂中文字幕 | 在线观看不卡视频 | 久久99日韩 | 久久九九网站 | 波多野结衣在线播放视频 | 99热在线免费观看 | 激情丁香婷婷 | 国产精品久久久久久影院 | 欧美一级在线 | 亚洲国产精品女人久久久 | 91黄视频在线 | 久久96 | 一区精品在线 | 99在线视频播放 | 天天色天天射天天综合网 | 欧美人人 | 五月天综合 | 1000部18岁以下禁看视频 | 久久影院精品 | av免费试看| 久久久久伊人 | 五月婷丁香网 | 91中文在线视频 | 国产91九色视频 | 成人高清av在线 | 欧美在线视频第一页 | 在线观看免费av网站 | 午夜视频在线网站 | 亚洲免费色 | 91免费版成人 | 亚洲日韩中文字幕在线播放 | 娇妻呻吟一区二区三区 | 亚洲精品视频免费在线 | 国内精品久久久久久久影视简单 | 国产成人久久久77777 | 97av在线视频免费播放 | 91一区二区在线 | 久久噜噜少妇网站 | 久久a v视频 | 久久视频网 | 亚洲欧美日本A∨在线观看 青青河边草观看完整版高清 | 精品视频免费观看 | 麻豆高清免费国产一区 | 欧美日韩不卡一区二区三区 | 亚洲欧美成人 | 久久性生活片 | 国产一级片免费播放 | 激情综合色播五月 | 久久精品国产免费看久久精品 | 免费成人在线电影 | 在线观看不卡视频 | 六月天色婷婷 | 亚洲精品国产拍在线 | 免费福利视频导航 | 二区三区精品 | 夜夜夜影院 | 日本电影久久 | 国产女人18毛片水真多18精品 | 中文有码在线视频 | 在线免费中文字幕 | 91麻豆视频| 久久国内精品视频 | 久久视频国产精品免费视频在线 | 亚洲黄色免费在线看 | 欧美日韩亚洲在线 | 手机在线看永久av片免费 | 亚洲精品五月天 | 国产成人av免费在线观看 | 久久九九免费视频 | 欧美在线久久 | 欧美大片aaa| 亚洲va欧美va国产va黑人 | 日韩黄色软件 | 天天看天天干天天操 | 久久在现| 中国一级片视频 | 亚洲高清在线观看视频 | a极黄色片 | 久久激情片 | 亚洲免费在线观看视频 | 欧美色就是色 | 日韩精品一区二区三区在线播放 | 超碰在线网 | 亚洲九九九| 欧美另类v | 欧美性做爰猛烈叫床潮 | 在线三级播放 | 808电影免费观看三年 | v片在线看 | 欧洲精品视频一区二区 | 色综合天天色综合 | 在线观看爱爱视频 | 天天干天天操天天射 | 亚洲在线观看av | 久久久久色 | www.夜夜草 | 91免费高清视频 | 国产精品爽爽久久久久久蜜臀 | 香蕉久久国产 | 中文字幕日韩精品有码视频 | 日韩欧美视频免费看 | 91精品啪在线观看国产 | 欧美日韩亚洲在线观看 | 精品国产免费av | 久久99久久99精品免视看婷婷 | 欧美日韩裸体免费视频 | 97人人模人人爽人人喊中文字 | 97视频免费播放 | 午夜婷婷在线播放 | 91精品91| 成人毛片网 | 操操综合| 黄色的网站免费看 | 国产福利小视频在线 | 亚洲精品国产精品乱码不99热 | 国产精品久久久久久影院 | 手机av看片 | 最新免费av在线 | 国产在线专区 | 久亚洲精品 | 97超碰资源 | 人人看人人做人人澡 | 亚洲精品456在线播放乱码 | 三上悠亚一区二区在线观看 | 日韩精品一区二区三区视频播放 | 69热国产视频 | 天天草天天干天天射 | 在线免费精品视频 | 很黄很黄的网站免费的 | 狠狠的操你 | 免费观看性生活大片 | zzijzzij日本成熟少妇 | 丰满少妇在线观看资源站 | 久久综合婷婷国产二区高清 | 亚洲成人动漫在线观看 | 精品欧美小视频在线观看 | 国产91全国探花系列在线播放 | 亚洲视频久久久久 | www.五月激情.com | 日本久久久久久 | 91高清免费 | 国产一区二区高清视频 | 亚洲aⅴ一区二区三区 | 人人藻人人澡人人爽 | 久久久久久久av | 日韩中文三级 | 免费高清在线视频一区· | 国产麻豆果冻传媒在线观看 | 高清免费在线视频 | 三级黄在线 | 福利视频一区二区 | 国产 一区二区三区 在线 | www视频在线播放 | 国产精品福利在线播放 | 久久观看免费视频 | 999亚洲国产996395| 在线免费av网 | 久久在线视频精品 | 亚州av成人 | 玖玖在线资源 | 91在线视频观看 | 九九综合久久 | 色婷婷狠 | 国产一级免费在线 | 日本中文一级片 | 久久久人 | 九九视频免费观看视频精品 | 黄污污网站 | 三上悠亚一区二区在线观看 | 国内精品视频一区二区三区八戒 | 国产成在线观看免费视频 | 国产91精品在线播放 | 色天天久久 | av一本久道久久波多野结衣 | 欧美午夜理伦三级在线观看 | 最近中文字幕大全中文字幕免费 | 丁香花在线视频观看免费 | 国产在线观看你懂的 | 一区二区三区在线播放 | 波多野结衣视频一区二区 | 最近中文字幕在线播放 | 国产色影院 | 91久久精品一区二区二区 | 国产欧美日韩视频 | 一区二区三区中文字幕在线观看 | 精品国产一区二区三区噜噜噜 | 久久一区二区三区超碰国产精品 | 亚洲欧美综合精品久久成人 | 日韩在线视频不卡 | 久青草视频 | 国产无遮挡猛进猛出免费软件 | 在线电影日韩 | 人人澡人摸人人添学生av | 在线观看免费版高清版 | 色婷婷激情网 | 69av免费视频 | 免费午夜在线视频 | 国产精品美女网站 | 五月天久久久久久 | 久久久片| 毛片激情永久免费 | 天天躁天天躁天天躁婷 | 天天射天| 久久特级毛片 | 精品色999 | 色视频 在线 | 日韩xxx视频| 天天干,天天操,天天射 | 六月激情婷婷 | 国产啊v在线| 在线观看黄色 | 欧美另类69 | 日韩黄色在线电影 | 91精品国产欧美一区二区 | 精品国产诱惑 | 国产精品一区久久久久 | 在线观看麻豆av | 四虎在线免费 | 亚洲午夜久久久久久久久电影网 | 夜夜夜夜夜夜操 | 国产精品永久在线观看 | 97视频人人免费看 | 亚洲欧洲中文日韩久久av乱码 | 成人亚洲综合 | 中文字幕乱码电影 | 日韩在线不卡av | www.伊人网 | 日韩aa视频| 久久与婷婷 | 亚洲国产影院 | 国产又粗又硬又爽视频 | 久久国内精品99久久6app | 成人片在线播放 | 日韩va在线观看 | 久久婷亚洲五月一区天天躁 | 中文字幕在线有码 | 国产精品久久久久高潮 | 久久9999久久免费精品国产 | 亚洲国产日本 | 九九九电影免费看 | 久草国产在线观看 | 亚洲欧美国产精品va在线观看 | 亚洲理论在线观看电影 | 色综合 久久精品 | 国产日韩在线看 | 久久这里只有精品视频99 | 日韩精品中文字幕有码 | 天天爽夜夜操 | 日日夜夜综合网 | 在线国产不卡 | 日本中文在线播放 | 成人一区二区在线观看 | 午夜av免费 | 欧美成人猛片 | 在线视频第一页 | 国内少妇自拍视频一区 | 日韩高清免费在线观看 | 日韩中文字幕免费在线观看 | 成 人 黄 色 片 在线播放 | 免费麻豆网站 | 国产一区二区三区四区在线 | 国产高清免费在线观看 | 午夜999 | 777奇米四色 | 黄色福利网站 | 操操日日 | 欧美成人久久 | 久久99精品久久久久蜜臀 | 天天舔夜夜操 | 久久精品电影网 | 精品在线你懂的 | 99re久久精品国产 | 亚洲精品免费看 | 国产精品一区二区三区在线播放 | 亚州国产精品 | 久久久www免费电影网 | 国产剧情一区二区在线观看 | 久久免费黄色大片 | 国产在线看一区 | 欧美日韩在线电影 | 国产一级片免费视频 | 成人av免费电影 | 婷婷国产v亚洲v欧美久久 | 国产二区av | 天天综合网 天天 | 97自拍超碰 | 欧美一级大片在线观看 | 亚洲精品中文字幕在线观看 | 国产主播大尺度精品福利免费 | 啪啪肉肉污av国网站 | 国产在线视频不卡 | 日本特黄特色aaa大片免费 | 日韩亚洲在线视频 | 97超碰资源网| 久久任你操 | 免费看国产一级片 | 91一区在线观看 | 亚洲激情校园春色 | 在线成人av| 欧美日韩一区二区在线观看 | 国产一级电影在线 | 91在线91 | 国产最新视频在线 | 天天人人综合 | 在线欧美最极品的av | 高清av免费一区中文字幕 | www.av在线.com| 国产精品一区二区三区四区在线观看 | 国产精品免费麻豆入口 | 国产手机在线精品 | 午夜精品久久久久久久久久 | 最新色视频 | 中文字幕国产一区二区 | 国产精品乱码久久久久 | 国产中文字幕一区 | 亚洲婷婷在线 | 亚洲综合激情五月 | 色婷婷综合久久久 | 亚洲精品国产精品99久久 | 一级黄色大片在线观看 | 日韩高清成人 | 又黄又爽又湿又无遮挡的在线视频 | av在线播放快速免费阴 | 在线观看精品国产 | 亚洲精品麻豆视频 | a午夜在线 | 香蕉网址 | 天天拍天天色 | 狠狠五月婷婷 | 久久婷婷五月综合色丁香 | 伊人国产视频 | 九七在线视频 | 国产精品资源 | 国产精品久久久久久久久免费看 | 99re8这里有精品热视频免费 | 波多野结衣视频一区二区三区 | 久久人人精 | 国产一级二级在线 | 久久综合久久久久88 | 亚洲一区欧美精品 | 天天操欧美 | 人人射人人爱 | 国产91精品在线观看 | 中文字幕国产一区二区 | 99国产精品视频免费观看一公开 | 国产亚洲免费观看 | 91桃色在线观看视频 | 精品国精品自拍自在线 | 毛片网站在线观看 | 在线韩国电影免费观影完整版 | 草久视频在线 | 日韩欧美精选 | 人人干在线观看 | 99精品国产99久久久久久97 | 成人免费观看完整版电影 | 啪啪资源| 国产日韩精品一区二区三区 | 国产区在线 | 在线视频电影 | 色婷婷综合五月 | 曰本三级在线 | 精品久久网站 | www黄色av| 久久精品国产精品 | 国产午夜精品久久 | 午夜精品久久久久久久99水蜜桃 | 欧美动漫一区二区三区 | 最新中文字幕在线观看视频 | 久久黄色免费观看 | 天天视频亚洲 | 亚洲深爱激情 | 黄色一二级片 | www.久久com| 精品久久久久久一区二区里番 | www.五月激情.com | 人人澡人人添人人爽一区二区 | 欧美午夜精品久久久久 | 免费色视频网站 | 五月激情丁香图片 | 性色av一区二区三区在线观看 | 国产精品成人免费一区久久羞羞 | 亚洲动漫在线观看 | 国产成人av综合色 | 免费视频色 | 亚洲精品久久久蜜桃 | 精品夜夜嗨av一区二区三区 | 久久午夜精品影院一区 | av线上看| 日韩精品一区不卡 | 黄色一级在线免费观看 | 亚洲观看黄色网 | 国产淫片免费看 | 在线免费高清一区二区三区 | 天堂网在线视频 | 精品免费久久久久久 | 欧美激情精品久久久久久免费印度 | 国产在线精品一区二区 | 亚洲精品免费在线播放 | 久久综合中文字幕 | 中文永久免费观看 | 中文字幕在线网址 | 国产欧美最新羞羞视频在线观看 | 免费热情视频 | 日韩av片在线 | 精品国产一区二区三区av性色 | 丁香狠狠 | 日韩高清一二三区 | 深爱激情站 | 91精品一区二区三区久久久久久 | 在线观看a视频 | 黄视频网站大全 | 一区在线观看 | 香蕉久久久久久久 | 亚洲高清av在线 | 99精品久久只有精品 | 国产裸体永久免费视频网站 | 免费观看全黄做爰大片国产 | 亚洲国产免费av | 九九日韩 | 精品国产乱码久久久久 | 国产精品视频不卡 | 免费av小说 | 91av视频免费在线观看 | 黄色毛片视频 | 久久久久久久精 | 成人福利av | 天天综合网久久综合网 | 四虎影视国产精品免费久久 | 麻豆视频在线免费观看 | 99精品成人 | 久久线视频 | 日韩欧美xxxx | 日韩高清av在线 | 亚洲综合丁香 | 天天色天天干天天色 | 激情综合网五月婷婷 | 99久久99久国产黄毛片 | 五月天婷婷在线播放 | 999久久久久久久久久久 | 国产自产高清不卡 | www.eeuss影院av撸 | 日韩欧美视频在线免费观看 | 黄色三级久久 | 狠狠躁天天躁 | 日韩欧美国产成人 | 中文字幕免费观看视频 | 中文字幕国产一区 | 六月丁香久久 | 免费男女羞羞的视频网站中文字幕 | 亚洲视频 中文字幕 | 中文字幕乱视频 | 91喷水 | 日韩网站在线免费观看 | 最近日本字幕mv免费观看在线 | 91久久精品日日躁夜夜躁国产 | 香蕉视频在线看 | 色视频在线看 | 中文字幕在线观看第二页 | 欧美精品久久久久久久久久 | 中文字幕丝袜一区二区 | 天天天干天天射天天天操 | 国产精品99久久久久久武松影视 | 丁香激情综合 | 免费日韩av电影 | 中文字幕成人 | 国产黄色片免费在线观看 | 在线高清 | 久久精品国产亚洲a | 国产美女在线观看 | 国产成人精品久久久久 | 久久久久久久久久伊人 | 国产一区二区久久 | 999久久国产 | 在线观看视频99 | www激情网 | 久久成人国产精品入口 | 国产精品视频免费 | 日韩精品一区二区三区免费观看视频 | 蜜桃视频成人在线观看 | 免费网站污| av久久在线 | 色婷婷久久久综合中文字幕 | 久久亚洲私人国产精品va | 亚洲精品国偷拍自产在线观看 | 91视频下载 | 91三级视频| 日韩精品五月天 | 免费不卡中文字幕视频 | 97精品国产97久久久久久 | 操久 | 久久亚洲在线 | 亚洲国产成人在线观看 | 在线日韩中文 | www.久久成人| 日韩欧美在线视频一区二区三区 | 天天操夜夜操国产精品 | 色99色| 九九九热精品免费视频观看 | 日日操日日 | 97在线视频免费播放 | 丁香高清视频在线看看 | 在线视频一区二区 | 国际精品网 | 日韩av男人的天堂 | 182午夜在线观看 | 中文字幕日韩一区二区三区不卡 | 日本最大色倩网站www | 人人精久 | 五月激情视频 | 婷婷色在线播放 | 亚洲精品大全 | 日韩不卡高清 | 国产免费观看久久 | 欧美 亚洲 另类 激情 另类 | 91久久久久久久一区二区 | 91高清在线| 九九久久在线看 | 激情网站五月天 | 精品国产伦一区二区三区观看体验 | 国产一区视频在线 | 色偷偷av男人天堂 | 探花系列在线 | 免费av大片| 在线观看国产中文字幕 | 国产精品婷婷 | 最新中文字幕在线观看视频 | 超碰官网| 欧美极品一区二区三区 | 免费久久久久久 | 麻豆视频免费观看 | 色综合久久88色综合天天人守婷 | 超碰在线人 | 天天干夜夜操视频 | 中文字幕五区 | 三级小视频在线观看 | 国产日韩在线播放 | 免费看黄在线看 | 最新日韩在线观看视频 | 欧美大香线蕉线伊人久久 | 亚洲精品国产免费 | 欧美日韩一区二区三区不卡 | 日本最新高清不卡中文字幕 | 精品视频在线免费观看 | 91av九色 | 国产精品成人av久久 | 日韩中文在线电影 | 久草a视频| 欧美日韩国产精品一区 | 国产精品情侣视频 | 九九有精品 | 最新动作电影 | 天天操夜操 | 久久久久久久99 | 国内精品久久久久久久久久久久 | 久日精品 | 国产99久久久国产精品免费二区 | 91成熟丰满女人少妇 | 免费观看成人av | 日本精品视频在线 | 人人插人人射 | 久久久久久久久久久免费视频 | 欧美成人精品三级在线观看播放 | 91麻豆产精品久久久久久 | 国产福利91精品一区 | 999色视频| 国产精品99免视看9 国产精品毛片一区视频 | 色婷婷狠狠操 | 岛国大片免费视频 | 在线高清| 国产精品亚洲片在线播放 | 亚州日韩中文字幕 | 亚洲精品国产精品国自产在线 | 日日摸日日添日日躁av | 久久久国产电影 | 欧美激情第十页 | 看片网站黄 | 免费成人在线电影 | 在线观看免费日韩 | 一级精品视频在线观看宜春院 |