Java 定义类型处理MySQL point类型数据

1.三个类来处理

引入maven依赖

        <!-- 引入 jts 库解析 POINT -->
        <dependency>
            <groupId>com.vividsolutions</groupId>
            <artifactId>jts</artifactId>
            <version>1.13</version>
        </dependency>

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import java.io.Serializable;

/**
 *  经纬度对象
 * <br>
 *  x 经度 lon 浮点数,范围为180 ~ -180 <br>
 *  y 纬度 lat 浮点数,范围为90 ~ -90
 */
public class GeoPoint implements Serializable {

    /**
     * 参数校验
     *  在lon、lat 字段添加@Min @Max 注解,并且在使用该类的地方加 @Valid 注解
     *  如:
     *   @Valid
     *   private GeoPoint lonlat;
     */

    // controller @RequestBody 参数内嵌套对象,必须有一个无参的构造函数
    public GeoPoint() {}
    /**
     * 经度
     */
    @Min(value = -180, message = "经度lon不能小于-180")
    @Max(value = 180, message = "经度lon不能大于180")
    private double lon;
    /**
     * 纬度
     */
    @Min(value = -90, message = "纬度lat不能小于-90")
    @Max(value = 90, message = "纬度lat不能大于90")
    private double lat;

    /**
     *
     * @param x 经度 lon 浮点数,范围为180 ~ -180
     * @param y 纬度 lat 浮点数,范围为90 ~ -90
     */
    public GeoPoint(double x, double y) {
        this.lon = x;
        this.lat = y;
    }

    public double getLon() {
        return lon;
    }

    public void setLon(double lon) {
        this.lon = lon;
    }

    public double getLat() {
        return lat;
    }

    public void setLat(double lat) {
        this.lat = lat;
    }


    @Override
    public String toString() {
        return "GeoPoint{" +
                "lon=" + lon +
                ", lat=" + lat +
                '}';
    }

}

import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;
import com.vividsolutions.jts.geom.impl.CoordinateArraySequenceFactory;
import com.vividsolutions.jts.io.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class GeoPointConverter {
    /**
     * Little endian or Big endian
     */
    private int byteOrder = ByteOrderValues.LITTLE_ENDIAN;
    /**
     * Precision model
     */
    private PrecisionModel precisionModel = new PrecisionModel();
    /**
     * Coordinate sequence factory
     */
    private CoordinateSequenceFactory coordinateSequenceFactory = CoordinateArraySequenceFactory.instance();
    /**
     * Output dimension
     */
    private int outputDimension = 2;
    /**
     * Convert byte array containing SRID + WKB Geometry into Geometry object
     */
    public GeoPoint from(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
            // Read SRID
            byte[] sridBytes = new byte[4];
            inputStream.read(sridBytes);
            int srid = ByteOrderValues.getInt(sridBytes, byteOrder);
            // Prepare Geometry factory
            GeometryFactory geometryFactory = new GeometryFactory(precisionModel, srid, coordinateSequenceFactory);
            // Read Geometry
            WKBReader wkbReader = new WKBReader(geometryFactory);
            Geometry geometry = wkbReader.read(new InputStreamInStream(inputStream));
            Point point = (Point) geometry;
            // convert to GeoPoint
            GeoPoint geoPoint = new GeoPoint(point.getX(), point.getY());
            return geoPoint;
        } catch (IOException | ParseException e) {
            throw new IllegalArgumentException(e);
        }
    }
    /**
     * Convert Geometry object into byte array containing SRID + WKB Geometry
     */
    public byte[] to(GeoPoint geoPoint) {
        if (geoPoint == null) {
            return null;
        }
        //  @param x 经度 lon
        //  @param y 纬度 lat
        Coordinate coordinate = new Coordinate(geoPoint.getLon(), geoPoint.getLat());
        CoordinateArraySequence coordinateArraySequence = new CoordinateArraySequence(new Coordinate[]{coordinate}, 2);
        Point point = new Point(coordinateArraySequence, new GeometryFactory());
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            // Write SRID
            byte[] sridBytes = new byte[4];
            ByteOrderValues.putInt(point.getSRID(), sridBytes, byteOrder);
            outputStream.write(sridBytes);
            // Write Geometry
            WKBWriter wkbWriter = new WKBWriter(outputDimension, byteOrder);
            wkbWriter.write(point, new OutputStreamOutStream(outputStream));
            return outputStream.toByteArray();
        } catch (IOException ioe) {
            throw new IllegalArgumentException(ioe);
        }
    }
}

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.springframework.stereotype.Component;

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

@Component //注入Bean,全局配置使其自动转换,不需要在sql层手动指定
@MappedJdbcTypes(JdbcType.OTHER) // JdbcType只能用OTHER类型,没有point类型
@MappedTypes(GeoPoint.class) 
public class GeoPointTypeHandler extends BaseTypeHandler<GeoPoint> {
    GeoPointConverter converter = new GeoPointConverter();
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, GeoPoint parameter, JdbcType jdbcType) throws SQLException {
        ps.setBytes(i, converter.to(parameter));
    }
    @Override
    public GeoPoint getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return converter.from(rs.getBytes(columnName));
    }
    @Override
    public GeoPoint getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return converter.from(rs.getBytes(columnIndex));
    }
    @Override
    public GeoPoint getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return converter.from(cs.getBytes(columnIndex));
    }
}

