Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities.
Recently we have seen some new uses of the universal Mapper. Note the related uses of the universal Mapper
Official documents:
Gitee.com/free/Mapper…
Introduction to general purpose Mapper
General Mapper is a framework that can implement any MyBatis general method. The project provides routine add, delete, change and query operations as well as Example related single table operations. General Mapper is to solve 90% of the basic operations in the use of MyBatis, using it can be very convenient for development, can save a lot of time for developers.
General Mapper can be through Mybatis interceptor principle, dynamic to help us achieve a single table to add, delete, change, check function.
2 General principles of Mapper
To see how this works, start with the generic methods provided in the generic Mapper
/** * universal Mapper interface, query **@param<T> cannot be empty *@author liuzh
*/
@RegisterMapper
public interface SelectMapper<T> {
/** * Query according to the attribute value of the entity, the query condition uses equal sign **@param record
* @return* /
@SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL")
List<T> select(T record);
}
Copy the code
SelectMapper interfaces and methods use generic types, which need to be specified. Reflection makes it easy to get the type information of a generic interface
Type[] types = mapperClass.getGenericInterfaces(); Class<? > entityClass =null;
for (Type type : types) {
if (type instanceof ParameterizedType) {
ParameterizedType t = (ParameterizedType) type;
// Check whether the parent interface is selectMapper.class
if (t.getRawType() == SelectMapper.class) {
// Get the generic typeentityClass = (Class<? >) t.getActualTypeArguments()[0];
break; }}}Copy the code
JPA annotations added to the entity class are simply a means of mapping the relationship between the entity and the database table, which can be easily set up with some default rules or custom annotations. Once the mapping between the entity and the table is obtained, the same SQL code as in XML can be generated based on the functionality defined by the common interface method
SelectProvider: BasesElectProvider.class = basesElectProvider.class
/** * BaseSelectProvider implementation class, base method implementation class **@author liuzh
*/
public class BaseSelectProvider extends MapperTemplate {
public BaseSelectProvider(Class
mapperClass, MapperHelper mapperHelper) {
super(mapperClass, mapperHelper);
}
/** ** query **@param ms
* @return* /
public String selectOne(MappedStatement ms) { Class<? > entityClass = getEntityClass(ms);// Change the return value type to the entity type
setResultType(ms, entityClass);
StringBuilder sql = new StringBuilder();
sql.append(SqlHelper.selectAllColumns(entityClass));
sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty()));
return sql.toString();
}
/** ** query **@param ms
* @return* /
public String select(MappedStatement ms) { Class<? > entityClass = getEntityClass(ms);// Change the return value type to the entity type
setResultType(ms, entityClass);
StringBuilder sql = new StringBuilder();
sql.append(SqlHelper.selectAllColumns(entityClass));
sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty()));
sql.append(SqlHelper.orderByDefault(entityClass));
return sql.toString();
}
/** ** query **@param ms
* @return* /
public String selectByRowBounds(MappedStatement ms) {
return select(ms);
}
/** * query by primary key **@param ms
*/
public String selectByPrimaryKey(MappedStatement ms) {
finalClass<? > entityClass = getEntityClass(ms);// Change the return value to the entity type
setResultType(ms, entityClass);
StringBuilder sql = new StringBuilder();
sql.append(SqlHelper.selectAllColumns(entityClass));
sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
sql.append(SqlHelper.wherePKColumns(entityClass));
return sql.toString();
}
/** * query total number **@param ms
* @return* /
public String selectCount(MappedStatement ms) { Class<? > entityClass = getEntityClass(ms); StringBuilder sql =new StringBuilder();
sql.append(SqlHelper.selectCount(entityClass));
sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty()));
return sql.toString();
}
/** * query total number of primary keys **@param ms
* @return* /
public String existsWithPrimaryKey(MappedStatement ms) { Class<? > entityClass = getEntityClass(ms); StringBuilder sql =new StringBuilder();
sql.append(SqlHelper.selectCountExists(entityClass));
sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
sql.append(SqlHelper.wherePKColumns(entityClass));
return sql.toString();
}
/** * query all results **@param ms
* @return* /
public String selectAll(MappedStatement ms) {
finalClass<? > entityClass = getEntityClass(ms);// Change the return value type to the entity type
setResultType(ms, entityClass);
StringBuilder sql = new StringBuilder();
sql.append(SqlHelper.selectAllColumns(entityClass));
sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
// Undeleted query conditions for logical deletion
sql.append("<where>");
sql.append(SqlHelper.whereLogicDelete(entityClass, false));
sql.append("</where>");
sql.append(SqlHelper.orderByDefault(entityClass));
returnsql.toString(); }}Copy the code
In MyBatis, each method (annotation or XML) is processed and eventually constructed as an MappedStatement object.
Using the @selectProvider definition, we construct a ProviderSqlSource, which is an intermediate SqlSource and cannot itself be used as the SqlSource for the final execution. The StaticSqlSource is a static SQL that supports #{param} arguments, but does not support
. The < where > tag, etc
The general-purpose Mapper starts here by using the ProviderSqlSource to generate a normal MappedStatement. After the MappedStatement is generated, the ProviderSqlSource is replaced.
Interface method according to the MS ID (in the specification case, the interface name. Method name) to obtain the interface, through the interface generics can obtain the entityClass (entityClass), according to the relationship between the entity and the table we can spell out dynamic SQL XML
/** * query all results **@param ms
* @return* /
public String selectAll(MappedStatement ms) {
finalClass<? > entityClass = getEntityClass(ms);// Change the return value type to the entity type
setResultType(ms, entityClass);
StringBuilder sql = new StringBuilder();
sql.append(SqlHelper.selectAllColumns(entityClass));
sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
// Undeleted query conditions for logical deletion
sql.append("<where>");
sql.append(SqlHelper.whereLogicDelete(entityClass, false));
sql.append("</where>");
sql.append(SqlHelper.orderByDefault(entityClass));
return sql.toString();
}
Copy the code
The SqlSource can be generated using the createSqlSource method in XMLLanguageDriver of Mybatis. Then use reflection to replace the ProviderSqlSource with the new SqlSource.
Tk, mybatis mapper. Mapperhelper. MapperTemplate general mapper template classes
/** * reset SqlSource **@param ms
* @param sqlSource
*/
protected void setSqlSource(MappedStatement ms, SqlSource sqlSource) {
MetaObject msObject = MetaObjectUtil.forObject(ms);
msObject.setValue("sqlSource", sqlSource);
}
Copy the code
3 Universal Mapper
The universal Mapper provides some basic methods for adding, deleting, modifying, and checking:
New / / 1
// Mapper interface provides only basic add, delete, modify, and query. Batch add needs to use MySqlMapper interface, which inherits from InsertListMapper interface
userMapper.insert(new User());
userMapper.insertSelective(new User());
userMapper.insertList(new ArrayList<User>());
/ / 2
userMapper.updateByPrimaryKey(new User());
userMapper.updateByPrimaryKeySelective(new User());
userMapper.updateByExample(new User(), new Example(User.class));
userMapper.updateByExampleSelective(new User(), new Example(User.class));
Delete / / 3
userMapper.delete(new User());
userMapper.deleteByPrimaryKey("id");
userMapper.deleteByExample(new Example(User.class));
/ / 4 queries
userMapper.selectAll();
userMapper.select(new User());
userMapper.selectOne(new User());
userMapper.selectByExample(new Example(User.class));
Copy the code
0 Preparing the database
-- Build a predicate sentence
CREATE TABLE `user` (
`id` int NOT NULL COMMENT 'primary key',
`username` varchar(64) DEFAULT NULL COMMENT 'name',
`phone` varchar(64) DEFAULT NULL COMMENT 'phone',
`icon` varchar(255) DEFAULT NULL COMMENT 'binary'.PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='User table';
Add data
INSERT INTO `test`.`user`(`id`, `username`, `phone`, `icon`) VALUES (1.'Seven Plums'.'77777'.'The Head of Li Ziqi');
INSERT INTO `test`.`user`(`id`, `username`, `phone`, `icon`) VALUES (2.'2'.'2'.'world');
INSERT INTO `test`.`user`(`id`, `username`, `phone`, `icon`) VALUES (3.'3'.'3'.'3333');
INSERT INTO `test`.`user`(`id`, `username`, `phone`, `icon`) VALUES (5.'5'.'5'.'123adb');
INSERT INTO `test`.`user`(`id`, `username`, `phone`, `icon`) VALUES (7.'5'.'5'.'Hello Chinese characters');
Copy the code
1 Create a SpringBoot environment
2 Add maven dependencies
<! -- https://mvnrepository.com/artifact/tk.mybatis/mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>4.1.5</version>
</dependency>
<! Mybatis and Spring integration -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<! MySQL database driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Copy the code
3 Add the configuration file
spring.datasource.url=jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
Copy the code
4 Add an entity class
@Data
@Table(name = "user")
public class User {
@Id
private String id;
@Column
private String username;
@Column
private String phone;
@Column
private String icon;
@Transient
private Date queryTime = new Date();
}
Copy the code
5 Add a Mapper interface
// MySqlMapper interface mainly uses batch new function
public interface UserMapper extends Mapper<User>, MySqlMapper<User> {}Copy the code
6 Add controller Controllers
@Controller
@RequestMapping("/helloworld")
public class HelloWorld {
@Autowired
private UserMapper userMapper;
@GetMapping("/queryByCondition")
@ResponseBody
public String queryByCondition(@RequestParam("keyword") String keyword) {
// Use example to query complex relationships
// 1 example can query the fields you need and set the sorting rule (optional, default is to query all, no sorting condition)
Example example = new Example(User.class);
example.selectProperties("id"."phone"."icon")
.orderBy("id")
.desc();
// 2 Fuzzy query needs to spell % (mybatis-plus does not need)
example.createCriteria()
.andLike("username"."%" + keyword + "%")
.orEqualTo("phone", keyword);
List<User> users = userMapper.selectByExample(example);
System.out.println(users);
return "<h1>Hello Wrold</h1>"; }}Copy the code
7 Add a startup class
@MapperScan("com.cf.demo.mapper")
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }}Copy the code
8 test
Access from the local browser
Son: http://localhost:8080/helloworld/queryByCondition?keyword=
Browser page display:
Hello Wrold
Console display:
[User(id=1, username=null, phone=77777, icon= queryTime=Mon Oct 25 19:25:44 CST 2021)]Copy the code