解决Mybatis-plus高版本不向后兼容的问题
mybatis-plus插件后面的版本没有兼容低版本。即:不存在低版本中EntityWrapper这个类了。而该类采用数据库表真实字段名作查询条件,这样硬编码形式确实不友好,比如如果后面数据库表中字段更名那么所有涉及到的业务都需要去修改,且硬编码形式没有遵循orm映射框架的设计理念。所以mybatis-plus后面的版本已经不支持该类操作了。
但是这样造成一个问题。我们的一个项目开发设计时架构设计者采用了低版本的插件,但是项目进行一半时想要引入新版插件不兼容。要去一个个修改实在太麻烦,网上又没有这方面的文章。所以只能自己摸索出一个解决方案。
解决的第一步大家可以参考这篇文章:https://www.cnblogs.com/java-jun-world2099/articles/11114501.html
本以为就可以大功告成了,但是低高版本的插件内部设计重合度比较高(我并么有一步步去看原理),新的问题一个接一个。最后只能自己重写了BaseMapper和EntityWrapper这两个类。直接看代码好了:
application.yml
server: port: 8088 spring: datasource: url: jdbc:mysql://xx.xx.xx.xxx:3306/ces?useUnicode=true&characterEncoding=utf-8 username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl mapper-locations: classpath*:/mapper/*.xml
pom文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath/> </parent> <groupId>com.bootjar</groupId> <artifactId>shadeboot</artifactId> <version>0.0.1-SNAPSHOT</version> <name>shadeboot</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>shadejar</groupId> <artifactId>plusjar</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-core</artifactId> <version>3.1.1</version> </dependency> <!--<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.1</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>3.1.1</version> </dependency>--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatisplus-spring-boot-starter</artifactId> <version>1.0.5</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.6</version> </dependency> <!--lombok依赖--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.7</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
实体类User
@TableName("user") @Data public class User { @TableId private Long id; private String userName; private Integer age; private String email; private Date birth; }
UserMapper接口
package com.bootjar.shadeboot.mapper; import com.bootjar.shadeboot.entity.BaseMapper; import com.bootjar.shadeboot.entity.User; import org.apache.ibatis.annotations.Mapper; /** * @author:shf date:2019/7/1 10:40 */ @Mapper public interface UserMapper extends BaseMapper<User> { }
EntityWrapper
package com.bootjar.shadeboot.entity; 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.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.ReflectionKit; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.core.toolkit.TableInfoHelper; import java.util.Objects; /** * @author:shf date:2019/7/1 14:13 */ public class EntityWrapper<T> extends com.baomidou.mybatisplus.mapper.EntityWrapper<T> { public T entity; public MergeSegments expression; public String lastSql = ""; @Override public T getEntity() { return this.entity; } @Override public String getSqlSelect() { return null; } public String getSqlSet() { return null; } public MergeSegments getExpression() { return this.expression; } public String getCustomSqlSegment() { MergeSegments expression = this.getExpression(); if (Objects.nonNull(expression)) { NormalSegmentList normal = expression.getNormal(); String sqlSegment = this.getSqlSegment(); if (StringUtils.isNotEmpty(sqlSegment)) { if (normal.isEmpty()) { return sqlSegment; } return this.concatWhere(sqlSegment); } } return ""; } @Override public String getSqlSegment() { String sqlSegment = ""; String sqlWhere = ""; if (this.expression != null) { sqlSegment = this.expression.getSqlSegment(); } else if (this.sql != null) { sqlWhere = this.sql.toString(); } if (StringUtils.isNotEmpty(sqlSegment)) { return sqlSegment + this.lastSql; } else if (com.baomidou.mybatisplus.toolkit.StringUtils.isNotEmpty(sqlWhere)) { // return this.isWhere != null ? (this.isWhere ? sqlWhere : sqlWhere.replaceFirst("WHERE", this.AND_OR)) : sqlWhere.replaceFirst("WHERE", this.AND_OR); return sqlWhere; } else { return StringUtils.isNotEmpty(this.lastSql) ? this.lastSql : null; } } private String concatWhere(String sql) { return "WHERE " + sql; } @Override public boolean isEmptyOfWhere() { return this.isEmptyOfNormal() && this.isEmptyOfEntity(); } public boolean nonEmptyOfWhere() { return !this.isEmptyOfWhere(); } public boolean isEmptyOfNormal() { if(this.getExpression() != null){ return CollectionUtils.isEmpty(this.getExpression().getNormal()); } return true; } public boolean nonEmptyOfNormal() { return !this.isEmptyOfNormal(); } public boolean nonEmptyOfEntity() { T entity = this.getEntity(); if (entity == null) { return false; } else { TableInfo tableInfo = TableInfoHelper.getTableInfo(entity.getClass()); if (tableInfo == null) { return false; } else if (tableInfo.getFieldList().stream().anyMatch((e) -> { return this.fieldStrategyMatch(entity, e); })) { return true; } else { return StringUtils.isNotEmpty(tableInfo.getKeyProperty()) ? Objects.nonNull(ReflectionKit.getMethodValue(entity, tableInfo.getKeyProperty())) : false; } } } private boolean fieldStrategyMatch(T entity, TableFieldInfo e) { switch (e.getFieldStrategy()) { case NOT_NULL: return Objects.nonNull(ReflectionKit.getMethodValue(entity, e.getProperty())); case IGNORED: return true; case NOT_EMPTY: return StringUtils.checkValNotNull(ReflectionKit.getMethodValue(entity, e.getProperty())); default: return Objects.nonNull(ReflectionKit.getMethodValue(entity, e.getProperty())); } } public boolean isEmptyOfEntity() { return !this.nonEmptyOfEntity(); } }
BaseMapper
package com.bootjar.shadeboot.entity; import com.baomidou.mybatisplus.mapper.Wrapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.session.RowBounds; import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.Map; /** * @author:shf date:2019/7/1 13:17 */ public interface BaseMapper<T> extends com.baomidou.mybatisplus.core.mapper.BaseMapper<T> { int insert(T var1); Integer insertAllColumn(T var1); int deleteById(Serializable var1); int deleteByMap(@Param("cm") Map<String, Object> var1); Integer delete(@Param("ew") Wrapper<T> var1); int deleteBatchIds(@Param("coll") Collection<? extends Serializable> var1); int updateById(@Param("et") T var1); Integer updateAllColumnById(@Param("et") T var1); Integer update(@Param("et") T var1, @Param("ew") Wrapper<T> var2); T selectById(Serializable var1); List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> var1); List<T> selectByMap(@Param("cm") Map<String, Object> var1); T selectOne(@Param("ew") T var1); Integer selectCount(@Param("ew") Wrapper<T> var1); List<T> selectList(@Param("ew") Wrapper<T> var1); List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> var1); List<Object> selectObjs(@Param("ew") Wrapper<T> var1); List<T> selectPage(RowBounds var1, @Param("ew") Wrapper<T> var2); List<Map<String, Object>> selectMapsPage(RowBounds var1, @Param("ew") Wrapper<T> var2); }
测试类ShadebootApplicationTests
package com.bootjar.shadeboot; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.bootjar.shadeboot.entity.EntityWrapper; import com.bootjar.shadeboot.entity.User; import com.bootjar.shadeboot.mapper.UserMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.HashMap; import java.util.List; import java.util.Map; @RunWith(SpringRunner.class) @SpringBootTest public class ShadebootApplicationTests { @Autowired private UserMapper userMapper; //@Autowired //private UserCopyMapper userCopyMapper; @Test public void contextLoads() { User user = userMapper.selectById("1"); System.out.println("--------------------user:" + user); EntityWrapper<User> itemWrapper = new EntityWrapper<>(); itemWrapper.where("user_name = {0}", "Jack").eq("age", "20"); List<User> itemsEntities = userMapper.selectList(itemWrapper); System.out.println("----------------itemsEntities :" + itemsEntities); LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>() .eq(User::getUserName, "Jack").last("ORDER BY id DESC"); List<User> userList = userMapper.selectList(queryWrapper); System.out.println("----------------userList:" + userList); } @Test public void insertTest() { User user = new User(); user.setUserName("dada"); userMapper.insert(user); } @Test public void MapTest() { Map map = new HashMap(); map.put("user_name", "1q"); map.put("age", 18); List<User> MapList = userMapper.selectByMap(map); System.out.println("--------------------------MapList:" + MapList); } }
以上测试方法均通过,这是contextLoads方法的测试结果:
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7718a40f] will not be managed by Spring ==> Preparing: SELECT id,user_name,age,email,birth FROM user WHERE id=? ==> Parameters: 1(String) <== Columns: id, user_name, age, email, birth <== Row: 1, 1q, 18, test1@baomidou.com, 2019-01-01 <== Total: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@397ef2] --------------------user:User(id=1, userName=1q, age=18, email=test1@baomidou.com, birth=Tue Jan 01 14:00:00 CST 2019) Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1229a2b7] was not registered for synchronization because synchronization is not active JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7718a40f] will not be managed by Spring ==> Preparing: SELECT id,user_name,age,email,birth FROM user WHERE (user_name = ? OR age = ?) ==> Parameters: Jack(String), 20(String) <== Columns: id, user_name, age, email, birth <== Row: 2, Jack, 20, test2@baomidou.com, 2019-01-01 <== Row: 7, Jack, 24, test5@baomidou.com, 2019-01-01 <== Row: 8, Jack, 24, test5@baomidou.com, 2019-01-01 <== Row: 9, Jack, 24, test5@baomidou.com, 2019-01-01 <== Total: 4 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1229a2b7] ----------------itemsEntities :[User(id=2, userName=Jack, age=20, email=test2@baomidou.com, birth=Tue Jan 01 14:00:00 CST 2019), User(id=7, userName=Jack, age=24, email=test5@baomidou.com, birth=Tue Jan 01 14:00:00 CST 2019), User(id=8, userName=Jack, age=24, email=test5@baomidou.com, birth=Tue Jan 01 14:00:00 CST 2019), User(id=9, userName=Jack, age=24, email=test5@baomidou.com, birth=Tue Jan 01 14:00:00 CST 2019)] Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4d95a72e] was not registered for synchronization because synchronization is not active JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7718a40f] will not be managed by Spring ==> Preparing: SELECT id,user_name,age,email,birth FROM user WHERE user_name = ? AND ( age LIKE ? ) ORDER BY id DESC ==> Parameters: Jack(String), %24%(String) <== Columns: id, user_name, age, email, birth <== Row: 9, Jack, 24, test5@baomidou.com, 2019-01-01 <== Row: 8, Jack, 24, test5@baomidou.com, 2019-01-01 <== Row: 7, Jack, 24, test5@baomidou.com, 2019-01-01 <== Total: 3 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4d95a72e] ----------------userList:[User(id=9, userName=Jack, age=24, email=test5@baomidou.com, birth=Tue Jan 01 14:00:00 CST 2019), User(id=8, userName=Jack, age=24, email=test5@baomidou.com, birth=Tue Jan 01 14:00:00 CST 2019), User(id=7, userName=Jack, age=24, email=test5@baomidou.com, birth=Tue Jan 01 14:00:00 CST 2019)] 2019-07-01 16:12:07.160 INFO 17744 --- [ Thread-2] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' 2019-07-01 16:12:07.164 INFO 17744 --- [ Thread-2] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closed Process finished with exit code 0