2.使用

model中使用 


public class PositionInfo implements Serializable
{
    private static final long serialVersionUID = 1L;

    /** 经纬度 */
    @Valid //接口中使用 @Valid 对参数 PositionInfo 进行校验,需要在这里也加@Valid 注解
    private GeoPoint lonlat;


//....
}

controller

@Validated
@RestController
@RequestMapping("/positioninfo")
public class PositionInfoController
{
    @Autowired
    private PositionInfoService positionInfoService;


    /**
     * 新增地理位置信息
     */
    @PostMapping
    public Result addPositionInfo( @RequestBody @Valid PositionInfo positionInfo)
    {
        System.err.println(positionInfo);
        return reult(positionInfoService.insertPositionInfo(positionInfo));
    }

DAO


    @Select("select * from position_info_table")
//    @Results(
//        @Result(column = "lonlat",property = "lonlat",
//                javaType = GeoPoint.class,typeHandler = GeoPointTypeHandler.class)
//    )
     List<PositionInfo> listPositionInfo(PositionInfo positionInfo);



    @Insert("insert into position_info_table (lonlat) values (#{p.lonlat})" )
    int insertPositionInfo(@Param("p") PositionInfo positionInfo);

测试

--------


# 无效,解决:在GeoPointTypeHandler 使用 @Component
#配置point解析工具GeoPointTypeHandler,使其自动转换,不需要在sql层手动指定
#mybatis:
#    type-handlers-package:com.jeaglo.auxpolice.tools

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/648964.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

推送邮件接口设置的方法?邮件接口的作用?

推送邮件接口如何与现有系统集成&#xff1f;怎么调试邮件接口&#xff1f; 通过推送邮件接口&#xff0c;应用程序可以自动向用户发送邮件通知&#xff0c;提醒他们重要事件或更新。AokSend将介绍如何设置推送邮件接口&#xff0c;以便您的应用程序能够充分利用这一功能。 推…

和为k的子数组 ---- 前缀和

题目链接 题目: 分析: 思考: 此题能否用滑动窗口来解决? 滑动窗口的适用前提是具有单调性, left和right指针是不回退的, 此题中数组有负数和零, 很难保证指针不回退, 所以不能用滑动窗口利用前缀和的思想, 计算以i结尾的所有子数组, 前缀和为sum[i] 想要找到和为k的数组, 我…

基于图鸟UI的圈子商圈:一个全栈前端模板的探索与应用

摘要&#xff1a; 本文介绍了一个基于图鸟UI的纯前端模板——圈子商圈&#xff0c;它支持微信小程序、APP和H5等多平台开发。该模板不仅包含丰富的UI组件和页面模板&#xff0c;还提供了详尽的使用文档&#xff0c;旨在帮助开发者快速构建出酷炫且功能齐全的前端应用。本文将从…

让WSL内核使用BBR拥塞控制算法

使用git命令从Linux内核的Git仓库中获取源代码,$ git clone https://github.com/microsoft/WSL2-Linux-Kernel.git,找到对应的内核版本$ git log --grep="5.15.146.1-microsoft-standard-WSL2",回退到本机安装的内核版本$ git checkout <commit-id> ee5b8e3…

在 Rocky 9 上编译 MySQL 8.2.0 Debug 版本编译指南

↑ 关注“少安事务所”公众号&#xff0c;欢迎⭐收藏&#xff0c;不错过精彩内容~ unsetunset前情提要unsetunset 前文已经介绍了如何安装 Rocky Linux 9.2&#xff0c;这里便不再赘述。 同时&#xff0c;也已经介绍过 MySQL 8.2.0 的参数变化&#xff0c;以及提及如何安装 MyS…

力扣:236.二叉树的最近公共祖先(C++)

文章目录 1. 题目描述2. 题目解析2.1 思路一2.1 思路二 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 题目来源: 力扣…二叉树的最近公共祖先 1. 题目描述 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表…

代码随想录算法训练营第四十一天 | 理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

理论基础 代码随想录 视频&#xff1a;从此再也不怕动态规划了&#xff0c;动态规划解题方法论大曝光 &#xff01;| 理论基础 |力扣刷题总结| 动态规划入门_哔哩哔哩_bilibili 动归五部曲 1.dp数组以及下标的含义 2.递推公式 3.dp数组如何初始化 4.遍历顺序(例如先背包再…

ue的event dispatch.操作步骤,最详细了

功能&#xff1a;按下键盘1&#xff0c;send方监控键盘事件&#xff0c;recv方打印success Dispatch 间接通信 示例&#xff1a;1.发送方按下键盘1。2.接收方打印success 蓝图很简单&#xff1a; 发送方 接收方 具体操作步骤如下&#xff1a; 1.场景发送方运行监听键盘 2.接受…

Seurat Dimplot函数学习总结

今天为了画这个cluster中怎么显示标签的图&#xff0c;研究了一个Seurat中怎么画这个图的&#xff0c;下面是学习过程中做的总结 运行例子 rm(listls()) library(Seurat) library(SeuratData) library(ggplot2) library(patchwork) pbmc3k.final <- LoadData("pbmc3k…

学浪的缓存怎么导出来

学浪的缓存导出问题困扰着许多用户&#xff0c;备份和管理数据变得至关重要。在数字化时代&#xff0c;保护和利用数据是企业和个人不可或缺的需求。在这篇文章中&#xff0c;我们将深入探讨学浪缓存导出的方法&#xff0c;为您解决疑惑&#xff0c;让您轻松掌握数据的安全与便…

自定义类型详解(结构体,位段,枚举,联合体)

目录 结构体 结构体的自引用 匿名结构体 结构体内存对齐 结构体内存对齐的意义 修改默认对齐数 位段 位段的内存分配 位段的跨平台问题 位段的应用 枚举 枚举类型的定义 枚举和#define的区别 联合体&#xff08;共用体&#xff09; 联合体大小的计算 结构体 C语…

斐讯N1刷OpenWRT并安装内网穿透服务实现远程管理旁路由

文章目录 前言1. 制作刷机固件U盘1.1 制作刷机U盘需要准备以下软件&#xff1a;1.2 制作步骤 2. N1盒子降级与U盘启动2.1 N1盒子降级2.2 N1盒子U盘启动设置2.3 使用U盘刷入OpenWRT2.4 OpenWRT后台IP地址修改2.5 设置旁路由&无线上网 3. 安装cpolar内网穿透3.1 下载公钥3.2 …

08Django项目--用户管理系统--查(前后端)

对应视频链接点击直达 TOC 一些朋友加我Q反馈&#xff0c;希望有每个阶段的完整项目代码&#xff0c;那从今天开始&#xff0c;我会上传完整的项目代码。 用户管理&#xff0c;简而言之就是用户的增删改查。 08项目点击下载&#xff0c;可直接运行&#xff08;含数据库&…

3个完美恢复方案!苹果手机恢复视频就是这么简单

在日常生活中&#xff0c;我们使用苹果手机记录了许多珍贵的视频&#xff0c;包括家庭聚会、旅行经历等。但是我们不小心删除了&#xff0c;在“最近删除”文件夹中也找不到。 别担心&#xff0c;这并不困难&#xff01;无论您是意外删除了重要的视频还是遇到了其他数据丢失问…

PawSQL: 企业级SQL审核工具的新玩家

随着数据库应用在企业中的广泛使用&#xff0c;确保SQL代码质量的重要性日益凸显。现有的SQL审核工具很多&#xff0c;包括Yearning、goInception、Bytebase、爱可生的SQLE、云和恩墨的SQM等等&#xff0c;但是它们或者规则覆盖度、或者是在正确率等方面存在明显不足&#xff1…

【stm32】江科协听课笔记

[3-1] GPIO输出_哔哩哔哩_bilibili 5.GPIO输出 这里&#xff0c;寄存器就是一段特殊的存储器&#xff0c;内核可以通过APB2总线队寄存器进行读写&#xff0c;这样就可以完成输出/读取电平的功能。寄存器的每一位对应一个引脚&#xff0c;stm32是32位的&#xff0c;这里的寄存器…

K8S有了Service,为什么还要Ingress?

1、有了Service为什么还要Ingress? NodePort对外暴露端口存在的不足&#xff1a; 一个端口只能一个服务使用, 端口需要提前规划。 随着业务扩展, 端口的管理将是一个头疼的问题 只支持4层的负载均衡 LoadBalancer存在的不足&#xff1a; 贵、贵、贵。 要上云(俗话说上云…

前端Vue自定义顶部搜索框:实现热门搜索与历史搜索功能

前端Vue自定义顶部搜索框&#xff1a;实现热门搜索与历史搜索功能 摘要&#xff1a; 随着前端开发复杂性的增加&#xff0c;组件化开发成为了提高效率和降低维护成本的有效手段。本文介绍了一个基于Vue的前端自定义顶部搜索框组件&#xff0c;该组件不仅具备基本的搜索功能&am…

Android端 可使用Yolov5训练 路标识别

相信大家对于路标识别&#xff0c;红绿灯识别&#xff0c;图形识别opencv中也是一件烦人的事情&#xff0c;其参数是及其受到现实环境因素的影响的&#xff0c;那么今天我就给大家推荐一种方式&#xff0c;缺点是周期长&#xff0c;但其优点是如果训练效果好久对于环境的各种变…

安卓开发日志采集和分析面面谈

日志面面谈 为什么需要日志 复现问题&#xff0c;回溯到问题产生时候的系统状态&#xff0c;有利于定位和分析问题。 安卓日志有哪些&#xff1f; cpu 关注的纬度&#xff1a; 单个应用使用系统cpu分配温度 有什么用&#xff1a; App卡顿、ANRApp异常退出 怎么用&…