Sujet de l'interview Golden Nine Silver Ten Sprint-MyBatis (y compris les réponses)

Écrit en face: Les questions d'entretien avancées du back-end Java nécessaires pour les entretiens en 2020. Un guide de révision est résumé sur Github. Le contenu est détaillé, avec des images et des textes. Les amis qui ont besoin d'apprendre peuvent jouer!
Adresse GitHub: https://github.com/abel-max/Java-Study-Note/tree/master

1. Qu'est-ce que Mybatis?

(1) Mybatis est un cadre semi-ORM (Object Relational Mapping), qui encapsule JDBC en interne. Vous n'avez qu'à faire attention à l'instruction SQL elle-même pendant le développement, et vous n'avez pas besoin de dépenser de l'énergie pour gérer des processus complexes tels que le chargement de pilotes, la création de connexions et la création d'instructions. Le programmeur écrit directement le SQL écologique original, qui peut contrôler strictement les performances d'exécution SQL et a une grande flexibilité.
(2) MyBatis peut utiliser XML ou des annotations pour configurer et mapper les informations natives, et mapper les POJO aux enregistrements de la base de données, évitant presque tous les codes JDBC et le réglage manuel des paramètres et obtenant des ensembles de résultats.
(3) Configurez diverses instructions à exécuter au moyen de fichiers xml ou d'annotations, et générez les instructions SQL exécutées finales en mappant les objets java et les paramètres dynamiques de sql dans l'instruction. Enfin, le framework mybatis exécute sql et mappe les résultats à java objet et retour. (Le processus de l'exécution de sql au retour du résultat).

2. Les avantages de Mybaits

(1) Basé sur la programmation d'instructions SQL, il est assez flexible et n'aura aucun impact sur la conception existante de l'application ou de la base de données. SQL est écrit en XML, qui découple SQL et le code du programme pour faciliter la gestion unifiée; les balises XML sont fournies pour prendre en charge l'écriture Les instructions SQL dynamiques peuvent être réutilisées.
(2) Par rapport à JDBC, il réduit la quantité de code de plus de 50%, élimine une grande quantité de code redondant dans JDBC et n'a pas besoin de changer manuellement de connexion;
(3) Il est compatible avec diverses bases de données (car MyBatis utilise JDBC pour se connecter Base de données, tant que la base de données prise en charge par JDBC est prise en charge par MyBatis).
(4) Il peut être bien intégré à Spring;
(5) Fournir des balises de mappage pour prendre en charge le mappage de relation de champ ORM entre les objets et les bases de données; Fournir des balises de mappage de relation d'objet pour prendre en charge la maintenance des composants de relation d'objet.

3. Inconvénients du framework MyBatis

(1) La charge de travail d'écriture des instructions SQL est relativement importante, en particulier lorsqu'il existe de nombreux champs et tables associées, les développeurs ont certaines exigences pour écrire des instructions SQL.
(2) Les instructions SQL dépendent de la base de données, ce qui entraîne une mauvaise portabilité de la base de données, et la base de données ne peut pas être remplacée à volonté.

4. Occasions applicables du cadre MyBatis

(1) MyBatis se concentre sur SQL lui-même et est une solution de couche DAO suffisamment flexible.
(2) Pour les projets qui ont des exigences de haute performance ou des changements de demande, tels que les projets Internet, MyBatis sera un bon choix.

5. Quelle est la différence entre MyBatis et Hibernate?

(1) Mybatis est différent de hibernate, ce n'est pas exactement un framework ORM, car MyBatis oblige les programmeurs à écrire des instructions Sql.
(2) Mybatis écrit directement le SQL écologique original, qui peut contrôler strictement les performances d'exécution de SQL, et a une grande flexibilité. Il est très approprié pour le développement de logiciels qui ne nécessite pas d'exigences élevées sur les modèles de données relationnelles, car les exigences de ces logiciels changent fréquemment, et une fois que les exigences changent, elles nécessitent une sortie rapide. . Mais la prémisse de la flexibilité est que mybatis ne peut pas être indépendant de la base de données. Si vous devez implémenter un logiciel prenant en charge plusieurs bases de données, vous devez personnaliser plusieurs ensembles de fichiers de mappage SQL, ce qui représente beaucoup de travail.
(3) Hibernate possède de solides capacités de mappage objet / relationnel et une bonne indépendance de la base de données. Pour les logiciels avec des exigences élevées en matière de modèles relationnels, si vous utilisez hibernate pour développer des logiciels, vous pouvez enregistrer beaucoup de code et améliorer l'efficacité.

6. Quelle est la différence entre # {} et $ {}?

{} est un traitement de pré-compilation, $ {} est un remplacement de chaîne

Lorsque Mybatis traite # {}, il remplacera # {} dans sql par un?
Sign , et appellera la méthode set de PreparedStatement pour attribuer une valeur; lorsque Mybatis est en train de traiter , ce sera {}, ce qui estLorsque , il est le {} remplacer la valeur de la variable.
L'utilisation de # {} peut empêcher efficacement l'injection SQL et améliorer la sécurité du système.

7. Que dois-je faire lorsque le nom d'attribut dans la classe d'entité est différent du nom de champ dans la table?

Type 1: en définissant l'alias du nom de champ dans l'instruction sql de requête, l'alias du nom de champ est cohérent avec le nom d'attribut de la classe d'entité.

<select id=”selectorder” parametertype=”int” resultetype=”
me.gacl.domain.order”>
select order_id id, order_no orderno ,order_price price form
orders where order_id=#{id};
</select>

Le second type: pour mapper la correspondance biunivoque entre les noms de champ et les noms d'attribut de classe d'entité.

<select id="getOrder" parameterType="int"
resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<!–用 id 属性来映射主键字段–>
<id property=”id” column=”order_id”>
<!–用 result 属性来映射非主键字段,property 为实体类属性名,column
为数据表中的属性–>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>

8. Comment écrire une instruction similaire dans une requête floue?

Type 1: ajoutez un caractère générique sql dans le code Java.

string wildcardname = “%smi%”;
list<name> names = mapper.selectlike(wildcardname);
<select id=”selectlike”>
select * from foo where bar like #{value}
</select>

Type 2: l'épissage des caractères génériques dans les instructions SQL provoquera une injection SQL

string wildcardname = “smi”;
list<name> names = mapper.selectlike(wildcardname);
<select id=”selectlike”>
select * from foo where bar like "%"#{value}"%"
</select>

9. Habituellement, un fichier de mappage Xml écrira une interface Dao qui lui correspond Quel est le principe de fonctionnement de cette interface Dao? Lorsque les paramètres des méthodes dans l'interface Dao sont différents, les méthodes peuvent-elles être surchargées?

L'interface Dao est l'interface Mapper. Le nom complet de l'interface est la valeur de l'espace de noms dans le fichier de mappage; le nom de la méthode de l'interface est la valeur id de l'instruction du mappeur dans le fichier de mappage; les paramètres de la méthode d'interface sont les paramètres passés à sql.
L'interface Mapper n'a pas de classe d'implémentation. Lorsque la méthode d'interface est appelée, la chaîne de raccordement nom complet de l'interface + nom de méthode comme valeur de clé peut localiser de manière unique un MapperStatement. Dans Mybatis, chaque étiquette ,, et sera analysée comme un objet MapperStatement.

Par exemple: com.mybatis3.mappers.StudentDao.findStudentById, le seul MapperStatement dont l'espace de noms est com.mybatis3.mappers.StudentDao et dont l'id est findStudentById peut être trouvé.
Les méthodes de l'interface Mapper ne peuvent pas être surchargées car la stratégie de stockage et de recherche de nom complet + nom de méthode est utilisée. Le principe de fonctionnement de l'interface Mapper est le proxy dynamique JDK. Mybatis utilisera le proxy dynamique JDK pour générer le proxy d'objet proxy pour l'interface Mapper lors de l'exécution. L'objet proxy interceptera la méthode d'interface et exécutera le sql représenté par MapperStatement à la place, puis retournera le résultat de l'exécution SQL.

10. Comment fonctionne la pagination de Mybatis? Quel est le principe du plugin de pagination?

Mybatis utilise l'objet RowBounds pour la pagination, qui est la pagination de mémoire pour le jeu de résultats ResultSet, pas la pagination physique. Vous pouvez écrire des paramètres avec la pagination physique directement dans SQL pour terminer la fonction de pagination physique ou vous pouvez utiliser le plug-in de pagination pour terminer la pagination physique.
Le principe de base du plug-in de pagination est d'utiliser l'interface du plug-in fournie par Mybatis pour implémenter un plug-in personnalisé, d'intercepter le SQL à exécuter dans la méthode d'interception du plug-in, puis de réécrire le SQL, selon le dialecte dialecte, d'ajouter l'instruction de pagination physique correspondante et les paramètres de pagination physique

11. Comment Mybatis encapsule le résultat de l'exécution SQL en tant qu'objet cible et le renvoie? Quels sont les formulaires de cartographie?

La première consiste à utiliser des balises pour définir la relation de mappage entre les noms de colonne de base de données et les noms d'attribut d'objet un par un.
La seconde consiste à utiliser la fonction alias de la colonne sql pour écrire l'alias de la colonne comme nom d'attribut d'objet.
Avec la relation de mappage entre les noms de colonne et les noms d'attribut, Mybatis crée des objets par réflexion et utilise les attributs reflétés dans les objets pour les affecter et les renvoyer un par un. Les attributs qui ne peuvent pas trouver la relation de mappage ne peuvent pas être affectés.

12. Comment effectuer une insertion en vrac?

Tout d'abord, créez une instruction d'insertion simple:

<insert id=”insertname”>
insert into names (name) values (#{value})
</insert>
然后在 java 代码中像下面这样执行批处理插入:
list < string > names = new arraylist();
names.add(“fred”);
names.add(“barney”);
names.add(“betty”);
names.add(“wilma”);
// 注意这里 executortype.batch
sqlsession sqlsession =
sqlsessionfactory.opensession(executortype.batch);
try {
namemapper mapper = sqlsession.getmapper(namemapper.class);
for (string name: names) {
mapper.insertname(name);
}
sqlsession.commit();
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
throw e;
}
finally {
sqlsession.close();
}

13.Comment obtenir la valeur de la clé (primaire) générée automatiquement?

La méthode insert renvoie toujours une valeur int, qui représente le nombre de lignes insérées.
Si la stratégie d'auto-croissance est adoptée, la valeur de clé générée automatiquement peut être définie sur l'objet paramètre passé après l'exécution de la méthode d'insertion.
Exemple:

<insert id=”insertname” usegeneratedkeys=”true” keyproperty=”
id”>
insert into names (name) values (#{name})
</insert>
name name = new name();
name.setname(“fred”);
int rows = mapper.insertname(name);
// 完成后,id 已经被设置到对象中
system.out.println(“rows inserted = ” + rows);
system.out.println(“generated key value = ” + name.getid());

14. Comment passer plusieurs paramètres dans mapper?

1. Le premier type:
fonction de couche DAO
public UserselectUser (nom de chaîne, zone de chaîne);
xml correspondant, # {0} représente le premier paramètre de la couche dao, # {1} représente le premier paramètre de la couche dao Deux paramètres, plus de paramètres peuvent être ajoutés plus tard.

<select id="selectUser"resultMap="BaseResultMap">
select * fromuser_user_t whereuser_name = #{0}
anduser_area=#{1}
</select>

2. Le deuxième type: utilisez l'annotation @param:

public interface usermapper {
user selectuser(@param(“username”) string
username,@param(“hashedpassword”) string hashedpassword);
}

Ensuite, il peut être utilisé en xml comme suit (il est recommandé de le conditionner sous forme de carte et de le transmettre au mappeur en tant que paramètre unique):

<select id=”selectuser” resulttype=”user”>
select id, username, hashedpassword
from some_table
where username = #{username}
and hashedpassword = #{hashedpassword}
</select>

3. Le troisième type: plusieurs paramètres sont encapsulés dans une carte

try {
//映射文件的命名空间.SQL 片段的 ID,就可以调用对应的映射文件中的
SQL
//由于我们的参数超过了两个,而方法中只有一个 Object 参数收集,因此
我们使用 Map 集合来装载我们的参数
Map < String, Object > map = new HashMap();
map.put("start", start);
map.put("end", end);
return sqlSession.selectList("StudentID.pagination", map);
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
throw e;
} finally {
MybatisUtil.closeSqlSession();
}

15. A quoi sert Mybatis dynamic sql? Comment ça marche? Quels sont les SQL dynamiques?

Mybatis dynamic sql peut écrire du sql dynamique sous forme de balises dans le fichier de mappage Xml. Le principe d'exécution est de compléter le jugement logique basé sur la valeur de l'expression et d'épisser dynamiquement la fonction sql.
Mybatis fournit 9 types de balises SQL dynamiques: trim | where | set | foreach | if | choose
| when | else | bind.

16. Dans le fichier de mappage Xml, en plus des balises select | insert | updae | delete, quelles sont les autres balises?

Réponse :, ,,, plus 9 balises de SQL dynamique, parmi lesquelles figurent des balises de fragment SQL, importer des fragments SQL via des balises et générer des balises de stratégie pour les clés primaires qui ne prennent pas en charge l'incrémentation automatique.

17. Dans le fichier de mappage Xml de Mybatis, l'id peut-il être répété pour différents fichiers de mappage Xml?

Pour différents fichiers de mappage Xml, si l'espace de noms est configuré, alors l'id peut être répété; si l'espace de noms n'est pas configuré, alors l'id ne peut pas être répété; la
raison est que l'espace de noms + id est utilisé comme clé de Map <String, MapperStatement>
, s'il n'y a pas d'espace de noms, il n'y a plus rien Sous id, alors un identifiant dupliqué entraînera l'écrasement des données.
Avec un espace de noms, l'id peut être répété naturellement, et l'espace de noms + id est naturellement différent si l'espace de noms est différent.

18. Pourquoi Mybatis est-il un outil de cartographie ORM semi-automatique? Quelle est la différence entre elle et entièrement automatique?

Hibernate est un outil de mappage ORM entièrement automatique. Lorsque vous utilisez Hibernate pour interroger des objets associés ou des objets de collection associés, vous pouvez les obtenir directement en fonction du modèle de relation d'objet, ce qui le rend entièrement automatisé. Lorsque Mybatis interroge des objets associés ou des objets de collection associés, vous devez écrire manuellement sql pour terminer, c'est ce qu'on appelle un outil de mappage ORM semi-automatique.

19. Requêtes liées un-à-un, un-à-plusieurs?

<mapper namespace="com.lcb.mapping.userMapper">
<!--association 一对一关联查询 -->
<select id="getClass" parameterType="int"
resultMap="ClassesResultMap">
select * from class c,teacher t where c.teacher_id=t.t_id and
c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap">
<!-- 实体类的字段名和数据表的字段名映射 -->
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher"
javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
<!--collection 一对多关联查询 -->
<select id="getClass2" parameterType="int"
resultMap="ClassesResultMap2">
select * from class c,teacher t,student s where c.teacher_id=t.t_id
and c.c_id=s.class_id and c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap2">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher"
javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
<collection property="student"
ofType="com.lcb.user.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap>
</mapper>

20. De combien de façons MyBatis met-il en œuvre le one-to-one? Comment le faites-vous?

Il existe une requête conjointe et une requête imbriquée. La requête conjointe est une requête conjointe de plusieurs tables, qui ne peut être interrogée qu'une seule fois.
Elle peut être effectuée en configurant le nœud d'association dans resultMap pour configurer une classe un-à-un; la
requête imbriquée consiste à vérifier une table en premier, selon ce tableau L'identifiant de clé étrangère du résultat qu'il contient, pour interroger des données dans une autre table, est également configuré par association, mais la requête d'une autre table est configurée via l'attribut select.

21. Il existe plusieurs façons de réaliser un à plusieurs dans MyBatis, comment faire fonctionner?

Il existe des requêtes conjointes et des requêtes imbriquées. Une requête conjointe est une requête conjointe de plusieurs tables, qui n'est interrogée qu'une seule fois.
Elle peut être complétée en configurant une classe un-à-plusieurs dans le nœud de collection de resultMap; une requête imbriquée consiste à vérifier d'abord une table, en fonction de l'ID de clé étrangère du résultat dans la table, L'interrogation des données dans une autre table est également configurée via la collecte, mais la requête d'une autre table est configurée via le nœud de sélection.

22. Mybatis prend-il en charge le chargement différé? Dans l'affirmative, quel est son principe de mise en œuvre?

Réponse: Mybatis ne prend en charge que le chargement différé des objets d'association et des objets de collection. L'association fait référence à un à un, et la collection à une requête un à plusieurs. Dans le fichier de configuration Mybatis, vous pouvez configurer l'activation du chargement différé lazyLoadingEnabled = true | false.
Son principe est d'utiliser CGLIB pour créer l'objet proxy de l'objet cible. Lorsque la méthode cible est appelée, entrez la méthode d'intercepteur, telle que l'appel a.getB (). GetName (), et la méthode intercepteur invoke () trouve que a.getB () est valeur nulle, puis il enverra séparément la requête sql précédemment enregistrée associée à l'objet B, la requête B up, puis appellera a.setB (b), de sorte que l'attribut objet b de a a une valeur, puis complétera a.getB ( ) .getName () appel de la méthode. C'est le principe de base du chargement paresseux.
Bien sûr, non seulement Mybatis, mais presque tous, y compris Hibernate, prennent en charge le chargement paresseux selon le même principe.

23, cache primaire et secondaire de Mybatis

1) Cache de niveau 1: cache local HashMap basé sur PerpetualCache, son étendue de stockage est Session. Après le vidage ou la fermeture de la session, tous les caches de la session seront vidés et le cache de niveau 1 est activé par défaut.
2) Le mécanisme du cache de deuxième niveau est le même que celui du cache de premier niveau. Par défaut, PerpetualCache et HashMap sont utilisés pour le stockage. La différence est que l'étendue de stockage est Mapper (Namespace) et la source de stockage peut être personnalisée, comme Ehcache. Le cache de second niveau n'est pas activé par défaut. Pour activer le cache de second niveau, l'utilisation de la classe d'attributs de cache de second niveau doit implémenter l'interface de sérialisation Serializable (qui peut être utilisée pour enregistrer l'état de l'objet), qui peut être configurée dans son fichier de mappage;
3) Pour le mécanisme de mise à jour des données du cache , Lorsque
l'opération C / U / D est effectuée dans une certaine étendue (session de cache de premier niveau / espaces de noms de cache de second niveau ), tous les caches de select dans cette étendue seront effacés par défaut.

