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

标签 java spring generics converters propertyeditor

我正在将 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/

相关文章:

ios - 返回 Result<Object> 时,Realmswift 通用函数调用崩溃

c# - 从通用抽象类派生类和转换错误?

Java:枚举的通用方法

java - 如何重置 Android 微调器?

java - 标准 API 中的二叉树

spring - 使用 Rest 和 spring boot 将阿拉伯字符保存到数据库中

spring - CommonsMultipartResolver setMaxUploadSize 限制文件大小还是请求大小?

java - 在处理之前检查大文件是否已完全上传到目录中

java - org.apache.commons.lang3.time.DateFormatUtils.format() 线程安全吗?

java - Spring AOP - 代理从方法返回的对象