java - 约束检查控制器层与服务层
问题描述
我正在尝试学习 spring 并实现我正在从头开始构建一个 REST 应用程序。我很困惑我应该在哪里检查应用程序中的约束:控制器层与服务层。例如,在创建用户方法中,我想检查是否有任何其他用户使用相同的电子邮件,因为电子邮件在我的数据库中是唯一的。我还想检查密码是否匹配(密码和“确认密码”字段)等。
目前,在我的实现中,所有这些都在控制器层进行了验证,因此我可以为每种方法返回一个 ResponseEntity。
@PostMapping("/signUp")
public ResponseEntity<Object> createUser(@RequestBody RegisterUserDto user) {
if (userService.getUserByEmail(user.getEmailAddress()) != null) {
return ResponseEntity.badRequest().body("email already exists");
}
if (!user.getPassword().equals(user.getConfirmPassword())) {
return ResponseEntity.badRequest().body("passwords are not the same");
}
User savedUser = null;
try {
savedUser = userService.createUser(userDtoConversions.convertToEntityRegister(user));
} catch (ParseException e) {
e.printStackTrace();
}
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
.buildAndExpand(savedUser.getId()).toUri();
return ResponseEntity.created(location).build();
}
在服务层创建用户方法:
@Override
@Transactional
public User createUser(User newUser) {
newUser.setDateCreated(new Date());
return userRepository.save(newUser);
}
那么哪种方法更好呢?如果我在服务层检查约束和验证,我应该返回什么,以便在我的控制器中知道为什么创建用户失败?
解决方案
在我看来,处理异常的最佳位置是服务层。对于我来说,REST 控制器方法最多应该处理请求并将其传递给服务方法。
使用这种方法,您可以拥有非常明确定义的层,这些层可以完成非常明确的工作。例如,您的服务层将处理请求的验证、持久化操作,并且还将(如果需要)向控制器提供返回对象,然后将其包装到适当的响应对象中(ResponseEntity
在您的情况下)。
考虑到这一点,没有什么可以阻止您在服务层中抛出任何类型的异常并转化为正确的响应。Spring 有一个非常简洁和强大的机制,可以精确地完成所谓的异常处理程序。
因此,对于您的密码检查操作,您可以执行以下操作:
if (!user.getPassword().equals(user.getConfirmPassword())) {
throw new PasswordMismatchException("Passwords are not the same for user:: " + user.getName());
}
其中PasswordMismatchException
是 RuntimeException。有了类似的东西,您可以继续设置一个 ExceptionHandler 以及适当的方法来拦截它并将其转换为响应。一个简单的例子是:
@RestControllerAdvice
public class ApplicationExceptionHandler {
@ExceptionHandler(PasswordMismatchException.class)
public ResponseEntity<String> handleBadPasswords(PasswordMismatchException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
您可以在 Spring 的文档中阅读有关此内容的更多信息:
推荐阅读
- c# - 动画剪辑错误
- flutter - 图像未显示在屏幕颤动中
- class - ClaiR/Rascal:列出公共功能的最佳方式?
- spring-boot - 运行 UT 时出错 - BeanCreationException 未找到属性更新自定义存储库
- java - 从 java1.5 迁移到 java1.8 时遇到意外元素“resource-ref”
- r - 根据条件收集数据框中的多个列
- java - 如何将字符串放入数组而不重复
- r - 如何将二维数据分成两组
- c# - 我自己在调试模式下的二进制文件“二进制文件不是用调试信息构建的”
- javascript - 如果我需要每 5 秒在线或离线更新用户状态,我应该在 update.php 中添加什么?