Liferay开发中使用自定义SQL注意事项

原创
2017/01/08 11:18
阅读数 1.2K

在Liferay的开发过程中,有时需要用到联表查询。暂时还没吃透Liferay本身它自己是如何实现这个的。但是在Liferay开发社区上看到关于自定义SQL正确用法,特此记录下。

一、创建自定义SQL文件。这个是有明确要求的,包括文件名称,目录位置,SQL的写法等等。

在你的Portlet项目docroot/WEB-INF/src/目录下创建“custom-sql”的目录,在此目录中创建default.xml文件。文件格式如下:

<custom-sql>
    <sql id="建议用对应使用类的全路径包括方法名做为ID值">
    SQL query wrapped in <![CDATA[...]]>
    No terminating semi-colon
    </sql>
</custom-sql>

对应SQL必须写在<![CDATA[xxxxxx]]>中。

以下给出一个Demo写法。

<?xml version="1.0" encoding="UTF-8"?>
<custom-sql>
    <sql id="com.nosester.portlet.eventlisting.service.persistence.EventFinder.\
findByEventNameEventDescriptionLocationName">
        SELECT Event_Event.*
        FROM Event_Event
        INNER JOIN 
            Event_Location ON Event_Event.locationId = Event_Location.locationId
        WHERE
            (Event_Event.name LIKE ?) AND
            (Event_Event.description LIKE ?) AND
            (Event_Location.name LIKE ?)
    </sql>
</custom-sql>

二、创建对应的方法和类

1、在项目中找到xxx.xx.xx.service.persistence这个包,在此包下创建对应实体的FinderImpl类,类名有要求,必须是实体名+FinderImpl。如NewsFinderImpl.java,然后继承BasePersistenceImpl<News>,内容如下:

package xxx.service.persistence;

import com.liferay.portal.service.persistence.impl.BasePersistenceImpl;
import xxx.model.News;

public class NewsFinderImpl extends BasePersistenceImpl<News> {

}

2、运行Service Builder就会自动创建对应的Finder接口和Util类。这时修改NewsFinderImpl实现NewsFinder接口。

package xxx.service.persistence;

import com.liferay.portal.service.persistence.impl.BasePersistenceImpl;
import xxx.model.News;

public class NewsFinderImpl extends BasePersistenceImpl<News> implements NewsFinder {

}

3、在NewsFinderImpl里增加需要的实现方法。

java.util.List;
com.liferay.portal.kernel.dao.orm.QueryPos;
com.liferay.portal.kernel.dao.orm.QueryUtil;
com.liferay.portal.kernel.dao.orm.SQLQuery;
com.liferay.portal.kernel.dao.orm.Session;
com.liferay.portal.kernel.exception.SystemException;
com.liferay.portal.service.persistence.impl.BasePersistenceImpl;
com.liferay.util.dao.orm.CustomSQLUtil;
com.xxxx.model.News;
com.xxxx.model.impl.NewsImpl;

public List<News> findByNewsxxxxx(
    String a, String b, String c,
    int begin, int end) {

    Session session = null;
    try {
        session = openSession();

        String sql = CustomSQLUtil.get(
            FIND_BY_xxxx);

        SQLQuery q = session.createSQLQuery(sql);
        q.setCacheable(false);
        q.addEntity("News", NewsImpl.class);

        QueryPos qPos = QueryPos.getInstance(q);  
        qPos.add(a);
        qPos.add(b);
        qPos.add(c);

        return (List<News>) QueryUtil.list(q, getDialect(), begin, end);
    } catch (Exception e) {
        try {
            throw new SystemException(e);
        } catch (SystemException se) {
            se.printStackTrace();
        }
    } finally {
        closeSession(session);
    }

    return null;
}   

在这一步需要特别注意q.addEntity()这个方法,设置此方法就可以将查询结果自动封闭成对应的实体对象,否则返回的结果仅是一个List<List>的对应,不好取结果。

还需要留意CustomSQLUtil.get(xxx)这个方法,此工具会自动扫描刚才定义的SQL文件,可以根据ID值取对应的语句。而且做到语句和类分离,修改方便,一改以往把语句写到类里的不良习惯。

4、向NewsLocalServiceImpl类再增加对应的调用方法。在Liferay Portlet开发中对外提供服务的都是xxxLocalServiceUtils这样的类,正确的姿势是:在xxLocalServiceImpl增加方法,在方法里通过xxFinder类调用自己实现的方法。

5、再运行一次Service Builder就会在xxxLocalServiceUtils里增加对应的调用方式供Portlet调用。

对于刚接触Liferay开发的人来说,要经常运行ServiceBuilder会有点不习惯,但是正因为通过这个工具才大大减少了很多工作,而且所有创建的类和方法都很标准。

记录完毕,断续撸码去。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部