mybatis通用的多条件筛选查询

在开发项目阶段中为了方便往后的维护与灵活使用,做一个通用的查询功能比较便捷。在mybatis里面动态的拼接sql完成多条件查询,一些特殊字符可以采用一些其他代码代替。

封装格式如下

[
  {
    "arrInt": [
      0
    ],
    "arrStr": [
      "string"
    ],
    "cond": "string",
    "fieldName": "string",
    "intFieldValue1": 0,
    "intFieldValue2": 0,
    "isAndConn": false,
    "isEndOr": false,
    "isStartOr": false,
    "isStr": false,
    "relation": "string",
    "strFieldValue1": "string",
    "strFieldValue2": "string"
  }
]

cond条件: (主要是由于小于符号需要换别的标识代替转义)

SQL语句中的查询条件 传值时对应的标识代替
< lt
<= ltAndEq
> >
>= >=
= =
!= !=
like like(like查询时,前端拼接好 百分号)
in in (查询时,前端拼接好(1,2), 也可以改为传数组)
between between
isNull isNull
isNotNull isNotNull

示例:

[{
	"fieldName": "docStatus",  //字段名称是docStatus
	"cond": "=",			   //条件是等于
	"isStr": 1,				   //是字符串
	"relation": "and",		   //连接条件是and
	"strFieldValue1": "0"      //字段值
}]

1.建立一个参数接受实体类

package com.gy.data.entity;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;

import java.util.List;

@Data
@Builder
@ApiModel(value = "QueryParamBean" ,description = "通用查询")
public class QueryParamBean {

    @ApiModelProperty(value = "字段名")
    private String fieldName;

    @ApiModelProperty(value = "判断条件符号(等于,小于,大于。。等一系列)")
    private String cond;

    @ApiModelProperty(value = "字段值1___存放字符串类型")
    private String strFieldValue1;

    @ApiModelProperty(value = "字段值2___存放字符串类型")
    private String strFieldValue2;

    @ApiModelProperty(value = "是否是字符串")
    private Boolean isStr;

    @ApiModelProperty(value = "是否是AND连接符号 只有 AND 与 OR")
    private Boolean isAndConn;

    @ApiModelProperty(value = "字段值1(存放数字类型)")
    private Long intFieldValue1;

    @ApiModelProperty(value = "字段值2(存放数字类型)")
    private Long intFieldValue2;



    @ApiModelProperty(value = "字符串数组,(cond = in时,配合 in 条件使用)")
    private List<String> arrStr;

    @ApiModelProperty(value = "数字类型数组,(cond = in时,配合 in 条件使用)")
    private List<Integer> arrInt;




    @ApiModelProperty(value = "是否是前半括号(与前端无关属性)")
    private Boolean isStartOr;

    @ApiModelProperty(value = "是否是后半括号(与前端无关属性)")
    private Boolean isEndOr;

}


}

2.接受参数时,是一个数组接受

package com.gy.data.controller;

import com.google.common.base.Preconditions;
import com.gy.data.annotation.QueryParamMatchParenthesis;
import com.gy.data.entity.QueryParamBean;
import com.gy.data.mapper.gyv50read.GYV50ReadMapper;
import com.gy.data.mapper.gyv50read.GyV50OutStockMapper;
import com.gy.data.service.V50OutStockService;
import com.zlcloud.basedata.domain.OutStockMasterAndDetailDTO;
import com.zlcloud.basedata.domain.outofstockmaster.entity.OutOfStockMasterDTO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

/**
 * 订单库存查询
 *
 * @Author SUN JIE
 * @Date 8:39 2020-08-04
 * @return
 **/
@RequestMapping(value = "/V50OutStockController")
@RestController
@Api(value = "/V50OutStockController",tags = "成品出库单查询")
public class V50OutStockController {

    @Autowired
    private GyV50OutStockMapper gyV50OutStockMapper;

    @QueryParamMatchParenthesis
    @ApiOperation(value = "测试", httpMethod = "POST")
    @PostMapping(value = "/test", consumes = "application/json", produces = "application/json;charset=UTF-8")
    public List<Map> test(@RequestBody List<QueryParamBean> queryParamBeans) {
        int a = 100;
        return gyV50OutStockMapper.test(queryParamBeans);
    }

}

