Guli College 160,000 単語のメモ + 1,600 枚の写真 (19) - データ同期、ゲートウェイ

プロジェクトのソースコードと必要な情報
リンク: https://pan.baidu.com/s/1azwRyyFwXz5elhQL0BhkCA?pwd=8z59
抽出コード: 8z59

デモ19-運河データ同期、ゲートウェイ

1. 運河応用シナリオ

前回の統計解析機能では、結合度が高く効率が比較的低いリモートサービスコールを利用して統計データを取得していました。現在は別の実装方法を採用しており、データベースのテーブルをリアルタイムに同期することで実現しており、例えば毎日の登録者数やログイン者数をカウントしたい場合は、会員テーブルと統計情報を同期するだけで済みます。データベースを使用してローカル統計を実現することで、より効率的になります。高結合および低結合のCanal は、非常に優れたデータベース同期ツールですCanal は Alibaba 傘下のオープンソース プロジェクトで、純粋な Java で開発されており、現在は MySQL データ同期のみをサポートしています。

2. 準備

2.1 分析

1. Linux 仮想マシンとローカル Windows システムが必要です

2. Linux 仮想マシンには以下が必要です。

  • MySQLデータベースをインストールする
  • データベースとデータテーブルを作成する
  • 運河データ同期ツールをインストールする

3. ローカル Windows システムには以下が必要です。

  • MySQLデータベースをインストールする
  • データベースとデータテーブルを作成する

このうち、Linux で作成されたデータベース データ テーブルは、ローカル Windows システムで作成されたデータベース データ テーブルと同じ名前とテーブル構造を持ちます。

3. 私たちが望む効果は、Linux ライブラリ内のデータが変更されると、ローカル Windows ライブラリ内のデータも変更されるということです。

2.2 ローカル Windows での MySQL データベースとテーブルの構築

1. データベース guli を早い段階で作成しました。ここでは、データベース guli を右クリックしてテーブルを直接作成します。

ここに画像の説明を挿入

2. ここでのテーブル名は member で、フィールドが 3 つあります

ここに画像の説明を挿入

2.3 Linux仮想マシンでのMySQLデータベース構築とテーブル構築

1.「[email protected]」を右クリックし、「データベースの作成」を選択します。

ここに画像の説明を挿入

2. 「demo03-背景講師管理モジュール」の「2.1 データベース設計」の最初のステップでどのようなデータベースを作成しましたか? ここでどのようなデータベースが作成されますか?

ここに画像の説明を挿入

3. 「demo03-背景講師管理モジュール」の「2.1 データベース設計」の最初のステップでデータベースを作成する際、デフォルトで「データベースの振り分けルール」が選択されており、データベース作成後に振り分けルールが自動的に付与されます。 guli ライブラリへの名前は "uf8mb4_general_ci" です。しかし、Linux MySQL で作成された guli ライブラリによって与えられるソート ルールは「uf8mb4_general_ci」ではありません。とにかく、なぜ今手動でソート ルールを「uf8mb4_general_ci」に設定するのかわかりません。

①Linuxのguliデータベースを右クリックし、「データベースの変更...」を選択します。

ここに画像の説明を挿入

②データベース照合順序「uf8mb4_general_ci」を選択し、「保存」をクリックします。

ここに画像の説明を挿入

4. Linuxのguliライブラリを右クリックしてテーブルを作成します

ここに画像の説明を挿入

5.「2.2 ローカル Windows での MySQL データベースとテーブルの構築」の 2 番目の手順の記入方法、ここの記入方法

ここに画像の説明を挿入

2.4 バイナリログ機能を有効にする

1. canal の原理は mysql binlog テクノロジーに基づいているため、ここで mysql の binlog write 機能を有効にする必要があります。

2. 次のコマンドを使用して、binlog 機能が有効になっているかどうかを確認します。丸で囲まれた緑色のボックスがオンになり、有効であることを示します。

show variables like 'log_bin';

ここに画像の説明を挿入

3. 上図の緑色のボックスがオフになっている場合は、有効になっていないことを意味します。binlog を有効にするために設定ファイルを変更する必要があります (オンラインで自分でクエリを実行する)。設定ファイルを変更した後は、忘れずに mysql を再起動してください。

3.運河を設置する

3.1 canal圧縮パッケージをダウンロードする

1. ダウンロードアドレス:

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

2. 先生がcanal.deployer-1.1.4tar.gzこのバージョンを使用しているので、私もこのバージョンをここからダウンロードしました

