今天上午一位朋友问到了,关于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 java.util.Date;
 import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Point;


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


 public Event()
    public Event()  {}
{}


 public Long getId()
    public Long getId()  {
{
 return id;
        return id;
 }
    }


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


 public Date getDate()
    public Date getDate()  {
{
 return date;
        return date;
 }
    }


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


 public String getTitle()
    public String getTitle()  {
{
 return title;
        return title;
 }
    }


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

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

 public void setLocation(Point location)
    public void setLocation(Point location) {
{
 this.location = location;
    this.location = location;
 }
    }
 }
}
 <hibernate-mapping>
<hibernate-mapping>
 <class name="Event" table="EVENTS">
<class name="Event" table="EVENTS">
 <id name="id" column="EVENT_ID">
<id name="id" column="EVENT_ID">
 <generator class="native"/>
<generator class="native"/>
 </id>
</id>
 <property name="date" type="timestamp"
<property name="date" type="timestamp" 
 column="EVENT_DATE"/>
column="EVENT_DATE"/>
 <property name="title"/>
<property name="title"/>
 <property name="location"
<property name="location" 
 type="org.hibernatespatial.GeometryUserType"
type="org.hibernatespatial.GeometryUserType" 
 column="location"/>
column="location"/>
 </class>
</class>
 </hibernate-mapping>
</hibernate-mapping>

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

 <hibernate-configuration>
<hibernate-configuration>

 <session-factory>
    <session-factory>

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

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

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

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

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

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

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

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

 </session-factory>
    </session-factory>

 </hibernate-configuration>
</hibernate-configuration>
这句配置起到了重要的作用,这里声明了 hibernate 的方言。该方言声明了对postgis的一些支持。
并且大家也应该知道,在使用hibernate时候,如果需要自定义函数,要需要自定义方言。
5,第一个主类

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

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

 import util.HibernateUtil;
import util.HibernateUtil;


 public class EventManager
public class EventManager  {
{

 public int SRID = 4326;
    public int SRID = 4326;


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

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

 HibernateUtil.getSessionFactory().close();
        HibernateUtil.getSessionFactory().close();
 }
    }


 private void createAndStoreEvent(String title, Date theDate, String wktPoint)
    private void createAndStoreEvent(String title, Date theDate, String wktPoint)  {
{
 
        
 com.vividsolutions.jts.geom.Geometry geom = null;
        com.vividsolutions.jts.geom.Geometry geom = null;

 try
        try  {
{
 geom = pointFromText(wktPoint);
            geom = pointFromText(wktPoint);

 } catch (Exception e)
        } catch (Exception e)  {
{
 throw new RuntimeException("Not a WKT string:" + wktPoint);
            throw new RuntimeException("Not a WKT string:" + wktPoint);
 }
        }

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

 session.beginTransaction();
        session.beginTransaction();

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

 private List find(String wktFilter)
    private List find(String wktFilter) {
{
 WKTReader fromText = new WKTReader();
        WKTReader fromText = new WKTReader();
 com.vividsolutions.jts.geom.Geometry filter = null;
        com.vividsolutions.jts.geom.Geometry filter = null;

 try
        try {
{
 filter = fromText.read(wktFilter);
                filter = fromText.read(wktFilter);
 filter.setSRID(SRID);
                filter.setSRID(SRID);

 } catch(ParseException e)
        } catch(ParseException e) {
{
 throw new RuntimeException("Not a WKT String:" + wktFilter);
                throw new RuntimeException("Not a WKT String:" + wktFilter);
 }
        }
 Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
 session.beginTransaction();
        session.beginTransaction();
 System.out.println("Filter is : " + filter);
        System.out.println("Filter is : " + filter);
 Criteria testCriteria = session.createCriteria(Event.class);
        Criteria testCriteria = session.createCriteria(Event.class);
 testCriteria.add(SpatialRestrictions.within("location", filter, filter));
        testCriteria.add(SpatialRestrictions.within("location", filter, filter));
 List results = testCriteria.list();
        List results = testCriteria.list();
 session.getTransaction().commit();
        session.getTransaction().commit();
 return results;
        return results;
 }
    }
 
    

 private List find1(String wktFilter)
    private List find1(String wktFilter) {
{
 WKTReader fromText = new WKTReader();
        WKTReader fromText = new WKTReader();
 com.vividsolutions.jts.geom.Geometry filter = null;
        com.vividsolutions.jts.geom.Geometry filter = null;

 try
        try {
{
 filter = fromText.read(wktFilter);
                filter = fromText.read(wktFilter);
 filter.setSRID(SRID);
                filter.setSRID(SRID);

 } catch(ParseException e)
        } catch(ParseException e) {
{
 throw new RuntimeException("Not a WKT String:" + wktFilter);
                throw new RuntimeException("Not a WKT String:" + wktFilter);
 }
        }
 Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
 session.beginTransaction();
        session.beginTransaction();
 
        
 Query query = session.createQuery("select within(location,'srid=4326;POLYGON ((1 1, 20 1, 20 20, 1 20, 1 1))') from Event ");
        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();
        List list = query.list();
 return list;
        return list;
 }
    }



 public Point pointFromText(String txt) throws Exception
    public Point pointFromText(String txt) throws Exception  {
{

 String tmp = txt;
        String tmp = txt;

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


 try
        try  {
{
 WKTReader fromText = new WKTReader();
              WKTReader fromText = new WKTReader();
 Geometry  geom = fromText.read(tmp);
                Geometry  geom = fromText.read(tmp);
 
                
 
            
 Point pt = (Point) fromText.read(tmp);
            Point pt = (Point) fromText.read(tmp);
 pt.setSRID(SRID);
            pt.setSRID(SRID);
 return pt;
            return pt;

 } catch (Exception e)
        } catch (Exception e)  {
{
 return null;
            return null;
 }
        }
 }
    }


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