使用Mybatis向Mysql中的插入Point类型的数据全方位解析

1. 结果

希望每一个能够看到结果的人都能自己装载进去!加油!

2.代码

2.1TestMapper

java 复制代码
import org.apache.ibatis.annotations.*;
import java.util.Date;
import java.util.List;

/**
 * @author Administrator
 */
@Mapper
public interface TestMapper {
    /**
     * 更新名字 测试更新数据库
     *
     * @param id
     * @param name
     */
    @Update("UPDATE test SET name = #{name} WHERE id = #{id}")
    void updateNameByid(long id, String name);
    /**
     * 插入数据2 用纯sql语句插入
     * MyBatis 在处理 ST_GeomFromText 函数时,会将 #{lng} 和 #{lat} 视为一个整体,导致参数索引超出范围
     *        正确的语法  CONCAT('POINT(', #{lng}, ' ', #{lat}, ')')
     *        错误的语法: POINT(#{lng} #{lat})
     * @param name
     * @param lat
     * @param lng
     * @param date2
     */
    @Insert("INSERT INTO Test (name, location, create_time) VALUES ( #{name}, ST_GeomFromText(CONCAT('POINT(', #{lng}, ' ', #{lat}, ')')), #{date2})")
    void insertTest2(@Param("name") String name, @Param("lng") double lng, @Param("lat") double lat, @Param("date2") String date2);
    /**
     * 用GeoPoint对象插入数据 需使用GeoPointHandler
     * @param name
     * @param location
     * @param date2
     */
    @Insert("INSERT INTO Test (name, location, create_time) VALUES (#{name}, ST_GeomFromText(#{location}), #{date2})")
    void insertTest3(@Param("name") String name, @Param("location") GeoPoint location, @Param("date2") String date2);


}

2.2 GeoPoint

java 复制代码
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

import java.io.Serializable;
/**
 * @author Administrator
 */
@Builder
@AllArgsConstructor
@Data
public class GeoPoint implements Serializable {
    /**
     * 经度
     */
    private Double longitude;
    /**
     * 纬度
     */
    private Double latitude;

      @Override
    public String toString() {
    //重点,这个函数会影响输出到最终的sql语句,所以中间和mysql保持一致为空格。
        return "POINT(" + longitude + " " + latitude + ")";
    }
}

2.3处理坐标点转换 GeoPointTypeHandler

java 复制代码
import com.zjs.fish.entity.GeoPoint;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;

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

/**
 * @author Administrator
 */
@MappedTypes(GeoPoint.class)
public class GeoPointTypeHandler extends BaseTypeHandler<GeoPoint> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, GeoPoint parameter, JdbcType jdbcType) throws SQLException {
//           System.out.println("执行了setNonNullParameter");
        ps.setString(i, parameter.toString());
    }

    @Override
    public GeoPoint getNullableResult(ResultSet rs, String columnName) throws SQLException {
        System.out.println("执行了getNullableResult");
        String wkt = rs.getString(columnName);
        if (wkt == null) {
            return null;
        }
        String[] parts = wkt.replace("POINT(", "").replace(")", "").split(" ");
        double longitude = Double.parseDouble(parts[0]);
        double latitude = Double.parseDouble(parts[1]);
        return new GeoPoint(longitude, latitude);
    }

    @Override
    public GeoPoint getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        System.out.println("执行了getNullableResult");
        String wkt = rs.getString(columnIndex);
        if (wkt == null) {
            return null;
        }
        String[] parts = wkt.replace("POINT(", "").replace(")", "").split(" ");
        double longitude = Double.parseDouble(parts[0]);
        double latitude = Double.parseDouble(parts[1]);
        return new GeoPoint(longitude, latitude);
    }

    @Override
    public GeoPoint getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
          System.out.println("执行了getNullableResult");
        String wkt = cs.getString(columnIndex);
        if (wkt == null) {
            return null;
        }
        String[] parts = wkt.replace("POINT(", "").replace(")", "").split(" ");
        double longitude = Double.parseDouble(parts[0]);
        double latitude = Double.parseDouble(parts[1]);
        return new GeoPoint(longitude, latitude);
    }
}

2.4 测试

java 复制代码
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.io.InputStream;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;

