【问题标题】:Spring Generic Dao class nameSpring Generic Dao 类名
【发布时间】:2013-02-06 19:27:51
【问题描述】:

我已经为我的 spring/hibernate 项目配置了一个自定义的通用服务 DAO - 我可以轻松地从我的控制器中重用它。

它基本上看起来像这样:

public class DefaultService<T> {

private Class<T> e;

public String className(Class<T> e) {
    String clip = e.getName();
    clip = clip.substring(clip.lastIndexOf('.') + 1, clip.length());
    return clip;
}
public List<T> getAll(Integer status) {
    Session session = sessionFactory.getCurrentSession();
    Query query = session.createQuery("FROM " + className(e) + " WHERE status = " + status);
    return query.list();
}
...

引用者:

@Autowired
public DefaultService<Address> addressService;
addressService.get(1);

但是String clip = e.getName() 行会引发空指针异常。如果我将类移到属性部分,我可以让它工作(所以addressService.get(Address.class, 1),但我觉得这有点不整洁,特别是当有多个不同的类被调用时。

有什么方法可以让类正确生成一个值,而无需重复地将其添加到我的所有函数中?

提前致谢。

【问题讨论】:

    标签: java spring genericdao


    【解决方案1】:

    我做了类似的事情,你也需要泛型类作为构造函数参数,我的使用休眠实体,但你可以传入表名字符串。

    public class DomainRepository<T> {
    
        @Resource(name = "sessionFactory")
        protected SessionFactory sessionFactory;
    
     public DomainRepository(Class genericType) {
            this.genericType = genericType;
        }
    
     @Transactional(readOnly = true)
        public T get(final long id) {
            return (T) sessionFactory.getCurrentSession().get(genericType, id);
        }
    

    然后,您可以子类化(如果需要)来自定义或简单地在 spring 配置中设置您的 bean,如下所示:

    <bean id="tagRepository" class="com.yourcompnay.data.DomainRepository">
            <constructor-arg value="com.yourcompnay.domain.Tag"/>
    </bean>
    

    因此,在您的代码中,您可以像这样引用 tagRepository(除了上面和下面发布的代码之外,不需要其他代码 eis):

    @Resource(name = "tagRepository")
    private DomainRepository<Tag> tagRepository;
    

    另外,我将其称为存储库而不是服务,服务处理不同类型及其交互(不仅仅是一个)。特别是您使用 SQL 字符串的示例:

    public final String tableName;
    public DomainRepository(String tableName) {
          this.tableName = tableName;
    }
    public List<T> getAll(Integer status) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery("FROM " + tableName + " WHERE status = " + status);
        return query.list();
    }
    

    让你的 bean 像这样定义

    <bean id="addressRepository" class="com.yourcompnay.data.DomainRepository">
      <constructor-arg value="address"/>
    </bean>
    

    然后你也可以在必要时自己创建子类:

    public class PersonRepository extends DomainRepository<Person> {
        public PersonRepository(){
            super("person"); //assumes table name is person
        }
    

    【讨论】:

    • 我的完整类的第一行是@Repository,所以我将从现在开始调用它:) 因为它是我想要的类的名称,以便我可以创建自定义数据库查找,看看你的代码,理论上我只需要添加public void e(Class genericType) {this.e = genericType;}吗?
    • 查看更新,如果子类文件为空,请不要在必要时子类... onyl 子类。在我的应用程序中,我有许多存储库,它们只是通用存储库的实例,然后是一个或两个已被子类化的存储库(它们有更复杂的要求)。我提供的解决方案允许您子类化......我会向您展示这一点
    • 好的,所以我已经改造了我的应用程序以遵循这一点(不情愿地为每个模型创建所有这些额外的存储库)。最后一个问题——豆子有什么作用?没有它似乎工作得很好,虽然我确实需要删除 'tableName' 的 'final' 修饰符并添加一个 public DomainRepository() {} 方法......
    • @Toby 嗯?您只需创建一个 DomainRepository 类,bean 定义使用您在代码中引用的构造函数参数和 Generic 参数实例化 DomainReposiory 的实例...您没有子类化,无论是否勉强,但如果您有许多特定于某些类型/表的方法,它会很有用。
    • 啊,我明白了,所以这就像一个非此即彼的情况?好吧,我一直在使用一些可怕的解决方法来尝试使 dao 尽可能通用,因此最好为每个实际存储库创建一个单独的实例——它只有十几个,所以还不错。最后一个问题:哪个更好还是没有区别? @Autowired public PageRepos pagerep; or @Autowired public DomainRepository pagerep;'?非常感谢
    【解决方案2】:

    据我了解,您之所以获得 NPE,是因为您没有为此字段设置任何值。 所以你可以通过两种方式解决这个问题:

    1. 手动设置类对象,如注释 NimChimpsky。
    2. 动态获取类类型。例如,如果你使用 Spring,试试这个:

    protected Class getEntityClass() { return GenericTypeResolver.resolveTypeArguments(getClass(), DefaultService.class)[0]; }

    some workaround here

    【讨论】:

    • 这应该适用于我当前的代码吗?我对正在发生的事情有很好的基本了解,但我无法完全理解这条线如何适应?
    • 是的,这个方法应该对你有帮助。这一行显示了如何获取具体泛型类型的 Class 类型。您可以使用此类对象:获取名称和其他内容。
    【解决方案3】:

    最好为地址服务定义一个特定的类

    public class AddressService extends DefaultService<Address>{
      public String getClassName(){
       return "Address";
      }
    }
    

    在哪里

    public String getClassName();
    

    是在 DefaultService 中声明的抽象方法,并在您的数据访问逻辑中使用(如您的方法 className())。

    使用这种方法,您将能够添加特定的数据访问逻辑(例如,getUsersByAddress)

    【讨论】:

      猜你喜欢
      • 2011-10-10
      • 2018-01-14
      • 1970-01-01
      • 1970-01-01
      • 2016-02-21
      • 1970-01-01
      • 1970-01-01
      • 2015-03-05
      • 1970-01-01
      相关资源
      最近更新 更多