传统的controller-service-dao模式中,处理业务数据时,可以在service中处理,但是使用**Spring data rest时,由于框架自己生成相关接口,处理相关业务就要实现监听才行。要点如下。
1.Listener
@Component
public class TagListener extends AbstractRepositoryEventListener<TagEntity> {
private final ITagRepository tagRepository;
public TagListener(ITagRepository tagRepository) {
this.tagRepository = tagRepository;
}
@Override
protected void onBeforeCreate(TagEntity tag) {
TagEntity exist = tagRepository.findByName(tag.getName());
if (exist != null){
RestVerifyUtils.rejectValue(tag,"name","name.requied","The tag already exist");
}
tag.setId(IdUtils.generator());
}
}
继承AbstractRepositoryEventListener
抽象类,重写其中的方法,方法列表如下
- BeforeCreateEvent
- AfterCreateEvent
- BeforeSaveEvent
- AfterSaveEvent
- BeforeLinkSaveEvent
- AfterLinkSaveEvent
- BeforeDeleteEvent
- AfterDeleteEvent
2.Validator
@Component
public class TagValidator {
//beforeCreate+TagEntity+Validator
//执行时机+实体+Validator
@Component("beforeCreateTagEntityValidator")
class TagCreateValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return TagEntity.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "name", "required", "标签名称不能为空");
ValidationUtils.rejectIfEmpty(errors, "id", "required", "ID生成错误");
}
}
}
3.在Listener中抛出异常
Spring data rest 的异常监听是在 ValidatingRepositoryEventListener 中处理的。
private Errors validate(String event, Object entity) {
if (entity == null) {
return null;
}
Errors errors = new ValidationErrors(entity, persistentEntitiesFactory.getObject());
for (Validator validator : getValidatorsForEvent(event)) {
if (validator.supports(entity.getClass())) {
LOGGER.debug("{}: {} with {}", event, entity, validator);
ValidationUtils.invokeValidator(validator, entity, errors);
}
}
if (errors.hasErrors()) {
throw new RepositoryConstraintViolationException(errors);
}
return errors;
}
查看源码可以看到抛出RepositoryConstraintViolationException
异常需要参数errors
,error
的生成需要persistentEntitiesFactory
private final ObjectFactory<PersistentEntities> persistentEntitiesFactory;
/**
* Creates a new {@link ValidatingRepositoryEventListener} using the given repositories.
*
* @param persistentEntitiesFactory must not be {@literal null}.
*/
public ValidatingRepositoryEventListener(ObjectFactory<PersistentEntities> persistentEntitiesFactory) {
Assert.notNull(persistentEntitiesFactory, "PersistentEntities must not be null!");
this.persistentEntitiesFactory = persistentEntitiesFactory;
this.validators = new LinkedMultiValueMap<String, Validator>();
}
跟踪源码发现persistentEntitiesFactory是Spring自动注入的。于是就找到了可以自己封装验证器在Listener中使用。
@Bean
public PersistentEntities persistentEntities(ObjectFactory<PersistentEntities> entitiesObjectFactory) {
return entitiesObjectFactory.getObject();
}
public class RestVerifyUtils {
public static void reject(Object target, String errorCode, String message) {
PersistentEntities entities = SpringUtils.getBean("persistentEntities", PersistentEntities.class);
Errors errors = new ValidationErrors(target, entities);
errors.reject(errorCode, message);
throw new RepositoryConstraintViolationException(errors);
}
public static void rejectValue(Object target, String field, String errorCode, String message) {
PersistentEntities entities = SpringUtils.getBean("persistentEntities", PersistentEntities.class);
Errors errors = new ValidationErrors(target, entities);
errors.rejectValue(field, errorCode, message);
throw new RepositoryConstraintViolationException(errors);
}
public static void rejectValueIfNull(Object target, String field, String errorCode, String message) {
if (target == null) {
PersistentEntities entities = SpringUtils.getBean("persistentEntities", PersistentEntities.class);
Errors errors = new ValidationErrors(target, entities);
errors.rejectValue(field, errorCode, message);
throw new RepositoryConstraintViolationException(errors);
}
}
public static <T> void rejectIfEmpty(Collection<T> target, String errorCode, String message) {
if (CollectionUtils.isEmpty(target)) {
PersistentEntities entities = SpringUtils.getBean("persistentEntities", PersistentEntities.class);
Errors errors = new ValidationErrors(target, entities);
errors.reject(errorCode, message);
throw new RepositoryConstraintViolationException(errors);
}
}
}