ここに画像の説明を挿入

3.2 canal 圧縮ファイルを Linux にアップロードする

Xftp を使用して、前の手順でダウンロードした圧縮ファイルを Linux 仮想マシンにアップロードします (ここでは opt ディレクトリにアップロードしました)。

ここに画像の説明を挿入

3.3 canal圧縮ファイルを解凍する

1. cd /opt を実行して opt ディレクトリに入り、まず次のコマンドを使用して opt ディレクトリに解凍された canal を保存するフォルダーを作成します。

mkdir canal

ここに画像の説明を挿入

2. 次に、次のコマンドを使用して、canal 圧縮ファイルを前の手順で作成した canal ディレクトリに解凍します。

tar zxvf canal.deployer-1.1.4.tar.gz -C canal

ここに画像の説明を挿入

3.4 設定ファイルの変更

1. 次のコマンドを使用して、運河構成ファイルinstance.propertiesを編集モードで開きます。

vi /opt/canal/conf/example/instance.properties

ここに画像の説明を挿入

2. i を入力して挿入モードに入ります。最初の変更は次のとおりです。

  • 赤いボックスで囲まれた Linux の IP が表示されます (自分の Linux 仮想マシンの IP を入力します。注:自分の IP を入力するときは、キーボードの右側にある 0 ~ 9 の数字は使用できません。キーボードの上の数字 0 ~ 9 )
    • 先生は、ここで IP を変更しなくてもデフォルトの IP を使用するだけで大​​丈夫だと言いましたが127.0.0.1、それでも変更することをお勧めします
  • 緑色のボックスで囲まれた Linux の mysql のポート番号 (デフォルトは 3306)

ここに画像の説明を挿入

3. 2 番目の変更は次のとおりです。

  • 赤丸で囲った部分がユーザー名です
  • 緑枠はユーザーのパスワードです
  • 「8.9 MySQLにリモート接続する」の手順2で設定したユーザー名とパスワードを入力します。

ここに画像の説明を挿入

4. 4 番目の場所は変更する必要はなく、構成ファイル内のデフォルトのものを使用するだけです。

  • この構成の役割は、すべてのライブラリとすべてのテーブルが一致することを指定することです。

ここに画像の説明を挿入

その他の一致ルールは次のとおりです。

  • すべてのライブラリとすべてのテーブル:.*または.*\\..*

  • 運河ライブラリーの下にあるすべてのテーブル:canal\\..*

  • canal ライブラリーの下にある canal で始まる表:canal\\.canal.*

  • 運河ライブラリの下の特定のテーブル:canal.test1

  • 複数のルールの組み合わせ (カンマ区切り):canal\\..*,mysql.test1,mysql.test2

5. 変更後、 を押してEsc挿入モードを終了し、 Enter を押して:wq保存して終了します。

3.5 運河データ同期ツールの起動と終了

1. まず次のコマンドを使用して bin ディレクトリに移動します。

cd /opt/canal/bin

ここに画像の説明を挿入

2. 次に、次のコマンドを使用して、bin ディレクトリで運河データ同期ツールを起動します。

./startup.sh

ここに画像の説明を挿入

3. 運河データ同期ツールを閉じる場合は、bin ディレクトリで次のコマンドを使用します。

./stop.sh

ここに画像の説明を挿入

4. クライアントコード

4.1 サブモジュール canal_clientedu の作成

1. 合計モジュール guli_parent を右クリックし、「新規」->「モジュール…」を選択します。

ここに画像の説明を挿入

2.Maven プロジェクトを作成する

ここに画像の説明を挿入

3. 情報を入力したら、「完了」をクリックします。

ここに画像の説明を挿入

4.2 依存関係の導入

次のコードを canal_clientedu モジュールの pom.xml に追加して、必要な依存関係を導入します (Maven を更新することを忘れないでください)。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
        <groupId>commons-dbutils</groupId>
        <artifactId>commons-dbutils</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <dependency>
        <groupId>com.alibaba.otter</groupId>
        <artifactId>canal.client</artifactId>
    </dependency>
</dependencies>

ここに画像の説明を挿入

4.3 application.propertiesの構成

構成ファイル application.properties を作成し、構成を書き込みます

# 服务端口
server.port=10000
# 服务名
spring.application.name=canal-client

# 环境设置:dev、test、prod
spring.profiles.active=dev

# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/guli?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root

ここに画像の説明を挿入

4.4 スタートアップクラスの作成

