Maison > Java > javaDidacticiel > Comment imprimer les journaux d'erreurs dans les projets Java

Comment imprimer les journaux d'erreurs dans les projets Java

王林
Libérer: 2023-05-03 13:13:06
avant
1543 Les gens l'ont consulté

1. Paramètres illégaux introduits par le système de couche supérieure. Pour les erreurs introduites par des paramètres illégaux, les erreurs peuvent être interceptées via la vérification des paramètres et la vérification des conditions préalables 

2. Erreurs générées par l'interaction avec le système sous-jacent. Il existe deux types d'erreurs causées par l'interaction avec la couche inférieure :

a. Le système de la couche inférieure a été traité avec succès, mais la communication s'est mal déroulée, ce qui entraînera une incohérence des données entre les sous-systèmes.

Pour cette situation, un délai d'attente ; Un mécanisme de compensation peut être utilisé, enregistrer les tâches à l'avance et corriger les données ultérieurement via des tâches planifiées.

Si vous avez de meilleures solutions de conception, vous pouvez également laisser un message.

b. La communication a réussi, mais une erreur s'est produite dans le traitement de la couche inférieure.

Dans ce cas, il est nécessaire de communiquer avec les développeurs de niveau inférieur pour coordonner l'interaction entre les sous-systèmes ;

Il est nécessaire d'effectuer un traitement approprié ou de fournir des informations rapides raisonnables basées sur le code d'erreur et la description de l'erreur renvoyés par le niveau inférieur ; -couche de niveau.

Dans les deux cas, il est nécessaire de supposer que la fiabilité du système sous-jacent est moyenne et de prendre en compte les erreurs de conception.

3. Il y a une erreur dans le traitement du système à ce niveau.

Causes des erreurs dans ce système :

Cause 1 : Causée par une négligence. Une omission signifie que le programmeur aurait pu éviter de telles erreurs, mais n'y est pas parvenu. Par exemple, && a été saisi dans &, == a été saisi dans = erreurs de limites, erreurs de jugement logique composé, etc. La négligence est soit due au fait que le programmeur n'est pas suffisamment concentré, par exemple en étant fatigué, en faisant des heures supplémentaires toute la nuit ou en écrivant des programmes tout en tenant des réunions, ou encore en se précipitant pour implémenter la fonction sans tenir compte de la robustesse du programme.

Mesures d'amélioration : utilisez les outils d'analyse statique du code et la couverture des lignes de tests unitaires pour éviter efficacement de tels problèmes.

Raison 2 : Causée par une gestion insuffisante des erreurs et des exceptions. Par exemple, saisissez une question. Lors du calcul de l'addition de deux nombres, il faut non seulement considérer le problème du débordement de calcul, mais aussi considérer la situation de saisie illégale. Pour le premier, cela peut être évité grâce à la compréhension, aux erreurs ou à l'expérience, tandis que pour le second, il doit être limité afin qu'il se situe dans la plage que notre QI peut contrôler, par exemple en utilisant des expressions régulières pour filtrer les entrées illégales. Les expressions régulières doivent être testées. En cas de saisie illégale, fournissez des informations, des raisons et des suggestions aussi détaillées, compréhensibles et conviviales que possible.

Mesures d'amélioration : Considérez de manière aussi approfondie que possible diverses situations d'erreur et la gestion des exceptions. Après avoir implémenté le processus principal, ajoutez une étape : examinez attentivement diverses erreurs et exceptions possibles, et renvoyez des codes d'erreur et des descriptions d'erreur raisonnables. Chaque interface ou module gère efficacement ses propres erreurs et exceptions, ce qui peut efficacement éviter les bogues causés par des interactions de scènes complexes.

Par exemple, un cas d'usage métier est complété de manière interactive par des scénarios A.B.C. L'exécution réelle de A.B réussit, mais C échoue. À ce stade, B doit annuler les codes et messages raisonnables renvoyés par C et renvoyer les codes et messages raisonnables à A. A annule en fonction du retour de B et renvoie les codes et messages raisonnables. au client. Il s'agit d'un mécanisme de restauration segmenté qui nécessite que chaque scénario envisage une restauration dans des circonstances anormales.