24. Quelle est la liaison d'interface de MyBatis? Quels sont les moyens d'y parvenir?

La liaison d'interface consiste à définir l'interface arbitrairement dans MyBatis, puis à lier les méthodes de l'interface à l'instruction SQL, nous pouvons directement appeler la méthode d'interface, afin que nous puissions avoir des choix et des paramètres plus flexibles que la méthode d'origine fournie par SqlSession .
Il existe deux façons d'implémenter la liaison d'interface. La première consiste à créer une liaison via des annotations, qui consiste à ajouter @Select, @Update et d'autres annotations aux méthodes d'interface, qui contiennent des instructions SQL à lier; l'autre consiste à écrire du code SQL en XML Pour lier, dans ce cas, l'espace de noms dans le fichier de mappage xml doit être le nom de chemin complet de l'interface. Lorsque l'instruction SQL est relativement simple, utilisez la liaison d'annotation, lorsque l'instruction SQL est plus complexe, utilisez la liaison xml, utilisez généralement davantage la liaison xml.

25. Quelles sont les exigences lors de l'utilisation de l'interface mappeur de MyBatis pour appeler?

1. Le nom de la méthode d'interface Mapper est le même que l'ID de chaque SQL défini dans mapper.xml;
2. Le type de paramètre d'entrée de la méthode d'interface Mapper est le
même que le parameterType de chaque SQL défini dans mapper.xml ;
3. Le type de la méthode d'interface Mapper Le type de paramètre de sortie
est le même que le resultType de chaque SQL défini dans mapper.xml
4. L'espace de noms dans le fichier Mapper.xml est le chemin de classe de l'interface du mappeur.

