1.4Wワード!springmvc の世界を理解しましょう!

目次

1. 前提条件の理解

1. Tomcat とサーブレットの関係は何ですか?

2. springmvc が Web 開発を実現するために満たさなければならない条件は何ですか?

2. SpringMVCとは

3. SpringMVCに基づいてWebプロジェクトを作成する

①プロジェクトを作成し、依存関係を選択する

 ②ホットデプロイメントを設定します(一部のコード変更は手動で再実行しなくても有効になります)

4. フロントエンドとバックエンドの分離の開発プロセスを理解する

5. SpringMVCでWeb開発を実現

1. クライアントから返される応答を詳しく説明する

@コントローラ

@ResponseBody

リダイレクトと転送

前方

リダイレクト

転送とリダイレクトの違い: (M)

カスタム戻り値の型

@RestController

@RequestMapping

 2. サーバーがクライアントのリクエストをどのように受信するかを詳しく説明する

2.1 リクエストパスおよびリクエストヘッダーのパラメータについて

@Pathvirable

postman を使用してテスト結果を分析します。

@リクエストヘッダー

@CookieValue

@セッション属性

2.2 リクエストパラメータについて

注釈のないリクエストパラメータ

@RequestParam

@RequestPart

@RequestBody

構成クラスを通じてプログラムによる構成スキームを設定する

バックエンドパスの統合プレフィックスを設定します

インターセプターの設定

統合された例外処理

統合された結果処理:

responseBodyAdviceの役割について


1. 前提条件の理解

springmvc について実際に説明する前に、次の 2 つの質問を明確にしましょう。

1. Tomcat とサーブレットの関係は何ですか?

サーブレットは動的なページを実現する技術、サーブレットはWeb開発用の仕様、Tomcatはサーブレット仕様に準拠してWebサーバーとポート番号を提供し、一元管理を実現するサーブレットコンテナであることは皆さんご存知でしょう。サーブレットの; 同時に、ユーザーのリクエストを受信し、そのリクエストをサーブレットに送信し、サーブレットが応答を返した後にクライアントに応答を送信することができます。

2. springmvc が Web 開発を実現するために満たさなければならない条件は何ですか?

以上の説明から、tomcat はサーブレット仕様を満たしており、それに基づいて Web 開発を行っていることがよくわかりましたが、springmvc が Web 開発を実現するには、サーブレット仕様も満たさなければなりません。

2. SpringMVCとは

SpringMVC は Web 開発用のフレームワークです。また、springboot フレームワークにも依存しています (springboot には springmvc が含まれています)。一致は springboot フレームワークの構成よりも大きいという原則の利点を活かして、springmvc ファイル パスは springboot でデフォルトで構成されます。 springmvc 設定には多くのデフォルトが設定されており (ユーザーによる手動設定は必要ありません)、springmvc にはサーブレット仕様 (サーブレットのさらなるカプセル化) を満たす組み込み Web サーバー (カスタマイズされたサーバーに相当) があり、必要に応じてWeb開発でspringmvcを使用するには、springmvcの利用仕様を満たす必要があるだけです。

Web 開発に springmvc を使用する目的も非常に明確です。Web 開発をより便利にし、Web 開発の効率を向上させることです。

3. SpringMVCに基づいてWebプロジェクトを作成する

①プロジェクトを作成し、依存関係を選択する

 ②ホットデプロイメントを設定します(一部のコード変更は手動で再実行しなくても有効になります)

 

③ JMX を無効にする: 除外しないとプロジェクト開始時にエラーが報告されるため、このエラーはプロジェクトの実装には影響しませんが、標準化のために追加します。

 ④ Tomcat を無効にして、undertow に置き換えます (undertow は Tomcat よりわずかに効率的であるため、必須のオプションではありません)

⑤ コードセットを変更する

4. フロントエンドとバックエンドの分離の開発プロセスを理解する

springMVCのMVCは、①Model(モデル)②View(ビュー)③Controller(コントローラー) の3つの部分で構成されています。

