1. 개요

여기 Baeldung에 있는 등록 시리즈 의 마지막 몇 기사에서 우리는 MVC 방식으로 필요한 대부분의 기능을 구축했습니다.

이제 이러한 API 중 일부를 보다 RESTful 접근 방식으로 전환할 것입니다.

2. 레지스터 작업

주요 Register 작업부터 시작하겠습니다.

@PostMapping("/user/registration")
public GenericResponse registerUserAccount(
      @Valid UserDto accountDto, HttpServletRequest request) {
    logger.debug("Registering user account with information: {}", accountDto);
    User registered = createUserAccount(accountDto);
    if (registered == null) {
        throw new UserAlreadyExistException();
    }
    String appUrl = "http://" + request.getServerName() + ":" + 
      request.getServerPort() + request.getContextPath();
   
    eventPublisher.publishEvent(
      new OnRegistrationCompleteEvent(registered, request.getLocale(), appUrl));

    return new GenericResponse("success");
}

그렇다면 이것이 원래 MVC 구현과 어떻게 다릅니까?

여기 간다:

  • 이제 요청이 HTTP POST에 올바르게 매핑되었습니다.
  • 이제 적절한 DTO를 반환하고 Response body에 직접 마샬링합니다.
  • 우리는 더 이상 메서드에서 오류 처리를 전혀 다루지 않습니다.

또한 기존 showRegistrationPage() 를 제거합니다 . 이는 단순히 등록 페이지를 표시하는 데 필요하지 않기 때문입니다.

3. registration.html

또한 registration.html 을 다음과 같이 수정해야 합니다.

  • Ajax를 사용하여 등록 양식 제출
  • 작업 결과를 JSON으로 수신

여기 간다:

<html>
<head>
<title th:text="#{label.form.title}">form</title>
</head>
<body>
<form method="POST" enctype="utf8">
    <input  name="firstName" value="" />
    <span id="firstNameError" style="display:none"></span>
 
    <input  name="lastName" value="" />
    <span id="lastNameError" style="display:none"></span>
                     
    <input  name="email" value="" />           
    <span id="emailError" style="display:none"></span>
     
    <input name="password" value="" type="password" />
    <span id="passwordError" style="display:none"></span>
                 
    <input name="matchingPassword" value="" type="password" />
    <span id="globalError" style="display:none"></span>
 
    <a href="#" onclick="register()" th:text="#{label.form.submit}>submit</a>
</form>
             
 
<script src="jquery.min.js"></script>
<script type="text/javascript">
var serverContext = [[@{/}]];

