首页 > 解决方案 > 约束检查控制器层与服务层

问题描述

我正在尝试学习 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);
    }

那么哪种方法更好呢?如果我在服务层检查约束和验证,我应该返回什么,以便在我的控制器中知道为什么创建用户失败?

标签: javaspringrestmodel-view-controller

解决方案


在我看来,处理异常的最佳位置是服务层。对于我来说,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 的文档中阅读有关此内容的更多信息:

春季异常处理程序

Spring中的异常处理


推荐阅读