26. Quelles sont les manières d'écrire Mapper?

Le premier: la classe d'implémentation d'interface hérite de SqlSessionDaoSupport: pour utiliser cette méthode, vous devez écrire l'
interface mapper, la classe d'implémentation d'interface mapper et le fichier mapper.xml.
(1) Configurez l'emplacement de mapper.xml dans sqlMapConfig.xml

<mappers>
<mapper resource="mapper.xml 文件的地址" />
<mapper resource="mapper.xml 文件的地址" />
</mappers>

(2) Définir l'interface du mappeur
(3) Dans l'implémentation de la
méthode de mappage d'intégration de classe SqlSessionDaoSupport , this.getSqlSession () peut être utilisé pour ajouter, supprimer, modifier et vérifier des données.
(4) Configuration du ressort

<bean id=" " class="mapper 接口的实现">
<property name="sqlSessionFactory"
ref="sqlSessionFactory"></property>
</bean>

La seconde: utilisez org.mybatis.spring.mapper.MapperFactoryBean:
(1) Configurez l'emplacement de mapper.xml dans sqlMapConfig.xml. Si mapper.xml et l'interface mappre ont le même nom et sont dans le même répertoire, il n'est pas nécessaire de configurer

<mappers>
<mapper resource="mapper.xml 文件的地址" />
<mapper resource="mapper.xml 文件的地址" />
</mappers>

