java - Spring Boot 用户注册 - 将验证错误发送到 UI

标签 java spring spring-boot thymeleaf

我正在学习 Springboot 并尝试在这个 Baeldung 示例中跟踪注册错误如何到达 UI Registration Process进入用户界面。然而 Baeldung 网站上的实现与链接的 Baeldung Github 项目不同。

在网页的示例中,他们有一个注册 Controller ,如下所示:

@RequestMapping(value = "/user/registration", method = RequestMethod.POST)
public ModelAndView registerUserAccount
  (@ModelAttribute("user") @Valid UserDto accountDto, 
  BindingResult result, WebRequest request, Errors errors) {    
     User registered = new User();
     if (!result.hasErrors()) {
        registered = createUserAccount(accountDto, result);
      }
     if (registered == null) {
        result.rejectValue("email", "message.regError");
     }
   // rest of the implementation
}

private User createUserAccount(UserDto accountDto, BindingResult result) {
  User registered = null;
  try {
      registered = service.registerNewUserAccount(accountDto);
  } catch (EmailExistsException e) {
      return null;
  }    
  return registered;
}

对应的 HTML 为:

<div>
    <label th:text="#{label.user.email}">email</label>
    <input type="email" th:field="*{email}"/>
    <p th:each="error : ${#fields.errors('email')}" h:text="${error}">Validation error</p>
</div>

我知道 createUserAccount 方法可能会抛出异常并出错,该异常最终会添加到结果对象中,该结果对象通过 thymeleaf 转化为 HTML。

但是在链接的 github 中在同一个网页上的项目中,实现非常不同,我不明白错误是如何到达 UI 的。

controller现在看起来像:

    @RequestMapping(value = "/user/registration", method = RequestMethod.POST)
    @ResponseBody
    public GenericResponse registerUserAccount(@Valid final UserDto accountDto, final HttpServletRequest request) {
    LOGGER.debug("Registering user account with information: {}", accountDto);
    final User registered = userService.registerNewUserAccount(accountDto);
    eventPublisher.publishEvent(new OnRegistrationCompleteEvent(registered, request.getLocale(), getAppUrl(request)));
    return new GenericResponse("success");
    }

这会调用 registerNewUserAccount方法如下:

    @Override
    public User registerNewUserAccount(final UserDto accountDto) {
    if (emailExist(accountDto.getEmail())) {
        throw new UserAlreadyExistException("There is an account with that email adress: " + accountDto.getEmail());
    }
    // rest of method

UserAlreadyExistException类看起来像:

public final class UserAlreadyExistException extends RuntimeException {

    public UserAlreadyExistException() {
        super();
    }

    public UserAlreadyExistException(final String message, final Throwable cause) {
        super(message, cause);
    }

    public UserAlreadyExistException(final String message) {
        super(message);
    }

    public UserAlreadyExistException(final Throwable cause) {
        super(cause);
    }
}

甚至是registration HTML现在不同了,并且似乎不使用 Thymeleaf 来处理错误:

<div class="form-group row">
    <label class="col-sm-3" th:text="#{label.user.email}">email</label>
    <span class="col-sm-5"><input type="email" class="form-control" name="email" value="" required="required"/></span>                    
    <span id="emailError" class="alert alert-danger col-sm-4" style="display:none"></span>
</div>

This all builds up to the question : how does this exception and the associated messages bubble up back to the UI? In the implementation on the original example there were various errors (for example @NotEmtpty) that would be presented in the UI.

最佳答案

我认为您感到困惑的是:错误消息如何传递到首页,因为在 Controller 中没有它的代码。我的理解正确吗?

简短回答:

这是在位于: https://github.com/Baeldung/spring-security-registration/blob/master/src/main/java/org/baeldung/web/error/RestResponseEntityExceptionHandler.java 的全局异常处理程序中完成的

更多详细信息:

通常对于 Spring Controller ,我们将使用全局异常处理程序来捕获从 Controller 方法抛出的所有异常,但异常本身可以来自服务代码。处理程序方法用 @ExceptionHandler 注释。

因此“用户已存在”情况的错误消息流程如下:

  1. 前端 javascript 完成所有本地验证,例如电子邮件格式、密码长度等。只有当所有这些验证通过后,它才会调用 api 来注册新用户。
  2. Controller 收到注册用户的请求。
  3. Controller 调用服务方法来注册新用户。
  4. 服务方法在检测到时会抛出已经存在的异常。
  5. Controller 没有捕获异常,因此它会从 Controller 方法中抛出。
  6. 全局 Controller 异常处理程序捕获此异常并生成错误响应 dto,填充由 message.properties 提供的错误消息,以将相应的语言环境设置为错误响应。这些属性位于 src/main/resources 中,文件名声明了语言环境。填充错误响应后,它返回它,以便 spring 将此对象响应到前端。
  7. 前端接收响应。 javascript 检查是否有错误。如果是,则检查是什么类型的错误,然后进行相应的处理。

这种流程一开始可能不太直观。但一旦你理解了它,你就会很高兴使用它。它可以节省 Controller 中处理错误的大量代码。

我认为controllerAdvice是使用AOP实现的,这是一个非常强大的工具。如果您想了解更多,可以自己进一步研究。

关于验证错误处理:

异常处理程序继承 ResponseEntityExceptionHandler ,它处理请求负载验证的验证结果。请参阅处理程序的前两个重写方法。这对我来说也是新的,很高兴知道!

关于java - Spring Boot 用户注册 - 将验证错误发送到 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53891448/

相关文章:

java - 文件 API 导致 ANR

java - 在 Java SWT 窗口中启用滚动条

java - spring-boot-jms Redeliverypolicy bean 被忽略?

java - Spring Data Neo4j @GraphId 和 @Index

java - Spring 测试 - WebTestClient 无法 Autowiring 。未找到 'WebTestClient' 类型的 beans

java - Spring Hibernate 中实体字段的本地化

java - Spring bean 验证消息解析

java - 如何在 Visual Studio Code 上使用 web.xml 调试 spring mvc Web 应用程序?

java - 限制调用 Spring Boot Rest 端点,直到完成从数据库的映射

java - 使用Virtualbox的Hortonworks Hadoop-执行jar