mybatisplus 的SQL拦截器实现关联查询功能

由于项目中经常会使用到一些简单地关联查询,但是mybatisplus还不支持关联查询,不过在看官方文档的时候发现了mybatisplus的SQL拦截器(其实也是mybatis的)就想着能不能在SQL执行的时候做一些处理以至于可以支持关联查询,于是就动手开始了,目前还只是一个初步的demo,但是一些基本的关联查询功能经过验证是没有问题的

环境信息

jdk: 1.8
springboot: 2.3.4.RELEASE
mybatisplus: 3.4.2
lombok:1.18.12

代码设计

代码涉及四个关键的类:

JoinBuilder
这是一个建造者类,主要适用于生成关联查询的语句

CaseBuilder
这也是一个建造者类,主要是用来生成连接查询的条件语句

MyQueryWrapper
这是查询器,这里继承了官方的QueryWrapper,然后扩展了一些功能。添加了关联查询的功能

JoinQueryInterceptor
这是SQL拦截器,在上面使用自定义的查询器添加了关联查询之后就可以使用SQL拦截器进行sql的构造

类关系图如下:

代码实现

实现连接条件构造器

package com.jenkin.common.config;

import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;

import java.io.StringReader;
import java.util.HashSet;
import java.util.Set;

/**
 * @author jenkin
 * @Since 2021年4月12日14:45:58
 * @Version 1.0
 * @Description : 关联查询join构造器
 */
@Slf4j
public class JoinBuilder {
    private StringBuilder sb = new StringBuilder();
    /**
     * 关联表里面的查询字段,比如要查询关联的用户表里面的用户名称
     */
    private String[] selectFields;
    /**
     * 关联表
     */
    private String joinTable;

    /**
     * 查询字段去重
     */
    Set<String> set = new HashSet<>();
    /**
     * 主表
     */
    private String mainTable;
    /**
     * 关联类型
     */
    private String joinType;

    private static final String LEFT_BRACKET = " ( ";
    private static final String RIGHT_BRACKET = " ) ";
    private static final String AND = " AND ";
    private static final String OR = " OR ";
    /**
     * 左连接
     */
    public static final String LEFT = " left ";
    /**
     * 右连接
     */
    public static final String RIGHT = " right ";
    /**
     * 内连接
     */
    public static final String INNER = " inner ";

    public JoinBuilder selectField(String... fields) {
        this.selectFields = fields;
        if (!ArrayUtil.isEmpty(this.selectFields)) {
            for (int i = 0; i < this.selectFields.length; i++) {
                this.selectFields[i] = StringUtils.camelToUnderline(this.selectFields[i]);
                set.add(this.selectFields[i].toUpperCase());
            }
        }
        return this;
    }

    public Set<String> getSelectFields() {
        return set;

    }

    public String getMainTable() {
        return mainTable;
    }

    public String getSubTable() {
        return this.joinTable;
    }

    /**
     * @param joinType  关联类型  JoinBuilder.LEFT,JoinBuilder.RIGHT,JoinBuilder.INNER
     * @param mainTable 主表
     * @param joinTable 关联表
     * @return
     */
    public JoinBuilder join(String joinType, String mainTable, String joinTable) {
        mainTable = StringUtils.camelToUnderline(mainTable);
        ;
        joinTable = StringUtils.camelToUnderline(joinTable);
        ;
        this.joinTable = joinTable;
        this.mainTable = mainTable;
        this.joinType = joinType;
        return this;
    }

    public static JoinBuilder build() {
        return new JoinBuilder();
    }

    public JoinBuilder and() {
        sb.append(AND);
        return this;
    }

    public JoinBuilder or() {
        sb.append(OR);
        return this;
    }

    public StringBuilder getSql() {
        return sb;
    }

    public JoinBuilder on(CaseBuilder builder) {
        sb.append(LEFT_BRACKET).append(builder.getSql()).append(RIGHT_BRACKET);
        return this;
    }

