我正在尝试学习spring并实现这一目标,我正在从头开始构建REST应用程序。我很困惑应该在哪里检查应用程序中的约束:控制器层与服务层。 例如,在创建用户方法中,我想检查是否有其他用户使用相同的电子邮件,因为电子邮件在我的数据库中是唯一的。我还想检查密码是否匹配(密码和“确认密码”字段)等。
当前,在我的实现中,所有这些事情都在Controller层中进行了验证,因此我可以为每种方法返回一个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);
}
那么哪种方法更好?如果我在Service层中检查约束和验证,我应该返回什么,以便在控制器中知道为什么创建用户失败?
答案 0 :(得分:1)
在我看来,处理异常的最佳位置是服务层。对于我来说,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的文档中阅读有关此内容的更多信息: