Jason ---分享,共同进步

激情成就梦想,努力创造未来
随笔 - 53, 文章 - 1, 评论 - 45, 引用 - 0
数据加载中……

hibernate 支持 postgis函数


今天上午一位朋友问到了,关于hibernate中是否支持postgis函数的问题,我就这个问题,随便聊几句。


要想使用hibernate的空间数据操作,就要提到一个概念 java Topology Suite (字面上理解就是 空间拓扑的意思,简称JTS,
注意:过需要声明一点,本文中的JTS与进行java事务处理的JTS、JTA没有联系).

HIBERNATE中对空间数据作了支持(Hibernate Spatial),Hibernate Spatial是对处理空间数据的一个Hibernate扩展 ,

Hibernate Spatial 使用标准的方式处理地理信息数据 ,并且提供了一个可以跨数据库的处理的接口函数,

Hibernate Spatial 中包含了多种 OGC 简单的处理函数. 支持的数据库为: Oracle 10g/11g, Postgresql/Postgis, and MySQL.

要想使用 Hibernate Spatial  就要引入JTS, JTS 从根本上而言其实并不是很复杂,它主要是完成了java对几何对象、空间拓扑得核心操作算法。

下面通过简单配置来说明一下如何使用(我们使用的数据库是postgis):

数据库脚本:
sql:

CREATE TABLE events
(
  id bigint NOT NULL,
  event_date timestamp without time zone,
  title character varying(255),
  "location" geometry,
  CONSTRAINT events_pkey PRIMARY KEY (id)
)


1,引入 jts-1.8.jar, hibernate3.jar 等包 ,同时还要应用 hibernate-spatial-postgis-1.0-20070920.111959-1.jar 和
hibernate-spatial-1.0-20070920.111959-1.jar 包(如果不是postgre sql就要引用相应的数据库包)。


2,创建一个持久化类(po对象)

如下:
import java.util.Date;
import com.vividsolutions.jts.geom.Point;

public class Event {
    
private Long id;
    
private String title;
    
private Date date;
    
private Point location;

    
public Event() {}

    
public Long getId() {
        
return id;
    }


    
private void setId(Long id) {
        
this.id = id;
    }


    
public Date getDate() {
        
return date;
    }


    
public void setDate(Date date) {
        
this.date = date;
    }


    
public String getTitle() {
        
return title;
    }


    
public void setTitle(String title) {
        
this.title = title;
    }

    
    
public Point getLocation(){
    
return this.location;
    }

    
    
public void setLocation(Point location){
    
this.location = location;
    }

}
注意:上面的po对象中的location属性的类型。这个类型是空间数据类型。

3,创建相应的Mapping 文件

<hibernate-mapping>
<class name="Event" table="EVENTS">
<id name="id" column="EVENT_ID">
<generator class="native"/>
</id>
<property name="date" type="timestamp" 
column
="EVENT_DATE"/>
<property name="title"/>
<property name="location" 
type
="org.hibernatespatial.GeometryUserType" 
column
="location"/>
</class>
</hibernate-mapping>
注意:在上面的影射文件中,type="org.hibernatespatial.GeometryUserType" 这type类型声明很特别,我们知道在hibernate中要自定义影射类型,可以自定义类型UserType.在这个配置文件中定义的类型org.hibernatespatial.GeometryUserType就是hibernatespatial中定义支持空间数据库的类型。

4,配置hibernate 配置文件
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"
>

<hibernate-configuration>

    
<session-factory>

        
<!-- Database connection settings -->
        
<property name="connection.driver_class">org.postgresql.Driver</property>
        
<property name="connection.url">jdbc:postgresql://localhost:5432/test</property>
        
<property name="connection.username">postgres</property>
        
<property name="connection.password">test</property>

        
<!-- JDBC connection pool (use the built-in) -->
        
<property name="connection.pool_size">1</property>

        
<!-- SPATIAL SQL dialect -->
        
