The article directories
- Paging query
-
- Common paging
- Automatically fill in new time, update time, operator and other attributes
- Custom field types
-
- Automatically map Json data
- Automatically map spatial data formats
- Customize the Controller template
-
- Custom code templates
- Custom property injection
- Available parameters from the framework
- The template to modify
- Data permission implementation
- Lambda conditional constructor
-
- General Wrapper
- QueryWrapper
- UpdateWrapper
Spring Boot integration Mybatis- Plus
Paging query
First configure the paging plug-in
MybatisConfiguration#useDeprecatedExecutor = false to avoid cache problems (this property will be removed when the old plugin is removed) */
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(a) {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer(a) {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
Copy the code
Common paging
Example code for paging queries
@GetMapping
public Response pageAll(@RequestParam(required = false, defaultValue = "1") long current,
@RequestParam(required = false, defaultValue = "10") long size,
String roadName) {
Page roadPage = new Page<>(current, size);
LambdaQueryWrapper<Road> queryWrapper = new QueryWrapper().lambda();
queryWrapper.like(StringUtils.isNotBlank(roadName), Road::getRoadName, roadName);
Page pageList = roadService.page(roadPage, queryWrapper);
return Response.ok(pageList);
}
Copy the code
Automatically fill in new time, update time, operator and other attributes
- First of all,To implement the meta-object processor interface:
com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) { When Mapper calls insert, it does the following
log.info("start insert fill ...."); // Set the value for the entity property
this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class);
this.strictInsertFill(metaObject, "operator", String.class, "Zhang");
}
@Override
public void updateFill(MetaObject metaObject) {Mapper performs the following operations when calling the update operation
log.info("start update fill ...."); // Set the value for the entity property
this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class);
this.strictUpdateFill(metaObject, "operator", String.class, "Zhang"); }}Copy the code
The default methods provided by MetaObjectHandler have the following strategies:
- If the attribute has a value, it is not overridden.
- If the fill-in value is zero
null
Is not filled.
- Second, annotate the corresponding entity class
Note: Specify that this attribute must have a value in the case, or null if there is no value
The field must declare the TableField annotation, and the attribute fill selects the corresponding policy. This declaration tells Mybatis-Plus that it needs to reserve the injection of SQL fields
How to determine if the injected SQL scripts for insert and UPDATE omit the if tag of the fields in the corresponding case…
@Data
@EqualsAndHashCode(callSuper = false)
public class Stake implements Serializable {
private Long roadId;
private String stakeName;
@TableField(fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@TableField(fill = FieldFill.UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private String operator;
}
Copy the code
The overall principle
-
When an INSERT or update SQL script occurs
-
Take a look at the annotation of the corresponding field in the entity where the relevant SQL is currently occurring
- annotations
FieldFill.INSERT
, that is, dynamic add<if test="..." >... </if>
Insert related field - annotations
FieldFill.UPDATE
, that is, dynamic add<if test="..." >... </if>
Update related fields - annotations
FieldFill.UPDATE
, that is, dynamic add<if test="..." >... </if>
Insert and UPDATE related fields
- annotations
Custom field types
Type handler, used for converting between JavaType and JdbcType, used to set parameter values in PreparedStatement and fetch a value from a ResultSet or CallableStatement. This article explains how the myBaitS-Plus built-in common type processor can be quickly injected into myBatis containers via TableField annotations.
If an error is reported in XML with 5 custom handlers, delete the XML or configure it in XML as well
Automatically map Json data
@Data
@Accessors(chain = true)
@TableName(autoResultMap = true)
public class User {
private Long id;
/** * attention!! Mapping annotations must be enabled * *@TableName(autoResultMap = true) * * Either of the following two types of processors can exist simultaneously * * Note!! Selecting the corresponding JSON processor must also have the corresponding JSON parsing dependency package */
@TableField(typeHandler = JacksonTypeHandler.class)
// @TableField(typeHandler = FastjsonTypeHandler.class)
private OtherInfo otherInfo;
}
Copy the code
This annotation corresponds to the XML notation for
<result column="other_info" jdbcType="VARCHAR" property="otherInfo" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler" />
Copy the code
Automatically map spatial data formats
Mybatis custom field types take Mysql space data store as an example
@Data
@EqualsAndHashCode(callSuper = false)
@TableName( autoResultMap = true)
public class ServiceArea implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/** * Latitude and longitude format: X,Y */
@TableField(typeHandler = JacksonTypeHandler.class)
private double[] location;
@TableField(typeHandler = GeoPointTypeHandler.class)
private GeoPoint coordinate;
}
Copy the code
Customize the Controller template
Custom code templates
/ / specify custom templates path, location: / resources/templates/entity2. Java. FTL (or vm).
// Be careful not to include.ftl(or.vm), which is automatically identified according to the template engine used
TemplateConfig templateConfig = new TemplateConfig()
.setEntity("templates/entity2.java");
AutoGenerator mpg = new AutoGenerator();
// Configure a custom template
mpg.setTemplate(templateConfig);
Copy the code
Custom property injection
InjectionConfig injectionConfig = new InjectionConfig() {
// Custom attribute injection: ABC
// In the.ftl(or.vm) template, get the attributes with ${cfg. ABC}
@Override
public void initMap(a) {
Map<String, Object> map = new HashMap<>();
map.put("abc".this.getConfig().getGlobalConfig().getAuthor() + "-mp");
this.setMap(map); }}; AutoGenerator mpg =new AutoGenerator();
// Configure custom attribute injection
mpg.setCfg(injectionConfig);
Copy the code
Entity2.java.ftl custom attribute injection ABC =${cfg. ABC} Entity2.java.vm custom attribute injection ABC =$! {cfg.abc}Copy the code
Available parameters from the framework
Github AbstractTemplateEngine class getObjectMap returns all values of objectMap available.
/** * Render object MAP information **@paramTableInfo Table information object *@return ignore
*/
public Map<String, Object> getObjectMap(TableInfo tableInfo) {
Map<String, Object> objectMap;
ConfigBuilder config = getConfigBuilder();
if (config.getStrategyConfig().isControllerMappingHyphenStyle()) {
objectMap = CollectionUtils.newHashMapWithExpectedSize(33);
objectMap.put("controllerMappingHyphenStyle", config.getStrategyConfig().isControllerMappingHyphenStyle());
objectMap.put("controllerMappingHyphen", StringUtils.camelToHyphen(tableInfo.getEntityPath()));
} else {
objectMap = CollectionUtils.newHashMapWithExpectedSize(31);
}
objectMap.put("restControllerStyle", config.getStrategyConfig().isRestControllerStyle());
objectMap.put("config", config);
objectMap.put("package", config.getPackageInfo());
GlobalConfig globalConfig = config.getGlobalConfig();
objectMap.put("author", globalConfig.getAuthor());
objectMap.put("idType", globalConfig.getIdType() == null ? null : globalConfig.getIdType().toString());
objectMap.put("logicDeleteFieldName", config.getStrategyConfig().getLogicDeleteFieldName());
objectMap.put("versionFieldName", config.getStrategyConfig().getVersionFieldName());
objectMap.put("activeRecord", globalConfig.isActiveRecord());
objectMap.put("kotlin", globalConfig.isKotlin());
objectMap.put("swagger2", globalConfig.isSwagger2());
objectMap.put("date".new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
objectMap.put("table", tableInfo);
objectMap.put("enableCache", globalConfig.isEnableCache());
objectMap.put("baseResultMap", globalConfig.isBaseResultMap());
objectMap.put("baseColumnList", globalConfig.isBaseColumnList());
objectMap.put("entity", tableInfo.getEntityName());
objectMap.put("entitySerialVersionUID", config.getStrategyConfig().isEntitySerialVersionUID());
objectMap.put("entityColumnConstant", config.getStrategyConfig().isEntityColumnConstant());
objectMap.put("entityBuilderModel", config.getStrategyConfig().isEntityBuilderModel());
objectMap.put("chainModel", config.getStrategyConfig().isChainModel());
objectMap.put("entityLombokModel", config.getStrategyConfig().isEntityLombokModel());
objectMap.put("entityBooleanColumnRemoveIsPrefix", config.getStrategyConfig().isEntityBooleanColumnRemoveIsPrefix());
objectMap.put("superEntityClass", getSuperClassName(config.getStrategyConfig().getSuperEntityClass()));
objectMap.put("superMapperClassPackage", config.getStrategyConfig().getSuperMapperClass());
objectMap.put("superMapperClass", getSuperClassName(config.getStrategyConfig().getSuperMapperClass()));
objectMap.put("superServiceClassPackage", config.getStrategyConfig().getSuperServiceClass());
objectMap.put("superServiceClass", getSuperClassName(config.getStrategyConfig().getSuperServiceClass()));
objectMap.put("superServiceImplClassPackage", config.getStrategyConfig().getSuperServiceImplClass());
objectMap.put("superServiceImplClass", getSuperClassName(config.getStrategyConfig().getSuperServiceImplClass()));
objectMap.put("superControllerClassPackage", verifyClassPacket(config.getStrategyConfig().getSuperControllerClass()));
objectMap.put("superControllerClass", getSuperClassName(config.getStrategyConfig().getSuperControllerClass()));
return Objects.isNull(config.getInjectionConfig()) ? objectMap : config.getInjectionConfig().prepareObjectMap(objectMap);
}
Copy the code
The template to modify
${table.serviceName? substring(1)}
– Delete the initial letter${table.serviceName? uncap_first}
– Write the first letter in smaller capitals
packageThe ${package.Controller};
import org.springframework.web.bind.annotation.RequestMapping;
importThe ${package.Entity}.${entity};
importThe ${package.Service}.${table.serviceName}; < #if restControllerStyle>
importorg.springframework.web.bind.annotation.RestController; < #else>
importorg.springframework.stereotype.Controller; < / #if>
import com.laker.map.ext.framework.Response;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.*; < #ifsuperControllerClassPackage?? >import${superControllerClassPackage}; < / #if>
/** * <p> * ${table.comment! } Front-end controller * </p> * *@author ${author}
* @since ${date}
*/< #if restControllerStyle>
@RestController< #else>
@Controller< / #if>
@RequestMapping("<#if package.ModuleName?? && package.ModuleName ! = "">/${package.ModuleName}
/<#if controllerMappingHyphenStyle?? >${controllerMappingHyphen}<#else>${table.entityPath}
")< #ifsuperControllerClass?? >public class ${table.controllerName} extends ${superControllerClass} {
<#else>
public class ${table.controllerName} {
</#if>
@Autowired${table.serviceName} ${table.serviceName? substring(1)? uncap_first};@GetMapping
@ApiOperation(value = "${table.comment! } ")
public Response pageAll(@RequestParam(required = false, defaultValue = "1") long current,
@RequestParam(required = false, defaultValue = "10") long size) {
Page roadPage = new Page<>(current, size);
LambdaQueryWrapper<${table.entityName}> queryWrapper = newQueryWrapper().lambda(); Page pageList = ${table.serviceName? substring(1)? uncap_first}.page(roadPage, queryWrapper);return Response.ok(pageList);
}
@PostMapping
@apiOperation (value = "${table.comment! } ")
public Response saveOrUpdate(${table.entityName} param) {
returnResponse.ok(${table.serviceName? substring(1)? uncap_first}.saveOrUpdate(param)); }@GetMapping("/{id}")
@apiOperation (value = "${table.comment! } ")
public Response get(@PathVariable Long id) {
returnResponse.ok(${table.serviceName? substring(1)? uncap_first}.getById(id)); }@DeleteMapping("/{id}")
@apiOperation (value = "${table.comment! } ")
public Response delete(@PathVariable Long id) {
returnResponse.ok(${table.serviceName? substring(1)?uncap_first}.removeById(id));
}
}
Copy the code
Data permission implementation
Look at my other blog post, which details how to build a development scaffolding from scratch based on Mybatis-Plus data permissions
Lambda conditional constructor
The parent classes of QueryWrapper(LambdaQueryWrapper) and UpdateWrapper(LambdaUpdateWrapper) are used to generate WHERE conditions for SQL, Entity attributes are also used to generate SQL WHERE conditions Note: The WHERE conditions generated by entity do not have any behavior associated with where conditions generated using the various apis
The Lambda conditional constructor is recommended to reflect the call relationship directly when the property changes. Not a static string configuration like QueryWrapper
Lambda conditional constructor:
Page roadPage = new Page<>(current, size);
LambdaQueryWrapper<Board> queryWrapper = newQueryWrapper().lambda(); queryWrapper.eq(roadId ! =null, Board::getRoadId, roadId); queryWrapper.eq(deptId ! =null, Board::getDeptId, deptId);
Page pageList = boardService.page(roadPage, queryWrapper);
Copy the code
Normal conditional constructor:
Page roadPage = new Page<>(current, size);
QueryWrapper<Board> queryWrapper = newQueryWrapper(); queryWrapper.eq(roadId ! =null."road_id", roadId); queryWrapper.eq(deptId ! =null."dept_id", deptId);
Page pageList = boardService.page(roadPage, queryWrapper);
Copy the code
General Wrapper
conditions | explain | example |
---|---|---|
allEq | All are equal | Case 1:AllEq ({id: 1, name: "wang", the age: null}) — – >Id = 1 and name = 'old' and age is null Example 2:AllEq ({id:1, age:null}, false) — – >Id = 1 and id = 1 |
eq | Equal to = | Eq (” name “, “Lao Wang”)---> Name = ‘Lao Wang’ |
ne | Is not the same as < > | Ne (” Name “, “Lao Wang”)---> Name <> ‘Lao Wang’ |
gt | More than > | Gt (” age “, 18)---> age > 18 |
ge | The value is greater than or equal to >= | Ge (” age “, 18)---> age >= 18 |
lt | < < | 18) lt (” age “,---> age < 18 |
le | Less than or equal to <= | Le (” age “, 18)---> age <= 18 |
between | BETWEEN values 1 AND 2 | Between (” age “, 18, 30)---> age between 18 and 30 |
notBetween | NOT BETWEEN The value is 1 AND 2 | NotBetween (” age “, 18, 30)---> age not between 18 and 30 |
like | Values LIKE ‘% %’ | The like (” name “, “the king”)---> Name like ‘% king %’ |
notLike | NOT LIKE ‘% value %’ | NotLike (” name “, “the king”)---> Name not like ‘% king %’ |
likeLeft | Values LIKE ‘%’ | LikeLeft (” name “, “the king”)---> Name like ‘% king’ |
likeRight | Values LIKE ‘%’ | LikeRight (” name “, “the king”)---> Name like ‘king %’ |
isNull | Field IS NULL | IsNull (” name “)---> name is null |
isNotNull | The field IS NOT NULL | IsNotNull (” name “)---> name is not null |
in | IN (value.get(0), value.get(1),… | In (” age “, {1, 2, 3})---> The age in (1, 2, 3) |
notIn | NOT IN (value.get(0), value.get(1),… | NotIn (” age “, {1, 2, 3})---> The age not in (1, 2, 3) |
inSql | Field IN (SQL statement) | Ex. :InSql (" age ", "6") — – >The age in (6) Ex. :inSql("id", "select id from table where id < 3") — – >id in (select id from table where id < 3) |
notInSql | Field NOT IN (SQL statement) | Ex. :NotInSql (" age ", "6") — – >The age not in (6) Ex. :notInSql("id", "select id from table where id < 3") — – >id not in (select id from table where id < 3) |
groupBy | Grouping: GROUP BY field… | GroupBy (” id “, “name”)---> group by id,name |
orderByAsc | Sort: ORDER BY… ASC | OrderByAsc (” id “, “name”)---> order by id ASC,name ASC |
orderByDesc | Sort: ORDER BY… DESC | Ex. :orderByDesc("id", "name") — – >order by id DESC,name DESC |
orderBy | Sort: ORDER BY… | Ex. :orderBy(true, true, "id", "name") — – >order by id ASC,name ASC |
having | HAVING (SQL statement) | Ex. :having("sum(age) > 10") — – >having sum(age) > 10 Ex. :having("sum(age) > {0}", 11) — – >having sum(age) > 11 |
func | Func method (mainly convenient in the presence of if… Else call can be repeated in different ways) | Ex. :func(i -> if(true) {i.eq("id", 1)} else {i.ne("id", 1)}) |
The or joining together the or | Take the initiative to callor It means immediately after the nextmethodsNot withand Connection! (don’t callor The default value is Yesand Connection) |
Eq. (” id “, 1) or (.) eq (” name “, “king”)---> Id = 1 or id = 1 |
The OR nested OR | Or (I -> I.E Q (” name “, “Li Bai”).ne(” Status “, “Alive”)---> Or (name = ‘id’ and status <> ‘id’) |
|
and | AND nested | Ex. :And (I -> I.E Q ("name", "Li Bai ").ne("status"," alive ") — – >And (name = 'id' and status = 'id ') |
nested | Normal nesting does not include AND OR OR | Nested (I – > appropriate precautions q (” name “, “li bai”). Ne (” status “, “alive”))---> (name = ‘李白’ and status <> ‘活着’) |
apply | Concatenate SQL, which can be used for databasesfunctionDynamically enteredparams In front of the correspondingapplySql The inside of the{index} This is not SQL injection risk, on the contrary there will be! |
Ex. :apply("id = 1") — – >id = 1 Ex. :apply("date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'") — – >date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'") Ex. :apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08") — – >date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'") |
last | Ignore the optimization rules and directly concatenate the last SQL invocation only once. If you invoke the last SQL invocation multiple times, SQL injection risks. Exercise caution when using this command | last("limit 1") |
exists | Concatenate EXISTS (SQL statement) | Ex. :exists("select id from table where age = 1") — – >exists (select id from table where age = 1) |
notExists | Concatenate NOT EXISTS | Ex. :notExists("select id from table where age = 1") — – >not exists (select id from table where age = 1) |
QueryWrapper
type | explain | example |
---|---|---|
select | Setting query fields | Ex. :select("id", "name", "age") Ex. :select(i -> i.getProperty().startsWith("test")) |
UpdateWrapper
type | explain | example |
---|---|---|
set | SQL SET field | Ex. :Set ("name", "Lao Li tou ") Ex. :set("name", "") – > The database field value changes toAn empty stringEx. :set("name", null) – > The database field value changes tonull |
setSql | SET part of SET SQL | Ex. :SetSql ("name = 'name') |