使用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 写在最后

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

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

相关推荐
夜泉_ly1 小时前
MySQL -安装与初识
数据库·mysql
qq_529835352 小时前
对计算机中缓存的理解和使用Redis作为缓存
数据库·redis·缓存
月光水岸New5 小时前
Ubuntu 中建的mysql数据库使用Navicat for MySQL连接不上
数据库·mysql·ubuntu
狄加山6755 小时前
数据库基础1
数据库
我爱松子鱼5 小时前
mysql之规则优化器RBO
数据库·mysql
chengooooooo5 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
Rverdoser6 小时前
【SQL】多表查询案例
数据库·sql
Galeoto6 小时前
how to export a table in sqlite, and import into another
数据库·sqlite
人间打气筒(Ada)7 小时前
MySQL主从架构
服务器·数据库·mysql
leegong231117 小时前
学习PostgreSQL专家认证
数据库·学习·postgresql