canal_clientedu モジュールの Java パッケージの下に com.atguigu.canal パッケージを作成し、canal パッケージの下にスタートアップ クラス CanalApplication を作成します。

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

ここに画像の説明を挿入

4.5 書き込みカナルクライアントクラス

canal パッケージの下にパッケージ client を作成し、次に client パッケージの下にクライアント クラス CanalClient を作成します (コードは固定コードであり、専門家による入力は必要ありません。理解できれば変更できます [I don't'それは理解できませんし、今のところ理解するつもりもありません] ])

package com.atguigu.canal.client;

import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.protocol.CanalEntry.*;
import com.alibaba.otter.canal.protocol.Message;
import com.google.protobuf.InvalidProtocolBufferException;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.net.InetSocketAddress;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

@Component
public class CanalClient {
    
    

    //sql队列
    private Queue<String> SQL_QUEUE = new ConcurrentLinkedQueue<>();

    @Resource
    private DataSource dataSource;

    /**
     * canal入库方法
     */
    public void run() {
    
    

        CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress("192.168.44.132",
                11111), "example", "", "");
        int batchSize = 1000;
        try {
    
    
            connector.connect();
            connector.subscribe(".*\\..*");
            connector.rollback();
            try {
    
    
                while (true) {
    
    
                    //尝试从master那边拉去数据batchSize条记录,有多少取多少
                    Message message = connector.getWithoutAck(batchSize);
                    long batchId = message.getId();
                    int size = message.getEntries().size();
                    if (batchId == -1 || size == 0) {
    
    
                        Thread.sleep(1000);
                    } else {
    
    
                        dataHandle(message.getEntries());
                    }
                    connector.ack(batchId);

                    //当队列里面堆积的sql大于一定数值的时候就模拟执行
                    if (SQL_QUEUE.size() >= 1) {
    
    
                        executeQueueSql();
                    }
                }
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            } catch (InvalidProtocolBufferException e) {
    
    
                e.printStackTrace();
            }
        } finally {
    
    
            connector.disconnect();
        }
    }

    /**
     * 模拟执行队列里面的sql语句
     */
    public void executeQueueSql() {
    
    
        int size = SQL_QUEUE.size();
        for (int i = 0; i < size; i++) {
    
    
            String sql = SQL_QUEUE.poll();
            System.out.println("[sql]----> " + sql);

            this.execute(sql.toString());
        }
    }

    /**
     * 数据处理
     *
     * @param entrys
     */
    private void dataHandle(List<Entry> entrys) throws InvalidProtocolBufferException {
    
    
        for (Entry entry : entrys) {
    
    
            if (EntryType.ROWDATA == entry.getEntryType()) {
    
    
                RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
                EventType eventType = rowChange.getEventType();
                if (eventType == EventType.DELETE) {
    
    
                    saveDeleteSql(entry);
                } else if (eventType == EventType.UPDATE) {
    
    
                    saveUpdateSql(entry);
                } else if (eventType == EventType.INSERT) {
    
    
                    saveInsertSql(entry);
                }
            }
        }
    }

    /**
     * 保存更新语句
     *
     * @param entry
     */
    private void saveUpdateSql(Entry entry) {
    
    
        try {
    
    
            RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
            List<RowData> rowDatasList = rowChange.getRowDatasList();
            for (RowData rowData : rowDatasList) {
    
    
                List<Column> newColumnList = rowData.getAfterColumnsList();
                StringBuffer sql = new StringBuffer("update " + entry.getHeader().getTableName() + " set ");
                for (int i = 0; i < newColumnList.size(); i++) {
    
    
                    sql.append(" " + newColumnList.get(i).getName()
                            + " = '" + newColumnList.get(i).getValue() + "'");
                    if (i != newColumnList.size() - 1) {
    
    
                        sql.append(",");
                    }
                }
                sql.append(" where ");
                List<Column> oldColumnList = rowData.getBeforeColumnsList();
                for (Column column : oldColumnList) {
    
    
                    if (column.getIsKey()) {
    
    
                        //暂时只支持单一主键
                        sql.append(column.getName() + "=" + column.getValue());
                        break;
                    }
                }
                SQL_QUEUE.add(sql.toString());
            }
        } catch (InvalidProtocolBufferException e) {
    
    
            e.printStackTrace();
        }
    }

    /**
     * 保存删除语句
     *
     * @param entry
     */
    private void saveDeleteSql(Entry entry) {
    
    
        try {
    
    
            RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
            List<RowData> rowDatasList = rowChange.getRowDatasList();
            for (RowData rowData : rowDatasList) {
    
    
                List<Column> columnList = rowData.getBeforeColumnsList();
                StringBuffer sql = new StringBuffer("delete from " + entry.getHeader().getTableName() + " where ");
                for (Column column : columnList) {
    
    
                    if (column.getIsKey()) {
    
    
                        //暂时只支持单一主键
                        sql.append(column.getName() + "=" + column.getValue());
                        break;
                    }
                }
                SQL_QUEUE.add(sql.toString());
            }
        } catch (InvalidProtocolBufferException e) {
    
    
            e.printStackTrace();
        }
    }

    /**
     * 保存插入语句
     *
     * @param entry
     */
    private void saveInsertSql(Entry entry) {
    
    
        try {
    
    
            RowChange rowChange = RowChange.parseFrom(entry.getStoreValue());
            List<RowData> rowDatasList = rowChange.getRowDatasList();
            for (RowData rowData : rowDatasList) {
    
    
                List<Column> columnList = rowData.getAfterColumnsList();
                StringBuffer sql = new StringBuffer("insert into " + entry.getHeader().getTableName() + " (");
                for (int i = 0; i < columnList.size(); i++) {
    
    
                    sql.append(columnList.get(i).getName());
                    if (i != columnList.size() - 1) {
    
    
                        sql.append(",");
                    }
                }
                sql.append(") VALUES (");
                for (int i = 0; i < columnList.size(); i++) {
    
    
                    sql.append("'" + columnList.get(i).getValue() + "'");
                    if (i != columnList.size() - 1) {
    
    
                        sql.append(",");
                    }
                }
                sql.append(")");
                SQL_QUEUE.add(sql.toString());
            }
        } catch (InvalidProtocolBufferException e) {
    
    
            e.printStackTrace();
        }
    }

    /**
     * 入库
     * @param sql
     */
    public void execute(String sql) {
    
    
        Connection con = null;
        try {
    
    
            if(null == sql) return;
            con = dataSource.getConnection();
            QueryRunner qr = new QueryRunner();
            int row = qr.execute(con, sql);
            System.out.println("update: "+ row);
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            DbUtils.closeQuietly(con);
        }
    }
}