(2) Définissez l'interface du mappeur:
1. L'espace de nom dans mapper.xml est l'adresse
de l'interface du mappeur 2. Le nom de la méthode dans l'interface du mappeur est cohérent avec l'id de l'instruction définie dans mapper.xml 3. La définition dans
Spring

<bean id="" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="mapper 接口地址" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

Le troisième type: utilisez le mapper scanner:
(1) Ecrivez le fichier mapper.xml:
l'espace de noms dans mapper.xml est l'adresse de l'interface mapper; le nom de la méthode dans l'interface mapper est cohérent avec l'id de l'instruction définie dans mapper.xml; si Il n'est pas nécessaire de configurer la cohérence du nom de mapper.xml et de l'interface du mappeur dans sqlMapConfig.xml.
(2) Définissez l'interface du mappeur:
Notez que le nom de fichier de mapper.xml est cohérent avec le nom de l'interface du mappeur et est placé dans le même répertoire
(3) Configurez le scanner du mappeur:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="mapper 接口包地址
"></property>
<property name="sqlSessionFactoryBeanName"
value="sqlSessionFactory"/>
</bean>

(4) Récupérez l'objet d'implémentation du mappeur à partir du conteneur à ressort après avoir utilisé le scanner.

27. Décrivez brièvement le principe de fonctionnement du plug-in Mybatis et comment écrire un plug-in.

Réponse: Mybatis ne peut écrire des
plug-ins que pour les quatre interfaces de ParameterHandler, ResultSetHandler, StatementHandler et Executor. Mybatis utilise le proxy dynamique du JDK pour générer des objets proxy pour les interfaces qui doivent être interceptées pour implémenter la fonction d'interception de la méthode d'interface. Chaque fois que ces quatre interfaces sont exécutées Lorsque la méthode de l'objet, il entrera dans la méthode d'interception, plus précisément la méthode invoke () du InvocationHandler. Bien sûr, seules les méthodes que vous spécifiez pour être interceptées seront interceptées.
Ecrire un plug-in: implémentez l'interface Interceptor de Mybatis et écrasez la méthode intercept (), puis écrivez une annotation pour le plug-in pour spécifier les méthodes d'interface que vous souhaitez intercepter. N'oubliez pas de configurer le plug-in que vous avez écrit dans le fichier de configuration.

Je suppose que tu aimes

Origine blog.csdn.net/doubututou/article/details/109128923
conseillé
Classement