JSR303 とインターセプターの使用

1.JSR303

1. JSR303を理解する

JSRとはJava Specific Requestsの略で、Javaの仕様提案を意味します。これは、標準化された技術仕様を追加するよう JCP (Java Community Process) に正式に要求するものです。誰でも JSR を送信して、新しい API やサービスを Java プラットフォームに追加できます。JSR は Java の世界では重要な標準となっています。JSR-303 は、Bean Validation と呼ばれる JAVA EE 6 のサブ仕様です。Hibernate Validator は、Bean Validation の参照実装です。Hibernate Validator は、いくつかの追加の制約に加えて、JSR 303 仕様のすべての組み込み制約の実装を提供します。

 データの検証は、プレゼンテーション層から永続層までのすべてのアプリケーション層で発生する共通のタスクです。多くの場合、同じ検証ロジックがすべてのレイヤーで実装されますが、これには時間がかかり、エラーが発生しやすくなります。これらの検証の重複を避けるために、開発者は多くの場合、検証ロジックをドメイン モデルに直接バンドルし、ドメイン クラスと、実際にはクラス自体に関するメタデータである検証コードを混合します。

2. JSR303を使用する理由

フロントエンドはすでにデータを検証していませんか? なぜ検証を行う必要があるのでしょうか? なぜ検証を使用しないのでしょうか? フロントエンドのコード検証が適切に記述されていない場合、またはプログラミングを少し知っている人の場合、フロントエンドを直接バイパスしてリクエストを送信し (Postman などのテスト ツールを介して異常なデータ リクエストを行う)、間違ったコードを渡す可能性があります。パラメータ。バックエンド コードが危険にさらされていませんか?

したがって、通常はフロントエンドで 1 回の検証、バックエンドで 1 回の検証を実行することで、セキュリティを大幅に向上させることができます。

3.よく使われる注釈

注釈 説明する
@ヌル オブジェクトが null であることを確認するために使用されます
@NotNull null にすることができず、長さが 0 の文字列をチェックできないオブジェクトに使用されます。
@NotBlank String 型にのみ使用され、null や、trim()>0 後のサイズは使用できません
@空ではない コレクション クラスに使用されます。String クラスは null およびサイズ > 0 にすることはできません。ただし、スペースを含む文字列は検証できません。
@サイズ オブジェクト (配列、コレクション、マップ、文字列) の長さが指定された範囲内であるかどうかを確認するために使用されます。
@長さ String オブジェクトに使用されるサイズは、指定された範囲内である必要があります
@パターン String オブジェクトが正規表現に準拠するかどうかの規則
@Eメール String オブジェクトがメールボックス形式に準拠しているかどうかを判断するために使用されます。
@分 Number オブジェクトと String オブジェクトが指定された値以上であるかどうかを判断するために使用されます。
@マックス Number オブジェクトと String オブジェクトが指定された値以下であるかどうかを判断するために使用されます。
@AssertTrue ブール値オブジェクトが true かどうか
@AssertFalse ブールオブジェクトが false かどうか

 4. @Validated と @Valid の違い

@検証済み:

  • スプリング社提供

  • サポートグループの確認

  • 型、メソッド、およびメソッド パラメーターで使用できます。ただし、メンバー属性 (フィールド) には使用できません。

  • メンバー属性(フィールド)に追加できないため、カスケード検証だけでは完了できず、@Validと連携する必要がある

@有効:

  • JDK によって提供 (標準 JSR-303 仕様)

  • グループ検証はサポートされていません

  • メソッド、コンストラクター、メソッド パラメーター、メンバー プロパティ (フィールド) で使用できます。

  • メンバー属性 (フィールド) に追加して、カスケード検証を個別に完了できます。

5. JSR303を使用する

1. pom.xml の依存関係をインポートする 

<!-- JSR303 -->
<hibernate.validator.version>6.0.7.Final</hibernate.validator.version>

<!-- JSR303 -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>${hibernate.validator.version}</version>
</dependency>

2. 構成の検証

package com.xzs.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.NotBlank;

import javax.validation.constraints.NotNull;

@Data//相当于set get toString方法
@AllArgsConstructor //有参构造器
@NoArgsConstructor 
public class Clazz {
    @NotNull(message = "班级编号不能为空")
//    @Size(max = 100,min = 10,message = "大小必须在10至100之间")
    protected Integer cid;

