如何在弹簧控制器中为特定方法在验证器中应用不同的行为

pba*_*ski 3 java validation model-view-controller spring

如果有可能针对不同的控制器方法定制验证器,我想获得这种验证方法的答案。

简单验证器

@Component
public class UserDtoValidator implements Validator {
@Autowired
UserService userService;

@Override
public boolean supports(Class<?> aClass) {
    return UserDto.class.isAssignableFrom(aClass);
}

@Override
public void validate(Object target, Errors errors) {
    UserDto userDto = (UserDto) target;

    }
   //how to make 'if' below to be applied only for certain method in controller
   //in this case for controller createUser method
    if (userService.findByUserName(userDto.getUserName())!=null) {
        throw new InvalidPayloadException("Creating user requires unique userName");
    }
   //second 'if' for controller updateUser method 
     if (userService.findByUserName(userDto.getUserName())==null) {
        throw new InvalidPayloadException("Updating unexisting users is not allowed");
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

控制器:

在这里,验证器有两种相反的情况:

1使用唯一的用户名创建用户

2更新用户-必需的用户名

@Controller
@RequestMapping(value = "/api/users")
public class ApiUserController extends ExceptionsResolver {

    @Autowired
    private UserService userService;
    @Autowired
    private UserDtoValidator userDtoValidator;
    @InitBinder
    private void initBinder(WebDataBinder binder) {
    binder.setValidator(userDtoValidator);
    }


    @RequestMapping(consumes = "application/json", produces = "application/json", method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity createUser(@Valid @RequestBody UserDto userDto) throws JsonProcessingException {
        userService.saveUser(userDto);
        return new ResponseEntity(userDto, HttpStatus.ACCEPTED);
    }

    @RequestMapping(value = "/{userName}", consumes = "application/json", method = RequestMethod.PUT)
    @ResponseBody
    public ResponseEntity<UserDto> updateUser(@Valid @RequestBody UserDto userDto, @PathVariable String userName) {
         return new ResponseEntity("User updated", HttpStatus.ACCEPTED);
     }

}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我知道PUT应该创建新的,但是在这里我只需要PUT即可进行更新。

Eme*_*gia 5

您真正关心的是用户名是否存在。在某些情况下,您希望这样做,在某些情况下,您则不需要。

理论上,您可以使用@Username带有exists属性的注释。这与Adi的相似isUpdate,但不要称之为isUpdate。您不在乎需要验证的操作,仅在乎用户名是否存在。

验证组是针对此问题而设计的,即在不同情况下以不同的方式验证bean。创建两个验证组NewUserExistingUser。将@Valid您的通话替换为@ControllerSpring的@Validated

public ResponseEntity createUser(@Validated(NewUser.class) @RequestBody UserDto userDto) throws JsonProcessingException {}

public ResponseEntity<UserDto> updateUser(@Validated(ExistingUser.class) @RequestBody UserDto userDto, @PathVariable String userName) {}
Run Code Online (Sandbox Code Playgroud)

UserDto课堂上,理论上您会将该username属性标记为

@Username(exists = true, groups = ExistingUser.class);
@Username(exists = false, groups = NewUser.class);
public String getUsername() {}
Run Code Online (Sandbox Code Playgroud)

但是Java不允许您这样做。因此,您需要一种变通方法来设置多个用户名约束。在Bean验证API中的所有位置都使用了此功能,例如NotNull

/**
 * Defines several <code>@NotNull</code> annotations on the same element
 * @see javax.validation.constraints.NotNull
 *
 * @author Emmanuel Bernard
 */
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@interface List {
    NotNull[] value();
}
Run Code Online (Sandbox Code Playgroud)

有了这些东西之后,您只需要一个UsernameValidator可以根据exists标志检查用户名是否存在的验证器,其余的将由验证组负责。