3.自定义注解(配置方面也可以用其他接口实现与继承的方法进行封装)

package com.gy.data.annotation;

import java.lang.annotation.*;

/**
 * 通用查询参数 括号匹配配置
 *
 * @Author SUN JIE
 * @Date 15:16 2020-08-13
 * @param  null
 * @return
 **/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface QueryParamMatchParenthesis {
	//这里可以设置一个接受类,继续做配置,使用注解时传入一个配置类
	//例: Class value();
    String value() default "";
}

2.注解的工具方法,使用切面方式解析注解,重新拼接小括号

package com.gy.data.aop;

import com.gy.data.entity.QueryParamBean;

import lombok.extern.java.Log;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Configuration;

import java.util.*;

/**
 * 该注解是针对 拼接  WHERE 条件后, and 与 or条件分离
 * 加上括号的处理。如果一般的查询不需要 or条件,该注解不用加上
 * @Author SUN JIE
 * @Date 15:16 2020-08-13
 * @param  null
 * @return
 **/
@Aspect
@Configuration
@Log
public class QueryParamMatchParenthesisAspect {

    @Around("execution(public * *(..)) && @annotation(com.gy.data.annotation.QueryParamMatchParenthesis)")
    public Object interceptor(ProceedingJoinPoint pjp) throws Throwable {


        List<QueryParamBean> queryParamBean = new ArrayList<>();
        // 参数值
        Object[] args = pjp.getArgs();
        for (int k = 0; k < args.length; k++) {

            Object arg = args[k];

            queryParamBean = castList(arg, QueryParamBean.class);

            queryParamBean = setConnectSymbol(queryParamBean);

            args[k] = queryParamBean;

        }
        return pjp.proceed(args);

    }