Web リクエストとレスポンスのプロセスを組み合わせて、開発プロセスと springmc の 3 つのコンポーネントを理解します。

ユーザーは http リクエストを送信し、モデル層と組み合わせたコントローラー層を通じてリクエスト情報を解析して応答し、その応答データをビュー層に返し、最後にビュー層を通じて http 応答を返します。

特定のリリース方法と組み合わせてこれを分析します。

実際、専門的なロジックは次のようになります。
 

処理の流れ
DispatcherServlet の処理の流れは以下のステップに分かれます。

クライアントリクエストの受信
        クライアントがリクエストを送信すると、DispatcherServlet がそのリクエストを受信して​​処理します。リクエストの受信方法は DispatcherServlet の設定によって異なりますが、通常はリクエストを URL にマッピングし、その URL のリクエストをリッスンします。

リクエスト オブジェクトの作成
        DispatcherServlet は、クライアント リクエストに従ってリクエスト オブジェクトを作成します。リクエスト オブジェクトには、リクエスト メソッド、リクエスト ヘッダー、リクエスト パラメータなど、クライアントによってリクエストされたすべての情報が含まれます。

処理リクエストのマッピング
DispatcherServlet は、処理のためにリクエストを対応するコントローラにマップします。リクエストのマッピングは、HandlerMapping を通じて行われます。HandlerMapping は、リクエストを 1 つ以上のコントローラにマッピングする役割を果たし、処理に最適なコントローラを選択できるようにします。

コントローラ
        DispatcherServlet を呼び出すと、対応するコントローラが呼び出されて処理が行われ、コントローラはリクエストパラメータとビジネスロジックに従って対応する処理を実行し、ModelAndView オブジェクトを返します。

ビュー
        DispatcherServlet をレンダリングすると、ModelAndView オブジェクトがビュー リゾルバー (ViewResolver) に渡され、ビュー リゾルバーは ModelAndView 内のビュー名に従って、対応するビュー オブジェクトを解決します。次に、DispatcherServlet は、ビューをレンダリングするためにモデル データをビュー オブジェクトに渡します。最後に、ビュー オブジェクトは対応する応答結果を生成し、クライアントに返します。

 

5. SpringMVCでWeb開発を実現

1. クライアントから返される応答を詳しく説明する

@コントローラ

@controller は、このアノテーションによって変更されたクラスが Bean (通常はクラスの変更にのみ使用されます) であり、この Bean が Web リクエストと応答の処理を担当することを示します

@ResponseBody

@ResponseBody は、戻り値の型を指定する応答本文を示します (クラスとメソッドの両方を変更するために使用できます。変更されたクラスは、すべてのメソッドが戻り値の型を設定することを意味し、変更されたメソッドは、このメソッドのみが指定されることを意味します)戻り値の型)、@ResponseBody は、それによって変更されたメソッドの戻り値が特定のデータ形式で返されることを規定しており、デフォルトの戻り形式は json です

リダイレクトと転送

@ResponseBody を使用して戻り値の型の形式を指定しない場合、デフォルトの戻り値の型は String で、パスを表します。このパスは通常、転送とリダイレクトの2 つのアプリケーション シナリオに分けられます。

前方

構文形式: forward:/+path

キャプチャ パケット ビューの機能:

①リクエストとレスポンスが1つだけあるリソースはHTMLページです

 

リダイレクト

文法形式: "redirect:/+path"

キャプチャ パケット ビューの機能:

最初のリクエスト: 

 最初の応答:

二つ目の要求:

2 番目の応答:

転送とリダイレクトの違い: (M)

1. サーバーへのアクセスを 2 回リダイレクトし、サーバーへのアクセスは 1 回だけ転送します。

2. 転送先ページのURLは変わりませんが、リダイレクト先のアドレスは変わります。

3. 転送は独自の Web アプリケーションにのみ転送でき、リダイレクトは任意のリソース パスに再定義できます。

