@PathVariable的全局通用PropertyEditorSupport - >域对象

时间:2014-03-05 22:36:05

标签: java spring generics converter propertyeditor

我正在使用带有Spring Data MongoDB的Spring 4,并希望摆脱控制器中的一些样板代码。

我只想替换它:

@RequestMapping("{id}")
void a(@PathVariable ObjectId id) {
   DomainObject do = service.getDomainObjectById(id);
   // ...
}

用这个:

@RequestMapping("{id}")
void a(@PathVariable("id") DomainObject do) {
  // ...
}

目前,我必须为每个域对象编写一对PropertyEditorSupport@ControllerAdvice类:

@Component
public class SomeDomainObjectEditor extends PropertyEditorSupport {
    @Autowired
    SomeDomainObjectService someDomainObjectService;

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        setValue(someDomainObjectService.getById(new ObjectId(text)));
    }

    @Override
    public String getAsText() {
        SomeDomainObject value = (SomeDomainObject) getValue();
        return (value != null ? value.getId().toString() : null);
    }
}

@ControllerAdvice
public class SomeDomainObjectControllerAdvice {
    @Autowired
    SomeDomainObjectEditor someDomainObjectEditor;

    @InitBinder
    public void register(WebDataBinder binder, WebRequest request) {
        binder.registerCustomEditor(SomeDomainObject.class, someDomainObjectEditor);
    }
}

我无法找到一种简单的方法来以通用方式完成此操作,因为我有很多域对象,并且所有行为都相同。

我的所有域对象都实现BaseDocument<ID>,因此拥有getId()方法。所以基本上我想要这样的东西:

public class BaseDocumentPropertyEditor extends PropertyEditorSupport { ... }

使用Converter<String, BaseDocument<?>>并使其可以在Spring Framework中的其他位置使用也可以(=很好)。

我的主要问题是,我无法想象找到相应的@Service以便从DB中获取域对象的简单方法。 (由于某些数据的访问限制,我无法使用Repository

希望你有一些建议。谢谢!

1 个答案:

答案 0 :(得分:2)

NEWER:

如果您还需要正确的异常处理,则应使用DomainClassPropertyEditorRegistrar,因为DomainClassConverter吞下了基础异常......

我们走吧!只需使用:

更新您的WebMvcConfigurationSupport即可
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
    RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
    ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer();
    initializer.setPropertyEditorRegistrar(domainClassPropertyEditorRegistrar());
    return adapter;
}

@Bean
public DomainClassPropertyEditorRegistrar domainClassPropertyEditorRegistrar() {
    return new DomainClassPropertyEditorRegistrar();
}

(也许@Bean是不必要的,但至少它是这样工作的)

NEW:

Spring Data已经提供了我需要的一切:DomainClassConverter

刚刚放

@Bean
public DomainClassConverter<?> domainClassConverter() {
    return new DomainClassConverter<FormattingConversionService>(mvcConversionService());
}

WebMvcConfigurationSupport课程中,所有这些都是开箱即用的!

OLD:

我的最终解决方案是保持每个域对象的一对类方法。我刚刚构建了2个抽象类和一个接口,以尽量减少工作量:

1。 PropertyEditor

public abstract class AbstractEntityEditor<ID extends Serializable, SERVICE extends CanGetEntityById<?, ID>> extends PropertyEditorSupport {

    @Autowired
    SERVICE service;

    @Autowired
    ConversionService cs;

    final Class<ID> id;

    public AbstractEntityEditor(Class<ID> id) {
        this.id = id;
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        setValue(service.getById(cs.convert(text, id)));
    }

}

2. ControllerAdvice

public abstract class AbstractEntityEditorControllerAdvice<EDITOR extends PropertyEditor> {

    @Autowired
    EDITOR editor;

    final Class<?> entity;

    public AbstractEntityEditorControllerAdvice(Class<?> entity) {
        this.entity = entity;
    }

    @InitBinder
    public void register(WebDataBinder binder, WebRequest request) {
        binder.registerCustomEditor(entity, editor);
    }

}

3. 检索域对象的服务接口

public interface CanGetEntityById<ENTITY, ID extends Serializable> {
    ENTITY getById(ID id) throws NotFoundException;
}

这是一个示例用例:

<强> 1

@Component
public class UserEditor extends AbstractEntityEditor<ObjectId, UserService> {
    public UserEditor() {
        super(ObjectId.class);
    }
}

<强> 2

@ControllerAdvice
public class UserControllerAdvice extends AbstractEntityEditorControllerAdvice<UserEditor>{
    public UserControllerAdvice() {
        super(User.class);
    }
}

第3

public interface UserService extends GetEntityById<User, ObjectId> { }

<强> 4

@Service
public class UserServiceImpl implements UserService {
    public User getById(ObjectId id) throws NotFoundException {
        // fetch User from repository and return
    }
}

也许有办法让它好一点,但至少它有效!现在编写:-)只需5行代码。