    public Join getJoin() {
        CCJSqlParserManager pm = new CCJSqlParserManager();
        String sql = "select * from " + mainTable + " " + joinType + " join " + joinTable + " on " + sb;
        try {
            net.sf.jsqlparser.statement.Statement parse = pm.parse(new StringReader(sql));
            if (parse instanceof Select) {
                return ((PlainSelect) ((Select) parse).getSelectBody()).getJoins().get(0);
            }
            return null;
        } catch (JSQLParserException e) {
            log.warn(sql);
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @author jenkin
     * @Since 2021年4月12日14:45:58
     * @Version 1.0
     * @Description : 条件构造器,局限于关联查询
     */
    public static class CaseBuilder {

        /**
         * SQL语句
         */
        private StringBuilder sb = new StringBuilder();
        private static final String LEFT_BRACKET = " ( ";
        private static final String RIGHT_BRACKET = " ) ";

        private static final String EQ = "=";
        private static final String NE = "<>";
        private static final String GT = ">";
        private static final String LT = "<";
        private static final String GT_EQ = ">=";
        private static final String LT_EQ = "<=";
        private static final String AND = " AND ";
        private static final String OR = " OR ";

        public static CaseBuilder build() {
            return new CaseBuilder();
        }

        public StringBuilder getSql() {
            return sb;
        }

        /**
         * 把条件表达式用括号包裹起来
         *
         * @param builder
         * @return
         */
        public CaseBuilder brackets(CaseBuilder builder) {
            sb.append(LEFT_BRACKET).append(builder.sb).append(RIGHT_BRACKET);
            return this;
        }

        public CaseBuilder and() {
            sb.append(AND);
            return this;
        }

        public CaseBuilder or() {
            sb.append(OR);
            return this;
        }

        /**
         * 规定左侧为主表的列
         * ,右侧为从表的列,不可以写反
         * 注意,在使用定值查询的时候 例如 on a.name = b.name and age = 1
         * 这个时候一样要遵循左边为主表,右边为关联表的规则.
         * 例如
         * <p>
         * 1、 and里面的条件 age字段是存在在主表里面的 那么就写成 eq("age",1)
         * 2、如果age字段是在关联表里面的,那么应该写成 eq(1,"age")
         * <p>
         * 其他的条件语句例如,ne,gt,lt等等也适用这个逻辑
         *
         * @param left  左侧列名称
         * @param right 右侧列名称
         * @return
         */
        public CaseBuilder eq(Object left, Object right) {
            if (left instanceof String) {
                left = StringUtils.camelToUnderline((String) left);
            }
            if (right instanceof String) {
                right = StringUtils.camelToUnderline(String.valueOf(right));
            }
            sb.append(left).append(EQ).append(right);
            return this;
        }

        /**
         * 规定左侧为主表的列
         * ,右侧为从表的列,不可以写反
         *
         * @param left  左侧列名称
         * @param right 右侧列名称
         * @return
         */
        public CaseBuilder ne(String left, Object right) {
            left = StringUtils.camelToUnderline(left);
            if (right instanceof String) {
                right = StringUtils.camelToUnderline(String.valueOf(right));
            }
            sb.append(left).append(NE).append(right);
            return this;
        }

        /**
         * 关联查询一般是列关联,如果条件里面有值等式,要做特殊处理,目前还不支持
         *
         * @param left
         * @param right
         * @return
         */
        @Deprecated
        public CaseBuilder gt(String left, Object right) {
            sb.append(left).append(GT).append(right);
            return this;
        }

        /**
         * 关联查询一般是列关联,如果条件里面有值等式,要做特殊处理,目前还不支持
         *
         * @param left
         * @param right
         * @return
         */
        @Deprecated
        public CaseBuilder gtEq(String left, Object right) {
            sb.append(left).append(GT_EQ).append(right);
            return this;
        }

        /**
         * 关联查询一般是列关联,如果条件里面有值等式,要做特殊处理,目前还不支持
         *
         * @param left
         * @param right
         * @return
         */
        @Deprecated
        public CaseBuilder lt(String left, Object right) {
            sb.append(left).append(LT).append(right);
            return this;
        }

        /**
         * 关联查询一般是列关联,如果条件里面有值等式,要做特殊处理,目前还不支持
         *
         * @param left
         * @param right
         * @return
         */
        @Deprecated
        public CaseBuilder ltEq(String left, Object right) {
            sb.append(left).append(LT_EQ).append(right);
            return this;
        }
    }
}

定制化QueryWrapper

在这个定制化的查询器里面添加了一个addJoin的方法用来添加关联查询

package com.jenkin.common.config;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.jenkin.common.entity.qos.Sort;

import java.util.ArrayList;
import java.util.List;

/**
 * @author :jenkin
 * @date :Created at 2020/3/13 12:07
 * @description:条件构造器,重写字符串转换方法
 * @modified By:
 * @version: 1.0
 */
public class
MyQueryWrapper<T> extends QueryWrapper<T> {
    /**
     * 关联查询构造器
     */
    private final List<JoinBuilder> joinBuilder = new ArrayList<>();

    /**
     * 获取 columnName
     *
     * @param column
     */
    @Override
    protected String columnToString(String column) {
        return StringUtils.camelToUnderline(column);
    }

    public static<T> MyQueryWrapper<T> query(){
        return new MyQueryWrapper<T>();
    }

    /**
     * 关联查询构造
    * @param builder
     * @return
     */
    public  MyQueryWrapper<T> addJoin(JoinBuilder builder){
        this.joinBuilder.add(builder);
        return this;
    }

    public List<JoinBuilder> getJoinBuilder() {
        return joinBuilder;
    }
    /**
     * 排序
     * @param sorts
     * @return
     */
    public QueryWrapper<T> sort(List<Sort> sorts){
        if(!CollectionUtils.isEmpty(sorts)){
            sorts.forEach(item->{
                orderBy(item.getSortField()!=null,"asc".equals(item.getSortValue()),item.getSortField());
            });
        }
        return this;
    }

}

定义SQL拦截器

通过自定义的SQL拦截器去拦截我们写好的关联查询,然后生成对应的SQL

package com.jenkin.common.config;

import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.relational.Between;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* @author jenkin
* @className JoinQueryInterceptor
* @description TODO
* @date 2021/4/12 14:58
*/
public class JoinQueryInterceptor extends JsqlParserSupport implements InnerInterceptor {
    /**
     * 保存我们的关联查询的上下文信息
     */
    static ThreadLocal<List<JoinBuilder>> joinBuilderThreadLocal = new ThreadLocal<>();

    /**
     * 操作前置处理
     * <p>
     * 改改sql啥的
     *
     * @param executor      Executor(可能是代理对象)
     * @param ms            MappedStatement
     * @param parameter     parameter
     * @param rowBounds     rowBounds
     * @param resultHandler resultHandler
     * @param boundSql      boundSql
     */
    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
                            ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        if (parameter instanceof MapperMethod.ParamMap) {
            for (Object value : ((MapperMethod.ParamMap) parameter).values()) {
                if (value instanceof MyQueryWrapper) {
                    List<JoinBuilder> joinBuilders = ((MyQueryWrapper) value).getJoinBuilder();
                    if(!CollectionUtils.isEmpty(joinBuilders)){
                        joinBuilderThreadLocal.set(joinBuilders);
                        try {
                            logger.debug("开始添加关联查询SQL");
                            String s = this.parserSingle(boundSql.getSql(), parameter);
                            logger.debug("加了关联查询的SQL : "+ s);
                            PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
                            mpBs.sql(s);
                        }finally {
                            joinBuilderThreadLocal.remove();
                        }
                        return;
                    }
                }
            }
        }
    }

    /**
     * 查询
     */
    @Override
    protected void processSelect(Select select, int index, String sql, Object obj) {
        List<JoinBuilder> joinBuilders = joinBuilderThreadLocal.get();
        PlainSelect selectBody = (PlainSelect) select.getSelectBody();
        if (selectBody.getFromItem().getAlias()==null) {
            selectBody.getFromItem().setAlias(new Alias("mainjointable"));
        }
        setJoins(selectBody,joinBuilders);

    }

    private void setJoins(PlainSelect selectBody,List<JoinBuilder> joinBuilders) {
        List<SelectItem> selectItems = selectBody.getSelectItems();
        Expression where = selectBody.getWhere();
        List<Join> joins = new ArrayList<>();
        for (int i = 0; i < joinBuilders.size(); i++) {
            JoinBuilder joinBuilder = joinBuilders.get(i);
            Join builderJoin = joinBuilder.getJoin();
            Set<String> selectFields = new HashSet<>(joinBuilder.getSelectFields());
            Join join = new Join();
            join.setLeft(builderJoin.isLeft());
            join.setRight(builderJoin.isRight());
            join.setInner(builderJoin.isInner());
            Table table = new Table(joinBuilder.getSubTable());
            table.setAlias( new Alias("subjointable"+i));
            setSelectItems(table,selectFields,selectItems,selectBody);
            join.setRightItem(table);
//            Expression expression = getOnExpressionWithTable(joinBuilder);
            Expression onExpression = joinBuilder.getJoin().getOnExpression();
            selectFields = new HashSet<>(joinBuilder.getSelectFields());
            setOnCase(onExpression,table,selectFields,(Table) selectBody.getFromItem(),false);
            join.setOnExpression(onExpression);
            joins.add(join);
            selectFields = new HashSet<>(joinBuilder.getSelectFields());
            setWhere(where,table,selectFields,(Table) selectBody.getFromItem());
        }
        selectBody.setJoins(joins);
    }

//    private Expression getOnExpressionWithTable(JoinBuilder joinBuilder) {
        setWhere(joinBuilder.getJoin().getOnExpression(),);
//        return joinBuilder.getJoin().getOnExpression();
//    }

    private void setSelectItems(Table table,  Set<String> selectFields, List<SelectItem> selectItems, PlainSelect selectBody) {

        for (SelectItem selectItem : selectItems) {
            if (selectItem instanceof SelectExpressionItem) {
                if (((SelectExpressionItem) selectItem).getExpression() instanceof Column && selectBody.getFromItem() instanceof Table) {
                    Column expression = (Column) ((SelectExpressionItem) selectItem).getExpression();
                    if (expression.getTable()==null&&selectFields.contains(expression.getColumnName().toUpperCase())){
                        expression.setTable(table);
                        selectFields.remove(expression.getColumnName().toUpperCase());
                    }else if(expression.getTable()==null){
                        expression.setTable((Table) selectBody.getFromItem());
                    }
                }
            }
        }
        if (!selectFields.isEmpty()){
            for (String selectField : selectFields) {
                SelectExpressionItem selectExpressionItem = new SelectExpressionItem();
                Column column = new Column();
                column.setTable(table);
                column.setColumnName(selectField);
                selectExpressionItem.setExpression(column);
                selectItems.add(selectExpressionItem);
            }
        }
    }

    /**
     *
     * @param on
     * @param subTable
     * @param joinSelectFields
     * @param sourceTable
     * @param isLeft 是否是左侧列,如果是那么就是主表,如果false,那么就是关联表,如果为null,那么就需要根据join字段判断
     */
    private void setOnCase(Object on, Table subTable, Set<String> joinSelectFields , Table sourceTable,Boolean isLeft) {
        if (on==null) {
            return;
        }
        if (on instanceof Column) {
            Column column = (Column) on;
            if((column).getTable()==null &&isLeft!=null){
                (column).setTable(isLeft?sourceTable:subTable);
            }
            if (isLeft==null&&column.getTable()==null){
                (column).setTable(joinSelectFields.contains(column.getColumnName().toUpperCase())?subTable:sourceTable);
            }
        }else if (on instanceof BinaryExpression){
            setOnCase(((BinaryExpression) on).getLeftExpression(),subTable,joinSelectFields,sourceTable,true);
            setOnCase(((BinaryExpression) on).getRightExpression(),subTable,joinSelectFields,sourceTable,false);
        }else if (on instanceof Parenthesis){
            setOnCase(((Parenthesis) on).getExpression(),subTable,joinSelectFields,sourceTable,false);
        }else if(on instanceof IsNullExpression){
            setOnCase(((IsNullExpression) on).getLeftExpression(),subTable,joinSelectFields,sourceTable,null);
        }else if (on instanceof Between){
            setOnCase(((Between) on).getLeftExpression(),subTable,joinSelectFields,sourceTable,null);
        }
        //有其他条件再补充
    }

    private void setWhere(Object where, Table subTable, Set<String> joinSelectFields , Table sourceTable) {
        if (where==null) {
            return;
        }
        if (where instanceof Column) {
            Column column = (Column) where;
            if((column).getTable()==null&&joinSelectFields.contains((column).getColumnName().toUpperCase())){
                (column).setTable(subTable);
            }else if((column).getTable()==null){
                (column).setTable(sourceTable);
            }
        }else if (where instanceof BinaryExpression){
            setWhere(((BinaryExpression) where).getLeftExpression(),subTable,joinSelectFields,sourceTable);
            setWhere(((BinaryExpression) where).getRightExpression(),subTable,joinSelectFields,sourceTable);
        }else if (where instanceof Parenthesis){
            setWhere(((Parenthesis) where).getExpression(),subTable,joinSelectFields,sourceTable);
        }else if(where instanceof IsNullExpression){
            setWhere(((IsNullExpression) where).getLeftExpression(),subTable,joinSelectFields,sourceTable);
        }else if(where instanceof Between){
            setWhere(((Between) where).getLeftExpression(),subTable,joinSelectFields,sourceTable);
        }
        //有其他条件再补充
    }
}

注入拦截器

紧接着只需要在mybatisplus的配置文件里面注入这个拦截器就可以了

使用示例

使用的过程我们分为两步:

添加字段到主表PO
如图,红框中的部分是我们添加的需要从其他表里面关联查询的字段,注意这些字段需要使用@TableField注解标注,并且 select字段和exist字段都要为false,不然会影响新增和修改操作

queryWrapper构造关联查询

把字段添加好之后就可以开始写关联查询了,下奶的示例应该是一个涵盖了大部分场景的示例了,多表关联,多条件关联,等等

