Liferay 6.1开发学习(十九):Liferay ServiceBuilder之自定义查询
注:本篇博客所讲的代码内容基于前面的CRUD-demo的代码。看此篇文章前,请先阅读以下两篇博客
Liferay6.1简单增删改查示例:http://www.huqiwen.com/2012/11/01/liferay6-1-crud-demo/
Liferay 6.1开发学习(四):Service Builder:http://www.huqiwen.com/2012/09/11/liferay-6-1-development-study-4-service-builder/
在Liferay的二次开发中,经常使用到ServiceBuilder,它为我们生成了数据库操作层、业务层、SQL语句等内容,里面包含基础的增删改查的语句,可以满足简单的业务场景,但对于一些复杂的业务场景,可能需要有复杂的查询,单表的多字段联合查询,跨表的查询等等。在这里介绍几种常用的基于ServiceBuilder的自定义查询方法。
在service.xml中定义finder方法
在service.xml中定义一个如下的方法:
- <finder name="userId" return-type="Collection">
- <finder-column name="userId" />
- <finder-column name="groupId"/>
- </finder>
表示的意思为,我们生成一个叫findByUserId的方法,其中有两个参数为userId和groupId,返回的类型为一个集合类型,也就是List<xxx>,其中的xxx为这个service.xml中相应的entity的name值。
注意:finde-column 里面的name值必须和前面设置的column的值一致。
此处同时可以添加比较符号,如=, !=, <, <=, >, >=, 或者LIKE,默认为=,如果要添加其他比较符合,添加一个属性,如<finder-column name="bookName" comparator="LIKE"/>
重新执行serviceBuilder。会为我们生成一个public List<Books> findByUserId(long userId,long groupId)的方法。此方法我们可以通过xxxUtil.findByUserId进行调用,在此示例中就是使用BooksUtil类进行调用。
但是在portlet中我们一般不直接使用xxUtil方法,所以要通过BooksLocalServiceUtil方法进行调用,需要再进行一层包装,找到xxx.service.impl里面的BooksLocalServiceImpl类,我们在里面添加一个方法名为getAllBooks,然后在这个方法里面写booksPersistence.findByUserId(userId,groupId)。写完之后重新执行ServiceBuilder。(具体体代码参看CURD-demo里面的)
Liferay中的DynamicQuery
Liferay中的DynamicQuery是封装的hibernate的querycriteria,所以查询语法上基本和hibernate的querycriteria查询类似。比如现在我们要在Books这个表里面查询,实现bookName包含某一个关键字,而且groupId等于xxx的情况,代码如下。
- DynamicQuery query = DynamicQueryFactoryUtil.forClass(Books.class);
- if(Validator.isNotNull(keyWord)){
- query.add(PropertyFactoryUtil.forName("bookName").like("%"+keyWord+"%"));
- }
- query.add(PropertyFactoryUtil.forName("groupId").eq(groupId));
- dynamicQuery(query,start,end);
这几行代码的意思,是第一行相当于创建SQL:select * from books。
第2-4行为当keyword不为空的时候,为将上面的sql拼接为 select * from books where bookName like ‘%keyWord%’。
第5行为,再添加 and groupid=groupId
最后一行为执行查询,并返回相应的查询结果。
在Liferay中使用HQL进行查询
使用DynamicQuery在进行一些简单的查询时非常方便,如果要进行一些复杂的查询,如跨多表的查询等,使用DynamicQuery就会比较复杂;而且使用DynamicQuery查询返回的数据类型要么是现有的对象,要么是对象集合,有时候我们的查询可能需要返回的数据是某几个对象部分属性的组合等,这个时候可以使用HQL进行查询,在基于ServiceBuilder使用HQL时,有点小复杂,方法如下。
第一步:在xxx.service.persistence里面新建BooksFinderImpl方法,继承自BasePersistenceImpl类。此处的命名必须是xxFinderImpl,前面的xx是Service.xml里面定义的实体名称。
第二步:执行service builder,此时会在service包的xxx.service.persistence下面生成BooksFinder的接口类和对应的BooksFinderUtil类。
第三步:让我们的BooksFinderImpl继承BooksFinder类。现在我们的BooksFinderImpl类如下。
- public class BooksFinderImpl extends BasePersistenceImpl<Books> implements BooksFinder {
- }
第四步:在此类中编写我们的具体的查询方法(只是简单的示例代码),如下。
- public List findBooks(long userId, String keywords, int start, int end) throws SystemException{
- List list = null;
- String sql = null;
- sql = "SELECT book.bookId, book.bookNo,book.bookName FROM Books book where book.userId=? and book.bookName =?";
- Session session = null;
- try {
- session = openSession();
- Query q = session.createQuery(sql);
- q.setLong(0, userId);
- q.setString(1, keywords);
- list = (List)QueryUtil.list(q, getDialect(),start, end, false);
- }
- catch (Exception e) {
- throw processException(e);
- }
- finally {
- closeSession(session);
- }
- return list;
- }
第五步:重新执行ServiceBuilder,现在会在BooksFinderUtil里面生成相应的接口,但是我们不能直接调用BooksFinderUtil方法,需要将我们的这个方法添加到BooksLocalServiceImpl里面。我们在BooksLocalServiceImpl里面添加相应的方法,在BooksLocalServiceImpl里面使用booksFinder.findBooks()进行调用。
第六步:再次执行ServiceBuilder,现在就可以通过BooksLocalServiceUtil类调用自定义的查询类了。
PS:建一Liferay技术研究群:6537876,欢迎有兴趣的朋友加入。
为什么我按照这样的操作生成的方法返回的类型不是list,二手一个Book的类型
代码长啥样
我用你的这个方式不行,将这一行: list = (List)QueryUtil.list(q, getDialect(),start, end, false); 注释掉换成:list = q.list();前面的:Query q = session.createQuery(sql); 换成Query q = session.createSQLQuery(HQL).addEntity(“这里是xx-service.xml的名称”, 类名Impl.class);就可以实现查询功能了。但是有个问题就是只能得到该类的所有属性所对应的值,其它类的值无法获得。比如我们的sql写联查就只能得到其中一张表的数据而不是该SQL语句查询到的所有数据。求教该如何解决的好呢?