Raison 3 : Causée par un couplage logique étroit. En raison du couplage étroit de la logique métier, à mesure que les produits logiciels se développent étape par étape, diverses relations logiques sont complexes, ce qui rend difficile la vision de la situation globale, provoquant la propagation de l'impact des modifications locales à la portée mondiale, provoquant des problèmes imprévisibles. .

Mesures d'amélioration : Écrivez des fonctions et des méthodes courtes, de préférence pas plus de 50 lignes pour chaque fonction ou méthode. Écrivez des fonctions et des méthodes sans état, un état global en lecture seule, la même condition préalable produira toujours le même résultat et ne changera pas son comportement en fonction de l'état externe ; définir des structures, des interfaces et des segments logiques raisonnables pour établir la connexion entre les interfaces. Les interactions doivent être aussi orthogonales et faiblement couplées que possible ; pour la couche de service, des interfaces simples et orthogonales doivent être fournies autant que possible ; une reconstruction continue doit être effectuée pour maintenir les applications modulaires et faiblement couplées, et clarifier les dépendances logiques.

Pour les situations où un grand nombre d'interfaces métier interagissent entre elles, il est nécessaire de trier les processus logiques et les interdépendances de chaque interface métier et de les optimiser dans leur ensemble pour les entités avec un grand nombre d'états, c'est également le cas ; nécessaire de trier les interfaces commerciales pertinentes et de trier les relations de conversion.

Raison 4 : Causée par un algorithme incorrect.

Mesures d'amélioration : Séparez d'abord l'algorithme de l'application. Si l'algorithme a plusieurs implémentations, il peut être découvert grâce à des tests unitaires de vérification croisée, telles que des opérations de tri ; si l'algorithme a des propriétés réversibles, il peut être découvert grâce à des tests unitaires de vérification réversible, telles que des opérations de cryptage et de déchiffrement ; .

Cause cinq : Les paramètres du même type sont transmis dans le mauvais ordre. Par exemple, modifierFlow(int rx, int tx), l'appel réel est modifierFlow(tx,rx)

Mesures d'amélioration : rendre le type aussi spécifique que possible. Utilisez des nombres à virgule flottante lorsque vous devez les utiliser, utilisez des chaînes lorsque vous devez utiliser des chaînes et utilisez des types d'objets spécifiques lorsque vous devez les utiliser ; les paramètres du même type doivent être échelonnés autant que possible ; Pour être satisfait, vous devez le vérifier via des tests d'interface, les valeurs des paramètres d'interface doivent être différentes.

Raison six : exception de pointeur nul. Les exceptions de pointeur nul se produisent généralement lorsque l'objet n'est pas initialisé correctement ou si l'objet n'est pas nul n'est pas vérifié avant de l'utiliser.

Mesures d'amélioration : Pour les objets de configuration, vérifiez s'ils sont initialisés avec succès ; pour les objets ordinaires, vérifiez s'ils ne sont pas vides avant d'obtenir l'objet entité à utiliser.

Cause 7 : Erreur de communication réseau. Les erreurs de communication réseau sont généralement causées par des retards, des congestions ou des blocages du réseau. Les erreurs de communication réseau sont généralement des événements à faible probabilité, mais les événements à faible probabilité sont susceptibles de conduire à des pannes à grande échelle et à des bogues difficiles à reproduire.

Mesures d'amélioration : Créez des journaux INFO au point final du sous-système précédent et au point d'entrée du sous-système suivant respectivement. Le décalage horaire entre les deux donne un indice.

Cause huit : Erreurs de transaction et de concurrence. La combinaison de transactions et de concurrence peut facilement produire des erreurs très difficiles à localiser.

Mesures d'amélioration : Pour les opérations simultanées dans le programme qui impliquent des variables partagées et des modifications d'état importantes, des journaux INFO doivent être ajoutés.

S'il existe un moyen plus efficace, veuillez laisser un message pour le signaler.

Cause neuf : Erreur de configuration.

Mesures d'amélioration : Lors du démarrage de l'application ou du démarrage de la configuration correspondante, détectez tous les éléments de configuration, imprimez le journal INFO correspondant et assurez-vous que toutes les configurations sont chargées avec succès.