4. 転送はサーバージャンプに相当し、メソッド呼び出しに相当します。現在のファイルの実行中に、ターゲットファイルの実行に切り替わります。2 つのファイル (現在のファイルとターゲットファイル) は同じリクエストに属しており、フロントページとバックページはリクエストを共有します。これを使用して、データまたはセッション情報を渡すには、request.setAttribute() および request.getAttribute() を使用できます。リダイレクトにより新しいリクエストが生成され、リクエスト ドメイン情報とリクエスト パラメータは共有できません

5. 転送はサーバーの内部メソッド呼び出しと同等であるため、転送の背後にあるコードは引き続き実行されます (転送後に戻ることを忘れないでください)。リダイレクト コードが実行された後、メソッドの実行後にリダイレクト操作が実行されます。が完了した、つまり 2 番目のリクエストへのアクセスが完了した場合、それがリダイレクトするメソッドの最後の行である場合、すぐにリダイレクトされます (リダイレクトには return も必要です)。
 

カスタム戻り値の型

@ResponseBody を使用して戻り値の型を設定し、転送とリダイレクトを実行するだけでなく、次のようにカスタムの戻り値の型を実装することもできます。

例を挙げて説明します。.doc オブジェクトをクライアントに送信します (ネットワーク リソースのダウンロード)。

1. ファイルパスオブジェクトを作成する

2. パス内のバイト配列を読み取ります。

3. カスタム戻りオブジェクトを設定する

@Controller
public class SelfController {
    @GetMapping("/object1")
    public ResponseEntity test() throws IOException {
        //创建返回值
        //传输字节码文件
        Path p=new File("D:\\大物实验报告\\42109211014_20221018142451.doc").toPath();
        byte[]bytes= Files.readAllBytes(p);
      return   ResponseEntity.ok().header("content-type", "application/msword").body(bytes);
    }
}

アクセスするにはパスを使用します

@RestController

当面は、その機能を単に @Controller と @Responsebody のアノテーションを組み合わせたものとして理解することができます。

使用方法: クラスをロードする前に

@RequestMapping

@RequestMapping はリクエスト パスを表します。このアノテーションはクラスとメソッドの両方に追加できます。このアノテーションがクラスとメソッドの両方に追加された場合、リクエスト パスはクラス パス + メソッド パスで表されます

手順:

いくつかの属性:

●value:リクエストリクエストのマッピングアドレスを定義します。

●method: リクエストアドレスのメソッドを定義します(GET、POST、HEAD、OPTIONS、PUT、PATCH、DELETE、TRACE)。デフォルトではgetリクエストが受け付けられます。リクエストメソッドが定義されたメソッドと異なる場合、リクエストは成功しません。

●params:リクエストリクエストに含める必要があるパラメータ値を定義します。

 2. サーバーがクライアントのリクエストをどのように受信するかを詳しく説明する

2.1 リクエストパスおよびリクエストヘッダーのパラメータについて

@Pathvirable

使用法: 仮パラメータを変更するために使用されます

@Pathvirable 機能:リクエストパス内の動的パラメータを特定(@Pathvirableが変更したメソッドパラメータ変数と同名の変数を@RequestMappingを使用してリクエストパスから読み込み、同名の仮パラメータ変数に読み込む)メソッドの途中で。)

コードデモ:

@RestController
public class PathTest {
    @RequestMapping("/test/{id}")
    public Object test(@PathVariable Long id){
        //创建容器
        HashMap<String, Long> stringLongHashMap = new HashMap<>();
        stringLongHashMap.put("id", id);
        return  stringLongHashMap;
    }

postman を使用してテスト結果を分析します。

 @pathvirable によって変更された変数の型は、リクエスト パスの変数を検証できます。リクエスト パスのパラメーターがパラメーターの型と一致しない場合、400 エラーが報告されます

@リクエストヘッダー

機能: リクエストヘッダのフィールド名をバインドしてリクエストヘッダのフィールド情報を取得

使用例:

   @RequestMapping("/header")
    public Object getHeader(@RequestHeader("user-agent") String headers){
        HashMap<String, String> stringLongHashMap = new HashMap<>();
        stringLongHashMap.put("user-agent", headers);
        return  stringLongHashMap;
    }

@CookieValue

機能: Cookie 内のキー名をバインドして、Cookie 内の情報を取得します。

使い方:

    @RequestMapping("/cookie")
    public Object getCookie(@CookieValue("JSESSIONID") String cookie){
        HashMap<String, String> stringLongHashMap = new HashMap<>();
        stringLongHashMap.put("my-cookie", cookie);
        return  stringLongHashMap;

@セッション属性

これを説明する前に、Cookie とセッションの関係について簡単に説明します: セッションはサーバー側に保存され、サーバーはそれを使用してユーザー情報を保存します。セッションはキーと値のペアとして理解でき、キーはランダムです。生成された sessionId。値は現在のユーザーのセッション オブジェクトです。Cookie はクライアントに保存され、ユーザー情報の保存にも使用されます。ユーザー情報を確認するときは、ID の sessionId に基づいてサーバー上の対応する sessoin オブジェクトと照合します。検証

@SessionAttribute は、リクエスト パラメーターのセッション情報を取得するために使用されます (sessionId に従ってサーバー上のセッション オブジェクトを取得し、ユーザー情報を確認します)。

使用例:
 

 @RequestMapping("/login")
    public Object info(HttpServletRequest request){
        //通过session存储session信息
        HttpSession session = request.getSession(true);
        //存储session信息
        session.setAttribute("user", "zhangsan");
        //创建容器并返回
        HashMap<String, String> map = new HashMap<>();
        map.put("user", "zhangsan");
        return map;
    }
    @RequestMapping("/check")
    public Object checkLogin(@SessionAttribute("user") String name){
        HashMap<String, String> map = new HashMap<>();
        map.put("user", name);
        return map;
    }

一般に、ログイン認証の一般的なプロセスは次のとおりです。

初回ログイン時、セッションオブジェクトが存在するか確認し(存在しない場合は新規セッションオブジェクトを作成)、フロントエンドからのユーザー情報に応じてセッションオブジェクトを格納し、レスポンスを返し、その他の操作を行う(ユーザーログインに基づく必要があります)検証のためにsessionIdに従ってサーバーからセッションオブジェクトを取得する必要があります

結果分析:

2.2 リクエストパラメータについて

注釈のないリクエストパラメータ

 フロントエンドのリクエストパラメータは通常、送信用にクエリ文字列、フォームタイプのデータ、JSON形式のデータ、フォームデータタイプのデータの4つのデータ形式に分割されます。また、バックエンドがリクエストを受信するJavaオブジェクトは、単純なデータ形式に分割されます。データ型 (基本データ型 + ラッパー クラス + 文字列) と複雑なデータ型 (コレクション フレームワークとカスタム型)、以下でこれら 2 つのデータ型を分析します; 最初に結論を出します: それが単純なデータ型であるかどうかは、まだです
。複雑なデータ型です。アノテーションがない場合、バックエンドで解析できるのはクエリ文字列のみです。フォーム型データ、json 形式データ、json 型データはアノテーション ( @RequestBody ) を使用する必要があります。表はこれを説明しています:

これらのフロントエンド データ タイプを個別に分析します。
 

@RequestParam

@RequestParam (json 以外の他の型を変更でき、マップやリストなどのコレクションも変更できます)

パラメータ: vlaue/name: リクエスト パラメータを識別するために使用される名前 (リクエスト パス内のリクエスト パラメータの名前)。メソッド内のパラメータとリクエスト パス パラメータが完全に一致している限り、このパラメータも渡すことはできません。一貫性のある

required: このパラメータをリクエストパラメータで指定する必要があるかどうか: FALSE は必須ではないことを意味し、TRUE は指定する必要があることを意味します

パラメータのタイプが一致しない場合、または必要なパラメータが指定されていない場合は、400 エラーが報告されます。

役割: リクエストパラメータをコントローラメソッドの正式パラメータに変換する

使用例:
 

@RequestMapping("/requestB")
    public Object res(@RequestParam String name ,@RequestParam() Integer id){
        HashMap<String, String> map = new HashMap<>();
        map.put("name", name);
        map.put("id", id+"");
        return map;
    }

@RequestPart

@RequestPart は通常multipart/form-data、型データをコントローラー処理メソッドのパラメーターにマップするために使用されます。

アノテーション分析

  ①値:

    バインディングパラメータ名、パラメータ値はString型です。

  ②名前:

    バインディングパラメータ名、パラメータ値はString型です。name と value は同時に使用できますが、2 つの値が一致している必要があります。一致していないとエラーが発生します。(400)
  ③必須:

    指定された値をリクエスト ヘッダーに含める必要があるかどうか。デフォルト値は true です。

    required が true の場合、指定された値がリクエスト ヘッダーにない場合は例外がスローされます。

    required が false の場合、指定された値がリクエスト ヘッダーにない場合は null が返されます。

使用事例:

    @RequestMapping("/upload")
    //上传文件
    public Object upload(@RequestPart MultipartFile head, User user) throws IOException {
       head.transferTo(new File("D:/上传的"+head.getOriginalFilename()));
        HashMap<String, Object> map = new HashMap<>();
        map.put("file", head);
        return map;

    }

ファイルのアップロードで考えられるエラー: システムは指定されたファイル
java.io.FileNotFoundException を見つけることができません: C:\Users\86131\AppData\Local\Temp\tomcat.8080.6906634590984434583\work\Tomcat\localhost\ROOT\upload_135c4883_3414_49af_b54e_39dbe06 3b0de _00000002.tmp ( system find 指定されたファイルが見つかりませんでした。)

システムによって指定されたディレクトリに移動して、ファイルが正常にアップロードされたかどうかを確認してみましょう。

エラーは報告されましたが、ファイルは正常にアップロードされたことがわかりました。

エラーの原因を分析する前に、まずファイルのアップロードのロジックを分析します。クライアントがファイルをサーバーに送信すると、ファイルはまずシステムのネットワーク カードにエラーを報告し、次にファイル情報の一部をサーバーのメモリに保存します。 、関連するファイルの内容はローカルの一時ディレクトリに保存されます。transferTo() を呼び出すと、デフォルトで保存されたシステム ファイルが指定したファイル ディレクトリに移動されます。この場合、元の一時ディレクトリ内のファイルは失われます。 , そのため、後で関連するファイル情報を呼び出すときの方法は、まずサーバーのメモリ内を検索します。サーバーのメモリ内にそのような情報がない場合は、一時ディレクトリ内を検索する必要があります。そのような情報がない場合は、ファイルが一時ディレクトリにある場合、上記のエラーが報告されます。

この問題を解決するにはどうすればよいでしょうか?

解決策も比較的明確です。ファイル関連情報を呼び出すときは、transferTo() メソッドが実行される前にそれを呼び出すだけです。

@RequestBody

前述したように、アノテーションのないリクエスト パラメーターであっても、 @RequestParam アノテーションを使用していても、json データの解析はサポートされていません。一方、 @RequestBody は json データの解析を実現できますが、他のデータ型の解析はサポートしていませ。 。

使用例:

  @RequestMapping("/json")

    public Object jsonSend( @RequestBody User user){
        HashMap<String, String> map = new HashMap<>();
        map.put("name", user.getName());
        map.put("id", user.getId()+"");
        return map;
    }

構成クラスを通じてプログラムによる構成スキームを設定する

springbootプロジェクトは設定ファイルの形式を設定することで設定できることはわかっていますが、設定ファイルから設定するのが面倒だったり、設定ファイルでは実現できない設定をプログラミング(設定クラスの設定)で設定したりすることも可能です。 。この機能は @Configuration によって実現されます: @Configuration によって変更されたクラスは、springboot プロジェクトの開始時に構成をロードします。次の 2 つの例を使用して説明をロードします。

バックエンドパスの統合プレフィックスを設定します

機能: すべてのバックエンド コントローラーに統合プレフィックスを追加します (名前: api)

適用シナリオ: バックエンド リクエスト パスにアクセスする場合、その一部のパスの処理ロジックに何らかの統一的な検証を追加する必要があります。フロントエンド パスとバックエンド パスを区別するために、一律にすべてのコントローラのプレフィックス。

コード例を示します。

Web 開発に関連した設定を行っているため、設定は WebMvcConfigurer のインターフェイスを継承する必要があります。

@Configuration
public class AppConfig implements WebMvcConfigurer {
    //调用路径匹配的api,为所有的后端逻辑添加前缀
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
      configurer.addPathPrefix("api", c->{
          //通过循环遍历所有的后端controller判断是否要加前缀(暂时设置所有的路径都为前缀)
          //如果需要在此处使某些控制器不加前缀,在此处应该加一些别的逻辑经即可
         return true;
      });
    }

実際のパスには API リクエスト パスがありませんが、アクセスするときは「API」パスを介してアクセスする必要があります。そうしないと、404 が直接報告されます。

 

インターセプターの設定

まず、Web 開発の 3 つの主要なコンポーネントを理解しましょう: サーブレット (コネクタ)、リスナー (リスナー)、フィルター (フィルター)。明確にする必要があります: Spring は正式にインターセプターを提供しておらず、インターセプターは springmvc によって提供されます。しかし、その実装原理フィルターと同様です。

インターセプターの処理ロジックは次のとおりです。

 クライアントがリクエストを送り返す前に、リクエストはインターセプタの preHander 関連メソッドによって処理されます。preHander はブール値を返します。TRUE は下方向に実行を続け、FALSE は直接返します。コントローラ層が応答を返した後も、インターセプターを通過します。このとき、postHander() メソッドを呼び出し、最終的にクライアントに応答を返します。カスタム インターセプターは通常、次の 3 つのメソッドをオーバーライドします。

1. リクエストが処理される前に、preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) メソッドが呼び出されます。このメソッドは Interceptor クラスで最初に実行され、初期化前の操作を実行したり、現在のリクエストを前処理したり、リクエストを続行するかどうかを決定するための判断を行うために使用されます。このメソッドの戻り値は Boolean 型で、false が返された場合はリクエストが終了したことを意味し、後続の Interceptor および Controller は実行されません。true が返された場合は、次の preHandle メソッドの呼び出しを継続します。インターセプター (最後の場合) インターセプターが呼び出されるとき、現在のリクエストのコントローラー メソッドが呼び出されます。

2. postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) メソッドは、現在のリクエストが処理された後、つまり、Controller メソッドが呼び出された後に実行されますが、DispatcherServlet がレンダリングするビューを返す前に呼び出されます。 , ので、これを使用できます。メソッドでは、Controller によって処理される ModelAndView オブジェクトが操作されます。

3. afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) メソッドは、対応する Interceptor クラスの preHandle メソッドの戻り値が true の場合にのみ実行されます。名前が示すように、このメソッドはリクエスト全体が終了した後、つまり DispatcherServlet が対応するビューをレンダリングした後に実行されます。このメソッドは主にリソースのクリーンアップに使用されます。

インターセプタの設定プロセスは、①インターセプタのカスタマイズ ②インターセプトパスの設定 ③インターセプタの処理ロジックの設定 の 3 つの側面から設計および分析できます。

インターセプタには以下の3つのコードを与えます。
①パス処理:

ファジー マッチングをサポートするようにインターセプト パスを構成します。この構成方法は通常、インターセプト パスを追加し、インターセプトされない一部のパスを除外することによって処理されます。

/**: 任意のパスを追加します

/api/**: api の下に任意のパスを追加します

/api/*: api の下にディレクトリのレイヤーを追加します

除外パスを設定します。

/api/login: api の下のログイン ディレクトリを除外します。

/api/register: api 下の register ディレクトリを除外します。

②カスタムインターセプタ:

インターセプターをカスタマイズして HandlerInterceptor インターフェイスを参照し、インターフェイス内のメソッドを書き換えます。

③メソッドロジックの実現

オーバーライドされたメソッドにメソッド ロジックを実装する

完全なコード:

@Configuration
public class AppConfig implements WebMvcConfigurer {
    //调用路径匹配的api,为所有的后端逻辑添加前缀
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
      configurer.addPathPrefix("api", c->{
          //通过循环遍历所有的后端controller判断是否要加前缀(暂时设置所有的路径都为前缀)
         return true;
      });
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       //使用注册器进行注册过滤器
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/api/**").excludePathPatterns("/api/login")
                        .excludePathPatterns("/api/register");
    }
}
public class LoginInterceptor implements HandlerInterceptor {
    //设置请求逻辑:在请求前进行处理
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       //获取session
        HttpSession session = request.getSession(false);
        if(session!=null){
            String user = (String)session.getAttribute("user");
            if(user!=null){
                //判断是否是用户
                if(user.equals("admin")){
                    return true;
                }
            }
        }
        response.setStatus(401);

        return false;
    }
}

インターセプタ機能
ロギング:情報監視、情報統計、PV(Page View)計算などのリクエスト情報のログを記録、権限チェック:ログイン検出、プロセッサに入ってユーザがログインしているかどうかを検出、パフォーマンス
監視
:プロセッサは、リクエストの処理時間を取得するために、リクエストの開始時刻を処理前に記録し、処理後に終了時刻を記録します。(Apache などのリバース プロキシも自動的に記録できます)
一般的な動作: Cookie を読み取ってユーザー情報を取得し、ユーザー オブジェクトをリクエストに入力して、後続のプロセスの使用を容易にするとともに、ロケール、テーマ情報などを抽出します。 . 複数のプロセッサがある限り、必要なものはすべてインターセプタを使用して実装できます。

統合された例外処理

ブラウザ経由でリクエストを行った際にエラーが発生した場合、バックエンドのエラー情報がすべてブラウザ上に表示される可能性が高くなります(破壊的な操作)が、一方でユーザーエクスペリエンスにはあまり優しくありません。 。

そのため、コントローラ拡張には @ControllerAdvice アノテーションを使用、例外処理には @ExceptionHandle (例外クラス)を使用、例外処理には@ExceptionHandle (例外クラス)を使用し、統一例外処理とバックエンドエラー報告を統一する必要があります。処理ロジックは以下のとおりです。括弧内の例外クラス情報に従い、括弧内の例外クラスのエラーメッセージが発生した場合、以下のメソッドを使用してエラーレポートを処理します(例外処理のキャッチとなる関数です)。

@ControllerAdvice
public class ExceptionHandle {
    //默认以json形式返回数据
    @ResponseBody
    //统一捕获异常类
    @ExceptionHandler(Exception.class)
    public Object handle(Exception e){
        HashMap<String, Object> map = new HashMap<>();
        map.put("code",500);
        map.put("message",e.getMessage());
        return map;
    }

@ExceptionHandle (例外クラス) は括弧内の例外のみをキャプチャできます。括弧内の例外クラスのスコープ外に出ると、エラー情報をクライアントに直接返します: 変更されたエラーメッセージは次のとおりです。

@ControllerAdvice
public class ExceptionHandle {
    //默认以json形式返回数据
//    @ResponseBody
//    //统一捕获异常类
//    @ExceptionHandler(Exception.class)
//    public Object handle(Exception e){
//        HashMap<String, Object> map = new HashMap<>();
//        map.put("code",500);
//        map.put("message",e.getMessage());
//        return map;
//    }
    @ResponseBody
    //统一捕获异常类
    @ExceptionHandler(IOException.class)
    public Object handleIo(Exception e){
        HashMap<String, Object> map = new HashMap<>();
        map.put("code",500);
        map.put("message",e.getMessage());
        return map;
    }

統合された結果処理:

①カスタム結果クラス

@Data
public class Result {
    private Boolean ok;
    private Object data;
    private String error;
}

② @ControllerAdvice を使用して結果を均一に処理します。ok データ (データは返されたボディで直接処理されます) とエラーを設定します。

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        //进行赋值处理
        Result result = new Result();
        result.setOk(true);
        result.setData(body);
        result.setError(null);
        return result;
    }
}

この結果クラスを使用して、次のコードにアクセスします。

import java.util.HashMap;

/**
 * @author tongchen
 * @create 2023-04-28 10:34
 */