<property name="dialect">org.hibernatespatial.postgis.PostgisDialect</property>

        
<!-- Enable Hibernate's automatic session context management -->
        
<property name="current_session_context_class">thread</property>

        
<!-- Disable the second-level cache  -->
        
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

        
<!-- Echo all executed SQL to stdout -->
        
<property name="show_sql">true</property>

        
<!-- Drop and re-create the database schema on startup -->
        
<property name="hbm2ddl.auto">create</property>

        
<mapping resource="Event.hbm.xml"/>

    
</session-factory>

</hibernate-configuration>
注意:在上面的配置文件中, <property name="dialect">org.hibernatespatial.postgis.PostgisDialect</property>
这句配置起到了重要的作用,这里声明了 hibernate 的方言。该方言声明了对postgis的一些支持。
并且大家也应该知道,在使用hibernate时候,如果需要自定义函数,要需要自定义方言。


5,第一个主类


import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernatespatial.criterion.SpatialRestrictions;
import org.postgis.Geometry;
import org.postgis.LineString;
import org.postgis.MultiLineString;
import org.postgis.MultiPolygon;
import org.postgis.PGgeometry;
import org.postgis.Polygon;

import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import com.vividsolutions.jts.geom.*;
import java.util.Date;
import java.util.List;

import util.HibernateUtil;

public class EventManager {

    
public int SRID = 4326;

    
public static void main(String[] args) {
        EventManager mgr 
= new EventManager();

        String testPiont 
= "2,3";
        mgr.createAndStoreEvent(
"My Event"new Date(), testPiont);
    

        HibernateUtil.getSessionFactory().close();
    }


    
private void createAndStoreEvent(String title, Date theDate, String wktPoint) {
        
        com.vividsolutions.jts.geom.Geometry geom 
= null;
        
try {
            geom 
= pointFromText(wktPoint);
        }
 catch (Exception e) {
            
throw new RuntimeException("Not a WKT string:" + wktPoint);
        }


        Session session 
= HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        Event theEvent 
= new Event();
        theEvent.setTitle(title);
        theEvent.setDate(theDate);
        theEvent.setLocation((Point) geom);
        session.save(theEvent);
        session.flush();
        session.getTransaction().commit();
        List l
= find("POLYGON((1 1,20 1,20 20, 1 20, 1 1))");
        
        System.out.println(l.size());
        
        List l1
= find1("POLYGON((1 1,20 1,20 20, 1 20, 1 1))");
        
        System.out.println(l1.size());
    }

    
    
private List find(String wktFilter){
        WKTReader fromText 
= new WKTReader();
        com.vividsolutions.jts.geom.Geometry filter 
= null;
        
try{
                filter 
= fromText.read(wktFilter);
                filter.setSRID(SRID);
        }
 catch(ParseException e){
                
throw new RuntimeException("Not a WKT String:" + wktFilter);
        }

        Session session 
= HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        System.out.println(
"Filter is : " + filter);
        Criteria testCriteria 
= session.createCriteria(Event.class);
        testCriteria.add(SpatialRestrictions.within(
"location", filter, filter));
        List results 
= testCriteria.list();
        session.getTransaction().commit();
        
return results;
    }

    
    
private List find1(String wktFilter){
        WKTReader fromText 
= new WKTReader();
        com.vividsolutions.jts.geom.Geometry filter 
= null;
        
try{
                filter 
= fromText.read(wktFilter);
                filter.setSRID(SRID);
        }
 catch(ParseException e){
                
throw new RuntimeException("Not a WKT String:" + wktFilter);
        }

        Session session 
= HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        
        Query query 
= session.createQuery("select within(location,'srid=4326;POLYGON ((1 1, 20 1, 20 20, 1 20, 1 1))') from Event ");

        List list 
= query.list();
        
return list;
    }



    
public Point pointFromText(String txt) throws Exception {

        String tmp 
= txt;
        
if (!tmp.startsWith("POINT")) {
            tmp 
= tmp.replace(","" ");
            tmp 
= "POINT(" + tmp + ")";
        }


        
try {
              WKTReader fromText 
= new WKTReader();
                Geometry  geom 
= fromText.read(tmp);
                
            
            Point pt 
= (Point) fromText.read(tmp);
            pt.setSRID(SRID);
            
return pt;
        }
 catch (Exception e) {
            
return null;
        }

    }



    }

