Spring Validatorインターフェースチェックとグローバル異常プロセッサ


Spring Validatorインターフェースチェック
前のログはBean Validationチェック機構を使用して、基本的なデータタイプをチェックします。方法は本体類の属性に注釈を使用して検証方式を識別し、最後にController類に具体的な方法のモダリティに@Vlidated注釈を追加します。Bean Validationチェックは、Javaエンティティクラスで制約されているという欠点があります。複数のプロセッサ方法が同じエンティティクラスを使用する必要がある場合、エンティティクラスの属性に定義されているチェックルールは区分しにくいです。一部のプロセッサは属性を検証するだけでなく、複数の属性を検証する必要があります。各プロセッサのためにエンティティクラスを作成することはできません。解決の方法は前のログでも述べています。パケットチェック方式を使って、SpringのValidatorインターフェースチェックを使って、外部であるオブジェクトを指定する検査規則を許可します。
検証実行クラス
SpringのValidatorはインタフェースです。私達自身の検査実現類はこのインターフェースを実現しなければならないです。書き換え方法でユーザー定義の検査規則を完成できます。私達が実現する方法は二つあります。supports()とvalidate()

public class UserValidator implements Validator {
	@Override
	public boolean supports(Class<?> clazz) {
		//         class           
		return User.class.equals(clazz);
	}
 
	@Override
	public void validate(Object obj, Errors errors) {
		//       errors  
		ValidationUtils.rejectIfEmpty(errors, "username", "Username.is.empty", 
				"        。");
		User user = (User) obj;
		if (user.getPassword() == null || user.getPassword().equals("")) {
			// rejectValue()  :     ,     ,        
			errors.rejectValue("password", "Password.is.empty", "       。");
		} else if (user.getPassword().length() < 8) {
			errors.rejectValue("password", "Length.too.short", "          。");
		}
	}
}
Support()メソッドの機能は、このクラスが検証されたエンティティクラスをサポートしているかどうかを判断することです。例えば、この検査クラスは、Userクラスを検証し、supports()方法が検証されたエンティティクラスに入ってきて、反射機構によってUserクラスのインスタンスを取得し、着信された検証エンティティクラスと一致するかどうかを判断する。Validate()方法は検証を行う具体的な実施方法であり、方法パラメータリストの中にErrersオブジェクトがあり、中に検査のエラー情報を保存することに責任があります。以下は具体的な検査規則です。Validation Utilsチェックツール類の方法を使って検証します。提供されたパラメータはエラー情報オブジェクトerror、検査のフィールド名(検証エンティティクラスの属性について)で、グローバルエラーコード(BeaBen Validation検査ではエラーコードに基づいて外部propertiesのエラーメッセージを使用します。)最後のパラメータはデフォルトエラーメッセージです。グローバルエラーコードに対応するメッセージが見つからない場合は、デフォルトのエラーメッセージ情報を使用します。
Validation Utilsチェックツールクラスを使用する以外にも、23行目はerroeオブジェクトの方法を使用して、チェックエラー情報、パラメータ、Validation Utils類の取得方法を設定することができます。
Controller実現類
検査器類の配置が完了したら、具体的な業務論理処理部分、Controller類で使用します。

@Controller
@RequestMapping("user")
public class InterfaceValidationController {
	@InitBinder
	public void initBinder(DataBinder binder) {
		//  DataBinder    Validator    
		binder.setValidator(new UserValidator());
	}
	
