The Registration API becomes RESTful – 注册API成为RESTful

最后修改: 2015年 3月 26日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In the last few articles of the Registration series here on Baeldung, we built most of the functionality we needed in an MVC fashion.

Baeldung上的Registration系列的最后几篇文章中,我们以MVC的方式构建了我们需要的大部分功能。

We’re now going to transition some of these APIs to a more RESTful approach.

我们现在要把这些API中的一些过渡到更加RESTful的方法。

2. The Register Operation

2.注册操作

Let’s start with the main Register operation:

让我们从主要的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");
}

So, how is this different from the original MVC implementation?

那么,这与最初的MVC实现有什么不同?

Here goes:

在这里。

  • the request is now correctly mapped to an HTTP POST
  • we’re now returning a proper DTO and marshaling that directly into the body of the response
  • we’re no longer dealing with error handling in the method at all

We’re also removing the old showRegistrationPage() – as that’s not needed to simply display the registration page.

我们也删除了原来的showRegistrationPage()–因为不需要它来简单地显示注册页面。

3. The registration.html

3、registration.html

Furthermore, we need to modify the registration.html to:

此外,我们需要修改registration.html到。

  • use Ajax to submit the registration form
  • receive the results of the operation as JSON

Here goes:

在这里。

<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. Exception Handling

4.异常处理

Generally, implementing a good exception-handling strategy can make the REST API more robust and error-prone.

一般来说,实施一个好的异常处理策略可以使REST API更加健壮和容易出错。

We’re using the same @ControllerAdvice mechanism to deal cleanly with different exceptions – and now we need a new type of exception.

我们使用相同的@ControllerAdvice机制来干净地处理不同的异常–现在我们需要一种新的异常类型。

This is the BindException – which is thrown when the UserDto is validated (if invalid). We’ll override the default ResponseEntityExceptionHandler method handleBindException() to add the errors in the response body:

这就是BindException–当UserDto被验证(如果无效)时被抛出。我们将覆盖默认的ResponseEntityExceptionHandler方法handleBindException() 在响应体中添加错误。

@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);
}

Next, we will also need to handle our custom Exception UserAlreadyExistException – which is thrown when the user registers with an email that already exists:

接下来,我们还需要处理我们的自定义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. The GenericResponse

5.GenericResponse

We also need to improve the GenericResponse implementation to hold these validation errors:

我们还需要改进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 – Field and Global Errors

6.用户界面 – 字段和全局错误

Finally, let’s see how to handle both field and global errors using jQuery:

最后,让我们看看如何使用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>");
            });
 }
}

Note that:

请注意,。

  • If there are validation errors, then the message object contains the field errors and the error object contains global errors
  • We display each field error next to its field
  • We display all the global errors in one place at the end of the form

7. Conclusion

7.结论

The focus of this quick article is to bring the API into a more RESTful direction and show a simple way of dealing with that API in the front end.

这篇快速文章的重点是将API引入更多的RESTful方向,并展示在前端处理该API的简单方法。

The jQuery front end itself is not the focus – just a basic potential client that can be implemented in any number of JS frameworks, while the API remains exactly the same.

jQuery前端本身并不是重点–只是一个基本的潜在客户端,可以在任何数量的JS框架中实现,而API仍然完全相同。

The full implementation of this tutorial is available over on GitHub.

本教程的完整实现可在GitHub上获取。

Next »

Spring Security – Reset Your Password

« Previous

Registration with Spring Security – Password Encoding