请先滑到下面,看第7部分,否则走弯路。
一、数据表中有一张表,名为role_permission,DDL如下:
CREATE TABLE "public"."role_permission" (
"role_id" varchar(64) COLLATE "pg_catalog"."default" NOT NULL,
"permissions" json,
"create_time" timestamp(6) DEFAULT CURRENT_TIMESTAMP,
"update_time" timestamp(6) DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "role_permission_pkey" PRIMARY KEY ("role_id")
);
ALTER TABLE "public"."role_permission" OWNER TO "postgres";
这里可以看到是用的pg数据库;
二、定义entity中的数据表对象;
@TableName(value = "role_permission", autoResultMap = true) public class RolePermission implements Serializable { @Serial private static final long serialVersionUID = 1L; @TableId(value = "role_id", type = IdType.ASSIGN_UUID) private String roleId; @TableField(value = "permissions", typeHandler = CeGrantedAuthorityListTypeHandler.class) private List<CeGrantedAuthority> permissions; } 这里省略了创建时间和修改时间字段等,重点是要讨论permissions字段;
三、service层中保存数据;
List<CeGrantedAuthority> permissions = authorities.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
RolePermission rolePermission = new RolePermission()
.setRoleId(roleId)
.setPermissions(permissions);
this.saveOrUpdate(rolePermission);
以上写法,在mysql数据库中可以正常写入,但是在pg数据库是不行的,会报错,其实是pg数据库对json字段类型会进行强校验,所有只有自己复写saveOrUpdate方法;
四、mapper中定义接口及xml实现;
public interface RolePermissionMapper extends BaseMapper<RolePermission> { boolean saveOrUpdate(RolePermission rolePermission); } 重点是以下的xml实现,重点关注红色部分吧,我调了好久,才成功:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.fit2cloud.dao.mapper.RolePermissionMapper"> <insert id="saveOrUpdate" parameterType="com.fit2cloud.base.entity.RolePermission"> INSERT INTO "role_permission" (role_id, permissions) VALUES (#{roleId,jdbcType=VARCHAR}, to_json(#{permissions, jdbcType=VARCHAR, typeHandler=com.fit2cloud.common.utils.CeGrantedAuthorityListTypeHandler})) ON CONFLICT (role_id) DO UPDATE SET permissions = to_json(EXCLUDED.permissions); </insert> </mapper>
五、修改service中的调用
注释掉this.saveOrUpdate(rolePermission);
添加如下调用:
baseMapper.saveOrUpdate(rolePermission); 至此解决 环境:springboot3.1.0
mybatis-plus:3.5.3.1
postgsql 13.5
六、修改后带来的一些问题
mysql切pg数据库后,使用to_json会在json字符串前后加上双引号,并对其中的双引号进行转义,因此在回显时需要先处理一下,这部分也就是在CeGrantedAuthorityListTypeHandler进行修改(以下代码中红色部分就是我加的,能起作用,但是感觉不优雅,欢迎给出更好的解决方案)。
@Override
protected Object parse(String json) {
try {
if ( json.startsWith("\"") && json.endsWith("\"") ) {
json = json.substring(1, json.length() - 1);
}
json = json.replace("\\\"","\"");
JavaType javaType = getObjectMapper().getTypeFactory().constructParametricType(List.class, CeGrantedAuthority.class);
return getObjectMapper().readValue(json, javaType);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
七、以上的工作都是徒劳,其实改个配置就好了
jdbc:postgresql://{ip:port}/database?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false&stringtype=unspecified
加上 stringtype=unspecified 这个参数,根本就不再需要to_json这样繁琐的操作了,反向解析也省了。
没办法,刚写不到3周java,肯定是要走弯路的。。。