Raison 10 : Erreurs causées par une méconnaissance du métier. Dans les systèmes de taille moyenne et grande, certaines logiques métier et interactions commerciales sont relativement complexes. L'ensemble de la logique métier peut exister dans le cerveau de plusieurs étudiants en développement, et la compréhension de chacun est incomplète. Cela peut facilement conduire à des erreurs de codage professionnel.

Mesures d'amélioration : Concevoir des cas d'utilisation métier corrects par le biais de discussions et de communications avec plusieurs personnes, et rédiger et mettre en œuvre une logique métier basée sur des cas d'utilisation métier ; la logique métier finale et les cas d'utilisation métier doivent être entièrement archivés ; l'interface métier Conditions préalables, logique de traitement, post-vérification et précautions ; lorsque l'entreprise change, les commentaires commerciaux doivent être mis à jour simultanément ; Les annotations métier sont des documents importants pour les interfaces métier et jouent un rôle de mise en cache important dans la compréhension métier.

Cause 11 : Erreurs causées par des problèmes de conception. Par exemple, la méthode série synchrone aura des problèmes de performances et de réponse lente, tandis que la méthode asynchrone simultanée peut résoudre les problèmes de performances et de réponse lente, mais elle entraînera des dangers cachés pour la sécurité et l'exactitude. L'approche asynchrone entraînera des changements dans le modèle de programmation, ajoutant de nouveaux problèmes tels que l'envoi et la réception de messages asynchrones. L'utilisation du cache peut améliorer les performances, mais des problèmes se poseront avec les mises à jour du cache.

Mesures d'amélioration : Rédiger et réviser attentivement les documents de conception. Le document de conception doit décrire le contexte, les exigences, les objectifs commerciaux à atteindre, les indicateurs de performance commerciale à atteindre, les impacts possibles, les idées de conception globales, les plans détaillés, prévoyant les avantages, les inconvénients et les impacts possibles du plan à travers les tests et l'acceptation ; assurez-vous que les changements sont conformes aux objectifs commerciaux et aux mesures de performance commerciale.

Cause 12 : Erreur causée par des détails inconnus. Tels que les attaques par débordement de tampon et par injection SQL. D’un point de vue fonctionnel, il n’y a pas de problème, mais d’un point de vue d’utilisation malveillante, il y a des failles. Pour un autre exemple, si vous choisissez la bibliothèque Jackson pour l'analyse des chaînes JSON, par défaut, des erreurs d'analyse se produiront lorsque de nouveaux champs seront ajoutés à l'objet. L'annotation @JsonIgnoreProperties(ignoreUnknown = true) doit être ajoutée à l'objet pour répondre correctement aux modifications. Si vous choisissez d'autres bibliothèques JSON, vous n'aurez peut-être pas ce problème.

Mesures d'amélioration : D'une part, il est nécessaire d'accumuler de l'expérience, d'autre part, prendre en compte les problèmes de sécurité et les exceptions, et choisir des bibliothèques matures et rigoureusement testées.

Raison 13 : Des bugs qui apparaissent au fil du temps. Il n’est pas rare que des solutions qui semblaient excellentes dans le passé deviennent lourdes, voire inutiles, dans les scénarios actuels ou futurs. Par exemple, les algorithmes de chiffrement et de déchiffrement ont peut-être été considérés comme parfaits dans le passé, mais doivent être utilisés avec prudence après avoir été craqués.

Mesures d'amélioration : faites attention aux modifications et aux corrections de vulnérabilités, et corrigez rapidement les codes, bibliothèques et comportements obsolètes.

Cause quatorze : erreurs liées au matériel. Par exemple, fuites de mémoire, espace de stockage insuffisant, OutOfMemoryError, etc.

Mesures d'amélioration : Ajoutez une surveillance des performances d'indicateurs importants tels que le CPU/la mémoire/le réseau du système d'application.

Erreurs courantes dans le système :

  • L'enregistrement de l'entité dans la base de données n'existe pas, vous devez préciser de quelle entité ou identifiant d'entité il s'agit

  • La configuration de l'entité est incorrecte, vous devez préciser quelle configuration a le ; problème, la configuration correcte Que devrait-elle être ;

  • La ressource de l'entité ne remplit pas les conditions, vous devez préciser quelle est la ressource actuelle et quelles sont les exigences en matière de ressources

  • Les conditions préalables au fonctionnement de l'entité ne le sont pas ; satisfaire, vous devez préciser quelles conditions préalables doivent être remplies et le statut actuel. Qu'est-ce que c'est ?

  • Le post-contrôle de l'opération de l'entité n'est pas satisfait. Vous devez préciser quel post-contrôle doit être rempli et quel est le courant. le statut est :

  • Les problèmes de performances provoquent des délais d'attente. Vous devez spécifier la cause des problèmes de performances. Comment optimiser à l'avenir ?