@RestController
public class UserController {
    @RequestMapping("/user/{id}/{name}")
    public Object user(@PathVariable String name,@PathVariable Integer id ){
        HashMap<String, Object> map = new HashMap<>();
        map.put("user", name);
        return map;
    }
}

結果は次のとおりです。

しかし、問題が見つかりました。このコードでは、 data 以外の返され​​た情報を直接記述しています。実際のビジネス シナリオでは、返された結果をどのように統一的に処理すればよいでしょうか? (異常結果処理と統一結果処理)

A: リターンクラスを変更し、リターンメソッドの統一設定を解除して、特定のビジネスシナリオで結果を返却し、例外クラスについては個別に結果を返却します

具体的なコードと結果は次のとおりです。

@Data
public class Result<T> {
    private Integer ok;//1代表成功 0代表失败
    private T data;
    private String msg;//正确或异常的信息
    public static <T>Result<T> success(T data){
        Result<T> result = new Result<>();
        result.setData(data);
        result.setOk(1);
        return result;
    }
    public static  <T>Result<T>error(String msg){
        Result<T> result = new Result<>();
        result.setOk(0);
       result.setMsg(msg);
        return result;
    }
}

 通常の結果クラス:

@RestController
public class UserController {
    @RequestMapping("/user/{id}/{name}")
    public Object user(@PathVariable String name,@PathVariable Integer id ){
        HashMap<String, Object> map = new HashMap<>();
        map.put("id", id);
        map.put("name",name);
        return Result.success(map);
    }
}

