springboot 通过 hibernate 连接sqlserver 空间数据 位置数据

示例代码:https://github.com/bigben0123/spring-boot-spatial-example

1,配置application.properties

#sqlserver configure
spring.datasource.url =jdbc:sqlserver://localhost:1433;DatabaseName=myDatabase
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.driverClassName =com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.jpa.database=SQLSERVER
spring.jpa.properties.hibernate.default_schema=dbo

#database name
spring.jpa.properties.hibernate.default_catalog=myDatabase

#使用空间数据类型 geometry等,需要把方言改成:spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.sqlserver.SqlServer2008SpatialDialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect

# Naming strategy
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy

spring.jpa.hibernate.ddl-auto=create-drop
#spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.h2geodb.GeoDBDialect
#spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.mysql.MySQL56InnoDBSpatialDialect
spring.jpa.show-sql=true
spring.datasource.platform=mysql
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
logging.level.org.hibernate.type=TRACE

2, 在maven中添加sql server的jdbc驱动包

官网下载sqljdbc4的jar包

解压到任意位置(win:E:sqljdbc_6.0chsjre8)。在有sqljdbc4.jar包的文件夹下,通过shift+右键的方式–>此处打开命令窗口,然后执行以下maven命令: 

mvn install:install-file -DgroupId=com.microsoft.sqlserver -DartifactId=sqljdbc4 -Dversion=4.2 -Dpackaging=jar -Dfile=E:sqljdbc_6.0chsjre8sqljdbc42.jar

显示build success,mvn库文件会放在C:UsersAdministrator.m2 epositorycommicrosoftsqlserver

3,pom.xml中添加依赖

<!-- sqlserver connector -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc4</artifactId>
<scope>4.2</scope>
<version>4.2</version>
</dependency>

 ____________________________________________________________________________________________________

源码参考:

super entity:

package org.vaadin.example;

import java.io.Serializable;
import java.util.Objects;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;

/**
 *
 * @author Matti Tahvonen
 */
@MappedSuperclass
public abstract class AbstractEntity implements Serializable, Cloneable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Version
    private int version;

    public Long getId() {
        return id;
    }

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

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if(this.id == null) {
            return false;
        }

        if (obj instanceof AbstractEntity && obj.getClass().equals(getClass())) {
            return this.id.equals(((AbstractEntity) obj).id);
        }

        return false;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 43 * hash + Objects.hashCode(this.id);
        return hash;
    }
    
}
View Code
package org.vaadin.example;

import java.util.Date;

import javax.persistence.Entity;

import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import javax.persistence.Column;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
public class SpatialEvent extends AbstractEntity {

    private String title;

    @Temporal(TemporalType.DATE)
    private Date date;

    //@Column(columnDefinition = "POINT") // this type is known by MySQL
    @Column(columnDefinition = "geometry")
    private Point location;

    // @Column(columnDefinition = "POLYGON") // this type is known by MySQL
    @Column(columnDefinition = "geometry")
    private LineString route;

    public SpatialEvent() {
    }

    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 LineString getRoute() {
        return route;
    }

    public void setRoute(LineString route) {
        this.route = route;
    }

    public Point getLocation() {
        return location;
    }

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

}
View Code
package org.vaadin.example;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author mstahv
 */
public interface SpatialEventRepository
        extends JpaQueryDslPredicateRepository<SpatialEvent, Long> {
    

}
View Code

主代码:

package org.vaadin.example;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import java.util.Date;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class SpatialSpringBootAppApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpatialSpringBootAppApplication.class, args);
    }

    @Bean
    CommandLineRunner init(SpatialEventRepository repo,SimpleEventRepository repo1) {
        return (String... strings) -> {
            GeometryFactory factory = new GeometryFactory();
            
//            repo.insert(23, 61);

            
            SpatialEvent theEvent = new SpatialEvent();
            theEvent.setTitle("Example event");
            theEvent.setDate(new Date());
            theEvent.setLocation(factory.createPoint(new Coordinate(26, 62)));
            theEvent.getLocation().setSRID(4326);
            repo.save(theEvent);
        
            SpatialEvent eventWithPath = new SpatialEvent();
            Coordinate[] coords = new Coordinate[] { new Coordinate(22, 60), new Coordinate(23, 61), new Coordinate(22, 63) };
            eventWithPath.setRoute(factory.createLineString(coords));
            eventWithPath.getRoute().setSRID(4326);
            eventWithPath.setLocation(factory.createPoint(new Coordinate(22, 60)));
            eventWithPath.getLocation().setSRID(4326);
            eventWithPath.setDate(new Date());
            eventWithPath.setTitle("MTB cup 1/10");
            repo.save(eventWithPath);

        };
    }
}

计算距离:

select location.ToString(),version, geography::STGeomFromText(location.ToString(), 4326).STDistance(geography::STGeomFromText('POINT(22 60)', 4326)) from spatial_event

5公里以内:

select * from spatial_event where  geography::STGeomFromText(location.ToString(), 4326).STDistance(geography::STGeomFromText('POINT(22 60)', 4326))<5000

 注意:

sqlserver的java类与数据库名称对应:MyDatabase 对应 my_database


sqlserver 用原生sql语句时,需要写完整的表名:数据库.dbo.表名

        String sql = "select * from  mydb.dbo.mytable"
                +"  where  location.STDistance('POINT(-121.626 47.8315)')<5";

        Query query = em.createNativeQuery(sql);
//        query.setParameter(1, email);
//        query.setParameter(2, id);
        query.getResultList();

 写表名,实体类名都不行。报错:

 ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - 对象名 'spatial_event' 无效。

或者

org.hibernate.QueryException: could not resolve property: point of: org.vaadin.example.SpatialEvent [select p from org.vaadin.example.SpatialEvent p where                         within(p.point, :circle) = true]

 这是由于错写了这句:

spring.jpa.properties.hibernate.default_schema=dbo


1、先说说Sql Server中geometry和geography的区别:

        geometry:planar    平面坐标系【supported by SQL Server conforms to the Open Geospatial Consortium (OGC) Simple Features for SQL Specification version 1.1.0.】

        geography: terrestrial   地理坐标系【stores ellipsoidal (round-earth) data, such as GPS latitude and longitude coordinates.】

        如果要计算两个lat/lon点之间的实际距离就需要将geometry类型转成geography类型,不然结果肯定不正确。

2、geometry转geography的方法:

       geography::STGeomFromText(boundary.ToString(), 4326)

       boundary是geometry类型的,4326是坐标系的参数,4326代表GCS-WGS-1984坐标系,是系统默认的坐标系。

       可以通过这个sql获得系统的坐标系(Sql server中):Select * from sys.spatial_reference_systems where authorized_spatial_reference_id=4326

3、STDistance的用法:

       https://msdn.microsoft.com/zh-cn/library/bb933952(v=sql.110).aspx

       按照里面的例子能够计算出距离,但是如果输入的是经纬度的值,得出的结果总是觉得不对,值比较小,实际上需要按照第二步转化为geography类型再计算就可以了,4326坐标系默认返回距离的单位【unit】是米【meter】。

       STDistance也可以计算点到面的最短距离。

 

        
---------------------
作者:Spring_Ji
来源:CSDN
原文:https://blog.csdn.net/jcx5083761/article/details/46010215?utm_source=copy
版权声明:本文为博主原创文章,转载请附上博文链接!

----------------------------------------------------------------



参考:https://blog.csdn.net/bitree1/article/details/63253685

原文地址:https://www.cnblogs.com/bigben0123/p/9792153.html