コードが変更された場所:

  • 35 行目に独自の Linux 仮想マシンの IP アドレスを入力します。

4.6 スタートアップクラスの変更

ローカル ライブラリをリモート (Linux 仮想マシン) ライブラリと同期できるようにしたいのですが、データがリモート ライブラリに追加される場合は、ローカル ライブラリもデータを追加する必要があり、データがリモート ライブラリで変更される場合は、ローカル ライブラリがデータを追加する必要があります。ライブラリもデータを変更する必要があります。この目標を達成するには、プログラムが常に監視状態にあり、リモート ライブラリの変更を監視していることを確認する必要があります。「4.5 カナルクライアントクラスの作成」で記述したクラスの run メソッドは、リモート ライブラリの監視と関連操作の実行に使用されるため、メソッドを実行し続ける必要がある場合は、スタートアップ クラスを変更する必要があります

1. スタートアップ クラスにインターフェイス CommandLineRunner を実装させます。

ここに画像の説明を挿入

2. スタートアップ クラスに次のコードを追加します。

@Resource
private CanalClient canalClient;
@Override
public void run(String... strings) throws Exception {
    
    
    //项目启动,执行canal客户端监听
    canalClient.run();
}

ここに画像の説明を挿入

  • CommandLineRunner インターフェイスの run メソッドが書き換えられます。CommandLineRunner インターフェイスの run メソッドの機能は次のとおりです:プログラムが実行中である限り、書き換えられた CommandLineRunner インターフェイスの run メソッド内のコードは常に実行されます。

4.7 テスト

1. バックエンドサービスは、canal_clientedu を起動し、Linux で canal を起動するだけで済みます。

2. SQLyog を使用して Linux のライブラリにデータを挿入します

INSERT INTO member VALUES(1,'lucy',20)

ここに画像の説明を挿入

3. ローカル ライブラリのメンバー テーブルにもデータが挿入されていることがわかります。これは、データの同期が成功したことを示しています。

ここに画像の説明を挿入

5. ゲートウェイ

5.1 ゲートウェイの概念

1. クライアントとサーバーの間の壁は、リクエストの転送、負荷分散、権限制御など、多くの役割を果たすことができます。

2. 先生は、ゲートウェイ サービスも登録センターに登録する必要があると言いました(あまり理解できません)

