我正在使用带有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
。
希望你有一些建议。谢谢!
答案 0 :(得分: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。 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行代码。