    @NotBlank(message = "班级名不能为空")
    protected String cname;

    @NotBlank(message = "班级教员老师不能为空")
    protected String cteacher;

    private String pic="暂无图片";


}

3.検証方法

   @RequestMapping("/valiAdd")
    public String valiAdd(@Validated Clazz clazz, BindingResult result, HttpServletRequest req){
//        如果服务端验证不通过,有错误
        if(result.hasErrors()){
//            服务端验证了实体类的多个属性,多个属性都没有验证通过
            List<FieldError> fieldErrors = result.getFieldErrors();
            Map<String,Object> map = new HashMap<>();
            for (FieldError fieldError : fieldErrors) {
//                将多个属性的验证失败信息输送到控制台
                System.out.println(fieldError.getField() + ":" + fieldError.getDefaultMessage());
                map.put(fieldError.getField(),fieldError.getDefaultMessage());
            }
            req.setAttribute("errorMap",map);
        }else {
            this.clazzBiz.insertSelective(clazz);
            return "redirect:list";
        }
        return "clz/edit";
    }
フロントエンド
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户编辑、新增公共页面</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/${empty c ? 'clz/valiAdd' : 'clz/edit'}" method="post">
    学生id:<input type="text" name="id" value="${c.cid }"><span STYLE="color: red">${errorMap.cid}</span><br>
    学生名:<input type="text" name="name" value="${c.cname }"><span STYLE="color: red">${errorMap.cname}</span><br>
    老师:<input type="text" name="loginname" value="${c.cteacher }"><span STYLE="color: red">${errorMap.cteacher}</span><br>


    <input type="submit">
</form>
</body>
</html>

結果:

2.インターセプター

2.1.インターセプターとは何ですか?

SpringMVC のプロセッサ インターセプタはサーブレット開発におけるフィルタに似ており、プロセッサの前処理と後処理に使用されます。これは Web フレームワークに依存しており、実装ではアスペクト指向プログラミング (AOP) のアプリケーションである Java のリフレクション メカニズムに基づいています。インターセプターは Web フレームワークの呼び出しに基づいているため、Spring の依存関係注入 (DI) を使用して一部のビジネス操作を実行でき、同時にインターセプター インスタンスをコントローラーのライフ サイクル内で複数回呼び出すことができます。

2.2.インターセプターとフィルター

フィルターとは何ですか?

サーブレットコンテナに依存します。実装時の関数コールバックに基づいて、ほぼすべてのリクエストをフィルタリングできますが、欠点は、コンテナの初期化時にフィルタ インスタンスを 1 回しか呼び出せないことです。フィルターを使用する目的は、フィルター内の文字エンコーディングの変更、フィルター内の HttpServletRequest の一部のパラメーターの変更 (下品なテキストや危険な文字などのフィルターなど) など、いくつかのフィルター操作を実行することです。

 つまり、インターセプターはリクエストの処理中にリクエストをインターセプトして処理するコンポーネントであり、前処理、後処理、リクエストのインターセプト、およびフィルター機能を実装するために使用できます。リクエストの統合処理と制御のための柔軟なメカニズムを提供します。

インターセプターとフィルターの違い

  • フィルター

    1. フィルタはサーブレット テクノロジに属しており、あらゆる Web プロジェクトで使用できます。

    2.filter は主にすべてのリクエストをフィルタリングするためです

    3.フィルターの実行時間がインターセプターよりも早い

  • インターセプター

    1.interceptor は SpringMVC テクノロジーに属しており、使用する前に SpringMVC 環境が必要です。

    2.interceptor は通常、プロセッサーコントローラーをインターセプトします

    3.interceptor は、dispatcherServlet によって処理されたリクエストのみをインターセプトできます

2.3 インターセプタのアプリケーション シナリオと機能
権限の検証: インターセプタは、ユーザーがログインしているかどうか、リソースにアクセスする権限があるかどうかなどを確認するなど、ユーザーの権限を検証するために使用できます。リクエストを傍受し、権限の検証を実行することで、システムのセキュリティとデータの整合性を保護できます。

ロギング: インターセプターを使用して、要求された URL、要求パラメーター、処理時間、応答結果などを含む要求および応答のログ情報を記録できます。ログを記録することで、システムの監視、トラブルシューティング、パフォーマンスの最適化を簡単に実行できます。

