springboot——typeHandler的使用

  1. 使用场景

typeHandler,类型转换器,就是将数据库中的类型与Java中的类型进行相互转换的处理器。

有时候,我们进行存储时的字段类型和数据库最终存储的字段类型是不一致的:比如我们在springboot传入的是一个list,而在数据库中需要以VARCHAR类型保存;又比如我们在springboot传入一个JSON类型,而数据库中以String类型存储该字段;或者说数据库中是JSON类型,但java无找不到对应的JSON类型(直接使用JSONObject会报错),也可以使用typeHandler。

一般情况,我们可以强转String再存储该字段,但有时候查询数据时会出现问题:较为典型的是String类型的JSON串数据,以String类型返回至前端时,会由于进行两次json解析,导致返回结果反斜杆:

而这会导致前端解析时出错,所以我们需要用typeHandler对其进行转换:

简而言之,typeHandler就是当springboot后端实体类中字段类型和数据库中字段类型不一致时进行使用。

2. mybatis下使用typeHandler

首先,我们需要编写一个typeHandler(以JSON转VARCHAR为例):

@MappedTypes(JSONObject.class)
@MappedJdbcTypes(JdbcType.LONGVARCHAR)
public class JsonObjectTypeHandler extends BaseTypeHandler<JSONObject> {

    /**
     * 插入数据时,将JSONObject转String
     * @param ps
     * @param i
     * @param parameter
     * @param jdbcType
     * @throws SQLException
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, JSONObject parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, JSONObject.toJSONString(parameter));
    }

    /**
     * 根据列名,获取可以为空的结果
     * @param rs
     * @param columnName
     * @return
     * @throws SQLException
     */
    @Override
    public JSONObject getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String sqlJson = rs.getString(columnName);
        if (null != sqlJson){
            return JSONObject.parseObject(sqlJson);
        }
        return null;
    }

    /**
     * 根据列索引,获取可以为空的结果
     * @param rs
     * @param columnIndex
     * @return
     * @throws SQLException
     */
    @Override
    public JSONObject getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String sqlJson = rs.getString(columnIndex);
        if (null != sqlJson){
            return JSONObject.parseObject(sqlJson);
        }
        return null;
    }

    @Override
    public JSONObject getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String sqlJson = cs.getString(columnIndex);
        if (null != sqlJson){
            return JSONObject.parseObject(sqlJson);
        }
        return null;
    }
}

注意,该typeHandler需要放在mapper文件夹下(即和mapper类放在一起,否则会找不到)

然后,在mapper.xml文件中,编写resultmap映射字段,并指定哪些字段需要使用typeHandler:

<!--字段映射,将数据库中String类型的json串映射为JSONObject,避免返回前段时两次序列化使得返回结果带反斜杠-->
    <resultMap id="illnessMap" type="com.seven.springcloud.dto.IllnessDTO">
        <result column="Weight" property="Weight" javaType="com.alibaba.fastjson.JSONObject" jdbcType="VARCHAR"
                typeHandler="com.seven.springcloud.mapper.JsonObjectTypeHandler"/>
        <result column="Add_date" property="Drug_Date"/>
    </resultMap>
    <!--查询所有病人的信息-->
    <select id="selectUserIllness" resultMap="illnessMap">
        select * from user_illness where Account=#{Account}
    </select>

然后,实体类中,将字段类型设为JSONObject:

@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_EMPTY)     //空值不返回
public class IllnessDTO implements Serializable {
    private JSONObject Weight;
    private String Drug_Date;
}

然后,就可以成功映射数据啦。

查看数据库,保存的是一个String类型的JSON串:

3. mybatis plus下使用typeHandler

使用mybatis plus时,我们也可以使用mybatis的方式,xml文件中编写resultMap的形式映射字段;也可以选择以mybatis plus的注解的形式使用。

首先,我们仍然需要编写一个typeHandler类:

@MappedJdbcTypes(JdbcType.VARCHAR)  //数据库类型
@MappedTypes({JSONObject.class})          //java数据类型
public class JsonTypeHandler implements TypeHandler<JSONObject> {
    @Override
    public void setParameter(PreparedStatement ps, int i, JSONObject parameter, JdbcType jdbcType) throws SQLException {
        if (parameter!=null){
            ps.setString(i, JSONObject.toJSONString(parameter));
        }

    }

    @Override
    public JSONObject getResult(ResultSet rs, String columnName) throws SQLException {
        return JSONObject.parseObject(rs.getString(columnName));
    }

    @Override
    public JSONObject getResult(ResultSet rs, int columnIndex) throws SQLException {
        return JSONObject.parseObject(rs.getString(columnIndex));
    }

    @Override
    public JSONObject getResult(CallableStatement cs, int columnIndex) throws SQLException {
        return JSONObject.parseObject(cs.getString(columnIndex));
    }
}

注:我们需要再application.yml文件中指定该typeHandler所在的包的位置,否则会找不到:

mybatis-plus:
  type-handlers-package: com.seven.demo.typerHandler

然后,我们在实体类进行配置即可:

@TableName(value ="student",autoResultMap = true)    //autoResultMap为true才会自动配置resultMap映射字段
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Serializable {

    @TableId
    private Long id;

    private String name;

    @TableField(value = "grade", typeHandler = JsonTypeHandler.class)    //指定typeHandler进行转换类型
    private JSONObject grade;

    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}

然后,我们就可以对类型进行转换了。

下面我们可以编写接口测试一下:

@RestController
public class StudentController {
    @Resource
    private StudentService studentService;

    @PostMapping("/add")
    public boolean add(@RequestBody Student student){
        return studentService.save(student);
    }

    @GetMapping("/get")
    public Student get(@RequestParam("id")int id){
        return studentService.getById(id);
    }
}

测试成功,查看数据库:

成功保存字符类型json串。

猜你喜欢

转载自blog.csdn.net/tang_seven/article/details/129733851