MySQL空间地理位置字段: geometry


 

CREATE TABLE `zone_area` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  `location` geometry DEFAULT NULL,
  `geohash` varchar(20) GENERATED ALWAYS AS (st_geohash(`location`,8)) VIRTUAL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='';
ALTER TABLE zone_area ADD COLUMN `geohash` varchar(20) GENERATED ALWAYS AS (st_geohash(`location`,8)) VIRTUAL;

 

字段: 使用geometry类型存储空间点数据;

存储: 

SET location = geomfromtext('point(108.9498710632 34.2588125935)'));

 

搜索: 查询方圆5公里数据? geohash字段是将二维通过geohash算法变成一维;

 

虚拟自增列 Generated Column是MySQL 5.7引入的新特性,Cenerated Column,就是数据库中这一列由其他列计算而得。
generated column always总是自动生成

 

 

FLOOR(X)表示向下取整,只返回值X的整数部分,小数部分舍弃。
CEILING(X) 表示向上取整,只返回值X的整数部分,小数部分舍弃。
#DECIMAL 四舍五入
SELECT CAST('123.456' AS DECIMAL) #123
SELECT CAST('123.456' AS DECIMAL(10,2)) #123.46
ROUND(X) -- 四舍五入
SELECT ROUND('123.456') #123
SELECT ROUND('123.456',2) #123.46

 

 

Mybatis如何处理

<方案1>

1.新增和更新方案:  直接手写sql进行更新

新增的话,先设置该字段为空,新增完后,走sql更新单独字段

@Update("update order set coordinate=geomfromtext(#{coordinate}) where id=#{id}") void updateCoordinateById(@Param("id") Long id, @Param("coordinate") String coordinate);

2.查看

pom.xml

        <!-- 空间几何 -->
        <dependency>
            <groupId>org.geolatte</groupId>
            <artifactId>geolatte-geom</artifactId>
            <version>1.8.2</version>
        </dependency>  

 

entity

 
 

@TableName(autoResultMap = true)
class Order {
  @ApiModelProperty(value = "GPS")
  @TableField(value = "coordinate",typeHandler = GeoPointTypeHandler.class)
  private Point coordinate;
}

 

GeoPointTypeHandler 
package com.xx.handler;

import org.geolatte.geom.ByteBuffer;
import org.geolatte.geom.Point;
import org.geolatte.geom.codec.Wkb;

import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 自定义类型转换器映射空间几何数据
 */
public class GeoPointTypeHandler extends BaseAttributeTypeHandler<Point > {


    @Override
    public Point getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
        var bytes = (byte[])resultSet.getObject(columnName);
        return this.mapPoint(bytes);
    }

    @Override
    public Point getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return (Point) resultSet.getObject(i);
    }

    @Override
    public Point getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return (Point) callableStatement.getObject(i);
    }


    /*
     * bytes转Point对象
     */
    private Point mapPoint(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        try {
            Point point =  (Point) Wkb.fromWkb(ByteBuffer.from(bytes));
            return point;
        } catch (Exception e) {

        }
        return null;
    }
}
View Code
BaseAttributeTypeHandler
package com.xx.handler;

import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.springframework.core.ResolvableType;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.lang.reflect.Type;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class BaseAttributeTypeHandler<T> extends BaseTypeHandler<Object> {

    private JavaType javaType;

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    public BaseAttributeTypeHandler() {
        ResolvableType resolvableType = ResolvableType.forClass(getClass());
        Type type = resolvableType.as(BaseAttributeTypeHandler.class).getGeneric().getType();
        javaType = constructType(type);
    }

    public static JavaType constructType(Type type) {
        Assert.notNull(type, "[Assertion failed] - type is required; it must not be null");
        return TypeFactory.defaultInstance().constructType(type);
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
            throws SQLException {
        ps.setString(i, JSONUtil.toJsonStr(parameter));
    }

    @Override
    public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String value = rs.getString(columnName);
        return convertToEntityAttribute(value);
    }


    @Override
    public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return convertToEntityAttribute(rs.getString(columnIndex));
    }


    @Override
    public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String value = cs.getString(columnIndex);
        return convertToEntityAttribute(value);
    }


    public Object convertToEntityAttribute(String dbData) {
        if (StringUtils.isEmpty(dbData)) {
            if (List.class.isAssignableFrom(javaType.getRawClass())) {
                return Collections.emptyList();
            } else if (Set.class.isAssignableFrom(javaType.getRawClass())) {
                return Collections.emptySet();
            } else if (Map.class.isAssignableFrom(javaType.getRawClass())) {
                return Collections.emptyMap();
            } else {
                return null;
            }
        }
        return toObject(dbData, javaType);
    }


    public static <T> T toObject(String json, JavaType javaType) {
        Assert.hasText(json, "[Assertion failed] - this json must have text; it must not be null, empty, or blank");
        Assert.notNull(javaType, "[Assertion failed] - javaType is required; it must not be null");
        try {
            return OBJECT_MAPPER.readValue(json, javaType);
        } catch (com.fasterxml.jackson.core.JsonParseException e) {
            throw new RuntimeException(e.getMessage(), e);
        } catch (JsonMappingException e) {
            throw new RuntimeException(e.getMessage(), e);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
}
View Code
 

 前端提交的参数

class OrderParam {
        @ApiModelProperty(value = "GPS")
        private Coordinate coordinate;
}

 Coordinate

package com.xx.entity;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.geolatte.geom.Point;
import org.geolatte.geom.codec.Wkt;
import org.geolatte.geom.crs.CoordinateSystemAxis;

@Data
@NoArgsConstructor
public class Coordinate {
    @ApiModelProperty(value = "纬度")
    private Double latitude;

    @ApiModelProperty(value = "经度")
    private Double longitude;

    public Coordinate(Double longitude, Double latitude) {
        this.latitude = latitude;
        this.longitude = longitude;
    }

    public Coordinate(Point point) {
        this.longitude = point.getPosition().getCoordinate(CoordinateSystemAxis.mkLonAxis());
        this.latitude = point.getPosition().getCoordinate(CoordinateSystemAxis.mkLatAxis());
    }


    public Point toPoint() {
        return (Point) Wkt.fromWkt(String.format("POINT(%g %g)", this.getLongitude(), this.getLatitude()));
    }

    public double distance(Coordinate other) {
        if ((this.longitude == other.getLongitude()) && (this.latitude == other.getLatitude())) {
            return 0;
        } else {
            double metersPerDegree = 2 * Math.PI * 6378137 / 360;

            double theta = this.longitude - other.getLongitude();


            double dist = Math.sin(Math.toRadians(this.latitude)) * Math.sin(Math.toRadians(other.getLatitude())) +
                    Math.cos(Math.toRadians(this.latitude)) * Math.cos(Math.toRadians(other.getLatitude())) * Math.cos(Math.toRadians(theta));
            dist = Math.acos(dist);
            dist = Math.toDegrees(dist);
            dist = dist * metersPerDegree;

            return dist;
        }
    }

}
View Code

 

<方案2>  参考https://github.com/tzjzcy/mybatis-mysql-geo-boot

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM