Bootstrap

若依框架使用—MybatisPlus中动态sql语句详解

若依框架使用—MybatisPlus中动态sql语句详解

MybatisPlus中动态sql语句主要涉及到两个属性ew.getSqlSelectew.getCustomSqlSegment

ew.getSqlSelect主要用于拼接select后面的语句

ew.getCustomSqlSegment用于拼接Where后面的语句

代码实现

Service层

@Override
public TableDataInfo<DeviceChannelVo> queryPageList(DeviceChannelBo deviceChannelBo, PageQuery pageQuery) {
    LambdaQueryWrapper<DeviceChannel> lqw = buildQueryWrapper(deviceChannelBo);
    Page<DeviceChannelVo> result = baseMapper.selectVoPageList(pageQuery.build(),lqw);
    return TableDataInfo.build(result);
}

private LambdaQueryWrapper<DeviceChannel> buildQueryWrapper(DeviceChannelBo bo) {
        LambdaQueryWrapper<DeviceChannel> lqw = Wrappers.lambdaQuery();
        //配合ew.getSqlSelect使用
        lqw.select(DeviceChannel::getId,DeviceChannel::getDeviceId,DeviceChannel::getChannelId,DeviceChannel::getName);
        //配合ew.getCustomSqlSegment使用    
        lqw.eq(StringUtils.isNotBlank(bo.getDeviceId()), DeviceChannel::getDeviceId, bo.getDeviceId());
        lqw.eq(StringUtils.isNotBlank(bo.getChannelId()), DeviceChannel::getChannelId, bo.getChannelId());
        lqw.like(StringUtils.isNotBlank(bo.getName()), DeviceChannel::getName, bo.getName());
        lqw.eq(bo.getStatus() != null, DeviceChannel::getStatus, bo.getStatus());
        return lqw;
    }

Mapper层

@Mapper
public interface DeviceChannelMapper extends BaseMapperPlus<DeviceChannel, DeviceChannelVo> {

    Page<DeviceChannelVo> selectVoPageList(@Param("page") Page<DeviceChannelVo> page,@Param(Constants.WRAPPER) Wrapper<DeviceChannel> queryWrapper);

} 

XML层

<select id="selectVoPageList" resultMap="DeviceChannelResult">
    select
    <if test="ew.getSqlSelect != null">
        ${ew.getSqlSelect}
    </if>
    <if test="ew.getSqlSelect == null">
        id, T1.channelId, T1.deviceId, name, T2.dept_id
    </if>
    FROM device_channel T1
    LEFT JOIN  dept_device T2
    ON T1.deviceId = T2.device_id AND T1.channelId = T2.channel_id
        ${ew.getCustomSqlSegment}
    ORDER BY T1.id
</select>

相关源码

条件构造抽象类Wrapper

/*
 * Copyright (c) 2011-2024, baomidou ([email protected]).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.baomidou.mybatisplus.core.conditions;

import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
import com.baomidou.mybatisplus.core.conditions.segments.NormalSegmentList;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.*;

import java.util.Objects;

/**
 * 条件构造抽象类
 *
 * @author hubin
 * @since 2018-05-25
 */
@SuppressWarnings("all")
public abstract class Wrapper<T> implements ISqlSegment {

    /**
     * 实体对象(子类实现)
     *
     * @return 泛型 T
     */
    public abstract T getEntity();

    public String getSqlSelect() {
        return null;
    }

    public String getSqlSet() {
        return null;
    }

    public String getSqlComment() {
        return null;
    }

    public String getSqlFirst() {
        return null;
    }

    /**
     * 获取 MergeSegments
     */
    public abstract MergeSegments getExpression();

    /**
     * 获取自定义SQL 简化自定义XML复杂情况
     * <p>
     * 使用方法: `select xxx from table` + ${ew.customSqlSegment}
     * <p>
     * 注意事项:
     * 1. 逻辑删除需要自己拼接条件 (之前自定义也同样)
     * 2. 不支持wrapper中附带实体的情况 (wrapper自带实体会更麻烦)
     * 3. 用法 ${ew.customSqlSegment} (不需要where标签包裹,切记!)
     * 4. ew是wrapper定义别名,不能使用其他的替换
     */
    public String getCustomSqlSegment() {
        MergeSegments expression = getExpression();
        if (Objects.nonNull(expression)) {
            NormalSegmentList normal = expression.getNormal();
            String sqlSegment = getSqlSegment();
            if (StringUtils.isNotBlank(sqlSegment)) {
                if (normal.isEmpty()) {
                    return sqlSegment;
                } else {
                    return Constants.WHERE + StringPool.SPACE + sqlSegment;
                }
            }
        }
        return StringPool.EMPTY;
    }

    /**
     * 查询条件为空(包含entity)
     */
    public boolean isEmptyOfWhere() {
        return isEmptyOfNormal() && isEmptyOfEntity();
    }

    /**
     * 查询条件不为空(包含entity)
     */
    public boolean isNonEmptyOfWhere() {
        return !isEmptyOfWhere();
    }

    @Deprecated
    public boolean nonEmptyOfWhere() {
        return isNonEmptyOfWhere();
    }

    /**
     * 查询条件为空(不包含entity)
     */
    public boolean isEmptyOfNormal() {
        return CollectionUtils.isEmpty(getExpression().getNormal());
    }

    /**
     * 查询条件为空(不包含entity)
     */
    public boolean isNonEmptyOfNormal() {
        return !isEmptyOfNormal();
    }

    @Deprecated
    public boolean nonEmptyOfNormal() {
        return isNonEmptyOfNormal();
    }

    /**
     * 深层实体判断属性
     *
     * @return true 不为空
     */
    public boolean isNonEmptyOfEntity() {
        T entity = getEntity();
        if (entity == null) {
            return false;
        }
        TableInfo tableInfo = TableInfoHelper.getTableInfo(entity.getClass());
        if (tableInfo == null) {
            return false;
        }
        if (tableInfo.getFieldList().stream().anyMatch(e -> fieldStrategyMatch(tableInfo, entity, e))) {
            return true;
        }
        return StringUtils.isNotBlank(tableInfo.getKeyProperty()) ? Objects.nonNull(tableInfo.getPropertyValue(entity, tableInfo.getKeyProperty())) : false;
    }

    @Deprecated
    public boolean nonEmptyOfEntity() {
        return isNonEmptyOfEntity();
    }

    /**
     * 根据实体FieldStrategy属性来决定判断逻辑
     */
    private boolean fieldStrategyMatch(TableInfo tableInfo, T entity, TableFieldInfo e) {
        switch (e.getWhereStrategy()) {
            case NOT_NULL:
                return Objects.nonNull(tableInfo.getPropertyValue(entity, e.getProperty()));
            case IGNORED:
                return true;
            case ALWAYS:
                return true;
            case NOT_EMPTY:
                return StringUtils.checkValNotNull(tableInfo.getPropertyValue(entity, e.getProperty()));
            case NEVER:
                return false;
            default:
                return Objects.nonNull(tableInfo.getPropertyValue(entity, e.getProperty()));
        }
    }

    /**
     * 深层实体判断属性
     *
     * @return true 为空
     */
    public boolean isEmptyOfEntity() {
        return !isNonEmptyOfEntity();
    }

    /**
     * 获取格式化后的执行sql
     *
     * @return sql
     * @since 3.3.1
     */
    public String getTargetSql() {
        return getSqlSegment().replaceAll("#\\{.+?}", "?");
    }

    /**
     * 条件清空
     *
     * @since 3.3.1
     */
    abstract public void clear();
}

自用常量集中管理Constants

/*
 * Copyright (c) 2011-2024, baomidou ([email protected]).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.baomidou.mybatisplus.core.toolkit;

import java.io.Serializable;

/**
 * mybatis_plus 自用常量集中管理
 *
 * @author miemie
 * @since 2018-07-22
 */
public interface Constants extends StringPool, Serializable {

    /**
     * project name
     */
    String MYBATIS_PLUS = "mybatis-plus";

    /**
     * MD5
     */
    String MD5 = "MD5";
    /**
     * AES
     */
    String AES = "AES";
    /**
     * AES 算法
     */
    String AES_CBC_CIPHER = "AES/CBC/PKCS5Padding";
    /**
     * as
     */
    String AS = " AS ";


