3

さまざまなコントローラーメソッドのバリデーターをカスタマイズする可能性がある場合、この検証アプローチがあれば答えを得たいと思います。

シンプルなバリデーター

@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");
    }
  }
}

コントローラ:

ここでは、バリデーターに対して 2 つの反対の状況があります。

1 一意の userName を持つユーザーの作成

2 ユーザーの更新 - 必須の userName

@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);
     }

}

ところで、PUT が新規作成する必要があることはわかっていますが、ここでは更新目的で PUT だけが必要です。

4

3 に答える 3

3

ユーザーを作成または更新しているかどうか (インターセプターと ThreadLocal オブジェクトを使用) をバリデータ内から知る方法は考えられますが、洗練されたものではありません。

それがあなたが求めているものと正確に一致しないことは知っていますが、私は次のようなカスタム検証注釈を使用することになると思います:

@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UsernameValidator.class)
public @interface Username
{
    String message() default "...";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    boolean isUpdate() default true;
}

そしてバリデータ:

public class UsernameValidator implements ConstraintValidator<Username, String>
{
    private boolean isUpdate;

    public void initialize(Username constraintAnnotation)
    {
        isUpdate = constraintAnnotation.isUpdate();
    }

    public boolean isValid(String value, ConstraintValidatorContext context)
    {
        if (isUpdate)
        {
            // Make sure the user exists
        }
        else
        {
            // Make sure the user doesn't exist
        }           
    }
}

このような実装の使用法は、次のようになります。

@Username                           // In case of an update
@Username(isUpdate = false)         // In case of a creation

もちろん、特定のユースケースに変換する必要がありますが、要点は理解できると思います。

私はまだ何とかあなたを助けることができたと思っています. 幸運を!

于 2013-10-28T21:44:54.917 に答える
1

私は同じ問題を抱えていましたが、このことに対する「魔法の」解決策はないようです。

更新と保存のための一般的なものを備えたバリデーターになりました。特定のチェックは、コントローラ メソッドに残されました。

もう 1 つの解決策は、別の dto を作成することです (orm 目的で dto オブジェクトを使用しない場合)。そして、それらに JSR-303 検証アノテーションを使用します (簡潔にするため)。しかし、この解決策は実際には特定のケースに依存します。たとえば、フィールドの小さなサブセットのみを更新できる場合に適しているようです。

于 2013-10-28T22:26:21.850 に答える