	@RequestMapping("login")
	public String login(Model model, @Valid User user, BindingResult result) {
		List<ObjectError> allErrors = null;
		if (result.hasErrors()) {
			allErrors = result.getAllErrors();
			//         
			for(ObjectError objectError : allErrors) {
				System.out.println("code = " + objectError.getCode() + 
						"DefaultMessage = " + objectError.getDefaultMessage());
				//             
				model.addAttribute("allErrors", allErrors);
			}
			
			//       
			return "users/login";
		} else {
			//         ,          
			return "users/successLogin";
		}
	}
まずinitBinder()法により、Controller類の方法で検証器のバインディングを行う必要があり、方法はData Binderオブジェクトパラメータが必要であり、Data Binderオブジェクトの機能はデータバインディングを行い、データをタイプ変換したり、検証器を設定したりすることができる。DataBinderにはBindingResoultというメンバー変数があり、データが検証されたデータにエラー情報があるとBindingResoultオブジェクトの中のErrers属性に入れられます。Errersオブジェクトのセットの前に述べたように、エラー情報を保存するために使用されます。Controller具体的な方法のパラメータリストには、検査対象のデータオブジェクトUser類に@Validの注釈を追加し、当該オブジェクトに対してデータチェックを行い、BindingResultオブジェクトを追加します。15行目は、対象のhasErrrors()方法でチェックが間違っているかどうかを判断し、getAllErrrors()法を使ってエラー情報を取得して出力することができます。最後の22行目はエラー情報をフロントエンドページに表示し、ユーザーに提示します。
フロントページテスト
最後に、フロントエンドページで簡単なログインテストを行います。

<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>    </title>
</head>
<body>
	<from action="login.action" method="post">
		   :<input type="text" name="username" /></br>
		  :  &nbsp;&nbsp;&nbsp;<input type="password" name="password" /></br>
		<input type="submit" value="  "/>
		<!--          -->
		<c:if test="${allErrors != null }">
			<c:forEach items="${allErrors}" var="error">
				</br><font color="red">${error.defaultMessage}</font>
			</c:forEach>
		</c:if>
	</from>
</body>
</html>
15行目はバックグラウンドから送られてきたallErrersエラーメッセージのセットを巡回しました。チェックエラーが発生したらエラーメッセージが表示されます。前の検証器の構成により、User類オブジェクトのデータ検証にユーザ名とパスワードが空であることは許されません。

入力情報が正しい場合、ユーザー名とパスワードが空ではなく、パスワードの長さが8桁以下でなければ、成功的にジャンプできます。

グローバル異常プロセッサException Resoliver
プログラムの実行時のエラー情報については、ログを見てエラーを確認できます。エラー情報をフロントページにアップロードすると、エラーの原因が分かりますように、エラー情報を処理して、情報をフロントページに転送してキャプチャします。エラー情報の捕獲と加工処理を完了するには、我々の異常プロセッサを配置する必要があります。異常プロセッサは、プログラムをカスタマイズして実行している時に、どのように異常を解析するかを目的としています。また、例外プロセッサを設定する必要があります。キャプチャされた異常に対して、カスタム異常クラスに配置された予期異常であれば、該当のエラー情報を抛り出します。そうでなければ、他の表示を行います。
カスタム異常クラス
まず、カスタム異常クラスです。例として、Userクラスを扱う異常クラスと異常プロセッサを定義します。異常クラスでは、Userクラスに異常が発生した場合のエラー情報を設定します。

package com.mvc.exception;
 
public class UserException extends Exception {
	private static final long serialVersionUID = 1L;
	private String exceptionMessage;
	
	public UserException(String exceptionMessage) {
		super(exceptionMessage);
		this.exceptionMessage = exceptionMessage;
	}
	
	public String getExceptionMessage() {
		return exceptionMessage;
	}
	public void setExceptionMessage(String exceptionMessage) {
		this.exceptionMessage = exceptionMessage;
	}
}
カスタム異常クラスUserExceptionはUser類の異常を専門に処理していますが、User類はどのように指定されますか?これは異常プロセッサで完了し、UserExceptionはExceptionクラスを引き継いでいます。このように、私達は具体的なController方法でthrowsを投げます。このクラスでは、異常情報を格納するための異常情報変数が定義されており、異常プロセッサがUser類の異常を捉えるとUserExceptionの構造方法で異常情報を設定し、最後にUserExceptionをスローします。
異常プロセッサ
異常プロセッサの構成に来て、異常プロセッサは捕獲と処理の異常の核心であり、Spring MVCにおいて、一階の異常は一級ずつ上に投げて、最後に大域異常プロセッサに到達します。大域異常プロセッサの仕事は主に四段階があります。
  • 異常を捕獲し、異常タイプを解析した。
  • 異常が予期異常(定義された異常類がある)であれば、該当する異常情報をスローする。
  • 異常が予期されていない場合、カスタム異常クラスを作成し、対応する異常情報(例えば、「未知の異常情報」)をスローする。
  • は、異常情報をフロントエンドページに結びつけ、対応する異常情報ページにジャンプする。
  • 上記のカスタム異常クラスに合わせて、User類に対する異常プロセッサの構成を見てみよう。
    
