在实际场景使用springboot+mybatis来完成数据库的增删改查时,可能会面对接收的参数比较复杂的情况。比如在接收restful风格的请求参数时,可能filter里的过滤条件比较复杂,包含有数字、字符串、List等类型混合的请求。同时为了使得mybatis的查询写得更通用,需要覆盖各种场景,这就要借助于Mybatis的各种特性来实现。
接下来,就以实际的例子来给出代码参考。该部分的代码可以直接沿用到未来的其它实际场景中。
接收Restful风格的复杂参数请求,利用mybatis处理包含的Map、List、String等数据类型,并根据请求参数进行排序和分页等操作
在实际场景中遇到的一个复杂restful风格接口中的请求参数,filter里的过滤条件比较多,且参数结构较为复杂:
{
"appKey": "appKey",
"filter": {
"id": ["609a3d7242ff880018b9e26b"],
"eventName": "免费",
"eventKey": "click",
"positionInfo": {"posId":"5fd9f7b71b52740011016b75", "levelId":"5fd9f7b71b5274001103740"},
"clientVersion": ["210f63dd6b6c4c09b4cf55a4"],
"priority":0
},
"limit": 999,
"populate": "",
"projectId": "5fd9f67840e8580047582075",
"skip": 0,
"sort": {
"id": 1
}
}
对部分数据做了脱敏,但仍然保留了filter中的复杂参数场景。可以看到filter中包含了Map、List、String、Integer,基本包含了主要的数据类型。因此,对这个问题的解决可以延用到许多其它的场景。
首先给出Mapper.java的代码
import com.example.data.pojo.Statsevents;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
public interface StatseventsMapper {
int deleteByPrimaryKey(String id);
int insert(Statsevents record);
Statsevents selectByPrimaryKey(String id);
List<Statsevents> selectAll(@Param("param") Map<String, Object> paramMap);
int updateByPrimaryKey(Statsevents record);
}
上述代码包含了增删改查的四个功能。主要关注于seleteAll
查找指定条件的所有数据,这里利用了@Param("param")
注解来命令导入的参数,这样在xml文件中就可以用param
来使用引入的参数。通过上面的请求参数,确定引入的参数类型为Map
接下来就是主要的mybatis的xml文件的编写
<select id="selectAll" parameterType="java.util.Map" resultMap="BaseResultMap">
select id, eventName, eventKey, priority, positionInfo, clientVersion
from statsevents
<where>
<if test="param.containsKey('filter') and param.get('filter').size() > 0">
<foreach collection="param.get('filter').entrySet()" index="key" item='val' separator="and" open=" " close=" ">
<choose>
<when test="val instanceof com.alibaba.fastjson.JSONArray and val.size()>0">
${key} in
<foreach collection="val" item="_key" open="(" close=")" separator=",">
#{_key}
foreach>
when>
<when test="val instanceof com.alibaba.fastjson.JSONObject and val.size() > 0">
<foreach collection="val" index="pKey" item="pVal" open=" " separator="and" close=" ">
${key} like "%${pVal}%"
foreach>
when>
<when test="key == 'clientVersion' and val instanceof com.alibaba.fastjson.JSONArray and val.size() > 0">
<foreach collection="val" item="cVal" open=" " separator="and" close=" ">
${key} like '%${cVal}%'
foreach>
when>
<when test="val instanceof Integer and val != null">
${key} like '%"status": ${val}%'
when>
<when test="val instanceof String and val != ''">
${key} like '%${val}%'
when>
choose>
foreach>
if>
where>
<if test="param.containsKey('sort')">
<foreach collection="param.get('sort').entrySet()" index="key" item="val">
<if test="val == -1">
order by ${key} asc
if>
<if test="val == 1">
order by ${key} desc
if>
foreach>
if>
<if test="param.containsKey('limit') and param.containsKey('skip')">
limit ${param.get("skip")}, ${param.get("limit")}
if>
select>
上述代码基本完整展示了基于Restful风格的请求参数下,mybatis的处理方式。包含了处理复杂的参数请求,以及根据请求参数进行排序和分页的功能。
本次主要是处理Restful风格的请求参数,根据filter里的筛选条件,查询指定数据。
由于传入的是一个Map
的参数类型,因此,最外层使用了处理Map数据类型时的方法。
利用foreach
标签进行循环,其中colleaction
参数表示待遍历的Map数据集,index
表示索引(也就是key),item
表示每个键的值,index-item
就表示了键值对, separator
表示遍历每个键值对后的分隔符,open
和close
表示遍历开始前和结束后拼接的字符串。
接下来,对filter下的键值对进行遍历,通过判断不同值的类型,执行相应操作。因为我这里之前引入了fastjson来对Map和List进行处理,因此判断数据类型的时候采用了val instanceof com.alibaba.fastjson.JSONObject
和val instanceof com.alibaba.fastjson.JSONArray
。如果是原始的Map和List可以直接用val instanceof java.utils.List
或val instanceof java.utils.Map
来进行判断类型。
对于Map类型的处理参考刚刚的方式。对于List数据类型的方法如下:
利用foreach
标签进行循环,其中colleaction
参数表示待遍历的List数据集,item
表示List中的每个值,separator
表示遍历每个值后的分隔符,open
和close
表示遍历开始前和结束后拼接的字符串。
接下来分别处理Integer和String的类型,对于Integer类型的数据判空时需要设置val != null
最后处理排序和分页的功能。根据sort指定的键进行排序,键可以指定为任意值。分页时判断传入的参数中是否有limit和skip参数,利用sql本身的语法实现分页。