Spring Boot中MyBatis Map自定义TypeHandler异常排查与修复
问题排查与修复方案
一、解决monthlyCounts字段为null的问题
核心原因及修复动作:
- 自定义TypeHandler未注册
确保MyBatis能识别你的TypeHandler:- 直接在TypeHandler类上添加注解:
@MappedTypes(Map.class) @MappedJdbcTypes(JdbcType.VARCHAR) public class MapStringIntegerTypeHandler extends BaseTypeHandler<Map<String, Integer>> { // 实现逻辑 } - 或者在Spring Boot配置文件中指定扫描路径:
mybatis: type-handlers-package: com.yourproject.handler
- 直接在TypeHandler类上添加注解:
- Mapper XML未关联TypeHandler
在结果映射中明确指定字段使用自定义处理器:<resultMap id="TaskCountResponseMap" type="com.yourproject.dto.TaskCountResponse"> <result property="monthlyCounts" column="monthly_counts" typeHandler="com.yourproject.handler.MapStringIntegerTypeHandler"/> </resultMap> - SQL未返回目标字段
检查SQL语句,确保查询结果包含monthly_counts字段(与实体类字段对应)。
二、解决JSON拼接的解析错误问题
错误根源:
手动拼接JSON时容易出现格式不规范,比如循环拼接键值对时多了冗余逗号、字符串未转义等,导致JSON格式无效。
修复方案:
方案1:用数据库内置函数生成标准JSON(推荐)
利用数据库自带的JSON聚合函数,避免手动拼接的格式问题:
- MySQL:
SELECT JSON_OBJECTAGG(month, count) AS monthly_counts FROM task_stats GROUP BY year - PostgreSQL:
SELECT json_object_agg(month, count) AS monthly_counts FROM task_stats GROUP BY year
方案2:修正手动拼接逻辑
如果必须手动拼接,严格保证格式规范:
以MySQL为例,用GROUP_CONCAT处理逗号分隔:
SELECT CONCAT('{', GROUP_CONCAT(CONCAT('"', month, '":', count) SEPARATOR ','), '}') AS monthly_counts FROM task_stats GROUP BY year
注意:如果month是字符串类型,要确保引号转义正确,避免语法错误。
三、正确的自定义TypeHandler实现示例
确保处理器能完成JSON与Map的双向转换:
@MappedTypes(Map.class) @MappedJdbcTypes(JdbcType.VARCHAR) public class MapStringIntegerTypeHandler extends BaseTypeHandler<Map<String, Integer>> { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @Override public void setNonNullParameter(PreparedStatement ps, int i, Map<String, Integer> parameter, JdbcType jdbcType) throws SQLException { try { ps.setString(i, OBJECT_MAPPER.writeValueAsString(parameter)); } catch (JsonProcessingException e) { throw new SQLException("Map转JSON字符串失败", e); } } @Override public Map<String, Integer> getNullableResult(ResultSet rs, String columnName) throws SQLException { return parseJson(rs.getString(columnName)); } @Override public Map<String, Integer> getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return parseJson(rs.getString(columnIndex)); } @Override public Map<String, Integer> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return parseJson(cs.getString(columnIndex)); } private Map<String, Integer> parseJson(String json) throws SQLException { if (json == null || json.isEmpty()) { return Collections.emptyMap(); } try { return OBJECT_MAPPER.readValue(json, new TypeReference<Map<String, Integer>>() {}); } catch (JsonProcessingException e) { throw new SQLException("JSON字符串转Map失败", e); } } }
内容的提问来源于stack exchange,提问作者Sercan Noyan Germiyanoğlu
相关产品推荐
相关产品推荐

