Maison > Java > javaDidacticiel > le corps du texte

Introduction au jugement conditionnel dans Spring Boot (avec code)

不言
Libérer: 2019-04-11 13:14:08
avant
3578 Les gens l'ont consulté

Le contenu de cet article est une introduction au jugement conditionnel dans Spring Boot (avec code). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Ces conditions dans Spring Boot

Spring Boot nous offre une multitude de conditions qui nous permettent d'ajouter des beans au conteneur dans le projet de manière très pratique. Cet article explique principalement chaque annotation et illustre son utilisation avec du code.

Toutes les annotations ConditionalOnXXX peuvent être placées sur une classe ou une méthode. Si la méthode est sur une classe, elle déterminera si toutes les méthodes annotées @Bean de la classe sont exécutées.

@Conditional

Les autres annotations conditionnelles ci-dessous sont du sucre syntaxique. Vous pouvez personnaliser ConditionalOnXXX via la méthode suivante.
L'annotation conditionnelle est définie comme suit, recevant le tableau de classe qui implémente le. Interface de conditions.

public @interface Conditional {
    Class extends Condition>[] value();
}
Copier après la connexion
Copier après la connexion

L'interface Condition n'a qu'une seule méthode matches, qui renvoie le résultat de la correspondance.

public interface Condition {
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
Copier après la connexion
Copier après la connexion

Configurez les conditions via le système d'exploitation pour configurer Bean. Lorsque Window est utilisé, l'objet Person de Bill est instancié, et lorsque Linux est utilisé, l'objet Person de Linus est instancié.

//LinuxCondition,为方便起见,去掉判断代码,直接返回true了
public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return true;
    }
}
Copier après la connexion
Copier après la connexion
//WindowsCondition,为方便起见,去掉判断代码,直接返回false了
public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
        return false;
    }
}
Copier après la connexion
Copier après la connexion
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private String name;
    private Integer age;
}
Copier après la connexion
Copier après la connexion
//配置类
@Configuration
public class BeanConfig {

    @Bean(name = "bill")
    @Conditional({WindowsCondition.class})
    public Person person1(){
        return new Person("Bill Gates",62);
    }

    @Bean("linus")
    @Conditional({LinuxCondition.class})
    public Person person2(){
        return new Person("Linus",48);
    }
}
Copier après la connexion
Copier après la connexion
public class AppTest {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);

    @Test
    public void test(){
        String osName = applicationContext.getEnvironment().getProperty("os.name");
        System.out.println("当前系统为:" + osName);
        Map<string> map = applicationContext.getBeansOfType(Person.class);
        System.out.println(map);
    }
}</string>
Copier après la connexion
Copier après la connexion

Résultat de sortie :

Le système actuel est : Mac OS X
{linus=Person(name=Linus, age=48)}

@ConditionalOnBean & @ConditionalOnMissingBean

Ces deux annotations jugeront l'objet Bean dans le conteneur Bean. L'exemple utilisé est lors de la configuration s'il s'avère qu'il n'y en a pas. Instance d'ordinateur, instanciez un ordinateur de sauvegarde.

@Data
@AllArgsConstructor
@ToString
public class Computer {
    private String name;
}
Copier après la connexion
Copier après la connexion
@Configuration
public class BeanConfig {
    @Bean(name = "notebookPC")
    public Computer computer1(){
        return new Computer("笔记本电脑");
    }

    @ConditionalOnMissingBean(Computer.class)
    @Bean("reservePC")
    public Computer computer2(){
        return new Computer("备用电脑");
    }
}
Copier après la connexion
Copier après la connexion
public class TestApp {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
    @Test
    public void test1(){
        Map<string> map = applicationContext.getBeansOfType(Computer.class);
        System.out.println(map);
    }
}</string>
Copier après la connexion
Copier après la connexion

Modifiez BeanConfig, si vous commentez le premier @Bean, l'ordinateur de sauvegarde sera instancié, sinon l'ordinateur de sauvegarde ne sera pas instancié

@ConditionalOnClass & @ConditionalOnMissingClass

Cette annotation déterminera s'il y a une classe spécifiée sur le chemin de classe. J'étais confus lorsque je l'ai vue pour la première fois. S'il n'y a pas de classe spécifiée sur le chemin de classe, la compilation ne réussira pas. .. Ceci est principalement utilisé lors de l'intégration de composants tiers avec la même fonction. Tant qu'il y a une classe du composant sur le chemin de classe, elle sera automatiquement configurée. Par exemple, lorsque Spring Boot Web configure automatiquement le. composant view, qu'il utilise Velocity, Thymeleaf ou freemaker, c'est la méthode utilisée.
L'exemple est deux ensembles d'armures A (combinaison légère) et B (combinaison sombre). Si A n'est pas présent, configurez B.

public interface Fighter {
    void fight();
}
public class FighterA implements Fighter {
    @Override
    public void fight() {
        System.out.println("使用光明套装");
    }
}
public class FighterB implements Fighter {
    @Override
    public void fight() {
        System.out.println("使用暗黑套装");
    }
}
Copier après la connexion
Copier après la connexion

Van est un samouraï et utilise la combinaison pour combattre

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Van {
    private Fighter fighter;
    public void fight(){
        fighter.fight();
    }
}
Copier après la connexion
Copier après la connexion

VanConfigA/B instancie le samouraï

@Configuration
@ConditionalOnClass({FighterA.class})
public class VanConfigA {
    @Primary
    @Bean
    public Van vanA(){
        return new Van(new FighterA());
    }
}
@Configuration
@ConditionalOnClass({FighterB.class})
public class VanConfigB {
    @Bean
    public Van vanB(){
        return new Van(new FighterB());
    }
}
Copier après la connexion
Copier après la connexion

Classe de test, par défaut, si suit AB Les deux sont sur le chemin de classe, les deux ensembles seront chargés et A sera défini sur PRIMARY. Si FightA.class est supprimé dans la classe cible, seul l'ensemble B sera chargé.

@SpringBootApplication
public class TestApp implements CommandLineRunner {
    @Autowired
    private Van van;
    public static void main(String[] args) {
        SpringApplication.run(TestApp.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
        //do something
       van.fight();
    }
}
Copier après la connexion
Copier après la connexion

De plus, essayez de fusionner les deux VanConfigA/B et mettez l'annotation ConditionalOnClass sur la méthode. Si vous supprimez un package, une erreur se produira.

@ConditionalOnExpress

Jugement conditionnel basé sur des expressions. Cette fonction peut être utilisée dans la plupart des cas avec @ConditionalOnProperty L'expression est plus flexible car SpEL peut être utilisée. Dans l'exemple, la valeur de test.enabled dans les propriétés sera jugée. BeanConfig juge respectivement trois types de booléens, de chaînes et de nombres. J'ai essayé de nombreuses autres méthodes mais aucune ne fonctionne, comme l'utilisation directe de ==. Il semble que les attributs configurés seront traités comme des chaînes.

@Data
public class TestBean {
    private String name;
}
Copier après la connexion
Copier après la connexion
@Configuration
@ConditionalOnExpression("#{${test.enabled:true} }")
//@ConditionalOnExpression("'zz'.equalsIgnoreCase('${test.name2}')")
//@ConditionalOnExpression("new Integer('${test.account}')==1")
public class BeanConfig {
    @Bean
    public TestBean testBean(){
        return new TestBean("我是美猴王");
    }
}
Copier après la connexion
Copier après la connexion
@SpringBootApplication
public class TestAppCommand implements CommandLineRunner {
    @Autowired
    private TestBean testBean;

    public static void main(String[] args) {
        SpringApplication.run(TestAppCommand.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println(testBean.getName());
    }
}
Copier après la connexion
Copier après la connexion

@ConditionalOnProperty

convient au jugement conditionnel sur une seule propriété, tandis que le @ConditionalOnExpress ci-dessus convient à des situations plus complexes, telles que l'association de plusieurs propriétés Comparez. Cet exemple donne également trois types de base de jugements conditionnels, mais il semble qu'ils puissent tous être traités comme des chaînes...

@Data
@AllArgsConstructor
@NoArgsConstructor
public class TestBean {
    private String name;
}
Copier après la connexion
@Configuration
@ConditionalOnProperty(prefix = "test", name="enabled", havingValue = "true",matchIfMissing = false)
//@ConditionalOnProperty(prefix = "test", name="account", havingValue = "1",matchIfMissing = false)
//@ConditionalOnProperty(prefix = "test", name="name1", havingValue = "zz",matchIfMissing = false)
public class BeanConfig {

    @Bean
    public TestBean testBean(){
        return new TestBean("我是美猴王");
    }
}
Copier après la connexion
@SpringBootApplication
public class TestAppCommand implements CommandLineRunner {
    @Autowired
    private TestBean testBean;
    public static void main(String[] args) {
        SpringApplication.run(TestAppCommand.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
        System.out.println(testBean.getName());

    }
}
Copier après la connexion

@ConditionalOnJava

Vous pouvez utilisez la version Java pour juger.

@Data
public class TestBean {
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
@Configuration
@ConditionalOnJava(JavaVersion.EIGHT)
public class BeanConfig {

    @Bean
    public TestBean testBean(){
        return new TestBean();
    }
}
Copier après la connexion
public class TestApp {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
    @Test
    public void test(){
        Map<string> map = context.getBeansOfType(TestBean.class);
        System.out.println(map);
    }
}</string>
Copier après la connexion

@ConditionalOnResource

Effectuer un jugement conditionnel selon que le fichier de ressources spécifié existe, par exemple en jugeant ehcache.properties pour déterminer s'il faut assembler automatiquement le composant ehcache .

@Data
public class TestBean {
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
@Configuration
@ConditionalOnResource(resources = "classpath:application.yml")
public class BeanConfig {

    @Bean
    public TestBean testBean(){
        return new TestBean();
    }
}
Copier après la connexion
Copier après la connexion
public class TestApp {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);

    @Test
    public void test(){
        Map<string> map = context.getBeansOfType(TestBean.class);
        System.out.println(map);
    }
}</string>
Copier après la connexion
Copier après la connexion

@ConditionalOnSingleCandidate

Je n'ai pas encore pensé au scénario d'application. Les conditions pour réussir la condition sont : 1. Il n'y a qu'un seul bean correspondant. conteneur 2. Le bean correspondant a Multiple, mais PRIMARY a été formulé. Dans l'exemple, lors de l'assemblage de BeanB, vous devez vérifier l'état de l'assemblage de BeanA, donc BeanBConfig doit être classé après BeanAConfig. Vous pouvez modifier BeanAConfig et supprimer l'annotation @Primary, ou supprimer les trois annotations @Bean, et BeanB ne le sera pas. instancié.

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BeanA {
    private String name;
}
Copier après la connexion
Copier après la connexion
@Configuration
public class BeanAConfig {

    @Bean
    @Primary
    public BeanA bean1(){
        return new BeanA("bean1");
    }
    @Bean(autowireCandidate = false)
    public BeanA bean2(){
        return new BeanA("bean2");
    }
    //@Bean(autowireCandidate = false)
    public BeanA bean3(){
        return new BeanA("bean3");
    }
}
Copier après la connexion
Copier après la connexion
@Data
public class BeanB {
}
Copier après la connexion
Copier après la connexion
@Configuration
@AutoConfigureAfter(BeanAConfig.class)
@ConditionalOnSingleCandidate(BeanA.class)
public class BeanBConfig {

    @Bean
    public BeanB targetBean(){
        return new BeanB();
    }
}
Copier après la connexion
Copier après la connexion
public class TestApp {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanAConfig.class, BeanBConfig.class);

    @Test
    public void test(){
        Map<string> map = context.getBeansOfType(BeanA.class);
        System.out.println(map);
        Map<string> map2 = context.getBeansOfType(BeanB.class);
        System.out.println(map2);
    }
}</string></string>
Copier après la connexion
Copier après la connexion

@ConditionalOnNotWebApplication & @ConditionalOnWebApplication

Déterminez si l'environnement actuel est une application Web.







Ces conditions dans le jugement Spring Boot



                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              

Ces conditions dans Spring BootSpring Boot nous offre une multitude de conditions pour nous permettre de les utiliser très facilement dans le projet Ajouter des beans au conteneur. Cet article explique principalement chaque annotation et illustre son utilisation avec du code. Toutes les annotations ConditionalOnXXX peuvent être placées sur une classe ou une méthode. Si la méthode est sur une classe, elle déterminera si toutes les méthodes annotées @Bean de la classe sont exécutées. @ConditionalLes autres annotations conditionnelles ci-dessous sont du sucre syntaxique. Vous pouvez personnaliser ConditionalOnXXX via la méthode suivante.

L'interface Condition n'a qu'une seule méthode matches, qui renvoie le résultat de la correspondance.

Configurez les conditions via le système d'exploitation pour configurer Bean. Lorsque Window est utilisé, l'objet Person de Bill est instancié, et lorsque Linux est utilisé, l'objet Person de Linus est instancié.

Résultat de sortie :

Le système actuel est : Mac OS X
{linus=Person(name=Linus, age=48)}

public @interface Conditional {
    Class extends Condition>[] value();
}
Copier après la connexion
Copier après la connexion
@ConditionalOnBean & @ConditionalOnMissingBean

Ces deux annotations jugeront l'objet Bean dans le conteneur Bean. L'exemple utilisé est lors de la configuration s'il s'avère qu'il n'y en a pas. Instance d'ordinateur, instanciez un ordinateur de sauvegarde.
public interface Condition {
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
Copier après la connexion
Copier après la connexion

//LinuxCondition,为方便起见,去掉判断代码,直接返回true了
public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return true;
    }
}
Copier après la connexion
Copier après la connexion
//WindowsCondition,为方便起见,去掉判断代码,直接返回false了
public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
        return false;
    }
}
Copier après la connexion
Copier après la connexion
Modifiez BeanConfig, si vous commentez le premier @Bean, l'ordinateur de sauvegarde sera instancié, sinon l'ordinateur de sauvegarde ne sera pas instancié
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private String name;
    private Integer age;
}
Copier après la connexion
Copier après la connexion
//配置类
@Configuration
public class BeanConfig {

