Springboot+Mybatis处理复杂参数类型(Map、List等)


文章目录

  • Springboot+Mybatis处理复杂参数类型(Map、List等)
  • 需求场景
  • 请求参数
  • 解决方案
  • 代码讲解
  • mybatis处理Map数据类型的方法
  • mybatis处理List数据类型的方法


在实际场景使用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<String, Object>。

接下来就是主要的mybatis的xml文件的编写

<select id="selectAll" parameterType="java.util.Map" resultMap="BaseResultMap">

    select id, eventName, eventKey, priority, positionInfo, clientVersion
    from statsevents
    <where>
      <!--根据filter筛选数据-->
      <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>
            <!--处理List类型参数-->
          <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>
            <!--处理Map类型参数,like是因为需要模糊搜索-->
          <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>
          <!--需要找到同时包含指定clientVersion值,因此不能用in,更改为and-->
          <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>
            <!--处理Integer类型参数-->
          <when test="val instanceof Integer and val != null">
            ${key} like '%"status": ${val}%'
          </when>
            <!--处理String类型参数-->
          <when test="val instanceof String and val != ''">
            ${key} like '%${val}%'
          </when>
        </choose>
        </foreach>
      </if>
    </where>

    <!--根据sort的键进行排序,键可以指定为任意值-->
    <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>

    <!--根据skip和limit做分页-->
    <if test="param.containsKey('limit') and param.containsKey('skip')">
      limit ${param.get("skip")}, ${param.get("limit")}
    </if>
  </select>

上述代码基本完整展示了基于Restful风格的请求参数下,mybatis的处理方式。包含了处理复杂的参数请求,以及根据请求参数进行排序和分页的功能。

代码讲解

本次主要是处理Restful风格的请求参数,根据filter里的筛选条件,查询指定数据。

由于传入的是一个Map<String, Object>的参数类型,因此,最外层使用了处理Map数据类型时的方法。

mybatis处理Map数据类型的方法

利用foreach标签进行循环,其中colleaction参数表示待遍历的Map数据集index表示索引(也就是key)item表示每个键的值,index-item就表示了键值对, separator表示遍历每个键值对后的分隔符openclose表示遍历开始前和结束后拼接的字符串

接下来,对filter下的键值对进行遍历,通过判断不同值的类型,执行相应操作。因为我这里之前引入了fastjson来对Map和List进行处理,因此判断数据类型的时候采用了val instanceof com.alibaba.fastjson.JSONObjectval instanceof com.alibaba.fastjson.JSONArray。如果是原始的Map和List可以直接用val instanceof java.utils.Listval instanceof java.utils.Map来进行判断类型。

对于Map类型的处理参考刚刚的方式。对于List数据类型的方法如下:

mybatis处理List数据类型的方法

利用foreach标签进行循环,其中colleaction参数表示待遍历的List数据集item表示List中的每个值,separator表示遍历每个值后的分隔符openclose表示遍历开始前和结束后拼接的字符串

接下来分别处理Integer和String的类型,对于Integer类型的数据判空时需要设置val != null

最后处理排序和分页的功能。根据sort指定的键进行排序,键可以指定为任意值。分页时判断传入的参数中是否有limit和skip参数,利用sql本身的语法实现分页。