    /**
     * 实体类
     */
    String ENTITY = "et";
    /**
     * 实体类 带后缀 ==> .
     */
    String ENTITY_DOT = ENTITY + DOT;
    /**
     * wrapper 类
     */
    String WRAPPER = "ew";
    /**
     * wrapper 类 带后缀 ==> .
     */
    String WRAPPER_DOT = WRAPPER + DOT;
    /**
     * wrapper 类的属性 entity
     */
    String WRAPPER_ENTITY = WRAPPER_DOT + "entity";
    /**
     * wrapper 类的属性 sqlSegment
     */
    String WRAPPER_SQLSEGMENT = WRAPPER_DOT + "sqlSegment";
    /**
     * wrapper 类的属性 emptyOfNormal
     */
    String WRAPPER_EMPTYOFNORMAL = WRAPPER_DOT + "emptyOfNormal";
    /**
     * wrapper 类的属性 nonEmptyOfNormal
     */
    String WRAPPER_NONEMPTYOFNORMAL = WRAPPER_DOT + "nonEmptyOfNormal";
    /**
     * wrapper 类的属性 nonEmptyOfEntity
     */
    String WRAPPER_NONEMPTYOFENTITY = WRAPPER_DOT + "nonEmptyOfEntity";
    /**
     * wrapper 类的属性 emptyOfWhere
     */
    String WRAPPER_EMPTYOFWHERE = WRAPPER_DOT + "emptyOfWhere";
    /**
     * wrapper 类的判断属性 nonEmptyOfWhere
     */
    String WRAPPER_NONEMPTYOFWHERE = WRAPPER_DOT + "nonEmptyOfWhere";
    /**
     * wrapper 类的属性 entity 带后缀 ==> .
     */
    String WRAPPER_ENTITY_DOT = WRAPPER_DOT + "entity" + DOT;
    /**
     * wrapper 类的属性 expression 下级属性 order
     */
    String WRAPPER_EXPRESSION_ORDER = WRAPPER_DOT + "useAnnotationOrderBy";
    /**
     * UpdateWrapper 类的属性 sqlSet
     */
    String U_WRAPPER_SQL_SET = WRAPPER_DOT + "sqlSet";
    /**
     * QueryWrapper 类的属性 sqlSelect
     */
    String Q_WRAPPER_SQL_SELECT = WRAPPER_DOT + "sqlSelect";
    /**
     * wrapper 类的属性 sqlComment
     */
    String Q_WRAPPER_SQL_COMMENT = WRAPPER_DOT + "sqlComment";
    /**
     * wrapper 类的属性 sqlFirst
     */
    String Q_WRAPPER_SQL_FIRST = WRAPPER_DOT + "sqlFirst";
    /**
     * columnMap
     */
    @Deprecated
    String COLUMN_MAP = "cm";
    /**
     * columnMap.isEmpty
     */
    String COLUMN_MAP_IS_EMPTY = COLUMN_MAP + DOT + "isEmpty";
    /**
     * collection
     *
     * @see #COLL
     * @deprecated 3.5.2 后面修改成collection
     */
    @Deprecated
    String COLLECTION = "coll";

    /**
     * @since 3.5.2
     */
    String COLL = "coll";
    /**
     * list
     *
     * @since 3.5.0
     */
    String LIST = "list";
    /**
     * where
     */
    String WHERE = "WHERE";
    /**
     * limit
     */
    String LIMIT = "LIMIT";

    /**
     * @since 3.5.2
     */
    String ARRAY = "array";
    /**
     * order by
     */
    String ORDER_BY = "ORDER BY";
    /**
     * asc
     */
    String ASC = "ASC";
    /**
     * desc
     */
    String DESC = "DESC";
    /**
     * 乐观锁字段
     */
    String MP_OPTLOCK_VERSION_ORIGINAL = "MP_OPTLOCK_VERSION_ORIGINAL";

    /**
     * wrapper 内部参数相关
     */
    String WRAPPER_PARAM = "MPGENVAL";
    String WRAPPER_PARAM_MIDDLE = ".paramNameValuePairs" + DOT;


    /**
     * 默认批次提交数量
     */
    int DEFAULT_BATCH_SIZE = 1000;
}
;