Généralement, les erreurs difficiles à localiser apparaîtront à des endroits relativement bas. Étant donné que la couche inférieure ne peut pas prédire le scénario commercial spécifique, les messages d'erreur affichés sont relativement généraux.

Cela nécessite de fournir un maximum d'indices au niveau supérieur de l'entreprise. L'erreur doit être provoquée par le fait que les conditions préalables ne sont pas remplies sur une certaine couche de la pile lors de l'interaction de plusieurs systèmes ou couches. Lors de la programmation, essayez de vous assurer que toutes les conditions préalables nécessaires sont remplies dans chaque couche de la pile, évitez autant que possible de transmettre des paramètres erronés à la couche inférieure et interceptez autant que possible les erreurs au niveau de la couche métier.

La plupart des erreurs sont causées par une combinaison de raisons. Mais chaque erreur doit avoir sa cause. Après avoir résolu les erreurs, effectuez une analyse approfondie de la manière dont les erreurs se sont produites et comment éviter qu’elles ne se reproduisent. Vous pouvez réussir en travaillant dur, mais ce n'est que par la réflexion que vous pourrez progresser ! Recommandation : la journalisation élégante de Java : chapitre pratique de log4j

Comment rédiger des journaux d'erreurs qui facilitent le dépannage des problèmes

Principes de base de la journalisation des erreurs :

  1. Aussi complet que possible. Chaque journal d'erreurs décrit en détail : quelle erreur s'est produite dans quel scénario, quelle en est la raison (ou les raisons possibles), comment la résoudre (ou des conseils de solution

  2. soyez aussi précis que possible) ; Par exemple, si les ressources CN sont insuffisantes, à quel manque de ressources spécifique cela fait-il référence ? Peut-il être spécifié directement via le programme. Pour les erreurs générales, telles que VM NOT EXIST, il est nécessaire de spécifier le scénario dans lequel cela se produit, lequel ? peut faciliter les travaux statistiques ultérieurs.

  3. Soyez le plus direct possible. Le journal d’erreurs idéal devrait permettre aux utilisateurs de connaître la cause et comment la résoudre dès la première intuition, plutôt que d’avoir à passer par plusieurs étapes pour trouver la véritable cause.

  4. Intégrez l'expérience existante directement dans le système. Tous les problèmes et expériences résolus doivent être intégrés dans le système de la manière la plus conviviale possible afin de donner de meilleurs conseils aux nouveaux employés, plutôt que d'être enterrés ailleurs.

  5. La mise en page doit être soignée et ordonnée, et le format doit être unifié et standardisé. Les journaux denses, semblables à des essais, sont déchirants à regarder. Ils sont assez peu conviviaux et peu pratiques pour résoudre les problèmes.

  6. Utilisez plusieurs mots-clés pour identifier la demande de manière unique, en mettant en évidence les mots-clés : heure, identifiant d'entité (tel que vmname), nom de l'opération.

Étapes de base pour le dépannage :

Connectez-vous au serveur d'application -> Ouvrez le fichier journal -> Localisez l'emplacement du journal des erreurs -> problème.

Parmi eux :

  1. De la connexion à l'ouverture du fichier journal. Puisqu'il existe plusieurs serveurs d'applications, il n'est pas pratique de se connecter un par un pour les visualiser. Il est nécessaire d'écrire un outil et de le placer sur l'AG pour afficher tous les journaux du serveur directement sur l'AG, et même filtrer directement les journaux d'erreurs requis.

  2. Localiser l'emplacement du journal des erreurs. La présentation actuelle des journaux est dense, ce qui rend difficile la localisation des journaux d'erreurs. En règle générale, vous pouvez d'abord utiliser « time » pour localiser l'emplacement au début du journal des erreurs, puis utiliser la combinaison mot-clé d'entité/nom d'opération pour verrouiller l'emplacement du journal des erreurs. Bien que la localisation des journaux d’erreurs en fonction de requestId soit plus traditionnelle, elle nécessite d’abord de trouver le requestId et n’est pas descriptive. Il est préférable de localiser l’emplacement du journal des erreurs directement en fonction de mots-clés heure/contenu.