    package com.mvc.exception;
     
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.web.servlet.HandlerExceptionResolver;
    import org.springframework.web.servlet.ModelAndView;
     
    public class UserExceptionResolver implements HandlerExceptionResolver {
    	@Override
    	public ModelAndView resolveException(HttpServletRequest request, 
    			HttpServletResponse response, Object handler, Exception ex) {
    		//           
    		UserException userException = null;
    		if (ex instanceof UserException) {
    			//        UserException,             
    			userException = (UserException) ex;
    		} else {
    			//               
    			userException = new UserException("      。");
    		}
    		
    		//       
    		String errorMessage = userException.getExceptionMessage();
    		ModelAndView modelAndView = new ModelAndView();
    		//            
    		modelAndView.addObject("errorMessage", errorMessage);
    		//          
    		modelAndView.setViewName("errorPage/userError");
    		
    		return modelAndView;
    	}
    	
    }
    Spring MVCにおいて、異常情報は最終的にDisplatch Servletを通じてグローバル異常プロセッサにより処理され、グローバル異常プロセッサがHandlerException Resoliverインターフェースの接続を実現する必要があります。この方法には2つのパラメータがあるので注意してください。object handlerは異常プロセッサが処理する対象を指定します。Exception exは明らかに下の階から投げられた異常を受信します。
    私達の異常プロセッサUserException Resoloverでは、14行目はまず異常なタイプが私達の定義の予期している異常UserExceptionかどうかを判断します。最後の26行目は、異常情報を処理した後、フロントエンドページに送信して表示し、エラーメッセージ画面にジャンプします。
    テストケース
    最後に私達の異常プロセッサを使います。まずSpringプロファイルにこの異常プロセッサを追加します。
    
    <!--           -->
    <bean class="com.mvc.exception.UserExceptionResolver"></bean>
    その後、Controller類の方法で相応の判断をし、予期異常があれば、抛り出す:
    
    @Controller
    @RequestMapping("user")
    public class InterfaceValidationController {
    	@InitBinder
    	public void initBinder(DataBinder binder) {
    		//  DataBinder    Validator    
    		binder.setValidator(new UserValidator());
    	}
     
    	@RequestMapping("login")
    	public String login(Model model, @Valid User user, BindingResult result) 
    			throws UserException {
    		boolean allowVisit = checkUser(user);
    		if (!allowVisit) {
    			//          ,    
    			throw new UserException("       !");
    		}
    		
    		List<ObjectError> allErrors = null;
    		if (result.hasErrors()) {
    			allErrors = result.getAllErrors();
    			//         
    			for(ObjectError objectError : allErrors) {
    				System.out.println("code = " + objectError.getCode() + 
    						"DefaultMessage = " + objectError.getDefaultMessage());
    				//             
    				model.addAttribute("allErrors", allErrors);
    			}
    			
    			//       
    			return "users/login";
    		} else {
    			//         ,          
    			return "users/successLogin";
    		}
    	}
    57行目を見ることができます。最後にエラーページにジャンプして、エラー情報を表示します。
    
    <%@ page language="java" import="java.util.*" 
    	contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    <meta charset="utf-8">
    <title>    </title>
    </head>
    <body>
    	    ,      :</br>
    	<h3>
    		<font color="red">${errorMessage}</font>
    	</h3></br>
    </body>
    </html>

    完全コードはGitHubにアップロードされました。
    https://github.com/justinzengtm/SSM-Framework/tree/master/SpringMVC_プロジェクト
    以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。