我正在将 Spring 4 与 Spring Data MongoDB 结合使用,并希望删除 Controller 中的一些样板代码。
我只想替换这个:
@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
)。
希望大家给点建议。谢谢!
最佳答案
较新:
如果您还需要正确的异常处理,则应该使用 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 个抽象类和一个接口(interface),以最大限度地减少工作量:
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.检索域对象的服务接口(interface)
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 行代码即可编写 :-)
。
关于java - @PathVariable 的全局通用 PropertyEditorSupport -> 域对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22210891/