在SelectProvider注解中使用复杂类型参数(List)

最近开发中尝试使用注解来代替xml完成Mybatis的sql编写,实现更完(装)整(逼)的无xml编程。结果没写多久就跌进大坑了Orz

总所周知的是Mybatis支持的注解中有@Select、@Insert、@Update、@Delete这四个基本操作。使用这些注解你可以非常快的完成基础操作,如果想执行一些复杂操作,例如包含where、foreach等xml中一个标签即可完成的操作,便需要用到另一个注解 –> @SelectProvider

如果你的需求只是传递一些基础类型,那你学习使用SelectProvider的曲线还是很平滑的。如果你的需求是传递一些复杂类型,例如List,那就可能会尴尬了。

1
2
3
4
5
@Mapper
public interface QuestionMapper {
@SelectProvider(type = QuestionSqlProvider.class, method = "listQuestionByQuestionId")
List<Question> listQuestionByQuestionId(@Param("idList") List<Integer> idList);
}

一开始我理所当然的把List作为输入参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public String listQuestionByQuestionId(final List<Integer> idList) {
StringBuilder sb = new StringBuilder();
sb.append("(");
for (Integer questionId : idList) {
sb.append(" '" + questionId + "',");
}
sb.deleteCharAt(sb.length() - 1);
sb.append(")");
System.out.println(sb.toString());
return new SQL() {{
SELECT(" question_id,question_title,create_time ");
FROM(" question ");
WHERE(" question_id in " + sb.toString());
}}.toString();
}

燃鹅。。jvm很无情的抛了个错误出来

1
2
00:29:39.814 [http-nio-8080-exec-1] DEBUG o.s.web.servlet.DispatcherServlet - Could not complete request
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (com.amosannn.mapper.QuestionSqlProvider.listQuestionByQuestionId). Cause: org.apache.ibatis.binding.BindingException: Parameter 'arg0' not found. Available parameters are [idList, param1]

很难受,Mybatis的官方文档里并没有针对@SelectProvider有更多的demo,翻遍了各大门户网站也没见到有相关的讨论。兜兜转转依旧没有眉目,想到多参数的传递会被Mybatis自动封装进Map,该不会List也是同样被封装进Map吧。结果一试还真是这样。。

终于摸索出问题的关键,只需把形参由List类型替换为Map类型就能接收到前面传来的List了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class QuestionSqlProvider {
public String listQuestionByQuestionId(final Map<String, Object> map) {
List<Integer> idList = (List<Integer>)map.get("idList");
StringBuilder sb = new StringBuilder();
sb.append("(");
for (Integer questionId : idList) {
sb.append(" '" + questionId + "',");
}
sb.deleteCharAt(sb.length() - 1);
sb.append(")");
System.out.println(sb.toString());
return new SQL() {{
SELECT(" question_id,question_title,create_time ");
FROM(" question ");
WHERE(" question_id in " + sb.toString());
}}.toString();
}
}