通过上面的方法,我们可以测试出来,hibernate已经可以支持空间数据类型的数据操作了,可以实现空间数据入库到空间数据对象影射到java对象中(插入和查询方法),但是有一个问题,就是支持的空间数据操作方法太少了。例如 contains,disjoint,within等十几个方法。这些方法都是简单的空间数据操作方法,要想实现复杂的空间数据这还远远不够的。相对于这方面来说ibatis 就很方便的使用了。

这方面的资料比较少,大家都交流 ,有什么好的经验大家分享一下。 

 

posted on 2008-07-15 23:05 agun 阅读(2750) 评论(7)  编辑  收藏 所属分类: 架构设计与系统分析

评论

# re: hibernate 支持 postgis函数  回复  更多评论   

我用HQL去查询结果(hibernate+postgis)
select t.fname from Tgpoi t where t.ftcd=111;

select asText(t.the_geom) from Tgpoi t where t.ftcd=111;

都可以查找出来

但我想得到多个字段的话,输出:
Ljava.lang.Object;@232dsfdff

请问一下如何能得到某条记录所有的值
2008-07-16 13:20 | ads

# re: hibernate 支持 postgis函数  回复  更多评论   

又来麻烦你了,
hibernate 与 postgis 结合可以看看这个
http://www.hibernatespatial.org/tutorial.html
上面说的还不错,提供大家参考
2008-07-16 13:38 | ads

# re: hibernate 支持 postgis函数  回复  更多评论   

呵呵,这个文章很好,你上面说想得到多个字段,hibernate查询输出的一定是对象。
如果是 select asText(t.the_geom) ,asText(t.the_geom) from Tgpoi t where t.ftcd=111;
这样的HQL,那么
Query query = session.createQuery("select asText(t.the_geom) ,asText(t.the_geom) from Tgpoi t where t.ftcd=111");
List l= query.list();
System.out.println(((List)l.get(0)).get(0).toString());
System.out.println(((List)l.get(0)).get(1).toString());
这样就能分别拿到查询了列了。
不知道你不是你说的意思。多交流。
2008-07-17 13:57 | agun

# re: hibernate 支持 postgis函数  回复  更多评论   

呵呵
谢谢了
我做出来了,主要问题出在了
我的驱动包引错了,大大的失误
嘿嘿!!现在学习这个,资料太小,几乎都是外文的,可怜我的外文水平!!!
2008-07-28 10:54 | ads

# re: hibernate 支持 postgis函数  回复  更多评论   

呵呵,出来就好,现在这方面的中文的资料不是很多,hibernate的postgis支持不是很好,许多gis函数都需要自己声明。有什么好的资料,到时候都拿出来分享,一起学习。
2008-07-29 16:31 | agun

# re: hibernate 支持 postgis函数  回复  更多评论   

如果是大量的GIS开发,最好不要用HIBERNATE即使用上面地方法能够支持,也只是支持不多的几个函数,要想做更多更好的空间处理,用ibatis可以很容易结合自己的Handler Type来处理。
2010-11-29 11:17 | agun

# re: hibernate 支持 postgis函数  回复  更多评论   

这个项目文件还有没有?可不可以拷我一份?最近需要用到这个但是一直搞不定!!我的邮箱是:youdianshen@126.com
2013-03-20 11:31 | 沈维海

只有注册用户登录后才能发表评论。


网站导航: