Ce guide détaille les étapes nécessaires pour intégrer MyBatis-Plus dans un projet backend Ruoyi-Vue.
- Ajout de MyBatis-Plus au POM principal
Il est mensionné dans certaines documentations d'ajouter également PageHelper. Cependant, le projet backend Ruoyi-Vue inclut déjà PageHelper, donc cette étape est omise.
Définissez les versions pour MyBatis-Plus et Lombok :
<mybatis-plus.version>3.5.2</mybatis-plus.version>
<lombok.version>1.18.12</lombok.version>
Ajoutez les dépendances au fichier POM prinicpal :
<!-- Dépendance MyBatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
- Inclusion de MyBatis-Plus dans le POM de
ruoyi-common
Ajoutez les dépendances suivantes au fichier POM du module ruoyi-common :
<!-- Dépendance MyBatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
- Intégration de MyBatis-Plus dans le POM de
ruoyi-framework
Ajoutez les dépendances suivantes au fichier POM du module ruoyi-framework :
<!-- MyBatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
Dans le répertoire ruoyi-framework/src/main/java/com/ruoyi/framework/config, supprimez la classe MybatisConfig et créez la classe MybatisPlusConfig avec le contenu suivant :
package com.ruoyi.framework.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@Configuration
public class MybatisPlusConfig {
private static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
@Autowired
private Environment env;
public static String setTypeAliasesPackage(String typeAliasesPackage) {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
List<String> allResult = new ArrayList<>();
try {
for (String aliasesPackage : typeAliasesPackage.split(",")) {
List<String> result = new ArrayList<>();
aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
Resource[] resources = resolver.getResources(aliasesPackage);
if (resources != null && resources.length > 0) {
MetadataReader metadataReader;
for (Resource resource : resources) {
if (resource.isReadable()) {
metadataReader = metadataReaderFactory.getMetadataReader(resource);
try {
result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
if (!result.isEmpty()) {
HashSet<String> hashResult = new HashSet<>(result);
allResult.addAll(hashResult);
}
}
if (!allResult.isEmpty()) {
typeAliasesPackage = String.join(",", allResult.toArray(new String[0]));
} else {
throw new RuntimeException("Error scanning mybatis typeAliasesPackage, parameter typeAliasesPackage: " + typeAliasesPackage + " found no packages");
}
} catch (IOException e) {
e.printStackTrace();
}
return typeAliasesPackage;
}
public Resource[] resolveMapperLocations(String[] mapperLocations) {
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
List<Resource> resources = new ArrayList<>();
if (mapperLocations != null) {
for (String mapperLocation : mapperLocations) {
try {
Resource[] mappers = resourceResolver.getResources(mapperLocation);
resources.addAll(Arrays.asList(mappers));
} catch (IOException e) {
// Ignore
}
}
}
return resources.toArray(new Resource[0]);
}
/**
* Configuration for the new version
* @return MybatisPlusInterceptor bean
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// Add various interceptors
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// Optimistic locker interceptor
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
Dans le répertoire ruoyi-framework/src/main/java/com/ruoyi/framework/, créez un package nommé mybatisplus et, à l'intérieur de ce package, créez la classe MyMetaObjectHandler :
package com.ruoyi.framework.mybatisplus;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.ruoyi.common.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.time.LocalDateTime;
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
private static final String CREATE_BY = "createBy";
private static final String CREATE_TIME = "createTime";
private static final String UPDATE_BY = "updateBy";
private static final String UPDATE_TIME = "updateTime";
private static final String DELETED = "delFlag";
/**
* Fill strategy for insert operations.
*/
@Override
public void insertFill(MetaObject metaObject) {
// Recommended from version 3.3.0
this.setFieldValByName(CREATE_BY, SecurityUtils.getUsername(), metaObject);
this.setFieldValByName(CREATE_TIME, formatDate(metaObject.getSetterType(CREATE_TIME)), metaObject);
this.setFieldValByName(UPDATE_BY, SecurityUtils.getUsername(), metaObject);
this.setFieldValByName(UPDATE_TIME, formatDate(metaObject.getSetterType(CREATE_TIME)), metaObject);
this.setFieldValByName(DELETED, "0", metaObject);
}
/**
* Fill strategy for update operations.
*/
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName(UPDATE_BY, SecurityUtils.getUsername(), metaObject);
this.setFieldValByName(UPDATE_TIME, formatDate(metaObject.getSetterType(CREATE_TIME)), metaObject);
}
/**
* Handles specific date types.
* @param setterType The type of the setter argument.
* @return The formatted date object.
*/
private Object formatDate(Class<?> setterType) {
if (Date.class.equals(setterType)) {
return new Date();
} else if (LocalDateTime.class.equals(setterType)) {
return LocalDateTime.now();
} else if (Long.class.equals(setterType)) {
return System.currentTimeMillis();
}
return null;
}
}
- Configuration de MyBatis-Plus dans
application.ymldu projetruoyi-admin
Dans le fichier application.yml du projet ruoyi-admin, assurez-vous de commenter la configuration Mybatis existante et d'ajouter la configuration pour MyBatis-Plus comme suit :
# MyBatis Configuration (Commented out)
#mybatis:
# # Alias package for types
# typeAliasesPackage: com.ruoyi.**.domain
# # Mapper XML file location
# mapperLocations: classpath*:mapper/**/*Mapper.xml
# # Global configuration file location
# configLocation: classpath:mybatis/mybatis-config.xml
# MyBatis-Plus Configuration
mybatis-plus:
# Location of corresponding XML files
mapperLocations: classpath*:mapper/**/*Mapper.xml
# Entity scanning, separate multiple packages with commas or semicolons
typeAliasesPackage: com.ruoyi.**.domain
# Optional: Base type for entity scanning
#typeAliasesSuperType: Class>
# Optional: Type handlers package
#typeHandlersPackage: null
# Optional: Enum types package for entity fields
#typeEnumsPackage: null
# Check if MyBatis XML files exist on startup, default is false
checkConfigLocation: false
# MyBatis executor type: SIMPLE, REUSE, BATCH
executorType: SIMPLE
# External configuration properties for MyBatis
configurationProperties: null
configuration:
# Enable automatic camel case to underscore mapping
mapUnderscoreToCamelCase: true
# Default enum type handler. Options: org.apache.ibatis.type.EnumTypeHandler (stores name), org.apache.ibatis.type.EnumOrdinalTypeHandler (stores ordinal), com.baomidou.mybatisplus.extension.handlers.MybatisEnumTypeHandler (requires IEnum or @EnumValue)
defaultEnumTypeHandler: org.apache.ibatis.type.EnumTypeHandler
# Enable aggressive lazy loading
aggressiveLazyLoading: true
# MyBatis automatic mapping behavior: NONE, PARTIAL, FULL
autoMappingBehavior: PARTIAL
# Handling of unknown columns or properties during automatic mapping: NONE, WARNING, FAILING
autoMappingUnknownColumnBehavior: NONE
# MyBatis level 1 cache scope: SESSION or STATEMENT
localCacheScope: SESSION
# Enable MyBatis level 2 cache, default is true
cacheEnabled: true
global-config:
# Whether to display the logo banner on startup
banner: true
# Whether to initialize SqlRunner
enableSqlRunner: false
dbConfig:
# ID type: AUTO (auto-increment), NONE (none), INPUT (user input), ASSIGN_ID (global unique ID), ASSIGN_UUID (global unique UUID)
idType: AUTO
# Table name prefix
tablePrefix: null
# Column naming format, e.g., '%s'. Not applicable to primary keys.
columnFormat: null
# Whether to use snake_case for table names (converts camelCase)
tableUnderline: true
# Use uppercase for table and column names
capitalMode: false
# Global logic delete field name
logicDeleteField: null
# Value for logically deleted records
logicDeleteValue: 2
# Value for logically undeleted records
logicNotDeleteValue: 0
# Field strategy for insert operations: IGNORED, NOT_NULL, NOT_EMPTY, DEFAULT, NEVER
insertStrategy: NOT_NULL
# Field strategy for update operations: IGNORED, NOT_NULL, NOT_EMPTY, DEFAULT, NEVER
updateStrategy: NOT_NULL
# Field strategy for select operations (wrapper conditions): IGNORED, NOT_NULL, NOT_EMPTY, DEFAULT, NEVER
selectStrategy: NOT_NULL