パラメータの前処理: インターセプタは、パラメータの検証、変換、変更など、リクエスト パラメータを前処理できます。これにより、リクエスト パラメータの有効性と一貫性が確保され、エラーや例外の発生が減少します。

例外処理: インターセプターを使用すると、要求プロセス中に発生する例外を均一に処理できます。例外をインターセプトして均一に処理することで、わかりやすいエラー プロンプト ページを提供したり、特定のエラー情報を返すことができ、システムのフォールト トレランスとユーザー エクスペリエンスが向上します。

キャッシュ制御: インターセプターを使用して、リクエストされた URL、パラメーター、その他の条件、キャッシュの有効期限などに基づいてキャッシュを使用するかどうかを決定するなど、キャッシュの使用を制御できます。リクエストをインターセプトしてキャッシュ制御を行うことで、システムのパフォーマンスと応答速度を向上させることができます。

リクエストのリダイレクト: インターセプターは、特定の条件に従ってリクエストをリダイレクトし、処理のためにリクエストを他の URL またはプロセッサに転送できます。リクエストをインターセプトしてリダイレクトすることで、リクエストの転送、ルーティング、プロセス制御を実現できます。

統合処理: インターセプターを使用して、リクエストの統合エンコード変換、文字セット設定、応答ヘッダー設定などの統合処理ロジックを実装できます。リクエストをインターセプトして均一に処理することで、システムの一貫性と保守性が向上します。

        インターセプタは Web 開発で広く使用されており、リクエストをインターセプト、処理、変更し、権限の検証、ロギング、パラメータの前処理、例外処理、キャッシュ制御、リクエストのリダイレクト、統合処理などの機能を実装できます。インターセプタを使用することで、システムのセキュリティ、安定性、パフォーマンス、保守性を向上させることができます。

 インターセプターの作成と使用

インターセプターのワークフロー

写真が示すように

package com.xzs.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class OneInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("【OneInterceptor】:preHandle...");

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("【OneInterceptor】:postHandle...");

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("【OneInterceptor】:afterCompletion...");
    }
}

 インターセプターの構成

<mvc:interceptors>
        <bean class="com.xzs.interceptor.OneInterceptor"></bean>
</mvc:interceptors>

テスト 

 リクエストを送信すると、取得された結果が表示されます

以上がインターセプトに失敗した場合のインターセプト方法です。

 このコードの true 値を false に変更すると、インターセプトが成功します。

インターセプトが成功すると、次のコードは実行されなくなります。

複数のインターセプター

package com.xzs.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TwoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("【TwoInterceptor】:preHandle...");

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("【TwoInterceptor】:postHandle...");

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("【TwoInterceptor】:afterCompletion...");
    }
}

 構成

   <mvc:interceptors>
        <!--2) 多拦截器(拦截器链)-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.xzs.interceptor.OneInterceptor"/>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/clz/**"/>
            <bean class="com.xzs.interceptor.TwoInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

 ご覧のとおり、再度テストしたときに複数のインターセプトが行われました

 ログイン傍受のケース

ログインブロッカー

package com.xzs.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("【implements】:preHandle...");
        StringBuffer url = request.getRequestURL();
        if (url.indexOf("/login") > 0 || url.indexOf("/logout") > 0){
            //        如果是 登录、退出 中的一种
            return true;
        }
//            代表不是登录,也不是退出
//            除了登录、退出,其他操作都需要判断是否 session 登录成功过
        String uname = (String) request.getSession().getAttribute("uname");
        if (uname == null || "".equals(uname)){
            response.sendRedirect("/page/login");
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

フロントエンドライティング

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录界面</title>
</head>
<body>
<h1>登录界面</h1>
<form action="/login" method="post">
    账号:<input name="uname">
    <input type="submit">
</form>
</body>
</html>

 運用制御層へのログイン

package com.xzs.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@Controller
public class LoginController {
    @RequestMapping("/login")
    public String login(HttpServletRequest req){
        String uname = req.getParameter("uname");
        HttpSession session = req.getSession();
        if ("zs".equals(uname)){
            session.setAttribute("uname",uname);
        }
        return "redirect:/clz/list";
    }

    @RequestMapping("/logout")
    public String logout(HttpServletRequest req){
        req.getSession().invalidate();
        return "redirect:/clz/list";
    }
}

テスト

「zs」は入力しないでください

張三登場 

 

 やめる

おすすめ

転載: blog.csdn.net/weixin_72997875/article/details/132844260