 MyQueryWrapper<MenuPo> queryWrapper = new MyQueryWrapper<>();
        //添加一个关联表查询,关联用户表
        queryWrapper.addJoin(
                JoinBuilder.build()
                        //查询用户表里面的用户名称和用户邮箱字段
                        .selectField(MenuPo.Fields.userName, MenuPo.Fields.userEmail)
                        //使用左连接关联
                        .join(JoinBuilder.LEFT, MenuPo.class, UserPo.class)
                        //设置关联条件
                        .on(JoinBuilder.CaseBuilder.build()
                                //主表的创建人字段等于关联表的用户编码字段
                                // 注意,在条件中默认是第一个参数为主表的字段,第二个参数为关联表的字段
                                .eq(BasePo.Fields.createdBy, UserPo.Fields.userCode)
                        )
        //再添加一个关联查询,关联角色表
        ).addJoin(
                JoinBuilder.build()
                        //查血角色表里面的角色名称
                        .selectField(MenuPo.Fields.roleName)
                        //左连接
                        .join(JoinBuilder.LEFT,MenuPo.class, RolePo.class)
                        //关联条件
                        .on(JoinBuilder.CaseBuilder.build()
                                //code等于角色code
                            .eq(MenuPo.Fields.code, RolePo.Fields.roleCode)
                                //并且
                            .and()
                                //括号
                            .brackets(
                                    //parent =-1 or parent =1
                                    JoinBuilder.CaseBuilder.build()
                                            .eq(MenuPo.Fields.parent,-1)
                                            .or()
                                            .eq(MenuPo.Fields.parent,1)
                            )
                )
         //外层筛选条件,用户名=jenkin
        ).eq(MenuPo.Fields.userName,"jenkin");
        //执行查询
        menuService.list(queryWrapper);

可以在控制台看到执行的SQL:

SELECT
	mainjointable.id,
	mainjointable.NAME,
	mainjointable.CODE,
	mainjointable.parent,
	mainjointable.menu_level,
	mainjointable.permissions,
	mainjointable.menu_url,
	mainjointable.menu_icon,
	mainjointable.menu_order,
	mainjointable.menu_type,
	mainjointable.delete_flag,
	mainjointable.created_by,
	mainjointable.creation_date,
	mainjointable.last_update_date,
	mainjointable.last_updated_by,
	mainjointable.version_number,
	subjointable0.USER_EMAIL,
	subjointable0.USER_NAME,
	subjointable1.ROLE_NAME
FROM
	lsc_menu AS mainjointable
	LEFT JOIN lsc_user AS subjointable0 ON ( mainjointable.created_by = subjointable0.user_code )
	LEFT JOIN lsc_role AS subjointable1 ON (
		mainjointable.CODE = subjointable1.role_code
	AND ( mainjointable.parent = - 1 OR mainjointable.parent = 1 )
	)
WHERE
	mainjointable.delete_flag = 0
	AND (
	subjointable0.user_name = ?)

到此这篇关于基于mybatisplus 的SQL拦截器实现关联查询的文章就介绍到这了,更多相关mybatisplus关联查询内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • mybatis-plus分页查询的实现示例