例外結果クラス:

public class MyException extends Exception{
    public MyException(String message) {
        super(message);
    }
}
@RestController
public class ExceptionController {
    @RequestMapping("/test")
    public void test() throws MyException {
        throw new MyException("HAHAHH");
    }
}

例外結果クラスの処理:
 

@ControllerAdvice
public class ExceptionHandle {
    //默认以json形式返回数据
//    @ResponseBody
//    //统一捕获异常类
//    @ExceptionHandler(Exception.class)
//    public Object handle(Exception e){
//        HashMap<String, Object> map = new HashMap<>();
//        map.put("code",500);
//        map.put("message",e.getMessage());
//        return map;
//    }
    @ResponseBody
    //统一捕获异常类
    @ExceptionHandler(MyException.class)
    public Object handleIo(Exception e){
        HashMap<String, Object> map = new HashMap<>();
      return Result.error("服务器错误");
    }


}

通常の結果:

 例外の結果:

responseBodyAdviceの役割について

 

 ResponseBodyAdvice インターフェイスは、コントローラーがリターンを実行した後、応答がクライアントに返される前に、応答に対して何らかの処理を実行します。これにより、応答データの統一されたカプセル化または暗号化を実現できます。

  このインターフェースには 2 つのメソッドがあります。

(1) supports—beforeBodyWrite メソッドを実行するかどうかを判断し、実行する場合は true、実行しない場合は false—supports メソッドを通じて、応答を処理するクラスまたはメソッドを選択でき、残りは処理されません。

(2) beforeBodyWrite - 応答処理の具体的な実行方法。

おすすめ

転載: blog.csdn.net/m0_65431718/article/details/130361545