3. クライアントはアクセス時に最初にゲートウェイを通過し、ゲートウェイは次のプロセスを実行します。まず、ゲートウェイ ハンドラー マッピングでパスの照合を行い、一致する場合は、ゲートウェイ Web ハンドラーに入って実行を開始し、次に、フィルターフィルター、権利管理、クロスドメインを実装できます...

ここに画像の説明を挿入

4. Spring Cloud Gateway のいくつかの重要な概念:

  • ルーティング: ルーティングはゲートウェイの最も基本的な部分であり、ルーティング情報は ID、宛先 URL、一連のアサーション、および一連のフィルターで構成されます。アサートルートが true の場合、要求された URL は設定と一致します。
  • Assertion: Java8のアサーション関数。端的に言えば、一致ルールを宣言することです。たとえば、ユーザーが今 eduservice にアクセスした場合、ポート 8001 にジャンプさせます。
  • フィルター: リクエストとレスポンスを変更して、権限管理、クロスドメイン、統一された例外処理を実現します...

5.2 サブサブモジュール api_gateway の作成

1. まず、サブモジュールのインフラストラクチャを作成します。

① プロジェクト全体 guli_parent を右クリックし、「新規」->「モジュール…」を選択します。

ここに画像の説明を挿入

②Mavenプロジェクトを作成する

ここに画像の説明を挿入

③ 情報を入力後、「完了」をクリックします。

ここに画像の説明を挿入

④このサブモジュールの下にはサブモジュールがあるため、インフラストラクチャモジュールのpom.xmlに以下のコードを追加し、サブプロジェクトをpomタイプに変更することを示します(mavenの更新を忘れずに)

<packaging>pom</packaging>

ここに画像の説明を挿入

⑤インフラストラクチャモジュール内にはコードを書きたくないので、モジュール配下のsrcディレクトリを削除します。

ここに画像の説明を挿入

2. インフラストラクチャ モジュールを右クリックし、[新規]->[モジュール…] を選択します。

ここに画像の説明を挿入

3.Maven プロジェクトを作成する

ここに画像の説明を挿入

4. 情報を入力したら、「完了」をクリックします

ここに画像の説明を挿入

5.3 依存関係の追加

api_gateway モジュールの pom.xml に依存関係を追加します (Maven を更新することを忘れないでください)。

<dependencies>
    <dependency>
        <groupId>com.atguigu</groupId>
        <artifactId>common_utils</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

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

    <!--gson-->
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
    </dependency>

    <!--服务调用-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
</dependencies>

ここに画像の説明を挿入

5.4 スタートアップクラスの作成

api_gateway モジュールの Java パッケージの下にパッケージ com.atguigu.gateway を作成し、ゲートウェイ パッケージの下にスタートアップ クラス ApiGatewayApplication を作成します。

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

ここに画像の説明を挿入

nacosにゲートウェイサービスを登録する必要があるため、スタートアップクラスに@EnableDiscoveryClientアノテーションを追加する必要がある

5.5 application.propertiesの構成

構成ファイル application.properties を作成し、構成を書き込みます

# 服务端口
server.port=8222
# 服务名
spring.application.name=service-gateway
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

#使用服务发现路由
spring.cloud.gateway.discovery.locator.enabled=true

