Java 通过服务API公开Hibernate标准
这更多的是一个设计问题,而不是实现问题,这将是一个漫长的过程,所以请容忍我。最好用一个例子来解释: 假设我有一个名为Product的业务实体,它有一系列属性(名称、价格、供应商等)。 它由接口(产品)和实现(ProductImpl,在Hibernate中映射)以及基本CRUD服务接口(ProductService)和实现(ProductServiceImpl)表示。Java 通过服务API公开Hibernate标准,java,hibernate,Java,Hibernate,这更多的是一个设计问题,而不是实现问题,这将是一个漫长的过程,所以请容忍我。最好用一个例子来解释: 假设我有一个名为Product的业务实体,它有一系列属性(名称、价格、供应商等)。 它由接口(产品)和实现(ProductImpl,在Hibernate中映射)以及基本CRUD服务接口(ProductService)和实现(ProductServiceImpl)表示。 产品和产品服务是作为API公开的,它们的实现不是。 我想向ProductService添加一个List findPro
产品和产品服务是作为API公开的,它们的实现不是。 我想向ProductService添加一个List findProducts(QueryCriteria criteria criteria)方法,该方法将返回满足给定条件的产品列表。 这些要求是:
Product.price gt 50.0
)product.vendor.name=“Oracle”
)按product.vendor.name desc、product.price asc排序“
)product.vendor.name=“Microsoft”
,则上述(2)中的查询应生成空结果集- 允许客户端直接指定HQL(从“where”子句开始)。 这是最简单的解决方案,但在安全方面也是最有问题的。即使假设过滤器(#4)足够简单,可以通过Hibernate的会话过滤器实现,HQL仍然需要解析,以确保查询参数被指定为参数,而不是内联的
- 使用包装很薄的Hibernate的DetachedCriteria代替QueryCriteria。 “精简包装”,因为不能允许客户机直接创建DetachedCriteria,因为无法控制为哪个映射实体创建它。 此外,这也不如HQL灵活,因为有些查询不容易(或根本不可能)通过Criteria API表达。与HQL方法一样,筛选器(#4)将仅限于Hibernate会话筛选器
- 编写我自己的QueryCriteria接口/实现,在幕后形成DetachedCriteria或HQL。 虽然这可能是最灵活的解决方案,但它必须从CriteriaAPI复制大量代码,这似乎不太理想
另外,在我的具体案例中,所有API客户机都是内部的且“半可信的”——也就是说,我不太担心有人试图故意破坏某些东西,而是担心糟糕的编程导致5个表的笛卡尔乘积:-)不过,最好能想出一个解决方案,使API能够向公众公开。公开这样的实现细节从来都不是一个好主意。从那时起,您就被绑定到该库。更糟糕的是,库的任何API更改都会导致服务的API i更改。任何遗留的安全注意事项 critera中使用的bean属性名(属性名、enum with less、equal和more以及value的三元组)怎么样?在模型上使用bean包装器,您可以将其转换为hibernate标准
模型更改后,还可以将此属性名称转换为新版本。Hmm-有趣的问题 仔细考虑后,编写您自己的标准接口可能是一个不错的选择。它不会将您与实现捆绑在一起,并且会降低安全性问题 根据涉及的对象数量,我们还考虑返回整套产品(应用必要的过滤器),然后让最终用户应用带有lambdaj或类似过滤器。请参阅:
Hibernate是一个低级基础架构框架,因此应该隐藏在幕后。如果下个月您的应用程序出于某种原因需要切换到另一个ORM框架,那么您的API将毫无用处。即使在同一应用程序中的层之间进行封装,也是至关重要的 说到这里,我认为您的方法应该接收执行搜索所需信息的抽象。我建议您创建
产品
字段的枚举,并实现一个或两个简单的限制版本
该方法的参数可以是相等限制列表、另一个相对限制列表,当然还有一个顺序指示符(枚举值之一加上asc/desc的标志)
这只是一个大致的方向,我希望我能把我的观点讲清楚 如果有可能扩展您的API,我建议让您的API“更丰富”——添加更多的方法,如下面的一些方法,使您的服务听起来更自然。要使您的API更大而不显得臃肿,这可能会很棘手,但如果您遵循类似的命名方案,使用它似乎会很自然
productService.findProductsByName("Widget")
productService.findProductsByName(STARTS_WITH,"Widg")
productService.findProductsByVendorName("Oracle")
productService.findProductsByPrice(OVER,50)
通过使用CollectionUtils和谓词,组合结果(应用多个限制)可以留待客户端在收到结果集后执行。您甚至可以为API的使用者构建一些通用谓词,只是为了更好。CollectionUtils.select()很有趣
选项二:如果无法扩展API,那么我会选择第三个项目
- 编写我自己的QueryCriteria接口/实现,它将形成
Product.Restriction restriction = new Product.Restriction().name("Widget").vendor("Oracle").price(OVER,50) ); productService.findProducts(restriction);
public List<Entity> findEntities(String queryName, QueryParameters parameters);
List<Product> products = findProducts("latestUpdates", new QueryParameters() .add("vendor", "Oracle") .add("price", "50.0") );
List<Product> products = findProducts("latestUpdates", new QueryParameters(product, "vendor", "price"));