SpringBoot+Mybatis Plus+PostGIS踩坑

LHabc 发布于 2024-09-06


初次尝试使用Java来写Web API,选用了一些经典的Java框架。为满足定位服务相关功能,数据库上依然使用PostgreSQL+PostGIS这一经典组合。在配置PostGIS的JDBC驱动和ORM时遇到了一些坑,特此记录。

基础项目

首先搭建SpringBoot+Mybatis Plus+PostgreSQL项目,在服务器上建好相关数据库和Role,这一步教程充足,过程顺利,此处略过不提。

我使用application.properties文件配置参数,数据库配置大概如下:

spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://域名:端口/数据库
spring.datasource.username=数据库Role
spring.datasource.password=密码
spring.sql.init.mode=always
spring.sql.init.schema-locations=classpath:db/schema.sql
spring.sql.init.data-locations=classpath:db/data.sql
mybatis-plus.global-config.db-config.schema=public

注意,mybatis-plus.global-config.db-config.schema=public非常重要,某些特殊名称的表,如user,只有在加了这句话之后ORM才能正确运行。

schema.sql和data.sql与mybatis-plus官方示例类似,需要放在resources/db下面,内容如下所示:

DROP TABLE IF EXISTS "user";

CREATE TABLE "user"
(
    id    SERIAL4   PRIMARY KEY,
    name  VARCHAR   NULL DEFAULT NULL,
    age   INT4      NULL DEFAULT NULL,
    email VARCHAR   NULL DEFAULT NULL
);
DELETE FROM "user";

INSERT INTO "user" (id, name, age, email)
VALUES (1, 'Jone', 18, '[email protected]'),
       (2, 'Jack', 20, '[email protected]'),
       (3, 'Tom', 28, '[email protected]'),
       (4, 'Sandy', 21, '[email protected]'),
       (5, 'Billie', 24, '[email protected]');

测试使用的User类如下:

import lombok.Data;

@Data
public class User {
    private Integer id;
    private String name;
    private Integer age;
    private String email;
}

UserMapper类如下:

import centerc.music.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

public interface UserMapper extends BaseMapper<User> {

}

测试代码如下:

@Autowired
private UserMapper userMapper;

@Test
public void testSelect() {
    System.out.println(("----- selectAll method test ------"));
    List<User> userList = userMapper.selectList(null);
    Assert.isTrue(5 == userList.size(), "");
    userList.forEach(System.out::println);
}

通过测试则说明已经成功连接到数据库,角色权限和ORM配置都正确,下面开始配置PostGIS扩展功能。

数据库配置

首先在服务器安装PostGIS。以Ubuntu 22.04为例,运行以下命令:

sudo apt install postgis

安装成功后,以具有superuser权限的Role登录PostgreSQL,使用\c database 命令使用数据库,并执行以下语句启用扩展:

CREATE EXTENSION postgis;

扩展会自动在数据库下建立spatial_ref_sys表。至此数据库端配置完成。

Java配置

Java端配置PostGIS的教程比较少,而且普遍过时。经过一下午的探索与尝试,发现postgis-java值得一试。

首先,需要下载该库最新的release代码并使用mvn package命令构建Jar包。构建过程中遇到git-commit-id-plugin插件报错。修改postgis-java/pom.xml,将

<plugin>
    <groupId>pl.project13.maven</groupId>
    <artifactId>git-commit-id-plugin</artifactId>
    <version>${git-commit-id-plugin.version}</version>
...
</plugin>

改为

<plugin>
    <groupId>pl.project13.maven</groupId>
    <artifactId>git-commit-id-plugin</artifactId>
    <version>${git-commit-id-plugin.version}</version>
    <configuration>
        <failOnNoGitDirectory>false</failOnNoGitDirectory>
    </configuration>
...
</plugin>

即可。

点击此处下载构建好的Jar包(2024.1.0版本)和一会儿会用到的TypeHandler文件。

将构建好的四个Jar包放在resources/lib下,修改我们项目的pom.xml,添加如下本地依赖:

<dependency>
    <groupId>net.postgis</groupId>
    <artifactId>postgis-jdbc</artifactId>
    <version>2024.1.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/src/main/resources/lib/postgis-jdbc-2024.1.0.jar</systemPath>
</dependency>
<dependency>
    <groupId>net.postgis</groupId>
    <artifactId>postgis-geometry</artifactId>
    <version>2024.1.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/src/main/resources/lib/postgis-geometry-2024.1.0.jar</systemPath>
</dependency>
<dependency>
    <groupId>net.postgis</groupId>
    <artifactId>postgis-jdbc-java2d</artifactId>
    <version>2024.1.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/src/main/resources/lib/postgis-jdbc-java2d-2024.1.0.jar</systemPath>
</dependency>
<dependency>
    <groupId>net.postgis</groupId>
    <artifactId>postgis-jdbc-jts</artifactId>
    <version>2024.1.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/src/main/resources/lib/postgis-jdbc-jts-2024.1.0.jar</systemPath>
</dependency>

将TypeHandler放在项目路径下,并记好该包的位置。

修改application.properties 中的spring.datasource.driver-class-name和spring.datasource.url,添加mybatis-plus.type-handlers-package,修改后如下所示:

spring.datasource.driver-class-name=net.postgis.jdbc.DriverWrapper
spring.datasource.url=jdbc:postgresql_postGIS://域名:端口/数据库
spring.datasource.username=数据库Role
spring.datasource.password=密码
spring.sql.init.mode=always
spring.sql.init.schema-locations=classpath:db/schema.sql
# spring.sql.init.data-locations=classpath:db/data.sql 一会儿测试时使用Mybatis Plus填充数据
mybatis-plus.global-config.db-config.schema=public
mybatis-plus.type-handlers-package=xxx.typehandler

测试

接下来,我们删除在最开始建立的user表,修改User类和测试函数以验证配置是否正确。

schema.sql:

DROP TABLE IF EXISTS "user";

CREATE TABLE "user"
(
    id    SERIAL4               PRIMARY KEY,
    name  VARCHAR               NULL DEFAULT NULL,
    age   INT4                  NULL DEFAULT NULL,
    email VARCHAR               NULL DEFAULT NULL,
    geom  GEOMETRY(POINT, 4326) NULL DEFAULT NULL
);

User类:

import lombok.Data;
import net.postgis.jdbc.geometry.Point;

@Data
public class User {
    private Integer id;
    private String name;
    private Integer age;
    private String email;
    private Point geom;
}

net.postgis.jdbc.geometry.Point会映射到PostGIS中的GEOMETRY(POINT)类型。

测试代码:

@Autowired
private UserMapper userMapper;

@Test
@Transactional
public void testPostGIS() {
    System.out.println(("----- testPostgis method test ------"));
    User user = new User();
    user.setAge(18);
    user.setEmail("lhabc@test");
    user.setName("test");
    user.setGeom(new Point(1, 1));
    userMapper.insert(user);

    user.setName("LHabc");
    userMapper.updateById(user);

    List<User> userList = userMapper.selectList(null);
    Assert.isTrue(userList.size() == 1, "");
    userList.forEach(System.out::println);

    userMapper.deleteById(user.getId());
    userList = userMapper.selectList(null);
    Assert.isTrue(userList.isEmpty(), "");
}

无报错且输出User(id=1674174465, name=LHabc, age=18, [email protected], geom=SRID=4326;POINT(1 1)),说明一切顺利。