我正在学习 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
注释。
因此“用户已存在”情况的错误消息流程如下:
- 前端 javascript 完成所有本地验证,例如电子邮件格式、密码长度等。只有当所有这些验证通过后,它才会调用 api 来注册新用户。
- Controller 收到注册用户的请求。
- Controller 调用服务方法来注册新用户。
- 服务方法在检测到时会抛出已经存在的异常。
- Controller 没有捕获异常,因此它会从 Controller 方法中抛出。
- 全局 Controller 异常处理程序捕获此异常并生成错误响应 dto,填充由 message.properties 提供的错误消息,以将相应的语言环境设置为错误响应。这些属性位于 src/main/resources 中,文件名声明了语言环境。填充错误响应后,它返回它,以便 spring 将此对象响应到前端。
- 前端接收响应。 javascript 检查是否有错误。如果是,则检查是什么类型的错误,然后进行相应的处理。
这种流程一开始可能不太直观。但一旦你理解了它,你就会很高兴使用它。它可以节省 Controller 中处理错误的大量代码。
我认为controllerAdvice是使用AOP实现的,这是一个非常强大的工具。如果您想了解更多,可以自己进一步研究。
关于验证错误处理:
异常处理程序继承 ResponseEntityExceptionHandler ,它处理请求负载验证的验证结果。请参阅处理程序的前两个重写方法。这对我来说也是新的,很高兴知道!
关于java - Spring Boot 用户注册 - 将验证错误发送到 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53891448/