function register(){
    $(".alert").html("").hide();
    var formData= $('form').serialize();
    $.post(serverContext + "/user/registration",formData ,function(data){
        if(data.message == "success"){
            window.location.href = serverContext +"/successRegister.html";
        }
    })
    .fail(function(data) {
        if(data.responseJSON.error.indexOf("MailError") > -1)
        {
            window.location.href = serverContext + "/emailError.html";
        }
        else if(data.responseJSON.error.indexOf("InternalError") > -1){
            window.location.href = serverContext + 
              "/login.html?message=" + data.responseJSON.message;
        }
        else if(data.responseJSON.error == "UserAlreadyExist"){
            $("#emailError").show().html(data.responseJSON.message);
        }
        else{
            var errors = $.parseJSON(data.responseJSON.message);
            $.each( errors, function( index,item ){
                $("#"+item.field+"Error").show().html(item.defaultMessage);
            });
            errors = $.parseJSON(data.responseJSON.error);
            $.each( errors, function( index,item ){
                $("#globalError").show().append(item.defaultMessage+"<br>");
            });
 }
}
</script>
</body>
</html>

4. 예외 처리

일반적으로 좋은 예외 처리 전략을 구현하면 REST API가 더 강력해지고 오류가 발생하기 쉽습니다.

다른 예외를 깔끔하게 처리하기 위해 동일한 @ControllerAdvice 메커니즘을 사용하고 있으며 이제 새로운 유형의 예외가 필요합니다.

이것은 BindException 입니다. 이것은 UserDto 의 유효성이 검사될 때(잘못된 경우) throw됩니다 . 기본 ResponseEntityExceptionHandler 메서드 인 handleBindException() 을 재정 의하여 Response body에 오류를 추가합니다.

@Override
protected ResponseEntity<Object> handleBindException
  (BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
    logger.error("400 Status Code", ex);
    BindingResult result = ex.getBindingResult();
    GenericResponse bodyOfResponse = 
      new GenericResponse(result.getFieldErrors(), result.getGlobalErrors());
    
    return handleExceptionInternal(
      ex, bodyOfResponse, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
}

다음으로 사용자가 이미 존재하는 이메일로 등록할 때 발생하는 사용자 정의 Exception UserAlreadyExistException 도 처리해야 합니다.

@ExceptionHandler({ UserAlreadyExistException.class })
public ResponseEntity<Object> handleUserAlreadyExist(RuntimeException ex, WebRequest request) {
    logger.error("409 Status Code", ex);
    GenericResponse bodyOfResponse = new GenericResponse(
      messages.getMessage("message.regError", null, request.getLocale()), "UserAlreadyExist");
    
    return handleExceptionInternal(
      ex, bodyOfResponse, new HttpHeaders(), HttpStatus.CONFLICT, request);
}

5. 일반 응답

또한 이러한 유효성 검사 오류를 유지하기 위해 GenericResponse 구현 을 개선해야 합니다.

public class GenericResponse {

    public GenericResponse(List<FieldError> fieldErrors, List<ObjectError> globalErrors) {
        super();
        ObjectMapper mapper = new ObjectMapper();
        try {
            this.message = mapper.writeValueAsString(fieldErrors);
            this.error = mapper.writeValueAsString(globalErrors);
        } catch (JsonProcessingException e) {
            this.message = "";
            this.error = "";
        }
    }
}

6. UI – 필드 및 전역 오류

마지막으로 jQuery를 사용하여 필드 및 전역 오류를 모두 처리하는 방법을 살펴보겠습니다.

var serverContext = [[@{/}]];

function register(){
    $(".alert").html("").hide();
    var formData= $('form').serialize();
    $.post(serverContext + "/user/registration",formData ,function(data){
        if(data.message == "success"){
            window.location.href = serverContext +"/successRegister.html";
        }
    })
    .fail(function(data) {
        if(data.responseJSON.error.indexOf("MailError") > -1)
        {
            window.location.href = serverContext + "/emailError.html";
        }
        else if(data.responseJSON.error.indexOf("InternalError") > -1){
            window.location.href = serverContext + 
              "/login.html?message=" + data.responseJSON.message;
        }
        else if(data.responseJSON.error == "UserAlreadyExist"){
            $("#emailError").show().html(data.responseJSON.message);
        }
        else{
            var errors = $.parseJSON(data.responseJSON.message);
            $.each( errors, function( index,item ){
                $("#"+item.field+"Error").show().html(item.defaultMessage);
            });
            errors = $.parseJSON(data.responseJSON.error);
            $.each( errors, function( index,item ){
                $("#globalError").show().append(item.defaultMessage+"<br>");
            });
 }
}

참고:

  • 유효성 검사 오류가 있는 경우 메시지 개체에는 필드 오류가 포함되고 오류 개체에는 전역 오류가 포함 됩니다.
  • 해당 필드 옆에 각 필드 오류를 표시합니다.
  • 모든 전역 오류를 양식 끝에 한 곳에 표시합니다.

7. 결론

이 빠른 기사의 초점은 API를 보다 RESTful 방향으로 가져오고 프런트 엔드에서 해당 API를 처리하는 간단한 방법을 보여주는 것입니다.

jQuery 프론트 엔드 자체는 초점이 아닙니다. API는 정확히 동일하게 유지되는 동안 여러 JS 프레임워크에서 구현할 수 있는 기본적인 잠재적 클라이언트일 뿐입니다.

이 예제의 전체 구현은 GitHub 에서 사용할 수 있습니다 .

다음 »
Spring Security – 비밀번호 재설정
« 이전
Spring Security에 등록 – 비밀번호 인코딩
REST footer banner