2

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

我只想替换这个:

@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 框架中的其他地方使用它也可以(= 很好)让它工作。

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

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

4

1 回答 1

2

较新:

如果您还想要适当的异常处理,您应该使用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是不必要的,但至少它是这样工作的)

新的:

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

就放

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

WebMvcConfigurationSupport课堂上,这一切都是开箱即用的!

老的:

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

1.属性编辑器

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 行代码:-)

于 2014-03-06T13:16:36.907 回答