使用Mybatis向Mysql中的插入Point类型的数据全方位解析
1. 结果
希望每一个能够看到结果的人都能自己装载进去!加油!
2.代码
2.1TestMapper
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
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
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 测试
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配置
<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
<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.
<!-- 镜像配置-->
<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 写在最后
如果有不能解决的欢迎提问,收到信息后回及时回复。
希望每个人都能从中走出来!