Java 如何为多个实体使用单个JPA规范类和方法

Java 如何为多个实体使用单个JPA规范类和方法,java,spring,spring-boot,spring-data-jpa,criteria-api,Java,Spring,Spring Boot,Spring Data Jpa,Criteria Api,我正在创建一个springboot应用程序,它包含产品、类别、机械、UsageLocation等实体。。所有这些实体的共同点是,它们都有一个名为name的字符串属性,可以使用name从UI中进行筛选。我已经为产品编写了一个使用名称进行过滤的规范,它正在工作。下面是代码 public final class ProductSpecifications { public static Specification<Product> whereNameContains(Strin

我正在创建一个springboot应用程序,它包含产品、类别、机械、UsageLocation等实体。。所有这些实体的共同点是,它们都有一个名为name的字符串属性,可以使用name从UI中进行筛选。我已经为产品编写了一个使用名称进行过滤的规范,它正在工作。下面是代码

public final class ProductSpecifications 
{

    public static Specification<Product> whereNameContains(String name)
    {
        Specification<Product> finalSpec = (Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder cb)
            -> cb.like(root.get(Product_.PRODUCT_NAME), "%"+name+"%");
        return finalSpec;
    }

    public static Specification<Product> whereNameEqauls(String name)
    {
        Specification<Product> finalSpec = (Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder cb)
            -> cb.equal(root.get(Product_.PRODUCT_NAME), name);
        return finalSpec;
    }
}

公共最终类产品规范
{
公共静态规范whereNameContains(字符串名称)
{
规范finalSpec=(根目录、CriteriaQuery查询、CriteriaBuilder cb)
->cb.like(root.get(产品名称),“%”+NAME+“%”;
返回最终规格;
}
公共静态规范wherenameqauls(字符串名称)
{
规范finalSpec=(根目录、CriteriaQuery查询、CriteriaBuilder cb)
->cb.equal(root.get(产品名称),NAME);
返回最终规格;
}
}

现在的问题是,我必须再次编写相同的代码来过滤其他实体,唯一的区别是类名(Product)、字段名(Product_name)和方法的返回类型。我可以创建一个泛型类和方法吗?我可以将类名和字段名作为参数传递给它,它将返回相应返回类型的规范。

首先让您的
规范构建器成为泛型的

@Service
public final class SpecificationsBuilder<T>
{

    public static Specification<T> whereNameContains(String key,String name)
    {
        Specification<T> finalSpec = (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb)
            -> cb.like(root.get(key), "%"+name+"%");
        return finalSpec;
    }
}

您可以为SpecificationsBuilder创建自己的通用库,我有一个。您可以找到详细信息

我使用Abinash的答案解决了这个问题。下面是可重用规范类的工作代码

import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.ec.application.model.Product;
import com.ec.common.Filters.FilterAttributeData;
import com.ec.common.Filters.FilterDataList;

public class SpecificationsBuilder<T>
{

      //#######################################/#################//
     //      Level 0 - If the field that you want to query is parent entity               //
    //########################################################//    

    public Specification<T> whereDirectFieldContains(String key,List<String> names)
    {
        Specification<T> finalSpec = null;
        for(String name:names)
        {
            Specification<T> internalSpec = (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb)
                    -> cb.like(root.get(key), "%"+ name  +"%");
            finalSpec  = specOrCondition(finalSpec,internalSpec); // to append specifications as I am filtering based on list of strings
        }
        return finalSpec;
    }

      //#######################################//
     //     Level 1 - If you want to query a child entity.          //                //
    //#######################################//

    public Specification<T> whereChildFieldContains(String childTable, String childFiledName,
            List<String> names) 
    {
        Specification<T> finalSpec = null;
        for(String name:names)
        {
            Specification<T> internalSpec = (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb)
                    -> cb.like(root.get(childTable).get(childFiledName), "%"+ name  +"%"); 
            finalSpec  = specOrCondition(finalSpec,internalSpec);  // to append specifications as I am filtering based on list of strings
        }
        return finalSpec;
    }

      //#######################################//
     //     Reusable Spec Setter to handle  NULLs.               //
    //#######################################//

    public Specification<T> specAndCondition(Specification<T> finalSpec, Specification<T> internalSpec) 
    {
        if(finalSpec == null) return internalSpec;
        else return finalSpec.and(internalSpec);
    }

    public Specification<T> specOrCondition(Specification<T> finalSpec, Specification<T> internalSpec) 
    {
        if(finalSpec == null) return internalSpec;
        else return finalSpec.or(internalSpec);
    } 
}

public static Specification<Product> getSpecification(FilterDataList filterDataList)
    {
        List<String> productNames = specbldr.fetchValueFromFilterList(filterDataList,"product");
        List<String> categoryNames = specbldr.fetchValueFromFilterList(filterDataList,"category");
        Specification<Product> finalSpec = null;
        if(productNames != null && productNames.size()>0)
            finalSpec = specbldr.specAndCondition(finalSpec, specbldr.whereDirectFieldContains(Product_.PRODUCT_NAME, productNames));

        if(categoryNames != null && categoryNames.size()>0)
        {
            finalSpec = specbldr.specAndCondition(finalSpec,
                    specbldr.whereChildFieldContains(Product_.CATEGORY,Category_.CATEGORY_NAME, categoryNames));
        }   
        return finalSpec;   
    }


import java.util.List;
导入javax.persistence.criteria.CriteriaBuilder;
导入javax.persistence.criteria.CriteriaQuery;
导入javax.persistence.criteria.Root;
导入org.springframework.data.jpa.domain.Specification;
导入org.springframework.stereotype.Service;
导入com.ec.application.model.Product;
导入com.ec.common.Filters.FilterAttributeData;
导入com.ec.common.Filters.FilterDataList;
公共类规范生成器
{
//#######################################/#################//
//级别0-如果要查询的字段是父实体//
//########################################################//    
DirectFieldContains包含的公共规范(字符串键、列表名称)
{
规范finalSpec=null;
for(字符串名称:名称)
{
规范internalSpec=(根目录,CriteriaQuery查询,CriteriaBuilder cb)
->cb.like(root.get(key),“%”+name+“%”;
finalSpec=specOrCondition(finalSpec,internalSpec);//在我根据字符串列表进行筛选时附加规范
}
返回最终规格;
}
//#######################################//
//级别1-如果要查询子实体。////
//#######################################//
ChildFieldContains(字符串childTable、字符串childFiledName、,
(名单名称)
{
规范finalSpec=null;
for(字符串名称:名称)
{
规范internalSpec=(根目录,CriteriaQuery查询,CriteriaBuilder cb)
->cb.like(root.get(childTable).get(childFiledName),“%”+name+“%”;
finalSpec=specOrCondition(finalSpec,internalSpec);//在我根据字符串列表进行筛选时附加规范
}
返回最终规格;
}
//#######################################//
//可重用的规范设置器,用于处理空值//
//#######################################//
公共规范规范和条件(规范最终规范、规范内部规范)
{
if(finalSpec==null)返回internalSpec;
否则返回最终规格和(内部规格);
}
公共规范规范条件(规范最终规范、规范内部规范)
{
if(finalSpec==null)返回internalSpec;
否则返回最终规格或(内部规格);
} 
}
这是实体规范类的代码

import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.ec.application.model.Product;
import com.ec.common.Filters.FilterAttributeData;
import com.ec.common.Filters.FilterDataList;

public class SpecificationsBuilder<T>
{

      //#######################################/#################//
     //      Level 0 - If the field that you want to query is parent entity               //
    //########################################################//    

    public Specification<T> whereDirectFieldContains(String key,List<String> names)
    {
        Specification<T> finalSpec = null;
        for(String name:names)
        {
            Specification<T> internalSpec = (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb)
                    -> cb.like(root.get(key), "%"+ name  +"%");
            finalSpec  = specOrCondition(finalSpec,internalSpec); // to append specifications as I am filtering based on list of strings
        }
        return finalSpec;
    }

      //#######################################//
     //     Level 1 - If you want to query a child entity.          //                //
    //#######################################//

    public Specification<T> whereChildFieldContains(String childTable, String childFiledName,
            List<String> names) 
    {
        Specification<T> finalSpec = null;
        for(String name:names)
        {
            Specification<T> internalSpec = (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb)
                    -> cb.like(root.get(childTable).get(childFiledName), "%"+ name  +"%"); 
            finalSpec  = specOrCondition(finalSpec,internalSpec);  // to append specifications as I am filtering based on list of strings
        }
        return finalSpec;
    }

      //#######################################//
     //     Reusable Spec Setter to handle  NULLs.               //
    //#######################################//

    public Specification<T> specAndCondition(Specification<T> finalSpec, Specification<T> internalSpec) 
    {
        if(finalSpec == null) return internalSpec;
        else return finalSpec.and(internalSpec);
    }

    public Specification<T> specOrCondition(Specification<T> finalSpec, Specification<T> internalSpec) 
    {
        if(finalSpec == null) return internalSpec;
        else return finalSpec.or(internalSpec);
    } 
}

public static Specification<Product> getSpecification(FilterDataList filterDataList)
    {
        List<String> productNames = specbldr.fetchValueFromFilterList(filterDataList,"product");
        List<String> categoryNames = specbldr.fetchValueFromFilterList(filterDataList,"category");
        Specification<Product> finalSpec = null;
        if(productNames != null && productNames.size()>0)
            finalSpec = specbldr.specAndCondition(finalSpec, specbldr.whereDirectFieldContains(Product_.PRODUCT_NAME, productNames));

        if(categoryNames != null && categoryNames.size()>0)
        {
            finalSpec = specbldr.specAndCondition(finalSpec,
                    specbldr.whereChildFieldContains(Product_.CATEGORY,Category_.CATEGORY_NAME, categoryNames));
        }   
        return finalSpec;   
    }



公共静态规范getSpecification(FilterDataList FilterDataList)
{
List productNames=specbldr.fetchValueFromFilterList(filterDataList,“产品”);
List categoryNames=specbldr.fetchValueFromFilterList(filterDataList,“category”);
规范finalSpec=null;
如果(productNames!=null&&productNames.size()>0)
finalSpec=specbldr.specAndCondition(finalSpec,specbldr.whereDirectFieldContains(Product.Product\u NAME,productNames));
if(categoryNames!=null&&categoryNames.size()>0)
{
finalSpec=specbldr.specAndCondition(finalSpec,
specbldr.whereChildFieldContains(产品类别、类别类别名称、类别名称));
}   
返回最终规格;
}

你试过了吗?我不明白这个问题。如果你问我在发布问题之前是否尝试过任何解决方案-是的。我试了将近两天,然后贴出了这个问题。是的。经过一点调整后就成功了。非常感谢您的时间和支持。当然。我是新手。所以,我不知道我必须接受。我只是把它标记为有用。不管怎样,我现在把它标记为已接受。再次感谢您抽出时间。:)我是新来的?我不知道这有什么影响。看到你的评论后,我意识到。我把我的答案标为绿色勾号,因为这正是我所问问题的答案。不管怎样,我现在把它恢复了。