#设置路由id
spring.cloud.gateway.routes[0].id=service-acl
#设置路由的uri
spring.cloud.gateway.routes[0].uri=lb://service-acl
#设置路由断言,代理servicerId为auth-service的/auth/路径
spring.cloud.gateway.routes[0].predicates= Path=/*/acl/**

#配置service-cms服务
#设置路由id(可以随便起,但建议写服务名字)
spring.cloud.gateway.routes[1].id=service-cms
#设置路由的uri    lib://在nacos注册的服务名称
spring.cloud.gateway.routes[1].uri=lb://service-cms
#设置路由断言,代理servicerId为auth-service的/auth/路径
spring.cloud.gateway.routes[1].predicates= Path=/educms/**

spring.cloud.gateway.routes[2].id=service-edu
spring.cloud.gateway.routes[2].uri=lb://service-edu
spring.cloud.gateway.routes[2].predicates= Path=/eduservice/**

spring.cloud.gateway.routes[3].id=service-msm
spring.cloud.gateway.routes[3].uri=lb://service-msm
spring.cloud.gateway.routes[3].predicates= Path=/edumsm/**

spring.cloud.gateway.routes[4].id=service-order
spring.cloud.gateway.routes[4].uri=lb://service-order
spring.cloud.gateway.routes[4].predicates= Path=/eduorder/**

spring.cloud.gateway.routes[5].id=service-oss
spring.cloud.gateway.routes[5].uri=lb://service-oss
spring.cloud.gateway.routes[5].predicates= Path=/eduoss/**

spring.cloud.gateway.routes[6].id=service-statistics
spring.cloud.gateway.routes[6].uri=lb://service-statistics
spring.cloud.gateway.routes[6].predicates= Path=/staservice/**

#配置service-ucenter服务
spring.cloud.gateway.routes[7].id=service-ucenter
spring.cloud.gateway.routes[7].uri=lb://service-ucenter
spring.cloud.gateway.routes[7].predicates= Path=/educenter/**

spring.cloud.gateway.routes[8].id=service-vod
spring.cloud.gateway.routes[8].uri=lb://service-vod
spring.cloud.gateway.routes[8].predicates= Path=/eduvod/**

9 行目はspring.cloud.gateway.discovery.locator.enabled=true、Gateway のサービス ディスカバリを使用して呼び出しを実装することを意味します (nginx を使用してリクエスト転送を実装する場合との違いは、nginx ではパス マッチングが使用されるのに対し、Gateway ではサービス ディスカバリを使用してマッチングが行われることです [個人的な理解なので、正しいかどうかはわかりません])

5.6 テスト

1.nacosを起動し、バックエンドプロジェクトでservice_eduとapi_gatewayを起動します。

2.アドレス バーにhttp://localhost:8222/eduservice/subject/getAllSubject と入力してデータを表示し、構成が成功したことを示します。

ここに画像の説明を挿入

5.7 負荷分散の実現

Gateway は負荷分散をカプセル化しており、何も設定せずに負荷分散を実現できます。service_edu サービスをクラスターにすると (同じ機能を実装し、サービス名は同じですが、ポート番号が異なります)、このサービスを配置します。 2 台のサーバーのポート番号はそれぞれ 8101 と 8102 です。クライアントが eduservice にアクセスすると、ゲートウェイは負荷分散である特定のルール (ポーリング、重み、最小リクエスト時間) に従ってリクエストを 8101 または 8102 に割り当てることを決定します。

ここに画像の説明を挿入

5.8 クロスドメイン、権限管理、例外処理の実現

1. すべて固定コードです。入力する必要はありません。コードのこの部分はデータに組み込まれます。

ここに画像の説明を挿入

2. 上記の 3 つのフォルダーをコピーして、api_gateway モジュールのゲートウェイ パッケージに貼り付けます。

ここに画像の説明を挿入

  • CorsConfig クラスは、すべてのリクエストをクロスドメインにするプラグインを追加する構成クラスです。
  • AuthGlobalFilter の役割:どのリクエストにアクセスできるか、どのリクエストにアクセスできないか、アクセスが失敗した場合にどのような値が出力されるかを指定します。

3. CorsConfig クラスにクロスドメインを実装しているため、サービス モジュール内のすべてのクロスドメイン アノテーション @CrossOrigin をコメントアウトするか削除する必要があります。そうしないとエラーが報告されます (ただし、実際には理解できないため) CorsConfig、AuthGlobalFilter、ErrorHandlerConfig、および JsonExceptionHandler の 4 つのクラスは、無差別に使用することをあえてしないため、これら 4 つのクラスすべてをコメントアウトしました。使用されるリクエスト転送は引き続き nginx を使用して実装されています)

4. フロントエンド プロジェクト vue-admin-1010 の config ディレクトリにある dev.env.js ファイルのアドレスの 9001 を、ゲートウェイのポート番号 8222 に変更します。

ここに画像の説明を挿入

5. フロントエンド プロジェクト vue-front-1010 の utils ディレクトリにある request.js ファイルのアドレスを 9001 からゲートウェイのポート番号 8222 に変更します。

ここに画像の説明を挿入

コメントを読んで、後ろの権限管理はすべて cv だと言いました。先生は急いでいて、それを実現する方法について詳しく説明しませんでした。最初は、慣れるためにもう一度聞いてみようと思いました。ゲートウェイを読み終えて、先生が本当にそうでなかったことに気づきました 時間です、すべては履歴書に関するものです、重要なのは私が十分ではないということです、そしてそれをまったく説明しないと理解できません、権限管理については後ほど説明しませんので、このプロジェクトはここで終了とさせていただきます。

2022.07.27 2022.09.22 開花終了~~~

おすすめ

転載: blog.csdn.net/maxiangyu_/article/details/127033142