public class MyBatisDemo {
    private SqlSession sqlSession;
    private TestMapper testMapper;
    @Before
    public void setUp() throws Exception {
        try {
            //1.配置
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //2. 获取sqlSession对象,用它来时执行sql
            sqlSession = sqlSessionFactory.openSession();
            testMapper = sqlSession.getMapper(TestMapper.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @After
    public void tearDown() throws Exception {
        if (sqlSession != null) {
            sqlSession.close();
        }
    }

    @org.junit.Test
    public void updateNameTest() {
        System.out.println("updateNameTest");
        testMapper.updateNameByid(1, "小王八");
        sqlSession.commit();
    }

    @org.junit.Test
    public void insertTest2() {
        System.out.println("insertTest2");
        String name = "赵9";
        double lng = 121.7128;
        double lat = 32.6895;
        //插入时间类型
        Date date = new Date();
        //这个是日期的常量,我写在GlobalConst,自己根据情况配置 public DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String date2 = GlobalConst.formatter.format(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
        testMapper.insertTest2(name, lng, lat, date2);
        sqlSession.commit();
    }

    @org.junit.Test
    public void insertTest3() {
        System.out.println("insertTest3");
        String name = "赵9";
        double lng = 121.7128;
        double lat = 32.6895;
        Date date = new Date();
//同上
        String date2 = GlobalConst.formatter.format(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());

        GeoPoint location = new GeoPoint(lng, lat);
//        System.out.println(location.toString());
        testMapper.insertTest3(name, location, date2);
        sqlSession.commit();
    }
}

3. 解析

3.1 mybatis配置

xml 复制代码
<configuration>
    <settings>
    <!--        打开日志-->
         <setting name="logImpl" value="SLF4J"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="useGeneratedKeys" value="true"/>
<!--        <setting name="useLegacyDatetimeCode" value="false"/>-->
    </settings>
<!-- 根据自己的路径进行调整-->
    <typeHandlers>
        <typeHandler javaType="com.xxx.xxx.entity.GeoPoint" jdbcType="VARCHAR"
                     handler="com.xxx.xxx.typehandlers.GeoPointTypeHandler"/>
    </typeHandlers>
    <!--   环境变量 -->
    <environments default="development">
     .......//这个就不做说明了。
    </environments>
<!--对应自己的mapper文件,这里使用的事注解的mapper所以没有xml文件,也不用对应找xml -->
    <mappers>
        <package name="com.xxx.xxx.mapper"/>
    </mappers>
</configuration>

3.2 pom引入

缺什么自己找吧,环境是Springboot2.7.15 java1.8 maven 3.6

maven 复制代码
<dependencies>

        <!-- Spring Boot Starter Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

          <!-- MyBatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.3.6</version>
        </dependency>
        <!-- Spring Boot Starter Tomcat -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>

        <!-- Servlet API -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- JSTL -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <!-- 测试插件 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <!-- Gson 插件 -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.9.1</version>
        </dependency>

        <!-- 数据库连接插件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--        数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <!-- 添加 JUnit Jupiter 和 Spring Boot Test 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- lombok   -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version> <!-- 请使用最新版本 -->
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>6.3.4</version>
        </dependency>

<!--     几何信息   -->
        <dependency>
            <groupId>org.locationtech.jts</groupId>
            <artifactId>jts-core</artifactId>
            <version>1.19.0</version>
        </dependency>
        
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.14</version>
        </dependency>
            <!-- MyBatis Plus Starter for Spring Boot -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
    </dependencies>

3.3流程解析

| 所有的转移最终都还是要通过sql语句到Mysql数据库的过程,只是因为不同的平台之间显示的GPS数据的写法不同会造成需要不同的接口来进行适配。所以一开始就不要把问题想想的很复杂。

如果环境报错,就尽量用一致的环境,这里适配到java1.8也是希望能够最大程度的兼容.

最后这个Mapper+sql语句的方式简化了编写的逻辑,但增减了新手的理解能力。作为前端Android开发的我也花了三天才适应,不知道你们能否适应。

4. 填坑

4.1 插件问题,

所有的pom插件都能够在阿里云找到,如果不能找到最好不要使用,

阿里云仓库地址:

https://developer.aliyun.com/mvn/search  

如果粘贴进pom报错,可以clean一下project.

xml 复制代码
<!-- 镜像配置-->
<mirrors>
    <mirror>
        <id>alimaven</id>
        <name>aliyun maven</name>
        <url>https://maven.aliyun.com/repository/public</url>
        <mirrorOf>*</mirrorOf>
    </mirror>
</mirrors>

4.2 Mysql几何类型

ST_GeomFromText 做sql的标配,他其实是在数据库层面转写的一个函数,用于将坐标点转换成一个集合对象,存储在数据库中。因为这个几何数据作为数学基础的大类,被分割出来就是为了更好的去为相关的应用做配套,所以一定要对这写做一个了结。

他的参数就一个,字符串,但是又一定的标准 前面Point就是点类型,后面接着就是点坐标,当然还有面,线,集合等等类型,注意括号的层次即可。

@Override

public String toString() {

return "POINT(" + longitude + " " + latitude + ")";

}

重写GeoPoint中的点坐标结构,已达到插入数据库的标准,这是我遇到的重点问题。网上真的是搜索了一大圈,AI也问了1天多。真的是不出个所以然来。如果对项目结构没有自己的认知,很容易被整的头晕脑胀。

4.3 写在最后

如果有不能解决的欢迎提问,收到信息后回及时回复。

希望每个人都能从中走出来!

相关推荐
工业甲酰苯胺2 小时前
Redis性能优化的18招
数据库·redis·性能优化
没书读了3 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
jokerest1233 小时前
web——sqliabs靶场——第十三关——报错注入+布尔盲注
mybatis
i道i3 小时前
MySQL win安装 和 pymysql使用示例
数据库·mysql
小怪兽ysl3 小时前
【PostgreSQL使用pg_filedump工具解析数据文件以恢复数据】
数据库·postgresql
武子康3 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
wqq_9922502774 小时前
springboot基于微信小程序的食堂预约点餐系统
数据库·微信小程序·小程序
爱上口袋的天空4 小时前
09 - Clickhouse的SQL操作
数据库·sql·clickhouse
Oak Zhang5 小时前
sharding-jdbc自定义分片算法,表对应关系存储在mysql中,缓存到redis或者本地
redis·mysql·缓存
聂 可 以5 小时前
Windows环境安装MongoDB
数据库·mongodb