Java 约束检查控制器层与服务层
我正在努力学习spring,并从零开始构建REST应用程序。我不知道应该在哪里检查应用程序中的约束:控制器层还是服务层。 例如,在createuser方法中,我想检查是否有其他用户使用相同的电子邮件,因为电子邮件在我的数据库中是唯一的。我还想检查密码是否匹配(密码和“确认密码”字段)等 目前,在我的实现中,所有这些都是在控制器层进行验证的,所以我可以为每种方法返回一个ResponseEntityJava 约束检查控制器层与服务层,java,spring,rest,model-view-controller,Java,Spring,Rest,Model View Controller,我正在努力学习spring,并从零开始构建REST应用程序。我不知道应该在哪里检查应用程序中的约束:控制器层还是服务层。 例如,在createuser方法中,我想检查是否有其他用户使用相同的电子邮件,因为电子邮件在我的数据库中是唯一的。我还想检查密码是否匹配(密码和“确认密码”字段)等 目前,在我的实现中,所有这些都是在控制器层进行验证的,所以我可以为每种方法返回一个ResponseEntity @PostMapping("/signUp") public ResponseEnt
@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();
}
那么哪种方法更好呢?如果我在服务层中检查约束和验证,我应该返回什么以便在控制器中知道创建用户失败的原因?在我看来,处理异常的最佳位置是服务层。对于我来说,REST控制器方法最多应该处理请求并将其传递给服务方法 使用这种方法,您可以非常清楚地定义层,这些层可以完成非常清楚定义的工作。例如,您的服务层将处理请求的验证、持久化操作,并且还将(如果需要)向控制器提供一个返回对象,然后该返回对象将封装到相应的响应对象中(
ResponseEntity
)
记住这一点,没有什么能阻止您在服务层抛出任何类型的异常,并将其转化为正确的响应。Spring有一个非常简洁而强大的机制,可以精确地执行被称为异常处理程序的操作
因此,对于密码检查操作,您可以执行以下操作:
if (!user.getPassword().equals(user.getConfirmPassword())) {
throw new PasswordMismatchException("Passwords are not the same for user:: " + user.getName());
}
其中,密码不匹配异常
是一个运行时异常。使用类似的方法,您可以继续设置ExceptionHandler,并使用适当的方法来截取它并将其转换为响应。一个简单的例子是:
@RestControllerAdvice
public class ApplicationExceptionHandler {
@ExceptionHandler(PasswordMismatchException.class)
public ResponseEntity<String> handleBadPasswords(PasswordMismatchException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
@RestControllerAdvice
公共类ApplicationExceptionHandler{
@ExceptionHandler(PasswordMismatchException.class)
公共响应手柄密码(密码不匹配例外e){
返回ResponseEntity.badRequest().body(e.getMessage());
}
}
您可以阅读Spring文档中的更多内容:
将其视为一个漏斗是一个有用的方法:我可以设想多个接口来更新该记录吗?(JSON API和HTML接口是两个很好的例子。)如果是这样,那么该功能将进入两个接口使用的公共服务中,从而减少重复。(在您的特定情况下,您可能只希望在数据库列上有一个不区分大小写的唯一约束。您可能还是想查询它。最后,如果可能,请使用
Instant
而不是Date
)
@RestControllerAdvice
public class ApplicationExceptionHandler {
@ExceptionHandler(PasswordMismatchException.class)
public ResponseEntity<String> handleBadPasswords(PasswordMismatchException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}