【问题标题】:Spring: Unique Id validator without using HibernateSpring:不使用 Hibernate 的唯一 ID 验证器
【发布时间】:2020-04-25 14:44:35
【问题描述】:

在您进行 POST 时,验证器检查是否有重复 ID 的最佳方法是什么?

我尝试创建自定义验证器,但总是得到 Internal Server Error

{ "时间戳": "2020-04-25T14:37:19.158+0000", “状态”:500, "error": "内部服务器错误", "message": "HV000030: No validator can be found for constraint 'com.omega.mtest.validator.IdConstraint' 验证类型 'java.lang.Integer'。检查 'id' 的配置", “路径”:“/用户” }

这是我的模型类

    public class User {

        @IdConstraint
        @Min(value = 1, message = "ID can't be zero or null")
        @Max(value = 1000000, message = "We collect a billion records")
        private int id;



        @Pattern(regexp = "^[a-zA-Z ]*$", message = "Input doesn't match for a full name")
        private String name;

        @Min(value = 10)
        @Max(value = 120, message = "We didn't expect that age")
        private int age;

        @Pattern(regexp = "^[a-zA-Z ]*$", message = "Input doesn't match for a city name")
        private String city;

        public User(int id, String name, int age, String city) {
            this.id = id;
            this.name = name;
            this.age = age;
            this.city = city;
        }

       //getters
    }

自定义验证器接口:

@Constraint(validatedBy = UserValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RUNTIME)
public @interface IdConstraint {

    String message() default "The input list cannot contain two ugual IDs";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

接口的类实现

public class UserValidator implements ConstraintValidator<IdConstraint, List<User>> {

    @Override
    public void initialize(IdConstraint constraintAnnotation) {

    }

    @Override
    public boolean isValid(List<User> users, ConstraintValidatorContext context) {
        if (users.size() == 1) {
            return true;
        } else {
            for (int i = 0; i < users.size(); i++) {
                for (int j = 0; j < users.size(); j++) {
                    if (i != j) {
                        if (users.get(i).getId() == users.get(j).getId()) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
    }

控制器类:

@Validated
@RestController
public class UsersController {

    @Autowired
    public UserService userService;

    @RequestMapping(value = "/user", method = RequestMethod.POST)
    public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
        return new ResponseEntity<>(userService.createUser(user), HttpStatus.CREATED);
    }

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException e) {
        return new ResponseEntity<>("Not valid due to validation error: " + e.getMessage(), HttpStatus.BAD_REQUEST);
    }

    @RequestMapping(value = "/users", method = RequestMethod.GET)
    public List<User> getUsers() {
        return userService.getAllUsers();
    }

    @RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
    public User getUserById(@PathVariable int id) {
        return userService.findUserById(id);
    }
}

用户服务

public interface UserService {

    List<User> getAllUsers();

    User createUser(User user);

    User findUserById(int id);

    List<User> list();
}

回购

@Component
public class UserRepository implements UserService {

    private List<User> users;

    public UserRepository() {
        users = new ArrayList<>();
    }

    @Override
    public List<User> getAllUsers() {
        return users.stream().collect(Collectors.toList());
    }

    @Override
    public User createUser(User user) {
        users.add(user);
        return user;
    }


    @Override
    public User findUserById(int id) {
        return users.stream()
                .filter(t -> t.getId() == id)
                .findAny()
                .orElse(null);
    }

    @Override
    public List<User> list() {
        return users;
    }
}

【问题讨论】:

    标签: java spring unique-constraint customvalidator


    【解决方案1】:

    首先,你在错误的地方使用了@IdConstraint,这意味着private int id。你必须把它放在List&lt;User&gt;上。当您有用户列表并且两个用户中的任何一个在请求正文中没有相同的 id 时,您的验证器就会工作。 你可以解决这两种方法。

    检查就是服务:

    在 post 端点中,您使用一个用户作为请求正文。因此,您可以使用存储库的getById() 检查服务中的数据库中是否存在 id。如果存在则引发异常,否则插入。

    User user= userRepository.getById(user.getId());
    if (ObjectUtils.isEmpty(user)) {
      throw new UserNotFoundException();
    }
    

    使用验证器:

    在验证器函数中调用存储库并不是更好的方法。 但是,您仍然希望可以这样做。

    public class UserIdValidator implements ConstraintValidator<IdConstraint, Integer> {
    
        @Autowired
        Private UserService userService;
    
        @Override
        public void initialize(IdConstraint constraintAnnotation) {
    
        }
    
        @Override
        public boolean isValid(Integer id, ConstraintValidatorContext context) {
          User user= userService.findUserById(id);
          if (ObjectUtils.isEmpty(user)) {
            return false;
          }
          return true;
        }
    }
    

    【讨论】:

    • 说实话,帖子的要求是不要获得重复的 ID。如果我们找不到用户 id,您的方法是引发异常。
    • 我在想你在请求正文中传递的 ID 那么问题是什么?您也可以使用验证器方法。但是您不需要为此获取整个用户列表(已接受的解决方案)
    • 不再获取所有用户 ;-)
    • You have to put this on List&lt;User&gt;. 为什么?该帖子包含一个用户...这是您验证的用户...不是用户列表...
    • @OutOfMemoryError 这取决于你,我只是想给你一个好的解决方案,而不仅仅是解决你的问题
    【解决方案2】:

    您的验证人签名不正确。

    您在这里验证的不是用户列表,而是一个 Integer 。

    这样

    public class UserIdValidator implements ConstraintValidator<IdConstraint, Integer> {
    

    那么你必须询问你的服务是否已经使用了这个id。

    public class UserIdValidator implements ConstraintValidator<IdConstraint, Integer> {
    
        @Autowired
        Private UserService userService;
    
        @Override
        public void initialize(IdConstraint constraintAnnotation) {
    
        }
    
        @Override
        public boolean isValid(Integer id, ConstraintValidatorContext context) {
             return !userService.existsById(id);
            }
        }
    

    【讨论】:

    • 有个bug,我可以放两条相同id的记录:)
    • 对不起,我不明白?
    • 已更新...但逻辑不是这里的重要部分...首先解决您的异常:-)。顺便说一句,将 int 更改为 Integer 到用户类型
    • 我遇到了一个错误,bug,这样我就可以有 2 个具有相同 int 的 id。
    • @CodeScale 为什么需要从数据库中获取所有用户?这是非常昂贵的操作和无用的东西。
    【解决方案3】:

    我是这样做的,而且效果很好:

      @RequestMapping(value = "/user", method = RequestMethod.POST)
    public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
        Optional<User> check = userService.findUserById(user.getId());
        if (check.isPresent()) {
            return new ResponseEntity<>(userService.createUser(user), HttpStatus.CREATED);
        }
        return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
    }
    
    
    
    @RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
        public ResponseEntity<User> getUserById(@PathVariable int id) {
            if (userService.findUserById(id).isPresent()) {
                return new ResponseEntity<>(userService.findUserById(id).get(), HttpStatus.OK);
            }
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
        }
    

    【讨论】:

      猜你喜欢
      • 2016-12-17
      • 1970-01-01
      • 1970-01-01
      • 2015-02-12
      • 2016-04-15
      • 1970-01-01
      • 2013-08-19
      • 2011-07-12
      • 1970-01-01
      相关资源
      最近更新 更多