前後端分離プロジェクト処理異常ベストプラクティス推奨(vue,Java)


異常をどのように処理するかはプロジェクトの中で極めて頭が痛いことであり、特に前後に分離されたプロジェクトでは、ExceptionはRestfulとして処理しなければならない.ここには、Exceptionを処理するコードがプロジェクトコードに分散することを避ける方法が含まれており、異常処理の再構築と多言語サポートに大きな迷惑をかける.また、一部のデータベースのerror-codeや500のHTTP STATUSではなく、ユーザーが見たエラーメッセージが有効であるように、例外情報を正しく定義する方法も含まれています.
異常がJSONとしてフロントエンドに正常に伝達される場合、フロントエンドコードがどのように異常を解析するか、異常に含まれる情報をユーザに表示するか、バックエンドJavaの異常生成と伝達、およびフロントエンドVUEが異常を受信した後の処理方法について説明する.
我々が実現すべき結果は,フロントエンドが次のJSONメッセージを受信し,メッセージの内容をユーザに表示することである.
{"exception":"DuplicatedUserException","error":"Conflict","message":"admin      . ","status":409,"errors":null}

メッセージの内容から、登録するユーザ名がすでに占有されていることがわかります.HttpStatus_Conflict:409,例外はユーザがカスタマイズしたDuplicatedUserExceptionである.
バックエンドJavaコード:
抽象クラスを定義するErrorResponseの生成を含み、将来他のカスタム例外ごとに対応するHandlerがこの抽象クラスを継承します.
import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpStatus;

import com.lims.api.exception.ErrorResponse;

/**
 * Extend this to code an exception handler
 */
public abstract class AbstractExceptionHandler {
	
	protected final Log log = LogFactory.getLog(this.getClass());
	
	private String exceptionName;
	
	public AbstractExceptionHandler(String exceptionName) {
		this.exceptionName = exceptionName;
	}

	public String getExceptionName() {
		return exceptionName;
	}
	
	protected String getMessage(T ex) {
		return ex.getMessage();
	}
	
	protected HttpStatus getStatus(T ex) {
		return null;
	}
	
	protected Collection getErrors(T ex) {
		return null;
	}

	public ErrorResponse getErrorResponse(T ex) {
		
		ErrorResponse errorResponse = new ErrorResponse();
		
		String message = getMessage(ex);
		if (message != null)
			errorResponse.setMessage(message);
		
		HttpStatus status = getStatus(ex);
		if (status != null) {
			errorResponse.setStatus(status.value());
			errorResponse.setError(status.getReasonPhrase());
		}
		
		errorResponse.setErrors(getErrors(ex));
		
		return errorResponse;
	}
}

カスタム例外クラス:DuplicatedUserException、例外メッセージはpropertyファイルによって与えられ、メッセージ内容の変更と多言語サポートを容易にする
import org.springframework.http.HttpStatus;

import com.lims.api.util.LimsUtils;

public class DuplicatedUserException extends RuntimeException {

	/**
	 * 
	 */
	private static final long serialVersionUID = -21168497361531088L;
	// HTTP Status code to be returned
	private HttpStatus status = HttpStatus.BAD_REQUEST;

	public DuplicatedUserException(String userName) {
		super(LimsUtils.getMessage("com.lims.api.exception.DuplicatedUserException", userName));
	}

	public HttpStatus getStatus() {
		return status;
	}

	public void setStatus(HttpStatus status) {
		this.status = status;
	}

	public DuplicatedUserException httpStatus(HttpStatus status) {
		this.status = status;
		return this;
	}

}

カスタム例外クラスのHandler
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import com.lims.api.exception.AbstractExceptionHandler;
import com.lims.api.security.web.exception.DuplicatedUserException;

@Component
@Order(Ordered.LOWEST_PRECEDENCE)
public class DuplicatedUserExceptionHandler extends AbstractExceptionHandler {

	public DuplicatedUserExceptionHandler() {
		
		super(DuplicatedUserException.class.getSimpleName());
		log.info("DuplicatedUserExceptionHandler Created");
	}
	

	@Override
	public HttpStatus getStatus(DuplicatedUserException ex) {
		return ex.getStatus();
	}

}

以上の3つのクラスに基づいて,@Controllerで投げ出されたすべての異常をResponseに含めてフロントエンドに渡すことができる.次のコードの例を示します.
    @PostMapping("/sign-up")
    public void signUp(@RequestBody ApplicationUser user){
        if(!applicationUserService.isValid(user)) {
        	throw (new DuplicatedUserException(user.getUserName()).httpStatus(HttpStatus.CONFLICT));
        };
        user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        applicationUserRepository.save(user);
    }

フロントエンドVUEの多くはAxiosを使用します.ここでは例を示します.
 vm.$ajax.post('/api/users/sign-up', register)
            .then(function (res) {
              toastr.success(res.data.message)
            }).catch(function (error) {
              toastr.error(error.response.data.message)
            })

このように前後端の異常処理は構造的に非常に簡潔であり,各カスタムの異常はユーザにより友好的な情報を表示することができ,propertyファイルによる情報の定義により属性ファイルの多言語サポート機能を十分に利用することができる.
フロントエンドで例外を処理するコードは、条件付き処理を必要とせず、各例外のメッセージ表示は統一されたコードである.フロントエンドコードモジュールの再利用には重要な役割を果たす.
Cheers!