3. Analysez le journal des erreurs. Le contenu du journal des erreurs doit être plus direct et plus clair, indiquer clairement qu'il est cohérent avec les caractéristiques du problème actuel à étudier et donner des indices importants.

Habituellement, le problème avec les journaux d'erreurs de programme est que le contenu du journal ne peut être compris qu'en fonction du contexte de code actuel. Il semble concis, mais il est toujours écrit de manière incomplète et dans un format semi-anglais ; , il est difficile de savoir ce qui se dit. Il faut faire réfléchir ou regarder le code pour comprendre ce que signifie le log. N’est-ce pas un cas de souffrance auto-infligée ? Extension : Décrivez en détail les principales bibliothèques d'outils de journalisation de Java

Par exemple :

if ((storageType == StorageType.dfs1 || storageType == StorageType.dfs2)                  && (zone.hasStorageType(StorageType.io3) || zone.hasStorageType(StorageType.io4))) {  // 进入dfs1 和dfs2 在io3 io4 存储。  } else {        log.info("zone storage type not support, zone: " + zone.getZoneId() + ", storageType: "  + storageType.name());        throw new BizException(DeviceErrorCode.ZONE_STORAGE_TYPE_NOT_SUPPORT);  }
Copier après la connexion

zone Quel type de stockage doit être pris en charge ? Do Not Let Me Think !

Les journaux d'erreurs doivent être : clairs même lorsque vous quittez le contexte du code .

De plus, si vous pouvez expliquer clairement les raisons directement dans le journal des erreurs, vous pouvez économiser certains efforts lors de la création des journaux d'inspection.

Dans un sens, le journal des erreurs peut également être un document très utile, enregistrant divers cas d'utilisation illégaux.

Le contenu du journal des erreurs du programme actuel peut présenter les problèmes suivants :

1. Le journal des erreurs ne précise pas les paramètres et le contenu de l'erreur :

catch(Exception ex){        log.error("control ip insert failed", ex);        return new ResultSet<AddControlIpResponse>(  ControlIpErrorCode.ERROR_CONTROL_IP_INSERT_FAILURE);  }
Copier après la connexion

ne précise pas l'adresse IP de contrôle où l'insertion a échoué. ajoutez le mot-clé control ip, il sera plus facile de rechercher et de verrouiller les erreurs.

De même :

log.error("Get some errors when insert subnet and its IPs into database. Add subnet or IP failure.", e);
Copier après la connexion

ne précise pas à quel sous-réseau et à quelles adresses IP il appartient. Il convient de noter que les spécifier nécessite un travail supplémentaire, ce qui peut légèrement affecter les performances. C'est là que les performances et la capacité de débogage doivent être pesées.

解决方案:使用 String.format("Some msg to ErrorObj: %s", errobj) 方法指明错误参数及内容。

这通常要求对 DO 对象编写可读的 toString 方法。

2.错误场景不明确:

log.error("nc has exist, nc ip" + request.getIp());
Copier après la connexion

在 createNc 中检测到 NC 已经存在报错。但是日志上没有指明错误场景, 让人猜测,为什么会报NC已存在错误。

可以改为

log.error("nc has exist when want to create nc, please check nc parameters. Given nc ip: " + request.getIp());  log.error("[create nc] nc has exist, please check nc parameters. Given nc ip: " + request.getIp());
Copier après la connexion

类似的还有:

log.error("not all vm destroyed, nc id " + request.getNcId());
Copier après la connexion

改成

log.error("[delete nc] some vms [%s] in the nc are not destroyed. nc id: %s", vmNames, request.getNcId());
Copier après la connexion

解决方案:错误消息加上 when 字句, 或者错误消息前加上 【接口名】, 指明错误场景,直接从错误日志就知道明白了。

一般能够知道 executor 的可以加上 【接口名】, service 加上 when 字句。

3.内容不明确, 或不明其义:

if(aliMonitorReporter == null) {          log.error("aliMonitorReporter is null!");  } else {         aliMonitorReporter.attach(new ThreadPoolMonitor(namePrefix, asynTaskThreadPool.getThreadPoolExecutor()));  }
Copier après la connexion

改为:

log.error("aliMonitorReporter is null, probably not initialized properly, please check configuration in file xxx.");
Copier après la connexion

类似的还有:

if (diskWbps == null && diskRbps == null && diskWiops == null    && diskRiops == null) {        log.error("none of attribute is specified for modifying");        throw new BizException(DeviceErrorCode.NO_ATTRIBUTE_FOR_MODIFY);  }
Copier après la connexion

改为

log.error("[modify disk attribute] None of [diskWbps,diskRbps,diskWiops,diskRiops] is specified for disk id:" + diskId);
Copier après la connexion

解决方案:更清晰贴切地描述错误内容。

4.排查问题的引导内容不明确:

log.error("get gw group ip segment failed. zkPath: " + LockResource.getGwGroupIpSegmnetLockPath(request.getGwGroupId()));
Copier après la connexion

zkPath ? 如何去排查这个问题?我该去找谁?到哪里去查找更具体的线索?

解决方案:加上相应的背景知识和引导排查措施。

5.错误内容不够具体细致:

if (!ncResourceService.isNcResourceEnough(ncResourceDO,    vmResourceCondition)) {        log.error("disk space is not enough at vm's nc, nc id:" + vmDO.getNcId());        throw new BizException(ResourceErrorCode.ERROR_RESOURCE_NOT_ENOUGH);  }
Copier après la connexion

究竟是什么资源不够?目前剩余多少?现在需要多少?值得注意的是, 要指明这些要额外做一些事情, 可能会稍微影响性能。这时候需要权衡性能和可调试性。

解决方案:通过改进程序或程序技巧, 尽可能揭示出具体的差异所在, 减少人工比对的操作。

6.半英文句式读起来不够清晰明白,需要思考来拼凑起完整的意思:

log.warn("cache status conflict, device id "+deviceDO.getId()+" db status "+deviceDO.getStatus() +", nc status "+ status);
Copier après la connexion

改为:

log.warn(String.format("[query cache status] device cache status conflicts between regiondb and nc, status of device '%s' in regiondb is %s , but is %s in nc.", deviceDO.getId(), deviceDO.getStatus(), status));
Copier après la connexion

解决方案:改为自然可读的英文句式。

总结起来, 错误日志格式可以为:

log.error("[接口名或操作名] [Some Error Msg] happens. [params] [Probably Because]. [Probably need to do].");  log.error(String.format("[接口名或操作名] [Some Error Msg] happens. [%s]. [Probably Because]. [Probably need to do].", params));
Copier après la connexion

log.error("[Some Error Msg] happens to 错误参数或内容 when [in some condition]. [Probably Because]. [Probably need to do].");  log.error(String.format("[Some Error Msg] happens to %s when [in some condition]. [Probably Because]. [Probably need to do].", parameters));
Copier après la connexion

[Probably Reason]. [Probably need to do]. 在某些情况下可以省略;在一些重要接口和场景下最好能说明一下。

每一条错误日志都是独立的,尽可能完整、具体、直接说明何种场景下发生了什么错误,由什么原因导致,要采用什么措施或步骤。

问题:

1.String.format 的性能会影响打日志吗?

一般来说, 错误日志应该是比较少的, 使用 String.format 的频度并不会太高,不会对应用和日志造成影响。

2.开发时间非常紧张时, 有时间去斟酌字句吗?

建立一个标准化的内容格式,将内容往格式套,可以节省斟酌字句的时间。

3.什么时候使用 info, warn , error ?

  •  info 用于打印程序应该出现的正常状态信息, 便于追踪定位;

  •  warn 表明系统出现轻微的不合理但不影响运行和使用;

  •  error 表明出现了系统错误和异常,无法正常完成目标操作。

错误日志是排查问题的重要手段之一。当我们编程实现一项功能时, 通常会考虑可能发生的各种错误及相应原因:

要排查出相应的原因, 就需要一些关键描述来定位原因。

这就会形成三元组:

错误现象 -> 错误关键描述 -> 最终的错误原因。

需要针对每一种错误尽可能提供相应的错误关键描述,从而定位到相应的错误原因。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:yisu.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal