问题
I have a SDR project and I am successfully validating the user entity for POST request but as soon as I update an existing entity using either PATCH or PUT the DB is updated BEFORE the validation is executed (the validator is being executed and error is returned but the DB is being updated anyway).
Do I need to setup a separate config for update ? Am I missing an extra step for that?
Entity
@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
public class Member {
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "member_id_gen")
@SequenceGenerator(name = "member_id_gen", sequenceName = "member_id_seq")
@Id
@JsonIgnore
private long id;
@Version
private Integer version;
@NotNull
protected String firstName;
@NotNull
protected String lastName;
@Valid
protected String email;
}
Repository
@RepositoryRestResource(collectionResourceRel = "members", path = "member")
public interface MemberRepository extends PagingAndSortingRepository<Member, Long> {
public Member findByFirstName(String firstName);
public Member findByLastName(String lastName);
}
Validator
@Component
public class BeforeSaveMemberValidator implements Validator {
public BeforeSaveMemberValidator() {}
private String EMAIL_REGEX = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$";
@Override
public boolean supports(Class<?> clazz) {
return Member.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
Member member = (Member) target;
if(ObjectUtils.isEmpty(member.getFirstName())) {
errors.rejectValue("firstName", "member.firstName.empty");
}
if(ObjectUtils.isEmpty(member.getLastName())) {
errors.rejectValue("lastName", "member.lastName.empty");
}
if(!ObjectUtils.isEmpty(member.getDni()) && !member.getDni().matches("^[a-zA-Z0-9]*$")) {
errors.rejectValue("dni", "member.dni.invalid");
}
if(!ObjectUtils.isEmpty(member.getEmail()) && !member.getEmail().matches(EMAIL_REGEX)) {
errors.rejectValue("email", "member.email.notValid");
}
}
}
BeforeSave service
@Service
@RepositoryEventHandler(Member.class)
public class MemberService {
@HandleBeforeCreate
@HandleBeforeSave
@Transactional
public void beforeCreate(Member member) {
...
}
}
回答1:
I think you should rename your validator, for example, to MemberValidator
then assign it as described here:
@Override
protected void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener v) {
v.addValidator("beforeCreate", new MemberValidator());
v.addValidator("beforeSave", new MemberValidator());
}
But I suggest you to use Bean validation instead of your custom validators. To use it in SDR project you can inject LocalValidatorFactoryBean
, then assign it for 'beforeCreate' and 'beforeSave' events in configureValidatingRepositoryEventListener
:
@Configuration
@RequiredArgsConstructor // Lombok annotation
public class RepoRestConfig extends RepositoryRestConfigurerAdapter {
@NonNull private final LocalValidatorFactoryBean validatorFactoryBean;
@Override
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener v) {
v.addValidator("beforeCreate", validatorFactoryBean);
v.addValidator("beforeSave", validatorFactoryBean);
super.configureValidatingRepositoryEventListener(v);
}
}
In this case your SDR will automatically validate payloads of POST, PUT and PATCH requests for all exposed SDR repositories.
See my example for more details.
来源:https://stackoverflow.com/questions/46999658/spring-data-rest-validation-for-put-and-patch-running-after-db-update