    @Bean(name = "bill")
    @Conditional({WindowsCondition.class})
    public Person person1(){
        return new Person("Bill Gates",62);
    }

    @Bean("linus")
    @Conditional({LinuxCondition.class})
    public Person person2(){
        return new Person("Linus",48);
    }
}
Copier après la connexion
Copier après la connexion
@ConditionalOnClass & @ConditionalOnMissingClass
public class AppTest {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);

    @Test
    public void test(){
        String osName = applicationContext.getEnvironment().getProperty("os.name");
        System.out.println("当前系统为:" + osName);
        Map<string> map = applicationContext.getBeansOfType(Person.class);
        System.out.println(map);
    }
}</string>
Copier après la connexion
Copier après la connexion

Cette annotation déterminera s'il y a une classe spécifiée sur le chemin de classe. J'étais confus lorsque je l'ai vue pour la première fois. S'il n'y a pas de classe spécifiée sur le chemin de classe, la compilation ne réussira pas. .. Ceci est principalement utilisé lors de l'intégration de composants tiers avec la même fonction. Tant qu'il y a une classe du composant sur le chemin de classe, elle sera automatiquement configurée. Par exemple, lorsque Spring Boot Web configure automatiquement le. composant view, qu'il utilise Velocity, Thymeleaf ou freemaker, c'est la méthode utilisée.

L'exemple est deux ensembles d'armures A (combinaison légère) et B (combinaison sombre). Si A n'est pas présent, configurez B.

Van est un samouraï et utilise la combinaison pour combattre

VanConfigA/B instancie le samouraï

@Data
@AllArgsConstructor
@ToString
public class Computer {
    private String name;
}
Copier après la connexion
Copier après la connexion
@Configuration
public class BeanConfig {
    @Bean(name = "notebookPC")
    public Computer computer1(){
        return new Computer("笔记本电脑");
    }

    @ConditionalOnMissingBean(Computer.class)
    @Bean("reservePC")
    public Computer computer2(){
        return new Computer("备用电脑");
    }
}
Copier après la connexion
Copier après la connexion
Classe de test, par défaut, si suit AB Les deux sont sur le chemin de classe, les deux ensembles seront chargés et A sera défini sur PRIMARY. Si FightA.class est supprimé dans la classe cible, seul l'ensemble B sera chargé.
public class TestApp {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
    @Test
    public void test1(){
        Map<string> map = applicationContext.getBeansOfType(Computer.class);
        System.out.println(map);
    }
}</string>
Copier après la connexion
Copier après la connexion

De plus, essayez de fusionner les deux VanConfigA/B et mettez l'annotation ConditionalOnClass sur la méthode. Si vous supprimez un package, une erreur se produira.

@ConditionalOnExpress


Jugement conditionnel basé sur des expressions. Cette fonction peut être utilisée dans la plupart des cas avec @ConditionalOnProperty L'expression est plus flexible car SpEL peut être utilisée. Dans l'exemple, la valeur de test.enabled dans les propriétés sera jugée. BeanConfig juge respectivement trois types de booléens, de chaînes et de nombres. J'ai essayé de nombreuses autres méthodes mais aucune ne fonctionne, comme l'utilisation directe de ==. Il semble que les attributs configurés seront traités comme des chaînes.

public interface Fighter {
    void fight();
}
public class FighterA implements Fighter {
    @Override
    public void fight() {
        System.out.println("使用光明套装");
    }
}
public class FighterB implements Fighter {
    @Override
    public void fight() {
        System.out.println("使用暗黑套装");
    }
}
Copier après la connexion
Copier après la connexion

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Van {
    private Fighter fighter;
    public void fight(){
        fighter.fight();
    }
}
Copier après la connexion
Copier après la connexion
@ConditionalOnProperty