    按照官方文档进行的配置:快速开始|mybatis-plus 引入依赖: <!-- 引入mybatisPlus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version> </dependency> <!--

  • 结合mybatis-plus实现简单不需要写sql的多表查询

    项目地址: GITHUB (本地下载) java mybatis 多表查询 简介 实现简单的实体类操作多表,  首先你的项目是使用了mybatis-plus 才可以使用 设计说明 如何关联表? 找第一张表注解为 TableId (mybatis-plus 注解)的属性名, 到每二张表找同样的属性名, 如果没找到,反过来找,如果还没找到,挨个属性找.以此类推,实现关联的前提条件是 主从表的关联例名必须一样 // user 表 @TableId private Integer userId // a

  • 完美解决MybatisPlus插件分页查询不起作用总是查询全部数据问题

    问题描述: 在使用mybatisplus插件进行分页查询时分页参数不起作用,总是查出来全部数据. 原因分析: 查看打印的sql日志发现sql后面并没有limit条件,怀疑是缺少配置. 解决方案: 查阅资料通过添加配置类MybatisPlusConfig解决问题: @Configuration public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor(){ return new

  • MyBatis-Plus 分页查询以及自定义sql分页的实现

    一.引言 分页查询每个人程序猿几乎都使用过,但是有部分同学不懂什么是物理分页和逻辑分页. 物理分页:相当于执行了limit分页语句,返回部分数据.物理分页只返回部分数据占用内存小,能够获取数据库最新的状态,实施性比较强,一般适用于数据量比较大,数据更新比较频繁的场景. 逻辑分页:一次性把全部的数据取出来,通过程序进行筛选数据.如果数据量大的情况下会消耗大量的内存,由于逻辑分页只需要读取数据库一次,不能获取数据库最新状态,实施性比较差,适用于数据量小,数据稳定的场合. 那么MP中的物理分页怎么实现

  • MyBatis-Plus 如何实现连表查询的示例代码

    在项目开发中,难免会遇到连表查询的操作. 项目中用的是 MyBatis-Plus,是新使用的框架.官方文档看这里. 我写过一篇通过单元测试来验证 MyBatis-Plus 的 CRUD 操作.点这里跳转 今天遇到连表查询的问题,特此记录一下. 遇到需要连表操作,想起 MyBatis 的操作连表查询,要是 MyBatis-Plus 也像 MyBatis 一样,就脑壳痛了.(MyBatis-Plus 是 MyBatis 的增强版) 脑壳痛归脑壳痛,先动手干. 首先 因为官方的内置接口方法都是针对单表

  • mybatis-plus QueryWrapper自定义查询条件的实现

    mybatis-plus框架功能很强大,把很多功能都集成了,比如自动生成代码结构,mybatis crud封装,分页,动态数据源等等,附上官网链接https://mp.baomidou.com/,github上有代码例子,国内小伙伴推荐码云https://gitee.com/baomidou/mybatis-plus.  但是,其中还是有些小坑,文档也没有涉及的很全面,碰到问题,百度或者发issue,能力强的还是直接看源码好,一切答案都在源码中. 版本推荐用3.1.0,3.1.1及以上版本有bu

  • mybatisplus 的SQL拦截器实现关联查询功能

    由于项目中经常会使用到一些简单地关联查询,但是mybatisplus还不支持关联查询,不过在看官方文档的时候发现了mybatisplus的SQL拦截器(其实也是mybatis的)就想着能不能在SQL执行的时候做一些处理以至于可以支持关联查询,于是就动手开始了,目前还只是一个初步的demo,但是一些基本的关联查询功能经过验证是没有问题的 环境信息 jdk: 1.8 springboot: 2.3.4.RELEASE mybatisplus: 3.4.2 lombok:1.18.12 代码设计 代码

  • MyBatis自定义SQL拦截器示例详解

    目录 前言 定义是否开启注解 注册SQL 拦截器 处理逻辑 如何使用 总结 前言 本文主要是讲通过 MyBaits 的 Interceptor 的拓展点进行对 MyBatis 执行 SQL 之前做一个逻辑拦截实现自定义逻辑的插入执行. 适合场景:1. 比如限制数据库查询最大访问条数:2. 限制登录用户只能访问当前机构数据. 定义是否开启注解 定义是否开启注解, 主要做的一件事情就是是否添加 SQL 拦截器. // 全局开启 @Retention(RetentionPolicy.RUNTIME)

  • mybatis-plus多表关联查询功能的实现

    学习目标: mybatis-plus多表关联查询 学习内容: mybatis-plus多表关联查询 实体类部分代码 @Data @AllArgsConstructor @NoArgsConstructor @TableName("wb_member") public class WbMember implements Serializable { private static final long serialVersionUID=1L; /** * 用户ID */ @ApiModel

  • springboot整合mybatis-plus基于注解实现一对一(一对多)查询功能

    因为目前所用mybatis-plus版本为3.1.1,感觉是个半成品,所有在实体类上的注解只能支持单表,没有一对一和一对多关系映射,且该功能还在开发中,相信mybatis-plus开发团队在不久的将来应该会实现此功能. 由于本人开发习惯的原因,实在是太讨厌大量的xml充斥在整个项目中,尤其是表的mapper.xml,虽然有代码生成器可以生成,但是有些复杂的查询还是需要手写配置文件里的动态sql,这点比较反感(至于为什么反感,也是有多方面原因的). 不过可能是大量的java开发人员已经被虐惯了,已

  • AngularJS使用拦截器实现的loading功能完整实例

    本文实例讲述了AngularJS使用拦截器实现的loading功能.分享给大家供大家参考,具体如下: <!DOCTYPE html> <html lang="zh-CN" ng-app="myApp"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge

  • SSM项目使用拦截器实现登录验证功能

    目录 登录接口实现 拦截器类代码实现 配置文件实现 登录接口实现 public User queryUser(String UserName, String Password,HttpServletRequest request, HttpServletResponse response) { User user = userMapper.queryUser(UserName,Password); if(!StringUtils.isEmpty(user)){ //1.获取session Htt

  • Mybatis自定义拦截器和插件开发详解

    前言 在Spring中我们经常会使用到拦截器,在登录验证.日志记录.性能监控等场景中,通过使用拦截器允许我们在不改动业务代码的情况下,执行拦截器的方法来增强现有的逻辑.在mybatis中,同样也有这样的业务场景,有时候需要我们在不侵入原有业务代码的情况下拦截sql,执行特定的某些逻辑.那么这个过程应该怎么实现呢,同样,在mybatis中也为开发者预留了拦截器接口,通过实现自定义拦截器这一功能,可以实现我们自己的插件,允许用户在不改动mybatis的原有逻辑的条件下,实现自己的逻辑扩展. 本文将按

  • 实例讲解Java的MyBatis框架对MySQL中数据的关联查询

    mybatis 提供了高级的关联查询功能,可以很方便地将数据库获取的结果集映射到定义的Java Bean 中.下面通过一个实例,来展示一下Mybatis对于常见的一对多和多对一关系复杂映射是怎样处理的. 设计一个简单的博客系统,一个用户可以开多个博客,在博客中可以发表文章,允许发表评论,可以为文章加标签.博客系统主要有以下几张表构成: Author表:作者信息表,记录作者的信息,用户名和密码,邮箱等. Blog表   :  博客表,一个作者可以开多个博客,即Author和Blog的关系是一对多.

  • Java的Struts框架中Action的编写与拦截器的使用方法

    Struts2 Action/动作 动作是Struts2框架的核心,因为他们的任何MVC(模型 - 视图 - 控制器)框架.每个URL将被映射到一个特定的动作,它提供了来自用户的请求提供服务所需的处理逻辑. 但动作也提供其他两个重要的能力.首先,操作从请求数据的传输中起着重要的作用,通过向视图,无论是一个JSP或其它类型的结果.二,动作必须协助的框架,在确定结果应该渲染视图,在响应该请求将被退回. 创建动作: 在Struts2的动作,唯一的要求是必须有一个无参数的方法返回String或结果的对象

  • 防止未登录用户操作—基于struts2拦截器的简单实现

    一般,我们的web应用都是只有在用户登录之后才允许操作的,也就是说我们不允许非登录认证的用户直接访问某些页面或功能菜单项.我还记得很久以前我的做法:在某个jsp页面中查看session中是否有值(当然,在用户登录逻辑中会将用户名或者用户对象存入session中),如果session中用户信息为空,那么redirect 到登录页面.然后在除了登录页面外的其它所有需要验证用户已登录的页面引入这个jsp . 比如,我们将检查用户是否登录的代码放入一个jsp页面中,如 checkUser.jsp <%@

随机推荐