    public static <T> List<T> castList(Object obj, Class<T> clazz)
    {
        List<T> result = new ArrayList<T>();
        if(obj instanceof List<?>)
        {
            for (Object o : (List<?>) obj)
            {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }

    public List<QueryParamBean> setConnectSymbol(List<QueryParamBean> queryParamBeans){
        //判断前端是否有放状态值,没放默认为1
        boolean isStart = false;
        boolean isEnd = true;
        List<QueryParamBean> newParamBeans = new ArrayList<>();
        for(int i=0;i<queryParamBeans.size();i++){

            //如果是最后一个参数则结束循环
            QueryParamBean queryParamBean =  QueryParamBean.builder().build();

            BeanUtils.copyProperties(queryParamBeans.get(i),queryParamBean);

            if(queryParamBeans.size()-1==i){
                if(isStart){
                    queryParamBean.setIsEndOr(true);
                }
                queryParamBean.setIsAndConn(true);
                newParamBeans.add(queryParamBean);
                break;
            }
            //如果是结束的,并且是or则拼接
            if(isEnd && !queryParamBeans.get(i).getIsAndConn()){
                isStart = true;
                isEnd = false;
                queryParamBean.setIsStartOr(true);
            }
            //如果是已经开始or的,则非or就结束
            if(isStart && !queryParamBeans.get(i).getIsAndConn()){
                isStart = false;
                isEnd = true;
                queryParamBean.setIsEndOr(true);
            }
            newParamBeans.add(queryParamBean);
        }
        return newParamBeans;
    }





}


3.这里的mapper接口因为多数据源的原因我用到多态,一般是不需要使用两个mapper接口

    package com.gy.data.mapper.v50common;

import com.gy.data.entity.QueryParamBean;
import com.zlcloud.basedata.domain.outofstockdetail.entity.OutOfStockDetailDTO;
import com.zlcloud.basedata.domain.outofstockmaster.entity.OutOfStockMasterDTO;
import org.apache.ibatis.annotations.Param;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;
import java.util.Map;

/**
 * @author jayson
 * @version 2.0
 * @date 2020-08-10 11:03
 */
public interface V50OutStockCommMapper {
    List<Map> test(@Param("queryParamBeans") List<QueryParamBean> queryParamBeans);
}

4.继承父类的mapper

package com.gy.data.mapper.gyv50read;

import com.gy.data.mapper.v50common.V50OutStockCommMapper;
/**
 * @author jayson
 * @version 2.0
 * @date 2020-08-10 11:02
 */
public interface GyV50OutStockMapper extends V50OutStockCommMapper {
}


5.已经拼接好的条件,其他查询语句都可以使用

<sql id="Query_Model_ByCond">
    <foreach collection="queryParamBeans" item="item" index="index">
      <if test="item.cond == 'lt'.toString()">
        <if test="item.isStartOr">(</if>
        ${item.fieldName}  <![CDATA[ < ]]>
        <choose>
          <when test="item.isStr">#{item.strFieldValue1}</when>
          <otherwise>#{item.intFieldValue1}</otherwise>
        </choose>

        <if test="item.isEndOr">)</if>
        <if test="queryParamBeans.size()-1 != index">
          <choose>
            <when test="item.isAndConn"> AND </when>
            <otherwise> OR </otherwise>
          </choose>
        </if>
      </if>

      <if test="item.cond == 'ltAndEq'.toString()">
        <if test="item.isStartOr">(</if>
        ${item.fieldName}  <![CDATA[ <= ]]>
        <choose>
          <when test="item.isStr">#{item.strFieldValue1}</when>
          <otherwise>#{item.intFieldValue1}</otherwise>
        </choose>
        <if test="item.isEndOr">)</if>
        <if test="queryParamBeans.size()-1 != index">
          <choose>
            <when test="item.isAndConn"> AND </when>
            <otherwise> OR </otherwise>
          </choose>
        </if>
      </if>

      <if test="item.cond == '>'.toString()">
        <if test="item.isStartOr">(</if>
        ${item.fieldName} >
        <choose>
          <when test="item.isStr">#{item.strFieldValue1}</when>
          <otherwise>#{item.intFieldValue1}</otherwise>
        </choose>
        <if test="item.isEndOr">)</if>
        <if test="queryParamBeans.size()-1 != index">
          <choose>
            <when test="item.isAndConn"> AND </when>
            <otherwise> OR </otherwise>
          </choose>
        </if>
      </if>

      <if test="item.cond == '>='.toString()">
        <if test="item.isStartOr">(</if>
        ${item.fieldName} >=
        <choose>
          <when test="item.isStr">#{item.strFieldValue1}</when>
          <otherwise>#{item.intFieldValue1}</otherwise>
        </choose>
        <if test="item.isEndOr">)</if>
        <if test="queryParamBeans.size()-1 != index">
          <choose>
            <when test="item.isAndConn"> AND </when>
            <otherwise> OR </otherwise>
          </choose>
        </if>
      </if>

      <if test="item.cond == '='.toString()">
        <if test="item.isStartOr">(</if>
        ${item.fieldName} =
        <choose>
          <when test="item.isStr">#{item.strFieldValue1}</when>
          <otherwise>#{item.intFieldValue1}</otherwise>
        </choose>
        <if test="item.isEndOr">)</if>
        <if test="queryParamBeans.size()-1 != index">
          <choose>
            <when test="item.isAndConn"> AND </when>
            <otherwise> OR </otherwise>
          </choose>
        </if>
      </if>

      <if test="item.cond == '!='.toString()">
        <if test="item.isStartOr">(</if>
        ${item.fieldName} <![CDATA[ <> ]]>
        <choose>
          <when test="item.isStr">#{item.strFieldValue1}</when>
          <otherwise>#{item.intFieldValue1}</otherwise>
        </choose>
        <if test="item.isEndOr">)</if>
        <if test="queryParamBeans.size()-1 != index">
          <choose>
            <when test="item.isAndConn"> AND </when>
            <otherwise> OR </otherwise>
          </choose>
        </if>
      </if>

      <if test="item.cond == 'like'.toString()">
        <if test="item.isStartOr">(</if>
        ${item.fieldName} LIKE #{item.strFieldValue1}
        <if test="item.isEndOr">)</if>
        <if test="queryParamBeans.size()-1 != index">
          <choose>
            <when test="item.isAndConn"> AND </when>
            <otherwise> OR </otherwise>
          </choose>
        </if>
      </if>

      <if test="item.cond == 'in'.toString()">
        <if test="item.isStartOr">(</if>
        ${item.fieldName} in
        <foreach collection="item.arr" item="a" separator="," open="(" close=")">
          #{a}
        </foreach>
        <if test="item.isEndOr">)</if>
        <if test="queryParamBeans.size()-1 != index">
          <choose>
            <when test="item.isAndConn"> AND </when>
            <otherwise> OR </otherwise>
          </choose>
        </if>
      </if>

      <if test="item.cond == 'between'.toString()">
        <if test="item.isStartOr">(</if>
        ${item.fieldName} between
        <choose>
        <when test="item.isStr"> #{item.strFieldValue1} AND #{item.strFieldValue2} </when>
          <otherwise>  #{item.intFieldValue1} AND #{item.intFieldValue2} </otherwise>
        </choose>
        <if test="item.isEndOr">)</if>
        <if test="queryParamBeans.size()-1 != index">
          <choose>
            <when test="item.isAndConn"> AND </when>
            <otherwise> OR </otherwise>
          </choose>
        </if>
      </if>

      <if test="item.cond == 'isNull'.toString()">
        <if test="item.isStartOr">(</if>
        IFNULL(${item.fieldName},'0')='0'
        <if test="item.isEndOr">)</if>
        <choose>
          <when test="item.isAndConn"> AND </when>
          <otherwise> OR </otherwise>
        </choose>
      </if>

      <if test="item.cond == 'isNotNull'.toString()">
        <if test="item.isStartOr">(</if>
        IFNULL(${item.fieldName},'0')<![CDATA[ <> ]]> '0'
        <if test="item.isEndOr">)</if>
        <if test="queryParamBeans.size()-1 != index">
          <choose>
            <when test="item.isAndConn"> AND </when>
            <otherwise> OR </otherwise>
          </choose>
        </if>
      </if>

    </foreach>
  </sql>

6:引入通用的查询sql条件

  <select id="selectOrderByCond" parameterType="java.util.List">
    select
     a.*
    FROM
    test a 
    WHERE 1=1
    <include refid="Query_Model_ByCond"></include>
  </select>

结语:一个简单使用通用查询的工具得以实现,配合前端使用。在前端搜索框的条件进行调整时,后端不用继续调整。后端也可用作自己查询时使用该方法

package com.gy.newoms.utils;

import io.swagger.annotations.ApiModelProperty;

/**
 * @author jayson
 * @version 2.0
 * @date 2020-08-13 12:30
 */
public class QueryParamBeanConfig {

    //小于
    public static String COND_LT = "lt";

    //小于等于
    public static String COND_LT_AND_EQ = "ltAndEq";

    //大于
    public static String COND_GT = ">";

    //大于等于
    public static String COND_GT_AND_EQ = ">=";

    //等于
    public static String COND_EQ = "=";

    //不等于
    public static String COND_NOT_EQ = "!=";

    //模糊查询( 值自己加上百分号)
    public static String COND_LIKE = "like";

    //in 配合数组使用
    public static String COND_IN = "in";

    //在什么范围之间
    public static String COND_BETWEEN = "between";

    //是null值
    public static String COND_IS_NULL = "isNull";

    //不是null值
    public static String COND_IS_NOT_NULL = "isNotNull";

    //连接下一个条件(or)
    public static String RELATION_OR = "OR";

    //连接下一个条件(and)
    public static String RELATION_AND = "AND";
}

    private void setAcceptWhere(List<QueryParamBean> queryParamBeans, boolean b) {
        QueryParamBean queryParamBean = QueryParamBean.builder().fieldName(OrderMasterFieldNameModel.FIELD_NAME_DATA_STATE)
                .cond(QueryParamBeanConfig.COND_EQ)
                .intFieldValue1(-1L)
                .isAndConn(true)
                .isStr(false)
                .isStartOr(true).build();
        queryParamBeans.add(queryParamBean);


        QueryParamBean queryParamBean2 = QueryParamBean.builder().fieldName(OrderMasterFieldNameModel.FIELD_NAME_IS_CANCEL)
                .cond(QueryParamBeanConfig.COND_EQ)
                .intFieldValue1(0L)
                .isAndConn(true)
                .isStr(false)
                .isEndOr(true).build();
        queryParamBeans.add(queryParamBean2);
    }

你可能感兴趣的:(java基础,mybatis)