工作过程中,在进行接口测试的时候遇到了问题并成功解决,在此记录下结果。
- 首先,以下是我项目中某个查询功能的动态sql语句
<select id="queryCodes" parameterType="string" resultType="string">
SELECT
<if test="faqCode == 'all'">
DISTINCT faq_label_code
</if>
<if test="faqCode != 'all' and faqCode != '' and faqCode != null">
faq_label_code
</if>
<if test="faqCode == null">
DISTINCT faq_code
</if>
FROM
faq_label_mid
WHERE 1=1
<if test="faqCode != 'all' and faqCode != '' and faqCode != null">
AND faq_code = #{faqCode}
</if>
</select>
可以看到,这里传入一个string类型的参数,通过对faqCode这个参数进行判断在数据库表中得到对应的查询结果。
- 下面是mapper接口中的方法,通过调用该方法就能去执行上面的动态sql语句
public interface FaqLabelMidMapper extends MzhMapper<FaqLabelMid> {
List<String> queryCodes(String faqCode);
}
- 当传入一个字符串到这个方法并调用时,报错情况如下
Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'faqCode' in 'class java.lang.String'
-
解决方法
提示的错误原因是 faqCode 字段没有 get 方法,这里错误的原因其实是WHERE 后面的if判断导致的
为调用接口的方法入参提供一个@Param注解,如下
List<String> queryCodes(@Param("faqCode") String faqCode);
就能成功运行。
当我把圈出来的部分代码注释掉时,即使不用加@Param注解也能运行成功。
- 结论
mybatis传单个String类型,可以不用@param注解,前提是xml中不含有条件表达式(when,if..标签中没有引用到该参数)
注意点:对于该文章中上面的sql语句,if 可以在两个地方使用,分别是在SELECT...FROM 之间 和在 WHERE 之后。
对于本文中出现的错误,主要是因为WHERE后有if条件判断,但是方法入参却没有加上@Param注解导致。
经过我的测试,在SELECT...FROM之间有加上if条件判断,但是如果WHERE后没有if条件判断,即使方法入参不加@Param注解貌似也是能运行成功,至于其中的原理可能还得深入研究(如果有大佬愿意讲解,欢迎在评论区留言,或者有错误的地方可以直接在评论区提出,我会及时修改)
扩展:
上面的栗子中针对的是接口入参类型是单个字符串,以下介绍一下入参分别为List、Map类型是时的做法。
-当入参为List集合时
int deleteLabelsByCodes(List<String> codes);
sql语句
<delete id="deleteLabelsByCodes" parameterType="list">
DELETE FROM
t_faq_label
WHERE 1=1
<if test="list != null">
AND faq_label_code
IN
<foreach collection="list" item="code" open="(" separator="," close=")">
#{code}
</foreach>
</if>
</delete>
我并没有在接口入参出加上@Param("list") 类似这样的注解,但是同样能执行成功,这是为什么呢?
这里我们不妨来看一下 查阅资料后mybatis中 对foreach这个标签属性解释
注意圈出来的部分我们可以知道,List<?>对象 作为入参时foreach的对象默认用 "list" 代替作为键,其实类似于我们使用注解@Param("list"),这样即使我们没加注解,遇到where 后的if判断同样能运行成功。
但是如果我们在接口入参加上了@Param注解,这时候默认以"list"作为键的规则就失效了,这时候不管是if 中的test判断还是foreach中的collection,都要以@Param注解中指定的参数为主。如下栗子
//这里加上@Param("codes")
int deleteLabelsByCodes(@Param("codes") List<String> codes);
<delete id="deleteLabelsByCodes" parameterType="list">
DELETE FROM
t_faq_label
WHERE 1=1
<!--这边list要改为codes-->
<if test="codes != null">
AND faq_label_code
IN
<!--这边list要改为codes-->
<foreach collection="codes" item="code" open="(" separator="," close=")">
#{code}
</foreach>
</if>
</delete>
-当入参为Map时
- test表达式中不用再加#,$之类的取值符了,就直接这样写就可以取到map中key所对应的值,而其他地方需要有#{map中的key}来取得map中该key所对应的值
Map<String,Object> conditions = new HashMap<>();
conditions.put("question",question);
conditions.put("faqTypeName",faqTypeName);
conditions.put("languageCode",languageCode);
List<String> queryExistedFaqLabel(Map<String,Object> conditions );
<select id="queryExistedFaqLabel" parameterType="map" resultType="string">
SELECT
faq_label_code
FROM
t_faq_label
WHERE
1=1
AND
faq_label_code
IN
<if test="faqLabelCodes != null">
<foreach collection="faqLabelCodes" item="faqLabelCode" index="index" open="(" separator="," close=")">
#{faqLabelCode}
</foreach>
</if>
<if test="languageCode != '' and languageCode != null">
AND language_code = #{languageCode}
</if>
</select>
- 对于在接口上加@Param("params")注解时,方法如下
List<WeixinUserLocationList> findweixinUserLocations(@Param("params") Map<String, Object> map);
注意就是注解@param 这个,是mybatis的,然后在xml中这样写:
<if test="params.accountId!=null">
and a.accountid=#{params.accountId}
</if>
<if test="params.nickname!=null and params.nickname !=''">
and a.nickname like '%${params.nickname}%'
</if>
<if test="params.beginDate!=null and params.beginDate!=''">
and date_format(a.createtime,'%Y-%m-%d')>=${params.beginDate}
</if>
<if test="params.endDate!=null and params.endDate!=''">
<![CDATA[ and date_format(a.createtime,'%Y-%m-%d')<=${params.endDate} ]]>
</if>
${params.nickname}这种写法参数默认是传字符串,#{params.accountId}可以取Long,Integer之类的。