convient au jugement conditionnel sur une seule propriété, tandis que le @ConditionalOnExpress ci-dessus convient à des situations plus complexes, telles que l'association de plusieurs propriétés Comparez. Cet exemple donne également trois types de base de jugements conditionnels, mais il semble qu'ils puissent tous être traités comme des chaînes...
@Configuration
@ConditionalOnClass({FighterA.class})
public class VanConfigA {
    @Primary
    @Bean
    public Van vanA(){
        return new Van(new FighterA());
    }
}
@Configuration
@ConditionalOnClass({FighterB.class})
public class VanConfigB {
    @Bean
    public Van vanB(){
        return new Van(new FighterB());
    }
}
Copier après la connexion
Copier après la connexion

@SpringBootApplication
public class TestApp implements CommandLineRunner {
    @Autowired
    private Van van;
    public static void main(String[] args) {
        SpringApplication.run(TestApp.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
        //do something
       van.fight();
    }
}
Copier après la connexion
Copier après la connexion

@ConditionalOnJava

Vous pouvez utilisez la version Java pour juger.

@Data
public class TestBean {
    private String name;
}
Copier après la connexion
Copier après la connexion
@Configuration
@ConditionalOnExpression("#{${test.enabled:true} }")
//@ConditionalOnExpression("'zz'.equalsIgnoreCase('${test.name2}')")
//@ConditionalOnExpression("new Integer('${test.account}')==1")
public class BeanConfig {
    @Bean
    public TestBean testBean(){
        return new TestBean("我是美猴王");
    }
}
Copier après la connexion
Copier après la connexion
@ConditionalOnResource
@SpringBootApplication
public class TestAppCommand implements CommandLineRunner {
    @Autowired
    private TestBean testBean;

    public static void main(String[] args) {
        SpringApplication.run(TestAppCommand.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println(testBean.getName());
    }
}
Copier après la connexion
Copier après la connexion

Effectuer un jugement conditionnel selon que le fichier de ressources spécifié existe, par exemple en jugeant ehcache.properties pour déterminer s'il faut assembler automatiquement le composant ehcache .

@Data
public class TestBean {
}
Copier après la connexion
Copier après la connexion
Copier après la connexion
@Configuration
@ConditionalOnResource(resources = "classpath:application.yml")
public class BeanConfig {

    @Bean
    public TestBean testBean(){
        return new TestBean();
    }
}
Copier après la connexion
Copier après la connexion
public class TestApp {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);

    @Test
    public void test(){
        Map<string> map = context.getBeansOfType(TestBean.class);
        System.out.println(map);
    }
}</string>
Copier après la connexion
Copier après la connexion

@ConditionalOnSingleCandidate

这个还没有想到应用场景,条件通过的条件是:1 对应的bean容器中只有一个 2.对应的bean有多个,但是已经制定了PRIMARY。例子中,BeanB装配的时候需要看BeanA的装配情况,所以BeanBConfig要排在BeanAConfig之后.可以修改BeanAConfig,将@Primary注解去掉,或者把三个@Bean注解去掉,BeanB就不会实例化了。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BeanA {
    private String name;
}
Copier après la connexion
Copier après la connexion
@Configuration
public class BeanAConfig {

    @Bean
    @Primary
    public BeanA bean1(){
        return new BeanA("bean1");
    }
    @Bean(autowireCandidate = false)
    public BeanA bean2(){
        return new BeanA("bean2");
    }
    //@Bean(autowireCandidate = false)
    public BeanA bean3(){
        return new BeanA("bean3");
    }
}
Copier après la connexion
Copier après la connexion
@Data
public class BeanB {
}
Copier après la connexion
Copier après la connexion
@Configuration
@AutoConfigureAfter(BeanAConfig.class)
@ConditionalOnSingleCandidate(BeanA.class)
public class BeanBConfig {

    @Bean
    public BeanB targetBean(){
        return new BeanB();
    }
}
Copier après la connexion
Copier après la connexion
public class TestApp {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanAConfig.class, BeanBConfig.class);

    @Test
    public void test(){
        Map<string> map = context.getBeansOfType(BeanA.class);
        System.out.println(map);
        Map<string> map2 = context.getBeansOfType(BeanB.class);
        System.out.println(map2);
    }
}</string></string>
Copier après la connexion
Copier après la connexion

@ConditionalOnNotWebApplication & @ConditionalOnWebApplication

判断当前环境是否是Web应用。

  • Introduction au jugement conditionnel dans Spring Boot (avec code)


你可能感兴趣的



评论                                                    



载入中...

显示更多评论


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:segmentfault.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